@zenuml/core 3.47.9 → 3.48.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/zenuml.mjs +13529 -0
- package/dist/cli/zenuml.mjs.map +1 -0
- package/dist/cloud-icons-eHuugVSv.js.map +1 -0
- package/dist/zenuml.esm.mjs +2153 -2156
- package/dist/zenuml.esm.mjs.map +1 -0
- package/dist/zenuml.js +82 -82
- package/dist/zenuml.js.map +1 -0
- package/package.json +18 -5
- package/.agents/skills/babysit-pr/SKILL.md +0 -223
- package/.agents/skills/babysit-pr/agents/openai.yaml +0 -7
- package/.agents/skills/dia-scoring/SKILL.md +0 -139
- package/.agents/skills/dia-scoring/agents/openai.yaml +0 -7
- package/.agents/skills/dia-scoring/references/selectors-and-keys.md +0 -253
- package/.agents/skills/land-pr/SKILL.md +0 -120
- package/.agents/skills/propagate-core-release/SKILL.md +0 -205
- package/.agents/skills/propagate-core-release/agents/openai.yaml +0 -7
- package/.agents/skills/propagate-core-release/references/downstreams.md +0 -42
- package/.agents/skills/ship-branch/SKILL.md +0 -105
- package/.agents/skills/submit-branch/SKILL.md +0 -76
- package/.agents/skills/validate-branch/SKILL.md +0 -72
- package/.claude/commands/README.md +0 -162
- package/.claude/commands/analyze.md +0 -101
- package/.claude/commands/clarify.md +0 -158
- package/.claude/commands/code-review.md +0 -322
- package/.claude/commands/constitution.md +0 -73
- package/.claude/commands/create-docs.md +0 -309
- package/.claude/commands/full-context.md +0 -121
- package/.claude/commands/gemini-consult.md +0 -164
- package/.claude/commands/handoff.md +0 -146
- package/.claude/commands/implement.md +0 -56
- package/.claude/commands/plan.md +0 -43
- package/.claude/commands/refactor.md +0 -188
- package/.claude/commands/specify.md +0 -21
- package/.claude/commands/tasks.md +0 -62
- package/.claude/commands/update-docs.md +0 -314
- package/.claude/hooks/README.md +0 -270
- package/.claude/hooks/config/sensitive-patterns.json +0 -86
- package/.claude/hooks/gemini-context-injector.sh +0 -129
- package/.claude/hooks/mcp-security-scan.sh +0 -147
- package/.claude/hooks/notify.sh +0 -103
- package/.claude/hooks/setup/hook-setup.md +0 -96
- package/.claude/hooks/setup/settings.json.template +0 -63
- package/.claude/hooks/sounds/complete.wav +0 -0
- package/.claude/hooks/sounds/input-needed.wav +0 -0
- package/.claude/hooks/subagent-context-injector.sh +0 -65
- package/.claude/skills/babysit-pr/SKILL.md +0 -223
- package/.claude/skills/babysit-pr/agents/openai.yaml +0 -7
- package/.claude/skills/dia-scoring/SKILL.md +0 -139
- package/.claude/skills/dia-scoring/agents/openai.yaml +0 -7
- package/.claude/skills/dia-scoring/references/selectors-and-keys.md +0 -253
- package/.claude/skills/emoji-eval/SKILL.md +0 -187
- package/.claude/skills/land-pr/SKILL.md +0 -120
- package/.claude/skills/propagate-core-release/SKILL.md +0 -205
- package/.claude/skills/propagate-core-release/agents/openai.yaml +0 -7
- package/.claude/skills/propagate-core-release/references/downstreams.md +0 -42
- package/.claude/skills/ship-branch/SKILL.md +0 -105
- package/.claude/skills/submit-branch/SKILL.md +0 -76
- package/.claude/skills/validate-branch/SKILL.md +0 -72
- package/.claude/skills/zenuml-ux-research/SKILL.md +0 -183
- package/.claude/skills/zenuml-ux-research/references/assertion-catalog.md +0 -261
- package/.claude/skills/zenuml-ux-research/references/best-practices-overview.md +0 -56
- package/.claude/skills/zenuml-ux-research/references/report-template.md +0 -89
- package/.claude/skills/zenuml-ux-research/references/scenarios/edit-message-label.md +0 -37
- package/.claude/skills/zenuml-ux-research/references/scenarios/insert-message.md +0 -36
- package/.claude/skills/zenuml-ux-research/references/scenarios/insert-participant.md +0 -31
- package/.claude/skills/zenuml-ux-research/references/scenarios/rename-participant.md +0 -33
- package/.claude/skills/zenuml-ux-research/references/scenarios/undo-insert.md +0 -35
- package/.devcontainer/devcontainer.json +0 -21
- package/.dockerignore +0 -19
- package/.eslintrc.js +0 -39
- package/.git-blame-ignore-revs +0 -6
- package/.kiro/hooks/README.md +0 -38
- package/.kiro/hooks/session-sound-notification.js +0 -44
- package/.kiro/hooks/session-sound-notification.json +0 -23
- package/.mcp.json.example +0 -17
- package/.nvmrc +0 -1
- package/.prettierignore +0 -4
- package/.prettierrc +0 -1
- package/.specify/memory/constitution.md +0 -33
- package/.specify/scripts/bash/check-prerequisites.sh +0 -166
- package/.specify/scripts/bash/common.sh +0 -113
- package/.specify/scripts/bash/create-new-feature.sh +0 -97
- package/.specify/scripts/bash/setup-plan.sh +0 -60
- package/.specify/scripts/bash/update-agent-context.sh +0 -728
- package/.specify/templates/agent-file-template.md +0 -23
- package/.specify/templates/plan-template.md +0 -219
- package/.specify/templates/spec-template.md +0 -116
- package/.specify/templates/tasks-template.md +0 -127
- package/.storybook/main.ts +0 -25
- package/.storybook/preview.ts +0 -29
- package/.watchmanconfig +0 -3
- package/AGENTS.md +0 -26
- package/CLAUDE.md +0 -124
- package/DEPLOYMENT.md +0 -62
- package/Dockerfile +0 -36
- package/IMPLEMENTATION_PLAN.md +0 -163
- package/Integration/vanilla-js/index.html +0 -42
- package/MCP-ASSISTANT-RULES.md +0 -85
- package/README_CN.md +0 -15
- package/TUTORIAL.md +0 -116
- package/antlr/antlr-4.11.1-complete.jar +0 -0
- package/bun.lock +0 -1544
- package/bunfig.toml +0 -52
- package/docs/UNICODE_SUPPORT.md +0 -179
- package/docs/ai-context/deployment-infrastructure.md +0 -21
- package/docs/ai-context/docs-overview.md +0 -89
- package/docs/ai-context/handoff.md +0 -174
- package/docs/ai-context/project-structure.md +0 -160
- package/docs/ai-context/system-integration.md +0 -21
- package/docs/asciidoc/contributor.adoc +0 -54
- package/docs/asciidoc/create-my-own-theme.adoc +0 -149
- package/docs/asciidoc/images/creation-component.png +0 -0
- package/docs/asciidoc/images/creation-rtl.png +0 -0
- package/docs/asciidoc/images/message-arrow-rtl.png +0 -0
- package/docs/asciidoc/images/occurrence.png +0 -0
- package/docs/asciidoc/images/return-message-conflict.png +0 -0
- package/docs/asciidoc/images/shift-up-half-the-height.png +0 -0
- package/docs/asciidoc/images/three-layer-info-arch.png +0 -0
- package/docs/asciidoc/images/vertical-alignment.svg +0 -1
- package/docs/asciidoc/images/vertically-aligning.png +0 -0
- package/docs/asciidoc/index.adoc +0 -277
- package/docs/asciidoc/theme-debug-web-app.png +0 -0
- package/docs/asciidoc/tutorial.adoc +0 -22
- package/docs/asciidoc/user-css.png +0 -0
- package/docs/async-vs-sync-parser-rules.md +0 -81
- package/docs/divider-parser-allow-spaces.md +0 -38
- package/docs/highlighting-messages.md +0 -52
- package/docs/images/editor-sample.png +0 -0
- package/docs/inherited-vs-provided-from.md +0 -64
- package/docs/parser/Assignment.md +0 -8
- package/docs/parser/PARSER_IMPROVEMENTS_CC.md +0 -425
- package/docs/parser/grammar_review_gemini.md +0 -116
- package/docs/participants-function.md +0 -25
- package/docs/responsive-participant-margin.md +0 -52
- package/docs/starter.md +0 -9
- package/docs/superpowers/plans/2026-03-27-e2e-test-reorg.md +0 -698
- package/docs/superpowers/plans/2026-03-30-emoji-support.md +0 -1220
- package/docs/superpowers/plans/2026-03-30-self-correcting-scoring.md +0 -206
- package/docs/superpowers/plans/2026-04-15-keyboard-editing-on-diagram.md +0 -1992
- package/docs/superpowers/plans/2026-04-15-zenuml-ux-research-skill.md +0 -1452
- package/docs/ux-research/.gitkeep +0 -0
- package/docs/ux-research/2026-04-15-rename-participant.md +0 -156
- package/docs/ux-research/2026-04-18-insert-participant.md +0 -151
- package/docs/width-translate-and-offsets.md +0 -62
- package/docs/xss.md +0 -59
- package/e2e/data/compare-cases.js +0 -1090
- package/e2e/data/diff-algorithm.js +0 -199
- package/e2e/fixtures/create-message.html +0 -26
- package/e2e/fixtures/editable-label.html +0 -35
- package/e2e/fixtures/editable-span.html +0 -122
- package/e2e/fixtures/empty-diagram.html +0 -23
- package/e2e/fixtures/fixture.html +0 -31
- package/e2e/fixtures/insert-participant.html +0 -23
- package/e2e/fixtures/reorder-cross-fragment.html +0 -31
- package/e2e/fixtures/reorder-fragment.html +0 -29
- package/e2e/fixtures/reorder-message.html +0 -27
- package/e2e/fixtures/svg-test.html +0 -21
- package/e2e/fixtures/type-switch.html +0 -29
- package/e2e/tools/canonical-history.html +0 -908
- package/e2e/tools/compare-case.html +0 -371
- package/e2e/tools/compare.html +0 -35
- package/e2e/tools/native-diff-ext/background.js +0 -60
- package/e2e/tools/native-diff-ext/bridge.js +0 -26
- package/e2e/tools/native-diff-ext/content.js +0 -194
- package/e2e/tools/svg-preview.html +0 -56
- package/embed.html +0 -193
- package/eslint.config.mjs +0 -35
- package/firebase-debug.log +0 -108
- package/iframe-container-demo/diagram.html +0 -124
- package/iframe-container-demo/host.html +0 -817
- package/index.html +0 -771
- package/mermaid-zenuml-async-spa-auth.png +0 -0
- package/mermaid-zenuml-async-spa-auth.snapshot.md +0 -96
- package/newsletter/unicode-support-announcement.md +0 -134
- package/playground/creation.html +0 -53
- package/playground/message.html +0 -63
- package/playwright.config.ts +0 -40
- package/renderer.html +0 -366
- package/scripts/analyze-compare-case/collect-data.mjs +0 -1134
- package/scripts/analyze-compare-case/config.mjs +0 -102
- package/scripts/analyze-compare-case/geometry.mjs +0 -101
- package/scripts/analyze-compare-case/native-diff.mjs +0 -224
- package/scripts/analyze-compare-case/output.mjs +0 -74
- package/scripts/analyze-compare-case/panel-diff.mjs +0 -114
- package/scripts/analyze-compare-case/report.mjs +0 -162
- package/scripts/analyze-compare-case/residual-scopes.mjs +0 -347
- package/scripts/analyze-compare-case/scoring.mjs +0 -829
- package/scripts/analyze-compare-case.mjs +0 -149
- package/scripts/bump-version.js +0 -117
- package/scripts/snapshot-dual.js +0 -173
- package/scripts/update-snapshots.js +0 -70
- package/skills/dia-scoring/SKILL.md +0 -129
- package/skills/dia-scoring/agents/openai.yaml +0 -7
- package/skills/dia-scoring/references/selectors-and-keys.md +0 -253
- package/tailwind.config.js +0 -126
- package/test-compression.html +0 -274
- package/test-mermaid-zenuml.html +0 -57
- package/test-setup.ts +0 -124
- package/test-url-params.html +0 -192
- package/tsconfig.app.json +0 -31
- package/tsconfig.node.json +0 -24
- package/tsconfig.test.json +0 -9
- package/vite.config.lib.ts +0 -93
- package/vite.config.ts +0 -84
- package/wrangler.toml +0 -18
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
# Selectors And Keys
|
|
2
|
-
|
|
3
|
-
The analyzer uses these roots:
|
|
4
|
-
|
|
5
|
-
- HTML root: `#html-output .frame`, fallback `#html-output .sequence-diagram`
|
|
6
|
-
- SVG root: `#svg-output > svg`
|
|
7
|
-
|
|
8
|
-
Offset anchor:
|
|
9
|
-
|
|
10
|
-
- All reported offsets use the outermost frame root's top-left corner
|
|
11
|
-
- HTML side: `#html-output .frame`, fallback `#html-output .sequence-diagram`
|
|
12
|
-
- SVG side: `#svg-output > svg`
|
|
13
|
-
- Do not emit final `dx` / `dy` values from participant-local or other nested-container anchors
|
|
14
|
-
|
|
15
|
-
HTML label extraction:
|
|
16
|
-
|
|
17
|
-
- Normal messages: iterate `.interaction`, skip `.return`, `.creation`, and self interactions, then read `.message .editable-span-base`
|
|
18
|
-
- Self messages: `.self-invocation .label .editable-span-base`
|
|
19
|
-
- Returns: `.interaction.return .message .editable-span-base`, fallback `.interaction.return .name`
|
|
20
|
-
- Fragment conditions: `.fragment .segment > .text-skin-fragment:not(.finally)`, using only visible child spans when conditional branches are stacked
|
|
21
|
-
- Fragment sections:
|
|
22
|
-
- `.fragment.fragment-tcf .segment > .header.inline-block.bg-skin-frame.opacity-65`
|
|
23
|
-
- `.fragment.fragment-tcf .segment > .header.finally`
|
|
24
|
-
|
|
25
|
-
SVG label extraction:
|
|
26
|
-
|
|
27
|
-
- Normal messages: `g.message:not(.self-call) > text.message-label`
|
|
28
|
-
- Self messages: `g.message.self-call > text.message-label`
|
|
29
|
-
- Returns: `g.return > text.return-label`
|
|
30
|
-
- Fragment conditions: `g.fragment > text.fragment-condition`
|
|
31
|
-
- Fragment condition / section groups: `g.fragment > g` containing `text.fragment-section-label`
|
|
32
|
-
- texts starting with `[` are treated as `fragment-condition`
|
|
33
|
-
- other texts are treated as `fragment-section`
|
|
34
|
-
|
|
35
|
-
Pairing key:
|
|
36
|
-
|
|
37
|
-
- Semantic grouping is by `kind + text`
|
|
38
|
-
- Duplicate labels are paired by top-to-bottom order within that group
|
|
39
|
-
- Output key is:
|
|
40
|
-
- `kind`
|
|
41
|
-
- `text`
|
|
42
|
-
- `y_order`
|
|
43
|
-
- Fragment labels also include `owner=<fragment header>` in the human-readable summary when available
|
|
44
|
-
|
|
45
|
-
Per-letter scoring:
|
|
46
|
-
|
|
47
|
-
- Grapheme segmentation uses `Intl.Segmenter`, fallback `Array.from`
|
|
48
|
-
- Glyph boxes come from browser layout ranges, not whole-word centroids
|
|
49
|
-
- Numeric `dx` and `dy` are only emitted when direct layout evidence and diff-image evidence agree
|
|
50
|
-
|
|
51
|
-
Arrow extraction:
|
|
52
|
-
|
|
53
|
-
- HTML normal/return messages:
|
|
54
|
-
- line: direct child `svg` line strip inside `.message`
|
|
55
|
-
- head: direct child arrowhead `svg` inside `.message`
|
|
56
|
-
- HTML self messages:
|
|
57
|
-
- loop: painted geometry inside `svg.arrow`
|
|
58
|
-
- parts: outer loop path plus nested arrowhead path
|
|
59
|
-
- SVG normal messages:
|
|
60
|
-
- line: `line.message-line`
|
|
61
|
-
- head: `svg.arrow-head`
|
|
62
|
-
- SVG returns:
|
|
63
|
-
- line: `line.return-line`
|
|
64
|
-
- head: `polyline.return-arrow`
|
|
65
|
-
- SVG self messages:
|
|
66
|
-
- loop: painted geometry inside the outer `svg` under `g.message.self-call`
|
|
67
|
-
- parts: outer loop path plus nested arrowhead path
|
|
68
|
-
|
|
69
|
-
Arrow scoring:
|
|
70
|
-
|
|
71
|
-
- Arrows are keyed by sequence number when numbering is available, for example `arrow:1.2.3`
|
|
72
|
-
- Normal and return arrows are measured as one combined geometry item:
|
|
73
|
-
- line + arrow head together
|
|
74
|
-
- Self arrows are measured as one loop geometry item
|
|
75
|
-
- Self arrows use the union of the painted loop path and arrowhead path, not the outer viewport box
|
|
76
|
-
- Arrow output is endpoint-based, not box-centroid-based
|
|
77
|
-
- For normal and return arrows, report:
|
|
78
|
-
- `left_dx`
|
|
79
|
-
- `right_dx`
|
|
80
|
-
- `width_dx`
|
|
81
|
-
- For self arrows, also report:
|
|
82
|
-
- `top_dy`
|
|
83
|
-
- `bottom_dy`
|
|
84
|
-
- `height_dy`
|
|
85
|
-
- Do not report `dy` for horizontal message arrows
|
|
86
|
-
|
|
87
|
-
HTML sequence number extraction:
|
|
88
|
-
|
|
89
|
-
- Normal messages: `.interaction:not(.return):not(.creation):not(.self-invocation):not(.self) > .message > .absolute.text-xs`
|
|
90
|
-
- Self messages: `.interaction.self-invocation > .message .absolute.text-xs`
|
|
91
|
-
- Returns: `.interaction.return > .message > .absolute.text-xs`
|
|
92
|
-
- Fragments: `.fragment > .header > .absolute.text-xs`
|
|
93
|
-
|
|
94
|
-
SVG sequence number extraction:
|
|
95
|
-
|
|
96
|
-
- Normal messages: `g.message:not(.self-call) > text.seq-number`
|
|
97
|
-
- Self messages: `g.message.self-call > text.seq-number`
|
|
98
|
-
- Returns: `g.return > text.seq-number`
|
|
99
|
-
- Fragments: `g.fragment > text.seq-number`
|
|
100
|
-
|
|
101
|
-
## Participant Icon Extraction
|
|
102
|
-
|
|
103
|
-
## Participant Header Extraction
|
|
104
|
-
|
|
105
|
-
HTML participant header extraction:
|
|
106
|
-
|
|
107
|
-
- Participant root: `.participant[data-participant-id]`
|
|
108
|
-
- Participant box: outer border box from the participant root element
|
|
109
|
-
- Participant stereotype: `label.interface`, when present
|
|
110
|
-
- Participant label: last `.name` descendant, measured by glyph boxes
|
|
111
|
-
|
|
112
|
-
SVG participant header extraction:
|
|
113
|
-
|
|
114
|
-
- Participant root: `g.participant[data-participant]`
|
|
115
|
-
- Skip `g.participant-bottom`
|
|
116
|
-
- Participant box element: `:scope > rect.participant-box`
|
|
117
|
-
- Participant box measurement must use the painted outer bounds of the stroked rect, not the inset rect geometry
|
|
118
|
-
- Participant stereotype:
|
|
119
|
-
- prefer `:scope > text.stereotype-label`
|
|
120
|
-
- fallback: top-most direct `text` child above `text.participant-label`
|
|
121
|
-
- Participant label: `:scope > text.participant-label`
|
|
122
|
-
|
|
123
|
-
Participant stereotype pairing and scoring:
|
|
124
|
-
|
|
125
|
-
- Pair by participant name
|
|
126
|
-
- Validate text equality, for example `«BFF»`
|
|
127
|
-
- Measure stereotype offset by per-letter glyph boxes relative to the outermost frame root, not by participant-local anchors or whole-word box centroids
|
|
128
|
-
- Report:
|
|
129
|
-
- `letter_deltas`
|
|
130
|
-
- concise aggregate only when the per-letter evidence agrees
|
|
131
|
-
- Do not mark the stereotype clean from glyph boxes alone
|
|
132
|
-
- Also check the live `#diff-panel canvas` over the union of the HTML and SVG stereotype glyph boxes
|
|
133
|
-
- If localized red or blue pixels persist in that stereotype region while glyph-box deltas are `0/0`, classify it as `ambiguous` or `paint-level residual`
|
|
134
|
-
|
|
135
|
-
Participant box pairing and scoring:
|
|
136
|
-
|
|
137
|
-
- Pair by participant name
|
|
138
|
-
- Report `html_box` and `svg_box` with `x`, `y`, `w`, `h`
|
|
139
|
-
- Box `x` / `y` values are frame-anchor-relative
|
|
140
|
-
- Report box deltas:
|
|
141
|
-
- `dx`
|
|
142
|
-
- `dy`
|
|
143
|
-
- `dw`
|
|
144
|
-
- `dh`
|
|
145
|
-
|
|
146
|
-
HTML icon extraction:
|
|
147
|
-
|
|
148
|
-
- Participant root: `.participant[data-participant-id]`
|
|
149
|
-
- Top-row participant only: keep the top-most entry for each participant id
|
|
150
|
-
- Icon host: first child inside the centered participant row when it is an async icon host
|
|
151
|
-
- `[aria-description]`
|
|
152
|
-
- or contains `svg`
|
|
153
|
-
- or has `h-6` sizing class from `AsyncIcon`
|
|
154
|
-
- Icon box: union of painted SVG shapes when available, fallback to the host box
|
|
155
|
-
- Participant label: last `.name` descendant, measured by glyph boxes
|
|
156
|
-
|
|
157
|
-
SVG icon extraction:
|
|
158
|
-
|
|
159
|
-
- Participant root: `g.participant[data-participant]`
|
|
160
|
-
- Skip `g.participant-bottom`
|
|
161
|
-
- Icon element: `:scope > g[transform]`
|
|
162
|
-
- Icon box: union of painted shapes within that transformed group
|
|
163
|
-
- Participant label: `:scope > text.participant-label`
|
|
164
|
-
|
|
165
|
-
Icon pairing:
|
|
166
|
-
|
|
167
|
-
- Pair by participant name
|
|
168
|
-
- Only report participant icon rows for participants where at least one side has an icon
|
|
169
|
-
- Participant labels for icon-bearing participants are paired by participant name, not raw label text
|
|
170
|
-
|
|
171
|
-
Icon scoring:
|
|
172
|
-
|
|
173
|
-
- Absolute icon drift:
|
|
174
|
-
- `icon_dx`
|
|
175
|
-
- `icon_dy`
|
|
176
|
-
- Absolute icon drift is measured from the outermost frame anchor
|
|
177
|
-
- Relative icon drift against the participant label anchor:
|
|
178
|
-
- `relative_dx`
|
|
179
|
-
- `relative_dy`
|
|
180
|
-
- If there is no participant label on one side, use the participant box center as the anchor
|
|
181
|
-
- Report presence mismatch if one renderer has an icon and the other does not
|
|
182
|
-
- Diff confirmation is taken from `#diff-panel canvas`, scoped to the union of the HTML and SVG icon boxes
|
|
183
|
-
|
|
184
|
-
## Residual Scope Attribution
|
|
185
|
-
|
|
186
|
-
Residual scope extraction:
|
|
187
|
-
|
|
188
|
-
- Build connected clusters from the live `#diff-panel canvas` colors:
|
|
189
|
-
- red = `html-only`
|
|
190
|
-
- blue = `svg-only`
|
|
191
|
-
- Ignore green `match` and magenta `color diff` pixels for positional scoping
|
|
192
|
-
- Each cluster reports:
|
|
193
|
-
- `size`
|
|
194
|
-
- `bbox`
|
|
195
|
-
- `centroid`
|
|
196
|
-
- These panel-derived clusters are the source of truth for residual hotspots.
|
|
197
|
-
|
|
198
|
-
Residual scope candidates:
|
|
199
|
-
|
|
200
|
-
- HTML side:
|
|
201
|
-
- labels
|
|
202
|
-
- numbers
|
|
203
|
-
- arrows
|
|
204
|
-
- participant stereotypes
|
|
205
|
-
- participant labels
|
|
206
|
-
- participant icons
|
|
207
|
-
- participant boxes
|
|
208
|
-
- diagram root fallback
|
|
209
|
-
- SVG side:
|
|
210
|
-
- labels
|
|
211
|
-
- numbers
|
|
212
|
-
- arrows
|
|
213
|
-
- participant stereotypes
|
|
214
|
-
- participant labels
|
|
215
|
-
- participant icons
|
|
216
|
-
- participant boxes
|
|
217
|
-
- `rect.frame-border-inner`, fallback `rect.frame-border` / `rect.frame-box`
|
|
218
|
-
- diagram root fallback
|
|
219
|
-
|
|
220
|
-
Residual scope attribution:
|
|
221
|
-
|
|
222
|
-
- Pick the closest candidate to the cluster centroid on each side
|
|
223
|
-
- Prefer targets that contain the centroid
|
|
224
|
-
- Prefer more specific categories over large containers:
|
|
225
|
-
- `participant-icon`
|
|
226
|
-
- `participant-stereotype`
|
|
227
|
-
- `label`, `number`, `participant-label`
|
|
228
|
-
- `arrow`
|
|
229
|
-
- `participant-box`
|
|
230
|
-
- `frame-border`
|
|
231
|
-
- `diagram-root`
|
|
232
|
-
- Use cluster/target overlap and centroid distance as tie-breakers
|
|
233
|
-
|
|
234
|
-
Residual scope output:
|
|
235
|
-
|
|
236
|
-
- `residual_scopes`: all attributed clusters
|
|
237
|
-
- `residual_scope_summary`: top 20 concise lines for terminal use
|
|
238
|
-
- `residual_scope_html_only_top`: top 10 `html-only` clusters
|
|
239
|
-
- `residual_scope_svg_only_top`: top 10 `svg-only` clusters
|
|
240
|
-
- When answering from the live panel, also report:
|
|
241
|
-
- the largest red clusters from `#diff-panel canvas`
|
|
242
|
-
- the largest blue clusters from `#diff-panel canvas`
|
|
243
|
-
- approximate diagram-space positions or bounding boxes
|
|
244
|
-
- attributed HTML and SVG targets for those clusters
|
|
245
|
-
- a short grouped summary of where the red and blue pixels are concentrated
|
|
246
|
-
|
|
247
|
-
Live panel validation:
|
|
248
|
-
|
|
249
|
-
- Source of truth for residual hotspots is `#diff-panel canvas`
|
|
250
|
-
- Confirm the hotspot by reading the panel's actual red and blue pixels at that area
|
|
251
|
-
- If the panel shows no red or blue pixels there, do not report that hotspot as a real residual diff
|
|
252
|
-
- If the panel shows non-zero red or blue totals, do not stop at the totals alone; locate the dominant clusters and report them
|
|
253
|
-
- Do not build or rely on a separate screenshot-to-screenshot diff for pixel comparison when `#diff-panel canvas` is available on the page
|
package/tailwind.config.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
important: ".zenuml",
|
|
3
|
-
content: ["./src/**/*.{js,jsx,ts,tsx,vue}", "./index.html"],
|
|
4
|
-
safelist: [
|
|
5
|
-
// add classes from tailwind.css
|
|
6
|
-
"theme-default",
|
|
7
|
-
"theme-mermaid",
|
|
8
|
-
"theme-darcula",
|
|
9
|
-
"theme-sky",
|
|
10
|
-
"theme-idle-afternoon",
|
|
11
|
-
"theme-coles",
|
|
12
|
-
"theme-woolworths",
|
|
13
|
-
"theme-anz",
|
|
14
|
-
"theme-nab",
|
|
15
|
-
"theme-google",
|
|
16
|
-
"theme-diagramly",
|
|
17
|
-
"theme-creately",
|
|
18
|
-
"theme-purple",
|
|
19
|
-
{
|
|
20
|
-
pattern: /(bg|text|outline)-.*/,
|
|
21
|
-
},
|
|
22
|
-
],
|
|
23
|
-
theme: {
|
|
24
|
-
extend: {
|
|
25
|
-
colors: {
|
|
26
|
-
skin: {
|
|
27
|
-
frame: "var(--color-bg-frame)", // it will generate from/via/to-skin-frame. see lifeline layer
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
textColor: {
|
|
31
|
-
skin: {
|
|
32
|
-
title:
|
|
33
|
-
"var(--color-text-title, var(--color-text-message, var(--color-text-base, #000)))",
|
|
34
|
-
participant:
|
|
35
|
-
"var(--color-text-participant, var(--color-text-message, var(--color-text-base, #000)))",
|
|
36
|
-
"lifeline-group-name":
|
|
37
|
-
"var(--color-text-message, var(--color-text-base, #000))",
|
|
38
|
-
message: "var(--color-text-message, var(--color-text-base, #000))",
|
|
39
|
-
"message-arrow":
|
|
40
|
-
"var(--color-message-arrow, var(--color-border-frame, var(--color-border-base, #000)))", // message arrow head
|
|
41
|
-
comment:
|
|
42
|
-
"var(--color-text-comment, var(--color-text-secondary, var(--color-text-base, #000)))",
|
|
43
|
-
"fragment-header":
|
|
44
|
-
"var(--color-text-fragment-header, var(--color-text-message, #000))",
|
|
45
|
-
fragment:
|
|
46
|
-
"var(--color-text-fragment, var(--color-text-message, #000))",
|
|
47
|
-
base: "var(--color-text-base)",
|
|
48
|
-
header: "var(--color-text-header)",
|
|
49
|
-
secondary: "var(--color-text-secondary)",
|
|
50
|
-
control:
|
|
51
|
-
"var(--color-text-control, var(--color-text-secondary, var(--color-text-base, #000)))",
|
|
52
|
-
muted: "var(--color-text-muted)",
|
|
53
|
-
hover: "var(--color-text-hover)",
|
|
54
|
-
link: "var(--color-text-link, var(--color-text-secondary, var(--color-text-base, #000)))",
|
|
55
|
-
fill: "var(--color-text-fill)",
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
backgroundColor: {
|
|
59
|
-
skin: {
|
|
60
|
-
canvas:
|
|
61
|
-
"var(--color-bg-canvas, var(--color-bg-base, var(--color-backup-white, #ffffff)))",
|
|
62
|
-
frame:
|
|
63
|
-
"var(--color-bg-frame, var(--color-bg-canvas, var(--color-bg-base, var(--color-backup-white, #ffffff))))",
|
|
64
|
-
title:
|
|
65
|
-
"var(--color-bg-title, var(--color-bg-frame, var(--color-bg-canvas, var(--color-bg-base, var(--color-backup-white, #ffffff)))))",
|
|
66
|
-
participant:
|
|
67
|
-
"var(--color-bg-participant, var(--color-bg-frame, var(--color-bg-canvas, var(--color-bg-base, var(--color-backup-white, #ffffff)))))",
|
|
68
|
-
lifeline:
|
|
69
|
-
"var(--color-border-participant, var(--color-border-participant, var(--color-border-frame, var(--color-border-base, #000))))",
|
|
70
|
-
divider:
|
|
71
|
-
"var(--color-border-participant, var(--color-border-frame, var(--color-border-base, #000)))",
|
|
72
|
-
"fragment-header":
|
|
73
|
-
"var(--color-bg-fragment-header, var(--color-bg-frame, var(--color-bg-canvas, var(--color-bg-base, var(--color-backup-white, #ffffff)))))",
|
|
74
|
-
occurrence:
|
|
75
|
-
"var(--color-bg-occurrence, var(--color-bg-participant, var(--color-bg-frame, var(--color-bg-canvas, var(--color-bg-base, var(--color-backup-white, #ffffff))))))",
|
|
76
|
-
base: "var(--color-bg-base)",
|
|
77
|
-
secondary: "var(--color-bg-secondary)",
|
|
78
|
-
hover: "var(--color-bg-hover)",
|
|
79
|
-
fill: "var(--color-bg-fill)",
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
borderColor: {
|
|
83
|
-
primary: "var(--color-border-primary)",
|
|
84
|
-
skin: {
|
|
85
|
-
frame: "var(--color-border-frame, var(--color-border-base, #000))",
|
|
86
|
-
participant:
|
|
87
|
-
"var(--color-border-participant, var(--color-border-frame, var(--color-border-base, #000)))",
|
|
88
|
-
"message-arrow":
|
|
89
|
-
"var(--color-message-arrow, var(--color-border-frame, var(--color-border-base, #000)))", // message arrow line
|
|
90
|
-
fragment:
|
|
91
|
-
"var(--color-border-fragment, var(--color-border-frame, var(--color-border-base, #000)))",
|
|
92
|
-
occurrence:
|
|
93
|
-
"var(--color-border-occurrence, var(--color-border-frame, var(--color-border-base, #000)))",
|
|
94
|
-
base: "var(--color-border-base)",
|
|
95
|
-
secondary: "var(--color-border-secondary)",
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
outlineColor: {
|
|
99
|
-
skin: {
|
|
100
|
-
primary: "var(--color-outline-primary)",
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
gradientColorStops: {
|
|
104
|
-
skin: {
|
|
105
|
-
base: "var(--color-bg-base)",
|
|
106
|
-
secondary: "var(--color-bg-secondary)",
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
boxShadow: {
|
|
110
|
-
participant: "var(--color-shadow-participant, transparent)",
|
|
111
|
-
occurrence: "var(--color-shadow-occurrence, transparent)",
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
variants: {
|
|
116
|
-
extend: {
|
|
117
|
-
overflow: ["hover", "focus"],
|
|
118
|
-
whitespace: ["hover", "focus"],
|
|
119
|
-
display: ["group-hover"],
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
corePlugins: {
|
|
123
|
-
preflight: false,
|
|
124
|
-
},
|
|
125
|
-
plugins: [require("@headlessui/tailwindcss")],
|
|
126
|
-
};
|
package/test-compression.html
DELETED
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>ZenUML Compression Test</title>
|
|
7
|
-
<style>
|
|
8
|
-
body {
|
|
9
|
-
font-family: Arial, sans-serif;
|
|
10
|
-
max-width: 1200px;
|
|
11
|
-
margin: 0 auto;
|
|
12
|
-
padding: 20px;
|
|
13
|
-
}
|
|
14
|
-
textarea {
|
|
15
|
-
width: 100%;
|
|
16
|
-
height: 200px;
|
|
17
|
-
margin: 10px 0;
|
|
18
|
-
font-family: monospace;
|
|
19
|
-
}
|
|
20
|
-
button {
|
|
21
|
-
background: #007bff;
|
|
22
|
-
color: white;
|
|
23
|
-
border: none;
|
|
24
|
-
padding: 10px 20px;
|
|
25
|
-
margin: 5px;
|
|
26
|
-
cursor: pointer;
|
|
27
|
-
border-radius: 4px;
|
|
28
|
-
}
|
|
29
|
-
button:hover {
|
|
30
|
-
background: #0056b3;
|
|
31
|
-
}
|
|
32
|
-
.output {
|
|
33
|
-
background: #f4f4f4;
|
|
34
|
-
padding: 10px;
|
|
35
|
-
margin: 10px 0;
|
|
36
|
-
border-radius: 4px;
|
|
37
|
-
word-break: break-all;
|
|
38
|
-
}
|
|
39
|
-
.error {
|
|
40
|
-
color: red;
|
|
41
|
-
background: #fee;
|
|
42
|
-
padding: 10px;
|
|
43
|
-
margin: 10px 0;
|
|
44
|
-
border-radius: 4px;
|
|
45
|
-
}
|
|
46
|
-
.success {
|
|
47
|
-
color: green;
|
|
48
|
-
background: #efe;
|
|
49
|
-
padding: 10px;
|
|
50
|
-
margin: 10px 0;
|
|
51
|
-
border-radius: 4px;
|
|
52
|
-
}
|
|
53
|
-
</style>
|
|
54
|
-
</head>
|
|
55
|
-
<body>
|
|
56
|
-
<h1>ZenUML Compression Test</h1>
|
|
57
|
-
|
|
58
|
-
<h2>Test URL Parameter Encoding/Decoding</h2>
|
|
59
|
-
<textarea id="zenUmlCode" placeholder="Enter ZenUML code here...">title Authentication Flow
|
|
60
|
-
RET ret = A.methodA() {
|
|
61
|
-
B.method() {
|
|
62
|
-
if (X) {
|
|
63
|
-
C.methodC() {
|
|
64
|
-
a = A.methodA() {
|
|
65
|
-
D.method()
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
while (Y) {
|
|
70
|
-
C.methodC() {
|
|
71
|
-
A.methodA()
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
</textarea>
|
|
77
|
-
|
|
78
|
-
<div>
|
|
79
|
-
<button onclick="encodeAndCompress()">Encode (Gzip + Base64)</button>
|
|
80
|
-
<button onclick="testDecode()">Test Decode</button>
|
|
81
|
-
<button onclick="generateUrl()">Generate URL</button>
|
|
82
|
-
<button onclick="clearAll()">Clear</button>
|
|
83
|
-
</div>
|
|
84
|
-
|
|
85
|
-
<h3>Encoded Output:</h3>
|
|
86
|
-
<div id="encodedOutput" class="output"></div>
|
|
87
|
-
|
|
88
|
-
<h3>URL:</h3>
|
|
89
|
-
<div id="urlOutput" class="output"></div>
|
|
90
|
-
|
|
91
|
-
<h3>Test Results:</h3>
|
|
92
|
-
<div id="testResults"></div>
|
|
93
|
-
|
|
94
|
-
<script type="module">
|
|
95
|
-
import pako from 'pako';
|
|
96
|
-
|
|
97
|
-
// Helper function to escape HTML special characters
|
|
98
|
-
function escapeHtml(unsafe) {
|
|
99
|
-
return unsafe
|
|
100
|
-
.replace(/&/g, "&")
|
|
101
|
-
.replace(/</g, "<")
|
|
102
|
-
.replace(/>/g, ">")
|
|
103
|
-
.replace(/"/g, """)
|
|
104
|
-
.replace(/'/g, "'");
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Compression and encoding functions
|
|
108
|
-
function compressAndEncode(text) {
|
|
109
|
-
try {
|
|
110
|
-
// Step 1: Compress with gzip
|
|
111
|
-
const compressed = pako.gzip(text);
|
|
112
|
-
|
|
113
|
-
// Step 2: Convert to base64
|
|
114
|
-
let binary = '';
|
|
115
|
-
const bytes = new Uint8Array(compressed);
|
|
116
|
-
for (let i = 0; i < bytes.byteLength; i++) {
|
|
117
|
-
binary += String.fromCharCode(bytes[i]);
|
|
118
|
-
}
|
|
119
|
-
const base64 = btoa(binary);
|
|
120
|
-
|
|
121
|
-
return base64;
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.error('Compression error:', error);
|
|
124
|
-
throw error;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Decompression and decoding functions
|
|
129
|
-
function decodeAndDecompress(base64String) {
|
|
130
|
-
try {
|
|
131
|
-
// Step 1: Decode base64
|
|
132
|
-
const binaryString = atob(base64String);
|
|
133
|
-
|
|
134
|
-
// Step 2: Convert to Uint8Array
|
|
135
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
136
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
137
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Step 3: Decompress
|
|
141
|
-
const decompressed = pako.ungzip(bytes, { to: 'string' });
|
|
142
|
-
|
|
143
|
-
return decompressed;
|
|
144
|
-
} catch (error) {
|
|
145
|
-
console.error('Decompression error:', error);
|
|
146
|
-
throw error;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function encodeAndCompress() {
|
|
151
|
-
const zenUmlCode = document.getElementById('zenUmlCode').value;
|
|
152
|
-
const resultsDiv = document.getElementById('testResults');
|
|
153
|
-
resultsDiv.innerHTML = '';
|
|
154
|
-
|
|
155
|
-
try {
|
|
156
|
-
const encoded = compressAndEncode(zenUmlCode);
|
|
157
|
-
document.getElementById('encodedOutput').textContent = encoded;
|
|
158
|
-
|
|
159
|
-
// Show compression ratio
|
|
160
|
-
const originalSize = new Blob([zenUmlCode]).size;
|
|
161
|
-
const compressedSize = new Blob([encoded]).size;
|
|
162
|
-
const ratio = ((originalSize - compressedSize) / originalSize * 100).toFixed(2);
|
|
163
|
-
|
|
164
|
-
resultsDiv.innerHTML = `
|
|
165
|
-
<div class="success">
|
|
166
|
-
Encoding successful!<br>
|
|
167
|
-
Original size: ${originalSize} bytes<br>
|
|
168
|
-
Encoded size: ${compressedSize} bytes<br>
|
|
169
|
-
Compression: ${ratio}% smaller
|
|
170
|
-
</div>
|
|
171
|
-
`;
|
|
172
|
-
} catch (error) {
|
|
173
|
-
resultsDiv.innerHTML = `<div class="error">Encoding failed: ${escapeHtml(error.message)}</div>`;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function testDecode() {
|
|
178
|
-
const encoded = document.getElementById('encodedOutput').textContent;
|
|
179
|
-
const resultsDiv = document.getElementById('testResults');
|
|
180
|
-
|
|
181
|
-
if (!encoded) {
|
|
182
|
-
resultsDiv.innerHTML = '<div class="error">No encoded data to decode. Please encode first.</div>';
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
const decoded = decodeAndDecompress(encoded);
|
|
188
|
-
const original = document.getElementById('zenUmlCode').value;
|
|
189
|
-
|
|
190
|
-
if (decoded === original) {
|
|
191
|
-
resultsDiv.innerHTML = `
|
|
192
|
-
<div class="success">
|
|
193
|
-
Decoding successful! The decoded content matches the original.<br>
|
|
194
|
-
<pre>${decoded}</pre>
|
|
195
|
-
</div>
|
|
196
|
-
`;
|
|
197
|
-
} else {
|
|
198
|
-
resultsDiv.innerHTML = `
|
|
199
|
-
<div class="error">
|
|
200
|
-
Decoding mismatch!<br>
|
|
201
|
-
Original length: ${original.length}<br>
|
|
202
|
-
Decoded length: ${decoded.length}
|
|
203
|
-
</div>
|
|
204
|
-
`;
|
|
205
|
-
}
|
|
206
|
-
} catch (error) {
|
|
207
|
-
resultsDiv.innerHTML = `<div class="error">Decoding failed: ${error.message}</div>`;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function generateUrl() {
|
|
212
|
-
const encoded = document.getElementById('encodedOutput').textContent;
|
|
213
|
-
|
|
214
|
-
if (!encoded) {
|
|
215
|
-
document.getElementById('urlOutput').innerHTML = '<span style="color: red;">Please encode first</span>';
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const baseUrl = window.location.origin + '/renderer.html';
|
|
220
|
-
const url = `${baseUrl}?code=${encodeURIComponent(encoded)}`;
|
|
221
|
-
|
|
222
|
-
document.getElementById('urlOutput').innerHTML = `
|
|
223
|
-
<a href="${url}" target="_blank">${url}</a><br>
|
|
224
|
-
<small>URL length: ${url.length} characters</small>
|
|
225
|
-
`;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function clearAll() {
|
|
229
|
-
document.getElementById('zenUmlCode').value = '';
|
|
230
|
-
document.getElementById('encodedOutput').textContent = '';
|
|
231
|
-
document.getElementById('urlOutput').textContent = '';
|
|
232
|
-
document.getElementById('testResults').innerHTML = '';
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Test some edge cases
|
|
236
|
-
function runTests() {
|
|
237
|
-
const testCases = [
|
|
238
|
-
{ name: 'Empty string', input: '' },
|
|
239
|
-
{ name: 'Simple text', input: 'Hello World' },
|
|
240
|
-
{ name: 'Unicode', input: '你好世界 🌍' },
|
|
241
|
-
{ name: 'Special characters', input: '!@#$%^&*()_+-=[]{}|;:,.<>?' }
|
|
242
|
-
];
|
|
243
|
-
|
|
244
|
-
let results = '<h3>Automated Tests:</h3>';
|
|
245
|
-
|
|
246
|
-
for (const test of testCases) {
|
|
247
|
-
try {
|
|
248
|
-
const encoded = compressAndEncode(test.input);
|
|
249
|
-
const decoded = decodeAndDecompress(encoded);
|
|
250
|
-
|
|
251
|
-
if (decoded === test.input) {
|
|
252
|
-
results += `<div class="success">✓ ${test.name}: PASSED</div>`;
|
|
253
|
-
} else {
|
|
254
|
-
results += `<div class="error">✗ ${test.name}: FAILED - Mismatch</div>`;
|
|
255
|
-
}
|
|
256
|
-
} catch (error) {
|
|
257
|
-
results += `<div class="error">✗ ${test.name}: ERROR - ${error.message}</div>`;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
document.getElementById('testResults').innerHTML = results;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Make functions available globally for onclick handlers
|
|
265
|
-
window.encodeAndCompress = encodeAndCompress;
|
|
266
|
-
window.testDecode = testDecode;
|
|
267
|
-
window.generateUrl = generateUrl;
|
|
268
|
-
window.clearAll = clearAll;
|
|
269
|
-
|
|
270
|
-
// Run tests on page load
|
|
271
|
-
runTests();
|
|
272
|
-
</script>
|
|
273
|
-
</body>
|
|
274
|
-
</html>
|