Skip to content

feat: allow to pass more null and undefined to Multiplicity#914

Merged
tbouffard merged 4 commits intomainfrom
refactor/migrate_Validation_story_to_TS
Sep 12, 2025
Merged

feat: allow to pass more null and undefined to Multiplicity#914
tbouffard merged 4 commits intomainfrom
refactor/migrate_Validation_story_to_TS

Conversation

@tbouffard
Copy link
Member

@tbouffard tbouffard commented Sep 11, 2025

Restore the behavior available in mxGraph to ease the migration.

In addition:

  • Improve nullish management in various related places
  • Improve JSDoc
  • Validation mixin type: remove duplicated declaration of multiplicities already defined in AbstractGraph
  • Migrate the Validation story to TypeScript to ease maintenance and detect errors earlier

Summary by CodeRabbit

  • New Features

    • Example/demo now supports plugin-based rubber-band selection and improved demo layout/text.
  • Bug Fixes

    • Standardized null/undefined handling across DOM utilities, validation, and multiplicity checks to reduce errors with missing attributes or values.
  • Refactor

    • Validation and multiplicity handling made more tolerant of absent metadata and nullish inputs for safer, more consistent behavior.
  • Documentation

    • Updated examples to the latest graph APIs and key handling; fixed story links and clarified cell getter/setter docs.

Restore the behavior available in mxGraph to ease the migration.

In addition:
  - Improve nullish management in various related places
  - Improve JSDoc
  - Validation mixin type: remove duplicated declaration of `multiplicities` already defined in AbstractGraph
  - Migrate the Validation story to TypeScript to ease maintenance and detect errors earlier
@tbouffard tbouffard added the enhancement New feature or request label Sep 11, 2025
@coderabbitai
Copy link

coderabbitai bot commented Sep 11, 2025

Walkthrough

Standardized null/undefined handling via isNullish across core utilities and validation; widened nullable types and signatures in Multiplicity; removed multiplicities from Validation mixin type augmentation; migrated Validation story to plugin-based Graph usage and object-form insertVertex/insertEdge APIs; minor docs and JSDoc tweaks.

Changes

Cohort / File(s) Summary of Changes
DOM util nullish checks
packages/core/src/util/domUtils.ts
Replaced direct null/undefined checks with isNullish, made isNode accept nullable attribute params and adjusted internal checks to use typeof ... === 'number' and loose equality for attribute comparisons.
Validation logic nullability
packages/core/src/view/mixins/ValidationMixin.ts
Swapped legacy != null checks for !isNullish(...), removed several <Cell> casts in favor of direct usage or non-null assertions; preserved behavior while standardizing nullish handling.
Validation mixin types
packages/core/src/view/mixins/ValidationMixin.type.ts
Removed multiplicities: Multiplicity[] from AbstractGraph module augmentation.
Multiplicity nullability & API
packages/core/src/view/other/Multiplicity.ts
Broadened constructor and public fields to allow `null
Cell JSDoc
packages/core/src/view/cell/Cell.ts
Updated JSDoc references to use {@link value} and {@link geometry}; no runtime/signature changes.
Validation story → plugins & insert API
packages/html/stories/Validation.stories.ts
Switched to getDefaultPlugins() with conditional RubberBandHandler in plugins, construct new Graph(container, undefined, plugins), migrated insertVertex/insertEdge to object-parameter form, adjusted handlers/listeners and story wrapper return.
Guide story comment
packages/html/stories/Guides.stories.ts
Added a comment referencing issue maxGraph/issues/910; no functional change.
Docs links
packages/website/docs/usage/i18n.md
Updated two links from Validation.stories.js to Validation.stories.ts.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Story as Validation.story
  participant Plugins as getDefaultPlugins()
  participant Graph as Graph
  participant RB as RubberBandHandler
  participant Val as Validation Pipeline

  User->>Story: load story
  Story->>Plugins: getDefaultPlugins()
  alt rubberBand enabled
    Plugins->>RB: push RubberBandHandler
  end
  Story->>Graph: new Graph(container, undefined, plugins)
  Story->>Graph: insertVertex({ ... }) / insertEdge({ ... })
  User->>Graph: interact (create/connect/delete)
  Graph->>Val: trigger validation
  Val-->>Graph: return error or ok
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Pre-merge checks (2 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The current description states the high-level intent but does not follow the repository's required template: the PR checklist is not completed, there is no linked issue number, no explicit notes about tests/screenshots, and it omits concrete details about API/signature changes (for example the Multiplicity constructor and method signature widenings) that are present in the diff. Please update the PR description to use the provided template: check the PR Checklist items, link or reference any related issue(s), provide a detailed Overview describing the behavioral and API changes (including signature changes to Multiplicity and any migration notes), list tests or Storybook updates that demonstrate the change, and add Notes about backward-compatibility or required follow-ups and any screenshots if applicable.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "feat: allow to pass more null and undefined to Multiplicity" clearly and concisely names the primary change (widening null/undefined handling for Multiplicity), follows the Conventional Commits style, and contains no noisy extras; it aligns with the PR objectives and the raw change summary.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


📜 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 0f7c24f and 1986023.

📒 Files selected for processing (3)
  • packages/core/src/util/domUtils.ts (2 hunks)
  • packages/core/src/view/cell/Cell.ts (2 hunks)
  • packages/core/src/view/mixins/ValidationMixin.type.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • packages/core/src/view/mixins/ValidationMixin.type.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/src/util/domUtils.ts
  • packages/core/src/view/cell/Cell.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build
  • GitHub Check: build (windows-2022)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (ubuntu-24.04)
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/migrate_Validation_story_to_TS

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

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 0

🧹 Nitpick comments (6)
packages/html/stories/Guides.stories.ts (1)

145-148: Good breadcrumb to the issue; add a small focus workaround to help KeyHandler in Storybook

Given the iframe focus quirk (see prior learnings), make the container focusable before calling focus() to improve key handling reliability.

Add near Line 141 (outside this hunk):

// Ensure container is focusable in Storybook iframe before focusing
container.tabIndex = 0;
packages/core/src/view/cell/Cell.ts (1)

236-245: Nit: align remaining tags to use {@link} consistently

There are still angle-bracket mentions of geometry. Consider switching to {@link geometry} for consistency.

-   * Returns the {@link Geometry} that describes the <geometry>.
+   * Returns the {@link Geometry} that describes the {@link geometry}.
...
-   * Sets the {@link Geometry} to be used as the <geometry>.
+   * Sets the {@link Geometry} to be used as the {@link geometry}.
packages/core/src/util/domUtils.ts (2)

224-229: Signature widened correctly; tiny doc follow-up

Allowing attributeName/attributeValue to be null aligns with the PR goals. Consider updating the JSDoc above to explicitly mention string | null for these params.


230-238: Minor clarity tweaks in isNode

  • Prefer a direct type check over isNaN for nodeType.
  • Keep the loose equality but document why, to avoid future eqeqeq “fixes” that would change semantics.
-    !isNaN(value.nodeType) &&
+    typeof value.nodeType === 'number' &&
     (isNullish(nodeName) || value.nodeName.toLowerCase() == nodeName.toLowerCase())
   ) {
-    return (
-      isNullish(attributeName) || value.getAttribute(attributeName) == attributeValue
-    );
+    // Intentionally using loose equality to treat null and undefined as equivalent here.
+    return isNullish(attributeName) || value.getAttribute(attributeName) == attributeValue;
   }
packages/html/stories/Validation.stories.ts (2)

53-53: Fix arg typing: story args include booleans, not just strings

rubberBand (and others) are booleans; typing as Record<string, string> is misleading. Relax to any for now (stories are JS-driven), or introduce a proper Args type later.

-const Template = ({ label, ...args }: Record<string, string>) => {
+const Template = ({ label, ...args }: Record<string, any>) => {

124-128: Help the Delete key binding in Storybook by ensuring focus

To mitigate iframe focus issues, make the container focusable and focus it before creating/binding the KeyHandler.

   // Removes cells when [DELETE] is pressed
   // TODO pressing the delete key has no effect in FF and Chrome (https://github.com/maxGraph/maxGraph/issues/910)
-  const keyHandler = new KeyHandler(graph);
+  // Ensure the container can receive focus for key events in Storybook iframes
+  container.tabIndex = 0;
+  container.focus();
+  const keyHandler = new KeyHandler(graph);
   keyHandler.bindKey(46, function () {
     if (graph.isEnabled()) {
       graph.removeCells();
     }
   });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55074e6 and 0f7c24f.

📒 Files selected for processing (8)
  • packages/core/src/util/domUtils.ts (2 hunks)
  • packages/core/src/view/cell/Cell.ts (1 hunks)
  • packages/core/src/view/mixins/ValidationMixin.ts (3 hunks)
  • packages/core/src/view/mixins/ValidationMixin.type.ts (0 hunks)
  • packages/core/src/view/other/Multiplicity.ts (6 hunks)
  • packages/html/stories/Guides.stories.ts (1 hunks)
  • packages/html/stories/Validation.stories.ts (3 hunks)
  • packages/website/docs/usage/i18n.md (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/core/src/view/mixins/ValidationMixin.type.ts
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: tbouffard
PR: maxGraph/maxGraph#835
File: packages/html/stories/Orthogonal.stories.ts:114-117
Timestamp: 2025-05-26T12:34:54.318Z
Learning: The `null!` assertion pattern exists across multiple stories in the TypeScript migration and should be addressed systematically rather than in individual 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.
📚 Learning: 2025-08-28T14:07:42.556Z
Learnt from: tbouffard
PR: maxGraph/maxGraph#908
File: packages/html/stories/Guides.stories.ts:0-0
Timestamp: 2025-08-28T14:07:42.556Z
Learning: KeyHandler does not work properly in Storybook environment due to iframe context - keyboard events added to document.documentElement in iframe don't receive events properly. This affects all maxGraph stories that use KeyHandler, with several stories having KeyHandler commented out with "TODO not working" comments.

Applied to files:

  • packages/html/stories/Guides.stories.ts
📚 Learning: 2025-08-28T14:07:42.556Z
Learnt from: tbouffard
PR: maxGraph/maxGraph#908
File: packages/html/stories/Guides.stories.ts:0-0
Timestamp: 2025-08-28T14:07:42.556Z
Learning: KeyHandler issues in Storybook are due to iframe isolation - Storybook renders stories in iframes where keyboard events don't properly reach document.addEventListener without explicit focus management. The solution is to ensure the iframe window has focus by calling window.focus() and focusing the target element in the preview configuration or story setup.

Applied to files:

  • packages/html/stories/Guides.stories.ts
📚 Learning: 2024-12-15T18:19:56.236Z
Learnt from: tbouffard
PR: maxGraph/maxGraph#598
File: packages/website/docs/manual/getting-started.md:70-70
Timestamp: 2024-12-15T18:19:56.236Z
Learning: In code examples within the documentation, such as in `packages/website/docs/manual/getting-started.md`, we assume that the `graph-container` element exists and is an `HTMLElement`, and we avoid adding error handling for its initialization to keep the code simple.

Applied to files:

  • packages/html/stories/Validation.stories.ts
🧬 Code graph analysis (4)
packages/core/src/util/domUtils.ts (1)
packages/core/src/internal/utils.ts (1)
  • isNullish (44-45)
packages/core/src/view/mixins/ValidationMixin.ts (1)
packages/core/src/internal/utils.ts (1)
  • isNullish (44-45)
packages/html/stories/Validation.stories.ts (2)
packages/html/stories/shared/configure.js (1)
  • createMainDiv (53-63)
packages/core/src/view/plugins/index.ts (1)
  • getDefaultPlugins (46-55)
packages/core/src/view/other/Multiplicity.ts (4)
packages/core/src/internal/i18n-utils.ts (1)
  • translate (29-35)
packages/core/src/view/cell/Cell.ts (1)
  • Cell (66-886)
packages/core/src/internal/utils.ts (1)
  • isNullish (44-45)
packages/core/src/util/domUtils.ts (1)
  • isNode (224-241)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build
  • GitHub Check: build (macos-14)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: build (windows-2022)
🔇 Additional comments (19)
packages/website/docs/usage/i18n.md (1)

74-75: LGTM: link updated to TS story

The source link now points to Validation.stories.ts, matching the migration. No further changes needed.

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

210-214: JSDoc reference fix looks good

Using {@link value} is consistent with the rest of the file.


217-221: JSDoc reference fix looks good

Same here; consistent and clearer.

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

18-19: Importing isNullish is appropriate for the new semantics

This matches the nullish-first approach used across the PR.

packages/html/stories/Validation.stories.ts (2)

68-74: Plugin-based RubberBand integration: LGTM

Using getDefaultPlugins() and conditionally pushing RubberBandHandler is clean and keeps the story consistent with the plugin model.


141-184: Object-form insert APIs: LGTM

Updated insertVertex/insertEdge calls match the new signatures and improve readability.

packages/core/src/view/mixins/ValidationMixin.ts (6)

21-21: LGTM! Good use of the centralized isNullish utility.

The import of isNullish from the internal utilities promotes consistency across the codebase for nullish checking.


116-118: LGTM! Consistent nullish checking pattern.

Replacing err != null with !isNullish(err) standardizes the nullish checking approach across the validation logic.


123-125: LGTM! Consistent error handling pattern.

Good consistency with the nullish checking pattern using isNullish.


190-190: LGTM! Removed unnecessary type cast.

Removing the <Cell>cell cast and passing cell directly is cleaner since the type is already known.


194-197: LGTM! Consistent nullish checking applied.

The nullish checking pattern is consistently applied here as well.


122-122: Remove the non-null assertion on edge when calling validateEdge.
validateEdge is declared to accept a nullable edge; edge! hides that and can mask cases where edge === null. Change:
packages/core/src/view/mixins/ValidationMixin.ts
const err = this.validateEdge(edge!, source, target);
to
const err = this.validateEdge(edge, source, target);
Verify there are no overrides that assume a non-null edge before removing the !.

packages/core/src/view/other/Multiplicity.ts (7)

23-23: LGTM! Consistent use of centralized isNullish utility.

Good alignment with the validation mixin changes by using the same utility function.


27-27: Documentation correctly updated to reference AbstractGraph.multiplicities.

The JSDoc now accurately reflects where multiplicities are stored.


29-44: Well-documented example with the updated constructor signature.

The example clearly demonstrates the new constructor parameters including the nullish values, making it easier for developers to understand the API changes.


50-57: Constructor signature properly widened to accept nullish values.

The parameters attr, value, validNeighbors, countError, and typeError now accept null | undefined, which aligns with the PR objective to restore mxGraph behavior for easier migration.


65-67: Good defensive programming with fallback values.

The use of nullish coalescing (??) ensures sensible defaults:

  • validNeighbors defaults to an empty array
  • countError and typeError are normalized to empty strings when nullish

This prevents potential runtime errors while maintaining backward compatibility.


179-179: Parameter naming convention for unused parameters.

Good practice using the underscore prefix (_edge) to indicate unused parameters. This clearly communicates intent to other developers.

Also applies to: 204-204


220-233: Robust type checking with early return and proper DOM node detection.

The refactored checkType method:

  1. Early returns false for nullish values (defensive programming)
  2. Properly checks for DOM nodes using a more explicit approach
  3. Falls back to strict equality for non-DOM values

The DOM node check is more robust than before, explicitly checking for the presence of nodeType property.

@sonarqubecloud
Copy link

@tbouffard tbouffard merged commit 207290a into main Sep 12, 2025
7 checks passed
@tbouffard tbouffard deleted the refactor/migrate_Validation_story_to_TS branch September 12, 2025 07:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant