@diagrammo/dgmo 0.32.1 → 0.33.0
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/.cursorrules +7 -2
- package/.github/copilot-instructions.md +7 -2
- package/.windsurfrules +7 -2
- package/SKILL.md +7 -2
- package/dist/advanced.cjs +981 -170
- package/dist/advanced.d.cts +35 -1
- package/dist/advanced.d.ts +35 -1
- package/dist/advanced.js +980 -170
- package/dist/auto.cjs +915 -171
- package/dist/auto.js +93 -93
- package/dist/auto.mjs +915 -171
- package/dist/cli.cjs +136 -134
- package/dist/index.cjs +981 -170
- package/dist/index.d.cts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.js +980 -170
- package/docs/ai-integration.md +7 -2
- package/docs/language-reference.md +39 -8
- package/package.json +2 -2
- package/src/advanced.ts +6 -1
- package/src/boxes-and-lines/layout-grouped.ts +909 -0
- package/src/boxes-and-lines/layout-search.ts +18 -1
- package/src/boxes-and-lines/parser.ts +3 -2
- package/src/c4/layout.ts +2 -1
- package/src/c4/parser.ts +3 -2
- package/src/c4/renderer.ts +3 -2
- package/src/cli.ts +68 -0
- package/src/er/parser.ts +2 -1
- package/src/er/renderer.ts +2 -1
- package/src/gantt/parser.ts +3 -5
- package/src/gantt/renderer.ts +7 -6
- package/src/index.ts +6 -1
- package/src/infra/parser.ts +2 -1
- package/src/infra/renderer.ts +4 -3
- package/src/journey-map/parser.ts +27 -8
- package/src/journey-map/renderer.ts +26 -9
- package/src/kanban/parser.ts +4 -3
- package/src/kanban/renderer.ts +6 -5
- package/src/map/completion.ts +116 -0
- package/src/map/layout.ts +4 -3
- package/src/map/parser.ts +3 -2
- package/src/mindmap/parser.ts +4 -3
- package/src/mindmap/renderer.ts +2 -1
- package/src/org/layout.ts +3 -2
- package/src/org/parser.ts +3 -2
- package/src/org/renderer.ts +5 -4
- package/src/pert/parser.ts +3 -2
- package/src/sequence/renderer.ts +10 -12
- package/src/sequence/tag-resolution.ts +2 -1
- package/src/sitemap/layout.ts +3 -2
- package/src/sitemap/parser.ts +36 -2
- package/src/sitemap/renderer.ts +12 -6
- package/src/timeline/renderer.ts +4 -3
- package/src/utils/legend-d3.ts +4 -3
- package/src/utils/legend-svg.ts +3 -2
- package/src/utils/tag-groups.ts +28 -7
- package/src/visualizations/parse.ts +2 -1
package/src/utils/tag-groups.ts
CHANGED
|
@@ -39,6 +39,23 @@ export interface TagGroup {
|
|
|
39
39
|
readonly lineNumber: number;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* DOM-safe key for a tag group — used wherever the group name becomes a
|
|
44
|
+
* `data-tag-*` attribute suffix, an entity metadata key, or an `active-tag`
|
|
45
|
+
* match target. For a single-identifier name (the only form the parser used to
|
|
46
|
+
* accept) this is exactly `name.toLowerCase()`, so swapping it in for existing
|
|
47
|
+
* diagrams is byte-identical. A quoted multi-word name (`tag "Trust Zone" as tz`)
|
|
48
|
+
* slugs to a hyphenated identifier (`trust-zone`) so it never produces an
|
|
49
|
+
* invalid DOM attribute name; the original `name` is kept for the legend label.
|
|
50
|
+
*/
|
|
51
|
+
export function tagAttrKey(name: string): string {
|
|
52
|
+
return name
|
|
53
|
+
.trim()
|
|
54
|
+
.toLowerCase()
|
|
55
|
+
.replace(/[^a-z0-9_-]+/g, '-')
|
|
56
|
+
.replace(/^-+|-+$/g, '');
|
|
57
|
+
}
|
|
58
|
+
|
|
42
59
|
/** Result of matching a tag block heading */
|
|
43
60
|
interface TagBlockMatch {
|
|
44
61
|
name: string;
|
|
@@ -450,12 +467,12 @@ export function resolveTagColor(
|
|
|
450
467
|
if (!activeGroupName) return undefined;
|
|
451
468
|
|
|
452
469
|
const group = tagGroups.find(
|
|
453
|
-
(g) => g.name
|
|
470
|
+
(g) => tagAttrKey(g.name) === tagAttrKey(activeGroupName)
|
|
454
471
|
);
|
|
455
472
|
if (!group) return undefined;
|
|
456
473
|
|
|
457
474
|
const metaValue =
|
|
458
|
-
metadata[group.name
|
|
475
|
+
metadata[tagAttrKey(group.name)] ??
|
|
459
476
|
(isContainer ? undefined : group.defaultValue);
|
|
460
477
|
if (!metaValue) return '#999999';
|
|
461
478
|
|
|
@@ -489,7 +506,7 @@ export function validateTagValues(
|
|
|
489
506
|
if (tagGroups.length === 0) return;
|
|
490
507
|
|
|
491
508
|
const groupMap = new Map<string, TagGroup>();
|
|
492
|
-
for (const g of tagGroups) groupMap.set(g.name
|
|
509
|
+
for (const g of tagGroups) groupMap.set(tagAttrKey(g.name), g);
|
|
493
510
|
|
|
494
511
|
for (const entity of entities) {
|
|
495
512
|
for (const [key, value] of Object.entries(entity.metadata)) {
|
|
@@ -557,10 +574,14 @@ export function validateTagGroupNames(
|
|
|
557
574
|
`'none' is a reserved keyword and cannot be used as a tag group name`
|
|
558
575
|
);
|
|
559
576
|
}
|
|
560
|
-
|
|
577
|
+
// A single-identifier name is valid as-is; a multi-word name is valid when
|
|
578
|
+
// quoted (`tag "Trust Zone" as tz`) — it slugs to a DOM-safe key while the
|
|
579
|
+
// original text stays the legend label. Reject only names whose slug is
|
|
580
|
+
// not a usable identifier (e.g. all-punctuation, or leading digit).
|
|
581
|
+
if (!VALID_TAG_IDENT_RE.test(tagAttrKey(group.name))) {
|
|
561
582
|
report(
|
|
562
583
|
group.lineNumber,
|
|
563
|
-
`Tag group name "${group.name}"
|
|
584
|
+
`Tag group name "${group.name}" can't form a valid key — use letters, digits, underscore, or hyphen, and quote a multi-word name (e.g. tag "Trust Zone" as tz)`
|
|
564
585
|
);
|
|
565
586
|
}
|
|
566
587
|
if (group.alias != null && !VALID_TAG_IDENT_RE.test(group.alias)) {
|
|
@@ -591,7 +612,7 @@ export function validateTagGroupNames(
|
|
|
591
612
|
export function cascadeTagMetadata<
|
|
592
613
|
T extends { metadata: Record<string, string>; children: readonly T[] },
|
|
593
614
|
>(roots: readonly T[], tagGroups: ReadonlyArray<{ name: string }>): void {
|
|
594
|
-
const keys = tagGroups.map((g) => g.name
|
|
615
|
+
const keys = tagGroups.map((g) => tagAttrKey(g.name));
|
|
595
616
|
if (keys.length === 0) return;
|
|
596
617
|
|
|
597
618
|
const walk = (node: T, inherited: Record<string, string>): void => {
|
|
@@ -629,7 +650,7 @@ export function injectDefaultTagMetadata(
|
|
|
629
650
|
for (const group of tagGroups) {
|
|
630
651
|
if (group.defaultValue) {
|
|
631
652
|
defaults.push({
|
|
632
|
-
key: group.name
|
|
653
|
+
key: tagAttrKey(group.name),
|
|
633
654
|
value: group.defaultValue,
|
|
634
655
|
});
|
|
635
656
|
}
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
stripDefaultModifier,
|
|
37
37
|
validateTagGroupNames,
|
|
38
38
|
validateTagValues,
|
|
39
|
+
tagAttrKey,
|
|
39
40
|
} from '../utils/tag-groups';
|
|
40
41
|
import type { TagGroup } from '../utils/tag-groups';
|
|
41
42
|
import type { Writable } from '../utils/brand';
|
|
@@ -1364,7 +1365,7 @@ function parseVisualizationFull(
|
|
|
1364
1365
|
);
|
|
1365
1366
|
for (const group of result.timelineTagGroups) {
|
|
1366
1367
|
if (!group.defaultValue) continue;
|
|
1367
|
-
const key = group.name
|
|
1368
|
+
const key = tagAttrKey(group.name);
|
|
1368
1369
|
for (const event of result.timelineEvents) {
|
|
1369
1370
|
if (!event.metadata[key]) {
|
|
1370
1371
|
event.metadata[key] = group.defaultValue;
|