Skip to content

Clean up command factory #3431

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

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from
Draft

Clean up command factory #3431

wants to merge 27 commits into from

Conversation

john-traas
Copy link
Contributor

@john-traas john-traas commented Feb 4, 2025

This PR adds utility functions that use built in functions from prosemirror to handle operations related to creating/removing and toggling between list types in the text editor.

Tests are also added for this functionality.

Fixes: #3313

Summary by CodeRabbit

  • New Features

    • Enhanced text editor behavior with improved list management—keyboard shortcuts now offer intuitive indenting, outdenting, splitting, and joining of list items.
    • Commands are now context-aware, enabling smarter, condition-based execution.
    • Link insertion has been refined with stronger URL validation for smoother pasting of links.
  • Documentation

    • Updated user guidance and release notes to reflect these text editor improvements.
  • Chores

    • Package version and dependency updates for increased overall stability.

Copy link

github-actions bot commented Feb 4, 2025

Documentation has been published to https://lundalogik.github.io/lime-elements/versions/PR-3431/

@john-traas john-traas force-pushed the clean-up-command-factory branch 2 times, most recently from 48cb384 to c6a8a28 Compare February 11, 2025 10:55
@john-traas john-traas marked this pull request as ready for review February 11, 2025 11:05
@john-traas john-traas force-pushed the clean-up-command-factory branch from c6a8a28 to 24b1710 Compare February 11, 2025 13:18
@adrianschmidt adrianschmidt force-pushed the main branch 3 times, most recently from 197298f to a0e1088 Compare February 13, 2025 18:06
Copy link
Contributor

@adrianschmidt adrianschmidt Feb 15, 2025

Choose a reason for hiding this comment

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

Why move tests into a folder called __tests__? Is that a prosemirror convention? Because we don't use that pattern anywhere else in lime-elements… 🧐

Copy link
Contributor Author

@john-traas john-traas Feb 15, 2025

Choose a reason for hiding this comment

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

Ah... The initial folder/file was generated by cursor when I had it help me setup the boilerplate for the tests. We should follow the normal pattern we use and have the tests alongside the files they are testing.

@adrianschmidt
Copy link
Contributor

If you try to make sub-lists, the behaviour quickly gets quite weird 🤔

Screen.Recording.2025-02-15.at.22.05.14.mov

@adrianschmidt adrianschmidt force-pushed the clean-up-command-factory branch from ed54b1f to fba00f3 Compare February 15, 2025 21:08
@john-traas
Copy link
Contributor Author

If you try to make sub-lists, the behaviour quickly gets quite weird 🤔

Screen.Recording.2025-02-15.at.22.05.14.mov

I think I have some ideas of why this is happening. I'll take a look again on Monday.

@adrianschmidt
Copy link
Contributor

adrianschmidt commented Feb 16, 2025

Yeah, I don't expect you to be working on the weekend just because I am 😂 No stress my friend! 🤗

@john-traas john-traas force-pushed the clean-up-command-factory branch 2 times, most recently from 8eb4802 to 07b8313 Compare February 21, 2025 15:19
john-traas and others added 13 commits March 25, 2025 13:46
## [38.6.0](v38.5.0...v38.6.0) (2025-03-25)

### Features

* **text editor:** conditionally allow commands ([819f599](819f599))
Bumps [@eslint/eslintrc](https://github.com/eslint/eslintrc) from 3.3.0 to 3.3.1.
- [Release notes](https://github.com/eslint/eslintrc/releases)
- [Changelog](https://github.com/eslint/eslintrc/blob/main/CHANGELOG.md)
- [Commits](eslint/eslintrc@v3.3.0...v3.3.1)

---
updated-dependencies:
- dependency-name: "@eslint/eslintrc"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Bumps [@microsoft/api-extractor](https://github.com/microsoft/rushstack/tree/HEAD/apps/api-extractor) from 7.52.1 to 7.52.2.
- [Changelog](https://github.com/microsoft/rushstack/blob/main/apps/api-extractor/CHANGELOG.md)
- [Commits](https://github.com/microsoft/rushstack/commits/@microsoft/api-extractor_v7.52.2/apps/api-extractor)

---
updated-dependencies:
- dependency-name: "@microsoft/api-extractor"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
@john-traas john-traas force-pushed the clean-up-command-factory branch from 07b8313 to 2545fc2 Compare March 26, 2025 15:30
Copy link

coderabbitai bot commented Mar 26, 2025

📝 Walkthrough

Walkthrough

This PR increments the project version to 38.6.0 and updates the changelog, package.json, and sonar configuration accordingly. It introduces new utility functions and refactors for the ProseMirror text editor—improving list command handling (including toggling between ordered and unordered lists), link validation, node and selection utilities, and menu state tracking. Additionally, a broad suite of new test files and documents has been added to support command testing, content generation, editor state/view building, event simulation, and schema creation.

Changes

File(s) Change Summary
CHANGELOG.md, package.json, sonar-project.properties Updated version from 38.5.0 to 38.6.0; added changelog entry for new text editor command feature; updated dependency and sonar.projectVersion values.
src/components/text-editor/list-functionality*.md Added documents outlining list functionality progress, implementation plans, and detailed feature descriptions for list management.
src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/{active-state-utils,link-utils,list-utils,node-utils,selection-utils}.ts Introduced new utility functions for managing active states, link validation, list operations, node traversal, and selection adjustments.
src/components/text-editor/prosemirror-adapter/menu/menu-commands.ts, src/components/text-editor/prosemirror-adapter/menu/menu-list-commands.spec.ts Refactored list command handling to use new handlers (handleListNoSelection, handleListWithSelection); updated command interface to include an allowed method; added tests for list command behavior.
src/components/text-editor/prosemirror-adapter/plugins/{link-plugin,list-key-handler,menu-state-tracking-plugin,table-plugin}.ts and their corresponding spec files Added new plugins for list key handling, menu state tracking, and table functionality; modified import sources for link validation; exported previously private functions; added comprehensive tests for plugin behavior.
src/components/text-editor/prosemirror-adapter/prosemirror-adapter.tsx Integrated the new list key handler plugin and updated the action bar update method to incorporate allowed types filtering.
src/components/text-editor/test-setup/** Added extensive test infrastructure including command testers, content generators, editor state/view builders, event simulators, schema builders, and accompanying documentation/logs for overall testing utilities.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Editor
    participant CmdHandler as List Command Handler
    participant Util as List Utility Functions

    User->>Editor: Trigger toggle list command
    Editor->>CmdHandler: Dispatch command request
    CmdHandler->>Util: Check selection state (list vs. no selection)
    Util-->>CmdHandler: Return list context details
    CmdHandler->>Editor: Apply list type conversion (ordered ↔ unordered)
    Editor-->>User: Updated document state
Loading

Assessment against linked issues

Objective (#3313) Addressed Explanation
Allow switching between unordered and ordered lists within the text editor

Possibly related PRs

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • 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 generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

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.

@john-traas john-traas marked this pull request as draft March 26, 2025 15:30
Copy link

@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: 33

🔭 Outside diff range comments (1)
src/components/text-editor/list-functionality-implementation-plan.md (1)

163-174: 🧹 Nitpick (assertive)

Missing language specification for code block

The final code block is missing a language specification, which is required by markdown standards. Also, the code block appears to be incomplete as the implementation details are not shown.

-   ```
+   ```typescript
+   // Add implementation details for keyboard shortcuts
+   ```
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

173-173: Fenced code blocks should be surrounded by blank lines
null

(MD031, blanks-around-fences)


173-173: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f556c7a and 2545fc2.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (37)
  • CHANGELOG.md (1 hunks)
  • package.json (2 hunks)
  • sonar-project.properties (1 hunks)
  • src/components/text-editor/list-functionality-development-log.md (1 hunks)
  • src/components/text-editor/list-functionality-implementation-plan.md (1 hunks)
  • src/components/text-editor/list-functionality.md (1 hunks)
  • src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/active-state-utils.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/link-utils.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/list-utils.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/node-utils.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/selection-utils.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/menu/menu-commands.ts (4 hunks)
  • src/components/text-editor/prosemirror-adapter/menu/menu-list-commands.spec.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/plugins/link-plugin.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/plugins/list-key-handler.spec.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/plugins/list-key-handler.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/plugins/menu-state-tracking-plugin.spec.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/plugins/menu-state-tracking-plugin.ts (3 hunks)
  • src/components/text-editor/prosemirror-adapter/plugins/table-plugin.spec.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/plugins/table-plugin.ts (1 hunks)
  • src/components/text-editor/prosemirror-adapter/prosemirror-adapter.tsx (2 hunks)
  • src/components/text-editor/test-setup/command-tester.spec.ts (1 hunks)
  • src/components/text-editor/test-setup/command-tester.ts (1 hunks)
  • src/components/text-editor/test-setup/content-generator.spec.ts (1 hunks)
  • src/components/text-editor/test-setup/content-generator.ts (1 hunks)
  • src/components/text-editor/test-setup/editor-state-builder.spec.ts (1 hunks)
  • src/components/text-editor/test-setup/editor-state-builder.ts (1 hunks)
  • src/components/text-editor/test-setup/editor-view-builder.spec.ts (1 hunks)
  • src/components/text-editor/test-setup/editor-view-builder.ts (1 hunks)
  • src/components/text-editor/test-setup/event-simulator.spec.ts (1 hunks)
  • src/components/text-editor/test-setup/event-simulator.ts (1 hunks)
  • src/components/text-editor/test-setup/schema-builder.spec.ts (1 hunks)
  • src/components/text-editor/test-setup/schema-builder.ts (1 hunks)
  • src/components/text-editor/test-setup/test-utils-development-log.md (1 hunks)
  • src/components/text-editor/test-setup/test-utils.md (1 hunks)
  • src/components/text-editor/test-setup/testing-utils-development-log.md (1 hunks)
  • src/components/text-editor/test-setup/testing-utils-guide.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
`**/*.{ts,tsx}`: Imports from other files in the same module (lime-elements) must use relative paths. Using absolute paths for imports will cause the production build to fail.

**/*.{ts,tsx}: Imports from other files in the same module (lime-elements) must use relative paths. Using absolute paths for imports will cause the production build to fail.

  • src/components/text-editor/prosemirror-adapter/plugins/table-plugin.spec.ts
  • src/components/text-editor/prosemirror-adapter/menu/menu-list-commands.spec.ts
  • src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/link-utils.ts
  • src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/node-utils.ts
  • src/components/text-editor/test-setup/editor-view-builder.ts
  • src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/selection-utils.ts
  • src/components/text-editor/test-setup/schema-builder.spec.ts
  • src/components/text-editor/test-setup/schema-builder.ts
  • src/components/text-editor/prosemirror-adapter/plugins/menu-state-tracking-plugin.spec.ts
  • src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/active-state-utils.ts
  • src/components/text-editor/prosemirror-adapter/plugins/table-plugin.ts
  • src/components/text-editor/prosemirror-adapter/plugins/list-key-handler.spec.ts
  • src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/list-utils.ts
  • src/components/text-editor/test-setup/command-tester.spec.ts
  • src/components/text-editor/prosemirror-adapter/plugins/list-key-handler.ts
  • src/components/text-editor/test-setup/command-tester.ts
  • src/components/text-editor/prosemirror-adapter/plugins/link-plugin.ts
  • src/components/text-editor/test-setup/event-simulator.spec.ts
  • src/components/text-editor/prosemirror-adapter/plugins/menu-state-tracking-plugin.ts
  • src/components/text-editor/prosemirror-adapter/prosemirror-adapter.tsx
  • src/components/text-editor/test-setup/event-simulator.ts
  • src/components/text-editor/test-setup/editor-state-builder.ts
  • src/components/text-editor/test-setup/content-generator.ts
  • src/components/text-editor/test-setup/editor-state-builder.spec.ts
  • src/components/text-editor/test-setup/content-generator.spec.ts
  • src/components/text-editor/prosemirror-adapter/menu/menu-commands.ts
  • src/components/text-editor/test-setup/editor-view-builder.spec.ts
`**/*.tsx`: Our `.tsx` files are typically using StencilJS, not React.

**/*.tsx: Our .tsx files are typically using StencilJS, not React.

  • src/components/text-editor/prosemirror-adapter/prosemirror-adapter.tsx
🧬 Code Definitions (16)
src/components/text-editor/prosemirror-adapter/plugins/table-plugin.spec.ts (1)
src/components/text-editor/prosemirror-adapter/plugins/table-plugin.ts (3)
  • getTableEditingPlugins (4-10)
  • getTableNodes (22-31)
  • createStyleAttribute (12-20)
src/components/text-editor/prosemirror-adapter/menu/menu-list-commands.spec.ts (1)
src/components/text-editor/prosemirror-adapter/menu/menu-commands.ts (1)
  • createListCommand (305-347)
src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/link-utils.ts (1)
src/components/text-editor/prosemirror-adapter/menu/menu-commands.ts (1)
  • isExternalLink (108-110)
src/components/text-editor/test-setup/editor-view-builder.ts (2)
src/components/text-editor/test-setup/editor-state-builder.ts (1)
  • createEditorState (14-29)
src/components/text-editor/test-setup/schema-builder.ts (1)
  • createTestSchema (12-33)
src/components/text-editor/test-setup/schema-builder.spec.ts (1)
src/components/text-editor/test-setup/schema-builder.ts (2)
  • createTestSchema (12-33)
  • createCustomTestSchema (42-87)
src/components/text-editor/prosemirror-adapter/plugins/menu-state-tracking-plugin.spec.ts (1)
src/components/text-editor/prosemirror-adapter/plugins/menu-state-tracking-plugin.ts (2)
  • getMenuItemStates (20-35)
  • createMenuStateTrackingPlugin (37-76)
src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/active-state-utils.ts (1)
src/components/text-editor/prosemirror-adapter/menu/menu-commands.ts (1)
  • CommandWithActive (34-37)
src/components/text-editor/prosemirror-adapter/plugins/list-key-handler.spec.ts (1)
src/components/text-editor/prosemirror-adapter/plugins/list-key-handler.ts (4)
  • isInListItem (15-30)
  • isEmptyListItem (35-55)
  • isAtStartOfListItem (60-81)
  • createListKeyHandlerPlugin (93-178)
src/components/text-editor/test-setup/command-tester.spec.ts (3)
src/components/text-editor/test-setup/editor-state-builder.ts (1)
  • createEditorState (14-29)
src/components/text-editor/test-setup/command-tester.ts (4)
  • getCommandResult (29-60)
  • testCommand (74-120)
  • testCommandWithView (130-185)
  • createCommandTester (193-202)
src/components/text-editor/test-setup/editor-view-builder.ts (1)
  • cleanupEditorView (84-93)
src/components/text-editor/test-setup/command-tester.ts (1)
src/components/text-editor/test-setup/editor-view-builder.ts (1)
  • createEditorView (14-46)
src/components/text-editor/test-setup/event-simulator.spec.ts (3)
src/components/text-editor/test-setup/editor-state-builder.ts (1)
  • createEditorState (14-29)
src/components/text-editor/test-setup/editor-view-builder.ts (2)
  • createEditorView (14-46)
  • cleanupEditorView (84-93)
src/components/text-editor/test-setup/event-simulator.ts (6)
  • simulateKeyPress (63-84)
  • KeyModifiers (48-53)
  • PasteData (89-93)
  • simulatePaste (102-139)
  • simulateClick (152-191)
  • simulateDragAndDrop (204-288)
src/components/text-editor/prosemirror-adapter/prosemirror-adapter.tsx (1)
src/components/text-editor/prosemirror-adapter/plugins/table-plugin.ts (1)
  • getTableEditingPlugins (4-10)
src/components/text-editor/test-setup/editor-state-builder.ts (1)
src/components/text-editor/test-setup/schema-builder.ts (1)
  • createTestSchema (12-33)
src/components/text-editor/test-setup/editor-state-builder.spec.ts (2)
src/components/text-editor/test-setup/editor-state-builder.ts (4)
  • createEditorState (14-29)
  • createEditorStateWithSelection (41-59)
  • setTextSelection (69-77)
  • createDocumentWithText (100-107)
src/components/text-editor/test-setup/schema-builder.ts (1)
  • createCustomTestSchema (42-87)
src/components/text-editor/test-setup/content-generator.spec.ts (2)
src/components/text-editor/test-setup/content-generator.ts (8)
  • createDocWithText (13-18)
  • createDocWithHTML (27-31)
  • MarkSpec (36-39)
  • createDocWithFormattedText (49-61)
  • createDocWithBulletList (97-118)
  • createDocWithHeading (128-144)
  • createDocWithBlockquote (153-166)
  • createDocWithCodeBlock (175-187)
src/components/text-editor/test-setup/schema-builder.ts (1)
  • createCustomTestSchema (42-87)
src/components/text-editor/test-setup/editor-view-builder.spec.ts (2)
src/components/text-editor/test-setup/editor-view-builder.ts (4)
  • cleanupEditorView (84-93)
  • createEditorView (14-46)
  • createDispatchSpy (54-75)
  • mockProseMirrorDOMEnvironment (101-143)
src/components/text-editor/test-setup/editor-state-builder.ts (1)
  • createEditorState (14-29)
🪛 GitHub Actions: Pull Request Checks
src/components/text-editor/prosemirror-adapter/menu/menu-list-commands.spec.ts

[error] 152-152: Expected: 'ordered_list', Received: 'bullet_list'


[error] 262-262: Expected: 'paragraph', Received: 'bullet_list'


[error] 386-386: Expected: 'bullet_list', Received: 'paragraph'

src/components/text-editor/prosemirror-adapter/plugins/list-key-handler.spec.ts

[error] 106-106: Expected: true, Received: false


[error] 435-435: Expected number of calls: >= 1, Received number of calls: 0


[error] 476-476: Expected number of calls: >= 1, Received number of calls: 0

🪛 markdownlint-cli2 (0.17.2)
CHANGELOG.md

1-1: First line in a file should be a top-level heading
null

(MD041, first-line-heading, first-line-h1)


3-3: Multiple consecutive blank lines
Expected: 1; Actual: 2

(MD012, no-multiple-blanks)


6-6: Multiple consecutive blank lines
Expected: 1; Actual: 2

(MD012, no-multiple-blanks)

src/components/text-editor/list-functionality-implementation-plan.md

62-62: Fenced code blocks should be surrounded by blank lines
null

(MD031, blanks-around-fences)


103-103: Fenced code blocks should be surrounded by blank lines
null

(MD031, blanks-around-fences)


138-138: Fenced code blocks should be surrounded by blank lines
null

(MD031, blanks-around-fences)


173-173: Fenced code blocks should be surrounded by blank lines
null

(MD031, blanks-around-fences)


173-173: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

src/components/text-editor/test-setup/testing-utils-guide.md

12-12: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


12-12: Lists should be surrounded by blank lines
null

(MD032, blanks-around-lists)


13-13: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


16-16: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


16-16: Lists should be surrounded by blank lines
null

(MD032, blanks-around-lists)


17-17: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


20-20: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


20-20: Lists should be surrounded by blank lines
null

(MD032, blanks-around-lists)


21-21: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


24-24: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


24-24: Lists should be surrounded by blank lines
null

(MD032, blanks-around-lists)


25-25: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


26-26: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


27-27: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


30-30: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


30-30: Lists should be surrounded by blank lines
null

(MD032, blanks-around-lists)


31-31: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


34-34: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


34-34: Lists should be surrounded by blank lines
null

(MD032, blanks-around-lists)


35-35: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


38-38: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


38-38: Lists should be surrounded by blank lines
null

(MD032, blanks-around-lists)


39-39: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


41-41: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/2/3

(MD029, ol-prefix)


45-45: Ordered list item prefix
Expected: 2; Actual: 3; Style: 1/2/3

(MD029, ol-prefix)


49-49: Ordered list item prefix
Expected: 3; Actual: 4; Style: 1/2/3

(MD029, ol-prefix)


54-54: Ordered list item prefix
Expected: 4; Actual: 5; Style: 1/2/3

(MD029, ol-prefix)


60-60: Ordered list item prefix
Expected: 5; Actual: 6; Style: 1/2/3

(MD029, ol-prefix)


62-62: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


65-65: Ordered list item prefix
Expected: 6; Actual: 7; Style: 1/2/3

(MD029, ol-prefix)


69-69: Ordered list item prefix
Expected: 7; Actual: 8; Style: 1/2/3

(MD029, ol-prefix)

🪛 Biome (1.9.4)
src/components/text-editor/test-setup/editor-view-builder.ts

[error] 90-90: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/list-utils.ts

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

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

src/components/text-editor/test-setup/editor-state-builder.ts

[error] 101-101: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)

src/components/text-editor/test-setup/content-generator.ts

[error] 130-130: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)

src/components/text-editor/test-setup/content-generator.spec.ts

[error] 119-119: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/components/text-editor/test-setup/editor-view-builder.spec.ts

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

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


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

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🪛 LanguageTool
src/components/text-editor/test-setup/test-utils-development-log.md

[style] ~112-~112: Consider an alternative adverb to strengthen your wording.
Context: ...anupEditorView(view, container?)** - Properly cleans up the editor view to prevent me...

(PROPERLY_THOROUGHLY)


[style] ~164-~164: ‘with success’ might be wordy. Consider a shorter alternative.
Context: ...to a state - Returns a CommandResult with success status, transaction, and new state -...

(EN_WORDINESS_PREMIUM_WITH_SUCCESS)


[uncategorized] ~189-~189: The preposition ‘as’ seems more likely in this position.
Context: ...ers?)** - Simulates key press events on the editor - Supports modifier keys ...

(AI_HYDRA_LEO_REPLACE_ON_AS)

src/components/text-editor/test-setup/testing-utils-development-log.md

[uncategorized] ~77-~77: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...ting - Accepts optional HTML content string - Uses the test schema by default, o...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[style] ~112-~112: Consider an alternative adverb to strengthen your wording.
Context: ...anupEditorView(view, container?)** - Properly cleans up the editor view to prevent me...

(PROPERLY_THOROUGHLY)


[style] ~164-~164: ‘with success’ might be wordy. Consider a shorter alternative.
Context: ...to a state - Returns a CommandResult with success status, transaction, and new state -...

(EN_WORDINESS_PREMIUM_WITH_SUCCESS)


[uncategorized] ~189-~189: The preposition ‘as’ seems more likely in this position.
Context: ...ers?)** - Simulates key press events on the editor - Supports modifier keys ...

(AI_HYDRA_LEO_REPLACE_ON_AS)

src/components/text-editor/list-functionality-development-log.md

[uncategorized] ~82-~82: You might be missing the article “the” here.
Context: ...lows the core principles established in implementation plan ### [March 26, 2024] **Fixed Lis...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~95-~95: You might be missing the article “the” here.
Context: ...e Behavior** - Fixed a critical bug in handleListWithSelection function in `me...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[style] ~97-~97: Consider using a different verb for a more formal wording.
Context: ...fferent list types (bullet/ordered) - Fixed the issue with toggling list off back t...

(FIX_RESOLVE)

🔇 Additional comments (110)
sonar-project.properties (1)

4-4: Version Bump Consistency Check
The update to sonar.projectVersion=38.6.0 correctly reflects the new release version. This change ensures consistency across the metadata in your project, aligning with updates in package.json and the changelog.

src/components/text-editor/prosemirror-adapter/plugins/link-plugin.ts (1)

5-7: Import refactoring looks good.

The isValidUrl function has been moved from menu-commands to a more specific utility file menu-command-utils/link-utils. This improves code organization by placing utility functions in dedicated files based on their functionality.

package.json (2)

3-3: Version increment is appropriate.

Incrementing to version 38.6.0 aligns with the feature changes described in the PR objectives for improving command factory functionality.


47-49: Dependency updates are appropriate.

Minor version updates to development dependencies help keep the project current with bug fixes and improvements.

src/components/text-editor/prosemirror-adapter/plugins/table-plugin.ts (1)

12-20: Function export is appropriate.

Making createStyleAttribute exportable allows it to be reused across modules, which is good for code reusability. The implementation remains unchanged and maintains its original functionality.

🧰 Tools
🪛 Biome (1.9.4)

[error] 17-17: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)

src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/node-utils.ts (1)

1-22: Well-implemented utility function.

The findAncestorDepthOfType utility is well-structured with:

  • Clear TypeScript typing
  • Comprehensive JSDoc documentation
  • Efficient implementation that iterates through ancestor nodes
  • Proper null return when no matching ancestor is found

This will be useful for determining the structure of the document when handling commands, especially for list operations mentioned in the PR objectives.

src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/selection-utils.ts (1)

11-17: LGTM! Clean and straightforward implementation.

This utility function correctly creates a new TextSelection using resolved document positions.

src/components/text-editor/test-setup/schema-builder.ts (2)

6-33: LGTM! Well-structured schema creation function with good documentation.

The createTestSchema function is well-documented and correctly creates a standardized ProseMirror schema with all the necessary nodes and marks for testing the text editor.


35-87: LGTM! Flexible schema customization with comprehensive options.

The createCustomTestSchema function provides excellent flexibility for creating custom schemas with various configurations. The implementation is clean, well-organized, and properly handles all the provided options.

src/components/text-editor/prosemirror-adapter/prosemirror-adapter.tsx (3)

55-55: LGTM! New import for list key handler plugin.

This import adds the necessary plugin for enhanced keyboard handling with lists.


402-402: LGTM! Added list key handler plugin to the editor.

The plugin is correctly integrated into the editor's plugin array, which will enable special key handling for list operations.


408-427: LGTM! Enhanced action bar filtering based on allowed types.

The implementation now correctly filters action bar items based on whether they are allowed in the current context, which aligns with the PR's objective of cleaning up the command factory.

The changes to this method will help address the issue with sub-lists mentioned in the PR comments by giving better control over what list operations are available in different contexts.

src/components/text-editor/test-setup/schema-builder.spec.ts (2)

4-30: LGTM! Thorough tests for the createTestSchema function.

The tests properly verify that the schema created by createTestSchema includes all the expected nodes and marks, providing good test coverage for this utility.


32-79: LGTM! Comprehensive tests for createCustomTestSchema with various configurations.

These tests effectively verify the customizability of the schema builder, including options to exclude certain features and add custom marks and nodes. The test coverage is thorough and well-structured.

src/components/text-editor/test-setup/testing-utils-development-log.md (1)

1-220: Documentation is thorough and well-structured

This development log provides excellent documentation of the testing utilities implementation. The clear organization with planned implementations, completed work (with dates), and implementation notes makes this a valuable reference for developers working on the text editor component.

The checklist approach with detailed explanations of each utility's purpose and parameters will help maintain consistency and encourage reuse of these testing utilities.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~77-~77: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...ting - Accepts optional HTML content string - Uses the test schema by default, o...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[style] ~112-~112: Consider an alternative adverb to strengthen your wording.
Context: ...anupEditorView(view, container?)** - Properly cleans up the editor view to prevent me...

(PROPERLY_THOROUGHLY)


[style] ~164-~164: ‘with success’ might be wordy. Consider a shorter alternative.
Context: ...to a state - Returns a CommandResult with success status, transaction, and new state -...

(EN_WORDINESS_PREMIUM_WITH_SUCCESS)


[uncategorized] ~189-~189: The preposition ‘as’ seems more likely in this position.
Context: ...ers?)** - Simulates key press events on the editor - Supports modifier keys ...

(AI_HYDRA_LEO_REPLACE_ON_AS)

src/components/text-editor/test-setup/command-tester.spec.ts (5)

1-10: LGTM: Well-structured imports

The imports are organized properly and use relative paths as required by the coding guidelines.


11-50: Comprehensive tests for getCommandResult

These tests thoroughly validate both the success and failure paths of the getCommandResult function, including checking transaction creation and state updates.


52-114: Well-structured tests for testCommand

The tests for the testCommand function cover all essential aspects: applicability verification, content verification, and document size changes. The explanatory comments enhance readability.


116-172: Good practice with resource cleanup

The test properly manages the EditorView lifecycle by tracking the view and container for cleanup in the afterEach block, which prevents memory leaks.


174-209: Thorough testing of createCommandTester

This test effectively validates that the createCommandTester function produces reusable testers that maintain correct behavior across different states.

src/components/text-editor/list-functionality-implementation-plan.md (3)

1-50: Well-organized implementation plan

This document clearly outlines the phased approach to enhancing list functionality while maintaining backward compatibility. The core principles emphasize preserving existing behavior, which is crucial for maintaining stability.


51-96: Detailed implementation approach for Tab/Shift+Tab handling

The implementation approach for indenting/outdenting list items is well-documented with clear code examples.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

62-62: Fenced code blocks should be surrounded by blank lines
null

(MD031, blanks-around-fences)


128-162: Clear backspace behavior implementation

The implementation details for improved backspace behavior are thorough and cover important edge cases like joining with non-list content.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

138-138: Fenced code blocks should be surrounded by blank lines
null

(MD031, blanks-around-fences)

src/components/text-editor/prosemirror-adapter/menu/menu-list-commands.spec.ts (2)

1-6: LGTM: Imports use relative paths as required

The imports correctly use relative paths following the coding guidelines.


7-55: Well-structured test setup and helper functions

The test suite has excellent organization with clear helper functions for creating paragraphs, selecting content, and verifying list structures.

src/components/text-editor/prosemirror-adapter/plugins/menu-state-tracking-plugin.spec.ts (8)

1-9: LGTM - Imports and setup look good

The import statements are correctly using relative paths, adhering to the project's coding guidelines. The file imports the necessary functions from ProseMirror and local modules.


10-15: Appropriate mock data setup

Good use of mocking the EditorMenuTypes enum for isolated testing purposes.


17-42: Well-structured test setup

The test setup is comprehensive with proper mocking of the MenuCommandFactory, updateCallback, view, and state. The use of Jest mocks ensures isolated testing of the target functionality.


44-87: Thorough testing of getMenuItemStates

The first test case properly verifies that active and allowed states are correctly determined from command properties. Good validation of method calls with toHaveBeenCalledWith.


89-122: Edge case testing for missing methods

Good coverage of the edge cases where active or allowed methods are missing. The test verifies that sensible defaults are used (false for active, true for allowed) when methods are not present.


125-135: Plugin creation verification

The test correctly verifies that the plugin is created with the expected instance type and key.


137-160: State update testing

The test effectively validates the plugin's state management when metadata is present in a transaction.


162-181: No-change scenario testing

This test correctly verifies that the plugin preserves the existing state when no metadata is provided in a transaction.

src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/link-utils.ts (2)

1-2: Imports look good

The imports are using relative paths as required by the coding guidelines.


4-12: Effective URL validation

The isValidUrl function is implemented correctly using try-catch with the URL constructor for validation.

src/components/text-editor/list-functionality.md (4)

1-25: Well-structured documentation of current list features

The documentation clearly outlines the current capabilities of list functionality in the text editor, which serves as a good reference point for understanding the existing implementation.


26-52: Comprehensive roadmap for planned features

The checklist format for planned features is excellent for tracking progress. The scope covers all important aspects of list functionality, from basic operations to advanced features like custom list markers and accessibility improvements.


54-78: Thorough implementation considerations

The documentation outlines important technical considerations for the implementation, including schema structure, commands, key bindings, testing requirements, and user experience considerations.


80-96: Clear technical approach

The technical approach section provides a solid foundation for implementing the planned features, with specific considerations for ProseMirror plugins, command enhancements, schema modifications, and input rules.

src/components/text-editor/prosemirror-adapter/plugins/table-plugin.spec.ts (5)

1-15: LGTM - Imports and setup

The imports are correctly using relative paths as required by the coding guidelines, and all necessary utilities are imported for testing.


16-26: Good test cleanup

Proper cleanup after each test to prevent test pollution and memory leaks.


28-70: Comprehensive testing of table plugin enabling

The tests thoroughly verify the plugin behavior when tables are enabled or disabled, and confirm that the plugin can be added to an editor state.


72-116: Complete coverage of table node specifications

The tests verify that all necessary table node types are defined and can be added to a schema, including custom cell attributes for styling.


118-168: Thorough style attribute helper testing

Good coverage of the style attribute helper, including getting values from DOM elements, setting values on attributes objects, and handling edge cases like falsy values.

src/components/text-editor/list-functionality-development-log.md (2)

1-26: Well-structured development log with clear implementation phases

This document effectively outlines the development approach for list functionality with clear phases and verification requirements. The critical warning about maintaining existing functionality is appropriately highlighted.


96-98: Good documentation of the critical bug fix

The explanation of the list toggle behavior fix is clear and covers all the key aspects of the issue resolution.

🧰 Tools
🪛 LanguageTool

[style] ~97-~97: Consider using a different verb for a more formal wording.
Context: ...fferent list types (bullet/ordered) - Fixed the issue with toggling list off back t...

(FIX_RESOLVE)

src/components/text-editor/prosemirror-adapter/plugins/list-key-handler.spec.ts (1)

522-530: Clever approach to testing preventDefault

This is a good technique for testing whether preventDefault was called on the event, by overriding the method and tracking its invocation.

src/components/text-editor/test-setup/test-utils-development-log.md (2)

1-52: Comprehensive test utilities documentation with clear implementation status

This document provides an excellent overview of the planned and implemented test utilities with clear checkboxes indicating completion status. The organization into categories makes it easy to navigate.


211-220: Well-documented implementation notes

These notes provide good context about the consistency and integration of the test utilities. They will be helpful for developers using the testing suite.

src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/active-state-utils.ts (3)

5-18: Well-implemented mark active state checker

This utility correctly handles both empty and non-empty selections when checking if a mark is active. For empty selections, it looks at the stored marks or marks at the cursor position, while for non-empty selections it checks if the mark exists in the selected range.


19-38: Good handling of node types and special cases

The function properly checks if the current node matches the specified type and handles the special case for headings with level attributes. The depth-based node lookup is the correct approach.


1-4:

❓ Verification inconclusive

Check imports for compliance with coding guidelines

According to the coding guidelines, imports from other files in the same module (lime-elements) must use relative paths.

The current imports look like relative paths, which is good. Let's verify this is consistent across the codebase:


🏁 Script executed:

#!/bin/bash
# Check if there are any absolute imports in the TS files for lime-elements
rg -l "from 'lime-elements" --type ts

Length of output: 42


Import paths verified for compliance.
The local module imports in src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/active-state-utils.ts use relative paths as required by our coding guidelines, and the external import from 'prosemirror-model' is acceptable. However, the repository-wide search for absolute imports referencing lime-elements produced no output—which is inconclusive. Please manually verify across the codebase that no module-internal imports use absolute paths.

src/components/text-editor/prosemirror-adapter/plugins/list-key-handler.ts (3)

1-30: Good initial checks for determining if the cursor is within a list item.

No syntax or logical errors found. The isInListItem function accurately traverses up the node hierarchy to detect a list_item. This helps ensure that subsequent list-related commands are only executed in the correct context.


57-81: Straightforward logic for determining cursor position at the start of a list item.

The isAtStartOfListItem function is well-structured. It returns early for non-collapsed selections and checks whether the cursor is exactly at the start of the list_item. This code block appears correct for the intended functionality.


83-178:

✅ Verification successful

Comprehensive key handling for list items with standard list commands.

The plugin design covers Tab/Shift+Tab for (out)denting, Enter for splitting or exiting empty list items, and Backspace for joining with the previous item or lifting out of the list. This is consistent with typical editor behavior.

However, given the reported sub-list “weird” behavior, consider adding tests for nested lists to ensure correct handling.

Here is a script that searches for sub-list usage in the tests or code, which can help verify that nesting is handled. If sub-lists appear or your plugin references them, you can confirm coverage:


🏁 Script executed:

#!/bin/bash
# Searches for potential references to sub-lists in the codebase
rg -A 5 "nested list" 
rg -A 5 "sub-list"
rg -A 5 "list.*list"

Length of output: 67012


Verified: Nested List Behavior is Fully Tested and Functions as Expected

The existing tests in the codebase—especially within src/components/text-editor/prosemirror-adapter/plugins/list-key-handler.spec.ts—demonstrate that nested and sub-list scenarios (including indenting and outdenting) are being validated. No additional tests or changes are necessary at this time.

src/components/text-editor/test-setup/editor-view-builder.ts (4)

14-46: Solid approach for creating and returning an editor view with container management.

This function is elegantly structured, providing both a default container and a default EditorState if none are supplied. Attaching the container to the DOM conditionally prevents extraneous elements during test runs. The code is clear and maintainable.


54-75: Flexible dispatch spy for transaction updates.

Automatically applying transactions to the view’s state is a neat solution for simplifying test flows. The setView method is especially useful for capturing the created view reference. No issues found here.


84-94: Proper cleanup routine to avoid memory leaks.

Destroying the view is essential to free resources, and removing the container from the DOM is a good practice. No concerns here.

🧰 Tools
🪛 Biome (1.9.4)

[error] 90-90: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


101-143: Minimal DOM environment mocking for Node-based tests.

This utility is effective for running ProseMirror-based tests without a full browser environment. The logic to restore the original window and document objects is correct. Good job ensuring that the mock environment remains confined to the test scope.

src/components/text-editor/test-setup/editor-state-builder.ts (2)

14-29: Verify error handling for invalid or unparseable HTML content
In createEditorState, if parseContentToDoc fails to parse invalid HTML, the method may throw an unhandled error. Consider a fallback or explicit error handling logic.


86-91: Security note for HTML parsing
Though this is test code, using innerHTML could be an attack vector if untrusted HTML were ever introduced. For production-level code, consider secure HTML parsing or sanitization.

src/components/text-editor/test-setup/event-simulator.ts (5)

8-43: Well-structured mock implementation
MockDataTransfer properly simulates file addition and data handling for testing. The mutable map approach is clear and sufficient for test environments. No immediate issues found.


63-84: Confirm cross-browser consistency
simulateKeyPress dispatches a 'keydown' event using KeyboardEvent. Some test environments may not fully support KeyboardEventInit fields. Verify that your test runners handle them consistently.


102-139: Ensure HTML paste content is handled as expected
simulatePaste sets both 'text/plain' and 'text/html' if provided. Confirm that ProseMirror's paste handling merges or prioritizes these as intended, especially if the test environment differs from a real browser.


152-191: Mock coordinate-based interactions
simulateClick gracefully assigns default bounding client rect and mocks elementFromPoint. This is appropriate for typical test environments. No changes necessary.


204-288: Robust drag-and-drop simulation
simulateDragAndDrop generates multiple events (mousedown, dragstart, dragover, drop, mouseup). This resembles real usage closely enough for thorough test coverage. Looks good.

src/components/text-editor/test-setup/command-tester.ts (4)

16-20: Interface helps clarify command outcomes
CommandResult is clean and self-explanatory. This aids readability when checking commands’ side effects during tests.


74-120: Comprehensive verification of command behavior
testCommand checks multiple aspects (applicability, text content, doc size, etc). This thorough approach is beneficial. Ensure that tests using it also cover commands that partially modify the doc (e.g., toggling marks).


130-185: DOM-based command validation
testCommandWithView is a good extension for commands needing an EditorView. The approach is straightforward and well-structured.


193-202: Reusable command tester
createCommandTester keeps the test code DRY and encapsulates logic nicely. No issues found.

src/components/text-editor/prosemirror-adapter/menu/menu-commands.ts (4)

5-5: Confirm usage of schema-list imports
The imports from 'prosemirror-schema-list' (wrapInList, sinkListItem) are used for advanced list operations. They look correct for the toggling logic.


258-296: Streamlined approach to list toggling
handleListWithSelection captures multiple list scenarios (removal, conversion, new wrap). The logic is well-structured. Just confirm thorough test coverage for selection ranges spanning multiple list items.


305-347: createListCommand handles single-cursor vs multi-range
Splitting logic into handleListNoSelection vs. handleListWithSelection is a neat approach. Ensure conversions (bullet ↔ ordered) are tested with partially selected lists.


409-410: Added keyboard shortcuts
'Mod-Shift-8' and 'Mod-Shift-9' for bullet/ordered lists are consistent with typical text editors. Implementation looks correct.

src/components/text-editor/prosemirror-adapter/plugins/menu-state-tracking-plugin.ts (5)

10-13: Separation of active and allowed states looks clean
Defining both active and allowed properties in this interface provides a clear and extensible structure for tracking menu state.


15-18: Callback refactor
Separating the callback parameters into activeTypes and allowedTypes enhances clarity and type safety for external consumers.


25-26: Comprehensive state determination
Using separate records for activeTypes and allowedTypes is an effective pattern, ensuring clarity when populating both properties.

Also applies to: 34-34


46-46: Initializing empty allowed and active states
Returning empty records here provides a straightforward initial value before the plugin updates them.


69-71: Clear separation for callback arguments
Invoking the updateCallback with separate menuItemStates.active and menuItemStates.allowed keeps the logic consistent.

src/components/text-editor/test-setup/event-simulator.spec.ts (7)

18-30: Consistent setup in beforeEach
Creating a fresh editor view and attaching its container to the DOM for each test ensures isolation and prevents cross-test pollution.


32-41: Clean teardown in afterEach
Destroying the editor view and removing the container fosters best practices for test cleanup.


43-59: Key press simulation test
Verifying the generated KeyboardEvent and key property ensures correctness of the simulated key press utility.


61-83: Modifier keys test
Including tests for modifier keys (ctrl, shift, etc.) provides confidence in complex keyboard interactions.


86-133: Paste simulation tests
Handling both text and HTML content in these tests thoroughly validates the simulatePaste utility.


135-171: Click simulation tests
Verifying mouse button codes (button = 0, 2) and click detail states (single/double) ensures robust coverage of mouse interactions.


173-233: Drag and drop simulation test
Checking the dispatch of multiple mouse and custom drag events in sequence solidly confirms that complex interactions are handled.

src/components/text-editor/test-setup/editor-state-builder.spec.ts (4)

10-55: Thorough tests for createEditorState
Verifying default schema, content creation, and custom schema support ensures that editor states are controlled and flexible.


57-70: Selection creation tests
Ensuring that the editor state sets the expected from and to selection boundaries adds confidence in selection-specific utilities.


72-84: Testing setTextSelection
Confirming that a new state is returned and that selection boundaries match expectations guards against accidental state mutation.


86-114: Document creation tests
Validating both text and empty paragraphs confirms that createDocumentWithText handles content consistently for various scenarios.

src/components/text-editor/prosemirror-adapter/menu/menu-command-utils/list-utils.ts (7)

1-11: Enumeration of list types
Defining LIST_TYPES as a tuple closely couples it with EditorMenuTypes and clarifies valid list types at a glance.


12-25: Valid in-list detection
Iterating up through $from.depth is a typical approach for checking node ancestry. This should reliably detect the specified list type.


49-49: Defined dispatch type
Exporting a dedicated Dispatch type clarifies the expected transaction signature for these utilities.


51-100: Controlled removal of list nodes
Replacing targeted list nodes with paragraphs while preserving content helps maintain consistent document flow.


133-172: Batch conversion of list nodes
Traversing the range via nodesBetween and selectively creating new nodes ensures consistent transformation for an entire selection.


174-205: Toggling list logic
Applying findWrapping and liftTarget covers both wrapping new lists and lifting existing ones, maximizing reusability.


208-243: Single-list node conversion
Scanning upward through the selection depth until the matching list type is found helps ensure the correct node is replaced.

src/components/text-editor/test-setup/content-generator.ts (4)

1-40: Well-structured utility functions with clear documentation.

The content generator utility functions are well-documented with JSDoc comments that clearly explain their purpose, parameters, and return values. The code organization is clean and follows a consistent pattern.


41-88: Well-implemented mark application logic with proper error handling.

The createDocWithFormattedText and its helper function createTextNodeWithMarks correctly implement mark application with proper error handling for invalid mark types.


90-118: Bullet list creation logic is correctly implemented.

The createDocWithBulletList function correctly maps text items to list items and wraps them in a bullet list node. The implementation follows ProseMirror's document structure requirements.


120-144: Well-implemented specialized document creators.

The heading, blockquote, and code block document creators all follow a consistent pattern and correctly implement the expected document structure for each type.

Also applies to: 146-166, 168-187

🧰 Tools
🪛 Biome (1.9.4)

[error] 130-130: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)

src/components/text-editor/test-setup/content-generator.spec.ts (3)

1-41: Well-structured test suite with thorough test cases.

The test suite is well-organized with comprehensive test cases for the content generator utilities. Each test verifies both the returned state type and the document structure.


74-140: Thorough test coverage for formatted text functionality.

The tests for createDocWithFormattedText cover all important aspects including applying different types of marks, handling mark attributes, and error cases for invalid mark types.

🧰 Tools
🪛 Biome (1.9.4)

[error] 119-119: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


142-179: Comprehensive tests for document creation functions.

The tests for bullet lists, headings, blockquotes, and code blocks thoroughly verify both the structure and content of the created documents, including edge cases like empty lists.

Also applies to: 181-254

src/components/text-editor/test-setup/editor-view-builder.spec.ts (3)

11-23: Good practice with proper cleanup in afterEach.

The use of afterEach to clean up the editor view and container prevents memory leaks, which is essential when testing components that manipulate the DOM.


79-137: Well-structured tests for dispatch spy functionality.

The tests for createDispatchSpy thoroughly verify both the tracking of transactions and the conditional auto-update behavior.


139-190: Thorough testing of cleanup and DOM environment mocking.

The tests for cleanupEditorView and mockProseMirrorDOMEnvironment properly verify the functionality using spies and appropriate assertions.

Also applies to: 192-248

src/components/text-editor/test-setup/test-utils.md (3)

1-40: Comprehensive documentation of testing utilities.

The documentation provides a clear overview of the available testing utilities with well-structured categories and descriptions.


41-74: Well-documented API reference.

The utility functions are clearly listed with their signatures and purposes, making it easy for developers to understand what's available and how to use each utility.


75-191: Helpful usage examples for common testing scenarios.

The examples demonstrate how to use the testing utilities in real-world scenarios, including setup/teardown patterns, command testing, and event simulation. These will be valuable for developers writing tests.

@@ -1,3 +1,11 @@
## [38.6.0](https://github.com/Lundalogik/lime-elements/compare/v38.5.0...v38.6.0) (2025-03-25)
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Heading Level Concern
The first line is a level-2 heading (## [38.6.0]…). Markdownlint (MD041) expects the file’s first heading to be a top-level heading. If your project’s style guidelines require a top-level (#) heading at the start of the file, consider updating it accordingly, or alternatively, suppress this warning if the current style is intentional.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

1-1: First line in a file should be a top-level heading
null

(MD041, first-line-heading, first-line-h1)

Comment on lines +2 to +3


Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Remove Extra Blank Lines After Version Heading
Markdownlint (MD012) flags multiple consecutive blank lines after the version header. Please remove the extra blank line(s) to improve readability and comply with the expected single blank line spacing.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

3-3: Multiple consecutive blank lines
Expected: 1; Actual: 2

(MD012, no-multiple-blanks)

Comment on lines +5 to +6


Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Reduce Consecutive Blank Lines Before “Features” Section
Similarly, there are multiple consecutive blank lines before the “### Features” heading. Reducing these extra lines to a single blank line will enhance the document’s clarity.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

6-6: Multiple consecutive blank lines
Expected: 1; Actual: 2

(MD012, no-multiple-blanks)

Comment on lines +3 to +9
export const adjustSelectionToFullBlocks = (state: EditorState) => {
const { $from, $to } = state.selection;
const from = $from.pos === $from.start() ? $from.pos : $from.end();
const to = $to.pos === $to.end() ? $to.pos : $to.start();

return { from: from, to: to };
};
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Consider adding clarification on the selection adjustment logic.

The adjustSelectionToFullBlocks function seems to do the opposite of what its name suggests in some cases. If the selection doesn't start at the beginning of a block, it uses the end position ($from.end()), and if it doesn't end at the end of a block, it uses the start position ($to.start()). This logic is counterintuitive and could benefit from a comment explaining this design choice.

 export const adjustSelectionToFullBlocks = (state: EditorState) => {
     const { $from, $to } = state.selection;
+    // If selection starts at the beginning of a block, use that position,
+    // otherwise use the end of the block containing the start position
     const from = $from.pos === $from.start() ? $from.pos : $from.end();
+    // If selection ends at the end of a block, use that position,
+    // otherwise use the start of the block containing the end position
     const to = $to.pos === $to.end() ? $to.pos : $to.start();

     return { from: from, to: to };
 };
📝 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 const adjustSelectionToFullBlocks = (state: EditorState) => {
const { $from, $to } = state.selection;
const from = $from.pos === $from.start() ? $from.pos : $from.end();
const to = $to.pos === $to.end() ? $to.pos : $to.start();
return { from: from, to: to };
};
export const adjustSelectionToFullBlocks = (state: EditorState) => {
const { $from, $to } = state.selection;
// If selection starts at the beginning of a block, use that position,
// otherwise use the end of the block containing the start position
const from = $from.pos === $from.start() ? $from.pos : $from.end();
// If selection ends at the end of a block, use that position,
// otherwise use the start of the block containing the end position
const to = $to.pos === $to.end() ? $to.pos : $to.start();
return { from: from, to: to };
};

Comment on lines +97 to +127
1. **Split List Items:**
- Override the Enter key behavior within lists
- Implement `splitListItem` command to properly split the current list item
- Handle empty list items (create a new paragraph outside the list)

2. **Implementation Details:**
```typescript
handleEnter(view, event) {
const { state } = view;
const { selection } = state;
const { $from, empty } = selection;

// Check if cursor is in a list item
if (isInListItem(state)) {
// If the list item is empty, exit the list
if (isEmptyListItem(state)) {
return liftListItem(schema.nodes.list_item)(state, view.dispatch);
}

// Otherwise split the list item
return splitListItem(schema.nodes.list_item)(state, view.dispatch);
}

return false;
}
```

3. **Helper Functions:**
- Create an `isEmptyListItem` function to check if the current list item is empty
- Implement proper handling of cursor position after splitting

Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Add blank lines around code blocks

The fenced code blocks should be surrounded by blank lines for better readability according to Markdown standards.

-   ```typescript
+
+   ```typescript
    handleEnter(view, event) {
      const { state } = view;
      const { selection } = state;
      const { $from, empty } = selection;
      
      // Check if cursor is in a list item
      if (isInListItem(state)) {
        // If the list item is empty, exit the list
        if (isEmptyListItem(state)) {
          return liftListItem(schema.nodes.list_item)(state, view.dispatch);
        }
        
        // Otherwise split the list item
        return splitListItem(schema.nodes.list_item)(state, view.dispatch);
      }
      
      return false;
    }
-   ```
+   ```
+
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

103-103: Fenced code blocks should be surrounded by blank lines
null

(MD031, blanks-around-fences)

Comment on lines +27 to +47
/**
* Get the other list type from the current list type.
* @param schema - The schema to use.
* @param currentType - The current list type.
* @returns The other list type.
*/
export const getOtherListType = (
schema: Schema,
currentType: string,
): NodeType => {
if (!LIST_TYPES.includes(currentType as any)) {
console.error(`Invalid list type: ${currentType}`);
}

const otherType = LIST_TYPES.find((type) => type !== currentType);
if (!otherType || !schema.nodes[otherType]) {
console.error(`List type "${otherType}" not found in schema`);
}

return schema.nodes[otherType];
};
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Fallback logging using console.error
Using console.error here surfaces misconfiguration issues on the console.

Consider substituting a more robust logging mechanism or a user-facing warning if these errors require handling beyond development.

Comment on lines +102 to +131
const fromOrderedToBulletList = (fromType: NodeType, toType: NodeType) => {
return (
fromType.name === EditorMenuTypes.OrderedList &&
toType.name === EditorMenuTypes.BulletList
);
};

const fromBulletToOrderedList = (fromType: NodeType, toType: NodeType) => {
return (
fromType.name === EditorMenuTypes.BulletList &&
toType.name === EditorMenuTypes.OrderedList
);
};

const convertListAttributes = (
fromType: NodeType,
toType: NodeType,
attrs: Record<string, any>,
) => {
const newAttrs = { ...attrs };
if (fromOrderedToBulletList(fromType, toType)) {
// Bullet lists generally do not need an "order" attribute.
delete newAttrs.order;
} else if (fromBulletToOrderedList(fromType, toType)) {
// For ordered lists, set a default start if not present.
newAttrs.order = newAttrs.order || 1;
}

return newAttrs;
};
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Handling list attribute conversion
In convertListAttributes, using delete newAttrs.order; adheres to the expected logic but can be less performant.

To address the static analysis hint and potentially improve performance, update the attribute removal like this:

-        delete newAttrs.order;
+        newAttrs.order = undefined;
📝 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
const fromOrderedToBulletList = (fromType: NodeType, toType: NodeType) => {
return (
fromType.name === EditorMenuTypes.OrderedList &&
toType.name === EditorMenuTypes.BulletList
);
};
const fromBulletToOrderedList = (fromType: NodeType, toType: NodeType) => {
return (
fromType.name === EditorMenuTypes.BulletList &&
toType.name === EditorMenuTypes.OrderedList
);
};
const convertListAttributes = (
fromType: NodeType,
toType: NodeType,
attrs: Record<string, any>,
) => {
const newAttrs = { ...attrs };
if (fromOrderedToBulletList(fromType, toType)) {
// Bullet lists generally do not need an "order" attribute.
delete newAttrs.order;
} else if (fromBulletToOrderedList(fromType, toType)) {
// For ordered lists, set a default start if not present.
newAttrs.order = newAttrs.order || 1;
}
return newAttrs;
};
const fromOrderedToBulletList = (fromType: NodeType, toType: NodeType) => {
return (
fromType.name === EditorMenuTypes.OrderedList &&
toType.name === EditorMenuTypes.BulletList
);
};
const fromBulletToOrderedList = (fromType: NodeType, toType: NodeType) => {
return (
fromType.name === EditorMenuTypes.BulletList &&
toType.name === EditorMenuTypes.OrderedList
);
};
const convertListAttributes = (
fromType: NodeType,
toType: NodeType,
attrs: Record<string, any>,
) => {
const newAttrs = { ...attrs };
if (fromOrderedToBulletList(fromType, toType)) {
// Bullet lists generally do not need an "order" attribute.
newAttrs.order = undefined;
} else if (fromBulletToOrderedList(fromType, toType)) {
// For ordered lists, set a default start if not present.
newAttrs.order = newAttrs.order || 1;
}
return newAttrs;
};
🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

*/
export function createDocWithHeading(
text: string,
level: number = 1,
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Remove redundant type annotation.

The type annotation for the level parameter is redundant since it's already inferred from the default value.

-    level: number = 1,
+    level = 1,
📝 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
level: number = 1,
level = 1,
🧰 Tools
🪛 Biome (1.9.4)

[error] 130-130: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)

Comment on lines +119 to +129
if (firstChild && firstChild.firstChild) {
const linkMark = firstChild.firstChild.marks.find(
(m) => m.type.name === 'link',
);
expect(linkMark).toBeDefined();

if (linkMark) {
expect(linkMark.attrs.href).toBe('https://example.com');
expect(linkMark.attrs.title).toBe('Example');
}
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Consider using optional chaining for safer property access.

Using optional chaining would make the code more robust by safely handling potential null or undefined values.

-            if (firstChild && firstChild.firstChild) {
-                const linkMark = firstChild.firstChild.marks.find(
+            const linkMark = firstChild?.firstChild?.marks.find(
                     (m) => m.type.name === 'link',
-                );
-                expect(linkMark).toBeDefined();
-
-                if (linkMark) {
-                    expect(linkMark.attrs.href).toBe('https://example.com');
-                    expect(linkMark.attrs.title).toBe('Example');
-                }
+                );
+            expect(linkMark).toBeDefined();
+
+            if (linkMark) {
+                expect(linkMark.attrs.href).toBe('https://example.com');
+                expect(linkMark.attrs.title).toBe('Example');
             }
📝 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 (firstChild && firstChild.firstChild) {
const linkMark = firstChild.firstChild.marks.find(
(m) => m.type.name === 'link',
);
expect(linkMark).toBeDefined();
if (linkMark) {
expect(linkMark.attrs.href).toBe('https://example.com');
expect(linkMark.attrs.title).toBe('Example');
}
}
const linkMark = firstChild?.firstChild?.marks.find(
(m) => m.type.name === 'link',
);
expect(linkMark).toBeDefined();
if (linkMark) {
expect(linkMark.attrs.href).toBe('https://example.com');
expect(linkMark.attrs.title).toBe('Example');
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 119-119: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

Comment on lines +210 to +211
delete global.window;
delete global.document;
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Replace delete operator with undefined assignment for better performance.

Using the delete operator can have performance implications. Consider assigning undefined instead.

-            delete global.window;
-            delete global.document;
+            global.window = undefined;
+            global.document = undefined;
📝 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
delete global.window;
delete global.document;
global.window = undefined;
global.document = undefined;
🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


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

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Text editor: switching a list between ordered an unordered does not work
3 participants