@cardenelabs/dragon 0.35.0 → 0.36.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/README.md +41 -3
- package/dist/cli.cjs +597 -375
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +597 -375
- package/dist/cli.js.map +1 -1
- package/dist/export.cjs +104 -37
- package/dist/export.cjs.map +1 -1
- package/dist/export.d.cts +1 -1
- package/dist/export.d.ts +1 -1
- package/dist/export.js +104 -37
- package/dist/export.js.map +1 -1
- package/dist/index.cjs +833 -526
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -15
- package/dist/index.d.ts +21 -15
- package/dist/index.js +833 -526
- package/dist/index.js.map +1 -1
- package/dist/player.global.js +2 -2
- package/dist/{schema-BBWfniwH.d.cts → schema-9VLameDG.d.cts} +15 -3
- package/dist/{schema-BBWfniwH.d.ts → schema-9VLameDG.d.ts} +15 -3
- package/package.json +20 -8
- package/src/cli.ts +13 -14
- package/src/figure-text.ts +1 -1
- package/src/index.ts +4 -4
- package/src/look/values.ts +16 -4
- package/src/messages.ts +158 -80
- package/src/parser.ts +402 -245
- package/src/player.ts +80 -9
- package/src/printer.ts +90 -60
- package/src/render/parts.ts +28 -8
- package/src/render/svg.ts +128 -33
- package/src/schema.ts +1 -1
- package/src/tokenize.ts +11 -8
- package/src/view.ts +5 -2
- package/src/words.ts +39 -65
package/dist/index.js
CHANGED
|
@@ -43,15 +43,15 @@ var TYPES_EN = {
|
|
|
43
43
|
};
|
|
44
44
|
var plural = (count, word) => `${count} ${word}${count === 1 ? "" : "s"}`;
|
|
45
45
|
var ja = {
|
|
46
|
-
additionalProperties: (
|
|
47
|
-
required: (
|
|
46
|
+
additionalProperties: (key2) => `${key2} \u3068\u3044\u3046\u6B04\u306F\u66F8\u3051\u306A\u3044`,
|
|
47
|
+
required: (key2) => `${key2} \u306E\u6B04\u304C\u8981\u308B`,
|
|
48
48
|
enum: (values) => `${values.join(" / ")} \u306E\u3069\u308C\u304B\u306B\u3059\u308B`,
|
|
49
49
|
type: (type) => TYPES_JA[type] ?? `${type} \u306B\u3059\u308B`,
|
|
50
50
|
minLength: (limit) => `${limit} \u5B57\u4EE5\u4E0A\u66F8\u304F`,
|
|
51
51
|
pattern: (forbidden) => forbidden ? `${forbidden.space ? "\u7A7A\u767D\u3068 " : ""}${forbidden.chars.join(" ")} \u306F\u4F7F\u3048\u306A\u3044` : "\u4F7F\u3048\u306A\u3044\u5B57\u304C\u5165\u3063\u3066\u3044\u308B",
|
|
52
52
|
minItems: (limit) => `${limit} \u3064\u4EE5\u4E0A\u66F8\u304F`,
|
|
53
53
|
minimum: (limit) => `${limit} \u4EE5\u4E0A\u306B\u3059\u308B`,
|
|
54
|
-
const: (
|
|
54
|
+
const: (value2) => `${value2} \u306B\u3059\u308B`,
|
|
55
55
|
not: (allowed) => allowed ? `${allowed.field} \u306E\u6B04\u306F kind \u304C ${allowed.kind} \u306E\u6642\u3060\u3051\u66F8\u3051\u308B` : "\u3053\u306E\u6B04\u306E\u7D44\u307F\u5408\u308F\u305B\u306F\u66F8\u3051\u306A\u3044",
|
|
56
56
|
anyOf: (fields) => fields.length > 0 ? `${fields.join(" \u304B ")} \u306E${fields.length === 2 ? "\u3069\u3061\u3089\u304B" : "\u3069\u308C\u304B"}\u306E\u6B04\u304C\u8981\u308B` : "\u66F8\u3051\u308B\u5F62\u306E\u3069\u308C\u306B\u3082\u5408\u308F\u306A\u3044",
|
|
57
57
|
oneOf: "\u66F8\u3051\u308B\u5F62\u306E\u3069\u308C\u304B 1 \u3064\u3060\u3051\u306B\u5408\u308F\u305B\u308B",
|
|
@@ -59,15 +59,15 @@ var ja = {
|
|
|
59
59
|
newer: (version, tool) => `\u7248 ${version} \u306E\u56F3\u306F\u3001\u3053\u306E\u9053\u5177 (\u7248 ${tool}) \u3088\u308A\u65B0\u3057\u3044\u306E\u3067\u8AAD\u3081\u306A\u3044\u3002\u9053\u5177\u3092\u65B0\u3057\u304F\u3059\u308B`
|
|
60
60
|
};
|
|
61
61
|
var en = {
|
|
62
|
-
additionalProperties: (
|
|
63
|
-
required: (
|
|
62
|
+
additionalProperties: (key2) => `The ${key2} field is not allowed`,
|
|
63
|
+
required: (key2) => `The ${key2} field is required`,
|
|
64
64
|
enum: (values) => `Use one of ${values.join(" / ")}`,
|
|
65
65
|
type: (type) => TYPES_EN[type] ?? `Use ${type}`,
|
|
66
66
|
minLength: (limit) => `Write at least ${plural(limit, "character")}`,
|
|
67
67
|
pattern: (forbidden) => forbidden ? `Cannot contain ${forbidden.space ? "spaces or " : ""}${forbidden.chars.join(" ")}` : "Contains characters that are not allowed",
|
|
68
68
|
minItems: (limit) => `Write at least ${plural(limit, "item")}`,
|
|
69
69
|
minimum: (limit) => `Use ${limit} or greater`,
|
|
70
|
-
const: (
|
|
70
|
+
const: (value2) => `Use ${value2}`,
|
|
71
71
|
not: (allowed) => allowed ? `The ${allowed.field} field is allowed only when kind is ${allowed.kind}` : "This combination of fields is not allowed",
|
|
72
72
|
anyOf: (fields) => fields.length > 0 ? `Write one of the ${fields.join(" or ")} fields` : "Does not match any of the allowed shapes",
|
|
73
73
|
oneOf: "Match exactly one of the allowed shapes",
|
|
@@ -1815,7 +1815,7 @@ var NOT_ALLOWED = {
|
|
|
1815
1815
|
"": { field: "sequence", kind: "sequence" },
|
|
1816
1816
|
carry: { field: "text", kind: "tag" }
|
|
1817
1817
|
};
|
|
1818
|
-
var escape = (
|
|
1818
|
+
var escape = (key2) => key2.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
1819
1819
|
function forbiddenOf(pattern) {
|
|
1820
1820
|
const inside = /^\^\[\^(.+)\]\+\$$/u.exec(pattern)?.[1];
|
|
1821
1821
|
if (inside === void 0) return void 0;
|
|
@@ -1830,12 +1830,12 @@ function toFieldError(error, errors, m) {
|
|
|
1830
1830
|
const at = error.instancePath;
|
|
1831
1831
|
switch (error.keyword) {
|
|
1832
1832
|
case "additionalProperties": {
|
|
1833
|
-
const
|
|
1834
|
-
return { pointer: `${at}/${escape(
|
|
1833
|
+
const key2 = String(params.additionalProperty);
|
|
1834
|
+
return { pointer: `${at}/${escape(key2)}`, message: m.additionalProperties(key2) };
|
|
1835
1835
|
}
|
|
1836
1836
|
case "required": {
|
|
1837
|
-
const
|
|
1838
|
-
return { pointer: `${at}/${escape(
|
|
1837
|
+
const key2 = String(params.missingProperty);
|
|
1838
|
+
return { pointer: `${at}/${escape(key2)}`, message: m.required(key2) };
|
|
1839
1839
|
}
|
|
1840
1840
|
case "not": {
|
|
1841
1841
|
const allowed = NOT_ALLOWED[at.slice(at.lastIndexOf("/") + 1)];
|
|
@@ -1880,145 +1880,174 @@ function validateDiagram(input, options = {}) {
|
|
|
1880
1880
|
}
|
|
1881
1881
|
|
|
1882
1882
|
// src/words.ts
|
|
1883
|
-
var
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
none: { ja: "\u306A\u3057", en: "none" }
|
|
1905
|
-
},
|
|
1906
|
-
/** 見せ方の値 */
|
|
1907
|
-
view: { fixed: { ja: "\u6B62\u3081\u308B", en: "fixed" }, follow: { ja: "\u5BC4\u308B", en: "follow" } },
|
|
1908
|
-
/** 線の名前を置く側 */
|
|
1909
|
-
side: {
|
|
1910
|
-
above: { ja: "\u4E0A", en: "above" },
|
|
1911
|
-
below: { ja: "\u4E0B", en: "below" },
|
|
1912
|
-
left: { ja: "\u5DE6", en: "left" },
|
|
1913
|
-
right: { ja: "\u53F3", en: "right" }
|
|
1914
|
-
}
|
|
1883
|
+
var keys = (table) => Object.keys(table);
|
|
1884
|
+
var KINDS = keys({ sequence: true, architecture: true });
|
|
1885
|
+
var HEADS = ["group", "end", "box", "strip", "step", "say", "code", "act", "note", "set"];
|
|
1886
|
+
var AS = "as";
|
|
1887
|
+
var ATTRS = {
|
|
1888
|
+
diagram: ["view"],
|
|
1889
|
+
group: ["note", "color", "icon"],
|
|
1890
|
+
box: ["note", "color", "icon"],
|
|
1891
|
+
edge: ["carry", "tag", "side"],
|
|
1892
|
+
set: ["tag"]
|
|
1893
|
+
};
|
|
1894
|
+
var CARRIES = keys({ coin: true, none: true });
|
|
1895
|
+
var VIEWS = keys({ fixed: true, follow: true });
|
|
1896
|
+
var SIDES = keys({ above: true, below: true, left: true, right: true });
|
|
1897
|
+
var OLD_HEADS = {
|
|
1898
|
+
\u6642\u7CFB\u5217\u56F3: "sequence",
|
|
1899
|
+
\u69CB\u6210\u56F3: "architecture",
|
|
1900
|
+
\u533A\u753B: "group",
|
|
1901
|
+
\u898B\u305B\u65B9: "view",
|
|
1902
|
+
region: "group",
|
|
1903
|
+
view: "view"
|
|
1915
1904
|
};
|
|
1916
|
-
function wordOf(group, value, lang) {
|
|
1917
|
-
return WORDS[group][value][lang];
|
|
1918
|
-
}
|
|
1919
|
-
function valueOf(group, word, lang) {
|
|
1920
|
-
const found = Object.entries(WORDS[group]).find(([, pair]) => pair[lang] === word);
|
|
1921
|
-
return found?.[0];
|
|
1922
|
-
}
|
|
1923
|
-
var otherLang = (lang) => lang === "ja" ? "en" : "ja";
|
|
1924
|
-
function languageOf(headLine) {
|
|
1925
|
-
const first = headLine.trim().split(/\s+/)[0] ?? "";
|
|
1926
|
-
return ["ja", "en"].find((lang) => valueOf("kind", first, lang) !== void 0);
|
|
1927
|
-
}
|
|
1928
|
-
function notationLanguage(notation) {
|
|
1929
|
-
const head = notation.split(/\r?\n/).map((line) => line.trim()).find((line) => line !== "" && !line.startsWith("//"));
|
|
1930
|
-
return head === void 0 ? void 0 : languageOf(head);
|
|
1931
|
-
}
|
|
1932
1905
|
|
|
1933
1906
|
// src/messages.ts
|
|
1907
|
+
var list = (words) => words.join(" / ");
|
|
1934
1908
|
var ja2 = () => {
|
|
1935
|
-
const
|
|
1909
|
+
const shapes = {
|
|
1910
|
+
sequence: "sequence <\u984C>",
|
|
1911
|
+
architecture: "architecture <\u984C>",
|
|
1912
|
+
group: "group <\u540D\u672D> as <\u540D\u524D> [note: <\u6DFB\u3048\u66F8\u304D>] \u304B\u3089 end \u307E\u3067",
|
|
1913
|
+
box: "box <\u540D\u672D> as <\u540D\u524D> [note: <\u4E0B\u306E\u5C0F\u3055\u306A\u5B57>]",
|
|
1914
|
+
strip: "strip <\u984C>: <\u6B04>, <\u6B04>",
|
|
1915
|
+
view: "sequence <\u984C> [view: follow]",
|
|
1916
|
+
step: "step <\u6BB5\u306E\u984C>",
|
|
1917
|
+
say: "say <\u6BB5\u306E\u672C\u6587>",
|
|
1918
|
+
code: "code <\u547D\u4EE4>",
|
|
1919
|
+
act: "act <\u540D\u672D>: <\u51E6\u7406\u306E\u540D\u524D>",
|
|
1920
|
+
note: "note <\u540D\u672D>: <\u4E0B\u306E\u5C0F\u3055\u306A\u5B57>",
|
|
1921
|
+
set: "set <\u6B04>: <\u5024> [tag: <\u672D>]"
|
|
1922
|
+
};
|
|
1936
1923
|
return {
|
|
1937
|
-
noHead: `\u6700\u521D\u306E\u884C\u306B\u56F3\u306E\u7A2E\u985E (${
|
|
1938
|
-
badHead: `\u6700\u521D\u306E\u884C\u306F ${
|
|
1924
|
+
noHead: `\u6700\u521D\u306E\u884C\u306B\u56F3\u306E\u7A2E\u985E (${list(KINDS)}) \u3068\u984C\u3092\u66F8\u304F`,
|
|
1925
|
+
badHead: `\u6700\u521D\u306E\u884C\u306F ${KINDS.join(" \u304B ")} \u3067\u59CB\u3081\u3001\u7D9A\u3051\u3066\u984C\u3092\u66F8\u304F`,
|
|
1926
|
+
oldForm: (word, shape) => `${word} \u306F\u4ECA\u306E\u5F62\u306E\u66F8\u304D\u65B9\u3002\u65B0\u3057\u3044\u5F62\u3067\u306F ${shapes[shape]} \u3068\u66F8\u304F`,
|
|
1927
|
+
unknownHead: (word) => `${word} \u306F\u884C\u306E\u982D\u306B\u66F8\u3051\u306A\u3044\u3002\u884C\u306F ${list(HEADS)} \u304B\u3001<\u540D\u672D> -> <\u540D\u672D> \u3067\u59CB\u3081\u308B`,
|
|
1939
1928
|
duplicate: (id) => `${id} \u306F\u65E2\u306B\u5BA3\u8A00\u3057\u305F\u540D\u672D`,
|
|
1929
|
+
needsId: (word) => `${word} \u306E\u5F8C\u308D\u306B\u540D\u672D\u3092\u66F8\u304F`,
|
|
1930
|
+
badId: (id) => `${id} \u306F\u540D\u672D\u306B\u4F7F\u3048\u306A\u3044\u3002\u540D\u672D\u306B\u306F\u7A7A\u767D\u3068 [ ] \u300C \u300D = : \u3092\u542B\u3081\u306A\u3044`,
|
|
1931
|
+
afterId: "\u540D\u672D\u306E\u5F8C\u308D\u306B\u306F as <\u540D\u524D> \u304B\u5C5E\u6027\u3092\u66F8\u304F",
|
|
1940
1932
|
undeclaredBox: (id) => `${id} \u3068\u3044\u3046\u7BB1\u306F\u5BA3\u8A00\u3057\u3066\u3044\u306A\u3044`,
|
|
1941
|
-
noBody: (title) => `\u6BB5\u300C${title}\u300D\u306B\u672C\u6587 (
|
|
1942
|
-
emptyStepTitle: "\
|
|
1933
|
+
noBody: (title) => `\u6BB5\u300C${title}\u300D\u306B\u672C\u6587 (say \u306E\u884C) \u304C\u8981\u308B`,
|
|
1934
|
+
emptyStepTitle: "step \u306E\u5F8C\u308D\u306B\u6BB5\u306E\u984C\u3092\u66F8\u304F",
|
|
1943
1935
|
noBoxes: "\u7BB1\u3092 1 \u3064\u4EE5\u4E0A\u5BA3\u8A00\u3059\u308B",
|
|
1944
|
-
noSteps: "\u6BB5 (
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1936
|
+
noSteps: "\u6BB5 (step \u306E\u884C) \u3092 1 \u3064\u4EE5\u4E0A\u66F8\u304F",
|
|
1937
|
+
emptySay: "say \u306E\u5F8C\u308D\u304B\u3001\u305D\u306E\u4E0B\u306B\u5B57\u4E0B\u3052\u3057\u305F\u884C\u306B\u6BB5\u306E\u672C\u6587\u3092\u66F8\u304F",
|
|
1938
|
+
sayTwice: "1 \u3064\u306E\u6BB5\u306B say \u306F 1 \u3064\u307E\u3067\u3002\u9577\u3044\u672C\u6587\u306F say \u306E\u4E0B\u306B\u5B57\u4E0B\u3052\u3057\u3066\u7D9A\u3051\u308B",
|
|
1939
|
+
codeTwice: "1 \u3064\u306E\u6BB5\u306B code \u306F 1 \u884C\u307E\u3067",
|
|
1940
|
+
emptyCode: "code \u306E\u5F8C\u308D\u306B\u547D\u4EE4\u3092\u66F8\u304F",
|
|
1941
|
+
declarationInStep: "group \u3068 box \u3068 strip \u306F\u6700\u521D\u306E step \u3088\u308A\u524D\u306B\u66F8\u304F",
|
|
1942
|
+
stepLineBeforeStep: "\u7DDA\u3068 say \u3068 code \u3068 act \u3068 note \u3068 set \u306F step \u306E\u4E0B\u306B\u66F8\u304F",
|
|
1943
|
+
nestedGroup: "group \u306E\u4E2D\u306B group \u306F\u66F8\u3051\u306A\u3044\u3002\u5148\u306B end \u3067\u9589\u3058\u308B",
|
|
1944
|
+
strayEnd: "end \u306E\u524D\u306B\u3001\u9589\u3058\u308B group \u304C\u7121\u3044",
|
|
1945
|
+
endTakesNothing: "end \u306E\u5F8C\u308D\u306B\u306F\u4F55\u3082\u66F8\u304B\u306A\u3044",
|
|
1946
|
+
unclosedGroup: (id) => `group ${id} \u3092 end \u3067\u9589\u3058\u3066\u3044\u306A\u3044`,
|
|
1947
|
+
regionReopened: (id) => `group ${id} \u306F\u5BA3\u8A00\u6E08\u307F\u3002\u3082\u3046\u4E00\u5EA6\u958B\u304F\u6642\u306F group ${id} \u3060\u3051\u3092\u66F8\u304D\u3001\u540D\u524D\u3068\u5C5E\u6027\u306F\u6700\u521D\u306E\u5BA3\u8A00\u306B\u66F8\u304F`,
|
|
1951
1948
|
emptyName: (id) => `${id} \u306E\u540D\u524D\u304C\u7A7A`,
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1949
|
+
stripTwice: "strip \u306F 1 \u3064\u3060\u3051\u5BA3\u8A00\u3059\u308B",
|
|
1950
|
+
stripShape: "strip \u306F strip <\u984C>: <\u6B04>, <\u6B04> \u306E\u5F62\u3067\u66F8\u304F",
|
|
1951
|
+
emptyStripField: "strip \u306E\u6B04\u306E\u540D\u524D\u304C\u7A7A",
|
|
1952
|
+
stripUndeclared: "set \u3092\u66F8\u304F\u524D\u306B\u3001strip <\u984C>: <\u6B04>, <\u6B04> \u3067\u5E2F\u3092\u5BA3\u8A00\u3059\u308B",
|
|
1953
|
+
noSuchField: (field2) => `${field2} \u3068\u3044\u3046\u6B04\u306F strip \u306B\u7121\u3044`,
|
|
1954
|
+
stripNeedsValue: "set \u306F set <\u6B04>: <\u5024> \u304B set <\u6B04> [tag: <\u672D>] \u306E\u5F62\u3067\u66F8\u304F",
|
|
1955
|
+
actShape: "act \u306F act <\u540D\u672D>: <\u51E6\u7406\u306E\u540D\u524D> \u306E\u5F62\u3067\u66F8\u304F",
|
|
1956
|
+
noteShape: "note \u306F note <\u540D\u672D>: <\u4E0B\u306E\u5C0F\u3055\u306A\u5B57> \u306E\u5F62\u3067\u66F8\u304F",
|
|
1957
|
+
edgeShape: "\u7DDA\u306F <\u540D\u672D> -> <\u540D\u672D>: <\u7DDA\u306E\u540D\u524D> [<\u5C5E\u6027>] \u306E\u5F62\u3067\u66F8\u304F",
|
|
1958
|
+
emptyLabel: "\u7DDA\u306E : \u306E\u5F8C\u308D\u306B\u7DDA\u306E\u540D\u524D\u3092\u66F8\u304F\u3002\u540D\u524D\u3092\u66F8\u304B\u306A\u3044\u6642\u306F : \u3082\u66F8\u304B\u306A\u3044",
|
|
1959
|
+
quoteUnclosed: '" \u3067\u59CB\u3081\u305F\u5B57\u3092 " \u3067\u9589\u3058\u3066\u3044\u306A\u3044',
|
|
1960
|
+
afterQuote: '" \u3067\u9589\u3058\u305F\u5B57\u306E\u5F8C\u308D\u306B\u306F\u3001\u5C5E\u6027\u304B\u6B21\u306E , \u3060\u3051\u3092\u66F8\u304F',
|
|
1961
|
+
attrUnclosed: "\u5C5E\u6027\u306F [ \u3067\u59CB\u3081\u3066 ] \u3067\u9589\u3058\u3001\u884C\u306E\u7D42\u308F\u308A\u306B\u7F6E\u304F",
|
|
1962
|
+
attrNoColon: (raw) => `[${raw}] \u306F\u66F8\u3051\u306A\u3044\u3002\u5C5E\u6027\u306F [<\u9375>: <\u5024>] \u306E\u5F62\u3067\u66F8\u304F`,
|
|
1963
|
+
attrNoValue: (key2) => `${key2}: \u306E\u5F8C\u308D\u306B\u5024\u3092\u66F8\u304F`,
|
|
1964
|
+
attrTwice: (key2) => `${key2} \u306F 1 \u3064\u306E\u884C\u306B 1 \u3064\u307E\u3067`,
|
|
1965
|
+
badAttr: (key2, allowed) => `${key2} \u306F\u3053\u306E\u884C\u306B\u66F8\u3051\u306A\u3044\u5C5E\u6027\u3002\u66F8\u3051\u308B\u306E\u306F ${list(allowed)}`,
|
|
1966
|
+
badColor: `color \u306F ${list(COLORS)} \u306E\u3069\u308C\u304B`,
|
|
1967
|
+
badView: `view \u306F ${list(VIEWS)} \u306E\u3069\u308C\u304B`,
|
|
1968
|
+
badCarry: `carry \u306F ${list(CARRIES)} \u306E\u3069\u308C\u304B\u3002\u672D\u306F tag: <\u5024> \u3067\u66F8\u304F`,
|
|
1969
|
+
badSide: `side \u306F ${list(SIDES)} \u306E\u3069\u308C\u304B`,
|
|
1970
|
+
carryTwice: "\u904B\u3076\u7269\u306F 1 \u672C\u306E\u7DDA\u306B 1 \u3064\u307E\u3067\u3002carry \u3068 tag \u306F\u4E00\u7DD2\u306B\u66F8\u304B\u306A\u3044"
|
|
1968
1971
|
};
|
|
1969
1972
|
};
|
|
1970
1973
|
var en2 = () => {
|
|
1971
|
-
const
|
|
1974
|
+
const shapes = {
|
|
1975
|
+
sequence: "sequence <title>",
|
|
1976
|
+
architecture: "architecture <title>",
|
|
1977
|
+
group: "group <id> as <name> [note: <note>] through end",
|
|
1978
|
+
box: "box <id> as <name> [note: <caption>]",
|
|
1979
|
+
strip: "strip <title>: <field>, <field>",
|
|
1980
|
+
view: "sequence <title> [view: follow]",
|
|
1981
|
+
step: "step <step title>",
|
|
1982
|
+
say: "say <step body>",
|
|
1983
|
+
code: "code <command>",
|
|
1984
|
+
act: "act <id>: <action>",
|
|
1985
|
+
note: "note <id>: <caption>",
|
|
1986
|
+
set: "set <field>: <value> [tag: <tag>]"
|
|
1987
|
+
};
|
|
1972
1988
|
return {
|
|
1973
|
-
noHead: `Write the diagram kind (${
|
|
1974
|
-
badHead: `Start the first line with ${
|
|
1989
|
+
noHead: `Write the diagram kind (${list(KINDS)}) and a title on the first line`,
|
|
1990
|
+
badHead: `Start the first line with ${KINDS.join(" or ")}, followed by the title`,
|
|
1991
|
+
oldForm: (word, shape) => `${word} is the old notation. Write ${shapes[shape]} instead`,
|
|
1992
|
+
unknownHead: (word) => `A line cannot start with ${word}. Start a line with ${list(HEADS)}, or <id> -> <id>`,
|
|
1975
1993
|
duplicate: (id) => `${id} is already declared`,
|
|
1994
|
+
needsId: (word) => `Write an id after ${word}`,
|
|
1995
|
+
badId: (id) => `${id} cannot be an id. An id has no spaces and none of [ ] \u300C \u300D = :`,
|
|
1996
|
+
afterId: "Write as <name> or attributes after the id",
|
|
1976
1997
|
undeclaredBox: (id) => `No box named ${id} is declared`,
|
|
1977
|
-
noBody: (title) => `Step "${title}" needs a body (a line
|
|
1978
|
-
emptyStepTitle: "Write a title after
|
|
1998
|
+
noBody: (title) => `Step "${title}" needs a body (a say line)`,
|
|
1999
|
+
emptyStepTitle: "Write a title after step",
|
|
1979
2000
|
noBoxes: "Declare at least one box",
|
|
1980
|
-
noSteps: "Write at least one step (a line
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
2001
|
+
noSteps: "Write at least one step (a step line)",
|
|
2002
|
+
emptySay: "Write the step body after say, or on indented lines below it",
|
|
2003
|
+
sayTwice: "A step takes one say. Continue a long body on indented lines below it",
|
|
2004
|
+
codeTwice: "A step takes at most one code line",
|
|
2005
|
+
emptyCode: "Write the command after code",
|
|
2006
|
+
declarationInStep: "Write group, box and strip before the first step",
|
|
2007
|
+
stepLineBeforeStep: "Write lines, say, code, act, note and set under a step",
|
|
2008
|
+
nestedGroup: "A group cannot hold another group. Close it with end first",
|
|
2009
|
+
strayEnd: "There is no group for this end to close",
|
|
2010
|
+
endTakesNothing: "Write nothing after end",
|
|
2011
|
+
unclosedGroup: (id) => `group ${id} is not closed with end`,
|
|
2012
|
+
regionReopened: (id) => `group ${id} is already declared. To open it again, write only group ${id}; put the name and attributes on the first one`,
|
|
1987
2013
|
emptyName: (id) => `${id} has an empty name`,
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2014
|
+
stripTwice: "Declare only one strip",
|
|
2015
|
+
stripShape: "Write a strip as strip <title>: <field>, <field>",
|
|
2016
|
+
emptyStripField: "A strip field name is empty",
|
|
2017
|
+
stripUndeclared: "Declare the strip as strip <title>: <field>, <field> before writing set",
|
|
2018
|
+
noSuchField: (field2) => `The strip has no field named ${field2}`,
|
|
2019
|
+
stripNeedsValue: "Write set as set <field>: <value> or set <field> [tag: <tag>]",
|
|
2020
|
+
actShape: "Write act as act <id>: <action>",
|
|
2021
|
+
noteShape: "Write note as note <id>: <caption>",
|
|
2022
|
+
edgeShape: "Write a line as <id> -> <id>: <label> [<attributes>]",
|
|
2023
|
+
emptyLabel: "Write the label after the : of a line, or leave out the : as well",
|
|
2024
|
+
quoteUnclosed: 'A value that starts with " is not closed with "',
|
|
2025
|
+
afterQuote: 'After a value closed with ", write only attributes or the next ,',
|
|
2026
|
+
attrUnclosed: "Start attributes with [, close them with ], and put them at the end of the line",
|
|
2027
|
+
attrNoColon: (raw) => `[${raw}] cannot be read. Write an attribute as [<key>: <value>]`,
|
|
2028
|
+
attrNoValue: (key2) => `Write a value after ${key2}:`,
|
|
2029
|
+
attrTwice: (key2) => `Write ${key2} only once on a line`,
|
|
2030
|
+
badAttr: (key2, allowed) => `${key2} cannot be written on this line. Write ${list(allowed)}`,
|
|
2031
|
+
badColor: `color is one of ${list(COLORS)}`,
|
|
2032
|
+
badView: `view is one of ${list(VIEWS)}`,
|
|
2033
|
+
badCarry: `carry is one of ${list(CARRIES)}. Write a tag as tag: <value>`,
|
|
2034
|
+
badSide: `side is one of ${list(SIDES)}`,
|
|
2035
|
+
carryTwice: "A line carries one thing. Do not write carry and tag together"
|
|
2004
2036
|
};
|
|
2005
2037
|
};
|
|
2006
2038
|
var MESSAGES = { ja: ja2(), en: en2() };
|
|
2007
2039
|
var messagesFor = (lang) => MESSAGES[lang];
|
|
2008
2040
|
|
|
2009
2041
|
// src/tokenize.ts
|
|
2042
|
+
var isBlankOrComment = (source) => source.text === "" || source.text.startsWith("//");
|
|
2010
2043
|
function columnOf(source, index) {
|
|
2011
2044
|
return source.column + Array.from(source.text.slice(0, index)).length;
|
|
2012
2045
|
}
|
|
2013
2046
|
function tokenize(notation) {
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
if (text2 === "" || text2.startsWith("//")) return;
|
|
2018
|
-
const lead = raw.length - raw.trimStart().length;
|
|
2019
|
-
lines.push({ line: index + 1, column: Array.from(raw.slice(0, lead)).length + 1, text: text2 });
|
|
2047
|
+
return notation.split(/\r?\n/).map((raw, index) => {
|
|
2048
|
+
const indent = Array.from(raw.slice(0, raw.length - raw.trimStart().length)).length;
|
|
2049
|
+
return { line: index + 1, column: indent + 1, indent, text: raw.trim() };
|
|
2020
2050
|
});
|
|
2021
|
-
return lines;
|
|
2022
2051
|
}
|
|
2023
2052
|
|
|
2024
2053
|
// src/version.ts
|
|
@@ -2058,74 +2087,162 @@ var NotationError = class extends Error {
|
|
|
2058
2087
|
column;
|
|
2059
2088
|
};
|
|
2060
2089
|
var fail = (source, index, message) => new NotationError(source.line, columnOf(source, index), message);
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2090
|
+
var ID = /^[^\s[\]「」=:]+$/u;
|
|
2091
|
+
var EDGE = /^([^\s:[\]]+?)\s*->\s*([^\s:[\]]+)/du;
|
|
2092
|
+
var isOneOf = (list2, word) => list2.includes(word);
|
|
2093
|
+
function skipSpaces(text2, at) {
|
|
2094
|
+
let i = at;
|
|
2095
|
+
while (i < text2.length && /\s/u.test(text2[i] ?? "")) i++;
|
|
2096
|
+
return i;
|
|
2097
|
+
}
|
|
2098
|
+
function readQuoted(source, at, m) {
|
|
2099
|
+
const text2 = source.text;
|
|
2100
|
+
let value2 = "";
|
|
2101
|
+
for (let i = at + 1; i < text2.length; i++) {
|
|
2102
|
+
const c = text2[i] ?? "";
|
|
2103
|
+
const next = text2[i + 1] ?? "";
|
|
2104
|
+
if (c === "\\" && (next === '"' || next === "\\")) {
|
|
2105
|
+
value2 += next;
|
|
2106
|
+
i++;
|
|
2107
|
+
} else if (c === '"') {
|
|
2108
|
+
return { value: value2, end: i + 1 };
|
|
2109
|
+
} else {
|
|
2110
|
+
value2 += c;
|
|
2111
|
+
}
|
|
2071
2112
|
}
|
|
2072
|
-
|
|
2113
|
+
throw fail(source, at, m.quoteUnclosed);
|
|
2073
2114
|
}
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
};
|
|
2082
|
-
function nameAndNote(text2, lang) {
|
|
2083
|
-
for (const [open, close] of QUOTES[lang]) {
|
|
2084
|
-
const found = new RegExp(`^(.*?)\\s*${escape2(open)}(.*)${escape2(close)}$`).exec(text2);
|
|
2085
|
-
if (found) return { name: (found[1] ?? "").trim(), note: found[2] ?? "" };
|
|
2115
|
+
function readName(source, at, m) {
|
|
2116
|
+
const text2 = source.text;
|
|
2117
|
+
const start = skipSpaces(text2, at);
|
|
2118
|
+
if (text2[start] === '"') {
|
|
2119
|
+
const quoted = readQuoted(source, start, m);
|
|
2120
|
+
const rest2 = skipSpaces(text2, quoted.end);
|
|
2121
|
+
if (rest2 < text2.length && text2[rest2] !== "[") throw fail(source, rest2, m.afterQuote);
|
|
2122
|
+
return { value: quoted.value, rest: rest2 };
|
|
2086
2123
|
}
|
|
2087
|
-
|
|
2124
|
+
const open = text2.indexOf("[", start);
|
|
2125
|
+
const rest = open < 0 ? text2.length : open;
|
|
2126
|
+
return { value: text2.slice(start, rest).trim(), rest };
|
|
2088
2127
|
}
|
|
2089
|
-
function
|
|
2090
|
-
const
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2128
|
+
function readAttrs(source, at, allowed, m) {
|
|
2129
|
+
const text2 = source.text;
|
|
2130
|
+
if (!text2.endsWith("]")) throw fail(source, at, m.attrUnclosed);
|
|
2131
|
+
const close = text2.length - 1;
|
|
2132
|
+
const attrs2 = /* @__PURE__ */ new Map();
|
|
2133
|
+
for (let i = at + 1; ; ) {
|
|
2134
|
+
const start = skipSpaces(text2, i);
|
|
2135
|
+
let colon = start;
|
|
2136
|
+
while (colon < close && text2[colon] !== ":" && text2[colon] !== ",") colon++;
|
|
2137
|
+
if (colon >= close || text2[colon] !== ":") throw fail(source, start, m.attrNoColon(text2.slice(start, colon).trim()));
|
|
2138
|
+
const key2 = text2.slice(start, colon).trim();
|
|
2139
|
+
if (!allowed.includes(key2)) throw fail(source, start, m.badAttr(key2, allowed));
|
|
2140
|
+
if (attrs2.has(key2)) throw fail(source, start, m.attrTwice(key2));
|
|
2141
|
+
let end = skipSpaces(text2, colon + 1);
|
|
2142
|
+
let value2;
|
|
2143
|
+
if (text2[end] === '"') {
|
|
2144
|
+
const quoted = readQuoted(source, end, m);
|
|
2145
|
+
value2 = quoted.value;
|
|
2146
|
+
end = skipSpaces(text2, quoted.end);
|
|
2147
|
+
if (end < close && text2[end] !== ",") throw fail(source, end, m.afterQuote);
|
|
2148
|
+
} else {
|
|
2149
|
+
const comma = text2.indexOf(",", end);
|
|
2150
|
+
const stop = comma < 0 || comma > close ? close : comma;
|
|
2151
|
+
value2 = text2.slice(end, stop).trim();
|
|
2152
|
+
end = stop;
|
|
2153
|
+
}
|
|
2154
|
+
if (value2 === "") throw fail(source, start, m.attrNoValue(key2));
|
|
2155
|
+
attrs2.set(key2, { value: value2, at: start });
|
|
2156
|
+
if (end >= close) return attrs2;
|
|
2157
|
+
i = end + 1;
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
function readList(source, at, m) {
|
|
2161
|
+
const text2 = source.text;
|
|
2162
|
+
const items = [];
|
|
2163
|
+
for (let i = at; ; ) {
|
|
2164
|
+
const start = skipSpaces(text2, i);
|
|
2165
|
+
let value2;
|
|
2166
|
+
let end;
|
|
2167
|
+
if (text2[start] === '"') {
|
|
2168
|
+
const quoted = readQuoted(source, start, m);
|
|
2169
|
+
value2 = quoted.value;
|
|
2170
|
+
end = skipSpaces(text2, quoted.end);
|
|
2171
|
+
if (end < text2.length && text2[end] !== ",") throw fail(source, end, m.afterQuote);
|
|
2172
|
+
} else {
|
|
2173
|
+
const comma = text2.indexOf(",", start);
|
|
2174
|
+
end = comma < 0 ? text2.length : comma;
|
|
2175
|
+
value2 = text2.slice(start, end).trim();
|
|
2176
|
+
}
|
|
2177
|
+
if (value2 === "") throw fail(source, start, m.emptyStripField);
|
|
2178
|
+
items.push(value2);
|
|
2179
|
+
if (end >= text2.length) return items;
|
|
2180
|
+
i = end + 1;
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
function readDeclared(source, word, allowed, m) {
|
|
2184
|
+
const text2 = source.text;
|
|
2185
|
+
const start = skipSpaces(text2, word.length);
|
|
2186
|
+
const id = /^[^\s[]+/u.exec(text2.slice(start))?.[0];
|
|
2187
|
+
if (id === void 0) throw fail(source, 0, m.needsId(word));
|
|
2188
|
+
if (!ID.test(id)) throw fail(source, start, m.badId(id));
|
|
2189
|
+
let rest = skipSpaces(text2, start + id.length);
|
|
2190
|
+
let name2;
|
|
2191
|
+
if (text2.startsWith(AS, rest) && /^(\s|$)/u.test(text2.slice(rest + AS.length, rest + AS.length + 1))) {
|
|
2192
|
+
const named = readName(source, rest + AS.length, m);
|
|
2193
|
+
if (named.value === "") throw fail(source, rest, m.emptyName(id));
|
|
2194
|
+
name2 = named.value;
|
|
2195
|
+
rest = named.rest;
|
|
2094
2196
|
}
|
|
2095
|
-
|
|
2197
|
+
if (rest < text2.length && text2[rest] !== "[") throw fail(source, rest, m.afterId);
|
|
2198
|
+
const attrs2 = rest < text2.length ? readAttrs(source, rest, allowed, m) : /* @__PURE__ */ new Map();
|
|
2199
|
+
return { id, idAt: start, ...name2 !== void 0 ? { name: name2 } : {}, attrs: attrs2 };
|
|
2096
2200
|
}
|
|
2097
|
-
function
|
|
2098
|
-
const
|
|
2099
|
-
|
|
2201
|
+
function lookOf(source, attrs2, m) {
|
|
2202
|
+
const color = attrs2.get("color");
|
|
2203
|
+
if (color && !isOneOf(COLORS, color.value)) throw fail(source, color.at, m.badColor);
|
|
2204
|
+
const note = attrs2.get("note")?.value;
|
|
2205
|
+
const icon = attrs2.get("icon")?.value;
|
|
2100
2206
|
return {
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
// 空白を全部読んでから次の字を見る (`\s` を外すと、空白 2 つの `帯 -> 受け手` を帯の値と読む)
|
|
2105
|
-
stripValue: new RegExp(`^${head("strip")}\\s+(?!\\s|->|:|=${opens})`)
|
|
2207
|
+
...note !== void 0 ? { note } : {},
|
|
2208
|
+
...color ? { color: color.value } : {},
|
|
2209
|
+
...icon !== void 0 ? { icon } : {}
|
|
2106
2210
|
};
|
|
2107
2211
|
}
|
|
2108
|
-
function
|
|
2109
|
-
const [
|
|
2110
|
-
if (
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
if (
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
const
|
|
2212
|
+
function oldForm(text2, inStep) {
|
|
2213
|
+
const first = text2.split(/\s/u)[0] ?? "";
|
|
2214
|
+
if (first === "\u5E2F") return { word: first, shape: inStep ? "set" : "strip" };
|
|
2215
|
+
if (Object.hasOwn(OLD_HEADS, first)) return { word: first, shape: OLD_HEADS[first] };
|
|
2216
|
+
if (text2.startsWith("#")) return { word: "#", shape: "step" };
|
|
2217
|
+
if (text2.startsWith(">")) return { word: ">", shape: "say" };
|
|
2218
|
+
if (text2.startsWith("`")) return { word: "`", shape: "code" };
|
|
2219
|
+
if (text2.includes("\u300C")) return { word: "\u300C\u300D", shape: inStep ? "note" : "box" };
|
|
2220
|
+
if (/^[^\s=:]+\s*=(?!>)/u.test(text2)) return { word: "=", shape: "box" };
|
|
2221
|
+
if (inStep && /^[^\s:]+\s*:/u.test(text2)) return { word: ":", shape: "act" };
|
|
2222
|
+
return void 0;
|
|
2223
|
+
}
|
|
2224
|
+
function parseLines(lines, m) {
|
|
2225
|
+
const headAt = lines.findIndex((source) => !isBlankOrComment(source));
|
|
2226
|
+
const head = lines[headAt];
|
|
2227
|
+
if (!head) throw new NotationError(1, 1, m.noHead);
|
|
2228
|
+
const kind = head.text.split(/\s/u)[0] ?? "";
|
|
2229
|
+
if (!isOneOf(KINDS, kind)) {
|
|
2230
|
+
const old = oldForm(head.text, false);
|
|
2231
|
+
throw fail(head, 0, old ? m.oldForm(old.word, old.shape) : m.badHead);
|
|
2232
|
+
}
|
|
2233
|
+
const titled = readName(head, kind.length, m);
|
|
2234
|
+
if (titled.value === "") throw fail(head, 0, m.badHead);
|
|
2235
|
+
const title = titled.value;
|
|
2236
|
+
const shown2 = titled.rest < head.text.length ? readAttrs(head, titled.rest, ATTRS.diagram, m).get("view") : void 0;
|
|
2237
|
+
if (shown2 && !isOneOf(VIEWS, shown2.value)) throw fail(head, shown2.at, m.badView);
|
|
2238
|
+
const view = shown2?.value;
|
|
2122
2239
|
const regions = [];
|
|
2123
2240
|
const boxes = [];
|
|
2124
2241
|
const ids = /* @__PURE__ */ new Set();
|
|
2125
2242
|
let strip2;
|
|
2126
|
-
let view;
|
|
2127
2243
|
const steps = [];
|
|
2128
2244
|
let building;
|
|
2245
|
+
let group;
|
|
2129
2246
|
const declare = (source, id, at) => {
|
|
2130
2247
|
if (ids.has(id)) throw fail(source, at, m.duplicate(id));
|
|
2131
2248
|
ids.add(id);
|
|
@@ -2134,9 +2251,16 @@ function parseLines(lines, fallback) {
|
|
|
2134
2251
|
if (!boxes.some((box) => box.id === id)) throw fail(source, at, m.undeclaredBox(id));
|
|
2135
2252
|
return id;
|
|
2136
2253
|
};
|
|
2254
|
+
const inStep = (source) => {
|
|
2255
|
+
if (!building) throw fail(source, 0, m.stepLineBeforeStep);
|
|
2256
|
+
return building;
|
|
2257
|
+
};
|
|
2258
|
+
const beforeSteps = (source) => {
|
|
2259
|
+
if (building) throw fail(source, 0, m.declarationInStep);
|
|
2260
|
+
};
|
|
2137
2261
|
const finish = () => {
|
|
2138
2262
|
if (!building) return;
|
|
2139
|
-
if (building.body
|
|
2263
|
+
if (building.body === void 0) throw fail(building.source, 0, m.noBody(building.title));
|
|
2140
2264
|
steps.push({
|
|
2141
2265
|
title: building.title,
|
|
2142
2266
|
body: building.body.join("\n"),
|
|
@@ -2144,21 +2268,73 @@ function parseLines(lines, fallback) {
|
|
|
2144
2268
|
events: building.events
|
|
2145
2269
|
});
|
|
2146
2270
|
};
|
|
2147
|
-
|
|
2271
|
+
const rest = lines.slice(headAt + 1);
|
|
2272
|
+
for (let i = 0; i < rest.length; i++) {
|
|
2273
|
+
const source = rest[i];
|
|
2274
|
+
if (!source || isBlankOrComment(source)) continue;
|
|
2148
2275
|
const text2 = source.text;
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
if (stepTitle === "") throw fail(source, 0, m.emptyStepTitle);
|
|
2153
|
-
building = { source, title: stepTitle, body: [], events: [] };
|
|
2276
|
+
const edge2 = EDGE.exec(text2);
|
|
2277
|
+
if (edge2) {
|
|
2278
|
+
inStep(source).events.push(readEdge(source, edge2));
|
|
2154
2279
|
continue;
|
|
2155
2280
|
}
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2281
|
+
const word = text2.split(/\s/u)[0] ?? "";
|
|
2282
|
+
if (!isOneOf(HEADS, word)) {
|
|
2283
|
+
const old = oldForm(text2, building !== void 0);
|
|
2284
|
+
throw fail(source, 0, old ? m.oldForm(old.word, old.shape) : m.unknownHead(word));
|
|
2285
|
+
}
|
|
2286
|
+
switch (word) {
|
|
2287
|
+
case "group":
|
|
2288
|
+
readGroup(source);
|
|
2289
|
+
break;
|
|
2290
|
+
case "end":
|
|
2291
|
+
if (text2 !== word) throw fail(source, word.length, m.endTakesNothing);
|
|
2292
|
+
if (!group) throw fail(source, 0, m.strayEnd);
|
|
2293
|
+
group = void 0;
|
|
2294
|
+
break;
|
|
2295
|
+
case "box":
|
|
2296
|
+
readBox(source);
|
|
2297
|
+
break;
|
|
2298
|
+
case "strip":
|
|
2299
|
+
readStrip(source);
|
|
2300
|
+
break;
|
|
2301
|
+
case "step": {
|
|
2302
|
+
if (group) throw fail(group.source, 0, m.unclosedGroup(group.id));
|
|
2303
|
+
finish();
|
|
2304
|
+
const stepTitle = text2.slice(word.length).trim();
|
|
2305
|
+
if (stepTitle === "") throw fail(source, 0, m.emptyStepTitle);
|
|
2306
|
+
building = { source, title: stepTitle, events: [] };
|
|
2307
|
+
break;
|
|
2308
|
+
}
|
|
2309
|
+
case "say":
|
|
2310
|
+
i = readSay(source, i);
|
|
2311
|
+
break;
|
|
2312
|
+
case "code": {
|
|
2313
|
+
const step = inStep(source);
|
|
2314
|
+
if (step.code !== void 0) throw fail(source, 0, m.codeTwice);
|
|
2315
|
+
const command = text2.slice(word.length).trim();
|
|
2316
|
+
if (command === "") throw fail(source, 0, m.emptyCode);
|
|
2317
|
+
step.code = command;
|
|
2318
|
+
break;
|
|
2319
|
+
}
|
|
2320
|
+
case "act": {
|
|
2321
|
+
const step = inStep(source);
|
|
2322
|
+
const on = readOnBox(source, word, m.actShape);
|
|
2323
|
+
step.events.push({ type: "action", box: on.box, label: on.text });
|
|
2324
|
+
break;
|
|
2325
|
+
}
|
|
2326
|
+
case "note": {
|
|
2327
|
+
const step = inStep(source);
|
|
2328
|
+
const on = readOnBox(source, word, m.noteShape);
|
|
2329
|
+
step.events.push({ type: "swap", box: on.box, text: on.text });
|
|
2330
|
+
break;
|
|
2331
|
+
}
|
|
2332
|
+
case "set":
|
|
2333
|
+
inStep(source).events.push(readSet(source));
|
|
2334
|
+
break;
|
|
2159
2335
|
}
|
|
2160
|
-
building.events.push(...parseStepLine(source, building));
|
|
2161
2336
|
}
|
|
2337
|
+
if (group) throw fail(group.source, 0, m.unclosedGroup(group.id));
|
|
2162
2338
|
finish();
|
|
2163
2339
|
if (boxes.length === 0) throw fail(head, 0, m.noBoxes);
|
|
2164
2340
|
if (steps.length === 0) throw fail(head, 0, m.noSteps);
|
|
@@ -2173,168 +2349,148 @@ function parseLines(lines, fallback) {
|
|
|
2173
2349
|
steps,
|
|
2174
2350
|
...kind === "sequence" ? { sequence: { lifelines: boxes.map((box) => box.id) } } : {}
|
|
2175
2351
|
};
|
|
2176
|
-
function
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
if (valueOf("view", word, other) !== void 0) throw foreignWord(source, at, "view", word);
|
|
2186
|
-
throw fail(source, at, m.badView);
|
|
2187
|
-
}
|
|
2188
|
-
view = chosen;
|
|
2189
|
-
return;
|
|
2190
|
-
}
|
|
2191
|
-
const stripDecl = own.strip.exec(text2);
|
|
2192
|
-
if (stripDecl) {
|
|
2193
|
-
if (strip2) throw fail(source, 0, m.stripTwice);
|
|
2194
|
-
const fields = (stripDecl[2] ?? "").split(",").map((field) => field.trim());
|
|
2195
|
-
if (fields.some((field) => field === "")) throw fail(source, 0, m.emptyStripField);
|
|
2196
|
-
strip2 = { title: stripDecl[1] ?? "", fields };
|
|
2197
|
-
return;
|
|
2198
|
-
}
|
|
2199
|
-
const regionDecl = own.region.exec(text2);
|
|
2200
|
-
const boxDecl = regionDecl ? void 0 : /^([^\s=]+)\s*=(?!>)\s*/d.exec(text2);
|
|
2201
|
-
const decl = regionDecl ?? boxDecl;
|
|
2202
|
-
if (!decl?.indices?.[1]) {
|
|
2203
|
-
if (foreign.view.test(text2) || foreign.strip.test(text2) || foreign.region.test(text2)) {
|
|
2204
|
-
throw foreignWord(source, 0, "head", text2.split(/\s+/)[0] ?? "");
|
|
2205
|
-
}
|
|
2206
|
-
if (looksLikeStepLine(text2, lang)) throw fail(source, 0, m.stepLineBeforeStep);
|
|
2207
|
-
throw fail(source, 0, m.unreadableDeclaration);
|
|
2208
|
-
}
|
|
2209
|
-
const id = decl[1] ?? "";
|
|
2210
|
-
declare(source, id, decl.indices[1][0]);
|
|
2211
|
-
const { end, attrs } = trailingAttrs(source, decl[0].length);
|
|
2212
|
-
const { name, note } = nameAndNote(text2.slice(decl[0].length, end), lang);
|
|
2213
|
-
if (name === "") throw fail(source, decl[0].length, m.emptyName(id));
|
|
2214
|
-
const look = {};
|
|
2215
|
-
for (const attr of attrs) {
|
|
2216
|
-
const key = valueOf("attr", attr.key, lang);
|
|
2217
|
-
if (key === "color") {
|
|
2218
|
-
if (!COLORS.includes(attr.value)) throw fail(source, attr.at, m.badColor);
|
|
2219
|
-
look.color = attr.value;
|
|
2220
|
-
} else if (key === "icon" && attr.value !== "") {
|
|
2221
|
-
look.icon = attr.value;
|
|
2222
|
-
} else if (key === "region" && !regionDecl) {
|
|
2223
|
-
if (!regions.some((region) => region.id === attr.value)) throw fail(source, attr.at, m.regionFirst(attr.value));
|
|
2224
|
-
look.region = attr.value;
|
|
2225
|
-
} else {
|
|
2226
|
-
if (valueOf("attr", attr.key, other) !== void 0) throw foreignWord(source, attr.at, "attr", attr.key);
|
|
2227
|
-
throw fail(source, attr.at, m.badAttr(attr.raw));
|
|
2228
|
-
}
|
|
2229
|
-
}
|
|
2230
|
-
if (regionDecl) {
|
|
2231
|
-
regions.push({
|
|
2232
|
-
id,
|
|
2233
|
-
name,
|
|
2234
|
-
...note !== void 0 ? { note } : {},
|
|
2235
|
-
...look.color ? { color: look.color } : {},
|
|
2236
|
-
...look.icon ? { icon: look.icon } : {}
|
|
2237
|
-
});
|
|
2238
|
-
return;
|
|
2352
|
+
function readGroup(source) {
|
|
2353
|
+
beforeSteps(source);
|
|
2354
|
+
if (group) throw fail(source, 0, m.nestedGroup);
|
|
2355
|
+
const declared = readDeclared(source, "group", ATTRS.group, m);
|
|
2356
|
+
if (regions.some((region) => region.id === declared.id)) {
|
|
2357
|
+
if (declared.name !== void 0 || declared.attrs.size > 0) throw fail(source, 0, m.regionReopened(declared.id));
|
|
2358
|
+
} else {
|
|
2359
|
+
declare(source, declared.id, declared.idAt);
|
|
2360
|
+
regions.push({ id: declared.id, name: declared.name ?? declared.id, ...lookOf(source, declared.attrs, m) });
|
|
2239
2361
|
}
|
|
2362
|
+
group = { source, id: declared.id };
|
|
2363
|
+
}
|
|
2364
|
+
function readBox(source) {
|
|
2365
|
+
beforeSteps(source);
|
|
2366
|
+
const declared = readDeclared(source, "box", ATTRS.box, m);
|
|
2367
|
+
declare(source, declared.id, declared.idAt);
|
|
2368
|
+
const { note, ...look } = lookOf(source, declared.attrs, m);
|
|
2240
2369
|
boxes.push({
|
|
2241
|
-
id,
|
|
2242
|
-
name,
|
|
2370
|
+
id: declared.id,
|
|
2371
|
+
name: declared.name ?? declared.id,
|
|
2243
2372
|
...note !== void 0 ? { sub: note } : {},
|
|
2244
|
-
...look
|
|
2245
|
-
...
|
|
2246
|
-
...look.region ? { region: look.region } : {}
|
|
2373
|
+
...look,
|
|
2374
|
+
...group ? { region: group.id } : {}
|
|
2247
2375
|
});
|
|
2248
2376
|
}
|
|
2249
|
-
function
|
|
2377
|
+
function readStrip(source) {
|
|
2378
|
+
beforeSteps(source);
|
|
2379
|
+
if (strip2) throw fail(source, 0, m.stripTwice);
|
|
2250
2380
|
const text2 = source.text;
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
if (own.stripValue.test(text2)) return [parseStripValue(source)];
|
|
2262
|
-
if (foreign.stripValue.test(text2)) throw foreignWord(source, 0, "head", text2.split(/\s+/)[0] ?? "");
|
|
2263
|
-
if (text2.includes("->")) return [parseEdge(source)];
|
|
2264
|
-
if (/^[^\s=]+\s*=(?!>)/.test(text2)) throw fail(source, 0, m.declarationInStep);
|
|
2265
|
-
const swap = swapLine(text2, lang);
|
|
2266
|
-
if (swap?.indices?.[1]) {
|
|
2267
|
-
const box = boxAt(source, swap[1] ?? "", swap.indices[1][0]);
|
|
2268
|
-
if ((swap[2] ?? "") === "") throw fail(source, swap.indices[1][1], m.emptySwap);
|
|
2269
|
-
return [{ type: "swap", box, text: swap[2] ?? "" }];
|
|
2381
|
+
const start = skipSpaces(text2, "strip".length);
|
|
2382
|
+
let stripTitle;
|
|
2383
|
+
let colon;
|
|
2384
|
+
if (text2[start] === '"') {
|
|
2385
|
+
const quoted = readQuoted(source, start, m);
|
|
2386
|
+
stripTitle = quoted.value;
|
|
2387
|
+
colon = skipSpaces(text2, quoted.end);
|
|
2388
|
+
} else {
|
|
2389
|
+
colon = text2.indexOf(":", start);
|
|
2390
|
+
stripTitle = colon < 0 ? "" : text2.slice(start, colon).trim();
|
|
2270
2391
|
}
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
throw fail(source, 0, m.unreadableStepLine);
|
|
2392
|
+
if (stripTitle === "" || text2[colon] !== ":") throw fail(source, 0, m.stripShape);
|
|
2393
|
+
strip2 = { title: stripTitle, fields: readList(source, colon + 1, m) };
|
|
2274
2394
|
}
|
|
2275
|
-
function
|
|
2276
|
-
const
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
const
|
|
2280
|
-
|
|
2281
|
-
let
|
|
2282
|
-
let
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
if (kind2 === "tag") {
|
|
2289
|
-
if (attr.value === "") throw fail(source, attr.at, m.tagNeedsValue);
|
|
2290
|
-
carry = { kind: kind2, text: attr.value };
|
|
2291
|
-
} else {
|
|
2292
|
-
if (attr.value !== "") throw fail(source, attr.at, m.carryTakesNoValue(attr.key));
|
|
2293
|
-
carry = { kind: kind2 };
|
|
2294
|
-
}
|
|
2295
|
-
} else if (label2 && valueOf("side", attr.value, lang) !== void 0) {
|
|
2296
|
-
labelSide = valueOf("side", attr.value, lang);
|
|
2297
|
-
} else {
|
|
2298
|
-
if (label2 && valueOf("side", attr.value, other) !== void 0) throw foreignWord(source, attr.at, "side", attr.value);
|
|
2299
|
-
if (valueOf("carry", attr.key, other) !== void 0) throw foreignWord(source, attr.at, "carry", attr.key);
|
|
2300
|
-
if (valueOf("attr", attr.key, other) !== void 0) throw foreignWord(source, attr.at, "attr", attr.key);
|
|
2301
|
-
throw fail(source, attr.at, m.badAttr(attr.raw));
|
|
2395
|
+
function readSay(source, index) {
|
|
2396
|
+
const step = inStep(source);
|
|
2397
|
+
if (step.body !== void 0) throw fail(source, 0, m.sayTwice);
|
|
2398
|
+
const inline = source.text.slice("say".length).trim();
|
|
2399
|
+
const body = inline === "" ? [] : [inline];
|
|
2400
|
+
let blanks = 0;
|
|
2401
|
+
let last = index;
|
|
2402
|
+
for (let j = index + 1; j < rest.length; j++) {
|
|
2403
|
+
const next = rest[j];
|
|
2404
|
+
if (!next) break;
|
|
2405
|
+
if (next.text === "") {
|
|
2406
|
+
blanks++;
|
|
2407
|
+
continue;
|
|
2302
2408
|
}
|
|
2409
|
+
if (next.indent <= source.indent) break;
|
|
2410
|
+
body.push(...Array.from({ length: blanks }, () => ""), next.text);
|
|
2411
|
+
blanks = 0;
|
|
2412
|
+
last = j;
|
|
2303
2413
|
}
|
|
2414
|
+
if (body.length === 0) throw fail(source, 0, m.emptySay);
|
|
2415
|
+
step.body = body;
|
|
2416
|
+
return last;
|
|
2417
|
+
}
|
|
2418
|
+
function readOnBox(source, word, shape) {
|
|
2419
|
+
const found = new RegExp(`^${word}\\s+([^\\s:]+)\\s*:\\s*(.*)$`, "du").exec(source.text);
|
|
2420
|
+
const idAt = found?.indices?.[1]?.[0];
|
|
2421
|
+
if (!found || idAt === void 0 || (found[2] ?? "") === "") throw fail(source, 0, shape);
|
|
2422
|
+
return { box: boxAt(source, found[1] ?? "", idAt), text: found[2] ?? "" };
|
|
2423
|
+
}
|
|
2424
|
+
function readEdge(source, edge2) {
|
|
2425
|
+
const text2 = source.text;
|
|
2426
|
+
const from = boxAt(source, edge2[1] ?? "", edge2.indices?.[1]?.[0] ?? 0);
|
|
2427
|
+
const to = boxAt(source, edge2[2] ?? "", edge2.indices?.[2]?.[0] ?? 0);
|
|
2428
|
+
let at = skipSpaces(text2, edge2[0].length);
|
|
2429
|
+
let label2;
|
|
2430
|
+
if (text2[at] === ":") {
|
|
2431
|
+
const named = readName(source, at + 1, m);
|
|
2432
|
+
if (named.value === "") throw fail(source, at, m.emptyLabel);
|
|
2433
|
+
label2 = named.value;
|
|
2434
|
+
at = named.rest;
|
|
2435
|
+
}
|
|
2436
|
+
if (at < text2.length && text2[at] !== "[") throw fail(source, at, m.edgeShape);
|
|
2437
|
+
const attrs2 = at < text2.length ? readAttrs(source, at, ATTRS.edge, m) : /* @__PURE__ */ new Map();
|
|
2438
|
+
const tag = attrs2.get("tag");
|
|
2439
|
+
const carried = attrs2.get("carry");
|
|
2440
|
+
if (tag && carried) throw fail(source, Math.max(tag.at, carried.at), m.carryTwice);
|
|
2441
|
+
if (carried && !isOneOf(CARRIES, carried.value)) throw fail(source, carried.at, m.badCarry);
|
|
2442
|
+
const side = attrs2.get("side");
|
|
2443
|
+
if (side && !isOneOf(SIDES, side.value)) throw fail(source, side.at, m.badSide);
|
|
2444
|
+
let carry = { kind: "envelope" };
|
|
2445
|
+
if (tag) carry = { kind: "tag", text: tag.value };
|
|
2446
|
+
else if (carried) carry = carried.value === "coin" ? { kind: "coin" } : { kind: "none" };
|
|
2304
2447
|
return {
|
|
2305
2448
|
type: "edge",
|
|
2306
2449
|
from,
|
|
2307
2450
|
to,
|
|
2308
|
-
...
|
|
2309
|
-
carry
|
|
2310
|
-
...
|
|
2451
|
+
...label2 !== void 0 ? { label: label2 } : {},
|
|
2452
|
+
carry,
|
|
2453
|
+
...side ? { labelSide: side.value } : {}
|
|
2311
2454
|
};
|
|
2312
2455
|
}
|
|
2313
|
-
function
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
const
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2456
|
+
function readSet(source) {
|
|
2457
|
+
const declared = strip2;
|
|
2458
|
+
if (!declared) throw fail(source, 0, m.stripUndeclared);
|
|
2459
|
+
const text2 = source.text;
|
|
2460
|
+
const start = skipSpaces(text2, "set".length);
|
|
2461
|
+
let field2;
|
|
2462
|
+
let at;
|
|
2463
|
+
if (text2[start] === '"') {
|
|
2464
|
+
const quoted = readQuoted(source, start, m);
|
|
2465
|
+
field2 = quoted.value;
|
|
2466
|
+
at = skipSpaces(text2, quoted.end);
|
|
2467
|
+
} else {
|
|
2468
|
+
at = start;
|
|
2469
|
+
while (at < text2.length && text2[at] !== ":" && text2[at] !== "[") at++;
|
|
2470
|
+
field2 = text2.slice(start, at).trim();
|
|
2471
|
+
}
|
|
2472
|
+
if (!declared.fields.includes(field2)) throw fail(source, start, m.noSuchField(field2));
|
|
2473
|
+
let value2;
|
|
2474
|
+
if (text2[at] === ":") {
|
|
2475
|
+
const named = readName(source, at + 1, m);
|
|
2476
|
+
if (named.value === "") throw fail(source, at, m.stripNeedsValue);
|
|
2477
|
+
value2 = named.value;
|
|
2478
|
+
at = named.rest;
|
|
2479
|
+
}
|
|
2480
|
+
if (at < text2.length && text2[at] !== "[") throw fail(source, at, m.stripNeedsValue);
|
|
2481
|
+
const tag = at < text2.length ? readAttrs(source, at, ATTRS.set, m).get("tag")?.value : void 0;
|
|
2482
|
+
if (value2 === void 0 && tag === void 0) throw fail(source, 0, m.stripNeedsValue);
|
|
2324
2483
|
return {
|
|
2325
2484
|
type: "strip",
|
|
2326
|
-
field,
|
|
2327
|
-
...
|
|
2485
|
+
field: field2,
|
|
2486
|
+
...value2 !== void 0 ? { value: value2 } : {},
|
|
2328
2487
|
...tag !== void 0 ? { tag } : {}
|
|
2329
2488
|
};
|
|
2330
2489
|
}
|
|
2331
2490
|
}
|
|
2332
|
-
function looksLikeStepLine(text2, lang) {
|
|
2333
|
-
return text2.startsWith(">") || text2.startsWith("`") || text2.includes("->") || swapLine(text2, lang) !== null;
|
|
2334
|
-
}
|
|
2335
2491
|
function parseNotation(notation, options = {}) {
|
|
2336
2492
|
try {
|
|
2337
|
-
return { ok: true, diagram: parseLines(tokenize(notation), options.lang ?? "ja") };
|
|
2493
|
+
return { ok: true, diagram: parseLines(tokenize(notation), messagesFor(options.lang ?? "ja")) };
|
|
2338
2494
|
} catch (error) {
|
|
2339
2495
|
if (!(error instanceof NotationError)) throw error;
|
|
2340
2496
|
return { ok: false, errors: [{ line: error.line, column: error.column, message: error.message }] };
|
|
@@ -2342,48 +2498,84 @@ function parseNotation(notation, options = {}) {
|
|
|
2342
2498
|
}
|
|
2343
2499
|
|
|
2344
2500
|
// src/printer.ts
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2501
|
+
var quote = (text2) => `"${text2.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
2502
|
+
var name = (text2) => text2.includes("[") || text2.startsWith('"') ? quote(text2) : text2;
|
|
2503
|
+
var key = (text2) => text2.includes(":") || text2.includes("[") || text2.startsWith('"') ? quote(text2) : text2;
|
|
2504
|
+
var field = (text2) => text2.includes(",") || text2.startsWith('"') ? quote(text2) : text2;
|
|
2505
|
+
var value = (text2) => text2.includes(",") || text2.includes("]") || text2.startsWith('"') ? quote(text2) : text2;
|
|
2506
|
+
var attrs = (pairs) => {
|
|
2507
|
+
const written = pairs.filter((pair) => pair[1] !== void 0);
|
|
2508
|
+
return written.length === 0 ? "" : ` [${written.map(([k, v]) => `${k}: ${value(v)}`).join(", ")}]`;
|
|
2509
|
+
};
|
|
2510
|
+
var shown = (id, text2) => text2 === id ? "" : ` as ${name(text2)}`;
|
|
2511
|
+
var declareRegion = (r) => `group ${r.id}${shown(r.id, r.name)}${attrs([
|
|
2512
|
+
["note", r.note],
|
|
2513
|
+
["color", r.color],
|
|
2514
|
+
["icon", r.icon]
|
|
2515
|
+
])}`;
|
|
2516
|
+
var declareBox = (b) => `box ${b.id}${shown(b.id, b.name)}${attrs([
|
|
2517
|
+
["note", b.sub],
|
|
2518
|
+
["color", b.color],
|
|
2519
|
+
["icon", b.icon]
|
|
2520
|
+
])}`;
|
|
2521
|
+
function event(e) {
|
|
2522
|
+
switch (e.type) {
|
|
2523
|
+
case "edge": {
|
|
2524
|
+
const carry = e.carry.kind === "tag" ? [["tag", e.carry.text]] : e.carry.kind === "envelope" ? [] : [["carry", e.carry.kind]];
|
|
2525
|
+
return `${e.from} -> ${e.to}${e.label === void 0 ? "" : `: ${name(e.label)}`}${attrs([...carry, ["side", e.labelSide]])}`;
|
|
2526
|
+
}
|
|
2527
|
+
case "action":
|
|
2528
|
+
return `act ${e.box}: ${e.label}`;
|
|
2529
|
+
case "swap":
|
|
2530
|
+
return `note ${e.box}: ${e.text}`;
|
|
2531
|
+
case "strip":
|
|
2532
|
+
return `set ${key(e.field)}${e.value === void 0 ? "" : `: ${name(e.value)}`}${attrs([["tag", e.tag]])}`;
|
|
2533
|
+
}
|
|
2349
2534
|
}
|
|
2350
|
-
function
|
|
2351
|
-
const
|
|
2352
|
-
const
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
const
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
return `${e.box}${quoted("", e.text, lang)}`;
|
|
2368
|
-
case "strip":
|
|
2369
|
-
return `${wordOf("head", "strip", lang)} ${e.field}${e.value === void 0 ? "" : ` = ${e.value}`}${e.tag === void 0 ? "" : ` [${e.tag}]`}`;
|
|
2535
|
+
function declarations(diagram) {
|
|
2536
|
+
const regions = diagram.regions ?? [];
|
|
2537
|
+
const runs = [];
|
|
2538
|
+
for (const b of diagram.boxes) {
|
|
2539
|
+
const last = runs.at(-1);
|
|
2540
|
+
if (last && last.region === b.region) last.boxes.push(b);
|
|
2541
|
+
else runs.push({ ...b.region !== void 0 ? { region: b.region } : {}, boxes: [b] });
|
|
2542
|
+
}
|
|
2543
|
+
const opened = [...new Set(runs.flatMap((run) => run.region === void 0 ? [] : [run.region]))];
|
|
2544
|
+
const inOrder = opened.length === regions.length && opened.every((id, i) => regions[i]?.id === id);
|
|
2545
|
+
const declared = /* @__PURE__ */ new Set();
|
|
2546
|
+
const blocks = [];
|
|
2547
|
+
if (!inOrder) {
|
|
2548
|
+
for (const r of regions) {
|
|
2549
|
+
blocks.push(`${declareRegion(r)}
|
|
2550
|
+
end`);
|
|
2551
|
+
declared.add(r.id);
|
|
2370
2552
|
}
|
|
2371
|
-
}
|
|
2372
|
-
const
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
(
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2553
|
+
}
|
|
2554
|
+
for (const run of runs) {
|
|
2555
|
+
const lines = run.boxes.map(declareBox);
|
|
2556
|
+
if (run.region === void 0) {
|
|
2557
|
+
blocks.push(lines.join("\n"));
|
|
2558
|
+
continue;
|
|
2559
|
+
}
|
|
2560
|
+
const region = regions.find((r) => r.id === run.region);
|
|
2561
|
+
const open = declared.has(run.region) || !region ? `group ${run.region}` : declareRegion(region);
|
|
2562
|
+
declared.add(run.region);
|
|
2563
|
+
blocks.push([open, ...lines.map((line) => ` ${line}`), "end"].join("\n"));
|
|
2564
|
+
}
|
|
2565
|
+
return blocks;
|
|
2566
|
+
}
|
|
2567
|
+
function printNotation(diagram) {
|
|
2568
|
+
const blocks = [`${diagram.kind} ${name(diagram.title)}${attrs([["view", diagram.view]])}`, ...declarations(diagram)];
|
|
2569
|
+
if (diagram.strip) blocks.push(`strip ${key(diagram.strip.title)}: ${diagram.strip.fields.map(field).join(", ")}`);
|
|
2570
|
+
for (const step of diagram.steps) {
|
|
2571
|
+
const body = step.body.split("\n");
|
|
2572
|
+
const say = body.length === 1 ? [` say ${step.body}`] : [" say", ...body.map((line) => line === "" ? "" : ` ${line}`)];
|
|
2573
|
+
blocks.push(
|
|
2574
|
+
[`step ${step.title}`, ...say, ...step.code === void 0 ? [] : [` code ${step.code}`], ...step.events.map((e) => ` ${event(e)}`)].join("\n")
|
|
2575
|
+
);
|
|
2576
|
+
}
|
|
2577
|
+
return `${blocks.join("\n\n")}
|
|
2578
|
+
`;
|
|
2387
2579
|
}
|
|
2388
2580
|
|
|
2389
2581
|
// src/look/fonts.ts
|
|
@@ -2619,7 +2811,7 @@ function resolvePalette(id) {
|
|
|
2619
2811
|
return found ?? PALETTES[DEFAULT_PALETTE];
|
|
2620
2812
|
}
|
|
2621
2813
|
function paletteVars(palette, theme) {
|
|
2622
|
-
return Object.entries(palette[theme]).map(([
|
|
2814
|
+
return Object.entries(palette[theme]).map(([key2, value2]) => `--${key2}:${value2}`).join(";");
|
|
2623
2815
|
}
|
|
2624
2816
|
var FONT_VARS = `--sans:"${FONTS.sans}";--mono:"${FONTS.mono}"`;
|
|
2625
2817
|
var COLOR_ORDER = ["blue", "amber", "green", "violet", "rose"];
|
|
@@ -2665,8 +2857,16 @@ var LOOK = {
|
|
|
2665
2857
|
stroke: { hair: 1, edge: 1.7, edgeOn: 2.25, arrow: 1.5, flow: 1.3, halo: 7, on: 1.75, glyph: 2, lifeline: 1.2, envelope: 1.5, badgeRing: 1.5 },
|
|
2666
2858
|
shadow: { near: 0.8, far: 4, nearY: 1, farY: 3 },
|
|
2667
2859
|
mini: { w: 168, pad: 8, title: 14, inset: 12, radius: 10 },
|
|
2668
|
-
/**
|
|
2669
|
-
|
|
2860
|
+
/**
|
|
2861
|
+
* 寄って追う見せ方の窓の高さの、幅に対する割合と下限。
|
|
2862
|
+
* `fitMinH` は見える高さに収める時 (#3047) の窓の高さの下限で、これより低い枠では収めずに枠の中で送る。
|
|
2863
|
+
* `narrow` は縦長の全体図を出す枠の幅の下限で、これより狭い枠 (携帯の幅) では全体図を出さずに窓へ幅を渡す (#3055)。
|
|
2864
|
+
* `badgeRoom` は番号の丸が窓から外れる段で窓を寄せ直す時に、丸の周りに空ける幅 (#3046)。
|
|
2865
|
+
* `headRoom` は時系列図の図の頭の箱の下端から、窓に線を見せ始める所までの幅 (#3118)。
|
|
2866
|
+
* `head` は時系列図の窓の上端に貼る頭の列の頭の箱で、アイコンを外した名前と下の字の 2 段 (#3120)。
|
|
2867
|
+
* `pad` は頭の列の上下の余白、`h` は箱の高さ、`nameY` と `subY` は箱の上端から名前と下の字の基準線まで
|
|
2868
|
+
*/
|
|
2869
|
+
follow: { aspect: 0.75, minH: 320, fitMinH: 160, ease: 0.6, narrow: 440, badgeRoom: 8, headRoom: 10, head: { pad: 8, h: 40, nameY: 17, subY: 31 } },
|
|
2670
2870
|
/** 色を混ぜる割合 (%) */
|
|
2671
2871
|
mix: { icon: 14, regionIcon: 16, regionIconEdge: 34, cap: 12, capEdge: 42, badgePast: 14, badgePastEdge: 70, mini: 62, miniBand: 16, miniBandEdge: 36, view: 6 },
|
|
2672
2872
|
/** 字の並びの基準線を、置きたい高さの真ん中からどれだけ下げるか */
|
|
@@ -2674,8 +2874,12 @@ var LOOK = {
|
|
|
2674
2874
|
/** 浮いて出る物が下から上がる長さと、弾んで出る物の始まりの大きさ */
|
|
2675
2875
|
rise: 5,
|
|
2676
2876
|
popFrom: 0.4,
|
|
2677
|
-
/**
|
|
2678
|
-
|
|
2877
|
+
/**
|
|
2878
|
+
* 動きを嫌わない人の頁の部品。
|
|
2879
|
+
* `narrow` は段の本文の帯を横 1 列に並べる帯の中身の幅の下限で、これより狭い帯 (携帯の幅) では題と本文を釦と番号の段の下に置く (#3057、#3069)。
|
|
2880
|
+
* `touch` はその狭い帯で段を送る釦の縦横で、指で押せる大きさにする (#3069)
|
|
2881
|
+
*/
|
|
2882
|
+
player: { gap: 10, radius: 12, button: 36, touch: 44, hidden: 1, focus: 2, narrow: 440 }
|
|
2679
2883
|
};
|
|
2680
2884
|
var MOTION = {
|
|
2681
2885
|
/** 最初の段の前に全体を見せる長さ */
|
|
@@ -2753,7 +2957,7 @@ function textWidth(text2, style) {
|
|
|
2753
2957
|
// src/layout/scene.ts
|
|
2754
2958
|
function edgesOf(diagram) {
|
|
2755
2959
|
return diagram.steps.flatMap(
|
|
2756
|
-
(step, s) => step.events.flatMap((
|
|
2960
|
+
(step, s) => step.events.flatMap((event2, e) => event2.type === "edge" ? [{ step: s, event: e, edge: event2 }] : [])
|
|
2757
2961
|
);
|
|
2758
2962
|
}
|
|
2759
2963
|
function boxColors(diagram) {
|
|
@@ -2776,9 +2980,9 @@ function boxWidth(diagram, id, withActions) {
|
|
|
2776
2980
|
if (!box) return LOOK.box.minW;
|
|
2777
2981
|
const lines = [textWidth(box.name, TYPE.boxName), textWidth(box.sub ?? "", TYPE.boxSub)];
|
|
2778
2982
|
for (const step of diagram.steps) {
|
|
2779
|
-
for (const
|
|
2780
|
-
if (
|
|
2781
|
-
if (withActions &&
|
|
2983
|
+
for (const event2 of step.events) {
|
|
2984
|
+
if (event2.type === "swap" && event2.box === id) lines.push(textWidth(event2.text, TYPE.boxSubStrong));
|
|
2985
|
+
if (withActions && event2.type === "action" && event2.box === id) lines.push(textWidth(event2.label, TYPE.boxSubStrong));
|
|
2782
2986
|
}
|
|
2783
2987
|
}
|
|
2784
2988
|
return Math.max(LOOK.box.minW, Math.max(...lines) + LOOK.box.padX * 2);
|
|
@@ -2847,24 +3051,24 @@ function placeLabel(request, obstacles) {
|
|
|
2847
3051
|
}
|
|
2848
3052
|
return { ...base, step: request.step, event: request.event, text: request.text, family: labelStyle(request.text).family, color: request.color };
|
|
2849
3053
|
}
|
|
2850
|
-
function fieldWidth(diagram,
|
|
2851
|
-
let
|
|
3054
|
+
function fieldWidth(diagram, name2) {
|
|
3055
|
+
let value2 = 0;
|
|
2852
3056
|
let tag = 0;
|
|
2853
3057
|
for (const step of diagram.steps) {
|
|
2854
|
-
for (const
|
|
2855
|
-
if (
|
|
2856
|
-
if (
|
|
2857
|
-
if (
|
|
3058
|
+
for (const event2 of step.events) {
|
|
3059
|
+
if (event2.type !== "strip" || event2.field !== name2) continue;
|
|
3060
|
+
if (event2.value !== void 0) value2 = Math.max(value2, textWidth(event2.value, hasWide(event2.value) ? TYPE.fieldValueJa : TYPE.fieldValue));
|
|
3061
|
+
if (event2.tag !== void 0) tag = Math.max(tag, textWidth(event2.tag, TYPE.tag) + LOOK.strip.tagPadX * 2);
|
|
2858
3062
|
}
|
|
2859
3063
|
}
|
|
2860
|
-
const both =
|
|
2861
|
-
return Math.max(textWidth(
|
|
3064
|
+
const both = value2 + (tag > 0 ? (value2 > 0 ? LOOK.strip.tagGap : 0) + tag : 0);
|
|
3065
|
+
return Math.max(textWidth(name2, TYPE.fieldName), both);
|
|
2862
3066
|
}
|
|
2863
3067
|
function stripNeed(diagram) {
|
|
2864
3068
|
if (!diagram.strip) return 0;
|
|
2865
3069
|
const { titleX, fieldGap, pad: pad2 } = LOOK.strip;
|
|
2866
3070
|
const start = titleX + textWidth(diagram.strip.title, TYPE.stripTitle) + fieldGap;
|
|
2867
|
-
return start + diagram.strip.fields.reduce((sum,
|
|
3071
|
+
return start + diagram.strip.fields.reduce((sum, name2) => sum + fieldWidth(diagram, name2) + fieldGap, 0) - fieldGap + pad2;
|
|
2868
3072
|
}
|
|
2869
3073
|
function layoutStrip(diagram, x, y, width) {
|
|
2870
3074
|
if (!diagram.strip) return void 0;
|
|
@@ -2873,13 +3077,13 @@ function layoutStrip(diagram, x, y, width) {
|
|
|
2873
3077
|
const fields = [];
|
|
2874
3078
|
let cx = start;
|
|
2875
3079
|
let row = 0;
|
|
2876
|
-
for (const
|
|
2877
|
-
const w = fieldWidth(diagram,
|
|
3080
|
+
for (const name2 of diagram.strip.fields) {
|
|
3081
|
+
const w = fieldWidth(diagram, name2);
|
|
2878
3082
|
if (cx > start && cx + w > width - pad2) {
|
|
2879
3083
|
cx = start;
|
|
2880
3084
|
row++;
|
|
2881
3085
|
}
|
|
2882
|
-
fields.push({ name, x: x + cx, y: y + row * line, w });
|
|
3086
|
+
fields.push({ name: name2, x: x + cx, y: y + row * line, w });
|
|
2883
3087
|
cx += w + fieldGap;
|
|
2884
3088
|
}
|
|
2885
3089
|
return { x, y, w: width, h: h + row * line, title: diagram.strip.title, fields };
|
|
@@ -2915,20 +3119,20 @@ function shiftContent(layout, dx, dy) {
|
|
|
2915
3119
|
}
|
|
2916
3120
|
if (layout.strip) {
|
|
2917
3121
|
layout.strip.y += dy;
|
|
2918
|
-
for (const
|
|
2919
|
-
|
|
2920
|
-
|
|
3122
|
+
for (const field2 of layout.strip.fields) {
|
|
3123
|
+
field2.x += dx;
|
|
3124
|
+
field2.y += dy;
|
|
2921
3125
|
}
|
|
2922
3126
|
}
|
|
2923
3127
|
}
|
|
2924
3128
|
function cornerBadge(events, step, layout) {
|
|
2925
3129
|
const { inset } = LOOK.badge;
|
|
2926
|
-
for (const
|
|
2927
|
-
const id =
|
|
3130
|
+
for (const event2 of events) {
|
|
3131
|
+
const id = event2.type === "swap" || event2.type === "action" ? event2.box : void 0;
|
|
2928
3132
|
const box2 = layout.boxes.find((b) => b.id === id);
|
|
2929
3133
|
if (box2) return { step, x: box2.x + inset, y: box2.y + inset, color: box2.color };
|
|
2930
3134
|
}
|
|
2931
|
-
if (layout.strip && events.some((
|
|
3135
|
+
if (layout.strip && events.some((event2) => event2.type === "strip")) return { step, x: layout.strip.x + inset, y: layout.strip.y + inset, color: "slate" };
|
|
2932
3136
|
const box = layout.boxes[0];
|
|
2933
3137
|
return { step, x: box.x + inset, y: box.y + inset, color: box.color };
|
|
2934
3138
|
}
|
|
@@ -3010,11 +3214,11 @@ function placeBoxes(diagram, groups) {
|
|
|
3010
3214
|
for (const slot of slots.values()) slot.col = used.indexOf(slot.col);
|
|
3011
3215
|
return slots;
|
|
3012
3216
|
}
|
|
3013
|
-
function nameLines(
|
|
3014
|
-
const spaces = [...
|
|
3015
|
-
if (spaces.length === 0) return [
|
|
3016
|
-
const at = spaces.reduce((best, i) => Math.abs(i -
|
|
3017
|
-
return [
|
|
3217
|
+
function nameLines(name2) {
|
|
3218
|
+
const spaces = [...name2.matchAll(/ /g)].map((m) => m.index);
|
|
3219
|
+
if (spaces.length === 0) return [name2];
|
|
3220
|
+
const at = spaces.reduce((best, i) => Math.abs(i - name2.length / 2) < Math.abs(best - name2.length / 2) ? i : best);
|
|
3221
|
+
return [name2.slice(0, at), name2.slice(at + 1)];
|
|
3018
3222
|
}
|
|
3019
3223
|
function headerSize(region) {
|
|
3020
3224
|
const { icon, nameY, line, inset } = LOOK.region;
|
|
@@ -3145,11 +3349,11 @@ function arrange(diagram, groups, slots, rooms) {
|
|
|
3145
3349
|
];
|
|
3146
3350
|
return candidates.find((points) => !blocked(points, from, to)) ?? candidates[2];
|
|
3147
3351
|
};
|
|
3148
|
-
const sceneEdges = edges.map(({ step, event, edge: edge2 }) => {
|
|
3352
|
+
const sceneEdges = edges.map(({ step, event: event2, edge: edge2 }) => {
|
|
3149
3353
|
const target = byId.get(edge2.to);
|
|
3150
3354
|
return {
|
|
3151
3355
|
step,
|
|
3152
|
-
event,
|
|
3356
|
+
event: event2,
|
|
3153
3357
|
from: edge2.from,
|
|
3154
3358
|
to: edge2.to,
|
|
3155
3359
|
points: route(edge2.from, edge2.to),
|
|
@@ -3251,11 +3455,11 @@ function layoutSequence(diagram) {
|
|
|
3251
3455
|
const spacing = widths.slice(1).map((w, i) => widths[i] / 2 + w / 2 + Q.columnGap);
|
|
3252
3456
|
const needs = [];
|
|
3253
3457
|
for (const step of diagram.steps) {
|
|
3254
|
-
for (const
|
|
3255
|
-
if (
|
|
3256
|
-
const a = column.get(
|
|
3257
|
-
const b = column.get(
|
|
3258
|
-
const w = textWidth(
|
|
3458
|
+
for (const event2 of step.events) {
|
|
3459
|
+
if (event2.type !== "edge" || event2.label === void 0) continue;
|
|
3460
|
+
const a = column.get(event2.from) ?? 0;
|
|
3461
|
+
const b = column.get(event2.to) ?? 0;
|
|
3462
|
+
const w = textWidth(event2.label, labelStyle(event2.label)) + L.padX * 2;
|
|
3259
3463
|
if (a === b) {
|
|
3260
3464
|
if (a < spacing.length) needs.push({ from: a, to: a + 1, need: Q.selfW + L.side + w + Q.labelRoom });
|
|
3261
3465
|
} else {
|
|
@@ -3299,14 +3503,14 @@ function layoutSequence(diagram) {
|
|
|
3299
3503
|
let below = 0;
|
|
3300
3504
|
let first = true;
|
|
3301
3505
|
diagram.steps.forEach((step, s) => {
|
|
3302
|
-
step.events.forEach((
|
|
3303
|
-
if (
|
|
3506
|
+
step.events.forEach((event2, e) => {
|
|
3507
|
+
if (event2.type !== "edge" && event2.type !== "action") return;
|
|
3304
3508
|
let above;
|
|
3305
3509
|
let under;
|
|
3306
|
-
if (
|
|
3307
|
-
const side =
|
|
3308
|
-
const self =
|
|
3309
|
-
const named =
|
|
3510
|
+
if (event2.type === "edge") {
|
|
3511
|
+
const side = event2.labelSide ?? "above";
|
|
3512
|
+
const self = event2.from === event2.to;
|
|
3513
|
+
const named = event2.label !== void 0;
|
|
3310
3514
|
above = named && side === "above" ? L.offset + L.h / 2 : gap;
|
|
3311
3515
|
under = self ? Q.selfH + gap : named && side === "below" ? L.offset + L.h / 2 : gap;
|
|
3312
3516
|
} else {
|
|
@@ -3316,9 +3520,9 @@ function layoutSequence(diagram) {
|
|
|
3316
3520
|
y = first ? y + above : y + Math.max(Q.minPitch, below + Q.rowGap + above) + (e === 0 && s > 0 ? Q.stepGap : 0);
|
|
3317
3521
|
first = false;
|
|
3318
3522
|
below = under;
|
|
3319
|
-
if (
|
|
3320
|
-
const xf = xs[column.get(
|
|
3321
|
-
const xt = xs[column.get(
|
|
3523
|
+
if (event2.type === "edge") {
|
|
3524
|
+
const xf = xs[column.get(event2.from) ?? 0];
|
|
3525
|
+
const xt = xs[column.get(event2.to) ?? 0];
|
|
3322
3526
|
const dir = Math.sign(xt - xf) || 1;
|
|
3323
3527
|
const points = xf === xt ? [
|
|
3324
3528
|
[xf, y],
|
|
@@ -3329,22 +3533,22 @@ function layoutSequence(diagram) {
|
|
|
3329
3533
|
[xf, y],
|
|
3330
3534
|
[xt - dir * LOOK.edge.inset, y]
|
|
3331
3535
|
];
|
|
3332
|
-
const color = edgeColor(
|
|
3333
|
-
edges.push({ step: s, event: e, from:
|
|
3334
|
-
if (
|
|
3536
|
+
const color = edgeColor(event2, colors);
|
|
3537
|
+
edges.push({ step: s, event: e, from: event2.from, to: event2.to, points, color, carry: event2.carry });
|
|
3538
|
+
if (event2.label !== void 0) {
|
|
3335
3539
|
requests.push({
|
|
3336
3540
|
step: s,
|
|
3337
3541
|
event: e,
|
|
3338
|
-
text:
|
|
3542
|
+
text: event2.label,
|
|
3339
3543
|
points,
|
|
3340
3544
|
color,
|
|
3341
|
-
...
|
|
3545
|
+
...event2.labelSide ? { side: event2.labelSide } : xf === xt ? { side: "right" } : {}
|
|
3342
3546
|
});
|
|
3343
3547
|
}
|
|
3344
3548
|
} else {
|
|
3345
|
-
const x = xs[column.get(
|
|
3346
|
-
const w = textWidth(
|
|
3347
|
-
actions.push({ step: s, event: e, box:
|
|
3549
|
+
const x = xs[column.get(event2.box) ?? 0];
|
|
3550
|
+
const w = textWidth(event2.label, TYPE.action) + LOOK.action.padX * 2;
|
|
3551
|
+
actions.push({ step: s, event: e, box: event2.box, text: event2.label, color: colors.get(event2.box) ?? "slate", x: x + LOOK.badge.r + 4, y: y - LOOK.action.h / 2, w, h: LOOK.action.h });
|
|
3348
3552
|
}
|
|
3349
3553
|
});
|
|
3350
3554
|
});
|
|
@@ -3388,17 +3592,17 @@ function plan(step) {
|
|
|
3388
3592
|
let cursor = MOTION.edgeAt;
|
|
3389
3593
|
let arrived;
|
|
3390
3594
|
let changes = 0;
|
|
3391
|
-
step.events.forEach((
|
|
3392
|
-
if (
|
|
3393
|
-
const carries =
|
|
3595
|
+
step.events.forEach((event2, e) => {
|
|
3596
|
+
if (event2.type === "edge") {
|
|
3597
|
+
const carries = event2.carry.kind !== "none";
|
|
3394
3598
|
const a = cursor;
|
|
3395
3599
|
const b = a + (carries ? MOTION.drawCarry : MOTION.draw);
|
|
3396
|
-
out.edges.push({ event: e, a, b, carries, coin:
|
|
3600
|
+
out.edges.push({ event: e, a, b, carries, coin: event2.carry.kind === "coin", named: event2.label !== void 0 });
|
|
3397
3601
|
cursor = a + MOTION.stagger;
|
|
3398
3602
|
arrived = b;
|
|
3399
3603
|
changes = 0;
|
|
3400
3604
|
out.busy = Math.max(out.busy, b);
|
|
3401
|
-
} else if (
|
|
3605
|
+
} else if (event2.type === "action") {
|
|
3402
3606
|
out.events.push({ event: e, at: cursor });
|
|
3403
3607
|
out.busy = Math.max(out.busy, cursor + MOTION.action);
|
|
3404
3608
|
cursor += MOTION.action;
|
|
@@ -3442,15 +3646,15 @@ function buildTimeline(diagram) {
|
|
|
3442
3646
|
if (later) label2.end = Math.min(label2.end, later.start);
|
|
3443
3647
|
});
|
|
3444
3648
|
labels.push(...named);
|
|
3445
|
-
for (const
|
|
3649
|
+
for (const event2 of p.events) events.push({ step: s, event: event2.event, at: span.start + event2.at });
|
|
3446
3650
|
});
|
|
3447
3651
|
const first = steps[0]?.start ?? 0;
|
|
3448
3652
|
const hasMain = departures.some((d) => d.who === "main");
|
|
3449
3653
|
const carriers = [];
|
|
3450
3654
|
for (const who of ["main", "coin"]) {
|
|
3451
|
-
const
|
|
3452
|
-
|
|
3453
|
-
const next =
|
|
3655
|
+
const list2 = departures.filter((d) => d.who === who);
|
|
3656
|
+
list2.forEach((d, k) => {
|
|
3657
|
+
const next = list2[k + 1];
|
|
3454
3658
|
const waits = k === 0 && (who === "main" || !hasMain);
|
|
3455
3659
|
carriers.push({
|
|
3456
3660
|
step: d.step,
|
|
@@ -3519,8 +3723,8 @@ var ICONS = {
|
|
|
3519
3723
|
var esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3520
3724
|
var r1 = (v) => Math.round(v * 100) / 100;
|
|
3521
3725
|
var cs = (k) => k === "coin" ? "--c:var(--coin);--ct:var(--coint)" : `--c:var(--c-${k});--ct:var(--t-${k})`;
|
|
3522
|
-
function glyph(
|
|
3523
|
-
const d =
|
|
3726
|
+
function glyph(name2, x, y, scale, cls = "dg-gl") {
|
|
3727
|
+
const d = name2 === void 0 ? void 0 : ICONS[name2];
|
|
3524
3728
|
return d ? `<path class="${cls}" transform="translate(${r1(x)} ${r1(y)}) scale(${scale})" d="${d}"/>` : "";
|
|
3525
3729
|
}
|
|
3526
3730
|
var pathOf = (points) => points.map(([x, y], i) => `${i === 0 ? "M" : "L"} ${r1(x)} ${r1(y)}`).join(" ");
|
|
@@ -3557,20 +3761,31 @@ function band(region) {
|
|
|
3557
3761
|
const mark = region.icon && ICONS[region.icon] ? `<rect class="dg-bi" x="${r1(x)}" y="${r1(y)}" width="${icon}" height="${icon}" rx="${iconRadius}"/>${glyph(region.icon, x + icon / 2, y + icon / 2, iconScale)}` : "";
|
|
3558
3762
|
return `<g style="${cs(region.color)}"><rect class="dg-band" x="${r1(region.x + 0.5)}" y="${r1(region.y + 0.5)}" width="${r1(region.w - 1)}" height="${r1(region.h - 1)}" rx="${radius}"/>${mark}${lines}${note}</g>`;
|
|
3559
3763
|
}
|
|
3560
|
-
function
|
|
3561
|
-
const { m, sh } = ctx;
|
|
3562
|
-
const { radius, icon, iconRadius, iconScale, iconY, nameY, subY } = LOOK.box;
|
|
3764
|
+
function subLines(box, m, changes, y) {
|
|
3563
3765
|
const seq = [[0, box.sub ?? "", "dg-ss"], ...changes];
|
|
3564
|
-
|
|
3766
|
+
return seq.map(([t, text2, cls], k) => {
|
|
3565
3767
|
const next = seq[k + 1]?.[0];
|
|
3566
3768
|
const anim = k === 0 ? next === void 0 ? "" : m.until(next - MOTION.untilFade) : next === void 0 ? m.rise(t) : m.rise(t, next - MOTION.untilFade);
|
|
3567
3769
|
if (text2 === "") return "";
|
|
3568
|
-
return `<g${anim ? ` class="dg-a" style="${anim}"` : ""}><text class="${cls}" x="${r1(box.cx)}" y="${r1(
|
|
3770
|
+
return `<g${anim ? ` class="dg-a" style="${anim}"` : ""}><text class="${cls}" x="${r1(box.cx)}" y="${r1(y)}" text-anchor="middle">${esc(text2)}</text></g>`;
|
|
3569
3771
|
}).join("");
|
|
3772
|
+
}
|
|
3773
|
+
function cardFrame(box, ctx, act, y, h) {
|
|
3774
|
+
const rect = (cls, extra = "") => `<rect class="${cls}" x="${r1(box.x)}" y="${r1(y)}" width="${r1(box.w)}" height="${h}" rx="${LOOK.box.radius}"${extra}/>`;
|
|
3775
|
+
return `${act ? `<g class="dg-a" style="${act}">${rect("dg-halo")}</g>` : ""}${rect("dg-st", ` ${ctx.sh}`)}${act ? `<g class="dg-a" style="${act}">${rect("dg-on")}</g>` : ""}`;
|
|
3776
|
+
}
|
|
3777
|
+
function card(box, ctx, on, changes) {
|
|
3778
|
+
const { icon, iconRadius, iconScale, iconY, nameY, subY } = LOOK.box;
|
|
3779
|
+
const subs = subLines(box, ctx.m, changes, box.cy + subY);
|
|
3570
3780
|
const act = on.length > 0 ? activeKf(ctx, on) : void 0;
|
|
3571
|
-
const rect = (cls, extra = "") => `<rect class="${cls}" x="${r1(box.x)}" y="${r1(box.y)}" width="${r1(box.w)}" height="${box.h}" rx="${radius}"${extra}/>`;
|
|
3572
3781
|
const mark = box.icon && ICONS[box.icon] ? `<rect class="dg-ic" x="${r1(box.cx - icon / 2)}" y="${r1(box.cy + iconY - icon / 2)}" width="${icon}" height="${icon}" rx="${iconRadius}"/>${glyph(box.icon, box.cx, box.cy + iconY, iconScale)}` : "";
|
|
3573
|
-
return `<g style="${cs(box.color)}">${
|
|
3782
|
+
return `<g style="${cs(box.color)}">${cardFrame(box, ctx, act, box.y, box.h)}${mark}<text class="dg-sn" x="${r1(box.cx)}" y="${r1(box.cy + nameY)}" text-anchor="middle">${esc(box.name)}</text>${subs}</g>`;
|
|
3783
|
+
}
|
|
3784
|
+
function headCard(box, ctx, on, changes) {
|
|
3785
|
+
const { pad: pad2, h, nameY, subY } = LOOK.follow.head;
|
|
3786
|
+
const subs = subLines(box, ctx.m, changes, pad2 + subY);
|
|
3787
|
+
const act = on.length > 0 ? activeKf(ctx, on) : void 0;
|
|
3788
|
+
return `<g style="${cs(box.color)}">${cardFrame(box, ctx, act, pad2, h)}<text class="dg-sn" x="${r1(box.cx)}" y="${r1(pad2 + nameY)}" text-anchor="middle">${esc(box.name)}</text>${subs}</g>`;
|
|
3574
3789
|
}
|
|
3575
3790
|
function lifeline(x, y1, y2) {
|
|
3576
3791
|
return `<line class="dg-ll" x1="${r1(x)}" y1="${r1(y1)}" x2="${r1(x)}" y2="${r1(y2)}"/>`;
|
|
@@ -3688,29 +3903,29 @@ function strip(s, changes, ctx) {
|
|
|
3688
3903
|
`<g style="${cs("slate")}"><rect class="dg-bi" x="${r1(s.x + S2.pad)}" y="${r1(my - S2.icon / 2)}" width="${S2.icon}" height="${S2.icon}" rx="${LOOK.box.iconRadius}"/>${glyph("env", s.x + S2.pad + S2.icon / 2, my, 0.78)}</g>`,
|
|
3689
3904
|
`<text class="dg-sh" x="${r1(s.x + S2.titleX)}" y="${r1(my + LOOK.baseline.stripTitle)}">${esc(s.title)}</text>`
|
|
3690
3905
|
];
|
|
3691
|
-
s.fields.forEach((
|
|
3906
|
+
s.fields.forEach((field2, i) => {
|
|
3692
3907
|
const prev = s.fields[i - 1];
|
|
3693
|
-
if (prev && prev.y ===
|
|
3694
|
-
const sx =
|
|
3695
|
-
parts.push(`<line class="dg-sep" x1="${r1(sx)}" y1="${r1(
|
|
3908
|
+
if (prev && prev.y === field2.y) {
|
|
3909
|
+
const sx = field2.x - S2.fieldGap / 2;
|
|
3910
|
+
parts.push(`<line class="dg-sep" x1="${r1(sx)}" y1="${r1(field2.y + S2.sepInset)}" x2="${r1(sx)}" y2="${r1(field2.y + S2.h - S2.sepInset)}"/>`);
|
|
3696
3911
|
}
|
|
3697
|
-
parts.push(`<text class="dg-fl" x="${r1(
|
|
3698
|
-
const
|
|
3699
|
-
const values =
|
|
3700
|
-
const tags =
|
|
3912
|
+
parts.push(`<text class="dg-fl" x="${r1(field2.x)}" y="${r1(field2.y + S2.nameY)}">${esc(field2.name)}</text>`);
|
|
3913
|
+
const list2 = changes.get(field2.name) ?? [];
|
|
3914
|
+
const values = list2.filter((c) => c.value !== void 0);
|
|
3915
|
+
const tags = list2.filter((c) => c.tag !== void 0);
|
|
3701
3916
|
values.forEach((c, k) => {
|
|
3702
3917
|
const next = values[k + 1]?.at;
|
|
3703
|
-
const
|
|
3918
|
+
const value2 = c.value;
|
|
3704
3919
|
const anim = next === void 0 ? m.rise(c.at) : m.rise(c.at, next - MOTION.untilFade);
|
|
3705
|
-
parts.push(`<g class="dg-a" style="${anim}"><text class="${hasWide(
|
|
3920
|
+
parts.push(`<g class="dg-a" style="${anim}"><text class="${hasWide(value2) ? "dg-fvj" : "dg-fv"}" x="${r1(field2.x)}" y="${r1(field2.y + S2.valueY)}">${esc(value2)}</text></g>`);
|
|
3706
3921
|
});
|
|
3707
3922
|
tags.forEach((c, k) => {
|
|
3708
3923
|
const next = tags[k + 1]?.at;
|
|
3709
3924
|
const tag = c.tag;
|
|
3710
|
-
const
|
|
3711
|
-
const x =
|
|
3925
|
+
const shown2 = [...values].reverse().find((v) => v.at <= c.at + 1e-9)?.value;
|
|
3926
|
+
const x = field2.x + (shown2 ? textWidth(shown2, hasWide(shown2) ? TYPE.fieldValueJa : TYPE.fieldValue) + S2.tagGap : 0);
|
|
3712
3927
|
const w = textWidth(tag, TYPE.tag) + S2.tagPadX * 2;
|
|
3713
|
-
const y =
|
|
3928
|
+
const y = field2.y + S2.valueY - S2.tagH / 2 - LOOK.baseline.tag;
|
|
3714
3929
|
parts.push(
|
|
3715
3930
|
`<g class="dg-tg dg-popc dg-a" style="${cs(c.color)};${next === void 0 ? m.pop(c.at) : m.pop(c.at, next - MOTION.untilFade)}"><rect x="${r1(x)}" y="${r1(y)}" width="${r1(w)}" height="${S2.tagH}" rx="${S2.tagH / 2}"/><text x="${r1(x + w / 2)}" y="${r1(y + S2.tagH / 2 + LOOK.baseline.tag)}" text-anchor="middle">${esc(tag)}</text></g>`
|
|
3716
3931
|
);
|
|
@@ -3737,7 +3952,7 @@ var Motion = class {
|
|
|
3737
3952
|
}
|
|
3738
3953
|
/** keyframes を 1 つ足し、その名前を付ける style の字を返す。 */
|
|
3739
3954
|
kf(points) {
|
|
3740
|
-
const
|
|
3955
|
+
const name2 = `${this.prefix}-${this.count++}`;
|
|
3741
3956
|
const at = /* @__PURE__ */ new Map();
|
|
3742
3957
|
for (const [t, props, ease] of [...points].sort((a, b) => a[0] - b[0])) {
|
|
3743
3958
|
const p = this.pct(t);
|
|
@@ -3751,8 +3966,8 @@ var Motion = class {
|
|
|
3751
3966
|
if (ease) d.push(`animation-timing-function:${ease}`);
|
|
3752
3967
|
return `${p}%{${d.join(";")}}`;
|
|
3753
3968
|
}).join("");
|
|
3754
|
-
this.frames.push(`@keyframes ${
|
|
3755
|
-
return `animation-name:${
|
|
3969
|
+
this.frames.push(`@keyframes ${name2}{${body}}`);
|
|
3970
|
+
return `animation-name:${name2}`;
|
|
3756
3971
|
}
|
|
3757
3972
|
/** `a` で出て `b` から消える。`within` を立てると `b` までに消え終わる。 */
|
|
3758
3973
|
vis(a, b = this.last, o = {}) {
|
|
@@ -3863,6 +4078,7 @@ var PART_CSS = [
|
|
|
3863
4078
|
`.dg-tg text{${font(TYPE.tag)};fill:var(--on-c)}`,
|
|
3864
4079
|
".dg-vp-bg{fill:var(--bg)}",
|
|
3865
4080
|
".dg-vp-frame{fill:none;stroke:var(--hair)}",
|
|
4081
|
+
".dg-hd-bg{fill:var(--bg)}",
|
|
3866
4082
|
".dg-mm-bg{fill:var(--surf);stroke:var(--hair)}",
|
|
3867
4083
|
`.dg-mm-t{${font(TYPE.miniTitle)};fill:var(--mute)}`,
|
|
3868
4084
|
".dg-mm-world{fill:var(--sunk);stroke:var(--hair)}",
|
|
@@ -3884,11 +4100,11 @@ function involved(diagram) {
|
|
|
3884
4100
|
on.set(id, (on.get(id) ?? /* @__PURE__ */ new Set()).add(s));
|
|
3885
4101
|
};
|
|
3886
4102
|
diagram.steps.forEach((step, s) => {
|
|
3887
|
-
for (const
|
|
3888
|
-
if (
|
|
3889
|
-
add(
|
|
3890
|
-
add(
|
|
3891
|
-
} else if (
|
|
4103
|
+
for (const event2 of step.events) {
|
|
4104
|
+
if (event2.type === "edge") {
|
|
4105
|
+
add(event2.from, s);
|
|
4106
|
+
add(event2.to, s);
|
|
4107
|
+
} else if (event2.type === "action" || event2.type === "swap") add(event2.box, s);
|
|
3892
4108
|
}
|
|
3893
4109
|
});
|
|
3894
4110
|
return new Map([...on].map(([id, steps]) => [id, [...steps].sort((a, b) => a - b)]));
|
|
@@ -3897,11 +4113,11 @@ function subChanges(diagram, timeline, actionsInBox) {
|
|
|
3897
4113
|
const raw = [];
|
|
3898
4114
|
let order = 0;
|
|
3899
4115
|
for (const time of timeline.events) {
|
|
3900
|
-
const
|
|
3901
|
-
if (
|
|
3902
|
-
if (actionsInBox &&
|
|
3903
|
-
raw.push({ t: time.at, order: order++, box:
|
|
3904
|
-
raw.push({ t: timeline.steps[time.step].end, order: order++, box:
|
|
4116
|
+
const event2 = diagram.steps[time.step]?.events[time.event];
|
|
4117
|
+
if (event2?.type === "swap") raw.push({ t: time.at, order: order++, box: event2.box, set: event2.text });
|
|
4118
|
+
if (actionsInBox && event2?.type === "action") {
|
|
4119
|
+
raw.push({ t: time.at, order: order++, box: event2.box, act: event2.label });
|
|
4120
|
+
raw.push({ t: timeline.steps[time.step].end, order: order++, box: event2.box, act: null });
|
|
3905
4121
|
}
|
|
3906
4122
|
}
|
|
3907
4123
|
raw.sort((a, b) => a.t - b.t || a.order - b.order);
|
|
@@ -3909,8 +4125,8 @@ function subChanges(diagram, timeline, actionsInBox) {
|
|
|
3909
4125
|
for (const box of diagram.boxes) {
|
|
3910
4126
|
let base = [box.sub ?? "", "dg-ss"];
|
|
3911
4127
|
let acting;
|
|
3912
|
-
let
|
|
3913
|
-
const
|
|
4128
|
+
let shown2 = base.join("|");
|
|
4129
|
+
const list2 = [];
|
|
3914
4130
|
for (const change of raw.filter((r) => r.box === box.id)) {
|
|
3915
4131
|
if (change.set !== void 0) {
|
|
3916
4132
|
base = [change.set, "dg-ss-ok"];
|
|
@@ -3918,12 +4134,12 @@ function subChanges(diagram, timeline, actionsInBox) {
|
|
|
3918
4134
|
}
|
|
3919
4135
|
if (change.act !== void 0) acting = change.act ?? void 0;
|
|
3920
4136
|
const now = acting !== void 0 ? [acting, "dg-ss-act"] : base;
|
|
3921
|
-
if (now.join("|") ===
|
|
3922
|
-
|
|
3923
|
-
|
|
4137
|
+
if (now.join("|") === shown2) continue;
|
|
4138
|
+
shown2 = now.join("|");
|
|
4139
|
+
list2.push([change.t, now[0], now[1]]);
|
|
3924
4140
|
}
|
|
3925
|
-
const kept =
|
|
3926
|
-
const next =
|
|
4141
|
+
const kept = list2.filter((change, k) => {
|
|
4142
|
+
const next = list2[k + 1];
|
|
3927
4143
|
return next === void 0 || next[0] - change[0] >= MOTION.minShow;
|
|
3928
4144
|
});
|
|
3929
4145
|
out.set(box.id, kept);
|
|
@@ -3933,12 +4149,12 @@ function subChanges(diagram, timeline, actionsInBox) {
|
|
|
3933
4149
|
function fieldChanges(diagram, timeline, layout) {
|
|
3934
4150
|
const out = /* @__PURE__ */ new Map();
|
|
3935
4151
|
for (const time of timeline.events) {
|
|
3936
|
-
const
|
|
3937
|
-
if (
|
|
4152
|
+
const event2 = diagram.steps[time.step]?.events[time.event];
|
|
4153
|
+
if (event2?.type !== "strip") continue;
|
|
3938
4154
|
const color = layout.badges[time.step]?.color ?? "slate";
|
|
3939
|
-
const
|
|
3940
|
-
|
|
3941
|
-
out.set(
|
|
4155
|
+
const list2 = out.get(event2.field) ?? [];
|
|
4156
|
+
list2.push({ at: time.at, color, ...event2.value !== void 0 ? { value: event2.value } : {}, ...event2.tag !== void 0 ? { tag: event2.tag } : {} });
|
|
4157
|
+
out.set(event2.field, list2);
|
|
3942
4158
|
}
|
|
3943
4159
|
return out;
|
|
3944
4160
|
}
|
|
@@ -3976,43 +4192,84 @@ function drawSvg(diagram, layout, timeline, palette, theme, follow) {
|
|
|
3976
4192
|
const content = Object.values(L).map((parts) => parts.join("")).join("");
|
|
3977
4193
|
const { near, far, nearY, farY } = LOOK.shadow;
|
|
3978
4194
|
const shadow = `<filter id="dg-sh-${id}" x="-20%" y="-30%" width="140%" height="180%"><feDropShadow dx="0" dy="${nearY}" stdDeviation="${near}" style="flood-color:var(--sh);flood-opacity:var(--shA)"/><feDropShadow dx="0" dy="${farY}" stdDeviation="${far}" style="flood-color:var(--sh);flood-opacity:var(--shB)"/></filter>`;
|
|
3979
|
-
const
|
|
4195
|
+
const heads = follow && layout.kind === "sequence" ? layout.boxes.map((box) => headCard(box, ctx, on.get(box.id) ?? [], subs.get(box.id) ?? [])).join("") : "";
|
|
4196
|
+
const view = follow ? followView(layout, timeline, diagram, m, id, content, follow, heads) : { body: `<rect class="dg-bg" width="${layout.width}" height="${layout.height}" rx="${LOOK.region.radius}"/>${content}`, w: layout.width, h: layout.height };
|
|
3980
4197
|
const css = `.dg-${id}{${FONT_VARS};--T:${timeline.total}s;${paletteVars(palette, theme)}}${PART_CSS}${m.frames.join("")}`;
|
|
3981
4198
|
return `<svg xmlns="http://www.w3.org/2000/svg" class="dg dg-${id}" viewBox="0 0 ${Math.ceil(view.w)} ${Math.ceil(view.h)}" width="${Math.ceil(view.w)}" height="${Math.ceil(view.h)}" role="img" aria-label="${esc(diagram.title)}" data-dragon="figure" data-view="${follow ? "follow" : "fixed"}"><style>${css}</style><defs>${shadow}</defs>${view.body}</svg>`;
|
|
3982
4199
|
}
|
|
4200
|
+
function union(rects) {
|
|
4201
|
+
const x = Math.min(...rects.map((r) => r.x));
|
|
4202
|
+
const y = Math.min(...rects.map((r) => r.y));
|
|
4203
|
+
return { x, y, w: Math.max(...rects.map((r) => r.x + r.w)) - x, h: Math.max(...rects.map((r) => r.y + r.h)) - y };
|
|
4204
|
+
}
|
|
3983
4205
|
function focusOf(layout, diagram, step) {
|
|
4206
|
+
const rects = focusParts(layout, diagram, step);
|
|
4207
|
+
return rects.length === 0 ? void 0 : union(rects);
|
|
4208
|
+
}
|
|
4209
|
+
function badgeFocus(badge2, parts, vw, vh) {
|
|
4210
|
+
const room = LOOK.badge.r + LOOK.follow.badgeRoom;
|
|
4211
|
+
const { x: bx, y: by } = badge2;
|
|
4212
|
+
const away = (p) => Math.hypot(Math.max(0, p.x - bx, bx - p.x - p.w), Math.max(0, p.y - by, by - p.y - p.h));
|
|
4213
|
+
let held = { x: bx - room, y: by - room, w: room * 2, h: room * 2 };
|
|
4214
|
+
for (const p of [...parts].sort((a, b) => away(a) - away(b))) {
|
|
4215
|
+
const next = union([held, p]);
|
|
4216
|
+
if (next.w <= vw && next.h <= vh) held = next;
|
|
4217
|
+
}
|
|
4218
|
+
return held;
|
|
4219
|
+
}
|
|
4220
|
+
function focusParts(layout, diagram, step) {
|
|
3984
4221
|
const rects = [];
|
|
3985
|
-
for (const e of layout.edges.filter((
|
|
4222
|
+
for (const e of layout.edges.filter((x) => x.step === step)) {
|
|
3986
4223
|
const xs = e.points.map((p) => p[0]);
|
|
3987
4224
|
const ys = e.points.map((p) => p[1]);
|
|
3988
4225
|
rects.push({ x: Math.min(...xs), y: Math.min(...ys), w: Math.max(...xs) - Math.min(...xs), h: Math.max(...ys) - Math.min(...ys) });
|
|
3989
4226
|
}
|
|
3990
4227
|
rects.push(...layout.labels.filter((l) => l.step === step), ...layout.actions.filter((a) => a.step === step));
|
|
3991
|
-
for (const
|
|
3992
|
-
const ids =
|
|
4228
|
+
for (const event2 of diagram.steps[step]?.events ?? []) {
|
|
4229
|
+
const ids = event2.type === "edge" ? [event2.from, event2.to] : event2.type === "action" || event2.type === "swap" ? [event2.box] : [];
|
|
3993
4230
|
for (const id of ids) {
|
|
3994
4231
|
const box = layout.boxes.find((b) => b.id === id);
|
|
3995
|
-
if (box && (layout.kind === "architecture" ||
|
|
4232
|
+
if (box && (layout.kind === "architecture" || event2.type === "swap")) rects.push(box);
|
|
3996
4233
|
}
|
|
3997
4234
|
}
|
|
3998
|
-
|
|
3999
|
-
const x = Math.min(...rects.map((r) => r.x));
|
|
4000
|
-
const y = Math.min(...rects.map((r) => r.y));
|
|
4001
|
-
return { x, y, w: Math.max(...rects.map((r) => r.x + r.w)) - x, h: Math.max(...rects.map((r) => r.y + r.h)) - y };
|
|
4235
|
+
return rects;
|
|
4002
4236
|
}
|
|
4003
|
-
function followView(layout, timeline, diagram, m, id, content, follow) {
|
|
4237
|
+
function followView(layout, timeline, diagram, m, id, content, follow, heads) {
|
|
4004
4238
|
const F = LOOK.follow;
|
|
4005
4239
|
const M = LOOK.mini;
|
|
4006
|
-
const
|
|
4007
|
-
const
|
|
4240
|
+
const frameWidth = Math.max(1, follow.width);
|
|
4241
|
+
const full = Math.min(layout.width, frameWidth);
|
|
4242
|
+
const title = FIGURE_TEXT[follow.lang].overview;
|
|
4243
|
+
const sized = (vh2) => {
|
|
4244
|
+
const mw2 = Math.min(M.w, full * 0.4, vh2 * 0.4 / layout.height * layout.width);
|
|
4245
|
+
const k2 = mw2 / layout.width;
|
|
4246
|
+
const mh2 = layout.height * k2;
|
|
4247
|
+
const bw2 = Math.max(mw2, Math.ceil(textWidth(title, TYPE.miniTitle)));
|
|
4248
|
+
return { vh: vh2, mw: mw2, k: k2, mh: mh2, bw: bw2, bgW: bw2 + M.pad * 2, bgH: mh2 + M.pad * 2 + M.title, beside: mh2 > mw2 };
|
|
4249
|
+
};
|
|
4250
|
+
const natural = sized(Math.min(layout.height, Math.max(F.minH, full * F.aspect)));
|
|
4251
|
+
const bare = natural.beside && frameWidth < F.narrow;
|
|
4252
|
+
const room = follow.height === void 0 ? Number.POSITIVE_INFINITY : natural.beside ? follow.height : follow.height - natural.bgH - M.inset;
|
|
4253
|
+
const { vh, mw, k, mh, bw, bgW, bgH, beside } = room < natural.vh ? sized(Math.max(F.fitMinH, room)) : { ...natural, vh: Number.isFinite(room) ? Math.min(layout.height, room) : natural.vh };
|
|
4254
|
+
const vw = beside && !bare ? Math.min(layout.width, frameWidth - bgW - M.inset) : full;
|
|
4008
4255
|
const clampX = (x) => Math.min(layout.width - vw / 2, Math.max(vw / 2, x));
|
|
4009
|
-
const
|
|
4256
|
+
const top = heads === "" ? 0 : Math.max(...layout.boxes.map((b) => b.y + b.h)) + F.headRoom;
|
|
4257
|
+
const strip2 = heads === "" ? 0 : F.head.pad * 2 + F.head.h;
|
|
4258
|
+
const below = vh - strip2;
|
|
4259
|
+
const clampY = (y) => Math.min(layout.height - below / 2, Math.max(top + below / 2, y));
|
|
4260
|
+
const r = LOOK.badge.r;
|
|
4010
4261
|
let prev = [layout.width / 2, layout.height / 2];
|
|
4011
|
-
const
|
|
4262
|
+
const middles = timeline.steps.map((_, s) => {
|
|
4012
4263
|
const f = focusOf(layout, diagram, s);
|
|
4013
4264
|
prev = f ? [f.x + f.w / 2, f.y + f.h / 2] : prev;
|
|
4265
|
+
const at = [clampX(prev[0]), clampY(prev[1])];
|
|
4266
|
+
const b = layout.badges.find((x) => x.step === s);
|
|
4267
|
+
if (!b || Math.abs(b.x - at[0]) <= vw / 2 - r && Math.abs(b.y - at[1]) <= below / 2 - r) return at;
|
|
4268
|
+
const near = badgeFocus(b, focusParts(layout, diagram, s), vw, below);
|
|
4269
|
+
prev = [near.x + near.w / 2, near.y + near.h / 2];
|
|
4014
4270
|
return [clampX(prev[0]), clampY(prev[1])];
|
|
4015
4271
|
});
|
|
4272
|
+
const centers = middles.map(([x, y]) => [x, y - strip2 / 2]);
|
|
4016
4273
|
const c0 = centers[0];
|
|
4017
4274
|
const cam = [
|
|
4018
4275
|
[0, c0[0], c0[1]],
|
|
@@ -4027,22 +4284,26 @@ function followView(layout, timeline, diagram, m, id, content, follow) {
|
|
|
4027
4284
|
const cl = centers[centers.length - 1];
|
|
4028
4285
|
cam.push([timeline.last, cl[0], cl[1], 1, EASE.inOut], [timeline.total, c0[0], c0[1]]);
|
|
4029
4286
|
const camKf = m.move(cam.map(([t, cx, cy, s, e]) => [t, vw / 2 - cx, vh / 2 - cy, s, e]));
|
|
4030
|
-
const
|
|
4031
|
-
const
|
|
4032
|
-
const
|
|
4033
|
-
const title = FIGURE_TEXT[follow.lang].overview;
|
|
4034
|
-
const bw = Math.max(mw, Math.ceil(textWidth(title, TYPE.miniTitle)));
|
|
4035
|
-
const bx = vw - bw - M.inset - M.pad;
|
|
4287
|
+
const bgX = beside ? vw + M.inset : vw - bgW - M.inset;
|
|
4288
|
+
const bgY = beside ? 0 : vh + M.inset;
|
|
4289
|
+
const bx = bgX + M.pad;
|
|
4036
4290
|
const mx = bx + (bw - mw) / 2;
|
|
4037
|
-
const my =
|
|
4038
|
-
const
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4291
|
+
const my = bgY + M.pad + M.title;
|
|
4292
|
+
const overview = () => {
|
|
4293
|
+
const shapes = [
|
|
4294
|
+
...layout.regions.map((r3) => `<rect class="dg-mm-band" style="${cs(r3.color)}" x="${mx + r3.x * k}" y="${my + r3.y * k}" width="${r3.w * k}" height="${r3.h * k}" rx="3"/>`),
|
|
4295
|
+
...layout.boxes.map((b) => `<rect class="dg-mm-card" style="${cs(b.color)}" x="${mx + b.x * k}" y="${my + b.y * k}" width="${b.w * k}" height="${b.h * k}" rx="1.5"/>`)
|
|
4296
|
+
].join("");
|
|
4297
|
+
const vp = m.move(cam.map(([t, cx, cy, , e]) => [t, mx + (cx - vw / 2) * k, my + (cy - vh / 2) * k, 1, e]));
|
|
4298
|
+
return {
|
|
4299
|
+
clip: `<clipPath id="dg-mm-${id}"><rect x="${mx}" y="${my}" width="${mw}" height="${mh}" rx="4"/></clipPath>`,
|
|
4300
|
+
body: `<rect class="dg-mm-bg" x="${bgX}" y="${bgY}" width="${bgW}" height="${bgH}" rx="${M.radius}"/><text class="dg-mm-t" x="${bx}" y="${my - M.pad + 2}">${title}</text><g clip-path="url(#dg-mm-${id})"><rect class="dg-mm-world" x="${mx}" y="${my}" width="${mw}" height="${mh}"/>${shapes}<rect class="dg-mm-vp dg-a"${strip2 === 0 ? "" : ` y="${strip2 * k}"`} width="${vw * k}" height="${(vh - strip2) * k}" rx="2" style="${vp}"/></g>`
|
|
4301
|
+
};
|
|
4302
|
+
};
|
|
4303
|
+
const mini = bare ? { clip: "", body: "" } : overview();
|
|
4304
|
+
const head = strip2 === 0 ? "" : `<g class="dg-hd"><rect class="dg-hd-bg" width="${vw}" height="${strip2}"/><line class="dg-sep" x1="0" y1="${strip2}" x2="${vw}" y2="${strip2}"/><g class="dg-a" style="${m.move(cam.map(([t, cx, , s, e]) => [t, vw / 2 - cx, 0, s, e]))}">${heads}</g></g>`;
|
|
4305
|
+
const body = `<defs><clipPath id="dg-vp-${id}"><rect width="${vw}" height="${vh}" rx="${LOOK.region.radius}"/></clipPath>${mini.clip}</defs><g clip-path="url(#dg-vp-${id})"><rect class="dg-vp-bg" width="${vw}" height="${vh}"/><g class="dg-a" style="${camKf}">${content}</g>${head}</g><rect class="dg-vp-frame" x="0.5" y="0.5" width="${vw - 1}" height="${vh - 1}" rx="${LOOK.region.radius}"/>${mini.body}`;
|
|
4306
|
+
return { body, w: beside && !bare ? vw + M.inset + bgW : full, h: beside ? vh : bgY + bgH };
|
|
4046
4307
|
}
|
|
4047
4308
|
function renderDiagram(input, options = {}) {
|
|
4048
4309
|
const lang = options.lang ?? "ja";
|
|
@@ -4066,8 +4327,10 @@ function renderDiagram(input, options = {}) {
|
|
|
4066
4327
|
}
|
|
4067
4328
|
|
|
4068
4329
|
// src/view.ts
|
|
4069
|
-
function chooseView(rendered, frameWidth) {
|
|
4070
|
-
const
|
|
4330
|
+
function chooseView(rendered, frameWidth, frameHeight) {
|
|
4331
|
+
const byWidth = Math.max(0, frameWidth) / rendered.layout.width;
|
|
4332
|
+
const scale = frameHeight === void 0 ? byWidth : Math.min(byWidth, Math.max(0, frameHeight) / rendered.layout.height);
|
|
4333
|
+
const textPx = scale * TYPE.boxName.size;
|
|
4071
4334
|
if (rendered.view) return { mode: rendered.view, textPx };
|
|
4072
4335
|
return { mode: textPx >= READABLE_PX ? "fixed" : "follow", textPx };
|
|
4073
4336
|
}
|
|
@@ -4081,15 +4344,29 @@ function playerCss() {
|
|
|
4081
4344
|
return [
|
|
4082
4345
|
`.dg-player{display:flex;flex-direction:column;gap:${px(P.gap)};color:var(--ink)}`,
|
|
4083
4346
|
`.dg-player .dg-frame{border-radius:${px(P.radius)};overflow:hidden}`,
|
|
4084
|
-
`.dg-
|
|
4347
|
+
// 並べ方は帯の中身の幅で選ぶ。帯の中の 1 段 (`.dg-row`) が並べ替わり、帯の左右の余白は置いた頁が帯に付ける
|
|
4348
|
+
`.dg-bar{container:dg-bar/inline-size}`,
|
|
4349
|
+
`.dg-row{display:flex;align-items:flex-start;gap:${px(P.gap)}}`,
|
|
4085
4350
|
`.dg-btns{display:flex;gap:${px(P.gap / 2)};flex:none}`,
|
|
4086
4351
|
`.dg-btn{width:${px(P.button)};height:${px(P.button)};border-radius:${px(P.radius)};border:${px(LOOK.stroke.hair)} solid var(--hair);background:var(--surf);color:var(--ink);${font2(TYPE.button)};cursor:pointer}`,
|
|
4087
4352
|
`.dg-btn:focus-visible{outline:${px(P.focus)} solid var(--c-blue);outline-offset:${px(P.focus)}}`,
|
|
4088
4353
|
`.dg-say{display:flex;gap:${px(P.gap)};min-width:0}`,
|
|
4089
4354
|
`.dg-no{${font2(TYPE.stepNo)};color:var(--mute);padding-top:${px(P.focus)}}`,
|
|
4355
|
+
`.dg-txt{display:grid;grid-template-columns:minmax(0,1fr);min-width:0}`,
|
|
4356
|
+
`.dg-txt>*{grid-area:1/1}`,
|
|
4357
|
+
`.dg-room{visibility:hidden}`,
|
|
4090
4358
|
`.dg-tt{${font2(TYPE.stepTitle)};margin:0}`,
|
|
4091
4359
|
`.dg-tb{${font2(TYPE.stepBody)};color:var(--ink2);margin:0;white-space:pre-line}`,
|
|
4092
|
-
`.dg-sr{position:absolute;width:${hidden};height:${hidden};margin:-${hidden};padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
|
|
4360
|
+
`.dg-sr{position:absolute;width:${hidden};height:${hidden};margin:-${hidden};padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}`,
|
|
4361
|
+
// 狭い帯 (携帯の幅) では、段を送る釦を指で押せる大きさにし、その横に番号を置き、
|
|
4362
|
+
// 題を 2 段目、本文を 3 段目に置いてどちらも帯の全幅を使う (#3057、#3069)。
|
|
4363
|
+
// 釦を大きくすると横に題を置く幅が足りず題が細かく折れるため、題は釦の段に置かない。
|
|
4364
|
+
// 題と本文を包む箱を外して写しも同じ升に重ねるので、2 段目は最も高い題、3 段目は最も長い本文の高さになる。
|
|
4365
|
+
// 題と本文の間は広い帯と同じく空けず、釦の段の下にだけ間を取って、帯が高くなる分を抑える
|
|
4366
|
+
`@container dg-bar (width < ${px(P.narrow)}){.dg-row{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:0 ${px(P.gap)}}.dg-say,.dg-txt,.dg-txt>*{display:contents}.dg-btns{grid-area:1/1;margin-bottom:${px(P.gap / 2)}}.dg-btn{width:${px(P.touch)};height:${px(P.touch)}}.dg-no{grid-area:1/2;display:flex;align-items:center;min-height:${px(P.touch)};padding-top:0}.dg-tt{grid-area:2/1/3/3}.dg-tb{grid-area:3/1/4/3}}`,
|
|
4367
|
+
// 指で触る時は、広い帯でも段を送る釦を指で押せる大きさにする (#3076)。並びは横 1 列のまま変えない。
|
|
4368
|
+
// 広い帯は本文が 2 行あれば帯の高さが変わらず、本文の無い帯だけが釦の分だけ高くなる
|
|
4369
|
+
`@media (pointer: coarse){.dg-btn{width:${px(P.touch)};height:${px(P.touch)}}}`
|
|
4093
4370
|
].join("");
|
|
4094
4371
|
}
|
|
4095
4372
|
function ensureCss(doc) {
|
|
@@ -4120,11 +4397,11 @@ function mountDiagram(host, diagram, options = {}) {
|
|
|
4120
4397
|
root.setAttribute("style", `${FONT_VARS};${paletteVars(palette, rendered.theme)}`);
|
|
4121
4398
|
const frame = doc.createElement("div");
|
|
4122
4399
|
frame.className = "dg-frame";
|
|
4123
|
-
const button = (
|
|
4400
|
+
const button = (name2, label2, text3) => {
|
|
4124
4401
|
const b = doc.createElement("button");
|
|
4125
4402
|
b.type = "button";
|
|
4126
4403
|
b.className = "dg-btn";
|
|
4127
|
-
b.dataset.dragon =
|
|
4404
|
+
b.dataset.dragon = name2;
|
|
4128
4405
|
b.setAttribute("aria-label", label2);
|
|
4129
4406
|
b.textContent = text3;
|
|
4130
4407
|
return b;
|
|
@@ -4143,21 +4420,41 @@ function mountDiagram(host, diagram, options = {}) {
|
|
|
4143
4420
|
no.className = "dg-no";
|
|
4144
4421
|
no.dataset.dragon = "step-no";
|
|
4145
4422
|
const text2 = doc.createElement("div");
|
|
4423
|
+
text2.className = "dg-txt";
|
|
4146
4424
|
const title = doc.createElement("p");
|
|
4147
4425
|
title.className = "dg-tt";
|
|
4148
4426
|
title.dataset.dragon = "step-title";
|
|
4149
4427
|
const body = doc.createElement("p");
|
|
4150
4428
|
body.className = "dg-tb";
|
|
4151
4429
|
body.dataset.dragon = "step-body";
|
|
4152
|
-
|
|
4430
|
+
const live = doc.createElement("div");
|
|
4431
|
+
live.append(title, body);
|
|
4432
|
+
text2.append(live);
|
|
4433
|
+
for (const step2 of steps) {
|
|
4434
|
+
const room = doc.createElement("div");
|
|
4435
|
+
room.className = "dg-room";
|
|
4436
|
+
room.dataset.dragon = "caption-room";
|
|
4437
|
+
const roomTitle = doc.createElement("p");
|
|
4438
|
+
roomTitle.className = "dg-tt";
|
|
4439
|
+
roomTitle.textContent = step2.title;
|
|
4440
|
+
const roomBody = doc.createElement("p");
|
|
4441
|
+
roomBody.className = "dg-tb";
|
|
4442
|
+
roomBody.textContent = step2.body;
|
|
4443
|
+
room.append(roomTitle, roomBody);
|
|
4444
|
+
text2.append(room);
|
|
4445
|
+
}
|
|
4153
4446
|
say.append(no, text2);
|
|
4447
|
+
for (const shown2 of [no, title, body]) shown2.setAttribute("aria-hidden", "true");
|
|
4448
|
+
const row = doc.createElement("div");
|
|
4449
|
+
row.className = "dg-row";
|
|
4450
|
+
row.append(buttons, say);
|
|
4154
4451
|
const bar = doc.createElement("div");
|
|
4155
4452
|
bar.className = "dg-bar";
|
|
4156
|
-
bar.append(
|
|
4157
|
-
const
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4453
|
+
bar.append(row);
|
|
4454
|
+
const list2 = doc.createElement("ol");
|
|
4455
|
+
list2.className = "dg-sr";
|
|
4456
|
+
list2.dataset.dragon = "steps";
|
|
4457
|
+
list2.setAttribute("aria-label", words.steps(rendered.diagram.title));
|
|
4161
4458
|
for (const step2 of steps) {
|
|
4162
4459
|
const item = doc.createElement("li");
|
|
4163
4460
|
const head = doc.createElement("strong");
|
|
@@ -4168,13 +4465,20 @@ function mountDiagram(host, diagram, options = {}) {
|
|
|
4168
4465
|
p.textContent = line;
|
|
4169
4466
|
item.append(p);
|
|
4170
4467
|
}
|
|
4171
|
-
|
|
4468
|
+
list2.append(item);
|
|
4172
4469
|
}
|
|
4173
|
-
root.append(frame, bar,
|
|
4470
|
+
root.append(frame, bar, list2);
|
|
4174
4471
|
host.append(root);
|
|
4175
4472
|
const frameWidth = () => frame.clientWidth || host.clientWidth || rendered.layout.width;
|
|
4176
|
-
|
|
4473
|
+
const frameHeight = () => {
|
|
4474
|
+
if (!options.fitHeight || !win) return void 0;
|
|
4475
|
+
const style = win.getComputedStyle(frame);
|
|
4476
|
+
const inner = frame.clientHeight - (Number.parseFloat(style.paddingTop) || 0) - (Number.parseFloat(style.paddingBottom) || 0);
|
|
4477
|
+
return inner > 0 ? inner : void 0;
|
|
4478
|
+
};
|
|
4479
|
+
let mode = chooseView(rendered, frameWidth(), frameHeight()).mode;
|
|
4177
4480
|
let width = frameWidth();
|
|
4481
|
+
let height = frameHeight();
|
|
4178
4482
|
let svg = null;
|
|
4179
4483
|
let step = 0;
|
|
4180
4484
|
let playing = !reduce;
|
|
@@ -4201,7 +4505,7 @@ function mountDiagram(host, diagram, options = {}) {
|
|
|
4201
4505
|
svg = next;
|
|
4202
4506
|
born = Date.now();
|
|
4203
4507
|
};
|
|
4204
|
-
const markup = () => mode === "follow" ? drawSvg(rendered.diagram, rendered.layout, timeline, palette, rendered.theme, { width, lang }) : rendered.svg;
|
|
4508
|
+
const markup = () => mode === "follow" ? drawSvg(rendered.diagram, rendered.layout, timeline, palette, rendered.theme, { width, ...height === void 0 ? {} : { height }, lang }) : rendered.svg;
|
|
4205
4509
|
const now = () => playing ? (at + (Date.now() - born) / 1e3) % timeline.total : at;
|
|
4206
4510
|
const stepAt = (t) => {
|
|
4207
4511
|
let found = 0;
|
|
@@ -4217,6 +4521,7 @@ function mountDiagram(host, diagram, options = {}) {
|
|
|
4217
4521
|
body.textContent = current?.body ?? "";
|
|
4218
4522
|
toggleButton.setAttribute("aria-label", playing ? words.pause : words.play);
|
|
4219
4523
|
toggleButton.textContent = playing ? BUTTON_TEXT.pause : BUTTON_TEXT.play;
|
|
4524
|
+
options.onStep?.(step);
|
|
4220
4525
|
};
|
|
4221
4526
|
const restart = (t, play) => {
|
|
4222
4527
|
at = t;
|
|
@@ -4242,8 +4547,8 @@ function mountDiagram(host, diagram, options = {}) {
|
|
|
4242
4547
|
const onPrev = () => go(step - 1);
|
|
4243
4548
|
const onNext = () => go(step + 1);
|
|
4244
4549
|
const onToggle = () => playing ? restart(now(), false) : restart(at, true);
|
|
4245
|
-
const onFigure = (
|
|
4246
|
-
const target =
|
|
4550
|
+
const onFigure = (event2) => {
|
|
4551
|
+
const target = event2.target?.closest?.("[data-step]");
|
|
4247
4552
|
const s = target ? Number(target.getAttribute("data-step")) : Number.NaN;
|
|
4248
4553
|
if (Number.isInteger(s)) go(s);
|
|
4249
4554
|
};
|
|
@@ -4254,11 +4559,13 @@ function mountDiagram(host, diagram, options = {}) {
|
|
|
4254
4559
|
const Observer = win?.ResizeObserver;
|
|
4255
4560
|
const observer = Observer ? new Observer(() => {
|
|
4256
4561
|
const w = frameWidth();
|
|
4257
|
-
const
|
|
4258
|
-
|
|
4562
|
+
const h = frameHeight();
|
|
4563
|
+
const chosen = chooseView(rendered, w, h).mode;
|
|
4564
|
+
if (chosen === mode && (mode === "fixed" || w === width && h === height)) return;
|
|
4259
4565
|
const t = now();
|
|
4260
4566
|
mode = chosen;
|
|
4261
4567
|
width = w;
|
|
4568
|
+
height = h;
|
|
4262
4569
|
at = t;
|
|
4263
4570
|
place(markup());
|
|
4264
4571
|
}) : void 0;
|
|
@@ -4290,6 +4597,6 @@ function mountDiagram(host, diagram, options = {}) {
|
|
|
4290
4597
|
};
|
|
4291
4598
|
}
|
|
4292
4599
|
|
|
4293
|
-
export { DEFAULT_PALETTE, FONTS, FORMAT_VERSION, PALETTES, chooseView, extractDiagrams, migrateFile, mountDiagram,
|
|
4600
|
+
export { DEFAULT_PALETTE, FONTS, FORMAT_VERSION, PALETTES, READABLE_PX, chooseView, extractDiagrams, migrateFile, mountDiagram, parseNotation, printNotation, readDiagram, renderDiagram, resolvePalette, validateDiagram };
|
|
4294
4601
|
//# sourceMappingURL=index.js.map
|
|
4295
4602
|
//# sourceMappingURL=index.js.map
|