refactor!: convert ImageMixin to ImageBundlePlugin by tbouffard · Pull Request #1050 · maxGraph/maxGraph · GitHub
Skip to content

refactor!: convert ImageMixin to ImageBundlePlugin#1050

Merged
redfish4ktc merged 14 commits into
mainfrom
refactor/migrate-image-mixin-to-plugin
Apr 24, 2026
Merged

refactor!: convert ImageMixin to ImageBundlePlugin#1050
redfish4ktc merged 14 commits into
mainfrom
refactor/migrate-image-mixin-to-plugin

Conversation

@tbouffard

@tbouffard tbouffard commented Apr 22, 2026

Copy link
Copy Markdown
Member

Replace ImageMixin with a dedicated ImageBundlePlugin (id 'image-bundle'). Mixins share a single state tree across all Graph instances and pollute AbstractGraph with domain-specific methods; plugins are per-instance, opt-in on BaseGraph, and keep AbstractGraph lean.

The plugin ships in getDefaultPlugins() so Graph users see no behavioral change. BaseGraph consumers must now opt in explicitly by adding ImageBundlePlugin to the plugins option. CellsMixin.postProcessCellStyle delegates bundle key resolution to the plugin via graph.getPlugin<ImageBundlePlugin>('image-bundle'); when the plugin is not registered the raw CellStateStyle.image is used as-is, matching the pre-existing "no bundle matched" path.

Also:

  • Add characterization tests for CellsMixin.postProcessCellStyle covering all 12 paths prior to the refactor so behavior preservation is verified, then merge them into the existing CellsMixin.test.ts suite, including an explicit plugin-absent case that guards the new optional-chain lookup.
  • Add unit tests for ImageBundlePlugin covering per-graph isolation, add/remove semantics, first-match-wins lookup, and onDestroy bundle clearing.
  • Add a Storybook story (packages/html/stories/ImageBundle.stories.ts) demonstrating bundle registration and usage.
  • Add a usage guide at packages/website/docs/usage/image-bundles.md covering registration, BaseGraph opt-in, and the XML-serialization change.
  • Document the plugin-id kebab-case naming convention in .claude/rules/architecture/coding-practices.md.
  • Reduce chunkSizeWarningLimit in ts-example-without-defaults now that the example no longer pulls the image-bundle code path into its bundle.
  • Record the migration under Unreleased breaking changes in CHANGELOG.md.

Non-breaking API changes

  • ImageBundle.putImage() and the ImageMap entry type now treat fallback as optional. The legacy mxGraph IE6/7 fallback path is preserved but flagged for potential removal in a future release; callers without a legacy-browser story no longer need to supply one.

BREAKING CHANGE:

  • AbstractGraph.addImageBundle, removeImageBundle, getImageFromBundles and the imageBundles property no longer exist on AbstractGraph, Graph, or BaseGraph. Migrate mutating call sites from graph.addImageBundle(bundle) (and siblings) to graph.getPlugin<ImageBundlePlugin>('image-bundle')!.addImageBundle(bundle). The non-null assertion is deliberate: if the plugin is not registered, the call must fail fast rather than silently drop the bundle registration. For read-only access, graph.getPlugin<ImageBundlePlugin>('image-bundle')?.imageBundles is appropriate because returning undefined when the plugin is absent matches the "no bundle matched" path already relied on by CellsMixin.postProcessCellStyle.
  • BaseGraph no longer ships image-bundle support by default. Add ImageBundlePlugin to the plugins option to opt in. Graph continues to work unchanged because ImageBundlePlugin is part of getDefaultPlugins().
  • XML serialization of <Graph>/<BaseGraph> no longer emits <Array as="imageBundles" />. Existing XML documents containing that element still decode without error but the field is silently ignored. Consumers that persist bundles as part of the graph XML must now serialize the plugin state separately.
  • CellsMixin.postProcessCellStyle silently skips bundle key resolution when ImageBundlePlugin is not registered — the raw CellStateStyle.image value is used as the image path. This matches the pre-existing "no bundle matched" behavior and is only relevant for BaseGraph consumers that do not add the plugin.

Notes

Covers #762

Bundle size impact (tree-shaking)

Measured against main at 6bc0f020ffa628f880701cc251f2e5cf9d0bb305:

Example main (6bc0f020) this PR
js-example 467.94 kB 467.92 kB
js-example-selected-features 386.69 kB 386.21 kB
js-example-without-defaults 321.28 kB 320.94 kB
ts-example 433.85 kB 433.88 kB
ts-example-selected-features 366.59 kB 366.24 kB
ts-example-without-defaults 304.04 kB 303.69 kB

Every example that does not bundle ImageBundlePlugin (*-without-defaults and *-selected-features) shrinks by roughly 0.3–0.5 kB, confirming that the image-bundle code path is now tree-shakable — which was not possible while it lived inside ImageMixin on AbstractGraph. The full-featured Graph examples are essentially flat (within ±0.05 kB), as expected: the plugin still ships by default there, only the wiring layer changed.

Out of scope (bundled)

  • .claude/rules/git/commit-conventions.md: documents the ! + uppercase BREAKING CHANGE: footer convention actually used by this PR's main commit, and realigns body wrap to 120 columns. A split-out PR is not worth the overhead since the rule change is exactly what this PR demonstrates.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Breaking Changes

    • ImageMixin removed; image-bundle behavior moved to a plugin. Graphs no longer serialize imageBundles by default; legacy entries are ignored on import. BaseGraph must opt into the plugin; Graph includes it by default.
  • New Features

    • Added ImageBundle plugin and runtime bundle management; style.image may reference bundle keys resolved to URLs/data URIs.
  • Tests

    • New/updated tests for plugin behavior, isolation, lookup order, normalization, and serialization.
  • Documentation

    • Usage docs and changelog updated.
  • Stories

    • Storybook example demonstrating image-bundle usage.

Replace ImageMixin with a dedicated ImageBundlePlugin (id 'image-bundle').
Mixins share a single state tree across all Graph instances and pollute AbstractGraph with domain-specific methods;
plugins are per-instance, opt-in on BaseGraph, and keep AbstractGraph lean.

The plugin ships in getDefaultPlugins() so Graph users see no behavioral change. BaseGraph consumers must now opt
in explicitly by adding ImageBundlePlugin to the plugins option. CellsMixin.postProcessCellStyle delegates bundle
key resolution to the plugin via graph.getPlugin<ImageBundlePlugin>('image-bundle'); when the plugin is not
registered the raw CellStateStyle.image is used as-is, matching the pre-existing "no bundle matched" path.

Also:
- Add characterization tests for CellsMixin.postProcessCellStyle covering all 12 paths prior to the refactor so
  behavior preservation is verified, then merge them into the existing CellsMixin.test.ts suite.
- Add unit tests for ImageBundlePlugin covering per-graph isolation, add/remove semantics, first-match-wins
  lookup, and onDestroy bundle clearing.
- Document the plugin-id kebab-case naming convention in .claude/rules/architecture/coding-practices.md.
- Reduce chunkSizeWarningLimit in ts-example-without-defaults now that the example no longer pulls the
  image-bundle code path into its bundle.
- Record the migration under Unreleased breaking changes in CHANGELOG.md.

BREAKING CHANGES:
- AbstractGraph.addImageBundle, removeImageBundle, getImageFromBundles and the imageBundles property no longer
  exist on AbstractGraph, Graph, or BaseGraph. Migrate to
  graph.getPlugin<ImageBundlePlugin>('image-bundle')?.addImageBundle(bundle) and siblings.
- BaseGraph no longer ships image-bundle support by default; add ImageBundlePlugin to the plugins option to opt in.
- XML serialization of <Graph>/<BaseGraph> no longer emits <Array as="imageBundles" />. Existing XML documents
  containing that element still decode without error but the field is silently ignored. Consumers that persist
  bundles as part of the graph XML must now serialize the plugin state separately.
- CellsMixin.postProcessCellStyle silently skips bundle key resolution when ImageBundlePlugin is not registered.
  This only affects BaseGraph consumers that omit the plugin.
The explore/plan/tasks files served their purpose during implementation; drop them from the branch now that the
migration has landed. Keeping them in-tree would clutter the repo with one-off process artifacts.
@tbouffard tbouffard added the refactor Code refactoring label Apr 22, 2026
@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Image-bundle behavior was moved out of AbstractGraph/ImageMixin into a new ImageBundlePlugin ('image-bundle'). Graphs opt into the plugin (Graph via defaults, BaseGraph via options). Serialization no longer emits imageBundles; CellsMixin delegates bundle lookup to the plugin when present and preserves raw image values when absent.

Changes

Cohort / File(s) Summary
Changelog & docs
CHANGELOG.md, packages/website/docs/usage/image-bundles.md
Documented breaking change, migration guidance, plugin usage, and new image-bundles usage docs.
Plugin implementation & exports
packages/core/src/view/plugin/ImageBundlePlugin.ts, packages/core/src/view/plugin/index.ts
Added ImageBundlePlugin ('image-bundle') with registry, add/remove/get APIs, onDestroy; exported and added to default plugins.
Core types & graph
packages/core/src/types.ts, packages/core/src/view/AbstractGraph.ts
Added 'image-bundle' to BuiltinPluginId; removed imageBundles field and its ImageBundle import from AbstractGraph.
ImageBundle class
packages/core/src/view/image/ImageBundle.ts
putImage(..., fallback?) now accepts optional fallback; ImageMap fallback typing and docs updated to recommend plugin registration.
Removed mixin & types
packages/core/src/view/mixin/ImageMixin.ts, packages/core/src/view/mixin/ImageMixin.type.ts, packages/core/src/view/mixin/_graph-mixins-apply.ts, packages/core/src/view/mixin/_graph-mixins-types.ts
Removed ImageMixin implementation and its AbstractGraph augmentation; stopped applying/importing the mixin.
CellsMixin update
packages/core/src/view/mixin/CellsMixin.ts, packages/core/src/view/mixin/CellsMixin.type.ts
postProcessCellStyle now resolves via this.getPlugin<ImageBundlePlugin>('image-bundle')?.getImageFromBundles(key); PartialGraph types use getPlugin; JSDoc clarified plugin-absent behavior and retained data-URI normalization.
Tests: plugin & cells
packages/core/__tests__/view/plugin/ImageBundlePlugin.test.ts, packages/core/__tests__/view/mixin/CellsMixin.test.ts, packages/core/__tests__/view/plugin/index.test.ts
Added ImageBundlePlugin tests; expanded CellsMixin tests for postProcessCellStyle and data-URI normalization; updated default plugins count expectation.
Tests: removed serialization & isolation checks
packages/core/__tests__/serialization/codec/all-graph-classes.test.ts, packages/core/__tests__/view/BaseGraph.test.ts
Removed imageBundles from serialization test fixtures and removed legacy BaseGraph imageBundles isolation test (moved to plugin tests).
Examples & stories
packages/html/stories/ImageBundle.stories.ts
Added Storybook story demonstrating ImageBundlePlugin usage with inline SVG data URIs and image-keyed vertices.
Misc: build & commit rules
packages/ts-example-without-defaults/vite.config.js, .claude/rules/git/commit-conventions.md
Minor Vite config tweak and updated commit-convention wording and line-wrap limit.

Sequence Diagram(s)

sequenceDiagram
  participant Cells as CellsMixin.postProcessCellStyle
  participant Graph as Graph/BaseGraph
  participant Plugin as ImageBundlePlugin
  participant Bundle as ImageBundle

  Cells->>Graph: getPlugin('image-bundle')
  Graph-->>Cells: ImageBundlePlugin | undefined
  alt Plugin present
    Cells->>Plugin: getImageFromBundles(key)
    Plugin->>Bundle: bundle.getImage(key) (in insertion order)
    Bundle-->>Plugin: image | null
    Plugin-->>Cells: first non-null image | null
    alt image found
      Cells->>Cells: normalize data-URI if needed\nset style.image = resolved image
    else no image
      Cells->>Cells: preserve original style.image (still run normalization)
    end
  else Plugin absent
    Cells->>Cells: preserve original style.image (still run normalization)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • Issue #762 — Same refactor objective: move image-bundle APIs from AbstractGraph/ImageMixin into a dedicated plugin accessed via getPlugin.

Possibly related PRs

  • PR #879 — Touches the same image-bundle surface and migration away from mixin/APIs on AbstractGraph.
  • PR #842 — Related to getPlugin typing and call-site changes that this PR relies on (optional chaining / non-null assertion).
  • PR #663 — Modifies applyGraphMixins usage; related to removal of ImageMixin from mixin application.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main refactoring effort: converting ImageMixin to ImageBundlePlugin, which is the central change across the codebase.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description thoroughly addresses all required template sections: checklist items are explained, overview details the problem (mixing shared state with domain-specific methods) and solution (per-instance plugin), breaking changes are documented with migration paths, and comprehensive notes cover tests, documentation, bundle impact, and out-of-scope items.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/view/image/ImageBundle.ts (1)

34-45: ⚠️ Potential issue | 🟡 Minor

Update documentation example to use TypeScript and modernize API calls.

Lines 34–45 mix a javascript code fence (line 34) with TypeScript generics syntax on line 45 (<ImageBundlePlugin>), which is invalid JavaScript and would fail if copied. Additionally, the example inconsistently uses the legacy mxImageBundle (line 35) alongside the new ImageBundlePlugin API (line 45).

Change the fence to typescript and update all API references to the current API:

Proposed documentation fix
- * ```javascript
- * let bundle = new mxImageBundle(alt);
+ * ```typescript
+ * const bundle = new ImageBundle(alt);
🧹 Nitpick comments (2)
packages/ts-example-without-defaults/vite.config.js (1)

30-30: LGTM! Bundle size limit appropriately adjusted.

The 1 kB reduction aligns with the PR's bundle-size impact (~0.3–0.5 kB shrinkage for examples omitting ImageBundlePlugin). Since ts-example-without-defaults likely omits the plugin, this calibration is appropriate.

📊 Optional: Verify the actual bundle size matches the new limit

After building, you may want to confirm the actual @maxgraph/core chunk size to ensure the limit is precisely calibrated:

#!/bin/bash
# Description: Build the ts-example-without-defaults package and check the maxgraph chunk size

cd packages/ts-example-without-defaults
npm run build 2>&1 | grep -i "maxgraph" || echo "Build output or chunk size info not found in build logs"
packages/core/__tests__/view/plugin/index.test.ts (1)

17-31: Assert the new default plugin explicitly.

The length check detects list-size drift, but it would still pass if ImageBundlePlugin were accidentally omitted and another plugin kept the count at 9. Add a targeted assertion for the behavior this PR depends on.

Proposed test strengthening
-import { getDefaultPlugins } from '../../../src';
+import { getDefaultPlugins, ImageBundlePlugin } from '../../../src';
@@
     const plugins = getDefaultPlugins();
     // detect any changes in default plugins, order does not matter
     expect(plugins).toHaveLength(9);
+    expect(plugins).toContain(ImageBundlePlugin);

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b281f3af-21d7-4715-abeb-3764bbf2ef8d

📥 Commits

Reviewing files that changed from the base of the PR and between bbaea99 and 34b1dc6.

📒 Files selected for processing (18)
  • CHANGELOG.md
  • packages/core/__tests__/serialization/codec/all-graph-classes.test.ts
  • packages/core/__tests__/view/BaseGraph.test.ts
  • packages/core/__tests__/view/mixin/CellsMixin.test.ts
  • packages/core/__tests__/view/plugin/ImageBundlePlugin.test.ts
  • packages/core/__tests__/view/plugin/index.test.ts
  • packages/core/src/types.ts
  • packages/core/src/view/AbstractGraph.ts
  • packages/core/src/view/image/ImageBundle.ts
  • packages/core/src/view/mixin/CellsMixin.ts
  • packages/core/src/view/mixin/CellsMixin.type.ts
  • packages/core/src/view/mixin/ImageMixin.ts
  • packages/core/src/view/mixin/ImageMixin.type.ts
  • packages/core/src/view/mixin/_graph-mixins-apply.ts
  • packages/core/src/view/mixin/_graph-mixins-types.ts
  • packages/core/src/view/plugin/ImageBundlePlugin.ts
  • packages/core/src/view/plugin/index.ts
  • packages/ts-example-without-defaults/vite.config.js
💤 Files with no reviewable changes (7)
  • packages/core/src/view/mixin/_graph-mixins-types.ts
  • packages/core/tests/serialization/codec/all-graph-classes.test.ts
  • packages/core/tests/view/BaseGraph.test.ts
  • packages/core/src/view/mixin/_graph-mixins-apply.ts
  • packages/core/src/view/AbstractGraph.ts
  • packages/core/src/view/mixin/ImageMixin.type.ts
  • packages/core/src/view/mixin/ImageMixin.ts

Comment thread CHANGELOG.md
Comment thread packages/core/__tests__/view/mixin/CellsMixin.test.ts
- Fix typos, switch the code fence to typescript, and convert legacy <name>
  doc links to {@link name} in the class-level JSDoc.
- Add a note flagging the fallback mechanism for potential removal in a future
  release (legacy mxGraph feature for IE6/7).
- Make fallback optional on the ImageMap entry and on putImage() so callers no
  longer need to supply one when there is no legacy-browser story.
The previous 'no bundle registered' test used a graph with the plugin registered but no bundles added, so it only
exercised the getImageFromBundles()-returns-null branch. Split it into two tests so the optional-chain branch
(plugin not registered on the graph) is also covered — this is the BaseGraph path that did not exist before the
mixin-to-plugin migration, and a regression dropping the ?. would otherwise go undetected.
The helper was nested inside the 'isValidAncestor' describe but is a pure, reusable fixture — Sonar flags nested
function declarations that don't need to live inside the block. Moving it to module scope matches the rest of the
helpers in this file and keeps scope aligned with lifetime.
…uidance

Switch the CHANGELOG migration example and the ImageBundle JSDoc snippet from optional chaining to a non-null
assertion when registering a bundle (graph.getPlugin<ImageBundlePlugin>('image-bundle')!.addImageBundle(bundle)).

With '?.' a missing plugin silently drops the bundle registration, which is exactly the kind of silent regression
callers migrating from the previous 'graph.addImageBundle(bundle)' method want to catch — if they rely on image
bundles, the plugin must be registered and the call must fail fast otherwise. The '?.' form remains appropriate
for read-only accessors (e.g. imageBundles, getImageFromBundles), where 'undefined' is a meaningful 'no plugin,
no bundle matched' result already relied on by CellsMixin.postProcessCellStyle.
@tbouffard tbouffard marked this pull request as draft April 23, 2026 05:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/core/src/view/image/ImageBundle.ts (1)

34-50: JSDoc example aligns with the new plugin API.

The updated snippet correctly reflects the removal of graph.addImageBundle and the move to graph.getPlugin<ImageBundlePlugin>('image-bundle')!.addImageBundle(bundle). The explicit note that BaseGraph users must register ImageBundlePlugin via plugins is useful given the opt-in behavior change.

One optional nit: the example still references a free-standing fallback identifier (lines 39 and 44) that is not declared in the snippet. Now that fallback is optional on putImage, you could simplify the example by omitting the third argument, which would also make the snippet copy-paste runnable.

✏️ Optional doc tweak
- *   'laSSASFQpIV5HJBDyHpqK2ejVRm2AAgZCdmCGO9CIBADs=', fallback);
+ *   'laSSASFQpIV5HJBDyHpqK2ejVRm2AAgZCdmCGO9CIBADs=');
@@
- *   '<rect fill="url(`#gradient`)" width="100%" height="100%"/></svg>'), fallback);
+ *   '<rect fill="url(`#gradient`)" width="100%" height="100%"/></svg>'));
packages/core/__tests__/view/mixin/CellsMixin.test.ts (1)

315-325: Minor: helper could honor the now-optional fallback.

Since ImageBundle.putImage no longer requires a fallback, registerBundle could pass fallback through as-is instead of substituting `${key}-fallback`. Not functionally wrong (the tests use alt=false so the fallback is never read), but the current default masks the optional-parameter contract and slightly complicates reasoning if a future test wants to assert undefined fallback behavior. Also, the returned ImageBundle is currently unused by any caller and could be dropped for simplicity.

✂️ Optional tightening
   const registerBundle = (
     graph: BaseGraph,
     entries: Array<{ key: string; value: string; fallback?: string }>
-  ): ImageBundle => {
+  ): void => {
     const bundle = new ImageBundle();
     for (const { key, value, fallback } of entries) {
-      bundle.putImage(key, value, fallback ?? `${key}-fallback`);
+      bundle.putImage(key, value, fallback);
     }
     graph.getPlugin<ImageBundlePlugin>('image-bundle')!.addImageBundle(bundle);
-    return bundle;
   };

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ecd01409-d238-45a1-99b3-773f756ca8de

📥 Commits

Reviewing files that changed from the base of the PR and between 34b1dc6 and 37ea024.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • packages/core/__tests__/view/mixin/CellsMixin.test.ts
  • packages/core/src/view/image/ImageBundle.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • CHANGELOG.md

Add a Breaking Changes section describing the convention used in ae05746: `!` after the type/scope plus an
uppercase `BREAKING CHANGES:` footer listing each break as a bullet. The prior standalone `!`-suffix line under
Types is removed — the new section now carries the full rule, avoiding a duplicate mention.

Also align the Body wrap guideline with the broader convention (120 columns) already used across the project.
@tbouffard tbouffard marked this pull request as ready for review April 24, 2026 05:46

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
.claude/rules/git/commit-conventions.md (1)

25-25: Change BREAKING CHANGES: to BREAKING CHANGE: to align with the official Conventional Commits specification.

The Conventional Commits specification (conventionalcommits.org) uses the singular form BREAKING CHANGE: in footer format, not plural. While projects can define custom conventions, adopting the standard form reduces confusion for contributors familiar with the specification. This affects lines 25 and 35.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6555ec6d-48cf-41a5-b43d-25bc86306e94

📥 Commits

Reviewing files that changed from the base of the PR and between 37ea024 and 443a2da.

📒 Files selected for processing (3)
  • .claude/rules/git/commit-conventions.md
  • packages/html/stories/ImageBundle.stories.ts
  • packages/website/docs/usage/image-bundles.md
✅ Files skipped from review due to trivial changes (1)
  • packages/website/docs/usage/image-bundles.md

Comment thread .claude/rules/git/commit-conventions.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 49919225-e422-4575-aa9e-3e08bbbb6cf6

📥 Commits

Reviewing files that changed from the base of the PR and between 443a2da and 33bdc3c.

📒 Files selected for processing (3)
  • .claude/rules/git/commit-conventions.md
  • packages/core/__tests__/view/plugin/ImageBundlePlugin.test.ts
  • packages/core/src/view/plugin/ImageBundlePlugin.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/src/view/plugin/ImageBundlePlugin.ts
  • packages/core/tests/view/plugin/ImageBundlePlugin.test.ts

Comment thread .claude/rules/git/commit-conventions.md Outdated
Comment thread .claude/rules/git/commit-conventions.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
.claude/rules/git/commit-conventions.md (1)

35-35: ⚠️ Potential issue | 🟠 Major

Use the same breaking-change footer token in the example (BREAKING CHANGE:).

The rule text (Line 25) and example (Line 35) currently disagree; this can lead to commits using the wrong footer token for automated parsing.

In Conventional Commits v1.0.0, which footer token is valid for breaking changes: "BREAKING CHANGE:" or "BREAKING CHANGES:"?

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 32c64526-797b-40fb-b3c4-046fe3ec35ef

📥 Commits

Reviewing files that changed from the base of the PR and between 33bdc3c and 4b21631.

📒 Files selected for processing (1)
  • .claude/rules/git/commit-conventions.md

@sonarqubecloud

Copy link
Copy Markdown

@redfish4ktc redfish4ktc merged commit c3e4de1 into main Apr 24, 2026
6 checks passed
@redfish4ktc redfish4ktc deleted the refactor/migrate-image-mixin-to-plugin branch April 24, 2026 13:39
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.

2 participants