@the-package-labs/idocs-core 0.4.0 → 0.6.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/dist/browser.js +2 -2
- package/dist/chunk-H77C3DSX.js +817 -0
- package/dist/{chunk-S7M3BRFI.js → chunk-MUGDM3EQ.js} +242 -11
- package/dist/{chunk-3QBMUILO.js → chunk-RJUH342Z.js} +1 -1
- package/dist/defaults.d.ts +2 -0
- package/dist/highlight.d.ts +21 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +116 -7
- package/dist/nested-layout.d.ts +4 -1
- package/dist/node.js +3 -3
- package/dist/placeholders.d.ts +40 -0
- package/dist/schema.d.ts +47 -0
- package/dist/scrubber.d.ts +34 -0
- package/dist/start.d.ts +22 -0
- package/dist/types.d.ts +32 -0
- package/package.json +1 -1
- package/dist/chunk-ITBBPZE6.js +0 -145
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BUILTIN_EDGE_KINDS,
|
|
3
3
|
BUILTIN_KINDS,
|
|
4
|
+
DEFAULT_ENTITY_WIDTH,
|
|
4
5
|
didYouMean,
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
highlightSegments,
|
|
7
|
+
languageLabel,
|
|
8
|
+
letterKey,
|
|
9
|
+
splitPlaceholders,
|
|
10
|
+
takesPlaceholders
|
|
11
|
+
} from "./chunk-H77C3DSX.js";
|
|
7
12
|
|
|
8
13
|
// src/icon-resolver.ts
|
|
9
14
|
import { getIconData, iconToSVG } from "@iconify/utils";
|
|
@@ -103,7 +108,62 @@ import remarkGfm from "remark-gfm";
|
|
|
103
108
|
import remarkParse from "remark-parse";
|
|
104
109
|
import remarkRehype from "remark-rehype";
|
|
105
110
|
import { unified } from "unified";
|
|
106
|
-
var
|
|
111
|
+
var isElement = (n, tag) => n.type === "element" && (tag === void 0 || n.tagName === tag);
|
|
112
|
+
var classesOf = (el2) => {
|
|
113
|
+
const c = el2.properties.className;
|
|
114
|
+
return Array.isArray(c) ? c.map(String) : typeof c === "string" ? c.split(/\s+/) : [];
|
|
115
|
+
};
|
|
116
|
+
var titleOf = (meta) => {
|
|
117
|
+
const m = meta?.match(/\btitle=(?:"([^"]*)"|'([^']*)')/);
|
|
118
|
+
return m?.[1] ?? m?.[2];
|
|
119
|
+
};
|
|
120
|
+
var el = (tagName, properties, children = []) => ({ type: "element", tagName, properties, children });
|
|
121
|
+
function commandBlocks() {
|
|
122
|
+
const wrap = (pre) => {
|
|
123
|
+
const code = pre.children.find((c) => isElement(c, "code"));
|
|
124
|
+
if (!code || !isElement(code)) return pre;
|
|
125
|
+
const lang = classesOf(code).find((c) => c.startsWith("language-"))?.slice("language-".length);
|
|
126
|
+
const title = titleOf(code.data?.meta);
|
|
127
|
+
if (code.children.every((c) => c.type === "text")) {
|
|
128
|
+
const text = code.children.map((c) => c.value).join("");
|
|
129
|
+
const segments = takesPlaceholders(lang, code.data?.meta) ? splitPlaceholders(text) : [{ kind: "text", text }];
|
|
130
|
+
code.children = highlightSegments(lang, segments).map((piece) => {
|
|
131
|
+
if (piece.kind === "var") {
|
|
132
|
+
const { key, raw } = piece.segment;
|
|
133
|
+
return el("span", { className: ["idocs-ph"], dataKey: key, dataRaw: raw }, [
|
|
134
|
+
{ type: "text", value: raw }
|
|
135
|
+
]);
|
|
136
|
+
}
|
|
137
|
+
return piece.cls ? el("span", { className: [`hl-${piece.cls}`] }, [{ type: "text", value: piece.text }]) : { type: "text", value: piece.text };
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return el(
|
|
141
|
+
"div",
|
|
142
|
+
{ className: ["idocs-cmd"], dataIdocsCmd: "", ...lang ? { dataLang: lang } : {} },
|
|
143
|
+
[
|
|
144
|
+
el("div", { className: ["idocs-cmd-head"] }, [
|
|
145
|
+
el("span", { className: ["idocs-cmd-lang"] }, [
|
|
146
|
+
{ type: "text", value: languageLabel(lang) }
|
|
147
|
+
]),
|
|
148
|
+
...title ? [el("span", { className: ["idocs-cmd-title"] }, [{ type: "text", value: title }])] : [],
|
|
149
|
+
el("div", { className: ["idocs-cmd-bar"] })
|
|
150
|
+
]),
|
|
151
|
+
pre,
|
|
152
|
+
el("div", { className: ["idocs-cmd-panel"] })
|
|
153
|
+
]
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
const walk = (node) => {
|
|
157
|
+
if (!("children" in node) || !node.children) return;
|
|
158
|
+
node.children = node.children.map((c) => {
|
|
159
|
+
if (isElement(c, "pre")) return wrap(c);
|
|
160
|
+
walk(c);
|
|
161
|
+
return c;
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
return (tree) => walk(tree);
|
|
165
|
+
}
|
|
166
|
+
var processor = unified().use(remarkParse).use(remarkGfm).use(remarkRehype).use(commandBlocks).use(rehypeStringify);
|
|
107
167
|
function renderMarkdown(md) {
|
|
108
168
|
const body = stripFrontmatter(md).trim();
|
|
109
169
|
if (!body) return "";
|
|
@@ -215,10 +275,28 @@ var ChipSchema = z.union([
|
|
|
215
275
|
z.string(),
|
|
216
276
|
z.strictObject({ label: z.string(), sub: z.string().optional() })
|
|
217
277
|
]);
|
|
278
|
+
var FieldProps = z.strictObject({
|
|
279
|
+
type: z.string().optional().describe("Its type: `keyword`, `uuid`, `string[]`."),
|
|
280
|
+
key: z.boolean().optional().describe("Part of the primary key. Shown with a `#` in front."),
|
|
281
|
+
ref: z.string().optional().describe(
|
|
282
|
+
"The `node` or `node.field` this one points at, like a foreign key. Draws a relation between the two cards."
|
|
283
|
+
),
|
|
284
|
+
note: z.string().optional().describe("Shown on hover and in the drawer.")
|
|
285
|
+
});
|
|
286
|
+
var FieldSchema = z.union([
|
|
287
|
+
z.string().min(1),
|
|
288
|
+
z.record(z.string().min(1), z.union([z.string(), z.null(), FieldProps])).refine((o) => Object.keys(o).length === 1, {
|
|
289
|
+
message: "One field per list item: `- name: type`"
|
|
290
|
+
})
|
|
291
|
+
]);
|
|
218
292
|
var NodeSchema = z.strictObject({
|
|
219
293
|
title: z.string().optional().describe("Display name. Defaults to the node id."),
|
|
220
294
|
sub: z.string().optional().describe("One line under the title, rendered in mono (ports, stack, version)."),
|
|
295
|
+
pill: z.string().optional().describe("Short label in the card header, like `TABLE` or `ES INDEX`."),
|
|
221
296
|
lines: z.array(z.string()).optional().describe("Short body lines inside the card."),
|
|
297
|
+
fields: z.array(FieldSchema).optional().describe(
|
|
298
|
+
"Makes the card an entity: a table of fields, each `name: type`. `ref` points a field at another entity."
|
|
299
|
+
),
|
|
222
300
|
icon: z.string().optional().describe("`postgresql`, `logos:redis`, `lucide:server` or ./path/to.svg."),
|
|
223
301
|
kind: z.string().optional().describe("Gives a default icon and colour family. See `kinds`."),
|
|
224
302
|
family: FamilySchema.optional().describe("Accent colour family; overrides the kind default."),
|
|
@@ -354,10 +432,31 @@ var ScenarioSchema = ScenarioBase.refine(
|
|
|
354
432
|
(s) => (s.phases?.length ?? 0) + (s.steps?.length ?? 0) > 0,
|
|
355
433
|
{ message: "A scenario needs `steps` or `phases`" }
|
|
356
434
|
);
|
|
435
|
+
var DefaultsSchema = z.strictObject({
|
|
436
|
+
view: Id.optional().describe(
|
|
437
|
+
"View shown first. Defaults to the view of `scenario`, or else the first view."
|
|
438
|
+
),
|
|
439
|
+
scenario: Id.optional().describe(
|
|
440
|
+
"Scenario selected first. Without it the diagram opens on its overview. It does not play until a reader presses play, unless `autoplay` is on."
|
|
441
|
+
),
|
|
442
|
+
mode: z.enum(["flow", "sequence", "story"]).optional().describe(
|
|
443
|
+
"How a scenario is drawn when it has no `mode` of its own: packets over the diagram, a sequence diagram, or a swimlane story."
|
|
444
|
+
),
|
|
445
|
+
sidebar: z.boolean().optional().describe(
|
|
446
|
+
"Whether the panel over the picture starts open. By default it does when there is a scenario or another view to choose, and the frame is wide enough."
|
|
447
|
+
),
|
|
448
|
+
subtitles: z.boolean().optional().describe("Words over the picture saying what the scenario is doing. On by default."),
|
|
449
|
+
autoplay: z.boolean().optional().describe(
|
|
450
|
+
"Play `scenario` as soon as the diagram is on screen. Needs `scenario`, and is ignored when the system asks for reduced motion."
|
|
451
|
+
)
|
|
452
|
+
});
|
|
357
453
|
var RootSchema = z.strictObject({
|
|
358
454
|
$schema: z.string().optional(),
|
|
359
455
|
title: z.string(),
|
|
360
456
|
description: z.string().optional().describe("Markdown shown above the first view."),
|
|
457
|
+
defaults: DefaultsSchema.optional().describe(
|
|
458
|
+
"How the diagram opens: its view, scenario and mode, and whether the panel and subtitles show. A page can still choose otherwise with the props of `<Diagram>`."
|
|
459
|
+
),
|
|
361
460
|
kinds: z.record(Id, z.strictObject({ icon: z.string().optional(), family: FamilySchema.optional() })).optional(),
|
|
362
461
|
edgeKinds: z.record(
|
|
363
462
|
Id,
|
|
@@ -380,7 +479,8 @@ var KNOWN_KEYS = {
|
|
|
380
479
|
group: Object.keys(GroupSchema.shape),
|
|
381
480
|
edge: Object.keys(EdgeSchema.shape),
|
|
382
481
|
view: Object.keys(ViewSchema.shape),
|
|
383
|
-
scenario: Object.keys(ScenarioBase.shape)
|
|
482
|
+
scenario: Object.keys(ScenarioBase.shape),
|
|
483
|
+
defaults: Object.keys(DefaultsSchema.shape)
|
|
384
484
|
};
|
|
385
485
|
function authoringJsonSchema() {
|
|
386
486
|
const schema = z.toJSONSchema(RootSchema, { io: "input", unrepresentable: "any" });
|
|
@@ -589,6 +689,7 @@ function build(data, src, error, warn, { resolveIcon }) {
|
|
|
589
689
|
const fixParents = Object.values(groups);
|
|
590
690
|
for (const g of fixParents) g.style = g.parent ? "frame" : "zone";
|
|
591
691
|
const nodes = {};
|
|
692
|
+
const refTexts = [];
|
|
592
693
|
for (const [id, n] of Object.entries(data.nodes)) {
|
|
593
694
|
if (n.kind && !kinds[n.kind]) {
|
|
594
695
|
warn(
|
|
@@ -617,11 +718,26 @@ function build(data, src, error, warn, { resolveIcon }) {
|
|
|
617
718
|
if (n.doc && docText === void 0)
|
|
618
719
|
warn(`Doc file "${n.doc}" was not found`, ["nodes", id, "doc"]);
|
|
619
720
|
const docHtml = [n.description, docText].filter((t) => !!t).map(renderMarkdown).join("");
|
|
721
|
+
const fields = (n.fields ?? []).map(toField);
|
|
722
|
+
const seenFields = /* @__PURE__ */ new Set();
|
|
723
|
+
fields.forEach((f, i) => {
|
|
724
|
+
if (seenFields.has(f.name)) {
|
|
725
|
+
error(`Field "${f.name}" appears twice in "${id}"`, ["nodes", id, "fields", i]);
|
|
726
|
+
}
|
|
727
|
+
seenFields.add(f.name);
|
|
728
|
+
});
|
|
729
|
+
n.fields?.forEach((item, i) => {
|
|
730
|
+
const ref = typeof item === "object" && item ? Object.values(item)[0] : void 0;
|
|
731
|
+
if (ref && typeof ref === "object" && ref.ref !== void 0)
|
|
732
|
+
refTexts.push({ node: id, index: i, text: ref.ref });
|
|
733
|
+
});
|
|
620
734
|
nodes[id] = {
|
|
621
735
|
id,
|
|
622
736
|
title: n.title ?? id,
|
|
623
737
|
sub: n.sub,
|
|
738
|
+
pill: n.pill,
|
|
624
739
|
lines: n.lines ?? [],
|
|
740
|
+
fields,
|
|
625
741
|
icon: iconFor(n.icon ?? kind?.icon, ["nodes", id, n.icon ? "icon" : "kind"]),
|
|
626
742
|
kind: n.kind,
|
|
627
743
|
family: n.family ?? kind?.family,
|
|
@@ -630,7 +746,7 @@ function build(data, src, error, warn, { resolveIcon }) {
|
|
|
630
746
|
badge: n.badge === void 0 ? void 0 : String(n.badge),
|
|
631
747
|
uses: n.uses ?? [],
|
|
632
748
|
chips: (n.chips ?? []).map((c) => typeof c === "string" ? { label: c } : c),
|
|
633
|
-
w: n.w,
|
|
749
|
+
w: n.w ?? (fields.length ? DEFAULT_ENTITY_WIDTH : void 0),
|
|
634
750
|
docHtml: docHtml || void 0,
|
|
635
751
|
links: n.links ?? [],
|
|
636
752
|
refs: n.refs ?? [],
|
|
@@ -638,18 +754,39 @@ function build(data, src, error, warn, { resolveIcon }) {
|
|
|
638
754
|
diagram: typeof n.diagram === "string" ? { name: n.diagram } : n.diagram
|
|
639
755
|
};
|
|
640
756
|
}
|
|
757
|
+
for (const { node: id, index, text } of refTexts) {
|
|
758
|
+
const found = resolveEnd(text, nodes);
|
|
759
|
+
if ("end" in found) {
|
|
760
|
+
nodes[id].fields[index].ref = found.end;
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
const name = nodes[id].fields[index].name;
|
|
764
|
+
error(
|
|
765
|
+
found.message ?? `Field "${name}" points at "${text}", which is not a node`,
|
|
766
|
+
["nodes", id, "fields", index, name, "ref"],
|
|
767
|
+
found.hint ?? didYouMean(text, Object.keys(nodes))
|
|
768
|
+
);
|
|
769
|
+
}
|
|
641
770
|
const edges = {};
|
|
642
771
|
const nodeIds = Object.keys(nodes);
|
|
643
772
|
(data.edges ?? []).forEach((e, i) => {
|
|
644
773
|
const path = ["edges", i];
|
|
645
774
|
let ok = true;
|
|
775
|
+
const ends = {};
|
|
646
776
|
for (const end of ["from", "to"]) {
|
|
647
|
-
|
|
648
|
-
|
|
777
|
+
const found = resolveEnd(e[end], nodes);
|
|
778
|
+
if ("end" in found) ends[end] = found.end;
|
|
779
|
+
else {
|
|
780
|
+
error(
|
|
781
|
+
found.message ?? `Edge ${end} "${e[end]}" is not a node`,
|
|
782
|
+
[...path, end],
|
|
783
|
+
found.hint ?? didYouMean(e[end], nodeIds)
|
|
784
|
+
);
|
|
649
785
|
ok = false;
|
|
650
786
|
}
|
|
651
787
|
}
|
|
652
|
-
const
|
|
788
|
+
const between = ends.from && ends.to && [ends.from, ends.to].every((x) => nodes[x.node].fields.length);
|
|
789
|
+
const kind = e.kind ?? (between ? "relation" : "http");
|
|
653
790
|
if (!edgeKinds[kind]) {
|
|
654
791
|
error(
|
|
655
792
|
`Unknown edge kind "${kind}"`,
|
|
@@ -658,7 +795,7 @@ function build(data, src, error, warn, { resolveIcon }) {
|
|
|
658
795
|
);
|
|
659
796
|
ok = false;
|
|
660
797
|
}
|
|
661
|
-
if (
|
|
798
|
+
if (ok && ends.from.node === ends.to.node) {
|
|
662
799
|
warn("Edge connects a node to itself and is not drawn", path);
|
|
663
800
|
ok = false;
|
|
664
801
|
}
|
|
@@ -670,8 +807,10 @@ function build(data, src, error, warn, { resolveIcon }) {
|
|
|
670
807
|
}
|
|
671
808
|
edges[id] = {
|
|
672
809
|
id,
|
|
673
|
-
from:
|
|
674
|
-
to:
|
|
810
|
+
from: ends.from.node,
|
|
811
|
+
to: ends.to.node,
|
|
812
|
+
fromField: ends.from.field,
|
|
813
|
+
toField: ends.to.field,
|
|
675
814
|
label: e.label,
|
|
676
815
|
kind,
|
|
677
816
|
both: e.both ?? false,
|
|
@@ -684,6 +823,32 @@ function build(data, src, error, warn, { resolveIcon }) {
|
|
|
684
823
|
noteHtml: e.note ? renderMarkdown(e.note) : void 0
|
|
685
824
|
};
|
|
686
825
|
});
|
|
826
|
+
const written = new Set(
|
|
827
|
+
Object.values(edges).flatMap((e) => {
|
|
828
|
+
const a = `${e.from}.${e.fromField ?? ""}`;
|
|
829
|
+
const b = `${e.to}.${e.toField ?? ""}`;
|
|
830
|
+
return [`${a}>${b}`, `${b}>${a}`];
|
|
831
|
+
})
|
|
832
|
+
);
|
|
833
|
+
for (const node of Object.values(nodes)) {
|
|
834
|
+
for (const f of node.fields) {
|
|
835
|
+
if (!f.ref || f.ref.node === node.id) continue;
|
|
836
|
+
const key = `${node.id}.${f.name}>${f.ref.node}.${f.ref.field ?? ""}`;
|
|
837
|
+
if (written.has(key)) continue;
|
|
838
|
+
const id = `ref:${node.id}.${f.name}`;
|
|
839
|
+
edges[id] = {
|
|
840
|
+
id,
|
|
841
|
+
from: node.id,
|
|
842
|
+
to: f.ref.node,
|
|
843
|
+
fromField: f.name,
|
|
844
|
+
toField: f.ref.field,
|
|
845
|
+
kind: "relation",
|
|
846
|
+
both: false,
|
|
847
|
+
hidden: false,
|
|
848
|
+
status: "built"
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
}
|
|
687
852
|
const viewDefs = Object.keys(data.views ?? {}).length ? data.views : { main: { title: data.title } };
|
|
688
853
|
const views = Object.entries(viewDefs).map(
|
|
689
854
|
([id, v]) => buildView(
|
|
@@ -701,10 +866,12 @@ function build(data, src, error, warn, { resolveIcon }) {
|
|
|
701
866
|
const sc = buildScenario(id, s, views, nodes, edges, error, warn);
|
|
702
867
|
if (sc) scenarios.push(sc);
|
|
703
868
|
}
|
|
869
|
+
const defaults = buildDefaults(data.defaults, views, scenarios, error);
|
|
704
870
|
return {
|
|
705
871
|
name: src.name,
|
|
706
872
|
title: data.title,
|
|
707
873
|
descriptionHtml: data.description ? renderMarkdown(data.description) : void 0,
|
|
874
|
+
defaults,
|
|
708
875
|
nodes,
|
|
709
876
|
groups,
|
|
710
877
|
edges,
|
|
@@ -713,6 +880,37 @@ function build(data, src, error, warn, { resolveIcon }) {
|
|
|
713
880
|
scenarios
|
|
714
881
|
};
|
|
715
882
|
}
|
|
883
|
+
function toField(item) {
|
|
884
|
+
if (typeof item === "string") return { name: item };
|
|
885
|
+
const [name, value] = Object.entries(item)[0];
|
|
886
|
+
if (value == null) return { name };
|
|
887
|
+
if (typeof value === "string") return { name, type: value };
|
|
888
|
+
const { ref: _ref, ...rest } = value;
|
|
889
|
+
return { name, ...rest };
|
|
890
|
+
}
|
|
891
|
+
function resolveEnd(text, nodes) {
|
|
892
|
+
if (nodes[text]) return { end: { node: text } };
|
|
893
|
+
const matches = [];
|
|
894
|
+
let known;
|
|
895
|
+
for (let i = text.indexOf("."); i > 0; i = text.indexOf(".", i + 1)) {
|
|
896
|
+
const node = nodes[text.slice(0, i)];
|
|
897
|
+
if (!node) continue;
|
|
898
|
+
known ??= node;
|
|
899
|
+
const field2 = text.slice(i + 1);
|
|
900
|
+
if (node.fields.some((f) => f.name === field2)) matches.push({ node: node.id, field: field2 });
|
|
901
|
+
}
|
|
902
|
+
if (matches.length === 1) return { end: matches[0] };
|
|
903
|
+
if (matches.length > 1) {
|
|
904
|
+
return { message: `"${text}" could be more than one field`, hint: "Rename a node or a field." };
|
|
905
|
+
}
|
|
906
|
+
if (!known) return {};
|
|
907
|
+
const field = text.slice(known.id.length + 1);
|
|
908
|
+
const names = known.fields.map((f) => f.name);
|
|
909
|
+
return {
|
|
910
|
+
message: `Node "${known.id}" has no field "${field}"`,
|
|
911
|
+
hint: didYouMean(field, names) ?? (names.length ? `Fields: ${names.join(", ")}` : void 0)
|
|
912
|
+
};
|
|
913
|
+
}
|
|
716
914
|
function buildView(id, v, diagramTitle, nodes, groups, edges, error) {
|
|
717
915
|
const known = [...Object.keys(nodes), ...Object.keys(groups)];
|
|
718
916
|
const members = (gid, out) => {
|
|
@@ -765,6 +963,38 @@ function buildView(id, v, diagramTitle, nodes, groups, edges, error) {
|
|
|
765
963
|
interfaces: v.interfaces ?? false
|
|
766
964
|
};
|
|
767
965
|
}
|
|
966
|
+
function buildDefaults(d, views, scenarios, error) {
|
|
967
|
+
if (!d) return void 0;
|
|
968
|
+
const ids = (list) => list.map((x) => x.id);
|
|
969
|
+
const view = views.find((v) => v.id === d.view);
|
|
970
|
+
if (d.view !== void 0 && !view) {
|
|
971
|
+
error(
|
|
972
|
+
`defaults.view "${d.view}" is not a view`,
|
|
973
|
+
["defaults", "view"],
|
|
974
|
+
didYouMean(d.view, ids(views))
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
const scenario = scenarios.find((s) => s.id === d.scenario);
|
|
978
|
+
if (d.scenario !== void 0 && !scenario) {
|
|
979
|
+
error(
|
|
980
|
+
`defaults.scenario "${d.scenario}" is not a scenario`,
|
|
981
|
+
["defaults", "scenario"],
|
|
982
|
+
didYouMean(d.scenario, ids(scenarios))
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
if (view && scenario && scenario.view !== view.id) {
|
|
986
|
+
error(
|
|
987
|
+
`defaults.scenario "${scenario.id}" plays on view "${scenario.view}", not "${view.id}"`,
|
|
988
|
+
["defaults", "scenario"],
|
|
989
|
+
`Drop \`view\` and the diagram opens on "${scenario.view}", or pick a scenario of "${view.id}".`
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
if (d.autoplay && d.scenario === void 0) {
|
|
993
|
+
error("defaults.autoplay needs a defaults.scenario to play", ["defaults", "autoplay"]);
|
|
994
|
+
}
|
|
995
|
+
const out = Object.fromEntries(Object.entries(d).filter(([, v]) => v !== void 0));
|
|
996
|
+
return Object.keys(out).length ? out : void 0;
|
|
997
|
+
}
|
|
768
998
|
function buildScenario(id, s, views, nodes, edges, error, warn) {
|
|
769
999
|
const viewId = s.view ?? views[0].id;
|
|
770
1000
|
const view = views.find((v) => v.id === viewId);
|
|
@@ -1042,6 +1272,7 @@ function describeIssue(issue) {
|
|
|
1042
1272
|
function allowedKeysFor(path) {
|
|
1043
1273
|
const [section] = path;
|
|
1044
1274
|
if (path.length === 0) return KNOWN_KEYS.root;
|
|
1275
|
+
if (path.length === 1) return section === "defaults" ? KNOWN_KEYS.defaults : void 0;
|
|
1045
1276
|
if (path.length !== 2) return void 0;
|
|
1046
1277
|
switch (section) {
|
|
1047
1278
|
case "nodes":
|
package/dist/defaults.d.ts
CHANGED
|
@@ -8,3 +8,5 @@ export declare const BUILTIN_KINDS: Record<string, KindDef>;
|
|
|
8
8
|
export declare const BUILTIN_EDGE_KINDS: Record<string, EdgeKindDef>;
|
|
9
9
|
export declare const STEP_KIND_COLORS: Record<string, string>;
|
|
10
10
|
export declare const DEFAULT_NODE_WIDTH = 178;
|
|
11
|
+
/** Cards with fields need room for a name and a type side by side. */
|
|
12
|
+
export declare const DEFAULT_ENTITY_WIDTH = 280;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { PlaceholderSegment } from './placeholders';
|
|
2
|
+
export type TokenClass = 'comment' | 'string' | 'keyword' | 'flag' | 'number' | 'variable' | 'key' | 'literal' | 'operator' | 'section';
|
|
3
|
+
export interface Token {
|
|
4
|
+
text: string;
|
|
5
|
+
cls?: TokenClass;
|
|
6
|
+
}
|
|
7
|
+
/** The name of a language as a block's header shows it. Blocks with none are text. */
|
|
8
|
+
export declare function languageLabel(lang: string | undefined): string;
|
|
9
|
+
export declare function highlight(lang: string | undefined, text: string): Token[];
|
|
10
|
+
export type Piece = {
|
|
11
|
+
kind: 'text';
|
|
12
|
+
text: string;
|
|
13
|
+
cls?: TokenClass;
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'var';
|
|
16
|
+
segment: Extract<PlaceholderSegment, {
|
|
17
|
+
kind: 'var';
|
|
18
|
+
}>;
|
|
19
|
+
};
|
|
20
|
+
/** A block's text as pieces to draw: coloured runs, with each placeholder where it was. */
|
|
21
|
+
export declare function highlightSegments(lang: string | undefined, segments: PlaceholderSegment[]): Piece[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
export * from './defaults';
|
|
2
2
|
export * from './geometry';
|
|
3
|
+
export * from './highlight';
|
|
3
4
|
export * from './layout';
|
|
4
5
|
export * from './nested-layout';
|
|
5
6
|
export * from './nesting';
|
|
6
7
|
export * from './outline';
|
|
7
8
|
export * from './phases';
|
|
9
|
+
export * from './placeholders';
|
|
8
10
|
export * from './route';
|
|
11
|
+
export * from './scrubber';
|
|
12
|
+
export * from './start';
|
|
9
13
|
export * from './story';
|
|
10
14
|
export * from './svg';
|
|
11
15
|
export * from './timeline';
|
package/dist/index.js
CHANGED
|
@@ -2,18 +2,31 @@ import {
|
|
|
2
2
|
attachNested,
|
|
3
3
|
linkDiagrams,
|
|
4
4
|
nestedDiagrams
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-RJUH342Z.js";
|
|
6
6
|
import {
|
|
7
7
|
BUILTIN_EDGE_KINDS,
|
|
8
8
|
BUILTIN_KINDS,
|
|
9
|
+
DEFAULT_ENTITY_WIDTH,
|
|
9
10
|
DEFAULT_NODE_WIDTH,
|
|
10
11
|
STEP_KIND_COLORS,
|
|
11
12
|
dist,
|
|
13
|
+
fillPlaceholders,
|
|
14
|
+
fillSegments,
|
|
15
|
+
highlight,
|
|
16
|
+
highlightSegments,
|
|
17
|
+
isSecretKey,
|
|
18
|
+
languageLabel,
|
|
12
19
|
letterKey,
|
|
20
|
+
placeholdersOf,
|
|
13
21
|
pointAt,
|
|
14
22
|
polylineLength,
|
|
15
|
-
roundedPath
|
|
16
|
-
|
|
23
|
+
roundedPath,
|
|
24
|
+
shownPlaceholder,
|
|
25
|
+
splitPlaceholders,
|
|
26
|
+
takesPlaceholders,
|
|
27
|
+
unsetPlaceholders,
|
|
28
|
+
varKey
|
|
29
|
+
} from "./chunk-H77C3DSX.js";
|
|
17
30
|
|
|
18
31
|
// src/layout.ts
|
|
19
32
|
import ELK from "elkjs/lib/elk.bundled.js";
|
|
@@ -960,9 +973,10 @@ function overlap(a, b, pad) {
|
|
|
960
973
|
var INLINE_PAD = { top: 40, left: 4, right: 4, bottom: 4 };
|
|
961
974
|
function openingView(diagram, ref) {
|
|
962
975
|
const has = (id) => diagram.views.some((v) => v.id === id);
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
976
|
+
const of = (scenario) => diagram.scenarios.find((s) => s.id === scenario)?.view;
|
|
977
|
+
return [ref.view, of(ref.scenario), of(diagram.defaults?.scenario), diagram.defaults?.view].find(
|
|
978
|
+
has
|
|
979
|
+
) ?? diagram.views[0].id;
|
|
966
980
|
}
|
|
967
981
|
var canExpand = (ref, diagrams) => !!ref && ref.mode !== "open" && !!diagrams[ref.name];
|
|
968
982
|
var canOpen = (ref, diagrams) => !!ref && ref.mode !== "expand" && !!diagrams[ref.name];
|
|
@@ -1186,6 +1200,81 @@ function phaseSpans(scenario) {
|
|
|
1186
1200
|
return out;
|
|
1187
1201
|
}
|
|
1188
1202
|
|
|
1203
|
+
// src/scrubber.ts
|
|
1204
|
+
function buildScrubber(tl) {
|
|
1205
|
+
const steps = tl.scenario.steps;
|
|
1206
|
+
const slots = [];
|
|
1207
|
+
let i = 0;
|
|
1208
|
+
while (i < steps.length) {
|
|
1209
|
+
let j = i + 1;
|
|
1210
|
+
const par = steps[i].par;
|
|
1211
|
+
if (par !== void 0) while (j < steps.length && steps[j].par === par) j++;
|
|
1212
|
+
const run = tl.steps.slice(i, j);
|
|
1213
|
+
slots.push({ from: i, to: j - 1, t0: Math.min(...run.map((s) => s.start)), t1: 0 });
|
|
1214
|
+
i = j;
|
|
1215
|
+
}
|
|
1216
|
+
slots.forEach((slot, k) => {
|
|
1217
|
+
slot.t1 = slots[k + 1]?.t0 ?? tl.duration;
|
|
1218
|
+
});
|
|
1219
|
+
if (slots[0]) slots[0].t0 = 0;
|
|
1220
|
+
const slotOf = (step) => slots.findIndex((s) => s.from <= step && step <= s.to);
|
|
1221
|
+
const sections = phaseSpans(tl.scenario).map((span) => ({
|
|
1222
|
+
phase: span.index,
|
|
1223
|
+
title: span.title,
|
|
1224
|
+
caption: span.caption,
|
|
1225
|
+
from: slotOf(span.from),
|
|
1226
|
+
to: slotOf(span.to)
|
|
1227
|
+
}));
|
|
1228
|
+
return { slots, sections, duration: tl.duration };
|
|
1229
|
+
}
|
|
1230
|
+
var clamp01 = (n) => Math.min(1, Math.max(0, n));
|
|
1231
|
+
function positionAt(s, t) {
|
|
1232
|
+
const n = s.slots.length;
|
|
1233
|
+
if (!n) return 0;
|
|
1234
|
+
let k = 0;
|
|
1235
|
+
s.slots.forEach((slot2, i) => {
|
|
1236
|
+
if (slot2.t0 <= t) k = i;
|
|
1237
|
+
});
|
|
1238
|
+
const slot = s.slots[k];
|
|
1239
|
+
const length = slot.t1 - slot.t0;
|
|
1240
|
+
return (k + (length > 0 ? clamp01((t - slot.t0) / length) : 0)) / n;
|
|
1241
|
+
}
|
|
1242
|
+
function timeAt(s, position) {
|
|
1243
|
+
const n = s.slots.length;
|
|
1244
|
+
if (!n) return 0;
|
|
1245
|
+
const x = clamp01(position) * n;
|
|
1246
|
+
const k = Math.min(n - 1, Math.floor(x));
|
|
1247
|
+
const slot = s.slots[k];
|
|
1248
|
+
return slot.t0 + (x - k) * (slot.t1 - slot.t0);
|
|
1249
|
+
}
|
|
1250
|
+
function slotAt(s, position) {
|
|
1251
|
+
const n = s.slots.length;
|
|
1252
|
+
return n ? Math.min(n - 1, Math.floor(clamp01(position) * n)) : -1;
|
|
1253
|
+
}
|
|
1254
|
+
function slotOfStep(s, index) {
|
|
1255
|
+
return s.slots.findIndex((slot) => slot.from <= index && index <= slot.to);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// src/start.ts
|
|
1259
|
+
var defaultMode = (diagram) => diagram.defaults?.mode ?? "flow";
|
|
1260
|
+
function startOf(diagram, want = {}) {
|
|
1261
|
+
const d = diagram.defaults ?? {};
|
|
1262
|
+
const scenarioById = (id) => diagram.scenarios.find((s) => s.id === id);
|
|
1263
|
+
const hasView = (id) => diagram.views.some((v) => v.id === id);
|
|
1264
|
+
const first = diagram.views[0].id;
|
|
1265
|
+
let view;
|
|
1266
|
+
let scenario;
|
|
1267
|
+
if (want.view !== void 0 || want.scenario !== void 0) {
|
|
1268
|
+
view = [want.view, scenarioById(want.scenario)?.view].find(hasView) ?? first;
|
|
1269
|
+
scenario = scenarioById(want.scenario)?.id ?? (scenarioById(d.scenario)?.view === view ? d.scenario ?? null : null);
|
|
1270
|
+
} else {
|
|
1271
|
+
scenario = scenarioById(d.scenario)?.id ?? null;
|
|
1272
|
+
view = [scenarioById(scenario ?? void 0)?.view, d.view].find(hasView) ?? first;
|
|
1273
|
+
}
|
|
1274
|
+
const mode = want.mode ?? scenarioById(scenario ?? void 0)?.mode ?? defaultMode(diagram);
|
|
1275
|
+
return { view, scenario, mode };
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1189
1278
|
// src/story.ts
|
|
1190
1279
|
function buildStory(diagram, scenario) {
|
|
1191
1280
|
const steps = scenario.steps;
|
|
@@ -1484,20 +1573,29 @@ function runBounds(tl, index) {
|
|
|
1484
1573
|
export {
|
|
1485
1574
|
BUILTIN_EDGE_KINDS,
|
|
1486
1575
|
BUILTIN_KINDS,
|
|
1576
|
+
DEFAULT_ENTITY_WIDTH,
|
|
1487
1577
|
DEFAULT_NODE_WIDTH,
|
|
1488
1578
|
INLINE_PAD,
|
|
1489
1579
|
STEP_KIND_COLORS,
|
|
1490
1580
|
attachNested,
|
|
1491
1581
|
buildOutline,
|
|
1582
|
+
buildScrubber,
|
|
1492
1583
|
buildStory,
|
|
1493
1584
|
buildTimeline,
|
|
1494
1585
|
canExpand,
|
|
1495
1586
|
canOpen,
|
|
1496
1587
|
defaultExpanded,
|
|
1588
|
+
defaultMode,
|
|
1497
1589
|
dist,
|
|
1590
|
+
fillPlaceholders,
|
|
1591
|
+
fillSegments,
|
|
1498
1592
|
frameAt,
|
|
1499
1593
|
hasPhases,
|
|
1594
|
+
highlight,
|
|
1595
|
+
highlightSegments,
|
|
1596
|
+
isSecretKey,
|
|
1500
1597
|
labelWidth,
|
|
1598
|
+
languageLabel,
|
|
1501
1599
|
layoutNested,
|
|
1502
1600
|
layoutView,
|
|
1503
1601
|
letterKey,
|
|
@@ -1509,14 +1607,25 @@ export {
|
|
|
1509
1607
|
packGrid,
|
|
1510
1608
|
pathJoin,
|
|
1511
1609
|
phaseSpans,
|
|
1610
|
+
placeholdersOf,
|
|
1512
1611
|
pointAt,
|
|
1513
1612
|
polylineLength,
|
|
1613
|
+
positionAt,
|
|
1514
1614
|
rectOfPath,
|
|
1515
1615
|
roundedPath,
|
|
1516
1616
|
routeEdges,
|
|
1517
1617
|
runBounds,
|
|
1518
1618
|
scopeSvgIds,
|
|
1619
|
+
shownPlaceholder,
|
|
1620
|
+
slotAt,
|
|
1621
|
+
slotOfStep,
|
|
1622
|
+
splitPlaceholders,
|
|
1623
|
+
startOf,
|
|
1519
1624
|
stepAt,
|
|
1520
1625
|
stepEnd,
|
|
1521
|
-
stepStart
|
|
1626
|
+
stepStart,
|
|
1627
|
+
takesPlaceholders,
|
|
1628
|
+
timeAt,
|
|
1629
|
+
unsetPlaceholders,
|
|
1630
|
+
varKey
|
|
1522
1631
|
};
|
package/dist/nested-layout.d.ts
CHANGED
|
@@ -25,7 +25,10 @@ export interface InnerLayout {
|
|
|
25
25
|
layout: NestedLayout;
|
|
26
26
|
}
|
|
27
27
|
export type Diagrams = Record<string, CompiledDiagram | undefined>;
|
|
28
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* The view a node's diagram shows when opened: the one the node names, its scenario's, the one the
|
|
30
|
+
* diagram opens on by itself, or the first.
|
|
31
|
+
*/
|
|
29
32
|
export declare function openingView(diagram: CompiledDiagram, ref: NodeDiagram): string;
|
|
30
33
|
/** Whether a reader may show this node's diagram in place: it is at hand and not limited to `open`. */
|
|
31
34
|
export declare const canExpand: (ref: NodeDiagram | undefined, diagrams: Diagrams) => boolean;
|
package/dist/node.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
attachNested,
|
|
3
3
|
linkDiagrams,
|
|
4
4
|
nestedDiagrams
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-RJUH342Z.js";
|
|
6
6
|
import {
|
|
7
7
|
FamilySchema,
|
|
8
8
|
KNOWN_KEYS,
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
compileDiagram,
|
|
12
12
|
createIconResolver,
|
|
13
13
|
renderMarkdown
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-MUGDM3EQ.js";
|
|
15
|
+
import "./chunk-H77C3DSX.js";
|
|
16
16
|
|
|
17
17
|
// src/node.ts
|
|
18
18
|
import { existsSync, readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
|