@rohal12/spindle 0.58.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pkg/format.js +1 -1
- package/dist/pkg/headless.js +318 -196
- package/dist/pkg/macro-registry.json +29 -11
- package/dist/pkg/story-variables.js +329 -206
- package/package.json +1 -1
- package/src/code-check.ts +156 -82
- package/src/components/macros/Button.tsx +3 -1
- package/src/components/macros/Checkbox.tsx +4 -1
- package/src/components/macros/Dialog.tsx +1 -1
- package/src/components/macros/MacroLink.tsx +1 -1
- package/src/components/macros/Meter.tsx +1 -1
- package/src/components/macros/Radiobutton.tsx +2 -2
- package/src/components/macros/Watch.tsx +11 -6
- package/src/components/macros/arg-utils.ts +0 -37
- package/src/components/macros/input-macro.ts +4 -1
- package/src/components/macros/macro-args.ts +93 -52
- package/src/components/macros/option-utils.ts +1 -1
- package/src/index.tsx +2 -4
- package/src/js-lexer.ts +19 -0
- package/src/markup/parse.ts +22 -4
- package/src/markup/spindle.peggy +21 -9
- package/src/markup/tokens.ts +3 -0
- package/src/markup/validate.ts +13 -10
- package/src/registry.ts +63 -6
- package/src/story-variables.ts +12 -8
- package/src/tooling.ts +15 -16
- package/src/widgets/widget-def.ts +2 -2
- package/types/index.d.ts +23 -0
- package/types/tooling.d.ts +28 -2
package/dist/pkg/headless.js
CHANGED
|
@@ -103,24 +103,41 @@ var LINK_SEPARATORS = [
|
|
|
103
103
|
["<-", true]
|
|
104
104
|
];
|
|
105
105
|
var NO_SELECTORS = {};
|
|
106
|
-
|
|
106
|
+
/**
|
|
107
|
+
* A link's display text and target, from its text `inner` (at `at` in the
|
|
108
|
+
* input), with where the target is written.
|
|
109
|
+
*/
|
|
110
|
+
function parseLink(inner, at) {
|
|
111
|
+
/** The trimmed text from `start` to `end` of inner, and where it is. */
|
|
112
|
+
const part = (start, end) => {
|
|
113
|
+
const raw = inner.slice(start, end);
|
|
114
|
+
const value = raw.trim();
|
|
115
|
+
const from = at + start + (value ? raw.indexOf(value) : 0);
|
|
116
|
+
return {
|
|
117
|
+
value,
|
|
118
|
+
start: from,
|
|
119
|
+
end: from + value.length
|
|
120
|
+
};
|
|
121
|
+
};
|
|
107
122
|
for (const [separator, targetFirst] of LINK_SEPARATORS) {
|
|
108
123
|
const idx = inner.indexOf(separator);
|
|
109
124
|
if (idx === -1) continue;
|
|
110
|
-
const before =
|
|
111
|
-
const after =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
125
|
+
const before = part(0, idx);
|
|
126
|
+
const after = part(idx + separator.length, inner.length);
|
|
127
|
+
const [display, target] = targetFirst ? [after, before] : [before, after];
|
|
128
|
+
return {
|
|
129
|
+
display: display.value,
|
|
130
|
+
target: target.value,
|
|
131
|
+
targetStart: target.start,
|
|
132
|
+
targetEnd: target.end
|
|
118
133
|
};
|
|
119
134
|
}
|
|
120
|
-
const
|
|
135
|
+
const whole = part(0, inner.length);
|
|
121
136
|
return {
|
|
122
|
-
display:
|
|
123
|
-
target:
|
|
137
|
+
display: whole.value,
|
|
138
|
+
target: whole.value,
|
|
139
|
+
targetStart: whole.start,
|
|
140
|
+
targetEnd: whole.end
|
|
124
141
|
};
|
|
125
142
|
}
|
|
126
143
|
function quoteArg(value) {
|
|
@@ -202,6 +219,8 @@ function tokenOf(x) {
|
|
|
202
219
|
type: "link",
|
|
203
220
|
display: x.display,
|
|
204
221
|
target: x.target,
|
|
222
|
+
targetStart: x.targetStart,
|
|
223
|
+
targetEnd: x.targetEnd,
|
|
205
224
|
...span
|
|
206
225
|
}, x);
|
|
207
226
|
case "variable": return withSelectors({
|
|
@@ -733,8 +752,8 @@ function peg$parse(input, options) {
|
|
|
733
752
|
function peg$f48() {
|
|
734
753
|
return !textMode;
|
|
735
754
|
}
|
|
736
|
-
function peg$f49(s, inner) {
|
|
737
|
-
return withSelectors(lexeme("link", location(), parseLink(inner)), s);
|
|
755
|
+
function peg$f49(s, at, inner) {
|
|
756
|
+
return withSelectors(lexeme("link", location(), parseLink(inner, at)), s);
|
|
738
757
|
}
|
|
739
758
|
function peg$f50() {
|
|
740
759
|
return !textMode;
|
|
@@ -1783,7 +1802,7 @@ function peg$parse(input, options) {
|
|
|
1783
1802
|
return s0;
|
|
1784
1803
|
}
|
|
1785
1804
|
function peg$parseLinkLexeme() {
|
|
1786
|
-
let s0, s1, s2, s3, s4, s5;
|
|
1805
|
+
let s0, s1, s2, s3, s4, s5, s6;
|
|
1787
1806
|
s0 = peg$currPos;
|
|
1788
1807
|
peg$savedPos = peg$currPos;
|
|
1789
1808
|
s1 = peg$f48();
|
|
@@ -1800,19 +1819,20 @@ function peg$parse(input, options) {
|
|
|
1800
1819
|
if (s2 !== peg$FAILED) {
|
|
1801
1820
|
s3 = peg$parseSelectors();
|
|
1802
1821
|
if (s3 !== peg$FAILED) {
|
|
1803
|
-
s4 = peg$
|
|
1804
|
-
s5 = peg$
|
|
1805
|
-
|
|
1822
|
+
s4 = peg$parseHere();
|
|
1823
|
+
s5 = peg$currPos;
|
|
1824
|
+
s6 = peg$parseLinkText();
|
|
1825
|
+
s5 = input.substring(s5, peg$currPos);
|
|
1806
1826
|
if (input.substr(peg$currPos, 2) === peg$c5) {
|
|
1807
|
-
|
|
1827
|
+
s6 = peg$c5;
|
|
1808
1828
|
peg$currPos += 2;
|
|
1809
1829
|
} else {
|
|
1810
|
-
|
|
1830
|
+
s6 = peg$FAILED;
|
|
1811
1831
|
if (peg$silentFails === 0) peg$fail(peg$e9);
|
|
1812
1832
|
}
|
|
1813
|
-
if (
|
|
1833
|
+
if (s6 !== peg$FAILED) {
|
|
1814
1834
|
peg$savedPos = s0;
|
|
1815
|
-
s0 = peg$f49(s3, s4);
|
|
1835
|
+
s0 = peg$f49(s3, s4, s5);
|
|
1816
1836
|
} else {
|
|
1817
1837
|
peg$currPos = s0;
|
|
1818
1838
|
s0 = peg$FAILED;
|
|
@@ -9441,6 +9461,22 @@ function regexEnd(src, start) {
|
|
|
9441
9461
|
return -1;
|
|
9442
9462
|
}
|
|
9443
9463
|
/**
|
|
9464
|
+
* The value of `src` when it is exactly one `"…"` or `'…'` string literal,
|
|
9465
|
+
* as JavaScript reads it (`"\u0048all"` is `Hall`, `"\1"` is U+0001 in
|
|
9466
|
+
* the non-strict code passages run), otherwise `null`: other code, or a
|
|
9467
|
+
* literal that is not well-formed (`"\u{110000}"`).
|
|
9468
|
+
*/
|
|
9469
|
+
function stringLiteralValue(src) {
|
|
9470
|
+
if (src[0] !== "\"" && src[0] !== "'") return null;
|
|
9471
|
+
try {
|
|
9472
|
+
const p = tokenizerAt(src, 0, "expression");
|
|
9473
|
+
p.nextToken();
|
|
9474
|
+
return p.type === types$1.string && p.end === src.length ? p.value : null;
|
|
9475
|
+
} catch {
|
|
9476
|
+
return null;
|
|
9477
|
+
}
|
|
9478
|
+
}
|
|
9479
|
+
/**
|
|
9444
9480
|
* Scan the `"…"` or `'…'` string literal opening at `start`. `end` is the
|
|
9445
9481
|
* index just past its closing quote, or `src.length` when it is unterminated
|
|
9446
9482
|
* (`closed` false). A backslash escapes the character after it, so a quote
|
|
@@ -10146,20 +10182,45 @@ var PARAMETER_TYPES = [
|
|
|
10146
10182
|
"options"
|
|
10147
10183
|
];
|
|
10148
10184
|
/**
|
|
10185
|
+
* What the value of a `string` or `text` argument holds, for the check at
|
|
10186
|
+
* story start and for tooling (see code-check.ts):
|
|
10187
|
+
* - `markup`: markup the macro renders (`{button}`'s label): its markup
|
|
10188
|
+
* is checked.
|
|
10189
|
+
* - `text`: plain text the macro uses as written (`{checkbox}`'s label).
|
|
10190
|
+
* - `passage`: a passage name (`{watch}`'s `goto`): the passage must exist.
|
|
10191
|
+
* - `expression`, `statements`: code (`{watch}`'s condition and `run`): it
|
|
10192
|
+
* is checked as code, and its variable references against the schema.
|
|
10193
|
+
*
|
|
10194
|
+
* Without it, the argument of a macro with `interpolate` holds `markup`,
|
|
10195
|
+
* any other `text`.
|
|
10196
|
+
*/
|
|
10197
|
+
var STRING_HOLDS = [
|
|
10198
|
+
"markup",
|
|
10199
|
+
"text",
|
|
10200
|
+
"passage",
|
|
10201
|
+
"expression",
|
|
10202
|
+
"statements"
|
|
10203
|
+
];
|
|
10204
|
+
/**
|
|
10149
10205
|
* Throw if a parameter `macro` declares (or an option of one) has no type,
|
|
10150
10206
|
* or one that isn't a ParameterType: arguments are read by their type, and
|
|
10151
|
-
* there is no default.
|
|
10207
|
+
* there is no default. Throw too if it declares what it `holds` wrongly.
|
|
10152
10208
|
*/
|
|
10153
10209
|
function checkParameterTypes(macro, parameters) {
|
|
10210
|
+
const holdsFix = `Give a \`string\` or \`text\` parameter one of ${STRING_HOLDS.join(", ")} to hold (see docs/custom-macros.md#what-a-string-holds).`;
|
|
10154
10211
|
for (const param of parameters) {
|
|
10155
10212
|
const type = param.type;
|
|
10156
|
-
if (!PARAMETER_TYPES.includes(type)) {
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
}
|
|
10213
|
+
if (!PARAMETER_TYPES.includes(type)) throw parameterError(macro, param, type === void 0 ? "has no type" : `has the unknown type ${JSON.stringify(type)}`, `Give it one of the types ${PARAMETER_TYPES.join(", ")} (see docs/custom-macros.md#parameter-types), or declare no parameters and read props.rawArgs.`);
|
|
10214
|
+
const holds = param.holds;
|
|
10215
|
+
if (holds !== void 0 && type !== "string" && type !== "text") throw parameterError(macro, param, `is of the type ${type}, which holds what it is`, holdsFix);
|
|
10216
|
+
if (holds !== void 0 && !STRING_HOLDS.includes(holds)) throw parameterError(macro, param, `holds the unknown ${JSON.stringify(holds)}`, holdsFix);
|
|
10160
10217
|
if (param.parameters) checkParameterTypes(macro, param.parameters);
|
|
10161
10218
|
}
|
|
10162
10219
|
}
|
|
10220
|
+
/** The error for the parameter `param` of `macro`: what is wrong, and the fix. */
|
|
10221
|
+
function parameterError(macro, param, problem, fix) {
|
|
10222
|
+
return /* @__PURE__ */ new Error(`spindle: The parameter "${param.name}" of the macro {${macro}} ${problem}. ${fix}`);
|
|
10223
|
+
}
|
|
10163
10224
|
var metadataRegistry = new NameMap();
|
|
10164
10225
|
function registerMacroMetadata(name, metadata) {
|
|
10165
10226
|
metadataRegistry.set(name, metadata);
|
|
@@ -10242,37 +10303,6 @@ function readWholeQuoted(src) {
|
|
|
10242
10303
|
const quoted = readQuoted(src, 0);
|
|
10243
10304
|
return quoted && quoted.end === src.length ? quoted.value : null;
|
|
10244
10305
|
}
|
|
10245
|
-
var JS_SIMPLE_ESCAPES = {
|
|
10246
|
-
n: "\n",
|
|
10247
|
-
t: " ",
|
|
10248
|
-
r: "\r",
|
|
10249
|
-
b: "\b",
|
|
10250
|
-
f: "\f",
|
|
10251
|
-
v: "\v",
|
|
10252
|
-
"0": "\0"
|
|
10253
|
-
};
|
|
10254
|
-
/** Undo every escape of a JavaScript string literal's body. */
|
|
10255
|
-
function decodeJsEscapes(body) {
|
|
10256
|
-
return body.replace(/\\(?:u\{([0-9a-fA-F]+)\}|u([0-9a-fA-F]{4})|x([0-9a-fA-F]{2})|(\r\n|[\n\r\u2028\u2029])|([\s\S]))/g, (_, braced, unicode, hex, lineBreak, other) => {
|
|
10257
|
-
if (lineBreak !== void 0) return "";
|
|
10258
|
-
const code = braced ?? unicode ?? hex;
|
|
10259
|
-
if (code !== void 0) {
|
|
10260
|
-
const point = parseInt(code, 16);
|
|
10261
|
-
return point <= 1114111 ? String.fromCodePoint(point) : "";
|
|
10262
|
-
}
|
|
10263
|
-
return JS_SIMPLE_ESCAPES[other] ?? other;
|
|
10264
|
-
});
|
|
10265
|
-
}
|
|
10266
|
-
/**
|
|
10267
|
-
* The value of `src` when it is exactly one `"…"` or `'…'` string, read as
|
|
10268
|
-
* the JavaScript literal it is (`"\u0048all"` is `Hall`), otherwise `null`.
|
|
10269
|
-
* `readWholeQuoted` keeps other escapes as written, for labels and code.
|
|
10270
|
-
*/
|
|
10271
|
-
function readWholeJsString(src) {
|
|
10272
|
-
const quoted = readQuoted(src, 0);
|
|
10273
|
-
if (!quoted || quoted.end !== src.length) return null;
|
|
10274
|
-
return decodeJsEscapes(src.slice(1, -1));
|
|
10275
|
-
}
|
|
10276
10306
|
/**
|
|
10277
10307
|
* Strip an optional quote from each end of an unquoted-or-loosely-quoted
|
|
10278
10308
|
* argument (`"Red`, `Red'`), leaving at least one character. This is the
|
|
@@ -16567,7 +16597,9 @@ var MacroArgumentError = class extends Error {
|
|
|
16567
16597
|
this.name = "MacroArgumentError";
|
|
16568
16598
|
}
|
|
16569
16599
|
};
|
|
16570
|
-
|
|
16600
|
+
/** Read `src`, at `place`, as `param` says. */
|
|
16601
|
+
function readValue(param, src, place) {
|
|
16602
|
+
place.spans?.set(param, [place.at, place.at + src.length]);
|
|
16571
16603
|
switch (param.type) {
|
|
16572
16604
|
case "string": {
|
|
16573
16605
|
const value = readWholeQuoted(src);
|
|
@@ -16578,7 +16610,7 @@ function readValue(param, src) {
|
|
|
16578
16610
|
case "names": return src.split(",").map((name) => name.trim());
|
|
16579
16611
|
case "delay": return parseDelay(src);
|
|
16580
16612
|
case "number": return Number(src);
|
|
16581
|
-
case "options": return readOptions(param.parameters ?? [], src);
|
|
16613
|
+
case "options": return readOptions(param.parameters ?? [], src, place);
|
|
16582
16614
|
default: return src;
|
|
16583
16615
|
}
|
|
16584
16616
|
}
|
|
@@ -16596,11 +16628,12 @@ function matchAt(re, src, pos) {
|
|
|
16596
16628
|
}
|
|
16597
16629
|
/**
|
|
16598
16630
|
* Read keyword options (`goto "X" priority 5 once`). A keyword takes the
|
|
16599
|
-
* quoted string or
|
|
16600
|
-
* declared, and their values, are
|
|
16601
|
-
* must be followed by a quoted
|
|
16631
|
+
* quoted string (with or without whitespace before it) or digit run after
|
|
16632
|
+
* it as its value; keywords that aren't declared, and their values, are
|
|
16633
|
+
* skipped. A keyword of a `string` parameter must be followed by a quoted
|
|
16634
|
+
* string.
|
|
16602
16635
|
*/
|
|
16603
|
-
function readOptions(params, src) {
|
|
16636
|
+
function readOptions(params, src, { at, spans }) {
|
|
16604
16637
|
const options = {};
|
|
16605
16638
|
let i = 0;
|
|
16606
16639
|
while (i < src.length) {
|
|
@@ -16611,22 +16644,20 @@ function readOptions(params, src) {
|
|
|
16611
16644
|
}
|
|
16612
16645
|
i += key.length;
|
|
16613
16646
|
let val;
|
|
16614
|
-
let quoted = null;
|
|
16615
16647
|
let j = i;
|
|
16616
16648
|
while (j < src.length && isWhitespace(src[j])) j++;
|
|
16617
|
-
|
|
16618
|
-
|
|
16619
|
-
|
|
16620
|
-
|
|
16621
|
-
|
|
16622
|
-
|
|
16623
|
-
|
|
16624
|
-
|
|
16625
|
-
i = j + digits.length;
|
|
16626
|
-
}
|
|
16649
|
+
const quoted = readQuoted(src, j);
|
|
16650
|
+
const digits = quoted || j === i ? null : matchAt(DIGITS_RE, src, j);
|
|
16651
|
+
if (quoted) {
|
|
16652
|
+
val = quoted.value;
|
|
16653
|
+
i = quoted.end;
|
|
16654
|
+
} else if (digits) {
|
|
16655
|
+
val = digits;
|
|
16656
|
+
i = j + digits.length;
|
|
16627
16657
|
}
|
|
16628
16658
|
const param = params.find((p) => p.name === key);
|
|
16629
|
-
if (param
|
|
16659
|
+
if (param && param.type !== "flag" && val !== void 0) spans?.set(param, [at + j, at + i]);
|
|
16660
|
+
if (param?.type === "string" && !quoted) throw new MacroArgumentError(param, matchAt(WORD_OR_PUNCT_RE, src, j) ?? "");
|
|
16630
16661
|
if (param?.type === "flag") options[key] = true;
|
|
16631
16662
|
else if (param?.type === "number") options[key] = Number(val ?? 0);
|
|
16632
16663
|
else if (param) options[key] = val;
|
|
@@ -16636,21 +16667,21 @@ function readOptions(params, src) {
|
|
|
16636
16667
|
/** `inline %name` reads a transient variable; `inline % 2` is modulo. */
|
|
16637
16668
|
var LEADING_OPERATOR_RE = /^(?:[-+*/&|^=<>?:,.]|%(?![A-Za-z_]))/;
|
|
16638
16669
|
/**
|
|
16639
|
-
*
|
|
16640
|
-
* `null` if it has no such flag. Next to a binary operator the
|
|
16641
|
-
* operand (`"a" + inline`), not a flag; the closing `/` of a
|
|
16642
|
-
* is not one.
|
|
16670
|
+
* Where the rest of `src` is without the flag `word` as its last or first
|
|
16671
|
+
* term, or `null` if it has no such flag. Next to a binary operator the
|
|
16672
|
+
* word is an operand (`"a" + inline`), not a flag; the closing `/` of a
|
|
16673
|
+
* regex literal is not one.
|
|
16643
16674
|
*/
|
|
16644
16675
|
function takeFlag(src, word) {
|
|
16645
16676
|
const spans = terms(src);
|
|
16646
16677
|
if (spans.length < 2) return null;
|
|
16647
16678
|
if (slice(src, spans[spans.length - 1]) === word) {
|
|
16648
|
-
const rest =
|
|
16649
|
-
if (!endsWithOperator(rest)) return rest;
|
|
16679
|
+
const rest = [0, spans[spans.length - 2][1]];
|
|
16680
|
+
if (!endsWithOperator(slice(src, rest))) return rest;
|
|
16650
16681
|
}
|
|
16651
16682
|
if (slice(src, spans[0]) === word) {
|
|
16652
|
-
const rest =
|
|
16653
|
-
if (!LEADING_OPERATOR_RE.test(rest)) return rest;
|
|
16683
|
+
const rest = [spans[1][0], src.length];
|
|
16684
|
+
if (!LEADING_OPERATOR_RE.test(slice(src, rest))) return rest;
|
|
16654
16685
|
}
|
|
16655
16686
|
return null;
|
|
16656
16687
|
}
|
|
@@ -16678,42 +16709,55 @@ function findSeparator(src, word) {
|
|
|
16678
16709
|
return null;
|
|
16679
16710
|
}
|
|
16680
16711
|
var takesRest = (param) => param.type === "expression" || param.type === "statements" || param.type === "passage" || param.type === "text";
|
|
16681
|
-
/**
|
|
16682
|
-
function
|
|
16683
|
-
|
|
16712
|
+
/** The text of `src` without the whitespace around it, and where it is. */
|
|
16713
|
+
function trimmed(src, at) {
|
|
16714
|
+
const text = src.trim();
|
|
16715
|
+
return [text, text ? at + src.indexOf(text) : at];
|
|
16716
|
+
}
|
|
16717
|
+
/**
|
|
16718
|
+
* Read the parameters of one group from `src` (`null`: no text), which is
|
|
16719
|
+
* at `at` in the raw arguments, into `args`.
|
|
16720
|
+
*/
|
|
16721
|
+
function readGroup(params, src, args, { at: srcAt, spans }) {
|
|
16722
|
+
let [text, at] = trimmed(src ?? "", srcAt);
|
|
16684
16723
|
for (const flag of params.filter((p) => p.type === "flag")) {
|
|
16685
16724
|
const rest = src === null ? null : takeFlag(text, flag.name);
|
|
16686
16725
|
args[flag.name] = rest !== null;
|
|
16687
|
-
text = rest
|
|
16726
|
+
if (rest) [text, at] = trimmed(slice(text, rest), at + rest[0]);
|
|
16688
16727
|
}
|
|
16689
16728
|
const positional = params.filter((p) => p.type !== "flag");
|
|
16690
16729
|
if (positional.length === 0) return;
|
|
16691
16730
|
const lastText = positional.findIndex((p, i) => takesRest(p) && !positional.slice(i + 1).some(takesRest));
|
|
16692
16731
|
const restIndex = lastText < 0 ? positional.length - 1 : lastText;
|
|
16693
|
-
|
|
16732
|
+
/** Read `param` from the text from `start` to `end`. */
|
|
16733
|
+
const read = (param, [start, end]) => start === end ? unset(param) : readValue(param, text.slice(start, end), {
|
|
16734
|
+
at: at + start,
|
|
16735
|
+
spans
|
|
16736
|
+
});
|
|
16694
16737
|
if (positional.length === 1) {
|
|
16695
|
-
args[positional[0].name] = read(positional[0], text);
|
|
16738
|
+
args[positional[0].name] = read(positional[0], [0, text.length]);
|
|
16696
16739
|
return;
|
|
16697
16740
|
}
|
|
16698
|
-
const
|
|
16741
|
+
const parts = terms(text);
|
|
16699
16742
|
let from = 0;
|
|
16700
|
-
let to =
|
|
16701
|
-
for (const param of positional.slice(0, restIndex)) args[param.name] = from < to ? read(param,
|
|
16702
|
-
const readTrailing = (param,
|
|
16743
|
+
let to = parts.length;
|
|
16744
|
+
for (const param of positional.slice(0, restIndex)) args[param.name] = from < to ? read(param, parts[from++]) : unset(param);
|
|
16745
|
+
const readTrailing = (param, span) => {
|
|
16703
16746
|
try {
|
|
16704
|
-
return read(param,
|
|
16747
|
+
return read(param, span);
|
|
16705
16748
|
} catch (error) {
|
|
16706
16749
|
if (error instanceof MacroArgumentError) return void 0;
|
|
16707
16750
|
throw error;
|
|
16708
16751
|
}
|
|
16709
16752
|
};
|
|
16710
16753
|
for (const param of positional.slice(restIndex + 1).reverse()) {
|
|
16711
|
-
const value = from < to && !endsWithOperator(text.slice(0,
|
|
16754
|
+
const value = from < to && !endsWithOperator(text.slice(0, parts[to - 1][0])) ? readTrailing(param, parts[to - 1]) : void 0;
|
|
16712
16755
|
args[param.name] = value ?? unset(param);
|
|
16713
16756
|
if (value !== void 0) to--;
|
|
16757
|
+
else spans?.delete(param);
|
|
16714
16758
|
}
|
|
16715
16759
|
const rest = positional[restIndex];
|
|
16716
|
-
args[rest.name] = from < to ? read(rest,
|
|
16760
|
+
args[rest.name] = from < to ? read(rest, [parts[from][0], parts[to - 1][1]]) : unset(rest);
|
|
16717
16761
|
}
|
|
16718
16762
|
/** The duration a timing macro ({repeat}, {type}, {timed}/{next}) waits. */
|
|
16719
16763
|
var DELAY_PARAMETER = {
|
|
@@ -16721,32 +16765,43 @@ var DELAY_PARAMETER = {
|
|
|
16721
16765
|
type: "delay",
|
|
16722
16766
|
required: true
|
|
16723
16767
|
};
|
|
16724
|
-
/**
|
|
16725
|
-
|
|
16768
|
+
/**
|
|
16769
|
+
* Read `rawArgs` into the declared `parameters` (see above). With `spans`,
|
|
16770
|
+
* note there where each argument set was read.
|
|
16771
|
+
*/
|
|
16772
|
+
function parseMacroArgs(rawArgs, parameters, spans) {
|
|
16726
16773
|
const args = {};
|
|
16727
|
-
let rest = rawArgs
|
|
16774
|
+
let [rest, restAt] = trimmed(rawArgs, 0);
|
|
16728
16775
|
let groupStart = 0;
|
|
16729
16776
|
parameters.forEach((separator, i) => {
|
|
16730
16777
|
if (separator.type !== "separator") return;
|
|
16731
16778
|
const at = rest === null ? null : findSeparator(rest, separator.name);
|
|
16732
16779
|
args[separator.name] = at !== null;
|
|
16733
16780
|
const before = at ? rest.slice(0, at[0]) : rest;
|
|
16734
|
-
readGroup(parameters.slice(groupStart, i), before, args
|
|
16781
|
+
readGroup(parameters.slice(groupStart, i), before, args, {
|
|
16782
|
+
at: restAt,
|
|
16783
|
+
spans
|
|
16784
|
+
});
|
|
16735
16785
|
rest = at ? rest.slice(at[1]) : null;
|
|
16786
|
+
if (at) restAt += at[1];
|
|
16736
16787
|
groupStart = i + 1;
|
|
16737
16788
|
});
|
|
16738
|
-
readGroup(parameters.slice(groupStart), rest, args
|
|
16789
|
+
readGroup(parameters.slice(groupStart), rest, args, {
|
|
16790
|
+
at: restAt,
|
|
16791
|
+
spans
|
|
16792
|
+
});
|
|
16739
16793
|
return args;
|
|
16740
16794
|
}
|
|
16741
16795
|
/**
|
|
16742
16796
|
* Read a `passage` argument as written (`{goto "Hall"}`, `{goto $room}`): a
|
|
16743
|
-
*
|
|
16744
|
-
* `Hall`), anything else
|
|
16797
|
+
* string literal is the name JavaScript reads from it (`"\u0048all"` is
|
|
16798
|
+
* `Hall`), anything else (a literal that is not well-formed too) an
|
|
16799
|
+
* expression, whose value is the name when it
|
|
16745
16800
|
* runs (see evaluatePassageName).
|
|
16746
16801
|
*/
|
|
16747
16802
|
function passageTarget(arg) {
|
|
16748
16803
|
const expression = arg.trim();
|
|
16749
|
-
const name =
|
|
16804
|
+
const name = stringLiteralValue(expression);
|
|
16750
16805
|
return name === null ? {
|
|
16751
16806
|
kind: "expression",
|
|
16752
16807
|
expression
|
|
@@ -16795,6 +16850,7 @@ function parseVarArgs(rawArgs) {
|
|
|
16795
16850
|
var OPTION_PARAMETERS = [{
|
|
16796
16851
|
name: "value",
|
|
16797
16852
|
type: "string",
|
|
16853
|
+
holds: "text",
|
|
16798
16854
|
required: true
|
|
16799
16855
|
}];
|
|
16800
16856
|
/** The parameters of the built-in sub-macros that take arguments. */
|
|
@@ -17269,30 +17325,63 @@ var CONDITION_MACROS = new Set([
|
|
|
17269
17325
|
"elseif",
|
|
17270
17326
|
"case"
|
|
17271
17327
|
]);
|
|
17272
|
-
/** Code inside the quoted strings of a macro's arguments, by parameter. */
|
|
17273
|
-
var CODE_IN_STRINGS = new Map([["watch", {
|
|
17274
|
-
condition: "expression",
|
|
17275
|
-
run: "statements"
|
|
17276
|
-
}]]);
|
|
17277
|
-
/** The `string` parameters of a macro that name a passage. */
|
|
17278
|
-
var PASSAGE_STRINGS = new Map([["watch", ["goto", "dialog"]]]);
|
|
17279
|
-
/**
|
|
17280
|
-
* The `text` and `string` parameters of a macro that the runtime keeps as
|
|
17281
|
-
* written, not as markup: an option's value, the name of a watcher.
|
|
17282
|
-
*/
|
|
17283
|
-
var LITERAL_STRINGS = new Map([
|
|
17284
|
-
["option", ["value"]],
|
|
17285
|
-
["watch", ["name"]],
|
|
17286
|
-
["unwatch", ["name"]]
|
|
17287
|
-
]);
|
|
17288
17328
|
/** Block macros whose body is the name of a passage. */
|
|
17289
17329
|
var PASSAGE_BODIES = new Set(["dialog"]);
|
|
17330
|
+
/**
|
|
17331
|
+
* `params` with each `string` and `text` parameter (options too) saying
|
|
17332
|
+
* what it holds: what it declares, else `holds`.
|
|
17333
|
+
*/
|
|
17334
|
+
function withHolds(params, holds) {
|
|
17335
|
+
return params.map((param) => {
|
|
17336
|
+
if (param.parameters) return {
|
|
17337
|
+
...param,
|
|
17338
|
+
parameters: withHolds(param.parameters, holds)
|
|
17339
|
+
};
|
|
17340
|
+
return (param.type === "string" || param.type === "text") && !param.holds ? {
|
|
17341
|
+
...param,
|
|
17342
|
+
holds
|
|
17343
|
+
} : param;
|
|
17344
|
+
});
|
|
17345
|
+
}
|
|
17346
|
+
/**
|
|
17347
|
+
* The declared parameters of `macros`, by name in any case, and of the
|
|
17348
|
+
* built-in sub-macros (`{option}`): what the story-start check, reference
|
|
17349
|
+
* collection and tooling read arguments by. Each `string` and `text`
|
|
17350
|
+
* parameter says what it holds: what it declares, else `markup` for a macro
|
|
17351
|
+
* with `interpolate` (which can resolve markup) and `text` for any other.
|
|
17352
|
+
*/
|
|
17353
|
+
function parameterLookup(macros) {
|
|
17354
|
+
const parameters = new NameMap();
|
|
17355
|
+
for (const { name, parameters: params, interpolate } of macros) if (params) parameters.set(name, withHolds(params, holdsByDefault(interpolate)));
|
|
17356
|
+
return (name) => {
|
|
17357
|
+
let params = parameters.get(name);
|
|
17358
|
+
if (!params) {
|
|
17359
|
+
const sub = subMacroParameters(name);
|
|
17360
|
+
if (sub) parameters.set(name, params = withHolds(sub, "text"));
|
|
17361
|
+
}
|
|
17362
|
+
return params;
|
|
17363
|
+
};
|
|
17364
|
+
}
|
|
17365
|
+
/** What a `string` or `text` argument holds when its parameter doesn't say. */
|
|
17366
|
+
var holdsByDefault = (interpolate) => interpolate ? "markup" : "text";
|
|
17367
|
+
/** Whether a parameter in `params` (options too) holds code in a string. */
|
|
17368
|
+
function holdsCode(params) {
|
|
17369
|
+
return params.some((p) => p.holds === "expression" || p.holds === "statements" || !!p.parameters && holdsCode(p.parameters));
|
|
17370
|
+
}
|
|
17290
17371
|
/** The goal of the code an argument of this type holds, if it is code. */
|
|
17291
17372
|
function codeGoal(param) {
|
|
17292
17373
|
if (param.type === "expression" || param.type === "passage") return "expression";
|
|
17293
17374
|
if (param.type === "statements") return "statements";
|
|
17294
17375
|
}
|
|
17295
17376
|
/**
|
|
17377
|
+
* What a `string` or `text` argument holds: what its parameter says (see
|
|
17378
|
+
* parameterLookup), else markup, which is checked.
|
|
17379
|
+
*/
|
|
17380
|
+
function stringHolds(param) {
|
|
17381
|
+
if (param.type !== "string" && param.type !== "text") return void 0;
|
|
17382
|
+
return param.holds ?? "markup";
|
|
17383
|
+
}
|
|
17384
|
+
/**
|
|
17296
17385
|
* The code and the markup-holding text in `tokens`, the tokens of `src`.
|
|
17297
17386
|
* `parametersOf` gives the declared parameters of a macro, if it has any.
|
|
17298
17387
|
*/
|
|
@@ -17304,8 +17393,8 @@ function* codeAndText(src, tokens, parametersOf) {
|
|
|
17304
17393
|
if (token.type === "link") yield {
|
|
17305
17394
|
kind: "passage",
|
|
17306
17395
|
name: token.target,
|
|
17307
|
-
offset:
|
|
17308
|
-
length: token.
|
|
17396
|
+
offset: token.targetStart,
|
|
17397
|
+
length: token.targetEnd - token.targetStart,
|
|
17309
17398
|
macro: "link",
|
|
17310
17399
|
label: src.slice(token.start, token.end)
|
|
17311
17400
|
};
|
|
@@ -17316,32 +17405,35 @@ function* codeAndText(src, tokens, parametersOf) {
|
|
|
17316
17405
|
goal: "expression",
|
|
17317
17406
|
label: `{${token.expression}}`
|
|
17318
17407
|
};
|
|
17319
|
-
else if (token.type === "html")
|
|
17320
|
-
|
|
17321
|
-
|
|
17322
|
-
|
|
17323
|
-
|
|
17324
|
-
|
|
17325
|
-
|
|
17326
|
-
|
|
17327
|
-
|
|
17328
|
-
|
|
17329
|
-
|
|
17330
|
-
|
|
17331
|
-
|
|
17332
|
-
|
|
17333
|
-
|
|
17334
|
-
|
|
17335
|
-
|
|
17336
|
-
|
|
17337
|
-
|
|
17338
|
-
|
|
17339
|
-
|
|
17340
|
-
|
|
17341
|
-
|
|
17408
|
+
else if (token.type === "html") {
|
|
17409
|
+
let cursor = token.start;
|
|
17410
|
+
for (const [name, value] of Object.entries(token.attributes)) {
|
|
17411
|
+
const at = locate(src, value, cursor);
|
|
17412
|
+
cursor = at + value.length;
|
|
17413
|
+
if (!isCodeAttribute(name)) {
|
|
17414
|
+
yield {
|
|
17415
|
+
kind: "text",
|
|
17416
|
+
text: value,
|
|
17417
|
+
offset: at,
|
|
17418
|
+
where: `In the ${name} attribute of <${token.tag}>: `
|
|
17419
|
+
};
|
|
17420
|
+
continue;
|
|
17421
|
+
}
|
|
17422
|
+
let from = 0;
|
|
17423
|
+
for (const part of splitSigilTemplate(value)) {
|
|
17424
|
+
if (!("expr" in part)) continue;
|
|
17425
|
+
const k = locate(value, part.expr, from);
|
|
17426
|
+
from = k + part.expr.length;
|
|
17427
|
+
yield {
|
|
17428
|
+
kind: "code",
|
|
17429
|
+
code: part.expr,
|
|
17430
|
+
offset: at + k,
|
|
17431
|
+
goal: "expression",
|
|
17432
|
+
label: `{${part.expr}} in the ${name} attribute of <${token.tag}>`
|
|
17433
|
+
};
|
|
17434
|
+
}
|
|
17342
17435
|
}
|
|
17343
|
-
}
|
|
17344
|
-
else if (token.type === "macro" && !token.isClose) {
|
|
17436
|
+
} else if (token.type === "macro" && !token.isClose) {
|
|
17345
17437
|
const name = token.name.toLowerCase();
|
|
17346
17438
|
if (name === "do") {
|
|
17347
17439
|
const close = closeOf(t, name);
|
|
@@ -17361,12 +17453,13 @@ function* codeAndText(src, tokens, parametersOf) {
|
|
|
17361
17453
|
const close = closeOf(t, name);
|
|
17362
17454
|
const body = tokens.slice(t + 1, close);
|
|
17363
17455
|
if (close > t + 1 && body.every((b) => b.type === "text")) {
|
|
17364
|
-
const
|
|
17456
|
+
const text = src.slice(token.end, tokens[close].start);
|
|
17457
|
+
const written = text.trim();
|
|
17365
17458
|
yield {
|
|
17366
17459
|
kind: "passage",
|
|
17367
|
-
name:
|
|
17368
|
-
offset:
|
|
17369
|
-
length:
|
|
17460
|
+
name: written.replace(/^["']|["']$/g, ""),
|
|
17461
|
+
offset: token.end + text.indexOf(written),
|
|
17462
|
+
length: written.length,
|
|
17370
17463
|
macro: name,
|
|
17371
17464
|
label: src.slice(token.start, token.end)
|
|
17372
17465
|
};
|
|
@@ -17374,7 +17467,8 @@ function* codeAndText(src, tokens, parametersOf) {
|
|
|
17374
17467
|
}
|
|
17375
17468
|
if (!args) continue;
|
|
17376
17469
|
const label = `{${token.name} ${args}}`;
|
|
17377
|
-
const
|
|
17470
|
+
const tag = src.slice(token.start, token.end - 1);
|
|
17471
|
+
const argsAt = token.start + tag.trimEnd().length - args.length;
|
|
17378
17472
|
if (CONDITION_MACROS.has(name)) {
|
|
17379
17473
|
yield {
|
|
17380
17474
|
kind: "code",
|
|
@@ -17393,8 +17487,9 @@ function* codeAndText(src, tokens, parametersOf) {
|
|
|
17393
17487
|
/** The code and text in the arguments `args` (at `offset`) of `macro`. */
|
|
17394
17488
|
function* argPieces(args, offset, params, macro, label) {
|
|
17395
17489
|
let values;
|
|
17490
|
+
const spans = /* @__PURE__ */ new Map();
|
|
17396
17491
|
try {
|
|
17397
|
-
values = parseMacroArgs(args, params);
|
|
17492
|
+
values = parseMacroArgs(args, params, spans);
|
|
17398
17493
|
} catch (error) {
|
|
17399
17494
|
if (!(error instanceof MacroArgumentError)) throw error;
|
|
17400
17495
|
yield {
|
|
@@ -17405,11 +17500,7 @@ function* argPieces(args, offset, params, macro, label) {
|
|
|
17405
17500
|
};
|
|
17406
17501
|
return;
|
|
17407
17502
|
}
|
|
17408
|
-
const
|
|
17409
|
-
const inStrings = CODE_IN_STRINGS.get(key) ?? {};
|
|
17410
|
-
const passageStrings = PASSAGE_STRINGS.get(key) ?? [];
|
|
17411
|
-
const literalStrings = LITERAL_STRINGS.get(key) ?? [];
|
|
17412
|
-
let cursor = 0;
|
|
17503
|
+
const name = macro.toLowerCase();
|
|
17413
17504
|
/** The pieces of the parameters `list`, with their values in `from`. */
|
|
17414
17505
|
function* visit(list, from) {
|
|
17415
17506
|
for (const param of list) {
|
|
@@ -17418,42 +17509,57 @@ function* argPieces(args, offset, params, macro, label) {
|
|
|
17418
17509
|
yield* visit(param.parameters, value ?? {});
|
|
17419
17510
|
continue;
|
|
17420
17511
|
}
|
|
17421
|
-
|
|
17422
|
-
|
|
17423
|
-
|
|
17424
|
-
const
|
|
17512
|
+
const span = spans.get(param);
|
|
17513
|
+
if (typeof value !== "string" || !value.trim() || !span) continue;
|
|
17514
|
+
const [start, end] = span;
|
|
17515
|
+
const written = args.slice(start, end);
|
|
17516
|
+
/** The name as written (quotes included), at the argument. */
|
|
17517
|
+
const passage = (passageName) => ({
|
|
17518
|
+
kind: "passage",
|
|
17519
|
+
name: passageName,
|
|
17520
|
+
offset: offset + start,
|
|
17521
|
+
length: end - start,
|
|
17522
|
+
macro: name,
|
|
17523
|
+
label
|
|
17524
|
+
});
|
|
17525
|
+
const goal = codeGoal(param);
|
|
17526
|
+
if (param.type === "passage") {
|
|
17527
|
+
const target = passageTarget(value);
|
|
17528
|
+
if (target.kind === "name") {
|
|
17529
|
+
yield passage(target.name);
|
|
17530
|
+
continue;
|
|
17531
|
+
}
|
|
17532
|
+
}
|
|
17425
17533
|
if (goal) {
|
|
17426
17534
|
const piece = {
|
|
17427
17535
|
kind: "code",
|
|
17428
17536
|
code: value,
|
|
17429
|
-
offset: offset +
|
|
17537
|
+
offset: offset + start,
|
|
17430
17538
|
goal,
|
|
17431
17539
|
label
|
|
17432
17540
|
};
|
|
17433
17541
|
if (param.type === "passage") {
|
|
17434
17542
|
piece.passage = true;
|
|
17435
|
-
piece.macro =
|
|
17543
|
+
piece.macro = name;
|
|
17436
17544
|
}
|
|
17437
|
-
if (!codeGoal(param)) piece.inString = true;
|
|
17438
17545
|
yield piece;
|
|
17546
|
+
continue;
|
|
17439
17547
|
}
|
|
17440
|
-
const
|
|
17441
|
-
const
|
|
17442
|
-
|
|
17443
|
-
|
|
17444
|
-
|
|
17445
|
-
|
|
17446
|
-
|
|
17447
|
-
|
|
17448
|
-
|
|
17449
|
-
length: written.length,
|
|
17450
|
-
macro: macro.toLowerCase(),
|
|
17451
|
-
label
|
|
17548
|
+
const at = offset + start + (value !== written && /^["']/.test(written) ? 1 : 0);
|
|
17549
|
+
const holds = stringHolds(param);
|
|
17550
|
+
if (holds === "expression" || holds === "statements") yield {
|
|
17551
|
+
kind: "code",
|
|
17552
|
+
code: value,
|
|
17553
|
+
offset: at,
|
|
17554
|
+
goal: holds,
|
|
17555
|
+
label,
|
|
17556
|
+
inString: true
|
|
17452
17557
|
};
|
|
17453
|
-
if (
|
|
17558
|
+
else if (holds === "passage") yield passage(value);
|
|
17559
|
+
else if (holds === "markup") yield {
|
|
17454
17560
|
kind: "text",
|
|
17455
17561
|
text: value,
|
|
17456
|
-
offset:
|
|
17562
|
+
offset: at,
|
|
17457
17563
|
where: `In the ${param.name} of {${macro}}: `
|
|
17458
17564
|
};
|
|
17459
17565
|
}
|
|
@@ -17480,10 +17586,12 @@ function locate(text, part, from) {
|
|
|
17480
17586
|
var WIDGET_PARAMETERS = [{
|
|
17481
17587
|
name: "name",
|
|
17482
17588
|
type: "text",
|
|
17589
|
+
holds: "text",
|
|
17483
17590
|
required: true
|
|
17484
17591
|
}, {
|
|
17485
17592
|
name: "parameters",
|
|
17486
|
-
type: "text"
|
|
17593
|
+
type: "text",
|
|
17594
|
+
holds: "text"
|
|
17487
17595
|
}];
|
|
17488
17596
|
/**
|
|
17489
17597
|
* The widget a {widget} definition's arguments declare: its name and its
|
|
@@ -17643,7 +17751,7 @@ function validateMarkup(passages, options) {
|
|
|
17643
17751
|
report(passage, base + token.start, `${where}Unknown macro {${token.name}}.${didYouMean(token.name, names, (n) => `{${n}}`)}`);
|
|
17644
17752
|
}
|
|
17645
17753
|
};
|
|
17646
|
-
const parametersOf =
|
|
17754
|
+
const parametersOf = options.parametersOf ?? (() => void 0);
|
|
17647
17755
|
/**
|
|
17648
17756
|
* Check `tokens`, the tokens of `src`, which starts at `base` in the
|
|
17649
17757
|
* passage: their macros, the code in them and the markup in their text.
|
|
@@ -17909,12 +18017,13 @@ function collectPassageRefs(content, storeVarMacros, onRef, parametersOf) {
|
|
|
17909
18017
|
withParseCache(() => collectTokenRefs(content, tokensOf(content, false), storeVarMacros, onRef, parametersOf));
|
|
17910
18018
|
}
|
|
17911
18019
|
/**
|
|
17912
|
-
* Report the references in the code that a macro's quoted arguments hold
|
|
17913
|
-
* the condition and `run` action of `{watch}`:
|
|
17914
|
-
* the strings.
|
|
18020
|
+
* Report the references in the code that a macro's quoted arguments hold
|
|
18021
|
+
* (see ParameterDef.holds), the condition and `run` action of `{watch}`:
|
|
18022
|
+
* the argument scan sees only the strings. Only the macros that declare
|
|
18023
|
+
* code in a string have their arguments read.
|
|
17915
18024
|
*/
|
|
17916
18025
|
function scanStringCode(token, params, onRef) {
|
|
17917
|
-
if (!params || !token.rawArgs) return;
|
|
18026
|
+
if (!params || !token.rawArgs || !holdsCode(params)) return;
|
|
17918
18027
|
for (const piece of argPieces(token.rawArgs, 0, params, token.name, "")) if (piece.kind === "code" && piece.inString) scanCode(piece.code, onRef, piece.goal);
|
|
17919
18028
|
}
|
|
17920
18029
|
/** Report the `$var` references in the tokens of `content`. */
|
|
@@ -18221,7 +18330,8 @@ defineMacro({
|
|
|
18221
18330
|
},
|
|
18222
18331
|
{
|
|
18223
18332
|
name: "label",
|
|
18224
|
-
type: "string"
|
|
18333
|
+
type: "string",
|
|
18334
|
+
holds: "markup"
|
|
18225
18335
|
}
|
|
18226
18336
|
],
|
|
18227
18337
|
render(_props, ctx) {
|
|
@@ -18588,6 +18698,7 @@ defineMacro({
|
|
|
18588
18698
|
parameters: [{
|
|
18589
18699
|
name: "label",
|
|
18590
18700
|
type: "text",
|
|
18701
|
+
holds: "markup",
|
|
18591
18702
|
required: true
|
|
18592
18703
|
}],
|
|
18593
18704
|
render({ rawArgs, children = [] }, ctx) {
|
|
@@ -18619,6 +18730,7 @@ defineMacro({
|
|
|
18619
18730
|
parameters: [{
|
|
18620
18731
|
name: "text",
|
|
18621
18732
|
type: "string",
|
|
18733
|
+
holds: "markup",
|
|
18622
18734
|
required: true
|
|
18623
18735
|
}, {
|
|
18624
18736
|
name: "passage",
|
|
@@ -18948,6 +19060,7 @@ defineMacro({
|
|
|
18948
19060
|
parameters: [{
|
|
18949
19061
|
name: "label",
|
|
18950
19062
|
type: "text",
|
|
19063
|
+
holds: "markup",
|
|
18951
19064
|
required: true
|
|
18952
19065
|
}, {
|
|
18953
19066
|
name: "noclose",
|
|
@@ -19494,7 +19607,8 @@ function defineInputMacro(name, type, toValue = (input) => input !== void 0 ? St
|
|
|
19494
19607
|
storeVar: true,
|
|
19495
19608
|
parameters: [VARIABLE_PARAMETER, {
|
|
19496
19609
|
name: "placeholder",
|
|
19497
|
-
type: "string"
|
|
19610
|
+
type: "string",
|
|
19611
|
+
holds: "text"
|
|
19498
19612
|
}],
|
|
19499
19613
|
render(_props, ctx) {
|
|
19500
19614
|
const placeholder = ctx.args.placeholder ?? "";
|
|
@@ -19530,7 +19644,8 @@ defineMacro({
|
|
|
19530
19644
|
storeVar: true,
|
|
19531
19645
|
parameters: [VARIABLE_PARAMETER, {
|
|
19532
19646
|
name: "label",
|
|
19533
|
-
type: "text"
|
|
19647
|
+
type: "text",
|
|
19648
|
+
holds: "text"
|
|
19534
19649
|
}],
|
|
19535
19650
|
render(_props, ctx) {
|
|
19536
19651
|
const label = ctx.args.label ?? "";
|
|
@@ -19561,11 +19676,13 @@ defineMacro({
|
|
|
19561
19676
|
{
|
|
19562
19677
|
name: "value",
|
|
19563
19678
|
type: "text",
|
|
19679
|
+
holds: "text",
|
|
19564
19680
|
required: true
|
|
19565
19681
|
},
|
|
19566
19682
|
{
|
|
19567
19683
|
name: "label",
|
|
19568
|
-
type: "text"
|
|
19684
|
+
type: "text",
|
|
19685
|
+
holds: "text"
|
|
19569
19686
|
}
|
|
19570
19687
|
],
|
|
19571
19688
|
render(_props, ctx) {
|
|
@@ -19985,6 +20102,7 @@ defineMacro({
|
|
|
19985
20102
|
parameters: [{
|
|
19986
20103
|
name: "condition",
|
|
19987
20104
|
type: "string",
|
|
20105
|
+
holds: "expression",
|
|
19988
20106
|
required: true
|
|
19989
20107
|
}, {
|
|
19990
20108
|
name: "options",
|
|
@@ -19992,19 +20110,23 @@ defineMacro({
|
|
|
19992
20110
|
parameters: [
|
|
19993
20111
|
{
|
|
19994
20112
|
name: "goto",
|
|
19995
|
-
type: "string"
|
|
20113
|
+
type: "string",
|
|
20114
|
+
holds: "passage"
|
|
19996
20115
|
},
|
|
19997
20116
|
{
|
|
19998
20117
|
name: "dialog",
|
|
19999
|
-
type: "string"
|
|
20118
|
+
type: "string",
|
|
20119
|
+
holds: "passage"
|
|
20000
20120
|
},
|
|
20001
20121
|
{
|
|
20002
20122
|
name: "run",
|
|
20003
|
-
type: "string"
|
|
20123
|
+
type: "string",
|
|
20124
|
+
holds: "statements"
|
|
20004
20125
|
},
|
|
20005
20126
|
{
|
|
20006
20127
|
name: "name",
|
|
20007
|
-
type: "string"
|
|
20128
|
+
type: "string",
|
|
20129
|
+
holds: "text"
|
|
20008
20130
|
},
|
|
20009
20131
|
{
|
|
20010
20132
|
name: "priority",
|
|
@@ -20033,6 +20155,7 @@ defineMacro({
|
|
|
20033
20155
|
parameters: [{
|
|
20034
20156
|
name: "name",
|
|
20035
20157
|
type: "text",
|
|
20158
|
+
holds: "text",
|
|
20036
20159
|
required: true
|
|
20037
20160
|
}],
|
|
20038
20161
|
render(_props, ctx) {
|
|
@@ -20081,11 +20204,10 @@ function stopWithErrors(errors) {
|
|
|
20081
20204
|
*/
|
|
20082
20205
|
function markupErrors(storyData, only) {
|
|
20083
20206
|
const macros = getMacroRegistry();
|
|
20084
|
-
const parameters = new Map(macros.map((m) => [m.name.toLowerCase(), m.parameters]));
|
|
20085
20207
|
return validateMarkup(storyData.passages.values(), {
|
|
20086
20208
|
isKnownMacro: (name) => !!getMacro(name) || isSubMacro(name) || !!getWidget(name),
|
|
20087
20209
|
macroNames: macros.map((m) => m.name),
|
|
20088
|
-
parametersOf: (
|
|
20210
|
+
parametersOf: parameterLookup(macros),
|
|
20089
20211
|
only
|
|
20090
20212
|
}).map(formatDiagnostic);
|
|
20091
20213
|
}
|