Skip to content

Conversation

tbouffard
Copy link
Member

@tbouffard tbouffard commented Jun 26, 2025

The Dictionary class had been introduced by mxGraph for browser without Map object support.
The Map class is available in the ECMAScript version supported by maxGraph, so we can remove it.

In the examples in this repository, the package size decreases by 0.7kB.

BREAKING CHANGES: The Dictionary class has been removed. The maxGraph API use the Map class instead, which is a standard JavaScript feature.
If your code depends on the Dictionary class, you can use the Map class instead.

Notes

Closes #855

Summary by CodeRabbit

Summary by CodeRabbit

  • Breaking Changes

    • Removed the custom Dictionary class from the API. Users should now use the standard JavaScript Map object for similar functionality.
  • Refactor

    • Replaced all internal usages of the Dictionary class with the native JavaScript Map object across the application, including state management, overlays, cell collections, and layout caches.
    • Updated method and property signatures where necessary to reflect the use of Map.
    • Improved type annotations and streamlined iteration over collections using standard Map methods.
  • Documentation

    • Updated the changelog to reflect the removal of the Dictionary class and the associated API changes.

The `Dictionary` class had been introduced by mxGraph for browser without `Map` object support.
The `Map` class is available in the ECMAScript version supported by maxGraph, so we can remove it.

In the examples in this repository, the package size decreases by 0.7kB.

BREAKING CHANGES: The `Dictionary` class has been removed. Use the `Map` class instead, which is a standard JavaScript feature.
@tbouffard tbouffard added the refactor Code refactoring label Jun 26, 2025
Copy link

coderabbitai bot commented Jun 26, 2025

"""

Walkthrough

This change removes the custom Dictionary class from the codebase and replaces all its usages with the native JavaScript Map object. All relevant imports, property types, method signatures, and internal logic are updated to use Map instead of Dictionary. The changelog is updated to reflect this breaking change.

Changes

File(s) Change Summary
CHANGELOG.md Updated to document removal of the Dictionary class and recommend using JavaScript Map instead.
.../core/src/util/Dictionary.ts Deleted the Dictionary class implementation.
.../core/src/index.ts Removed export of Dictionary.
.../core/src/util/arrayUtils.ts
.../core/src/util/cellArrayUtils.ts
.../core/src/util/styleUtils.ts
.../core/src/util/treeTraversal.ts
Replaced Dictionary with Map for internal data structures; updated method calls accordingly.
.../core/src/view/GraphView.ts Changed states property and related methods from Dictionary to Map.
.../core/src/view/cell/CellRenderer.ts
.../core/src/view/cell/CellState.ts
.../core/src/view/cell/CellStatePreview.ts
.../core/src/view/cell/TemporaryCellStates.ts
Converted overlays, deltas, and state maps from Dictionary to Map; updated logic to use Map API.
.../core/src/view/image/ImageExport.ts Updated overlay iteration to use Map.forEach instead of custom visit method.
.../core/src/view/layout/CompactTreeLayout.ts
.../core/src/view/layout/GraphLayout.ts
.../core/src/view/layout/HierarchicalLayout.ts
.../core/src/view/layout/SwimlaneLayout.ts
Replaced all custom dictionary-based caches with Map objects; updated all related method calls.
.../core/src/view/layout/hierarchical/CoordinateAssignment.ts
.../core/src/view/layout/hierarchical/GraphHierarchyModel.ts
.../core/src/view/layout/hierarchical/MinimumCycleRemover.ts
.../core/src/view/layout/hierarchical/SwimlaneModel.ts
Migrated all hierarchy and edge/vertex mapping from Dictionary to Map; updated value retrieval logic.
.../core/src/view/layout/types.ts Changed visited property in GraphLayoutTraverseArgs interface from Dictionary to Map.
.../core/src/view/mixins/CellsMixin.ts
.../core/src/view/mixins/ConnectionsMixin.ts
.../core/src/view/mixins/EdgeMixin.ts
.../core/src/view/mixins/SelectionMixin.ts
.../core/src/view/mixins/TerminalMixin.ts
.../core/src/view/mixins/TooltipMixin.ts
Replaced all dictionary-based fast lookups with Map objects; updated method calls.
.../core/src/view/plugins/SelectionCellsHandler.ts
.../core/src/view/plugins/SelectionHandler.ts
Converted handler and state collections from Dictionary to Map; updated all related logic.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Module
    participant Map

    User->>Module: Call function using key-value storage
    Module->>Map: set(key, value) / get(key) / delete(key)
    Map-->>Module: Return result
    Module-->>User: Return processed data
Loading

Possibly related issues

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-26T13_45_44_802Z-debug-0.log


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 598a447 and 166a082.

📒 Files selected for processing (7)
  • CHANGELOG.md (1 hunks)
  • packages/core/src/view/layout/HierarchicalLayout.ts (6 hunks)
  • packages/core/src/view/layout/SwimlaneLayout.ts (6 hunks)
  • packages/core/src/view/layout/hierarchical/SwimlaneModel.ts (5 hunks)
  • packages/core/src/view/mixins/SelectionMixin.ts (1 hunks)
  • packages/core/src/view/mixins/TerminalMixin.ts (2 hunks)
  • packages/core/src/view/plugins/SelectionHandler.ts (7 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/core/src/view/layout/HierarchicalLayout.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/core/src/view/mixins/SelectionMixin.ts
  • packages/core/src/view/mixins/TerminalMixin.ts
  • CHANGELOG.md
  • packages/core/src/view/plugins/SelectionHandler.ts
  • packages/core/src/view/layout/hierarchical/SwimlaneModel.ts
  • packages/core/src/view/layout/SwimlaneLayout.ts
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build (windows-2022)
  • GitHub Check: build (ubuntu-22.04)
✨ 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:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate sequence diagram to generate a sequence diagram of the changes in this 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

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

🧹 Nitpick comments (3)
packages/core/src/view/plugins/SelectionHandler.ts (1)

321-330: Use Map.has when you just need an existence check

isCellMoving (line 803) currently returns this.allCells.get(cell), which relies on the truthiness of the stored value.
With a Map, the semantic “is the key present?” is clearer (and marginally faster) via has.
No behaviour change, just crisper intent.

-  isCellMoving(cell: Cell) {
-    return this.allCells.get(cell);
-  }
+  isCellMoving(cell: Cell) {
+    return this.allCells.has(cell);
+  }
packages/core/src/view/layout/HierarchicalLayout.ts (1)

149-160: Consistency ‑ consider has for membership checks

The three caches are now native Maps – good.
Keep in mind that Map.has(key) is cheaper than get when you only need to know if an entry exists (e.g. in getEdges and getVisibleTerminal).
Not critical, but worth a tiny micro-cleanup.

packages/core/src/view/layout/SwimlaneLayout.ts (1)

492-520: Minor: prefer Map.has for clarity & micro-perf

Same comment as in HierarchicalLayout – use terminalCache.has(edge) when you only want to skip recomputation if cached.

-const term = terminalCache.get(edge);
-if (term != null) return term;
+if (terminalCache.has(edge)) return terminalCache.get(edge)!;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9130103 and 598a447.

📒 Files selected for processing (30)
  • CHANGELOG.md (1 hunks)
  • packages/core/src/index.ts (0 hunks)
  • packages/core/src/util/Dictionary.ts (0 hunks)
  • packages/core/src/util/arrayUtils.ts (1 hunks)
  • packages/core/src/util/cellArrayUtils.ts (4 hunks)
  • packages/core/src/util/styleUtils.ts (1 hunks)
  • packages/core/src/util/treeTraversal.ts (2 hunks)
  • packages/core/src/view/GraphView.ts (5 hunks)
  • packages/core/src/view/cell/CellRenderer.ts (4 hunks)
  • packages/core/src/view/cell/CellState.ts (1 hunks)
  • packages/core/src/view/cell/CellStatePreview.ts (4 hunks)
  • packages/core/src/view/cell/TemporaryCellStates.ts (2 hunks)
  • packages/core/src/view/image/ImageExport.ts (1 hunks)
  • packages/core/src/view/layout/CompactTreeLayout.ts (1 hunks)
  • packages/core/src/view/layout/GraphLayout.ts (1 hunks)
  • packages/core/src/view/layout/HierarchicalLayout.ts (5 hunks)
  • packages/core/src/view/layout/SwimlaneLayout.ts (5 hunks)
  • packages/core/src/view/layout/hierarchical/CoordinateAssignment.ts (4 hunks)
  • packages/core/src/view/layout/hierarchical/GraphHierarchyModel.ts (6 hunks)
  • packages/core/src/view/layout/hierarchical/MinimumCycleRemover.ts (1 hunks)
  • packages/core/src/view/layout/hierarchical/SwimlaneModel.ts (5 hunks)
  • packages/core/src/view/layout/types.ts (1 hunks)
  • packages/core/src/view/mixins/CellsMixin.ts (5 hunks)
  • packages/core/src/view/mixins/ConnectionsMixin.ts (1 hunks)
  • packages/core/src/view/mixins/EdgeMixin.ts (1 hunks)
  • packages/core/src/view/mixins/SelectionMixin.ts (1 hunks)
  • packages/core/src/view/mixins/TerminalMixin.ts (2 hunks)
  • packages/core/src/view/mixins/TooltipMixin.ts (1 hunks)
  • packages/core/src/view/plugins/SelectionCellsHandler.ts (12 hunks)
  • packages/core/src/view/plugins/SelectionHandler.ts (6 hunks)
💤 Files with no reviewable changes (2)
  • packages/core/src/index.ts
  • packages/core/src/util/Dictionary.ts
🧰 Additional context used
🧬 Code Graph Analysis (15)
packages/core/src/view/mixins/TerminalMixin.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/util/styleUtils.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/util/cellArrayUtils.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/view/mixins/ConnectionsMixin.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/view/mixins/EdgeMixin.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/view/layout/CompactTreeLayout.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/view/mixins/SelectionMixin.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/view/cell/TemporaryCellStates.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/util/treeTraversal.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/view/mixins/CellsMixin.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/view/layout/HierarchicalLayout.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/view/layout/hierarchical/GraphHierarchyModel.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/view/layout/GraphLayout.ts (1)
packages/core/src/view/layout/types.ts (1)
  • GraphLayoutTraverseArgs (23-29)
packages/core/src/view/layout/SwimlaneLayout.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
packages/core/src/view/GraphView.ts (1)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-888)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build (ubuntu-22.04)
  • GitHub Check: build (windows-2022)
🔇 Additional comments (50)
CHANGELOG.md (1)

17-17: LGTM! Clear documentation of the breaking change.

The changelog entry properly documents the removal of the Dictionary class and directs users to the native Map alternative. This is appropriately categorized as a breaking change.

packages/core/src/view/layout/hierarchical/MinimumCycleRemover.ts (1)

56-56: LGTM! Correct migration from Dictionary to Map.

The change from model.vertexMapper.getValues() to Array.from(model.vertexMapper.values()) is semantically correct. The Array.from() wrapper is necessary since Map.values() returns an iterator rather than an array.

packages/core/src/view/layout/types.ts (1)

28-28: LGTM! Type change is consistent with Dictionary to Map migration.

The type change from Dictionary<Cell, boolean> to Map<Cell, boolean> maintains the same semantics while using the native JavaScript type. This aligns with the overall refactoring effort.

packages/core/src/view/mixins/TerminalMixin.ts (2)

39-39: LGTM! Good migration with improved variable naming.

The change from Dictionary<Cell, boolean> to Map<Cell, boolean> is correct, and renaming dict to coveredEntries improves code readability by making the purpose clearer.


54-55: LGTM! Correct method call migration from Dictionary to Map.

The replacement of dict.put() with coveredEntries.set() correctly migrates from the custom Dictionary API to the native Map API while preserving the deduplication logic.

Also applies to: 63-64

packages/core/src/view/mixins/EdgeMixin.ts (2)

394-394: LGTM! Correct type migration to native Map.

The type change from Dictionary<Cell | null, boolean> to Map<Cell | null, boolean> maintains the same semantics while using the native JavaScript type for cell tracking.


397-397: LGTM! Correct method call migration.

The replacement of dict.put(cells[i], true) with dict.set(cells[i], true) correctly migrates from the custom Dictionary API to the native Map API.

packages/core/src/view/cell/TemporaryCellStates.ts (2)

38-38: LGTM: Property type correctly updated to use native Map.

The type change from Dictionary<Cell, CellState> to Map<Cell, CellState> is consistent with the broader refactor to remove the custom Dictionary class.


97-97: LGTM: Constructor correctly updated to use native Map.

The initialization change from new Dictionary() to new Map() properly aligns with the Map type declaration above.

packages/core/src/util/styleUtils.ts (2)

497-497: LGTM: Lookup map correctly updated to use native Map.

The type change from Dictionary<Cell, string[]> to Map<Cell, string[]> maintains the same functionality while using the native JavaScript Map.


504-504: LGTM: Method calls correctly updated from Dictionary API to Map API.

The changes from lookup.put(o1, p1) and lookup.put(o2, p2) to lookup.set(o1, p1) and lookup.set(o2, p2) properly use the native Map API while preserving identical functionality.

Also applies to: 511-511

packages/core/src/view/mixins/TooltipMixin.ts (1)

50-50: LGTM: Overlay iteration correctly updated to use Map API.

The change from state.overlays.visit((id, shape) => ...) to state.overlays.forEach((shape: Shape) => ...) properly uses the native Map.forEach() method. Since the callback only uses the shape value and not the key, the parameter order change doesn't affect functionality.

packages/core/src/view/image/ImageExport.ts (1)

155-157: LGTM: Overlay iteration improved with optional chaining and Map API.

The change from explicit null check with visit() to optional chaining with forEach() is both more concise and correctly uses the native Map API. The functionality remains identical while being more readable.

packages/core/src/view/cell/CellState.ts (1)

56-56: LGTM: Overlays property correctly updated to use native Map.

The change from Dictionary<CellOverlay, Shape> to Map<CellOverlay, Shape> with new Map() initialization properly implements the migration to native JavaScript Map while maintaining the same generic type signature for type safety.

packages/core/src/view/layout/CompactTreeLayout.ts (1)

415-415: LGTM! Dictionary correctly replaced with native Map.

The refactoring successfully replaces the custom Dictionary<Cell, string[]> with the native JavaScript Map<Cell, string[]> while preserving the exact same caching functionality for split cell paths in edge sorting.

Also applies to: 423-423, 431-431

packages/core/src/view/mixins/CellsMixin.ts (4)

460-460: LGTM! Dictionary correctly replaced with native Map in cloneCells.

The refactoring properly replaces Dictionary<Cell, boolean> with Map<Cell, boolean> for fast cell lookups during the cloning process.

Also applies to: 464-464


707-707: LGTM! Dictionary correctly replaced with native Map in removeCells.

The refactoring maintains the same fast lookup functionality for tracking cells to be removed, now using the native Map<Cell, boolean> instead of the custom Dictionary.

Also applies to: 710-710, 715-715


738-738: LGTM! Dictionary correctly replaced with native Map in cellsRemoved.

The change properly replaces the custom Dictionary with native Map for tracking processed cells during the removal process, preserving all functionality.

Also applies to: 741-741, 808-808


1223-1223: LGTM! Dictionary correctly replaced with native Map in moveCells.

The refactoring successfully updates the fast cell lookup mechanism in the move operation to use Map<Cell, boolean> instead of the custom Dictionary.

Also applies to: 1226-1226

packages/core/src/view/mixins/SelectionMixin.ts (1)

283-283: LGTM! Dictionary correctly replaced with native Map and improved naming.

The refactoring successfully replaces Dictionary<Cell, boolean> with Map<Cell, boolean> for tracking covered elements during change processing. The variable rename from dict to coveredElements also improves code readability.

Also applies to: 287-287, 289-289

packages/core/src/util/arrayUtils.ts (1)

113-114: LGTM! Dictionary correctly replaced with native Map, with improved typing and naming.

The refactoring successfully replaces the custom Dictionary with native Map for duplicate detection. The explicit function typing (arr: any[]): any[]) and descriptive variable name coveredEntries are also good improvements.

Also applies to: 118-118, 120-120

packages/core/src/view/mixins/ConnectionsMixin.ts (1)

375-378: LGTM! Clean Dictionary to Map migration.

The changes correctly replace the custom Dictionary with the native JavaScript Map:

  • Type annotation properly updated to Map<Cell, boolean>
  • Method call correctly changed from put() to set()
  • Existing get() calls remain unchanged since both APIs use the same method
packages/core/src/view/layout/hierarchical/CoordinateAssignment.ts (3)

295-309: LGTM! Correct Map initialization and method usage.

The changes properly migrate from Dictionary to Map:

  • Type annotation correctly updated to Map<GraphAbstractHierarchyCell, WeightedCellSorter>
  • Method call appropriately changed from put() to set()

861-861: LGTM! Proper conversion from Dictionary.getValues() to Map.values().

The change from model.edgeMapper.getValues() to Array.from(model.edgeMapper.values()) correctly handles the difference between Dictionary's getValues() (which returned an array) and Map's values() (which returns an iterator).


1034-1034: LGTM! Consistent conversion pattern applied.

Both instances correctly replace getValues() with Array.from(...values()), maintaining the same array output for the iteration logic while using the native Map API.

Also applies to: 1054-1054

packages/core/src/view/plugins/SelectionCellsHandler.ts (3)

57-57: LGTM! Property type and documentation correctly updated.

The property type is properly changed to Map<Cell, Handler> and the JSDoc comment is appropriately updated to remove the outdated Dictionary reference.

Also applies to: 100-100


134-134: LGTM! Comprehensive and correct API migration.

All method calls are properly updated:

  • visit()forEach() for iteration
  • Constructor changed from new Dictionary()new Map()

The forEach method provides the same functionality as the Dictionary's visit method.

Also applies to: 152-152, 184-184, 245-245, 256-256, 267-267


162-163: LGTM! Correct handler manipulation methods.

All Dictionary methods are properly migrated to Map equivalents:

  • put()set() for adding entries
  • remove()delete() for removing entries (with appropriate get() calls to retrieve handlers first)

The pattern of getting the handler before deleting it maintains the original logic correctly.

Also applies to: 178-178, 199-199, 218-219, 231-231

packages/core/src/view/layout/GraphLayout.ts (1)

145-145: LGTM! Complete migration of traverse method to use Map.

The changes correctly update the traverse method:

  • JSDoc parameter documentation properly updated to reflect Map type
  • Default initialization correctly changed to new Map()
  • Method call appropriately changed from put() to set()

This aligns with the GraphLayoutTraverseArgs interface where visited is typed as Map<Cell, boolean> | null.

Also applies to: 150-150, 153-153

packages/core/src/view/cell/CellRenderer.ts (5)

433-433: LGTM: Correct Map initialization

The initialization of createdOverlays using native Map is consistent with the refactoring objective.


436-439: LGTM: Proper Map method usage

The conversion from Dictionary methods to Map methods is correctly implemented:

  • state.overlays.get(cellOverlay) replaces Dictionary get operation
  • state.overlays.delete(cellOverlay) replaces Dictionary remove operation
  • createdOverlays.set(cellOverlay, shape) replaces Dictionary put operation

454-456: LGTM: Correct forEach usage

The replacement of Dictionary.visit() with Map.forEach() maintains the same iteration semantics while using the native Map API.


1090-1090: LGTM: Consistent Map iteration

The forEach method correctly replaces the previous Dictionary iteration pattern.


1464-1468: LGTM: Proper cleanup and reset

The destruction and reset of overlays using Map methods maintains the same cleanup semantics as the original Dictionary implementation.

packages/core/src/util/treeTraversal.ts (3)

114-114: LGTM: Updated documentation

The JSDoc comment correctly reflects the change from Dictionary to Map in the parameter type.


123-123: LGTM: Correct parameter type update

The parameter type change from Dictionary<Cell, boolean> to Map<Cell, boolean> maintains type safety while using the native Map.


129-132: LGTM: Proper Map usage in traversal logic

The conversion is correctly implemented:

  • new Map<Cell, boolean>() replaces Dictionary initialization
  • visited.set(vertex, true) replaces visited.put(vertex, true)

The traversal logic remains unchanged, ensuring behavioral compatibility.

packages/core/src/util/cellArrayUtils.ts (3)

63-67: LGTM: Correct Map initialization and usage in getTopmostCells

The conversion from Dictionary to Map is properly implemented:

  • new Map<Cell, boolean>() correctly initializes the coverage tracking
  • coveredEntries.set(cells[i], true) replaces the Dictionary put operation

76-76: LGTM: Proper Map.get() usage

The coveredEntries.get(parent) call correctly replaces the Dictionary get operation while maintaining the same lookup semantics.


97-102: LGTM: Consistent Map usage in getParents function

The Map operations are correctly implemented:

  • new Map<Cell, boolean>() for parent tracking initialization
  • coveredParents.get(parent) for duplicate detection
  • coveredParents.set(parent, true) for marking visited parents

The function logic remains unchanged while using native Map.

packages/core/src/view/cell/CellStatePreview.ts (5)

25-29: LGTM: Improved type safety with CellDelta interface

The introduction of the CellDelta interface enhances type safety by explicitly defining the structure of delta objects instead of using an anonymous type. This is a good improvement alongside the Dictionary to Map conversion.


36-36: LGTM: Correct Map initialization

The constructor properly initializes the deltas property with new Map() instead of the previous Dictionary.


45-45: LGTM: Enhanced type annotation

The property type Map<Cell, CellDelta> provides better type safety than the previous Dictionary with anonymous object type.


71-71: LGTM: Correct Map.set() usage

The deltas.set(state.cell, delta) call properly replaces the Dictionary put operation.


92-98: LGTM: Proper Map iteration with forEach

The conversion from Dictionary.visit() to Map.forEach() maintains the same iteration semantics for both the translation and revalidation phases of the preview.

packages/core/src/view/layout/hierarchical/SwimlaneModel.ts (1)

58-60: LGTM: Clean Dictionary to Map conversion

The refactoring correctly replaces the custom Dictionary class with native JavaScript Map:

  • Property types updated to Map<Cell, GraphHierarchyNode/Edge>
  • Initialization uses new Map() constructor
  • Method calls properly converted: .put().set(), .getValues()Array.from(.values())

The semantic behavior is preserved while gaining the benefits of native Map performance and standardization.

Also applies to: 128-133, 192-192, 241-241, 305-305

packages/core/src/view/GraphView.ts (4)

178-178: LGTM: Property and method signature updates

The states property and setStates method correctly transition from Dictionary<Cell, CellState> to Map<Cell, CellState>, maintaining type safety while using the native Map interface.

Also applies to: 312-312


948-949: LGTM: Proper Map API usage with null handling

The getState method correctly uses:

  • Map.get() with nullish coalescing (?? null) to maintain the existing null return behavior
  • Map.set() instead of the custom .put() method

The semantic behavior is preserved.

Also applies to: 954-954


972-972: LGTM: Array conversion for Map values

The getCellStates method correctly uses Array.from(this.states.values()) to replace the custom .getValues() method, maintaining the same return type of CellState[].


992-994: LGTM: Map deletion API usage

The removeState method properly uses:

  • Map.get() with nullish coalescing for retrieval
  • Map.delete() instead of the custom .remove() method

The state cleanup logic remains intact.

Comment on lines +1081 to 1092
this.allCells.forEach((state: CellState | null) => {
const realState = state ? this.graph.view.getState(state.cell) : null;

// Checks if cell was removed or replaced
if (realState !== state && state) {
state.destroy();

if (realState) {
this.allCells.put(state.cell, realState);
this.allCells.set(state.cell, realState);
} else {
this.allCells.remove(state.cell);
this.allCells.delete(state.cell);
}
Copy link

@coderabbitai coderabbitai bot Jun 26, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Mutating Map during forEach risks skipping entries

Inside the live-preview loop you call delete / set on this.allCells while iterating the same map.
The current logic works most of the time, but per the spec keys deleted before they are reached are skipped silently, which can lead to missed clean-up if a cell is re-inserted earlier in the iteration.

Safer pattern:

- this.allCells.forEach((state) => {
-
-   if (realState) this.allCells.set(state.cell, realState);
-   else           this.allCells.delete(state.cell);
- });
+ const pending: [Cell, CellState | null][] = [];
+ this.allCells.forEach((state) => {
+
+   pending.push([state.cell, realState]);   // record change
+ });
+ pending.forEach(([c, s]) => {
+   if (s) this.allCells.set(c, s);
+   else   this.allCells.delete(c);
+});

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/core/src/view/plugins/SelectionHandler.ts around lines 1081 to 1092,
the code mutates the this.allCells Map by calling set and delete inside a
forEach loop iterating over the same Map, which can cause entries to be skipped.
To fix this, avoid mutating the Map during iteration by first collecting the
keys or entries to update or delete in a separate array, then after the loop
completes, perform the set and delete operations on this.allCells. This ensures
all entries are processed without skipping due to mutation during iteration.

Copy link
Member Author

Choose a reason for hiding this comment

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

I understand this remark (and all other about this topic).
The code is coming from mxGraph and the logic hasn't been updated as part of this PR. If we want to improve this, we will do it in a dedicated PR.

Copy link

Choose a reason for hiding this comment

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

@tbouffard Understood! You're absolutely right to keep this PR focused on the Dictionary → Map migration. The forEach mutation issue is indeed a separate concern that can be addressed in a future PR dedicated to improving the underlying logic.

Thanks for maintaining clear scope boundaries - it makes the refactoring much easier to review and ensures the core objective stays on track.

🐰✨ rabbit thoughtfully notes the importance of focused refactoring


✏️ Learnings added
Learnt from: tbouffard
PR: maxGraph/maxGraph#857
File: packages/core/src/view/plugins/SelectionHandler.ts:1081-1092
Timestamp: 2025-06-26T13:27:18.983Z
Learning: User tbouffard prefers to keep PRs focused on their main objective and defer implementation improvements or logic fixes to future dedicated PRs. For maxGraph, refactoring PRs like Dictionary→Map migration should not include unrelated logic improvements even when valid issues are identified in the migrated code.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: tbouffard
PR: maxGraph/maxGraph#776
File: packages/core/src/view/AbstractGraph.ts:492-495
Timestamp: 2025-04-24T12:34:56.726Z
Learning: PR #776 focuses on refactoring to introduce AbstractGraph as a base class and moving code from Graph to AbstractGraph. Type improvements and other refinements should be addressed in future PRs to keep this one focused on the core architectural change.

Learnt from: tbouffard
PR: maxGraph/maxGraph#593
File: .github/workflows/create-github-release.yml:42-42
Timestamp: 2025-01-28T16:22:25.804Z
Learning: In the GitHub release notes template for maxGraph, TODO comments are intentionally included to mark sections that must be reviewed by maintainers before publishing the release. These TODOs should not be removed or converted to validation steps as they are part of the release review process.

Learnt from: tbouffard
PR: maxGraph/maxGraph#740
File: packages/core/src/util/requestUtils.ts:79-106
Timestamp: 2025-03-31T08:32:17.055Z
Learning: PR #740 is focused on reorganizing code into namespaces (guiUtils and requestUtils) without changing any implementations. Implementation improvements should be suggested for future PRs.

Learnt from: tbouffard
PR: maxGraph/maxGraph#849
File: packages/html/stories/DragSource.stories.js:98-101
Timestamp: 2025-06-13T07:48:10.300Z
Learning: User tbouffard prefers answers in English; avoid switching to other languages in future replies.

Learnt from: tbouffard
PR: maxGraph/maxGraph#715
File: packages/html/stories/ZoomAndFit.stories.ts:0-0
Timestamp: 2025-03-14T06:01:22.326Z
Learning: For future improvements to the Graph component in maxGraph, tbouffard is interested in refactoring the `fit` method to use an object parameter pattern instead of multiple positional parameters, as the current approach makes the API harder to use when many parameters need to be specified with default values.

coderabbitai bot added a commit that referenced this pull request Jun 26, 2025
Docstrings generation was requested by @tbouffard.

* #857 (comment)

The following files were modified:

* `packages/core/src/util/treeTraversal.ts`
Copy link

coderabbitai bot commented Jun 26, 2025

Note

Generated docstrings for this pull request at #858

Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
4.3% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@tbouffard tbouffard changed the title refactor!: remove Dictionary and use ECMAScript Map instead refactor!: remove Dictionary and use Map instead Jun 26, 2025
@tbouffard tbouffard merged commit cb6ff9a into main Jun 27, 2025
6 of 7 checks passed
@tbouffard tbouffard deleted the refactor/remove_dictionary branch June 27, 2025 07:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Code refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove the Dictionary class

1 participant