Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for multiple authors and update settings UI #395

Closed

Conversation

doxxx93
Copy link
Contributor

@doxxx93 doxxx93 commented Oct 14, 2024

  • Introduced AuthorStrategyFactory to separate author handling logic for Jekyll and Docusaurus
  • Applied author strategies in FrontMatterConverter
  • Added authors and platform fields to DocusaurusSettings and JekyllSettings
  • Enhanced O2Settings with UI for author input specific to Jekyll and Docusaurus
  • Added test cases for handling multiple authors
  • Extended existing defaultAuthor functionality to support multiple authors

Pull Request

Checklist

Please check if your PR fulfills the following requirements:

  • Tests for the changes have been added (for bugfixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Currently, there is no option to set a default author for Docusaurus conversions. Users have to manually add author information to each markdown file.

Issue Number: N/A

What is the new behavior?

Currently, there is no option to set a default author for Docusaurus conversions. Users have to manually add author information to each markdown file.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

This feature enhances the flexibility of content attribution, allowing for single or multiple authors to be specified seamlessly across different platforms. It improves the user experience by reducing the need for repetitive manual input and ensures consistent author information in the generated frontmatter.

image

Summary by CodeRabbit

  • New Features

    • Introduced a default author setting for front matter in markdown files, enhancing content attribution.
    • Added a user interface option to configure the default author in settings.
  • Bug Fixes

    • Improved handling of author fields in front matter conversion to ensure defaults are applied correctly.
  • Tests

    • New test cases added to validate the functionality of the default author settings.

- Implement defaultAuthor in FrontMatterConverter
- Update DocusaurusSettings to include defaultAuthor
- Add UI setting for defaultAuthor in O2Settings
Copy link
Contributor

coderabbitai bot commented Oct 14, 2024

Walkthrough

The changes introduce a new AuthorStrategyFactory class and several author strategy implementations to enhance the handling of authors in front matter for markdown documents. The FrontMatterConverter class is updated to utilize these strategies, allowing for flexible author management based on the platform type. Additionally, new properties related to authors are added to the DocusaurusSettings and JekyllSettings classes. The conversion functions for both Docusaurus and Jekyll are modified to instantiate the FrontMatterConverter with the appropriate parameters, and new test cases are added to validate these changes.

Changes

File Change Summary
src/AuthorStrategyFactory.ts Added AuthorStrategyFactory class with createStrategy method for author strategy instantiation.
src/FrontMatterConverter.ts Updated constructor to include authors and platform. Added private applyAuthors method.
src/docusaurus/docusaurus.ts Modified convertToDocusaurus to use FrontMatterConverter for front matter processing.
src/docusaurus/settings/DocusaurusSettings.ts Added authors, authorStrategy, and platform properties to DocusaurusSettings class.
src/enums/PlatformType.ts Introduced PlatformType enum with members Default, Jekyll, and Docusaurus.
src/jekyll/chirpy.ts Updated convertToChirpy to instantiate FrontMatterConverter with new parameters.
src/jekyll/settings/JekyllSettings.ts Added authors and platform properties to JekyllSettings class.
src/settings.ts Introduced private methods addJekyllAuthorsSettings and addDocusaurusAuthorsSettings in O2SettingTab.
src/strategies/authors/AuthorStrategy.ts Added AuthorStrategy interface with applyAuthors method.
src/strategies/authors/DefaultAuthorStrategy.ts Added DefaultAuthorStrategy class implementing AuthorStrategy.
src/strategies/authors/DocusaurusAuthorStrategy.ts Added DocusaurusAuthorStrategy class implementing AuthorStrategy.
src/strategies/authors/JekyllAuthorStrategy.ts Added JekyllAuthorStrategy class implementing AuthorStrategy.
src/tests/FrontMatterConverter.test.ts Added test cases for author conversion scenarios for Jekyll and Docusaurus platforms.

Poem

In fields where authors hop and play,
New strategies bloom in a bright array.
With every tale and every line,
Our front matter shines, oh so fine!
So gather 'round, let stories weave,
In the world of words, we all believe! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
src/docusaurus/settings/DocusaurusSettings.ts (1)

7-7: LGTM! Consider adding JSDoc comment for clarity.

The addition of the defaultAuthor property aligns well with the PR objectives and doesn't affect existing functionality. Good job!

Consider adding a JSDoc comment to provide more context about this property. For example:

/** The default author name to use when not specified in the front matter */
defaultAuthor: string;

This would improve code readability and make the purpose of this property clearer to other developers.

src/docusaurus/docusaurus.ts (1)

56-56: Consider adding error handling for defaultAuthor.

While the implementation is straightforward, it might be beneficial to add error handling in case plugin.docusaurus.defaultAuthor is undefined or null. This would prevent potential runtime errors and improve the robustness of the code.

Consider updating the code as follows:

-                plugin.docusaurus.defaultAuthor,
+                plugin.docusaurus.defaultAuthor || '',

This change ensures that an empty string is passed if defaultAuthor is not set, maintaining consistent behavior.

src/settings.ts (1)

67-67: Remove unnecessary comment

The Korean comment "새로운 설정 추가" is not necessary and should be removed for consistency with the rest of the codebase.

Apply this change:

-    this.addDefaultAuthorSetting(); // 새로운 설정 추가
+    this.addDefaultAuthorSetting();
src/tests/FrontMatterConverter.test.ts (3)

397-426: LGTM! Consider adding a test for multiple authors.

The 'FrontMatterConverter with defaultAuthor' test suite is well-structured and covers the main scenarios for the defaultAuthor functionality. The test cases are clear and use appropriate assertions.

Consider adding a test case for handling multiple existing authors to ensure the defaultAuthor is not added in this scenario. For example:

it('should not add defaultAuthor when multiple authors exist', () => {
  const converter = new FrontMatterConverter('file.md', 'path', false, false, 'Default Author');
  const input = '---\ntitle: "Test"\nauthors: [Existing Author 1, Existing Author 2]\n---\nContent';
  const result = converter.convert(input);
  expect(result).toContain('authors: [Existing Author 1, Existing Author 2]');
  expect(result).not.toContain('Default Author');
});

428-441: LGTM! Consider adding tests for edge cases.

The 'convertFrontMatter with defaultAuthor' test suite effectively covers the main scenarios for the defaultAuthor functionality in the convertFrontMatter function. The tests are concise and use clear assertions.

Consider adding the following test cases to improve coverage:

  1. Test when defaultAuthor is an empty string:
it('should not add authors when defaultAuthor is empty', () => {
  const input = '---\ntitle: "Test"\n---\nContent';
  const result = convertFrontMatter(input, '');
  expect(result).not.toContain('authors:');
});
  1. Test when defaultAuthor is undefined:
it('should not add authors when defaultAuthor is undefined', () => {
  const input = '---\ntitle: "Test"\n---\nContent';
  const result = convertFrontMatter(input, undefined);
  expect(result).not.toContain('authors:');
});
  1. Test with multiple existing authors:
it('should not add defaultAuthor when multiple authors exist', () => {
  const input = '---\ntitle: "Test"\nauthors: [Existing Author 1, Existing Author 2]\n---\nContent';
  const result = convertFrontMatter(input, 'Default Author');
  expect(result).toContain('authors: [Existing Author 1, Existing Author 2]');
  expect(result).not.toContain('Default Author');
});

396-441: Great job on implementing comprehensive tests for the defaultAuthor feature!

The new test suites for both FrontMatterConverter and convertFrontMatter functions effectively cover the defaultAuthor functionality. These additions align well with the PR objectives of introducing and testing the defaultAuthor feature.

The tests are well-structured, use clear assertions, and cover the main scenarios. With the suggested additional test cases for edge cases, the test coverage will be even more robust.

As the project grows, consider organizing related test cases into separate files or using nested describe blocks for better maintainability. For example, you could create a separate file for defaultAuthor-related tests or use a nested describe block like this:

describe('FrontMatterConverter', () => {
  // ... existing tests ...

  describe('defaultAuthor functionality', () => {
    // ... defaultAuthor-specific tests ...
  });
});

This structure will make it easier to locate and maintain specific test cases as the test suite expands.

src/FrontMatterConverter.ts (1)

Line range hint 157-174: Consistently format authors as an array in convertFrontMatter

Similarly, ensure that when setting frontMatter.authors in the convertFrontMatter function, the authors field is an array if that is the expected format.

Apply this diff to address the issue:

if (!frontMatter.authors && defaultAuthor && defaultAuthor.trim() !== '') {
-  frontMatter.authors = defaultAuthor;
+  frontMatter.authors = [defaultAuthor];
}
🧰 Tools
🪛 Biome

[error] 168-168: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 169-169: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 2a9fb3f and 8f4c7d0.

📒 Files selected for processing (5)
  • src/FrontMatterConverter.ts (4 hunks)
  • src/docusaurus/docusaurus.ts (1 hunks)
  • src/docusaurus/settings/DocusaurusSettings.ts (1 hunks)
  • src/settings.ts (2 hunks)
  • src/tests/FrontMatterConverter.test.ts (1 hunks)
🧰 Additional context used
🔇 Additional comments (6)
src/docusaurus/docusaurus.ts (2)

56-56: Verify the implementation of convertFrontMatter function.

To ensure the defaultAuthor parameter is correctly utilized in the convertFrontMatter function, it's important to verify its implementation.

Please run the following script to check the convertFrontMatter function:

Ensure that the defaultAuthor parameter is properly handled within the function.

✅ Verification successful

Implementation Verified

The defaultAuthor parameter is correctly utilized within the convertFrontMatter function.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of convertFrontMatter function

# Test: Search for the convertFrontMatter function definition
ast-grep --lang typescript --pattern $'export const convertFrontMatter = ($_, $_) => {
  $$$
}'

Length of output: 1409


56-56: LGTM! Verify defaultAuthor property initialization.

The addition of plugin.docusaurus.defaultAuthor to the convertFrontMatter function call aligns with the PR objectives. This change introduces the default author feature for Docusaurus conversion as intended.

To ensure the defaultAuthor property is properly initialized, please run the following script:

✅ Verification successful

: The defaultAuthor property is properly initialized with a default value and includes appropriate error handling in the convertFrontMatter function. No issues were found regarding its implementation and usage.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the initialization of the defaultAuthor property

# Test: Search for the initialization of the defaultAuthor property
rg --type typescript 'defaultAuthor.*=' src/

Length of output: 1409

src/settings.ts (2)

206-218: LGTM: Well-implemented new setting for default author

The addDefaultAuthorSetting() method is well-implemented and follows the established patterns in the class. It correctly handles the storage and retrieval of the default author value, provides clear descriptions and placeholders, and properly saves the settings when changed.


Line range hint 67-218: Summary: Default author setting successfully implemented

The implementation of the default author setting for Docusaurus conversion is well-done and meets the PR objectives. The new setting is seamlessly integrated into the existing settings interface and follows the established patterns in the codebase.

For improved code consistency, consider applying the following minor changes:

  1. Remove the Korean comment on line 67 as suggested earlier.
  2. Ensure consistent use of semicolons at the end of statements throughout the file.

Overall, great job on implementing this new feature!

src/FrontMatterConverter.ts (2)

67-67: Definition of defaultAuthor is appropriate

The addition of the defaultAuthor property enhances the configurability of the class.


74-80: Constructor updated correctly to include defaultAuthor

The constructor modification appropriately initializes the defaultAuthor property.

Comment on lines 171 to 172
if (!frontMatter.authors && defaultAuthor && defaultAuthor.trim() !== '') {
frontMatter.authors = defaultAuthor;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor to trim defaultAuthor once before the condition

To simplify the condition and avoid redundant trimming, consider trimming defaultAuthor before the condition check.

Suggested refactor:

+ defaultAuthor = defaultAuthor.trim();
if (!frontMatter.authors && defaultAuthor !== '') {
  frontMatter.authors = [defaultAuthor];
}

This ensures defaultAuthor is trimmed once, streamlining the condition.

Committable suggestion was skipped due to low confidence.

Comment on lines 98 to 101
if (!frontMatter.authors && this.defaultAuthor) {
frontMatter.authors = this.defaultAuthor;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure authors field is correctly formatted as an array

When assigning frontMatter.authors = this.defaultAuthor, verify that the authors field is in the expected format. If the authors front matter expects an array, consider wrapping this.defaultAuthor in an array to maintain consistency.

Apply this diff to fix the formatting:

if (!frontMatter.authors && this.defaultAuthor) {
-  frontMatter.authors = this.defaultAuthor;
+  frontMatter.authors = [this.defaultAuthor];
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!frontMatter.authors && this.defaultAuthor) {
frontMatter.authors = this.defaultAuthor;
}
if (!frontMatter.authors && this.defaultAuthor) {
frontMatter.authors = [this.defaultAuthor];
}

@songkg7 songkg7 added enhancement New feature or request docusaurus labels Oct 14, 2024
@songkg7 songkg7 self-requested a review October 14, 2024 01:28
@songkg7
Copy link
Owner

songkg7 commented Oct 14, 2024

Thank you for your contribution.
This PR is a really good idea. I'm eager to incorporate it once a few points are addressed.

In Docusaurus, 'authors' is fundamentally plural. Please modify the code to allow multiple authors by default instead of a single author. Reference is here.

Copy link
Owner

@songkg7 songkg7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refer to the comment and modify the code.

- Introduced AuthorStrategyFactory to separate author handling logic for Jekyll and Docusaurus
- Applied author strategies in FrontMatterConverter
- Added `authors` and `platform` fields to DocusaurusSettings and JekyllSettings
- Enhanced O2Settings with UI for author input specific to Jekyll and Docusaurus
- Added test cases for handling multiple authors
- Extended existing defaultAuthor functionality to support multiple authors
…or' into HEAD

# Conflicts:
#	src/FrontMatterConverter.ts
#	src/docusaurus/docusaurus.ts
#	src/docusaurus/settings/DocusaurusSettings.ts
#	src/settings.ts
#	src/tests/FrontMatterConverter.test.ts
@pull-request-size pull-request-size bot added size/L and removed size/M labels Oct 14, 2024
@doxxx93 doxxx93 changed the title Add default author feature for Docusaurus conversion feat: Add support for multiple authors and update settings UI Oct 14, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (12)
src/enums/PlatformType.ts (1)

1-6: LGTM! Consider translating the comment to English.

The PlatformType enum is well-structured and follows TypeScript naming conventions. It provides a clear and extensible way to represent different platform types.

Consider translating the comment to English for consistency and to ensure all team members can understand it. Here's a suggested translation:

// Additional platforms can be enumerated here.
src/strategies/authors/AuthorStrategy.ts (2)

3-5: Consider using an array for the authors parameter.

The AuthorStrategy interface looks good overall and aligns well with the strategy pattern. However, based on the PR comments and Docusaurus's support for multiple authors, consider modifying the authors parameter to be an array of strings instead of a single string.

export interface AuthorStrategy {
  applyAuthors(frontMatter: FrontMatter, authors: string[]): FrontMatter;
}

This change would allow for more flexibility in handling multiple authors, aligning better with Docusaurus's capabilities and the feedback provided in the PR comments.


1-6: Overall, the AuthorStrategy interface is well-defined.

The AuthorStrategy interface provides a clear and concise contract for implementing author strategies. It's appropriately placed in the project structure and imports the necessary FrontMatter type. The interface aligns well with the strategy pattern, allowing for flexible implementations of author application logic.

To fully address the PR objectives and comments:

  1. Consider modifying the authors parameter to be an array of strings, as suggested earlier.
  2. Ensure that implementations of this interface can handle both single and multiple authors effectively.
  3. Update related components and tests to work with the potentially modified interface.

These changes will enhance the flexibility of the author management system and better align with Docusaurus's capabilities.

src/strategies/authors/DefaultAuthorStrategy.ts (1)

1-8: Consider adding JSDoc comments

To improve code documentation and maintainability, consider adding JSDoc comments to the class and method.

Here's an example of how you could add JSDoc comments:

import { AuthorStrategy } from './AuthorStrategy';
import { FrontMatter } from '../../FrontMatterConverter';

/**
 * Implements a strategy for applying default authors to front matter.
 */
export class DefaultAuthorStrategy implements AuthorStrategy {
  /**
   * Applies the default authors to the front matter if no authors are present.
   * @param frontMatter - The original front matter.
   * @param authors - The default author(s) to apply.
   * @returns The updated front matter with authors applied if necessary.
   */
  applyAuthors(frontMatter: FrontMatter, authors: string | string[]): FrontMatter {
    // Implementation here
  }
}

These comments provide clear documentation about the purpose of the class and method, as well as the parameters and return value of the applyAuthors method.

src/strategies/authors/JekyllAuthorStrategy.ts (1)

7-7: Consider using undefined assignment instead of delete operator.

The static analysis tool flagged the use of the delete operator, which can have minor performance implications.

Consider replacing the delete operation with an undefined assignment:

- delete frontMatter.authors;
+ frontMatter.authors = undefined;

This change achieves the same result of removing the authors property while potentially offering a slight performance benefit.

🧰 Tools
🪛 Biome

[error] 7-7: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

src/strategies/authors/DocusaurusAuthorStrategy.ts (1)

5-14: Consider handling empty authors string and approve overall implementation.

The implementation looks good overall and accommodates multiple authors as requested. However, consider handling the case where the authors string is empty.

Here's a suggested improvement:

applyAuthors(frontMatter: FrontMatter, authors: string): FrontMatter {
  const authorsList = authors.split(',').map(author => author.trim()).filter(Boolean);
  frontMatter.author = undefined;
  if (authorsList.length === 0) {
    delete frontMatter.authors;
  } else if (authorsList.length === 1) {
    frontMatter.authors = authorsList[0];
  } else {
    frontMatter.authors = authorsList;
  }
  return frontMatter;
}

This version:

  1. Filters out empty author names.
  2. Handles empty authors string by removing the authors property.
  3. Uses undefined assignment instead of delete.
  4. Stores multiple authors as an array, which is more suitable for Docusaurus.
🧰 Tools
🪛 Biome

[error] 7-7: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

src/AuthorStrategyFactory.ts (1)

2-6: Remove empty lines in the import statement.

The import statement for AuthorStrategy contains unnecessary empty lines. Consider removing them to improve code readability.

Apply this diff to clean up the import statement:

 import {
   AuthorStrategy,
-
-
-
 } from './strategies/authors/AuthorStrategy';
src/jekyll/settings/JekyllSettings.ts (1)

Line range hint 1-85: Overall assessment: Enhance author handling and maintain consistency

The additions of authors and platform properties are good steps towards implementing the default author feature. However, to fully meet the PR objectives and maintain consistency within the JekyllSettings class, consider the following comprehensive refactor:

  1. Implement authors as an array of strings with proper encapsulation.
  2. Encapsulate the platform property.
  3. Add a method to handle default author logic, e.g.:
    getDefaultAuthor(): string | undefined {
      return this.authors.length > 0 ? this.authors[0] : undefined;
    }
  4. Update the class documentation to reflect these new capabilities.

These changes would provide a more robust implementation of the default author feature while maintaining the class's existing design patterns and improving its overall functionality.

src/settings.ts (3)

70-82: LGTM with suggestion: Consider array-based author storage for Jekyll.

The implementation of addJekyllAuthorsSettings is well-structured and consistent with other settings. However, to align with the PR objectives and the comment about Docusaurus using plural 'authors', consider storing the authors as an array instead of a comma-separated string. This would provide more flexibility and consistency across platforms.

Here's a suggested modification:

private addJekyllAuthorsSettings() {
  const jekyllSettings = this.plugin.jekyll as JekyllSettings;
  new Setting(this.containerEl)
    .setName('Jekyll Authors')
    .setDesc('Enter authors separated by commas. For single author, enter only one name.')
    .addText(text => text
      .setPlaceholder('author1, author2, ...')
      .setValue(jekyllSettings.authors.join(', '))
      .onChange(async (value) => {
        jekyllSettings.authors = value.split(',').map(author => author.trim()).filter(author => author);
        await this.plugin.saveSettings();
      }));
}

This change assumes jekyllSettings.authors is an array. You'll need to update the JekyllSettings class accordingly.


84-95: LGTM with suggestion: Consider array-based author storage for Docusaurus.

The implementation of addDocusaurusAuthorsSettings is well-structured and consistent with other settings. However, to fully align with the PR objectives and the comment about Docusaurus using plural 'authors', consider storing the authors as an array instead of a comma-separated string. This would provide more flexibility and better represent Docusaurus's typical usage.

Here's a suggested modification:

private addDocusaurusAuthorsSettings() {
  const docusaurusSettings = this.plugin.docusaurus as DocusaurusSettings;
  new Setting(this.containerEl)
    .setName('Docusaurus Authors')
    .setDesc('Enter authors separated by commas. For single author, enter only one name.')
    .addText(text => text
      .setPlaceholder('author1, author2, ...')
      .setValue(docusaurusSettings.authors.join(', '))
      .onChange(async (value) => {
        docusaurusSettings.authors = value.split(',').map(author => author.trim()).filter(author => author);
        await this.plugin.saveSettings();
      }));
}

This change assumes docusaurusSettings.authors is an array. You'll need to update the DocusaurusSettings class accordingly.


60-95: Overall: Good implementation with room for improvement

The changes successfully introduce author settings for both Jekyll and Docusaurus, meeting the primary objective of the PR. The implementations are consistent with existing code and well-integrated into the settings tab.

However, to fully address the PR objectives and the comment about Docusaurus typically using plural 'authors', consider the following improvements:

  1. Store authors as arrays instead of comma-separated strings for both Jekyll and Docusaurus.
  2. Update the JekyllSettings and DocusaurusSettings classes to reflect this change.
  3. Modify the UI to better represent multiple authors, possibly using a more advanced input method or displaying current authors as tags.

These changes would make the feature more flexible and better aligned with Docusaurus's conventions, while also improving the user experience for managing multiple authors.

src/tests/FrontMatterConverter.test.ts (1)

398-542: Comprehensive test coverage for author conversion

The new test suite for author/authors conversion is well-structured and covers various scenarios for both Jekyll and Docusaurus platforms. This aligns well with the PR objectives of introducing a default author feature.

However, there are a few points to consider:

  1. The implementation currently supports both single and multiple authors for both Jekyll and Docusaurus. This is good for flexibility but may not fully align with the typical usage patterns of these platforms.

  2. For Docusaurus, the tests are using authors (plural) which aligns with the feedback provided in the PR comments about Docusaurus typically using plural 'authors'.

  3. For Jekyll, the tests switch between author (singular) and authors (plural) depending on the number of authors. This might lead to inconsistencies in the front matter structure.

Consider the following improvements:

  1. For Jekyll, standardize on either author (singular) or authors (plural) for consistency, regardless of the number of authors. This will make the front matter structure more predictable.

  2. Add test cases for edge scenarios, such as:

    • Handling of empty author strings
    • Handling of author strings with extra whitespace
    • Preserving existing author information if no default author is provided
  3. Consider adding a test case that demonstrates how the converter behaves when an empty string is passed as the default author, to ensure it doesn't overwrite existing author information in such cases.

Example for handling empty author strings:

it('should handle empty author string', () => {
  const converter = new FrontMatterConverter('test-file', 'assets/img', false, false, '  ', PlatformType.Docusaurus);
  const input = `---
title: "Test Post"
---
Content`;
  const expected = `---
title: "Test Post"
---

Content`;
  expect(converter.convert(input)).toEqual(expected);
});

These additions would further improve the robustness of the test suite and ensure the feature handles various edge cases correctly.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 8f4c7d0 and 47f7c74.

📒 Files selected for processing (13)
  • src/AuthorStrategyFactory.ts (1 hunks)
  • src/FrontMatterConverter.ts (3 hunks)
  • src/docusaurus/docusaurus.ts (2 hunks)
  • src/docusaurus/settings/DocusaurusSettings.ts (1 hunks)
  • src/enums/PlatformType.ts (1 hunks)
  • src/jekyll/chirpy.ts (1 hunks)
  • src/jekyll/settings/JekyllSettings.ts (1 hunks)
  • src/settings.ts (1 hunks)
  • src/strategies/authors/AuthorStrategy.ts (1 hunks)
  • src/strategies/authors/DefaultAuthorStrategy.ts (1 hunks)
  • src/strategies/authors/DocusaurusAuthorStrategy.ts (1 hunks)
  • src/strategies/authors/JekyllAuthorStrategy.ts (1 hunks)
  • src/tests/FrontMatterConverter.test.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/FrontMatterConverter.ts
  • src/docusaurus/docusaurus.ts
  • src/docusaurus/settings/DocusaurusSettings.ts
🧰 Additional context used
🪛 Biome
src/AuthorStrategyFactory.ts

[error] 11-25: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

src/strategies/authors/DocusaurusAuthorStrategy.ts

[error] 7-7: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

src/strategies/authors/JekyllAuthorStrategy.ts

[error] 7-7: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (9)
src/strategies/authors/AuthorStrategy.ts (1)

1-1: LGTM: Import statement is correct.

The import of FrontMatter from the relative path '../../FrontMatterConverter' is appropriate and necessary for the interface definition.

src/strategies/authors/JekyllAuthorStrategy.ts (2)

1-4: LGTM: Imports and class declaration are correct.

The imports are appropriate, and the JekyllAuthorStrategy class correctly implements the AuthorStrategy interface.


1-15: Overall implementation aligns with PR objectives, with minor suggestions for improvement.

The JekyllAuthorStrategy class successfully implements the AuthorStrategy interface and contributes to the goal of flexible author management for Jekyll. The implementation handles both single and multiple authors, which aligns with the PR objective of accommodating multiple authors as suggested in the PR comments.

Two minor improvements were suggested:

  1. Revising the format of the authors property for better Jekyll compatibility.
  2. Considering the use of undefined assignment instead of the delete operator for potential performance benefits.

These changes will enhance the robustness and efficiency of the implementation.

🧰 Tools
🪛 Biome

[error] 7-7: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

src/strategies/authors/DocusaurusAuthorStrategy.ts (1)

1-4: LGTM: Imports and class declaration are well-structured.

The imports and class declaration follow TypeScript best practices. The class name DocusaurusAuthorStrategy accurately reflects its purpose.

src/AuthorStrategyFactory.ts (1)

12-24: LGTM: The createStrategy method logic is sound.

The method's logic is well-structured and covers all cases:

  1. It first checks for empty authors, returning a DefaultAuthorStrategy if true.
  2. It then uses a switch statement to return the appropriate strategy based on the platform.
  3. The default case provides a good fallback with DefaultAuthorStrategy.

The method adheres to the Single Responsibility Principle and is easy to understand.

src/jekyll/settings/JekyllSettings.ts (1)

2-2: LGTM: Import statement for PlatformType

The import of PlatformType is correctly added and necessary for the new platform property.

src/jekyll/chirpy.ts (1)

27-28: Clarify the scope of author-related changes

The addition of authors and platform parameters to the FrontMatterConverter constructor aligns with the PR objective of adding a default author feature. However, there's a discrepancy between the PR summary (which mentions Docusaurus) and this file (which is for Jekyll/Chirpy conversion).

  1. Could you clarify if the author-related changes are intended for both Docusaurus and Jekyll/Chirpy, or if there's a separate implementation for Docusaurus?
  2. What is the purpose of the platform parameter? It's not mentioned in the PR objectives or comments.

To ensure consistency across the codebase, please run the following script:

This script will help verify if similar changes have been made for Docusaurus and if the authors and platform properties are consistently used across the codebase.

✅ Verification successful

Verification of 'authors' and 'platform' Parameters Usage

The shell script results confirm that the authors and platform parameters are consistently utilized across both Docusaurus and Jekyll implementations. This alignment ensures that the FrontMatterConverter functions correctly for each platform, supporting the PR objectives of adding default author features and maintaining platform-specific configurations.

  • Consistency Across Platforms: Both Docusaurus and Jekyll settings files incorporate the authors and platform parameters.
  • Purpose of platform: Differentiates configurations for Docusaurus and Jekyll, ensuring appropriate behavior based on the target platform.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for similar changes in Docusaurus-related files and verify the usage of 'authors' and 'platform' parameters

# Search for FrontMatterConverter usage in Docusaurus-related files
echo "Checking FrontMatterConverter usage in Docusaurus files:"
rg --type typescript "new FrontMatterConverter" src/docusaurus

# Search for 'authors' property in settings files
echo "\nChecking 'authors' property in settings files:"
rg --type typescript "authors.*:" src/

# Search for 'platform' property in settings files
echo "\nChecking 'platform' property in settings files:"
rg --type typescript "platform.*:" src/

Length of output: 603


Script:

#!/bin/bash
# Description: Check for similar changes in Docusaurus-related files and verify the usage of 'authors' and 'platform' parameters

# Search for FrontMatterConverter usage in Docusaurus-related files
echo "Checking FrontMatterConverter usage in Docusaurus files:"
rg --type ts "new FrontMatterConverter" src/docusaurus

# Search for 'authors' property in settings files
echo "\nChecking 'authors' property in settings files:"
rg --type ts "authors.*:" src/

# Search for 'platform' property in settings files
echo "\nChecking 'platform' property in settings files:"
rg --type ts "platform.*:" src/

Length of output: 2332

src/settings.ts (1)

60-60: LGTM: New author settings integrated correctly.

The new method calls for Jekyll and Docusaurus author settings are appropriately placed within their respective sections. This change aligns well with the PR objectives and maintains the existing structure of the settings tab.

Also applies to: 68-69

src/tests/FrontMatterConverter.test.ts (1)

398-542: Overall assessment of the author conversion feature

The new test suite for author/authors conversion is a valuable addition that aligns well with the PR objectives. It provides good coverage for both Jekyll and Docusaurus platforms and tests various scenarios for adding and overwriting author information.

However, to fully address the feedback in the PR comments and ensure robustness, consider the following:

  1. Standardize the author field name (author vs authors) for each platform to ensure consistency.
  2. Add more edge case tests as suggested in the previous comment.
  3. Ensure that the implementation aligns with Docusaurus's preference for multiple authors by default.

To verify the implementation aligns with Docusaurus documentation, please run the following script:

This will help ensure that the implementation is consistent with Docusaurus best practices.

@@ -0,0 +1,6 @@
export enum PlatformType {
Default,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Clarify the Purpose of PlatformType.Default

The PlatformType.Default enum member is used in src/FrontMatterConverter.ts:

  • platform: PlatformType = PlatformType.Default

Consider renaming it to a more specific name or adding a comment to explain its purpose.

🔗 Analysis chain

Clarify the purpose of the Default enum member.

The Default enum member might be ambiguous. It's not clear what the default platform is or when it would be used.

Could you provide more context on the intended use of the Default member? If it's not necessary, consider removing it. If it is needed, consider renaming it to something more specific or adding a comment to explain its purpose.

To help understand the usage, let's search for its occurrences in the codebase:


Action Required: Please run the following shell script to search for usages of PlatformType.Default in TypeScript files.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usages of PlatformType.Default
rg --type typescript "PlatformType\.Default"

Length of output: 81


Script:

#!/bin/bash
# Search for usages of PlatformType.Default in TypeScript files
rg "PlatformType\.Default" --glob "*.ts" --glob "*.tsx"

Length of output: 135

Comment on lines +1 to +8
import { AuthorStrategy } from './AuthorStrategy';
import { FrontMatter } from '../../FrontMatterConverter';

export class DefaultAuthorStrategy implements AuthorStrategy {
applyAuthors(frontMatter: FrontMatter, authors: string): FrontMatter {
return frontMatter;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implementation doesn't fulfill the PR objectives

The current implementation of DefaultAuthorStrategy doesn't align with the PR objectives to set a default author. The applyAuthors method should modify the frontMatter to include the default author information.

Consider updating the applyAuthors method to add the author information to the frontMatter. Here's a suggested implementation:

applyAuthors(frontMatter: FrontMatter, authors: string): FrontMatter {
  if (!frontMatter.authors && authors) {
    return { ...frontMatter, authors: [authors] };
  }
  return frontMatter;
}

This implementation adds the default author to the frontMatter if no authors are present.

Comment on lines +5 to +7
applyAuthors(frontMatter: FrontMatter, authors: string): FrontMatter {
return frontMatter;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

applyAuthors method doesn't use the authors parameter

The current implementation of applyAuthors doesn't utilize the authors parameter, which defeats the purpose of having a default author strategy.

Update the method to use the authors parameter as demonstrated in the previous comment. Additionally, consider handling multiple authors as suggested in the PR comments:

applyAuthors(frontMatter: FrontMatter, authors: string | string[]): FrontMatter {
  if (!frontMatter.authors) {
    const authorList = Array.isArray(authors) ? authors : [authors];
    return { ...frontMatter, authors: authorList };
  }
  return frontMatter;
}

This implementation supports both single and multiple default authors, aligning with Docusaurus's use of plural 'authors'.

Comment on lines +5 to +14
applyAuthors(frontMatter: FrontMatter, authors: string): FrontMatter {
const authorsList = authors.split(',').map(author => author.trim());
delete frontMatter.authors;
if (authorsList.length === 1) {
frontMatter.author = authorsList[0];
} else {
frontMatter.authors = `[${authorsList.join(', ')}]`;
}
return frontMatter;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider revising the authors property format for Jekyll compatibility.

The implementation handles both single and multiple authors correctly. However, the format for multiple authors might not be compatible with Jekyll's expected format.

Jekyll typically expects multiple authors to be in a YAML array format. Consider modifying line 11 to:

- frontMatter.authors = `[${authorsList.join(', ')}]`;
+ frontMatter.authors = authorsList;

This change ensures that the authors property is set as an array, which is more compatible with Jekyll's YAML front matter parsing.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
applyAuthors(frontMatter: FrontMatter, authors: string): FrontMatter {
const authorsList = authors.split(',').map(author => author.trim());
delete frontMatter.authors;
if (authorsList.length === 1) {
frontMatter.author = authorsList[0];
} else {
frontMatter.authors = `[${authorsList.join(', ')}]`;
}
return frontMatter;
}
applyAuthors(frontMatter: FrontMatter, authors: string): FrontMatter {
const authorsList = authors.split(',').map(author => author.trim());
delete frontMatter.authors;
if (authorsList.length === 1) {
frontMatter.author = authorsList[0];
} else {
frontMatter.authors = authorsList;
}
return frontMatter;
}
🧰 Tools
🪛 Biome

[error] 7-7: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

if (authorsList.length === 1) {
frontMatter.authors = authorsList[0];
} else {
frontMatter.authors = `[${authorsList.join(', ')}]`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Reconsider the representation of multiple authors for Docusaurus.

The current implementation encloses multiple authors in square brackets as a string. However, Docusaurus typically expects an array of strings for multiple authors.

Consider modifying the implementation to use an actual array:

-      frontMatter.authors = `[${authorsList.join(', ')}]`;
+      frontMatter.authors = authorsList;

This change ensures that the authors field is correctly formatted for Docusaurus.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
frontMatter.authors = `[${authorsList.join(', ')}]`;
frontMatter.authors = authorsList;

Comment on lines +11 to +25
export class AuthorStrategyFactory {
static createStrategy(platform: PlatformType, authors: string): AuthorStrategy {
if (!authors) {
return new DefaultAuthorStrategy();
}
switch (platform) {
case PlatformType.Jekyll:
return new JekyllAuthorStrategy();
case PlatformType.Docusaurus:
return new DocusaurusAuthorStrategy();
default:
return new DefaultAuthorStrategy();
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider refactoring the class into a simple function.

The AuthorStrategyFactory class contains only a single static method. To improve code simplicity and follow functional programming principles, consider refactoring this class into a simple function.

Apply this diff to refactor the class into a function:

-export class AuthorStrategyFactory {
-  static createStrategy(platform: PlatformType, authors: string): AuthorStrategy {
+export function createAuthorStrategy(platform: PlatformType, authors: string): AuthorStrategy {
     if (!authors) {
       return new DefaultAuthorStrategy();
     }
     switch (platform) {
       case PlatformType.Jekyll:
         return new JekyllAuthorStrategy();
       case PlatformType.Docusaurus:
         return new DocusaurusAuthorStrategy();
       default:
         return new DefaultAuthorStrategy();
     }
   }
-}

This change addresses the static analysis warning and simplifies the code structure.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export class AuthorStrategyFactory {
static createStrategy(platform: PlatformType, authors: string): AuthorStrategy {
if (!authors) {
return new DefaultAuthorStrategy();
}
switch (platform) {
case PlatformType.Jekyll:
return new JekyllAuthorStrategy();
case PlatformType.Docusaurus:
return new DocusaurusAuthorStrategy();
default:
return new DefaultAuthorStrategy();
}
}
}
export function createAuthorStrategy(platform: PlatformType, authors: string): AuthorStrategy {
if (!authors) {
return new DefaultAuthorStrategy();
}
switch (platform) {
case PlatformType.Jekyll:
return new JekyllAuthorStrategy();
case PlatformType.Docusaurus:
return new DocusaurusAuthorStrategy();
default:
return new DefaultAuthorStrategy();
}
}
🧰 Tools
🪛 Biome

[error] 11-25: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


export default class JekyllSettings implements O2PluginSettings {
private _jekyllPath: string;
private _jekyllRelativeResourcePath: string;
authors: string = '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Consider revising the authors property implementation

While the plural name authors aligns with the suggestion to support multiple authors, the current implementation as a string may not be the most suitable for representing multiple authors. Additionally, the property is public, which is inconsistent with the encapsulation pattern used for other properties in this class.

Consider the following improvements:

  1. Change the type to an array of strings: authors: string[] = [];
  2. Make the property private and add getter/setter methods for consistency:
    private _authors: string[] = [];
    
    get authors(): string[] {
      return this._authors;
    }
    
    set authors(value: string[]) {
      this._authors = value;
    }

These changes would better support multiple authors and maintain consistency with the class's existing design patterns.


export default class JekyllSettings implements O2PluginSettings {
private _jekyllPath: string;
private _jekyllRelativeResourcePath: string;
authors: string = '';
platform: PlatformType = PlatformType.Jekyll;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider encapsulating the platform property

The platform property is correctly typed and initialized. However, to maintain consistency with the class's existing design patterns, consider encapsulating this property:

private _platform: PlatformType = PlatformType.Jekyll;

get platform(): PlatformType {
  return this._platform;
}

set platform(value: PlatformType) {
  this._platform = value;
}

This change would align the platform property with the encapsulation pattern used for other properties in this class, improving overall consistency and maintainability.

Copy link
Owner

@songkg7 songkg7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the biggest changes that occurred when o2 transitioned from 1.9 to 2.0 was the shift from an object-oriented programming(OOP) to a functional programming(FP). However, looking at the code you've written, it still feels object-oriented. Please refactor it to be more function-oriented, referring to the comments left by coderabbit and the existing code.

If applying these suggestions feels difficult or burdensome, please feel free to close this PR and make lighter modifications instead.

@@ -0,0 +1,6 @@
export enum PlatformType {
Copy link
Owner

@songkg7 songkg7 Oct 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in TS, as const is better than enum type. as follows:

export const PlatformType = {
  DEFAULT, DOCUSAURUS, JEKYLL
}

or refer to src/core/ObsidianRegex.ts

Comment on lines +70 to +95
private addJekyllAuthorsSettings() {
const jekyllSettings = this.plugin.jekyll as JekyllSettings;
new Setting(this.containerEl)
.setName('Jekyll Authors')
.setDesc('Enter authors separated by commas. For single author, enter only one name.')
.addText(text => text
.setPlaceholder('author1, author2, ...')
.setValue(jekyllSettings.authors)
.onChange(async (value) => {
jekyllSettings.authors = value;
await this.plugin.saveSettings();
}));
}

private addDocusaurusAuthorsSettings() {
const docusaurusSettings = this.plugin.docusaurus as DocusaurusSettings;
new Setting(this.containerEl)
.setName('Docusaurus Authors')
.setDesc('Enter authors separated by commas. For single author, enter only one name.')
.addText(text => text
.setPlaceholder('author1, author2, ...')
.setValue(docusaurusSettings.authors)
.onChange(async (value) => {
docusaurusSettings.authors = value;
await this.plugin.saveSettings();
}));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@doxxx93 doxxx93 closed this Oct 15, 2024
@doxxx93 doxxx93 deleted the feat/docusaurus-add-default-author branch October 15, 2024 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants