@zenuml/core 3.47.0 → 3.47.2
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/.agents/skills/babysit-pr/SKILL.md +223 -0
- package/.agents/skills/babysit-pr/agents/openai.yaml +7 -0
- package/.agents/skills/dia-scoring/SKILL.md +139 -0
- package/.agents/skills/dia-scoring/agents/openai.yaml +7 -0
- package/.agents/skills/dia-scoring/references/selectors-and-keys.md +253 -0
- package/.agents/skills/land-pr/SKILL.md +120 -0
- package/.agents/skills/propagate-core-release/SKILL.md +205 -0
- package/.agents/skills/propagate-core-release/agents/openai.yaml +7 -0
- package/.agents/skills/propagate-core-release/references/downstreams.md +42 -0
- package/.agents/skills/ship-branch/SKILL.md +105 -0
- package/.agents/skills/submit-branch/SKILL.md +76 -0
- package/.agents/skills/validate-branch/SKILL.md +72 -0
- package/.claude/skills/emoji-eval/SKILL.md +187 -0
- package/.claude/skills/propagate-core-release/SKILL.md +81 -76
- package/.claude/skills/propagate-core-release/agents/openai.yaml +2 -2
- package/AGENTS.md +1 -1
- package/dist/stats.html +1 -1
- package/dist/zenuml.esm.mjs +16210 -15460
- package/dist/zenuml.js +540 -535
- package/docs/superpowers/plans/2026-03-30-emoji-support.md +1220 -0
- package/docs/superpowers/plans/2026-03-30-self-correcting-scoring.md +206 -0
- package/e2e/data/compare-cases.js +233 -0
- package/e2e/tools/compare-case.html +17 -3
- package/package.json +3 -3
- package/playwright.config.ts +1 -1
- package/scripts/analyze-compare-case/collect-data.mjs +159 -16
- package/scripts/analyze-compare-case/config.mjs +1 -1
- package/scripts/analyze-compare-case/report.mjs +5 -0
- package/scripts/analyze-compare-case/residual-scopes.mjs +23 -1
- package/scripts/analyze-compare-case/scoring.mjs +13 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Self-Correcting Dia-Scoring Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Add a gap-detection and self-correction validation loop to the dia-scoring skill so it automatically detects and fixes analyzer blind spots during normal scoring runs.
|
|
6
|
+
|
|
7
|
+
**Architecture:** The entire change is a new section in `SKILL.md` — behavioral instructions that tell the agent to cross-reference the diff panel's pixel clusters against the analyzer's coverage map, triage unaccounted clusters, and fix `collect-data.mjs` when the gap is a selector/extraction miss. No new scripts or tooling.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Markdown (SKILL.md), Playwright browser_evaluate (runtime), collect-data.mjs (runtime fixes)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Task 1: Add "Gap Detection and Self-Correction" section to SKILL.md
|
|
14
|
+
|
|
15
|
+
**Files:**
|
|
16
|
+
- Modify: `/Users/pengxiao/.claude/skills/dia-scoring/SKILL.md` (append new section after the existing "Known Analyzer Internals" section, before "Commands")
|
|
17
|
+
|
|
18
|
+
- [ ] **Step 1: Add the new section**
|
|
19
|
+
|
|
20
|
+
Open `/Users/pengxiao/.claude/skills/dia-scoring/SKILL.md` and insert the following section between the "Known Analyzer Internals" section (line 167) and the "Commands" section (line 175):
|
|
21
|
+
|
|
22
|
+
```markdown
|
|
23
|
+
## Gap Detection and Self-Correction
|
|
24
|
+
|
|
25
|
+
After running the analyzer and producing the JSON report, **automatically validate** that the report covers all visible diff clusters. Do not wait for the user to request calibration.
|
|
26
|
+
|
|
27
|
+
### Step 1: Build a Coverage Map
|
|
28
|
+
|
|
29
|
+
Collect every fine-grained bounding box from the analyzer JSON:
|
|
30
|
+
- `html_box` / `svg_box` from labels, numbers, arrows
|
|
31
|
+
- `html_icon_box` / `svg_icon_box` from participant icons
|
|
32
|
+
- `label_box` from participant labels
|
|
33
|
+
- `stereotype_box`, `comment_box`, `divider_box`, occurrence boxes, etc.
|
|
34
|
+
|
|
35
|
+
Use the most specific boxes available (e.g., `icon_box` rather than the coarse `participant_box`) to avoid masking sub-element gaps.
|
|
36
|
+
|
|
37
|
+
### Step 2: Find Unaccounted Diff Clusters
|
|
38
|
+
|
|
39
|
+
Scan the `#diff-panel canvas` for connected clusters of red (HTML-only) or blue (SVG-only) pixels. Filter noise (clusters < 20 pixels). A cluster is **covered** when:
|
|
40
|
+
|
|
41
|
+
- The cluster's centroid falls inside a reported element's bounding box, OR
|
|
42
|
+
- The overlap between the cluster and a reported element's box is >= 30% of the cluster's area
|
|
43
|
+
|
|
44
|
+
Clusters meeting neither condition are **unaccounted** and trigger investigation.
|
|
45
|
+
|
|
46
|
+
`colorDiff` (purple) pixels within a covered region are expected and do not trigger investigation.
|
|
47
|
+
|
|
48
|
+
### Step 3: Verify Coordinate Mapping
|
|
49
|
+
|
|
50
|
+
Before inspecting the DOM at gap coordinates:
|
|
51
|
+
|
|
52
|
+
1. Derive an initial canvas-to-page mapping from frame/canvas geometry (canvas natural size / frame CSS size).
|
|
53
|
+
2. Probe a known anchor — pick a reported element with known page coordinates and verify the mapping lands on it via `document.elementFromPoint`.
|
|
54
|
+
3. If the probe hits the wrong panel, empty space, or an unrelated element, recalibrate once using the probe result.
|
|
55
|
+
4. If the mapping still fails after one recalibration, mark the cluster as `uncertain` and move on.
|
|
56
|
+
|
|
57
|
+
### Step 4: Inspect DOM at Gap Coordinates
|
|
58
|
+
|
|
59
|
+
For each unaccounted cluster with a verified mapping:
|
|
60
|
+
|
|
61
|
+
1. Use `document.elementFromPoint(x, y)` on both the HTML and SVG panels.
|
|
62
|
+
2. Walk up to the semantic parent (participant, message, fragment) to understand the element's role.
|
|
63
|
+
3. Classify: emoji icon, stereotype, arrow, label, or novel element.
|
|
64
|
+
|
|
65
|
+
### Step 5: Triage
|
|
66
|
+
|
|
67
|
+
Classify each gap before acting:
|
|
68
|
+
|
|
69
|
+
- **`likely_analyzer_gap`** — Element exists on both sides, belongs to an existing scoring category (icons, labels, stereotypes, etc.), but the collection logic missed it. Proceed to fix.
|
|
70
|
+
- **`likely_renderer_residual`** — Element exists on only one side, or the difference is a genuine rendering discrepancy. Report in scoring output but do not modify the analyzer.
|
|
71
|
+
- **`uncertain`** — Cannot determine cause confidently. Report with DOM context and coordinates for manual review.
|
|
72
|
+
|
|
73
|
+
Only `likely_analyzer_gap` triggers a self-fix.
|
|
74
|
+
|
|
75
|
+
### Step 6: Fix the Collection Logic
|
|
76
|
+
|
|
77
|
+
For `likely_analyzer_gap` clusters:
|
|
78
|
+
|
|
79
|
+
1. Read the relevant collection function in `collect-data.mjs` (e.g., `collectHtmlParticipants` for participant sub-elements).
|
|
80
|
+
2. Compare the function's selectors and extraction logic against the actual DOM element's tag, classes, and attributes.
|
|
81
|
+
3. Identify why it wasn't matched.
|
|
82
|
+
4. Fix the collection logic. This may include: adding selector patterns, adding fallback extraction paths, adjusting pairing logic, or modifying measurement paths. Keep changes targeted — no broad refactors.
|
|
83
|
+
|
|
84
|
+
This fixes the measurement tool, not the renderers.
|
|
85
|
+
|
|
86
|
+
### Step 7: Re-run and Verify
|
|
87
|
+
|
|
88
|
+
1. Re-run the analyzer on the target case. Confirm the previously-unaccounted cluster is now covered and semantically correct.
|
|
89
|
+
2. Run 1-2 sibling cases with the same element family and confirm: populated data, no regression in previously-working sections.
|
|
90
|
+
|
|
91
|
+
### Safety Limits
|
|
92
|
+
|
|
93
|
+
- Maximum **2 fix-and-rerun iterations** per scoring session.
|
|
94
|
+
- Only auto-fix `likely_analyzer_gap` that maps to an existing scoring category and collection function.
|
|
95
|
+
- Novel element types (no existing category): report as unresolved with element identity and coordinates.
|
|
96
|
+
|
|
97
|
+
### Limitations
|
|
98
|
+
|
|
99
|
+
- **Invisible diffs**: If an element renders identically in both HTML and SVG (no diff pixels), this loop cannot detect that the analyzer doesn't cover it. The loop is reactive to visible differences only.
|
|
100
|
+
- **Novel categories**: The loop can detect and report novel element types but does not create new scoring categories autonomously.
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- [ ] **Step 2: Update the participant icons scope line**
|
|
104
|
+
|
|
105
|
+
In the same file, find line 74:
|
|
106
|
+
|
|
107
|
+
```markdown
|
|
108
|
+
- participant icons (actor, database, ec2, lambda, azurefunction, sqs, sns, iam, boundary, control, entity)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Replace with:
|
|
112
|
+
|
|
113
|
+
```markdown
|
|
114
|
+
- participant icons (actor, database, ec2, lambda, azurefunction, sqs, sns, iam, boundary, control, entity, and emoji-based icons like 🌐, 🔒, 🗄️)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This documents that emoji icons are in scope, which the self-correction loop discovered.
|
|
118
|
+
|
|
119
|
+
- [ ] **Step 3: Verify the edit is well-formed**
|
|
120
|
+
|
|
121
|
+
Read the modified SKILL.md and confirm:
|
|
122
|
+
- The new section appears between "Known Analyzer Internals" and "Commands"
|
|
123
|
+
- No existing sections were accidentally modified
|
|
124
|
+
- The markdown renders correctly (no broken formatting)
|
|
125
|
+
|
|
126
|
+
Run: `cat /Users/pengxiao/.claude/skills/dia-scoring/SKILL.md | head -250`
|
|
127
|
+
Expected: The new "Gap Detection and Self-Correction" section is visible, followed by the existing "Commands" section.
|
|
128
|
+
|
|
129
|
+
- [ ] **Step 4: Commit**
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
cd /Users/pengxiao/workspaces/zenuml/mmd-zenuml-core
|
|
133
|
+
git add /Users/pengxiao/.claude/skills/dia-scoring/SKILL.md
|
|
134
|
+
git commit -m "feat(dia-scoring): add gap detection and self-correction validation loop"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Task 2: Validate the self-correction loop on the emoji-async-return case
|
|
140
|
+
|
|
141
|
+
This task verifies the new skill instructions work end-to-end by running a scoring session on the case that originally exposed the gap.
|
|
142
|
+
|
|
143
|
+
**Files:**
|
|
144
|
+
- No files created or modified — this is a validation task
|
|
145
|
+
|
|
146
|
+
- [ ] **Step 1: Run the analyzer on emoji-async-return**
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
cd /Users/pengxiao/workspaces/zenuml/mmd-zenuml-core
|
|
150
|
+
node scripts/analyze-compare-case.mjs --case emoji-async-return --json 2>&1 | python3 -c "
|
|
151
|
+
import json, sys
|
|
152
|
+
data = json.load(sys.stdin)
|
|
153
|
+
icons = data.get('participant_icons', [])
|
|
154
|
+
print(f'participant_icons count: {len(icons)}')
|
|
155
|
+
for icon in icons:
|
|
156
|
+
print(f' {icon.get(\"name\", \"?\")} — presence html:{icon.get(\"presence\",{}).get(\"html\")} svg:{icon.get(\"presence\",{}).get(\"svg\")} status:{icon.get(\"status\")}')
|
|
157
|
+
"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Expected: `participant_icons count: 0` (the analyzer doesn't detect emoji icons yet — this confirms the gap exists before the self-correction loop runs).
|
|
161
|
+
|
|
162
|
+
- [ ] **Step 2: Navigate to the compare-case page and read the diff panel**
|
|
163
|
+
|
|
164
|
+
Using Playwright:
|
|
165
|
+
1. Navigate to `http://localhost:8080/e2e/tools/compare-case.html?case=emoji-async-return`
|
|
166
|
+
2. Wait for `[native-diff-ext] Done!` in console
|
|
167
|
+
3. Read the `#diff-panel canvas` pixel data via `browser_evaluate`
|
|
168
|
+
4. Identify unaccounted clusters in the participant icon region
|
|
169
|
+
|
|
170
|
+
Expected: The diff panel shows HTML-only and SVG-only pixel clusters around the emoji icons (🌐, 🔒, 🗄️) that are not covered by any reported element in the analyzer output.
|
|
171
|
+
|
|
172
|
+
- [ ] **Step 3: Follow the self-correction loop**
|
|
173
|
+
|
|
174
|
+
Execute steps 1-7 of the new "Gap Detection and Self-Correction" section:
|
|
175
|
+
1. Build coverage map from analyzer JSON
|
|
176
|
+
2. Find unaccounted clusters (the icon regions)
|
|
177
|
+
3. Verify coordinate mapping with a known anchor probe
|
|
178
|
+
4. Inspect DOM at gap coordinates — find `span.mr-1.flex-shrink-0` (HTML) and emoji `tspan` (SVG)
|
|
179
|
+
5. Triage as `likely_analyzer_gap` (element exists on both sides, belongs to participant icons category)
|
|
180
|
+
6. Fix `collect-data.mjs` — add emoji icon detection to both `collectHtmlParticipants` and `collectSvgParticipants`
|
|
181
|
+
7. Re-run analyzer, verify icons are now detected. Run 1-2 sibling emoji cases.
|
|
182
|
+
|
|
183
|
+
Expected: After the fix, `participant_icons count: 3` with all three emoji icons detected and scored.
|
|
184
|
+
|
|
185
|
+
- [ ] **Step 4: Commit the collect-data.mjs fix**
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
cd /Users/pengxiao/workspaces/zenuml/mmd-zenuml-core
|
|
189
|
+
git add scripts/analyze-compare-case/collect-data.mjs
|
|
190
|
+
git commit -m "fix(analyzer): detect emoji-based participant icons in collect-data"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### Task 3: Commit the design spec
|
|
196
|
+
|
|
197
|
+
**Files:**
|
|
198
|
+
- Stage: `docs/superpowers/specs/2026-03-30-self-correcting-scoring-design.md`
|
|
199
|
+
|
|
200
|
+
- [ ] **Step 1: Commit the spec**
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
cd /Users/pengxiao/workspaces/zenuml/mmd-zenuml-core
|
|
204
|
+
git add docs/superpowers/specs/2026-03-30-self-correcting-scoring-design.md
|
|
205
|
+
git commit -m "docs: add self-correcting dia-scoring design spec"
|
|
206
|
+
```
|
|
@@ -843,6 +843,39 @@ OrderService.handle() {
|
|
|
843
843
|
B -> C: forward
|
|
844
844
|
==Done==`,
|
|
845
845
|
|
|
846
|
+
// --- Emoji ---
|
|
847
|
+
"emoji-participant": `[rocket] Production
|
|
848
|
+
Production.deploy()`,
|
|
849
|
+
"emoji-multi-participants": `[rocket] Production
|
|
850
|
+
[lock] Auth
|
|
851
|
+
[fire] Cache
|
|
852
|
+
Production->Auth: validate
|
|
853
|
+
Auth->Cache: lookup`,
|
|
854
|
+
"emoji-with-type": `@Database [fire] HotDB
|
|
855
|
+
@Actor [eyes] Reviewer
|
|
856
|
+
Reviewer->HotDB: query`,
|
|
857
|
+
"emoji-with-stereotype": `<<service>> [lock] Auth
|
|
858
|
+
<<gateway>> [rocket] API
|
|
859
|
+
API->Auth: authenticate`,
|
|
860
|
+
"emoji-no-emoji-baseline": `Production
|
|
861
|
+
Auth
|
|
862
|
+
Cache
|
|
863
|
+
Production->Auth: validate
|
|
864
|
+
Auth->Cache: lookup`,
|
|
865
|
+
"emoji-async-message": `A
|
|
866
|
+
B
|
|
867
|
+
A->B: [rocket] launching`,
|
|
868
|
+
"emoji-alt-condition": `A
|
|
869
|
+
B
|
|
870
|
+
A->B: [check] start
|
|
871
|
+
if(success) {
|
|
872
|
+
A->B: [rocket] proceed
|
|
873
|
+
}`,
|
|
874
|
+
"emoji-comment": `A
|
|
875
|
+
B
|
|
876
|
+
// [eyes] review this
|
|
877
|
+
A->B: process`,
|
|
878
|
+
|
|
846
879
|
// --- Icons ---
|
|
847
880
|
"icons": `@Actor User
|
|
848
881
|
@Database DB
|
|
@@ -854,4 +887,204 @@ User.login() {
|
|
|
854
887
|
MQ.enqueue()
|
|
855
888
|
Topic.publish()
|
|
856
889
|
}`,
|
|
890
|
+
|
|
891
|
+
// --- Emoji parity cases ---
|
|
892
|
+
"emoji-sync-call": `[rocket]A.method() {
|
|
893
|
+
[database]B.query()
|
|
894
|
+
}`,
|
|
895
|
+
"emoji-nested-calls": `[globe]API.handle() {
|
|
896
|
+
[lock]Auth.validate() {
|
|
897
|
+
[database]DB.lookup()
|
|
898
|
+
}
|
|
899
|
+
}`,
|
|
900
|
+
"emoji-async-return": `[globe]API->[lock]Auth: validate
|
|
901
|
+
Auth->[database]DB: lookup
|
|
902
|
+
DB-->Auth: [check] found
|
|
903
|
+
Auth-->API: [check] authorized`,
|
|
904
|
+
"emoji-with-fragment": `[rocket]Client->[lock]Server.request()
|
|
905
|
+
if(authorized) {
|
|
906
|
+
Server->[database]DB.query()
|
|
907
|
+
DB-->Server: [check] result
|
|
908
|
+
} else {
|
|
909
|
+
Server-->Client: [x] denied
|
|
910
|
+
}`,
|
|
911
|
+
"emoji-divider-case": `[rocket]A->[lock]B.start()
|
|
912
|
+
== [fire] Deploy Phase ==
|
|
913
|
+
B->[database]C.migrate()`,
|
|
914
|
+
"emoji-group-case": `group Backend {[database]DB [cache]Redis}
|
|
915
|
+
[globe]Gateway->DB.query()
|
|
916
|
+
Gateway->Redis.get()`,
|
|
917
|
+
"emoji-group-case-2groups": `group Backend {[database]DB [cache]Redis}
|
|
918
|
+
group Frontend {[globe]Gateway}
|
|
919
|
+
Gateway->DB.query()
|
|
920
|
+
Gateway->Redis.get()`,
|
|
921
|
+
"group-minimal": `group x {a}`,
|
|
922
|
+
"group-single-participant": `group Frontend {[globe]Gateway}
|
|
923
|
+
group Backend {[database]DB}
|
|
924
|
+
Gateway->DB.query()`,
|
|
925
|
+
"emoji-comment-styled": `// [eyes] monitoring
|
|
926
|
+
[rocket]A->[lock]B.deploy()
|
|
927
|
+
// [rocket, red] critical path
|
|
928
|
+
B->[database]C.write()`,
|
|
929
|
+
"emoji-colon-override": `[:red:] Alert
|
|
930
|
+
[rocket] Normal
|
|
931
|
+
Alert->Normal.notify()`,
|
|
932
|
+
"emoji-icon-combo": `@Actor [star] Admin
|
|
933
|
+
@Database [fire] HotDB
|
|
934
|
+
Admin->HotDB.query()`,
|
|
935
|
+
"emoji-long-names": `[rocket]ProductionServer->[lock]AuthService.validate()
|
|
936
|
+
AuthService->[database]UserDB.find()
|
|
937
|
+
UserDB-->AuthService: [check] found`,
|
|
938
|
+
"emoji-simple-async": `[rocket]A->[lock]B: hello
|
|
939
|
+
B-->A: [check] done`,
|
|
940
|
+
"emoji-self-call": `[gear]Processor.init() {
|
|
941
|
+
Processor.validate()
|
|
942
|
+
}`,
|
|
943
|
+
"emoji-title": `title [rocket] Deploy Pipeline
|
|
944
|
+
[lock]A->[database]B.save()`,
|
|
945
|
+
// emoji variants of existing patterns
|
|
946
|
+
"emoji-nested-sync-deep": `[rocket]A.methodA() {
|
|
947
|
+
[lock]B.methodB() {
|
|
948
|
+
[database]C.methodC() {
|
|
949
|
+
[fire]D.process()
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}`,
|
|
953
|
+
"emoji-async-many": `[rocket]A [lock]B [database]C
|
|
954
|
+
A->B: [check] msg1
|
|
955
|
+
B->C: [fire] msg2
|
|
956
|
+
C->B: [check] result
|
|
957
|
+
B->A: [check] done`,
|
|
958
|
+
"emoji-if-else": `[rocket]Client->[lock]Server.request()
|
|
959
|
+
if(valid) {
|
|
960
|
+
Server->[database]DB.query()
|
|
961
|
+
} else {
|
|
962
|
+
Server-->Client: [x] denied
|
|
963
|
+
}`,
|
|
964
|
+
"emoji-tcf": `[globe]A.process() {
|
|
965
|
+
try {
|
|
966
|
+
[database]B.save()
|
|
967
|
+
} catch(e) {
|
|
968
|
+
[warning]C.handle()
|
|
969
|
+
} finally {
|
|
970
|
+
[gear]D.cleanup()
|
|
971
|
+
}
|
|
972
|
+
}`,
|
|
973
|
+
"emoji-loop": `[rocket]A->[lock]B.fetch()
|
|
974
|
+
loop(retries < 3) {
|
|
975
|
+
B->[database]C.query()
|
|
976
|
+
C-->B: [check] ok
|
|
977
|
+
}`,
|
|
978
|
+
"emoji-par": `[rocket]Orchestrator.run() {
|
|
979
|
+
par {
|
|
980
|
+
[database]DB.write()
|
|
981
|
+
[cache]Redis.flush()
|
|
982
|
+
}
|
|
983
|
+
}`,
|
|
984
|
+
"emoji-return-chain": `[globe]API->[lock]Auth.check() {
|
|
985
|
+
Auth->[database]DB.query() {
|
|
986
|
+
DB-->Auth: [check] found
|
|
987
|
+
}
|
|
988
|
+
Auth-->API: [check] valid
|
|
989
|
+
}`,
|
|
990
|
+
"emoji-creation-simple": `[rocket]A.init() {
|
|
991
|
+
new B()
|
|
992
|
+
}`,
|
|
993
|
+
"emoji-color": `[rocket] Prod #FF6600
|
|
994
|
+
[lock] Auth #0747A6
|
|
995
|
+
Prod->Auth.validate()`,
|
|
996
|
+
"emoji-stereotype-only": `<<service>> [lock] Auth
|
|
997
|
+
<<gateway>> [globe] API
|
|
998
|
+
API->Auth.check()`,
|
|
999
|
+
"emoji-method-name": `A.[rocket]deploy()
|
|
1000
|
+
A.[lock]validate()
|
|
1001
|
+
A->[database]B.[fire]save()`,
|
|
1002
|
+
"emoji-condition-label": `[rocket]Client->[lock]Server.request()
|
|
1003
|
+
if(authorized) {
|
|
1004
|
+
Server->[database]DB.query()
|
|
1005
|
+
DB-->Server: [check] result
|
|
1006
|
+
} else {
|
|
1007
|
+
Server-->Client: [x] denied
|
|
1008
|
+
}`,
|
|
1009
|
+
"emoji-in-conditions": `if([check] authorized) {
|
|
1010
|
+
A.proceed()
|
|
1011
|
+
} else if([warning] rate limited) {
|
|
1012
|
+
A.wait()
|
|
1013
|
+
} else {
|
|
1014
|
+
A.deny()
|
|
1015
|
+
}`,
|
|
1016
|
+
"emoji-tcf-labels": `A.process() {
|
|
1017
|
+
try {
|
|
1018
|
+
B.save()
|
|
1019
|
+
} catch(DatabaseError) {
|
|
1020
|
+
C.rollback()
|
|
1021
|
+
} finally {
|
|
1022
|
+
D.cleanup()
|
|
1023
|
+
}
|
|
1024
|
+
}`,
|
|
1025
|
+
"emoji-loop-condition": `while([rocket] deploying) {
|
|
1026
|
+
A->[database]B.check()
|
|
1027
|
+
B-->A: [check] status
|
|
1028
|
+
}`,
|
|
1029
|
+
"emoji-opt-critical": `[rocket]A->[lock]B.request()
|
|
1030
|
+
opt {
|
|
1031
|
+
B.[gear]process()
|
|
1032
|
+
}
|
|
1033
|
+
critical([warning] important) {
|
|
1034
|
+
B->[database]C.save()
|
|
1035
|
+
}`,
|
|
1036
|
+
"emoji-nested-mixed": `[globe]Client->[lock]Server.handle() {
|
|
1037
|
+
if([check] cached) {
|
|
1038
|
+
Server->[cache]Redis.[rocket]get()
|
|
1039
|
+
} else {
|
|
1040
|
+
Server->[database]DB.[fire]query() {
|
|
1041
|
+
try {
|
|
1042
|
+
DB.[gear]process()
|
|
1043
|
+
} catch(timeout) {
|
|
1044
|
+
DB-->Server: [warning] retry
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}`,
|
|
1049
|
+
"emoji-all-features": `title [rocket] System Overview
|
|
1050
|
+
@Actor [star] Admin
|
|
1051
|
+
@Database [fire] DB
|
|
1052
|
+
<<service>> [lock] Auth
|
|
1053
|
+
[globe] API
|
|
1054
|
+
|
|
1055
|
+
// [eyes] authentication flow
|
|
1056
|
+
Admin->API.[key]login(credentials)
|
|
1057
|
+
API->Auth.[lock]validate(token) {
|
|
1058
|
+
if([check] valid) {
|
|
1059
|
+
Auth->DB.[fire]query(userId)
|
|
1060
|
+
DB-->Auth: [check] found
|
|
1061
|
+
} else {
|
|
1062
|
+
Auth-->API: [x] denied
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
== [rocket] deploy phase ==
|
|
1066
|
+
API->[gear]Worker: [rocket] process`,
|
|
1067
|
+
"emoji-chained-calls": `[rocket]A.[lock]auth().[fire]process().[check]save()`,
|
|
1068
|
+
"emoji-assign-return": `[globe]API->[lock]Auth.check() {
|
|
1069
|
+
result = [database]DB.query()
|
|
1070
|
+
return [check] authorized
|
|
1071
|
+
}`,
|
|
1072
|
+
"emoji-multi-async": `[rocket]A->[lock]B: [fire] step 1
|
|
1073
|
+
B->[database]C: [gear] step 2
|
|
1074
|
+
C->[globe]D: [check] step 3
|
|
1075
|
+
D-->A: [check] all done`,
|
|
1076
|
+
"emoji-named-params": `[rocket]A.[lock]method(userId=123, name="John")
|
|
1077
|
+
[database]B.[fire]create(type="User", active=true)`,
|
|
1078
|
+
"emoji-self-sync": `[gear]selfSync() {
|
|
1079
|
+
[rocket]A.[lock]method() {
|
|
1080
|
+
[database]B.save()
|
|
1081
|
+
}
|
|
1082
|
+
}`,
|
|
1083
|
+
"emoji-fragments-return": `[rocket]A.[lock]method() {
|
|
1084
|
+
if([check] x) {
|
|
1085
|
+
return [check] success
|
|
1086
|
+
} else {
|
|
1087
|
+
return [x] failure
|
|
1088
|
+
}
|
|
1089
|
+
}`,
|
|
857
1090
|
};
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
.nav button { padding: 4px 12px; background: #7c3aed; border: none; border-radius: 4px; color: white; font-size: 12px; cursor: pointer; }
|
|
18
18
|
.nav button:hover { background: #6d28d9; }
|
|
19
19
|
.nav button:disabled { background: #64748b; cursor: wait; }
|
|
20
|
+
.nav-btn { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; background: #334155; border: none; border-radius: 4px; color: white; font-size: 16px; cursor: pointer; text-decoration: none; line-height: 1; }
|
|
21
|
+
.nav-btn:hover { background: #475569; }
|
|
22
|
+
.nav-btn[style*="hidden"] { visibility: hidden; }
|
|
20
23
|
.nav .match-badge { font-size: 11px; color: #94a3b8; }
|
|
21
24
|
.container { display: flex; gap: 0; }
|
|
22
25
|
.container.stacked { flex-direction: column; }
|
|
@@ -27,7 +30,7 @@
|
|
|
27
30
|
.diff-panel.visible { display: block; }
|
|
28
31
|
.diff-panel .panel-content canvas { max-width: 100%; }
|
|
29
32
|
#html-output .footer { display: none !important; }
|
|
30
|
-
#html-output .privacy { visibility: hidden !important; }
|
|
33
|
+
#html-output .privacy { visibility: hidden !important; width: 0 !important; overflow: hidden !important; }
|
|
31
34
|
</style>
|
|
32
35
|
</head>
|
|
33
36
|
<body>
|
|
@@ -35,8 +38,8 @@
|
|
|
35
38
|
<a href="/e2e/tools/compare.html">← All cases</a>
|
|
36
39
|
<h2 id="case-name"></h2>
|
|
37
40
|
<div class="nav">
|
|
38
|
-
<a id="prev-link" href="#"
|
|
39
|
-
<a id="next-link" href="#"
|
|
41
|
+
<a id="prev-link" class="nav-btn" href="#" title="Previous case">‹</a>
|
|
42
|
+
<a id="next-link" class="nav-btn" href="#" title="Next case">›</a>
|
|
40
43
|
<span class="match-badge" id="match-badge"></span>
|
|
41
44
|
</div>
|
|
42
45
|
</div>
|
|
@@ -87,6 +90,15 @@
|
|
|
87
90
|
nextLink.style.visibility = "hidden";
|
|
88
91
|
}
|
|
89
92
|
|
|
93
|
+
// Keyboard navigation
|
|
94
|
+
document.addEventListener("keydown", (e) => {
|
|
95
|
+
if (e.key === "ArrowLeft" && prevLink.style.visibility !== "hidden") {
|
|
96
|
+
window.location.href = prevLink.href;
|
|
97
|
+
} else if (e.key === "ArrowRight" && nextLink.style.visibility !== "hidden") {
|
|
98
|
+
window.location.href = nextLink.href;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
90
102
|
// Expose DSL for the extension's batch mode to read
|
|
91
103
|
window.__currentDSL = code || "";
|
|
92
104
|
|
|
@@ -296,7 +308,9 @@
|
|
|
296
308
|
if (htmlFrame) {
|
|
297
309
|
const frameRect2 = htmlFrame.getBoundingClientRect();
|
|
298
310
|
// Hide SVG icons in the header area (top 35px) — checkbox, etc.
|
|
311
|
+
// Skip group outline overlays (data-group-overlay) which are functional rendering elements.
|
|
299
312
|
htmlFrame.querySelectorAll("svg").forEach(svg => {
|
|
313
|
+
if (svg.hasAttribute("data-group-overlay")) return;
|
|
300
314
|
const r = svg.getBoundingClientRect();
|
|
301
315
|
if (r.width > 0 && (r.top - frameRect2.top) < 35) _hideEl(svg);
|
|
302
316
|
});
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenuml/core",
|
|
3
|
-
"version": "3.47.
|
|
3
|
+
"version": "3.47.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"url": "https://github.com/mermaid-js/zenuml-core"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"dev": "vite dev --port
|
|
11
|
-
"preview": "bun run --bun vite preview --port
|
|
10
|
+
"dev": "vite dev --port 4000 --host 0.0.0.0",
|
|
11
|
+
"preview": "bun run --bun vite preview --port 4000 --host",
|
|
12
12
|
"build:site": "bun run --bun vite build",
|
|
13
13
|
"build:gh-pages": "bun run --bun vite build --mode gh-pages",
|
|
14
14
|
"build": "bun run --bun vite build -c vite.config.lib.ts",
|
package/playwright.config.ts
CHANGED