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