@rohal12/spindle-lsp 0.15.15 → 0.15.17
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/bin.js +490 -277
- package/dist/bin.js.map +4 -4
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -55,7 +55,7 @@ var VERSION;
|
|
|
55
55
|
var init_version = __esm({
|
|
56
56
|
"src/version.ts"() {
|
|
57
57
|
"use strict";
|
|
58
|
-
VERSION = false ? pkg.version : "0.15.
|
|
58
|
+
VERSION = false ? pkg.version : "0.15.17";
|
|
59
59
|
}
|
|
60
60
|
});
|
|
61
61
|
|
|
@@ -10488,10 +10488,30 @@ var init_config_loader = __esm({
|
|
|
10488
10488
|
}
|
|
10489
10489
|
});
|
|
10490
10490
|
|
|
10491
|
+
// src/core/workspace/source-order.ts
|
|
10492
|
+
import { pathToFileURL } from "node:url";
|
|
10493
|
+
function compareSourceUris(left, right) {
|
|
10494
|
+
const a = left.split("/").map(decodeURIComponent);
|
|
10495
|
+
const b = right.split("/").map(decodeURIComponent);
|
|
10496
|
+
for (let i2 = 0; i2 < Math.min(a.length, b.length); i2++) {
|
|
10497
|
+
const order = Buffer.compare(Buffer.from(a[i2], "utf8"), Buffer.from(b[i2], "utf8"));
|
|
10498
|
+
if (order !== 0) return order;
|
|
10499
|
+
}
|
|
10500
|
+
return a.length - b.length;
|
|
10501
|
+
}
|
|
10502
|
+
function compareSourcePaths(left, right) {
|
|
10503
|
+
return compareSourceUris(pathToFileURL(left).href, pathToFileURL(right).href);
|
|
10504
|
+
}
|
|
10505
|
+
var init_source_order = __esm({
|
|
10506
|
+
"src/core/workspace/source-order.ts"() {
|
|
10507
|
+
"use strict";
|
|
10508
|
+
}
|
|
10509
|
+
});
|
|
10510
|
+
|
|
10491
10511
|
// src/core/workspace/macro-sources.ts
|
|
10492
10512
|
import { existsSync as existsSync2, lstatSync, readdir, readFileSync as readFileSync2 } from "node:fs";
|
|
10493
10513
|
import { dirname, isAbsolute, join as join2, relative, resolve as resolve2, sep } from "node:path";
|
|
10494
|
-
import { pathToFileURL } from "node:url";
|
|
10514
|
+
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
10495
10515
|
function isExcludedSegment(segment) {
|
|
10496
10516
|
return EXCLUDED_DIRS.includes(segment) || segment.startsWith(".") && segment !== "." && segment !== "..";
|
|
10497
10517
|
}
|
|
@@ -10535,7 +10555,7 @@ async function findProjectFiles(root, pattern) {
|
|
|
10535
10555
|
}
|
|
10536
10556
|
}
|
|
10537
10557
|
});
|
|
10538
|
-
return files.filter((file2) => canDiscoverProjectPath(file2, root));
|
|
10558
|
+
return files.filter((file2) => canDiscoverProjectPath(file2, root)).sort(compareSourcePaths);
|
|
10539
10559
|
}
|
|
10540
10560
|
function isWithin(path2, dir) {
|
|
10541
10561
|
const rel = relative(dir, path2);
|
|
@@ -10557,7 +10577,7 @@ function findProjectRoot(dir) {
|
|
|
10557
10577
|
}
|
|
10558
10578
|
async function addProjectMacroSources(contents, dir) {
|
|
10559
10579
|
for (const filePath of await findMacroSourceFiles(findProjectRoot(dir))) {
|
|
10560
|
-
const uri =
|
|
10580
|
+
const uri = pathToFileURL2(filePath).toString();
|
|
10561
10581
|
if (contents.has(uri)) continue;
|
|
10562
10582
|
try {
|
|
10563
10583
|
contents.set(uri, readFileSync2(filePath, "utf-8"));
|
|
@@ -10571,6 +10591,7 @@ var init_macro_sources = __esm({
|
|
|
10571
10591
|
"use strict";
|
|
10572
10592
|
init_index_min();
|
|
10573
10593
|
init_config_loader();
|
|
10594
|
+
init_source_order();
|
|
10574
10595
|
MACRO_SOURCE_PATTERN = /\.[cm]?[jt]s$/i;
|
|
10575
10596
|
MACRO_SOURCE_GLOB = "**/*.{js,cjs,mjs,ts,cts,mts}";
|
|
10576
10597
|
EXCLUDED_DIRS = ["node_modules", "dist", "build"];
|
|
@@ -10600,7 +10621,7 @@ async function resolveFiles(pattern, cwd) {
|
|
|
10600
10621
|
return [...new Set(await findProjectFiles(directory, input))];
|
|
10601
10622
|
}
|
|
10602
10623
|
function readFileContents(files) {
|
|
10603
|
-
return new Map(files.map((file2) => [file2, readFileSync3(file2, "utf8")]));
|
|
10624
|
+
return new Map([...files].sort(compareSourcePaths).map((file2) => [file2, readFileSync3(file2, "utf8")]));
|
|
10604
10625
|
}
|
|
10605
10626
|
async function resolveInputs(patterns, cwd) {
|
|
10606
10627
|
const files = await Promise.all(patterns.map((pattern) => resolveFiles(pattern, cwd)));
|
|
@@ -10614,6 +10635,7 @@ var init_file_inputs = __esm({
|
|
|
10614
10635
|
"src/core/workspace/file-inputs.ts"() {
|
|
10615
10636
|
"use strict";
|
|
10616
10637
|
init_macro_sources();
|
|
10638
|
+
init_source_order();
|
|
10617
10639
|
}
|
|
10618
10640
|
});
|
|
10619
10641
|
|
|
@@ -14645,6 +14667,31 @@ function parseWithAst(src, goal) {
|
|
|
14645
14667
|
}
|
|
14646
14668
|
}
|
|
14647
14669
|
}
|
|
14670
|
+
function parseReferencePath(src) {
|
|
14671
|
+
const { ast } = parseWithAst(src, "expression");
|
|
14672
|
+
let node = ast.type === "ChainExpression" ? ast.expression : ast;
|
|
14673
|
+
let nested = false;
|
|
14674
|
+
while (node.type === "MemberExpression") {
|
|
14675
|
+
node = node.object;
|
|
14676
|
+
nested = true;
|
|
14677
|
+
}
|
|
14678
|
+
if (node.type !== "Identifier") return null;
|
|
14679
|
+
const sigil = sigilOf(node, src);
|
|
14680
|
+
if (!sigil || node.start !== 0) return null;
|
|
14681
|
+
return {
|
|
14682
|
+
sigil: sigil[0],
|
|
14683
|
+
name: sigil[1],
|
|
14684
|
+
nested
|
|
14685
|
+
};
|
|
14686
|
+
}
|
|
14687
|
+
function parseMemberIdentifier(src) {
|
|
14688
|
+
const { ast } = parseWithAst(`x.${src}`, "expression");
|
|
14689
|
+
if (ast.type !== "MemberExpression" || ast.computed) return null;
|
|
14690
|
+
const object3 = ast.object;
|
|
14691
|
+
const property = ast.property;
|
|
14692
|
+
if (object3.type !== "Identifier" || object3.start !== 0 || object3.end !== 1 || property.type !== "Identifier" || property.start !== 2 || property.end !== src.length + 2) return null;
|
|
14693
|
+
return property.name;
|
|
14694
|
+
}
|
|
14648
14695
|
function parseAst(src, goal, percentAt, transientsRead) {
|
|
14649
14696
|
try {
|
|
14650
14697
|
const p = tokenizerAt(src, 0, goal);
|
|
@@ -15194,9 +15241,13 @@ function indexCodeEnds(input) {
|
|
|
15194
15241
|
if (open !== void 0) possible.add(open);
|
|
15195
15242
|
} else if (/['"`/\\]/.test(c)) uncertain();
|
|
15196
15243
|
}
|
|
15197
|
-
return (start) => {
|
|
15198
|
-
if (start > lastBrace) return -1;
|
|
15199
|
-
|
|
15244
|
+
return (start, codeStart = start, limit = input.length) => {
|
|
15245
|
+
if (start > lastBrace || codeStart >= limit) return -1;
|
|
15246
|
+
const source = limit === input.length ? input : input.slice(0, limit);
|
|
15247
|
+
if (input[start - 1] !== "{" || possible.has(start - 1) || input.slice(start, codeStart).includes("{")) return defaultCodeEnd.closeBrace(source, codeStart, start);
|
|
15248
|
+
const base = Math.max(0, codeStart - 1);
|
|
15249
|
+
const end = parsedCodeEnd(source.slice(base), codeStart - base, "expression");
|
|
15250
|
+
return end < 0 ? -1 : base + end;
|
|
15200
15251
|
};
|
|
15201
15252
|
}
|
|
15202
15253
|
function isCodeAttribute(name) {
|
|
@@ -15232,10 +15283,14 @@ function splitSigilTemplate(template, incomplete = false) {
|
|
|
15232
15283
|
return parts;
|
|
15233
15284
|
}
|
|
15234
15285
|
function run$1(source, startRule, options, completion = false) {
|
|
15235
|
-
const hooks =
|
|
15286
|
+
const hooks = {
|
|
15236
15287
|
...defaultHooks,
|
|
15237
15288
|
...options.hooks
|
|
15238
|
-
}
|
|
15289
|
+
};
|
|
15290
|
+
if (!options.hooks?.closeBrace) {
|
|
15291
|
+
const codeEnd = indexCodeEnds(source);
|
|
15292
|
+
hooks.closeBrace = (_input, codeStart, lenientStart) => codeEnd(lenientStart, codeStart);
|
|
15293
|
+
}
|
|
15239
15294
|
try {
|
|
15240
15295
|
return peg$parse(source, {
|
|
15241
15296
|
startRule,
|
|
@@ -15290,7 +15345,7 @@ function pairingError(position, error48) {
|
|
|
15290
15345
|
const { line, column } = position(error48.start);
|
|
15291
15346
|
return new MarkupError(error48.message, error48.start, line, column, error48.code, error48.end, error48.data);
|
|
15292
15347
|
}
|
|
15293
|
-
function tokenizeMarkup(source, options = {}) {
|
|
15348
|
+
function tokenizeMarkup$1(source, options = {}) {
|
|
15294
15349
|
return run$1(source, "Tokens", options);
|
|
15295
15350
|
}
|
|
15296
15351
|
function parseSelectors(source, at3 = 0) {
|
|
@@ -15300,7 +15355,7 @@ function parseSelectors(source, at3 = 0) {
|
|
|
15300
15355
|
end: at3 + found.end
|
|
15301
15356
|
};
|
|
15302
15357
|
}
|
|
15303
|
-
function tokenizeMarkupTolerant(source, options = {}) {
|
|
15358
|
+
function tokenizeMarkupTolerant$1(source, options = {}) {
|
|
15304
15359
|
const { tokens: tokens2, errors } = scanMarkupTolerant(source, options);
|
|
15305
15360
|
return {
|
|
15306
15361
|
tokens: tokens2,
|
|
@@ -15312,15 +15367,18 @@ function scanMarkupTolerant(source, options = {}, completion = false) {
|
|
|
15312
15367
|
const errors = [];
|
|
15313
15368
|
const damage = [];
|
|
15314
15369
|
let position;
|
|
15370
|
+
const codeEnd = indexCodeEnds(source);
|
|
15371
|
+
const customCloseBrace = options.hooks?.closeBrace;
|
|
15315
15372
|
const lastBrace = source.lastIndexOf("}");
|
|
15316
|
-
const { closeBrace } = {
|
|
15317
|
-
...defaultHooks,
|
|
15318
|
-
...options.hooks
|
|
15319
|
-
};
|
|
15320
15373
|
const attempt = (text3, base2) => {
|
|
15321
15374
|
const hooks = {
|
|
15322
15375
|
...options.hooks,
|
|
15323
|
-
closeBrace: (input, codeStart, lenientStart) =>
|
|
15376
|
+
closeBrace: (input, codeStart, lenientStart) => {
|
|
15377
|
+
if (base2 + Math.min(codeStart, lenientStart) > lastBrace) return -1;
|
|
15378
|
+
if (customCloseBrace) return customCloseBrace(input, codeStart, lenientStart);
|
|
15379
|
+
const end = codeEnd(base2 + lenientStart, base2 + codeStart, base2 + text3.length);
|
|
15380
|
+
return end < 0 ? -1 : end - base2;
|
|
15381
|
+
}
|
|
15324
15382
|
};
|
|
15325
15383
|
try {
|
|
15326
15384
|
return run$1(text3, "Tokens", {
|
|
@@ -15401,6 +15459,20 @@ function createListeners() {
|
|
|
15401
15459
|
}
|
|
15402
15460
|
};
|
|
15403
15461
|
}
|
|
15462
|
+
function variableNameError(name, label2 = name) {
|
|
15463
|
+
return name === "__proto__" ? `"${label2}" cannot be used as a variable name (${RESERVED_NAME} is reserved)` : void 0;
|
|
15464
|
+
}
|
|
15465
|
+
function ownEntries(sources, keep = () => true) {
|
|
15466
|
+
const record2 = /* @__PURE__ */ Object.create(null);
|
|
15467
|
+
for (const source of sources) {
|
|
15468
|
+
if (!source) continue;
|
|
15469
|
+
for (const key of Object.keys(source)) {
|
|
15470
|
+
const value = source[key];
|
|
15471
|
+
if (keep(value)) record2[key] = value;
|
|
15472
|
+
}
|
|
15473
|
+
}
|
|
15474
|
+
return record2;
|
|
15475
|
+
}
|
|
15404
15476
|
function isWhitespace(ch) {
|
|
15405
15477
|
return /\s/.test(ch);
|
|
15406
15478
|
}
|
|
@@ -15721,6 +15793,51 @@ function passageTarget(arg) {
|
|
|
15721
15793
|
name
|
|
15722
15794
|
};
|
|
15723
15795
|
}
|
|
15796
|
+
function readBoundVariable(rawArgs) {
|
|
15797
|
+
const src = rawArgs.trim();
|
|
15798
|
+
const first = terms(src)[0];
|
|
15799
|
+
return first ? slice(src, first) : "";
|
|
15800
|
+
}
|
|
15801
|
+
function parseBoundVariable(rawArgs) {
|
|
15802
|
+
const term = readBoundVariable(rawArgs);
|
|
15803
|
+
if (!term) return null;
|
|
15804
|
+
const lead = rawArgs.length - rawArgs.trimStart().length;
|
|
15805
|
+
const offsets = [];
|
|
15806
|
+
for (let i2 = 0; i2 < term.length; i2++) if (term[i2] !== '"' && term[i2] !== "'") offsets.push(lead + i2);
|
|
15807
|
+
const firstToken = term.replace(/["']/g, "");
|
|
15808
|
+
const kind = {
|
|
15809
|
+
"%": "transient variables",
|
|
15810
|
+
_: "temporary variables",
|
|
15811
|
+
"@": "locals"
|
|
15812
|
+
}[firstToken.charAt(0)];
|
|
15813
|
+
if (kind) throw new Error(`${kind} (${firstToken}) cannot be bound to input macros`);
|
|
15814
|
+
const explicitSigil = firstToken.startsWith("$");
|
|
15815
|
+
if (!explicitSigil && firstToken.split(".")[0].includes("\\")) throw new Error("Escaped binding identifiers require a literal $ story-variable sigil");
|
|
15816
|
+
const segments = firstToken.replace(/^\$/, "").split(".").map((segment, index) => {
|
|
15817
|
+
if (!segment.includes("\\")) return segment;
|
|
15818
|
+
if (index > 0) {
|
|
15819
|
+
const name = parseMemberIdentifier(segment);
|
|
15820
|
+
if (name === null) throw new Error("Invalid bound identifier");
|
|
15821
|
+
return name;
|
|
15822
|
+
}
|
|
15823
|
+
const reference = parseReferencePath(`$${segment}`);
|
|
15824
|
+
if (!reference || reference.nested) throw new Error("Invalid bound identifier");
|
|
15825
|
+
return reference.name;
|
|
15826
|
+
});
|
|
15827
|
+
if (segments.includes("__proto__")) throw new Error(`"$${segments.join(".")}" cannot be bound: ${RESERVED_NAME} is reserved`);
|
|
15828
|
+
const rootStart = explicitSigil ? 1 : 0;
|
|
15829
|
+
const rootEnd = firstToken.indexOf(".", rootStart);
|
|
15830
|
+
const nameEnd = rootEnd < 0 ? firstToken.length : rootEnd;
|
|
15831
|
+
return {
|
|
15832
|
+
name: segments[0],
|
|
15833
|
+
path: segments.slice(1),
|
|
15834
|
+
explicitSigil,
|
|
15835
|
+
start: offsets[0] ?? lead,
|
|
15836
|
+
end: offsets.length ? offsets[offsets.length - 1] + 1 : lead,
|
|
15837
|
+
nameStart: offsets[rootStart] ?? lead + rootStart,
|
|
15838
|
+
nameEnd: offsets[nameEnd - 1] === void 0 ? lead : offsets[nameEnd - 1] + 1
|
|
15839
|
+
};
|
|
15840
|
+
}
|
|
15724
15841
|
function macroArgumentSpans(rawArgs, parameters) {
|
|
15725
15842
|
const spans = /* @__PURE__ */ new Map();
|
|
15726
15843
|
parseMacroArgs(rawArgs, parameters, void 0, spans);
|
|
@@ -15745,20 +15862,6 @@ function macroArgumentSpans(rawArgs, parameters) {
|
|
|
15745
15862
|
function subMacroParameters(name) {
|
|
15746
15863
|
return SUB_MACRO_PARAMETERS.get(name.toLowerCase());
|
|
15747
15864
|
}
|
|
15748
|
-
function variableNameError(name, label2 = name) {
|
|
15749
|
-
return name === "__proto__" ? `"${label2}" cannot be used as a variable name (${RESERVED_NAME} is reserved)` : void 0;
|
|
15750
|
-
}
|
|
15751
|
-
function ownEntries(sources, keep = () => true) {
|
|
15752
|
-
const record2 = /* @__PURE__ */ Object.create(null);
|
|
15753
|
-
for (const source of sources) {
|
|
15754
|
-
if (!source) continue;
|
|
15755
|
-
for (const key of Object.keys(source)) {
|
|
15756
|
-
const value = source[key];
|
|
15757
|
-
if (keep(value)) record2[key] = value;
|
|
15758
|
-
}
|
|
15759
|
-
}
|
|
15760
|
-
return record2;
|
|
15761
|
-
}
|
|
15762
15865
|
function withParseCache(fn) {
|
|
15763
15866
|
const outer = parses;
|
|
15764
15867
|
parses = /* @__PURE__ */ new Map();
|
|
@@ -15794,8 +15897,11 @@ function widgetParameters(params, holds = {}) {
|
|
|
15794
15897
|
...hasOwn(holds, name) ? { holds: holds[name] } : {}
|
|
15795
15898
|
}));
|
|
15796
15899
|
}
|
|
15900
|
+
function usesBuiltinSemantics(name, parametersOf2) {
|
|
15901
|
+
return parametersOf2.widget?.(name) === void 0 && parametersOf2.source?.(name) !== "user";
|
|
15902
|
+
}
|
|
15797
15903
|
function executesRawBody(name, parametersOf2) {
|
|
15798
|
-
return isRawMacro(name,
|
|
15904
|
+
return isRawMacro(name, false) && usesBuiltinSemantics(name, parametersOf2);
|
|
15799
15905
|
}
|
|
15800
15906
|
function withHolds(params, holds) {
|
|
15801
15907
|
return params.map((param) => {
|
|
@@ -15816,12 +15922,13 @@ function parameterLookup(macros) {
|
|
|
15816
15922
|
for (const { name, parameters: params, interpolate, widget, source } of macros) {
|
|
15817
15923
|
sources.set(name, source ?? "user");
|
|
15818
15924
|
if (params) parameters.set(name, withHolds(params, holdsByDefault(interpolate)));
|
|
15925
|
+
else parameters.delete(name);
|
|
15819
15926
|
if (widget) widgets.set(name, widgetParameters(widget.params, widget.holds) ?? []);
|
|
15820
15927
|
}
|
|
15821
15928
|
const lookup = (name) => {
|
|
15822
15929
|
if (widgets.has(name)) return void 0;
|
|
15823
15930
|
let params = parameters.get(name);
|
|
15824
|
-
if (!params) {
|
|
15931
|
+
if (!params && sources.get(name) !== "user") {
|
|
15825
15932
|
const sub = subMacroParameters(name);
|
|
15826
15933
|
if (sub) parameters.set(name, params = withHolds(sub, "text"));
|
|
15827
15934
|
}
|
|
@@ -15897,7 +16004,7 @@ function* codeAndText(src, tokens2, parametersOf2) {
|
|
|
15897
16004
|
continue;
|
|
15898
16005
|
}
|
|
15899
16006
|
const args2 = token.rawArgs;
|
|
15900
|
-
if (PASSAGE_BODIES.has(name) &&
|
|
16007
|
+
if (PASSAGE_BODIES.has(name) && usesBuiltinSemantics(name, parametersOf2)) {
|
|
15901
16008
|
const close = closeOfTextBody(t, name);
|
|
15902
16009
|
if (close > t + 1) {
|
|
15903
16010
|
const text3 = src.slice(token.end, tokens2[close].start);
|
|
@@ -15915,7 +16022,7 @@ function* codeAndText(src, tokens2, parametersOf2) {
|
|
|
15915
16022
|
if (!args2) continue;
|
|
15916
16023
|
const label2 = `{${token.name} ${args2}}`;
|
|
15917
16024
|
const argsAt = token.argsStart;
|
|
15918
|
-
if (CONDITION_MACROS.has(name) &&
|
|
16025
|
+
if (CONDITION_MACROS.has(name) && usesBuiltinSemantics(name, parametersOf2)) {
|
|
15919
16026
|
yield {
|
|
15920
16027
|
kind: "code",
|
|
15921
16028
|
code: args2,
|
|
@@ -16179,7 +16286,7 @@ function locate(text3, part, from) {
|
|
|
16179
16286
|
function completionContext(source, cursor, macros = []) {
|
|
16180
16287
|
if (!Number.isInteger(cursor) || cursor < 0 || cursor > source.length) throw new RangeError("cursor must be a UTF-16 offset within source");
|
|
16181
16288
|
const parametersOf2 = parameterLookup(macros);
|
|
16182
|
-
const codeContext = (code, goal, map2) => {
|
|
16289
|
+
const codeContext = (code, goal, map2, containers) => {
|
|
16183
16290
|
const probe = code.length + 1;
|
|
16184
16291
|
let executable = false;
|
|
16185
16292
|
lexJs(code + " __spindle_cursor__", {
|
|
@@ -16199,15 +16306,16 @@ function completionContext(source, cursor, macros = []) {
|
|
|
16199
16306
|
goal,
|
|
16200
16307
|
offset: offset2,
|
|
16201
16308
|
cursor: code.length,
|
|
16309
|
+
...containers.length ? { containers } : {},
|
|
16202
16310
|
...offsets.some((at3, i2) => at3 !== offset2 + i2) ? { sourceOffsets: offsets } : {}
|
|
16203
16311
|
};
|
|
16204
16312
|
};
|
|
16205
|
-
const read = (src, map2, text3 = false, depth = 0, sigilsOnly = false) => {
|
|
16313
|
+
const read = (src, map2, text3 = false, depth = 0, sigilsOnly = false, containers = []) => {
|
|
16206
16314
|
if (depth >= 64) return LITERAL;
|
|
16207
16315
|
if (sigilsOnly) {
|
|
16208
16316
|
let at3 = 0;
|
|
16209
16317
|
for (const part of splitSigilTemplate(src, true)) if ("expr" in part) {
|
|
16210
|
-
if (at3 + 1 + part.expr.length === src.length) return codeContext(part.expr, "expression", (i2) => map2(at3 + 1 + i2));
|
|
16318
|
+
if (at3 + 1 + part.expr.length === src.length) return codeContext(part.expr, "expression", (i2) => map2(at3 + 1 + i2), containers);
|
|
16211
16319
|
at3 += part.expr.length + 2;
|
|
16212
16320
|
} else at3 += ("text" in part ? part.text : part.verbatim).length;
|
|
16213
16321
|
return LITERAL;
|
|
@@ -16218,13 +16326,21 @@ function completionContext(source, cursor, macros = []) {
|
|
|
16218
16326
|
});
|
|
16219
16327
|
const token = tokens2[tokens2.length - 1];
|
|
16220
16328
|
if (!token || token.end !== src.length) return LITERAL;
|
|
16221
|
-
const codeAt = (code, at3, goal = "expression") => codeContext(code, goal, (i2) => map2(at3 + i2));
|
|
16222
|
-
const nested = (value, at3, offsets, onlySigils = false) => read(value, (i2) => map2(offsets?.[i2] ?? at3 + i2), true, depth + 1, onlySigils);
|
|
16329
|
+
const codeAt = (code, at3, goal = "expression") => codeContext(code, goal, (i2) => map2(at3 + i2), containers);
|
|
16330
|
+
const nested = (value, at3, offsets, onlySigils = false, container) => read(value, (i2) => map2(offsets?.[i2] ?? at3 + i2), true, depth + 1, onlySigils, container ? [...containers, container] : containers);
|
|
16223
16331
|
if (token.type === "variable" && token.nameEnd === src.length) return codeAt(src.slice(token.nameStart - 1), token.nameStart - 1);
|
|
16224
16332
|
if (token.type === "expression" && token.expressionEnd === src.length) return codeAt(token.expression, token.expressionStart);
|
|
16225
16333
|
if (token.type === "html") {
|
|
16226
|
-
for (const { name, value, at: at3 } of attributeValues(src, token)) if (at3 + value.length === src.length)
|
|
16227
|
-
|
|
16334
|
+
for (const { name, value, at: at3 } of attributeValues(src, token)) if (at3 + value.length === src.length) {
|
|
16335
|
+
const span = token.attributeSpans.find((span2) => span2.valueStart === at3);
|
|
16336
|
+
return nested(value, at3, void 0, isCodeAttribute(name), {
|
|
16337
|
+
kind: "attribute",
|
|
16338
|
+
name,
|
|
16339
|
+
quote: span?.quote ?? null,
|
|
16340
|
+
code: isCodeAttribute(name)
|
|
16341
|
+
});
|
|
16342
|
+
}
|
|
16343
|
+
} else if (token.type === "link" && token.displayEnd === src.length) return nested(token.display, token.displayStart, void 0, false, { kind: "link-label" });
|
|
16228
16344
|
else if (token.type === "text" && !token.comment) {
|
|
16229
16345
|
const opener = tokens2[tokens2.length - 2];
|
|
16230
16346
|
if (opener?.type === "macro" && !opener.isClose && executesRawBody(opener.name, parametersOf2)) return codeAt(token.value, token.start, "statements");
|
|
@@ -16232,7 +16348,7 @@ function completionContext(source, cursor, macros = []) {
|
|
|
16232
16348
|
const name = token.name.toLowerCase();
|
|
16233
16349
|
const args2 = token.rawArgs;
|
|
16234
16350
|
const widget = parametersOf2.widget?.(name);
|
|
16235
|
-
if (
|
|
16351
|
+
if (usesBuiltinSemantics(name, parametersOf2) && [
|
|
16236
16352
|
"if",
|
|
16237
16353
|
"elseif",
|
|
16238
16354
|
"case"
|
|
@@ -16246,9 +16362,14 @@ function completionContext(source, cursor, macros = []) {
|
|
|
16246
16362
|
if (scanStringLiteral(raw2, 0).closed) return LITERAL;
|
|
16247
16363
|
const value = escapes === "javascript" ? stringLiteralValue(raw2 + raw2[0]) : quoted.value;
|
|
16248
16364
|
if (value == null) return LITERAL;
|
|
16365
|
+
const container = {
|
|
16366
|
+
kind: "string",
|
|
16367
|
+
quote: raw2[0],
|
|
16368
|
+
escapes
|
|
16369
|
+
};
|
|
16249
16370
|
const offsets = escapeOffsets(raw2.slice(1), at4 + 1, value, escapes);
|
|
16250
|
-
if (holds === "expression" || holds === "statements") return codeContext(value, holds, (i2) => map2(offsets?.[i2] ?? at4 + 1 + i2));
|
|
16251
|
-
return holds === "markup" ? nested(value, at4 + 1, offsets) : LITERAL;
|
|
16371
|
+
if (holds === "expression" || holds === "statements") return codeContext(value, holds, (i2) => map2(offsets?.[i2] ?? at4 + 1 + i2), [...containers, container]);
|
|
16372
|
+
return holds === "markup" ? nested(value, at4 + 1, offsets, false, container) : LITERAL;
|
|
16252
16373
|
};
|
|
16253
16374
|
if (widget) {
|
|
16254
16375
|
const spans2 = splitArgSpans(args2);
|
|
@@ -16368,7 +16489,7 @@ function widgetDefinitions$1(passages, parametersOf2 = registeredParameters) {
|
|
|
16368
16489
|
if (passage.name !== "StoryInit" && !passage.tags?.includes("widget")) continue;
|
|
16369
16490
|
const open = [];
|
|
16370
16491
|
const done = [];
|
|
16371
|
-
for (const token of tokenizeMarkupTolerant(passage.content, { hooks }).tokens) if (token.type === "macro" && token.name.toLowerCase() === "widget") {
|
|
16492
|
+
for (const token of tokenizeMarkupTolerant$1(passage.content, { hooks }).tokens) if (token.type === "macro" && token.name.toLowerCase() === "widget") {
|
|
16372
16493
|
if (!token.isClose) open.push({
|
|
16373
16494
|
token,
|
|
16374
16495
|
isBlock: false
|
|
@@ -16507,7 +16628,7 @@ function validateMarkup(passages, options) {
|
|
|
16507
16628
|
continue;
|
|
16508
16629
|
}
|
|
16509
16630
|
try {
|
|
16510
|
-
const tokens2 = tokenizeMarkup(passage.content, { hooks });
|
|
16631
|
+
const tokens2 = tokenizeMarkup$1(passage.content, { hooks });
|
|
16511
16632
|
addWidgets(tokens2);
|
|
16512
16633
|
if (!reported) continue;
|
|
16513
16634
|
parseMarkup(passage.content, { hooks });
|
|
@@ -16614,9 +16735,9 @@ function tokensOf(text3, textMode, { tolerant, parametersOf: parametersOf2 } = {
|
|
|
16614
16735
|
text: textMode,
|
|
16615
16736
|
hooks: parametersOf2 && { isRaw: (name) => isRawMacro(name, parametersOf2.widget?.(name) !== void 0) }
|
|
16616
16737
|
};
|
|
16617
|
-
if (tolerant) return tokenizeMarkupTolerant(text3, options).tokens;
|
|
16738
|
+
if (tolerant) return tokenizeMarkupTolerant$1(text3, options).tokens;
|
|
16618
16739
|
try {
|
|
16619
|
-
return tokenizeMarkup(text3, options);
|
|
16740
|
+
return tokenizeMarkup$1(text3, options);
|
|
16620
16741
|
} catch (err) {
|
|
16621
16742
|
if (err instanceof MarkupError) return [];
|
|
16622
16743
|
throw err;
|
|
@@ -16846,6 +16967,29 @@ function scanSelectors(content2, token, at3, emit, options) {
|
|
|
16846
16967
|
storeVarMacros: NO_STORE_VAR_MACROS
|
|
16847
16968
|
});
|
|
16848
16969
|
}
|
|
16970
|
+
function boundReference(token, at3, all) {
|
|
16971
|
+
try {
|
|
16972
|
+
const binding = parseBoundVariable(token.rawArgs);
|
|
16973
|
+
if (!binding || !all && !binding.explicitSigil) return void 0;
|
|
16974
|
+
const mapped = {
|
|
16975
|
+
...binding,
|
|
16976
|
+
start: at3(token.argsStart + binding.start),
|
|
16977
|
+
end: at3(token.argsStart + binding.end),
|
|
16978
|
+
nameStart: at3(token.argsStart + binding.nameStart),
|
|
16979
|
+
nameEnd: at3(token.argsStart + binding.nameEnd)
|
|
16980
|
+
};
|
|
16981
|
+
return {
|
|
16982
|
+
sigil: "$",
|
|
16983
|
+
name: binding.name,
|
|
16984
|
+
path: binding.path,
|
|
16985
|
+
start: mapped.start,
|
|
16986
|
+
end: mapped.end,
|
|
16987
|
+
binding: mapped
|
|
16988
|
+
};
|
|
16989
|
+
} catch {
|
|
16990
|
+
return;
|
|
16991
|
+
}
|
|
16992
|
+
}
|
|
16849
16993
|
function collectTokenRefs(content2, tokens2, at3, emit, options) {
|
|
16850
16994
|
const { storeVarMacros, parametersOf: parametersOf2 } = options;
|
|
16851
16995
|
for (let t = 0; t < tokens2.length; t++) {
|
|
@@ -16873,24 +17017,12 @@ function collectTokenRefs(content2, tokens2, at3, emit, options) {
|
|
|
16873
17017
|
else scanInterpolations(value, valueIn, emit, options);
|
|
16874
17018
|
}
|
|
16875
17019
|
else if (token.type === "macro" && !token.isClose) {
|
|
16876
|
-
|
|
17020
|
+
const binding = storeVarMacros.has(token.name.toLowerCase()) && !parametersOf2.widget?.(token.name) ? boundReference(token, at3, options.all) : void 0;
|
|
17021
|
+
scanArgs(token, parametersOf2, at3, (ref2) => {
|
|
17022
|
+
if (!binding || ref2.start < binding.start || ref2.start >= binding.end) emit(ref2);
|
|
17023
|
+
}, options);
|
|
16877
17024
|
scanSelectors(content2, token, at3, emit, options);
|
|
16878
|
-
if (
|
|
16879
|
-
const lead = token.rawArgs.length - token.rawArgs.trimStart().length;
|
|
16880
|
-
const first = token.rawArgs.trim().split(/\s+/)[0] ?? "";
|
|
16881
|
-
const quoted = QUOTED_VAR_ARG_RE.exec(first);
|
|
16882
|
-
if (quoted) {
|
|
16883
|
-
const [name, ...path2] = quoted[1].split(".");
|
|
16884
|
-
const start = token.argsStart + lead + 1;
|
|
16885
|
-
emit({
|
|
16886
|
-
sigil: "$",
|
|
16887
|
-
name,
|
|
16888
|
-
path: path2,
|
|
16889
|
-
start: at3(start),
|
|
16890
|
-
end: at3(start + 1 + quoted[1].length)
|
|
16891
|
-
});
|
|
16892
|
-
} else if (!/^["'`]/.test(first)) scanCode(first, (i2) => at3(token.argsStart + lead + i2), emit);
|
|
16893
|
-
}
|
|
17025
|
+
if (binding) emit(binding);
|
|
16894
17026
|
if (executesRawBody(token.name, parametersOf2)) {
|
|
16895
17027
|
let close = t + 1;
|
|
16896
17028
|
while (close < tokens2.length) {
|
|
@@ -20983,7 +21115,7 @@ function scanSpindleMarkup(text3) {
|
|
|
20983
21115
|
if (inAttribute) match2.inAttribute = true;
|
|
20984
21116
|
tokens2.push(match2);
|
|
20985
21117
|
};
|
|
20986
|
-
for (const t of tokenizeMarkupTolerant(text3).tokens) if (t.type === "html") {
|
|
21118
|
+
for (const t of tokenizeMarkupTolerant$1(text3).tokens) if (t.type === "html") {
|
|
20987
21119
|
tags.push({
|
|
20988
21120
|
start: t.start,
|
|
20989
21121
|
end: t.end
|
|
@@ -20992,7 +21124,7 @@ function scanSpindleMarkup(text3) {
|
|
|
20992
21124
|
if (attribute.valueStart === void 0 || attribute.valueEnd === void 0) continue;
|
|
20993
21125
|
const value = text3.slice(attribute.valueStart, attribute.valueEnd);
|
|
20994
21126
|
if (!value.includes("{")) continue;
|
|
20995
|
-
for (const inner of tokenizeMarkupTolerant(value, { text: true }).tokens) if (inner.type === "macro" || inner.type === "variable" || inner.type === "expression") push2({
|
|
21127
|
+
for (const inner of tokenizeMarkupTolerant$1(value, { text: true }).tokens) if (inner.type === "macro" || inner.type === "variable" || inner.type === "expression") push2({
|
|
20996
21128
|
start: attribute.valueStart + inner.start,
|
|
20997
21129
|
end: attribute.valueStart + inner.end
|
|
20998
21130
|
}, true);
|
|
@@ -21145,7 +21277,7 @@ function replaceSpindleTokens(html) {
|
|
|
21145
21277
|
}
|
|
21146
21278
|
function closedMacroNames(text3) {
|
|
21147
21279
|
const found = /* @__PURE__ */ new Set();
|
|
21148
|
-
for (const t of tokenizeMarkupTolerant(text3).tokens) if (t.type === "macro" && t.isClose) found.add(t.name.toLowerCase());
|
|
21280
|
+
for (const t of tokenizeMarkupTolerant$1(text3).tokens) if (t.type === "macro" && t.isClose) found.add(t.name.toLowerCase());
|
|
21149
21281
|
return found;
|
|
21150
21282
|
}
|
|
21151
21283
|
function defaultIsBlock(text3, extra = []) {
|
|
@@ -21398,7 +21530,7 @@ function macroTokensByLine(lines) {
|
|
|
21398
21530
|
offset2 += line2.length + 1;
|
|
21399
21531
|
}
|
|
21400
21532
|
let line = 0;
|
|
21401
|
-
for (const token of tokenizeMarkupTolerant(lines.join("\n")).tokens) {
|
|
21533
|
+
for (const token of tokenizeMarkupTolerant$1(lines.join("\n")).tokens) {
|
|
21402
21534
|
if (token.type !== "macro") continue;
|
|
21403
21535
|
while (line + 1 < lines.length && starts[line + 1] <= token.start) line++;
|
|
21404
21536
|
const lineStart = starts[line];
|
|
@@ -21462,7 +21594,7 @@ function verbatimLines(lines) {
|
|
|
21462
21594
|
function wordWrap(text3, maxLen, indent) {
|
|
21463
21595
|
const lines = [];
|
|
21464
21596
|
const inToken = new Array(text3.length).fill(false);
|
|
21465
|
-
for (const token of tokenizeMarkupTolerant(text3).tokens) {
|
|
21597
|
+
for (const token of tokenizeMarkupTolerant$1(text3).tokens) {
|
|
21466
21598
|
if (token.type === "text") continue;
|
|
21467
21599
|
inToken.fill(true, token.start, token.end);
|
|
21468
21600
|
}
|
|
@@ -21491,6 +21623,23 @@ function wordWrap(text3, maxLen, indent) {
|
|
|
21491
21623
|
}
|
|
21492
21624
|
return lines;
|
|
21493
21625
|
}
|
|
21626
|
+
function tokenizationOptions(options) {
|
|
21627
|
+
if (!options.macros) return options;
|
|
21628
|
+
const macros = [...options.macros];
|
|
21629
|
+
const parametersOf2 = parameterLookup(macros);
|
|
21630
|
+
return {
|
|
21631
|
+
...options,
|
|
21632
|
+
hooks: {
|
|
21633
|
+
isRaw: (name) => isRawMacro(name, parametersOf2.widget?.(name) !== void 0),
|
|
21634
|
+
isBlock: blockLookup(macros),
|
|
21635
|
+
branchParents: (name) => branchParents(name, macros),
|
|
21636
|
+
...options.hooks
|
|
21637
|
+
}
|
|
21638
|
+
};
|
|
21639
|
+
}
|
|
21640
|
+
function tokenizeMarkupTolerant(source, options = {}) {
|
|
21641
|
+
return tokenizeMarkupTolerant$1(source, tokenizationOptions(options));
|
|
21642
|
+
}
|
|
21494
21643
|
function validateStoryMarkup(passages, macros, options = {}) {
|
|
21495
21644
|
const list3 = [...passages];
|
|
21496
21645
|
const all = [...macros];
|
|
@@ -21538,10 +21687,12 @@ function widgetDefinitions(passages, macros = []) {
|
|
|
21538
21687
|
}
|
|
21539
21688
|
function referenceOptions(macros, all = false, passages = []) {
|
|
21540
21689
|
const list3 = [...macros];
|
|
21690
|
+
const effective = new NameMap();
|
|
21691
|
+
for (const macro of list3) effective.set(macro.name, macro);
|
|
21541
21692
|
const widgets = effectiveWidgetDefinitions(widgetDefinitions$1(passages, parameterLookup(list3)));
|
|
21542
21693
|
return {
|
|
21543
21694
|
all,
|
|
21544
|
-
storeVarMacros: new Set(
|
|
21695
|
+
storeVarMacros: new Set([...effective.values()].filter((m) => m.storeVar).map((m) => m.name.toLowerCase())),
|
|
21545
21696
|
parametersOf: parameterLookup([...list3, ...definedWidgetMacros(widgets)]),
|
|
21546
21697
|
tolerant: true
|
|
21547
21698
|
};
|
|
@@ -21553,7 +21704,7 @@ function validateVariableReferences(passages, declarations, macros = []) {
|
|
|
21553
21704
|
const list3 = [...passages];
|
|
21554
21705
|
return checkVariableReferences(list3.filter((p) => !p.tags?.some((t) => NOT_MARKUP_TAGS.includes(t))), declarations, referenceOptions(macros, false, list3));
|
|
21555
21706
|
}
|
|
21556
|
-
var __defProp2, __exportAll, SIGIL_SCOPES, SIGIL_CHARS, grammar_shared_default, LB, RB, SIGIL_SCOPES$1, withSelectors, VOID_TAGS, BRANCH_PARENT$1, LINK_SEPARATORS, NO_SELECTORS, EMAIL_AUTOLINK, peg$SyntaxError,
|
|
21707
|
+
var __defProp2, __exportAll, NameMap, NameSet, SIGIL_SCOPES, SIGIL_CHARS, grammar_shared_default, LB, RB, SIGIL_SCOPES$1, withSelectors, VOID_TAGS, BRANCH_PARENT$1, LINK_SEPARATORS, NO_SELECTORS, EMAIL_AUTOLINK, peg$SyntaxError, BLOCK_MACROS, BLOCK_WIDGETS, WIDGETS, DEFINED_BLOCK_MACROS, RAW_BODY_MACROS, BRANCHING, quoteArg, PARAMETER_TYPES, STRING_HOLDS, metadataRegistry, companionParents, last$1, BRANCH_PARENT, lowerName, nameOf, closerOf, closes, astralIdentifierCodes, astralIdentifierStartCodes, nonASCIIidentifierChars, nonASCIIidentifierStartChars, reservedWords, ecma5AndLessKeywords, keywords$1, keywordRelationalOperator, nonASCIIidentifierStart, nonASCIIidentifier, TokenType, beforeExpr, startsExpr, keywords, types$1, lineBreak, lineBreakG, nonASCIIwhitespace, skipWhiteSpace, ref, hasOwnProperty$1, toString, hasOwn$1, isArray, regexpCache, loneSurrogate, Position, SourceLocation, defaultOptions, warnedAboutEcmaVersion, SCOPE_TOP, SCOPE_FUNCTION, SCOPE_ASYNC, SCOPE_GENERATOR, SCOPE_ARROW, SCOPE_SIMPLE_CATCH, SCOPE_SUPER, SCOPE_DIRECT_SUPER, SCOPE_CLASS_STATIC_BLOCK, SCOPE_CLASS_FIELD_INIT, SCOPE_SWITCH, SCOPE_VAR, BIND_NONE, BIND_VAR, BIND_LEXICAL, BIND_FUNCTION, BIND_SIMPLE_CATCH, BIND_OUTSIDE, Parser, prototypeAccessors, pp$9, literal, DestructuringErrors, pp$8, loopLabel, switchLabel, empty$1, FUNC_STATEMENT, FUNC_HANGING_STATEMENT, FUNC_NULLABLE_ID, pp$7, TokContext, types, pp$6, pp$5, empty, pp$4, pp$3, Scope, Node, pp$2, scriptValuesAddedInUnicode, ecma9BinaryProperties, ecma10BinaryProperties, ecma11BinaryProperties, ecma12BinaryProperties, ecma13BinaryProperties, unicodeBinaryProperties, unicodeBinaryPropertiesOfStrings, unicodeGeneralCategoryValues, ecma9ScriptValues, ecma10ScriptValues, ecma11ScriptValues, ecma12ScriptValues, ecma13ScriptValues, unicodeScriptValues, data, ecmaVersion, i, list$2, pp$1, BranchID, RegExpValidationState, CharSetNone, CharSetOk, CharSetString, Token, pp, INVALID_TEMPLATE_ESCAPE_ERROR, OPTIONS, AT_NAME_RE, TRANS_NAME_RE, SIGIL_IDENT_RE, LINE_BREAK_RE, NOT_A_BODY_RE, OPERAND_ENDS, SigilParser, OPENERS, CLOSERS$1, CodeSyntaxError, last, CLOSER, isNode, NAMESPACE_NAME, WORD_RE$2, FLAGS_RE, WORDS_BEFORE_STRING, NON_STRING_QUOTE_PREFIX, memoInput, memo, defaultCodeEnd, defaultHooks, MarkupError, OFFSET_FIELD, listeners, RESERVED_NAME, isArrayIndex, hasOwn, createNamespace, TRAILING_OPERATOR_RE, slice, MacroArgumentError, WORD_RE$1, NUMBER_RE$1, WORD_OR_PUNCT_RE, LEADING_OPERATOR_RE, takesRest, SUB_MACRO_PARAMETERS, parses, CONDITION_MACROS, PASSAGE_BODIES, holdsByDefault, JS_ESCAPE_RE, textPiece, LITERAL, registeredParameters, WIDGET_PARAMETERS, NOT_MARKUP, NOT_MARKUP_TAGS$1, BRANCH_MACROS, didYouMean, PASSAGE_ARGUMENT_HINT, BARE_WORD_RE, NUMBER_RE, IDENT_RE, KEY_RE, ARROW_RE, LINE_END_RE, ARRAY_INDEX_RE, UNSUPPORTED_UNDEFINED, Reader, VAR_PATH_RE, VALID_VAR_TYPES, PRIMITIVE_SAMPLES, UNSUPPORTED_TYPE, NO_STORE_VAR_MACROS, FIELD_PATH_RE, CLOSERS, BLOCK_WORDS, NOT_PARAMETERS, DECLARATIONS, WRITE_RE, MUTATORS, MUTATING_CALL_RE, BEFORE_BINDING, isWordChar, Bindings, CALL_RE, IDENTIFIER_ARGUMENT_RE, WORD_RE, MODIFIER_RE, KEY_START_RE, CONFIG_KEYS, ConfigReader, stringOf, booleanOf, textOf, stringsOf, VOID_ELEMENTS, characterEntities, own, hasOwnProperty, asciiAlpha, asciiAlphanumeric, asciiAtext, asciiDigit, asciiHexDigit, asciiPunctuation, unicodePunctuation, unicodeWhitespace, content$1, EditMap$1, document$1, containerConstruct, attention, autolink, blankLine, blockQuote, characterEscape, characterReference, nonLazyContinuation, codeFenced, codeIndented, furtherStart, codeText, SpliceBuffer, content, continuationConstruct, definition, titleBefore, hardBreakEscape, headingAtx, htmlBlockNames, htmlRawNames, htmlFlow, blankLineBefore, nonLazyContinuationStart, htmlText, labelEnd, resourceConstruct, referenceFullConstruct, referenceCollapsedConstruct, labelStartImage, labelStartLink, lineEnding, thematicBreak, list, listItemPrefixWhitespaceConstruct, indentConstruct, setextUnderline, flow$1, resolver, string$1, text$1, constructs_exports, document, contentInitial, flowInitial, flow, string, text, insideSpan, attentionMarkers, disable, search, alignment, EditMap, DEFAULT_PRETTIER_OPTIONS, SVG_PLACEHOLDERS, SPINDLE_PLACEHOLDERS, PLACEHOLDER_PATTERN, DEFAULT_DEDENTING, WHITESPACE_AS_WRITTEN, LIST_ITEM_REGEX, CODE_FENCE_REGEX, NO_WRAP, NOT_MARKUP_TAGS;
|
|
21557
21708
|
var init_story_variables = __esm({
|
|
21558
21709
|
"node_modules/@rohal12/spindle/dist/pkg/story-variables.js"() {
|
|
21559
21710
|
__defProp2 = Object.defineProperty;
|
|
@@ -21566,6 +21717,38 @@ var init_story_variables = __esm({
|
|
|
21566
21717
|
if (!no_symbols) __defProp2(target, Symbol.toStringTag, { value: "Module" });
|
|
21567
21718
|
return target;
|
|
21568
21719
|
};
|
|
21720
|
+
NameMap = class extends Map {
|
|
21721
|
+
get(name) {
|
|
21722
|
+
return super.get(name.toLowerCase());
|
|
21723
|
+
}
|
|
21724
|
+
set(name, value) {
|
|
21725
|
+
return super.set(name.toLowerCase(), value);
|
|
21726
|
+
}
|
|
21727
|
+
has(name) {
|
|
21728
|
+
return super.has(name.toLowerCase());
|
|
21729
|
+
}
|
|
21730
|
+
delete(name) {
|
|
21731
|
+
return super.delete(name.toLowerCase());
|
|
21732
|
+
}
|
|
21733
|
+
};
|
|
21734
|
+
NameSet = class {
|
|
21735
|
+
constructor(names = []) {
|
|
21736
|
+
this.names = new NameMap();
|
|
21737
|
+
for (const name of names) this.add(name);
|
|
21738
|
+
}
|
|
21739
|
+
add(name) {
|
|
21740
|
+
this.names.set(name, true);
|
|
21741
|
+
}
|
|
21742
|
+
has(name) {
|
|
21743
|
+
return this.names.has(name);
|
|
21744
|
+
}
|
|
21745
|
+
delete(name) {
|
|
21746
|
+
this.names.delete(name);
|
|
21747
|
+
}
|
|
21748
|
+
clear() {
|
|
21749
|
+
this.names.clear();
|
|
21750
|
+
}
|
|
21751
|
+
};
|
|
21569
21752
|
SIGIL_SCOPES = {
|
|
21570
21753
|
$: "variable",
|
|
21571
21754
|
_: "temporary",
|
|
@@ -21700,38 +21883,6 @@ var init_story_variables = __esm({
|
|
|
21700
21883
|
return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
|
|
21701
21884
|
}
|
|
21702
21885
|
};
|
|
21703
|
-
NameMap = class extends Map {
|
|
21704
|
-
get(name) {
|
|
21705
|
-
return super.get(name.toLowerCase());
|
|
21706
|
-
}
|
|
21707
|
-
set(name, value) {
|
|
21708
|
-
return super.set(name.toLowerCase(), value);
|
|
21709
|
-
}
|
|
21710
|
-
has(name) {
|
|
21711
|
-
return super.has(name.toLowerCase());
|
|
21712
|
-
}
|
|
21713
|
-
delete(name) {
|
|
21714
|
-
return super.delete(name.toLowerCase());
|
|
21715
|
-
}
|
|
21716
|
-
};
|
|
21717
|
-
NameSet = class {
|
|
21718
|
-
constructor(names = []) {
|
|
21719
|
-
this.names = new NameMap();
|
|
21720
|
-
for (const name of names) this.add(name);
|
|
21721
|
-
}
|
|
21722
|
-
add(name) {
|
|
21723
|
-
this.names.set(name, true);
|
|
21724
|
-
}
|
|
21725
|
-
has(name) {
|
|
21726
|
-
return this.names.has(name);
|
|
21727
|
-
}
|
|
21728
|
-
delete(name) {
|
|
21729
|
-
this.names.delete(name);
|
|
21730
|
-
}
|
|
21731
|
-
clear() {
|
|
21732
|
-
this.names.clear();
|
|
21733
|
-
}
|
|
21734
|
-
};
|
|
21735
21886
|
BLOCK_MACROS = new NameSet([
|
|
21736
21887
|
"if",
|
|
21737
21888
|
"for",
|
|
@@ -26999,6 +27150,11 @@ var init_story_variables = __esm({
|
|
|
26999
27150
|
OFFSET_FIELD = /^(start|end|[A-Za-z]*(Start|End))$/;
|
|
27000
27151
|
listeners = createListeners();
|
|
27001
27152
|
listeners.subscribe;
|
|
27153
|
+
RESERVED_NAME = "__proto__";
|
|
27154
|
+
isArrayIndex = (key) => /^(?:0|[1-9]\d*)$/.test(key);
|
|
27155
|
+
hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
|
|
27156
|
+
createNamespace = (...sources) => ownEntries(sources);
|
|
27157
|
+
Object.freeze(createNamespace());
|
|
27002
27158
|
TRAILING_OPERATOR_RE = /(?:[-+*/%&|^!~=<>?:,.]|(?:^|[^\w$@.])(?:typeof|void|new|delete|in|instanceof|await|yield))$/;
|
|
27003
27159
|
slice = (src, [start, end]) => src.slice(start, end);
|
|
27004
27160
|
MacroArgumentError = class extends Error {
|
|
@@ -27018,11 +27174,6 @@ var init_story_variables = __esm({
|
|
|
27018
27174
|
holds: "text",
|
|
27019
27175
|
required: true
|
|
27020
27176
|
}]]]);
|
|
27021
|
-
RESERVED_NAME = "__proto__";
|
|
27022
|
-
isArrayIndex = (key) => /^(?:0|[1-9]\d*)$/.test(key);
|
|
27023
|
-
hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
|
|
27024
|
-
createNamespace = (...sources) => ownEntries(sources);
|
|
27025
|
-
Object.freeze(createNamespace());
|
|
27026
27177
|
parses = null;
|
|
27027
27178
|
CONDITION_MACROS = /* @__PURE__ */ new Set([
|
|
27028
27179
|
"if",
|
|
@@ -27435,7 +27586,6 @@ var init_story_variables = __esm({
|
|
|
27435
27586
|
}
|
|
27436
27587
|
};
|
|
27437
27588
|
VAR_PATH_RE = /([$%])(\w+(?:\.\w+)*)/y;
|
|
27438
|
-
QUOTED_VAR_ARG_RE = /^["']\$(\w+(?:\.\w+)*)["']?$/;
|
|
27439
27589
|
VALID_VAR_TYPES = /* @__PURE__ */ new Set([
|
|
27440
27590
|
"number",
|
|
27441
27591
|
"string",
|
|
@@ -31487,7 +31637,7 @@ var init_tooling = __esm({
|
|
|
31487
31637
|
// src/core/workspace/document-store.ts
|
|
31488
31638
|
import { EventEmitter } from "node:events";
|
|
31489
31639
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
31490
|
-
import { pathToFileURL as
|
|
31640
|
+
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
31491
31641
|
function stripBom(text3) {
|
|
31492
31642
|
return text3.charCodeAt(0) === 65279 ? text3.slice(1) : text3;
|
|
31493
31643
|
}
|
|
@@ -31535,7 +31685,7 @@ var init_document_store = __esm({
|
|
|
31535
31685
|
for (const filePath of paths) {
|
|
31536
31686
|
try {
|
|
31537
31687
|
const text3 = readFileSync4(filePath, "utf-8");
|
|
31538
|
-
const uri =
|
|
31688
|
+
const uri = pathToFileURL3(filePath).href;
|
|
31539
31689
|
this.open(uri, text3);
|
|
31540
31690
|
} catch {
|
|
31541
31691
|
}
|
|
@@ -31549,7 +31699,10 @@ var init_document_store = __esm({
|
|
|
31549
31699
|
function buildLineStarts(text3) {
|
|
31550
31700
|
const starts = [0];
|
|
31551
31701
|
for (let i2 = 0; i2 < text3.length; i2++) {
|
|
31552
|
-
if (text3[i2] === "\
|
|
31702
|
+
if (text3[i2] === "\r") {
|
|
31703
|
+
if (text3[i2 + 1] === "\n") i2++;
|
|
31704
|
+
starts.push(i2 + 1);
|
|
31705
|
+
} else if (text3[i2] === "\n") starts.push(i2 + 1);
|
|
31553
31706
|
}
|
|
31554
31707
|
return starts;
|
|
31555
31708
|
}
|
|
@@ -31574,7 +31727,7 @@ function withoutCr(line) {
|
|
|
31574
31727
|
return line.endsWith("\r") ? line.slice(0, -1) : line;
|
|
31575
31728
|
}
|
|
31576
31729
|
function splitLines(text3) {
|
|
31577
|
-
return text3.split(
|
|
31730
|
+
return text3.split(/\r\n|[\r\n]/);
|
|
31578
31731
|
}
|
|
31579
31732
|
var init_text = __esm({
|
|
31580
31733
|
"src/core/text.ts"() {
|
|
@@ -31584,33 +31737,40 @@ var init_text = __esm({
|
|
|
31584
31737
|
|
|
31585
31738
|
// src/core/parsing/passage-parser.ts
|
|
31586
31739
|
import { createRequire as createCompilerRequire } from "node:module";
|
|
31740
|
+
function encodePassageName(name) {
|
|
31741
|
+
if (!name || /[\r\n]/.test(name)) return void 0;
|
|
31742
|
+
const encoded = name.replace(/[[\]{}\\]/g, "\\$&");
|
|
31743
|
+
const { parseTwee } = createCompilerRequire(import.meta.url)("@rohal12/twee-ts");
|
|
31744
|
+
const parsed = parseTwee(`:: ${encoded}`);
|
|
31745
|
+
return parsed.passages.length === 1 && parsed.passages[0].name === name && !parsed.diagnostics.some((d) => d.level === "error") ? encoded : void 0;
|
|
31746
|
+
}
|
|
31587
31747
|
function parsePassageHeader(rawLine, lineNumber) {
|
|
31588
31748
|
const line = withoutCr(rawLine);
|
|
31589
|
-
const bomLength =
|
|
31749
|
+
const bomLength = /^\uFEFF*/.exec(line)[0].length;
|
|
31590
31750
|
const escaped = line.replace(/\\./g, "ec");
|
|
31591
|
-
const prefix =
|
|
31751
|
+
const prefix = new RegExp("^::\\p{White_Space}*", "u").exec(escaped.slice(bomLength));
|
|
31592
31752
|
if (!prefix) return null;
|
|
31593
31753
|
const nameStart = bomLength + prefix[0].length;
|
|
31594
31754
|
const delimiter = /[\[\]{}]/g;
|
|
31595
31755
|
delimiter.lastIndex = nameStart;
|
|
31596
31756
|
const first = delimiter.exec(escaped);
|
|
31597
31757
|
const boundary = first?.index ?? line.length;
|
|
31598
|
-
const nameEnd = escaped.slice(0, boundary).
|
|
31599
|
-
const name = line.slice(nameStart, nameEnd).replace(/\\(.|$)/g, "$1").
|
|
31758
|
+
const nameEnd = escaped.slice(0, boundary).replace(new RegExp("\\p{White_Space}+$", "u"), "").length;
|
|
31759
|
+
const name = line.slice(nameStart, nameEnd).replace(/\\(.|$)/g, "$1").replace(new RegExp("^\\p{White_Space}+|\\p{White_Space}+$", "gu"), "");
|
|
31600
31760
|
if (!name) return null;
|
|
31601
31761
|
let rest = boundary;
|
|
31602
31762
|
let tags = [];
|
|
31603
31763
|
if (escaped[rest] === "[") {
|
|
31604
31764
|
const end = escaped.indexOf("]", rest + 1);
|
|
31605
31765
|
if (end === -1 || /[\[{}]/.test(escaped.slice(rest + 1, end))) return null;
|
|
31606
|
-
const decoded = line.slice(rest + 1, end).replace(/\\(.)/g, "$1")
|
|
31607
|
-
tags = decoded
|
|
31766
|
+
const decoded = line.slice(rest + 1, end).replace(/\\(.)/g, "$1");
|
|
31767
|
+
tags = decoded.match(/[^\p{White_Space}]+/gu) ?? [];
|
|
31608
31768
|
rest = end + 1;
|
|
31609
|
-
while (rest < line.length &&
|
|
31769
|
+
while (rest < line.length && new RegExp("\\p{White_Space}", "u").test(escaped[rest])) rest++;
|
|
31610
31770
|
}
|
|
31611
31771
|
let meta3;
|
|
31612
31772
|
if (rest < line.length) {
|
|
31613
|
-
const raw = line.slice(rest).
|
|
31773
|
+
const raw = line.slice(rest).replace(new RegExp("\\p{White_Space}+$", "u"), "");
|
|
31614
31774
|
if (escaped[rest] !== "{" || !raw.endsWith("}")) return null;
|
|
31615
31775
|
try {
|
|
31616
31776
|
meta3 = JSON.parse(raw);
|
|
@@ -31694,21 +31854,13 @@ var init_passage_parser = __esm({
|
|
|
31694
31854
|
|
|
31695
31855
|
// src/core/workspace/passage-index.ts
|
|
31696
31856
|
import { createRequire as createSettingsRequire } from "node:module";
|
|
31697
|
-
function compareSourceUris(left, right) {
|
|
31698
|
-
const a = left.split("/").map(decodeURIComponent);
|
|
31699
|
-
const b = right.split("/").map(decodeURIComponent);
|
|
31700
|
-
for (let i2 = 0; i2 < Math.min(a.length, b.length); i2++) {
|
|
31701
|
-
const order = Buffer.compare(Buffer.from(a[i2], "utf8"), Buffer.from(b[i2], "utf8"));
|
|
31702
|
-
if (order !== 0) return order;
|
|
31703
|
-
}
|
|
31704
|
-
return a.length - b.length;
|
|
31705
|
-
}
|
|
31706
31857
|
var PassageIndex;
|
|
31707
31858
|
var init_passage_index = __esm({
|
|
31708
31859
|
"src/core/workspace/passage-index.ts"() {
|
|
31709
31860
|
"use strict";
|
|
31710
31861
|
init_passage_parser();
|
|
31711
31862
|
init_text();
|
|
31863
|
+
init_source_order();
|
|
31712
31864
|
PassageIndex = class {
|
|
31713
31865
|
/** Per-URI list of passages. */
|
|
31714
31866
|
byUri = /* @__PURE__ */ new Map();
|
|
@@ -32334,20 +32486,18 @@ var init_parameter_validator = __esm({
|
|
|
32334
32486
|
// and reads the rest as a dot path into the story variables.
|
|
32335
32487
|
name: ["receiver"],
|
|
32336
32488
|
validate(arg) {
|
|
32337
|
-
|
|
32338
|
-
if (arg.type === 0 /* String */) {
|
|
32339
|
-
name = arg.text.slice(1, -1);
|
|
32340
|
-
} else if (arg.type === 8 /* Bareword */) {
|
|
32341
|
-
name = arg.text;
|
|
32342
|
-
}
|
|
32343
|
-
if (name === void 0) {
|
|
32489
|
+
if (arg.type !== 0 /* String */ && arg.type !== 8 /* Bareword */) {
|
|
32344
32490
|
return new TypeError2("Argument is not a variable receiver");
|
|
32345
32491
|
}
|
|
32346
|
-
|
|
32347
|
-
|
|
32348
|
-
|
|
32349
|
-
|
|
32350
|
-
|
|
32492
|
+
try {
|
|
32493
|
+
const binding = parseBoundVariable(arg.text);
|
|
32494
|
+
if (!binding) return new TypeError2("Argument is not a variable receiver");
|
|
32495
|
+
const root = `${binding.explicitSigil ? "$" : ""}${binding.name}`;
|
|
32496
|
+
if (!/^(?:\$\w|[A-Za-z_])[\w$]*$/.test(root)) {
|
|
32497
|
+
return new TypeError2(`Argument is not a valid variable receiver: '${root}'`);
|
|
32498
|
+
}
|
|
32499
|
+
} catch (error48) {
|
|
32500
|
+
return new TypeError2(`Invalid story variable receiver: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
32351
32501
|
}
|
|
32352
32502
|
return null;
|
|
32353
32503
|
}
|
|
@@ -32779,7 +32929,8 @@ function collectVariableReferences2(markup) {
|
|
|
32779
32929
|
name: ref2.name,
|
|
32780
32930
|
path: [ref2.name, ...ref2.path].join("."),
|
|
32781
32931
|
start: ref2.start,
|
|
32782
|
-
end: ref2.end
|
|
32932
|
+
end: ref2.end,
|
|
32933
|
+
binding: ref2.binding
|
|
32783
32934
|
}));
|
|
32784
32935
|
}
|
|
32785
32936
|
var init_executable_refs = __esm({
|
|
@@ -32805,13 +32956,13 @@ var init_passage_markup = __esm({
|
|
|
32805
32956
|
this.bodyEnd = bodyEnd;
|
|
32806
32957
|
const raw = doc.text.slice(bodyStart, bodyEnd);
|
|
32807
32958
|
this.isMarkup = isMarkupPassage(passage);
|
|
32808
|
-
if (raw.includes("\r
|
|
32959
|
+
if (raw.includes("\r")) {
|
|
32809
32960
|
const map2 = [];
|
|
32810
32961
|
let content2 = "";
|
|
32811
32962
|
for (let i2 = 0; i2 < raw.length; i2++) {
|
|
32812
32963
|
if (raw[i2] === "\r" && raw[i2 + 1] === "\n") continue;
|
|
32813
32964
|
map2.push(bodyStart + i2);
|
|
32814
|
-
content2 += raw[i2];
|
|
32965
|
+
content2 += raw[i2] === "\r" ? "\n" : raw[i2];
|
|
32815
32966
|
}
|
|
32816
32967
|
map2.push(bodyEnd);
|
|
32817
32968
|
this.content = content2;
|
|
@@ -32829,7 +32980,7 @@ var init_passage_markup = __esm({
|
|
|
32829
32980
|
content;
|
|
32830
32981
|
/** Whether Spindle reads the body as story markup (see isMarkupPassage). */
|
|
32831
32982
|
isMarkup;
|
|
32832
|
-
/** For each `content` offset, its offset in the document; null when the body has no
|
|
32983
|
+
/** For each `content` offset, its offset in the document; null when the body has no CR. */
|
|
32833
32984
|
toDoc;
|
|
32834
32985
|
cachedTokens;
|
|
32835
32986
|
cachedPairing;
|
|
@@ -32870,7 +33021,7 @@ var init_passage_markup = __esm({
|
|
|
32870
33021
|
}
|
|
32871
33022
|
/** The flat tokens and the malformed tags; none for a passage that is not markup. */
|
|
32872
33023
|
get tokenization() {
|
|
32873
|
-
return this.cachedTokens ??= this.isMarkup ? tokenizeMarkupTolerant(this.content) : { tokens: [], errors: [] };
|
|
33024
|
+
return this.cachedTokens ??= this.isMarkup ? tokenizeMarkupTolerant(this.content, { macros: this.doc.context.macros }) : { tokens: [], errors: [] };
|
|
32874
33025
|
}
|
|
32875
33026
|
get tokens() {
|
|
32876
33027
|
return this.tokenization.tokens;
|
|
@@ -33533,20 +33684,22 @@ function resolveStoryFormat(declared) {
|
|
|
33533
33684
|
return foreign === void 0 ? UNDECLARED_STORY_FORMAT : { name: foreign, isSpindle: false };
|
|
33534
33685
|
}
|
|
33535
33686
|
function passageContent(passage, text3) {
|
|
33536
|
-
return text3
|
|
33687
|
+
return splitLines(text3).slice(passage.headerEnd.end.line + 1, passage.range.end.line + 1).join("\n");
|
|
33688
|
+
}
|
|
33689
|
+
function effectiveStoryData(passages) {
|
|
33690
|
+
const passage = [...passages].filter((p) => p.name === "StoryData").at(-1);
|
|
33691
|
+
return passage ? [passage] : [];
|
|
33537
33692
|
}
|
|
33538
33693
|
function storyDataFormats(passages, getText) {
|
|
33539
33694
|
const formats = [];
|
|
33540
|
-
for (const passage of passages) {
|
|
33541
|
-
if (passage.name !== "StoryData") continue;
|
|
33695
|
+
for (const passage of effectiveStoryData(passages)) {
|
|
33542
33696
|
const text3 = getText(passage.uri);
|
|
33543
33697
|
formats.push(text3 === void 0 ? void 0 : readStoryDataFormat(passageContent(passage, text3)));
|
|
33544
33698
|
}
|
|
33545
33699
|
return formats;
|
|
33546
33700
|
}
|
|
33547
33701
|
function storyDataFormatVersion(passages, getText) {
|
|
33548
|
-
for (const passage of passages) {
|
|
33549
|
-
if (passage.name !== "StoryData") continue;
|
|
33702
|
+
for (const passage of effectiveStoryData(passages)) {
|
|
33550
33703
|
const text3 = getText(passage.uri);
|
|
33551
33704
|
if (text3 === void 0) continue;
|
|
33552
33705
|
const version2 = readStoryDataFormatVersion(passageContent(passage, text3));
|
|
@@ -33554,15 +33707,18 @@ function storyDataFormatVersion(passages, getText) {
|
|
|
33554
33707
|
}
|
|
33555
33708
|
return void 0;
|
|
33556
33709
|
}
|
|
33557
|
-
function
|
|
33710
|
+
function indexStoryDataTexts(texts) {
|
|
33558
33711
|
const index = new PassageIndex();
|
|
33559
33712
|
const byUri = /* @__PURE__ */ new Map();
|
|
33560
33713
|
for (const text3 of texts) {
|
|
33561
|
-
|
|
33562
|
-
const uri = `story-format:${byUri.size}`;
|
|
33714
|
+
const uri = `story-format:${String(byUri.size).padStart(16, "0")}`;
|
|
33563
33715
|
byUri.set(uri, text3);
|
|
33564
33716
|
index.rebuild(uri, text3);
|
|
33565
33717
|
}
|
|
33718
|
+
return { index, byUri };
|
|
33719
|
+
}
|
|
33720
|
+
function storyFormatOfTexts(texts) {
|
|
33721
|
+
const { index, byUri } = indexStoryDataTexts(texts);
|
|
33566
33722
|
const formats = storyDataFormats(index.getAllPassages(), (uri) => byUri.get(uri));
|
|
33567
33723
|
return { ...resolveStoryFormat(formats), hasStoryData: formats.length > 0 };
|
|
33568
33724
|
}
|
|
@@ -33580,14 +33736,7 @@ async function findStoryFormat(texts, dir) {
|
|
|
33580
33736
|
return { name, isSpindle };
|
|
33581
33737
|
}
|
|
33582
33738
|
function storyFormatVersionOfTexts(texts) {
|
|
33583
|
-
const index =
|
|
33584
|
-
const byUri = /* @__PURE__ */ new Map();
|
|
33585
|
-
for (const text3 of texts) {
|
|
33586
|
-
if (!text3.includes("StoryData")) continue;
|
|
33587
|
-
const uri = `story-format:${byUri.size}`;
|
|
33588
|
-
byUri.set(uri, text3);
|
|
33589
|
-
index.rebuild(uri, text3);
|
|
33590
|
-
}
|
|
33739
|
+
const { index, byUri } = indexStoryDataTexts(texts);
|
|
33591
33740
|
return storyDataFormatVersion(index.getAllPassages(), (uri) => byUri.get(uri));
|
|
33592
33741
|
}
|
|
33593
33742
|
async function findSpindleTarget(texts, dir) {
|
|
@@ -33614,6 +33763,7 @@ var UNDECLARED_STORY_FORMAT;
|
|
|
33614
33763
|
var init_story_format = __esm({
|
|
33615
33764
|
"src/core/workspace/story-format.ts"() {
|
|
33616
33765
|
"use strict";
|
|
33766
|
+
init_text();
|
|
33617
33767
|
init_document_store();
|
|
33618
33768
|
init_passage_index();
|
|
33619
33769
|
init_story_data();
|
|
@@ -34358,6 +34508,8 @@ var init_diagnostic_codes = __esm({
|
|
|
34358
34508
|
DiagnosticCode = {
|
|
34359
34509
|
/** The Spindle the project targets is older than the oldest one supported. */
|
|
34360
34510
|
UnsupportedSpindleVersion: "SP001",
|
|
34511
|
+
/** A fatal Twee source error reported by the public compiler parser. */
|
|
34512
|
+
TweeSyntaxError: "SP002",
|
|
34361
34513
|
/** `unknown-macro`: a macro that is none of the built-in, configured or defined ones. */
|
|
34362
34514
|
UndefinedMacro: "SP100",
|
|
34363
34515
|
/** `unclosed-block`, `mismatched-closer`, `stray-closer` of a macro. */
|
|
@@ -34406,38 +34558,39 @@ var init_diagnostic_codes = __esm({
|
|
|
34406
34558
|
LineTooLong: "SP500"
|
|
34407
34559
|
};
|
|
34408
34560
|
severityMap = {
|
|
34409
|
-
|
|
34410
|
-
|
|
34411
|
-
|
|
34412
|
-
|
|
34413
|
-
|
|
34414
|
-
|
|
34415
|
-
|
|
34416
|
-
|
|
34417
|
-
|
|
34418
|
-
|
|
34419
|
-
|
|
34420
|
-
|
|
34421
|
-
|
|
34422
|
-
|
|
34423
|
-
|
|
34424
|
-
|
|
34425
|
-
|
|
34426
|
-
|
|
34427
|
-
|
|
34428
|
-
|
|
34429
|
-
|
|
34430
|
-
|
|
34431
|
-
|
|
34432
|
-
|
|
34433
|
-
|
|
34434
|
-
|
|
34435
|
-
|
|
34436
|
-
|
|
34437
|
-
|
|
34438
|
-
|
|
34439
|
-
|
|
34440
|
-
|
|
34561
|
+
[DiagnosticCode.UnsupportedSpindleVersion]: "warning",
|
|
34562
|
+
[DiagnosticCode.TweeSyntaxError]: "error",
|
|
34563
|
+
[DiagnosticCode.UndefinedMacro]: "warning",
|
|
34564
|
+
[DiagnosticCode.MalformedContainer]: "error",
|
|
34565
|
+
[DiagnosticCode.MalformedElement]: "error",
|
|
34566
|
+
[DiagnosticCode.IllegalClosingTag]: "error",
|
|
34567
|
+
[DiagnosticCode.UnclosedMarkup]: "error",
|
|
34568
|
+
[DiagnosticCode.CodeSyntaxError]: "error",
|
|
34569
|
+
[DiagnosticCode.InvalidChildren]: "error",
|
|
34570
|
+
[DiagnosticCode.ExpectedNoArguments]: "error",
|
|
34571
|
+
[DiagnosticCode.ParameterTypeError]: "error",
|
|
34572
|
+
[DiagnosticCode.ParameterWarning]: "warning",
|
|
34573
|
+
[DiagnosticCode.TooManyArguments]: "error",
|
|
34574
|
+
[DiagnosticCode.UnquotedPassageName]: "error",
|
|
34575
|
+
[DiagnosticCode.ChildMaxExceeded]: "error",
|
|
34576
|
+
[DiagnosticCode.ChildMinNotMet]: "error",
|
|
34577
|
+
[DiagnosticCode.UndeclaredVariable]: "error",
|
|
34578
|
+
[DiagnosticCode.PrimitiveFieldAccess]: "error",
|
|
34579
|
+
[DiagnosticCode.NoStoryVariables]: "info",
|
|
34580
|
+
[DiagnosticCode.UndeclaredTransient]: "warning",
|
|
34581
|
+
[DiagnosticCode.TemporaryAssignedInLoop]: "warning",
|
|
34582
|
+
[DiagnosticCode.ArrayMemberAccess]: "warning",
|
|
34583
|
+
[DiagnosticCode.InvalidDeclaration]: "error",
|
|
34584
|
+
[DiagnosticCode.ReservedVariableName]: "error",
|
|
34585
|
+
[DiagnosticCode.BrokenPassageLink]: "warning",
|
|
34586
|
+
[DiagnosticCode.WidgetArgCountMismatch]: "warning",
|
|
34587
|
+
[DiagnosticCode.IncludeWidgetPassage]: "warning",
|
|
34588
|
+
[DiagnosticCode.UnusedWidget]: "hint",
|
|
34589
|
+
[DiagnosticCode.LinkRuntimeMismatch]: "warning",
|
|
34590
|
+
[DiagnosticCode.LiteralLinkInterpolation]: "warning",
|
|
34591
|
+
[DiagnosticCode.DeadEndPassage]: "hint",
|
|
34592
|
+
[DiagnosticCode.UnreachablePassage]: "hint",
|
|
34593
|
+
[DiagnosticCode.LineTooLong]: "warning"
|
|
34441
34594
|
};
|
|
34442
34595
|
}
|
|
34443
34596
|
});
|
|
@@ -34689,12 +34842,14 @@ var init_story_variables_owner = __esm({
|
|
|
34689
34842
|
});
|
|
34690
34843
|
|
|
34691
34844
|
// src/plugins/diagnostics.ts
|
|
34845
|
+
import { createRequire as createCompilerRequire3 } from "node:module";
|
|
34692
34846
|
function computeDiagnostics(uri, workspace, options) {
|
|
34693
34847
|
if (!workspace.initialized) return [];
|
|
34694
34848
|
if (!workspace.isSpindleProject()) return [];
|
|
34695
34849
|
const doc = workspace.markup.get(uri);
|
|
34696
|
-
if (!doc ||
|
|
34697
|
-
const diagnostics = [];
|
|
34850
|
+
if (!doc || isMacroSource(uri)) return [];
|
|
34851
|
+
const diagnostics = [...tweeDiagnostics(doc)];
|
|
34852
|
+
if (doc.passages.length === 0) return diagnostics;
|
|
34698
34853
|
const attempt = (check2) => {
|
|
34699
34854
|
try {
|
|
34700
34855
|
check2();
|
|
@@ -34725,6 +34880,27 @@ function computeDiagnostics(uri, workspace, options) {
|
|
|
34725
34880
|
}
|
|
34726
34881
|
return diagnostics.sort((a, b) => a.range.start.line - b.range.start.line || a.range.start.character - b.range.start.character);
|
|
34727
34882
|
}
|
|
34883
|
+
function tweeDiagnostics(doc) {
|
|
34884
|
+
const kept3 = tweeReports.get(doc);
|
|
34885
|
+
if (kept3) return kept3;
|
|
34886
|
+
const lines = splitLines(doc.text);
|
|
34887
|
+
const indexed = new Set(doc.passages.map((p) => p.passage.headerEnd.start.line));
|
|
34888
|
+
if (!lines.some((line, i2) => /^\uFEFF*::/.test(line) && (!indexed.has(i2) || /[[\]{}]/.test(line)))) {
|
|
34889
|
+
tweeReports.set(doc, []);
|
|
34890
|
+
return [];
|
|
34891
|
+
}
|
|
34892
|
+
const { parseTwee } = createCompilerRequire3(import.meta.url)("@rohal12/twee-ts");
|
|
34893
|
+
const diagnostics = parseTwee(doc.text).diagnostics.filter((d) => d.level === "error").map((d) => {
|
|
34894
|
+
const line = Math.min(Math.max((d.line ?? 1) - 1, 0), lines.length - 1);
|
|
34895
|
+
return makeDiag(
|
|
34896
|
+
{ start: { line, character: 0 }, end: { line, character: lines[line].length } },
|
|
34897
|
+
DiagnosticCode.TweeSyntaxError,
|
|
34898
|
+
d.message
|
|
34899
|
+
);
|
|
34900
|
+
});
|
|
34901
|
+
tweeReports.set(doc, diagnostics);
|
|
34902
|
+
return diagnostics;
|
|
34903
|
+
}
|
|
34728
34904
|
function storyReport(workspace) {
|
|
34729
34905
|
const documents = [];
|
|
34730
34906
|
for (const uri of workspace.passages.getDocumentUris()) {
|
|
@@ -35261,7 +35437,7 @@ function toLspDiagnostic(d) {
|
|
|
35261
35437
|
data: d.data
|
|
35262
35438
|
};
|
|
35263
35439
|
}
|
|
35264
|
-
var reports, COMPILER_PASSAGES, MARKUP_CODES, text2, list2, VARIABLE_CODES, WILL_NOT_START, BRANCH_MACROS2, DIRECT_CHILD_MACROS, DEFERRED_CONTAINERS, SPINDLE_MACROS, diagnosticsPlugin;
|
|
35440
|
+
var tweeReports, reports, COMPILER_PASSAGES, MARKUP_CODES, text2, list2, VARIABLE_CODES, WILL_NOT_START, BRANCH_MACROS2, DIRECT_CHILD_MACROS, DEFERRED_CONTAINERS, SPINDLE_MACROS, diagnosticsPlugin;
|
|
35265
35441
|
var init_diagnostics = __esm({
|
|
35266
35442
|
"src/plugins/diagnostics.ts"() {
|
|
35267
35443
|
"use strict";
|
|
@@ -35278,6 +35454,7 @@ var init_diagnostics = __esm({
|
|
|
35278
35454
|
init_story_variables_owner();
|
|
35279
35455
|
init_macro_sources();
|
|
35280
35456
|
init_spindle_version();
|
|
35457
|
+
tweeReports = /* @__PURE__ */ new WeakMap();
|
|
35281
35458
|
reports = /* @__PURE__ */ new WeakMap();
|
|
35282
35459
|
COMPILER_PASSAGES = /* @__PURE__ */ new Set(["StoryTitle", "StoryData"]);
|
|
35283
35460
|
MARKUP_CODES = {
|
|
@@ -35513,7 +35690,7 @@ __export(check_exports, {
|
|
|
35513
35690
|
runCheck: () => runCheck
|
|
35514
35691
|
});
|
|
35515
35692
|
import { resolve as resolve5 } from "node:path";
|
|
35516
|
-
import { pathToFileURL as
|
|
35693
|
+
import { pathToFileURL as pathToFileURL4 } from "node:url";
|
|
35517
35694
|
function parseArgs(args2) {
|
|
35518
35695
|
const options = {
|
|
35519
35696
|
format: "pretty",
|
|
@@ -35626,7 +35803,7 @@ async function runCheck(args2) {
|
|
|
35626
35803
|
return 1;
|
|
35627
35804
|
}
|
|
35628
35805
|
}
|
|
35629
|
-
const fileContents = new Map([...contents].map(([path2, text3]) => [
|
|
35806
|
+
const fileContents = new Map([...contents].map(([path2, text3]) => [pathToFileURL4(path2).toString(), text3]));
|
|
35630
35807
|
const storyFormat = await findStoryFormat(fileContents.values(), commonDir);
|
|
35631
35808
|
if (!storyFormat.isSpindle) {
|
|
35632
35809
|
console.error(skippedFormatNote(storyFormat));
|
|
@@ -35694,7 +35871,7 @@ var init_check = __esm({
|
|
|
35694
35871
|
|
|
35695
35872
|
// src/plugins/format/segment.ts
|
|
35696
35873
|
function splitPassages(text3) {
|
|
35697
|
-
const lines = text3
|
|
35874
|
+
const lines = splitLines(text3);
|
|
35698
35875
|
if (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
35699
35876
|
lines.pop();
|
|
35700
35877
|
}
|
|
@@ -35742,6 +35919,7 @@ function headerTags(header) {
|
|
|
35742
35919
|
var init_segment = __esm({
|
|
35743
35920
|
"src/plugins/format/segment.ts"() {
|
|
35744
35921
|
"use strict";
|
|
35922
|
+
init_text();
|
|
35745
35923
|
init_passage_parser();
|
|
35746
35924
|
}
|
|
35747
35925
|
});
|
|
@@ -37733,14 +37911,15 @@ function buildDefaultIsBlock(text3) {
|
|
|
37733
37911
|
async function formatDocument(text3, options) {
|
|
37734
37912
|
if (text3.charCodeAt(0) === 65279) return "\uFEFF" + await formatDocument(text3.slice(1), options);
|
|
37735
37913
|
const eol = dominantEol2(text3);
|
|
37736
|
-
const output = await formatLf2(text3.
|
|
37737
|
-
return
|
|
37914
|
+
const output = await formatLf2(splitLines(text3).join("\n"), options);
|
|
37915
|
+
return output.replace(/\n/g, eol);
|
|
37738
37916
|
}
|
|
37739
37917
|
function dominantEol2(text3) {
|
|
37740
|
-
const
|
|
37741
|
-
const
|
|
37742
|
-
|
|
37743
|
-
|
|
37918
|
+
const counts = /* @__PURE__ */ new Map();
|
|
37919
|
+
for (const [ending] of text3.matchAll(/\r\n|[\r\n]/g)) {
|
|
37920
|
+
counts.set(ending, (counts.get(ending) ?? 0) + 1);
|
|
37921
|
+
}
|
|
37922
|
+
return [...counts].sort((a, b) => b[1] - a[1])[0]?.[0] ?? "\n";
|
|
37744
37923
|
}
|
|
37745
37924
|
async function formatLf2(text3, options) {
|
|
37746
37925
|
const isBlock = options?.isBlock ?? buildDefaultIsBlock(text3);
|
|
@@ -37791,6 +37970,7 @@ var DEFAULT_DEDENTING2, BUILTIN_CONTAINERS, formatPlugin;
|
|
|
37791
37970
|
var init_format = __esm({
|
|
37792
37971
|
"src/plugins/format.ts"() {
|
|
37793
37972
|
"use strict";
|
|
37973
|
+
init_text();
|
|
37794
37974
|
init_tooling();
|
|
37795
37975
|
init_passage_parser();
|
|
37796
37976
|
init_segment();
|
|
@@ -37814,7 +37994,7 @@ var init_format = __esm({
|
|
|
37814
37994
|
if (text3 === void 0) return [];
|
|
37815
37995
|
const formatted = await formatDocument(text3, { ...formatOpts, filePath: params.textDocument.uri });
|
|
37816
37996
|
if (formatted === text3) return [];
|
|
37817
|
-
const lines = text3
|
|
37997
|
+
const lines = splitLines(text3);
|
|
37818
37998
|
return [{
|
|
37819
37999
|
range: {
|
|
37820
38000
|
start: { line: 0, character: 0 },
|
|
@@ -37832,7 +38012,7 @@ var init_format = __esm({
|
|
|
37832
38012
|
};
|
|
37833
38013
|
const formatted = await formatRange(text3, range2, { ...formatOpts, filePath: params.textDocument.uri });
|
|
37834
38014
|
if (formatted === text3) return [];
|
|
37835
|
-
const lines = text3
|
|
38015
|
+
const lines = splitLines(text3);
|
|
37836
38016
|
return [{
|
|
37837
38017
|
range: {
|
|
37838
38018
|
start: { line: 0, character: 0 },
|
|
@@ -69577,7 +69757,7 @@ __export(server_exports, {
|
|
|
69577
69757
|
startMcpServer: () => startMcpServer
|
|
69578
69758
|
});
|
|
69579
69759
|
import { writeFileSync as writeFileSync2 } from "node:fs";
|
|
69580
|
-
import { pathToFileURL as
|
|
69760
|
+
import { pathToFileURL as pathToFileURL5 } from "node:url";
|
|
69581
69761
|
function filterBySeverity2(diagnostics, minSeverity) {
|
|
69582
69762
|
const minIdx = SEVERITY_ORDER2.indexOf(minSeverity);
|
|
69583
69763
|
return diagnostics.filter((d) => {
|
|
@@ -69586,7 +69766,7 @@ function filterBySeverity2(diagnostics, minSeverity) {
|
|
|
69586
69766
|
});
|
|
69587
69767
|
}
|
|
69588
69768
|
function readFiles(files) {
|
|
69589
|
-
return new Map([...readFileContents(files)].map(([path2, text3]) => [
|
|
69769
|
+
return new Map([...readFileContents(files)].map(([path2, text3]) => [pathToFileURL5(path2).toString(), text3]));
|
|
69590
69770
|
}
|
|
69591
69771
|
async function skippedReason(fileContents, files) {
|
|
69592
69772
|
const format = await findStoryFormat(fileContents.values(), commonDirectory(files));
|
|
@@ -69622,7 +69802,7 @@ async function checkProject(pattern, severity, cwd = process.cwd()) {
|
|
|
69622
69802
|
try {
|
|
69623
69803
|
const results = [];
|
|
69624
69804
|
for (const filePath of files) {
|
|
69625
|
-
const uri =
|
|
69805
|
+
const uri = pathToFileURL5(filePath).toString();
|
|
69626
69806
|
let diags = computeDiagnostics(uri, workspace);
|
|
69627
69807
|
if (severity) {
|
|
69628
69808
|
diags = filterBySeverity2(diags, severity);
|
|
@@ -69654,7 +69834,7 @@ async function formatFiles(pattern, cwd = process.cwd()) {
|
|
|
69654
69834
|
let unchanged = 0;
|
|
69655
69835
|
const changedFiles = [];
|
|
69656
69836
|
for (const filePath of files) {
|
|
69657
|
-
const text3 = contents.get(
|
|
69837
|
+
const text3 = contents.get(pathToFileURL5(filePath).toString());
|
|
69658
69838
|
if (text3 === void 0) continue;
|
|
69659
69839
|
try {
|
|
69660
69840
|
const result2 = await formatDocument(text3, { filePath });
|
|
@@ -69680,7 +69860,7 @@ async function checkFormatting(pattern, cwd = process.cwd()) {
|
|
|
69680
69860
|
const needsFormatting = [];
|
|
69681
69861
|
const alreadyFormatted = [];
|
|
69682
69862
|
for (const filePath of files) {
|
|
69683
|
-
const text3 = contents.get(
|
|
69863
|
+
const text3 = contents.get(pathToFileURL5(filePath).toString());
|
|
69684
69864
|
if (text3 === void 0) continue;
|
|
69685
69865
|
try {
|
|
69686
69866
|
const result2 = await formatDocument(text3, { filePath });
|
|
@@ -79947,7 +80127,11 @@ function gateRegistrations(target, methods, enabled, nested = {}) {
|
|
|
79947
80127
|
}
|
|
79948
80128
|
if (methods.includes(prop) && typeof value === "function") {
|
|
79949
80129
|
return (handler, ...rest) => Reflect.apply(value, obj, [
|
|
79950
|
-
(...args2) =>
|
|
80130
|
+
(...args2) => {
|
|
80131
|
+
const allowed = enabled();
|
|
80132
|
+
const answer = (yes) => yes ? handler(...args2) : null;
|
|
80133
|
+
return typeof allowed === "boolean" ? answer(allowed) : allowed.then(answer);
|
|
80134
|
+
},
|
|
79951
80135
|
...rest
|
|
79952
80136
|
]);
|
|
79953
80137
|
}
|
|
@@ -79992,6 +80176,26 @@ var init_story_format_gate = __esm({
|
|
|
79992
80176
|
}
|
|
79993
80177
|
});
|
|
79994
80178
|
|
|
80179
|
+
// src/core/parsing/js-string-literal.ts
|
|
80180
|
+
function encodeStringLiteralBody(value, quote) {
|
|
80181
|
+
let out = "";
|
|
80182
|
+
for (let i2 = 0; i2 < value.length; i2++) {
|
|
80183
|
+
const ch = value[i2];
|
|
80184
|
+
if (ch === "\\" || ch === quote) out += "\\" + ch;
|
|
80185
|
+
else if (ch === "\n") out += "\\n";
|
|
80186
|
+
else if (ch === "\r") out += "\\r";
|
|
80187
|
+
else if (ch === "\u2028") out += "\\u2028";
|
|
80188
|
+
else if (ch === "\u2029") out += "\\u2029";
|
|
80189
|
+
else out += ch;
|
|
80190
|
+
}
|
|
80191
|
+
return out;
|
|
80192
|
+
}
|
|
80193
|
+
var init_js_string_literal = __esm({
|
|
80194
|
+
"src/core/parsing/js-string-literal.ts"() {
|
|
80195
|
+
"use strict";
|
|
80196
|
+
}
|
|
80197
|
+
});
|
|
80198
|
+
|
|
79995
80199
|
// src/core/markup/tree.ts
|
|
79996
80200
|
function* walkNodes(nodes) {
|
|
79997
80201
|
for (const node of nodes) {
|
|
@@ -80245,7 +80449,7 @@ function getCompletions(uri, position, triggerChar, workspace) {
|
|
|
80245
80449
|
...item,
|
|
80246
80450
|
textEdit: {
|
|
80247
80451
|
range: passage.range(start, end),
|
|
80248
|
-
newText: identifier ? item.label :
|
|
80452
|
+
newText: identifier ? item.label : encodeCompletion(`[${JSON.stringify(item.label)}]`, context.containers)
|
|
80249
80453
|
}
|
|
80250
80454
|
};
|
|
80251
80455
|
});
|
|
@@ -80268,6 +80472,12 @@ function getCompletions(uri, position, triggerChar, workspace) {
|
|
|
80268
80472
|
}
|
|
80269
80473
|
return [];
|
|
80270
80474
|
}
|
|
80475
|
+
function encodeCompletion(spelling, containers = []) {
|
|
80476
|
+
for (const container of [...containers].reverse()) {
|
|
80477
|
+
if (container.kind === "string") spelling = encodeStringLiteralBody(spelling, container.quote);
|
|
80478
|
+
}
|
|
80479
|
+
return spelling;
|
|
80480
|
+
}
|
|
80271
80481
|
function getClosingMacroCompletions(cursor, brace) {
|
|
80272
80482
|
const names = [...new Set(cursor.openBlocks(brace).map((macro) => macro.name))];
|
|
80273
80483
|
return names.map((name, idx) => ({
|
|
@@ -80360,7 +80570,7 @@ var init_completions = __esm({
|
|
|
80360
80570
|
"use strict";
|
|
80361
80571
|
init_tooling();
|
|
80362
80572
|
init_widgets();
|
|
80363
|
-
|
|
80573
|
+
init_js_string_literal();
|
|
80364
80574
|
init_link_runtime();
|
|
80365
80575
|
init_passage_parser();
|
|
80366
80576
|
init_markup_cursor();
|
|
@@ -80717,7 +80927,7 @@ var init_macro_heads = __esm({
|
|
|
80717
80927
|
function getDefinition(uri, position, workspace) {
|
|
80718
80928
|
const text3 = workspace.documents.getText(uri);
|
|
80719
80929
|
if (text3 === void 0 || !workspace.hasPassages(uri)) return null;
|
|
80720
|
-
const lines = text3
|
|
80930
|
+
const lines = splitLines(text3);
|
|
80721
80931
|
if (position.line >= lines.length) return null;
|
|
80722
80932
|
const passageResult = getPassageRefDefinition(uri, position, workspace);
|
|
80723
80933
|
if (passageResult) return passageResult;
|
|
@@ -80729,7 +80939,7 @@ function getPassageRefDefinition(uri, position, workspace) {
|
|
|
80729
80939
|
const doc = workspace.markup.get(uri);
|
|
80730
80940
|
const ref2 = doc && passageRefAt(doc, position);
|
|
80731
80941
|
if (!ref2) return null;
|
|
80732
|
-
const passage = workspace.passages.
|
|
80942
|
+
const passage = workspace.passages.getEffectivePassage(ref2.name);
|
|
80733
80943
|
if (!passage) return null;
|
|
80734
80944
|
return {
|
|
80735
80945
|
uri: passage.uri,
|
|
@@ -80754,6 +80964,7 @@ var definitionPlugin;
|
|
|
80754
80964
|
var init_definition = __esm({
|
|
80755
80965
|
"src/plugins/definition.ts"() {
|
|
80756
80966
|
"use strict";
|
|
80967
|
+
init_text();
|
|
80757
80968
|
init_macro_heads();
|
|
80758
80969
|
init_passage_refs();
|
|
80759
80970
|
definitionPlugin = {
|
|
@@ -80783,7 +80994,7 @@ var init_definition = __esm({
|
|
|
80783
80994
|
function findReferences(uri, position, workspace, includeDeclaration) {
|
|
80784
80995
|
const text3 = workspace.documents.getText(uri);
|
|
80785
80996
|
if (text3 === void 0 || !workspace.hasPassages(uri)) return [];
|
|
80786
|
-
const lines = text3
|
|
80997
|
+
const lines = splitLines(text3);
|
|
80787
80998
|
if (position.line >= lines.length) return [];
|
|
80788
80999
|
const line = lines[position.line];
|
|
80789
81000
|
const header = parsePassageHeader(line, position.line);
|
|
@@ -80893,6 +81104,7 @@ var referencesPlugin;
|
|
|
80893
81104
|
var init_references = __esm({
|
|
80894
81105
|
"src/plugins/references.ts"() {
|
|
80895
81106
|
"use strict";
|
|
81107
|
+
init_text();
|
|
80896
81108
|
init_macro_heads();
|
|
80897
81109
|
init_passage_refs();
|
|
80898
81110
|
init_passage_parser();
|
|
@@ -80919,26 +81131,6 @@ var init_references = __esm({
|
|
|
80919
81131
|
}
|
|
80920
81132
|
});
|
|
80921
81133
|
|
|
80922
|
-
// src/core/parsing/js-string-literal.ts
|
|
80923
|
-
function encodeStringLiteralBody(value, quote) {
|
|
80924
|
-
let out = "";
|
|
80925
|
-
for (let i2 = 0; i2 < value.length; i2++) {
|
|
80926
|
-
const ch = value[i2];
|
|
80927
|
-
if (ch === "\\" || ch === quote) out += "\\" + ch;
|
|
80928
|
-
else if (ch === "\n") out += "\\n";
|
|
80929
|
-
else if (ch === "\r") out += "\\r";
|
|
80930
|
-
else if (ch === "\u2028") out += "\\u2028";
|
|
80931
|
-
else if (ch === "\u2029") out += "\\u2029";
|
|
80932
|
-
else out += ch;
|
|
80933
|
-
}
|
|
80934
|
-
return out;
|
|
80935
|
-
}
|
|
80936
|
-
var init_js_string_literal = __esm({
|
|
80937
|
-
"src/core/parsing/js-string-literal.ts"() {
|
|
80938
|
-
"use strict";
|
|
80939
|
-
}
|
|
80940
|
-
});
|
|
80941
|
-
|
|
80942
81134
|
// src/plugins/rename.ts
|
|
80943
81135
|
function prepareRename(uri, position, workspace) {
|
|
80944
81136
|
const symbol2 = resolveSymbolAtCursor(uri, position, workspace);
|
|
@@ -80988,10 +81180,13 @@ function computeRename(uri, position, newName, workspace) {
|
|
|
80988
81180
|
if (isReservedPassageName(newName)) {
|
|
80989
81181
|
throw new RenameError(`Cannot rename to ${JSON.stringify(newName)}: it is a reserved passage name with a fixed meaning.`).at(uri, symbol2.range);
|
|
80990
81182
|
}
|
|
81183
|
+
const encoded = encodePassageName(newName);
|
|
80991
81184
|
for (const declaration of workspace.passages.getPassages(symbol2.name)) {
|
|
80992
|
-
|
|
80993
|
-
|
|
80994
|
-
|
|
81185
|
+
if (encoded === void 0) {
|
|
81186
|
+
const reason = /[\r\n]/.test(newName) ? "a passage header is a single line" : "a passage header cannot represent that name exactly";
|
|
81187
|
+
throw new RenameError(`Cannot rename to ${JSON.stringify(newName)}: ${reason}.`).at(declaration.uri, declaration.nameRange);
|
|
81188
|
+
}
|
|
81189
|
+
addEdit(declaration.uri, declaration.nameRange, encoded);
|
|
80995
81190
|
}
|
|
80996
81191
|
for (const { uri: refUri, ref: ref2, text: text3 } of refEdits) addEdit(refUri, ref2.range, text3);
|
|
80997
81192
|
preserveEntryPassage(symbol2.name, newName, workspace, addEdit);
|
|
@@ -81018,11 +81213,30 @@ function computeRename(uri, position, newName, workspace) {
|
|
|
81018
81213
|
throw new RenameError(`Cannot rename to ${JSON.stringify(newName)}: a variable with that name already exists.`).at(uri, symbol2.range);
|
|
81019
81214
|
}
|
|
81020
81215
|
const refs = symbol2.sigil === "%" ? findTransientReferences(symbol2.name, workspace, true) : findVariableReferences(symbol2.name, workspace, true);
|
|
81216
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
81021
81217
|
for (const ref2 of refs) {
|
|
81022
81218
|
const doc = workspace.markup.get(ref2.uri);
|
|
81023
81219
|
const passage = doc.passageAt(ref2.range.start);
|
|
81024
81220
|
const start = passage.contentOffset(positionToOffset(ref2.range.start, doc.lineStarts));
|
|
81025
81221
|
const end = passage.contentOffset(positionToOffset(ref2.range.end, doc.lineStarts));
|
|
81222
|
+
let byStart = bindings.get(passage);
|
|
81223
|
+
if (!byStart) {
|
|
81224
|
+
byStart = new Map(collectVariableReferences2(passage).flatMap((ref3) => ref3.binding ? [[ref3.start, ref3.binding]] : []));
|
|
81225
|
+
bindings.set(passage, byStart);
|
|
81226
|
+
}
|
|
81227
|
+
const binding = byStart.get(start);
|
|
81228
|
+
if (binding && binding.end === end) {
|
|
81229
|
+
let spelling = bareName;
|
|
81230
|
+
if (!binding.explicitSigil) {
|
|
81231
|
+
try {
|
|
81232
|
+
parseBoundVariable(spelling);
|
|
81233
|
+
} catch {
|
|
81234
|
+
spelling = `$${spelling}`;
|
|
81235
|
+
}
|
|
81236
|
+
}
|
|
81237
|
+
addEdit(ref2.uri, passage.range(binding.nameStart, binding.nameEnd), spelling);
|
|
81238
|
+
continue;
|
|
81239
|
+
}
|
|
81026
81240
|
const view = sourceView(passage, start, end);
|
|
81027
81241
|
const index = viewIndex(view, start);
|
|
81028
81242
|
let base;
|
|
@@ -81114,19 +81328,13 @@ function preserveEntryPassage(oldName, newName, workspace, addEdit) {
|
|
|
81114
81328
|
const declaration = workspace.passages.getPassage(oldName);
|
|
81115
81329
|
const doc = workspace.markup.get(declaration.uri);
|
|
81116
81330
|
const end = doc.passages.at(-1).position(doc.passages.at(-1).content.length);
|
|
81117
|
-
const eol =
|
|
81331
|
+
const eol = /\r\n|[\r\n]/.exec(doc.text)?.[0] ?? "\n";
|
|
81118
81332
|
addEdit(declaration.uri, { start: end, end }, `${eol}${eol}:: StoryData${eol}${JSON.stringify({ start: newName })}${eol}`);
|
|
81119
81333
|
}
|
|
81120
81334
|
}
|
|
81121
81335
|
function isEntryField(key) {
|
|
81122
81336
|
return readStoryData(JSON.stringify({ [key]: "Start" })).start === "Start";
|
|
81123
81337
|
}
|
|
81124
|
-
function passageHeaderProblem(name) {
|
|
81125
|
-
if (name.trim() === "") return "a passage name cannot be empty";
|
|
81126
|
-
if (/[\r\n]/.test(name)) return "a passage header is a single line, so the name cannot contain a line break";
|
|
81127
|
-
if (name !== name.trim()) return "a passage name cannot start or end with whitespace";
|
|
81128
|
-
return null;
|
|
81129
|
-
}
|
|
81130
81338
|
function unrepresentable(newName, where2) {
|
|
81131
81339
|
return new RenameError(`Cannot rename to ${JSON.stringify(newName)}: it cannot be written inside ${where2}.`);
|
|
81132
81340
|
}
|
|
@@ -81190,13 +81398,10 @@ function misreadRewrite(passage, edits, oldName, newName) {
|
|
|
81190
81398
|
const owner = edits.filter((edit) => edit.ref.piece <= index).at(-1) ?? edits[0];
|
|
81191
81399
|
return owner.ref;
|
|
81192
81400
|
}
|
|
81193
|
-
function escapePassageName(name) {
|
|
81194
|
-
return name.replace(/[[\]{}\\]/g, "\\$&");
|
|
81195
|
-
}
|
|
81196
81401
|
function resolveSymbolAtCursor(uri, position, workspace) {
|
|
81197
81402
|
const text3 = workspace.documents.getText(uri);
|
|
81198
81403
|
if (text3 === void 0 || !workspace.hasPassages(uri)) return null;
|
|
81199
|
-
const lines = text3
|
|
81404
|
+
const lines = splitLines(text3);
|
|
81200
81405
|
if (position.line >= lines.length) return null;
|
|
81201
81406
|
const line = lines[position.line];
|
|
81202
81407
|
const header = parsePassageHeader(line, position.line);
|
|
@@ -81240,6 +81445,7 @@ var init_rename = __esm({
|
|
|
81240
81445
|
import_vscode_languageserver2 = __toESM(require_api3(), 1);
|
|
81241
81446
|
init_story_data();
|
|
81242
81447
|
init_tooling();
|
|
81448
|
+
init_executable_refs();
|
|
81243
81449
|
init_source_view();
|
|
81244
81450
|
init_text();
|
|
81245
81451
|
init_link_runtime();
|
|
@@ -81609,7 +81815,7 @@ var init_semantic_tokens = __esm({
|
|
|
81609
81815
|
// src/plugins/code-actions.ts
|
|
81610
81816
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
81611
81817
|
import { basename as basename2, dirname as dirname5, join as join4 } from "node:path";
|
|
81612
|
-
import { fileURLToPath as fileURLToPath4, pathToFileURL as
|
|
81818
|
+
import { fileURLToPath as fileURLToPath4, pathToFileURL as pathToFileURL6 } from "node:url";
|
|
81613
81819
|
function computeCodeActions(uri, diagnostics, workspace, options = {}) {
|
|
81614
81820
|
const actions = [];
|
|
81615
81821
|
for (const diag of diagnostics) {
|
|
@@ -81660,7 +81866,7 @@ function addMacroToConfig(uri, macroName, workspace, options) {
|
|
|
81660
81866
|
if (!root) return null;
|
|
81661
81867
|
const existingPath = findConfigFile(root);
|
|
81662
81868
|
const configPath = existingPath ?? join4(root, DEFAULT_CONFIG_FILENAME);
|
|
81663
|
-
const configUri =
|
|
81869
|
+
const configUri = pathToFileURL6(configPath).toString();
|
|
81664
81870
|
const action = {
|
|
81665
81871
|
title: `Add '${macroName}' to ${basename2(configPath)}`,
|
|
81666
81872
|
kind: "quickfix",
|
|
@@ -81734,7 +81940,7 @@ function addMacroToYamlConfig(text3, macroName) {
|
|
|
81734
81940
|
const nl = text3.indexOf("\n", offset2);
|
|
81735
81941
|
offset2 = nl === -1 ? text3.length : nl + 1;
|
|
81736
81942
|
}
|
|
81737
|
-
const lead = offset2 === text3.length && text3.length > 0 &&
|
|
81943
|
+
const lead = offset2 === text3.length && text3.length > 0 && !/[\r\n]$/.test(text3) ? "\n" : "";
|
|
81738
81944
|
const pos = offsetToPosition2(text3, offset2);
|
|
81739
81945
|
return { range: { start: pos, end: pos }, newText: lead + entry };
|
|
81740
81946
|
}
|
|
@@ -81764,16 +81970,14 @@ function addMacroToJsonConfig(text3, macroName) {
|
|
|
81764
81970
|
container.macros = { [macroName]: NEW_MACRO_ENTRY };
|
|
81765
81971
|
}
|
|
81766
81972
|
const indent = text3.match(/^[ \t]+(?=")/m)?.[0] ?? " ";
|
|
81767
|
-
const newline =
|
|
81973
|
+
const newline = /[\r\n]$/.test(text3) || !text3.trim() ? "\n" : "";
|
|
81768
81974
|
return minimalEdit(text3, JSON.stringify(raw, null, indent) + newline);
|
|
81769
81975
|
}
|
|
81770
81976
|
function columnOf2(text3, offset2) {
|
|
81771
|
-
return
|
|
81977
|
+
return offsetToPosition2(text3, offset2).character;
|
|
81772
81978
|
}
|
|
81773
81979
|
function offsetToPosition2(text3, offset2) {
|
|
81774
|
-
|
|
81775
|
-
const lineStart = before.lastIndexOf("\n") + 1;
|
|
81776
|
-
return { line: before.split("\n").length - 1, character: offset2 - lineStart };
|
|
81980
|
+
return offsetToPosition(offset2, buildLineStarts(text3));
|
|
81777
81981
|
}
|
|
81778
81982
|
function minimalEdit(oldText, newText) {
|
|
81779
81983
|
const max = Math.min(oldText.length, newText.length);
|
|
@@ -81790,19 +81994,19 @@ function minimalEdit(oldText, newText) {
|
|
|
81790
81994
|
};
|
|
81791
81995
|
}
|
|
81792
81996
|
function insertLinesAt(text3, line, body, eol) {
|
|
81793
|
-
const lines = text3
|
|
81997
|
+
const lines = splitLines(text3);
|
|
81794
81998
|
const normalized = body.replace(/\r?\n/g, eol);
|
|
81795
81999
|
if (line < lines.length) {
|
|
81796
82000
|
const pos = { line, character: 0 };
|
|
81797
82001
|
return { range: { start: pos, end: pos }, newText: normalized };
|
|
81798
82002
|
}
|
|
81799
82003
|
const end = offsetToPosition2(text3, text3.length);
|
|
81800
|
-
const atBoundary = text3.length === 0 ||
|
|
82004
|
+
const atBoundary = text3.length === 0 || /[\r\n]$/.test(text3);
|
|
81801
82005
|
return { range: { start: end, end }, newText: (atBoundary ? "" : eol) + normalized };
|
|
81802
82006
|
}
|
|
81803
82007
|
function lineEndingFor(workspace, uri) {
|
|
81804
82008
|
const own2 = workspace.documents.getText(uri) ?? "";
|
|
81805
|
-
const detect = (text3) => text3.includes("\r\n") ? "\r\n" : text3.includes("\n") ? "\n" : void 0;
|
|
82009
|
+
const detect = (text3) => text3.includes("\r\n") ? "\r\n" : text3.includes("\n") ? "\n" : text3.includes("\r") ? "\r" : void 0;
|
|
81806
82010
|
const fromOwn = detect(own2);
|
|
81807
82011
|
if (fromOwn) return fromOwn;
|
|
81808
82012
|
for (const other of [...workspace.documents.getUris()].sort()) {
|
|
@@ -81821,7 +82025,7 @@ function declareVariable(diag, workspace, sigil) {
|
|
|
81821
82025
|
if (text3 === void 0) return [];
|
|
81822
82026
|
const markup = workspace.markup.get(passage.uri)?.passages.find((p) => p.passage === passage);
|
|
81823
82027
|
if (!markup) return [];
|
|
81824
|
-
const boundary = markup.bodyEnd === text3.length ? text3
|
|
82028
|
+
const boundary = markup.bodyEnd === text3.length ? splitLines(text3).length : markup.position(markup.content.length).line;
|
|
81825
82029
|
const edit = insertLinesAt(text3, boundary, `${sigil}${name} = 0
|
|
81826
82030
|
`, lineEndingFor(workspace, passage.uri));
|
|
81827
82031
|
return [{
|
|
@@ -81837,7 +82041,7 @@ function fixNoStoryVariables(workspace) {
|
|
|
81837
82041
|
if (targetUri === void 0) return null;
|
|
81838
82042
|
const text3 = workspace.documents.getText(targetUri);
|
|
81839
82043
|
if (text3 === void 0) return null;
|
|
81840
|
-
const edit = insertLinesAt(text3, text3
|
|
82044
|
+
const edit = insertLinesAt(text3, splitLines(text3).length, "\n:: StoryVariables\n", lineEndingFor(workspace, targetUri));
|
|
81841
82045
|
return {
|
|
81842
82046
|
title: "Create StoryVariables passage",
|
|
81843
82047
|
kind: "quickfix",
|
|
@@ -81882,10 +82086,10 @@ function fixBrokenLink(uri, diag, workspace) {
|
|
|
81882
82086
|
edits: [{ uri, ...edit }]
|
|
81883
82087
|
});
|
|
81884
82088
|
}
|
|
81885
|
-
const
|
|
81886
|
-
if (!workspace.passages.getPassage(name) &&
|
|
81887
|
-
const edit = insertLinesAt(text3, text3
|
|
81888
|
-
${
|
|
82089
|
+
const encoded = encodePassageName(name);
|
|
82090
|
+
if (!workspace.passages.getPassage(name) && encoded !== void 0) {
|
|
82091
|
+
const edit = insertLinesAt(text3, splitLines(text3).length, `
|
|
82092
|
+
:: ${encoded}
|
|
81889
82093
|
`, lineEndingFor(workspace, uri));
|
|
81890
82094
|
actions.push({
|
|
81891
82095
|
title: `Create passage '${name}'`,
|
|
@@ -82233,7 +82437,7 @@ function computeDocumentLinks(uri, workspace) {
|
|
|
82233
82437
|
const links = [];
|
|
82234
82438
|
for (const ref2 of documentPassageRefs(doc)) {
|
|
82235
82439
|
if (ref2.form !== "bracket") continue;
|
|
82236
|
-
const targetPassage = workspace.passages.
|
|
82440
|
+
const targetPassage = workspace.passages.getEffectivePassage(ref2.name);
|
|
82237
82441
|
links.push({
|
|
82238
82442
|
range: ref2.range,
|
|
82239
82443
|
target: targetPassage ? `${targetPassage.uri}#L${targetPassage.range.start.line + 1}` : void 0
|
|
@@ -82319,7 +82523,7 @@ var server_exports2 = {};
|
|
|
82319
82523
|
__export(server_exports2, {
|
|
82320
82524
|
startServer: () => startServer
|
|
82321
82525
|
});
|
|
82322
|
-
import { fileURLToPath as fileURLToPath5, pathToFileURL as
|
|
82526
|
+
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL7 } from "node:url";
|
|
82323
82527
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
82324
82528
|
import { basename as basename3, dirname as dirname6 } from "node:path";
|
|
82325
82529
|
function uriToFsPath(uri) {
|
|
@@ -82330,7 +82534,7 @@ function uriToFsPath(uri) {
|
|
|
82330
82534
|
}
|
|
82331
82535
|
}
|
|
82332
82536
|
function fsPathToUri(fsPath) {
|
|
82333
|
-
return
|
|
82537
|
+
return pathToFileURL7(fsPath).toString();
|
|
82334
82538
|
}
|
|
82335
82539
|
function isConfigFileUri(uri) {
|
|
82336
82540
|
const name = basename3(uriToFsPath(uri));
|
|
@@ -82344,6 +82548,10 @@ function startServer(args2) {
|
|
|
82344
82548
|
let activePlugins = [];
|
|
82345
82549
|
let workspaceRoot;
|
|
82346
82550
|
let startupWarning;
|
|
82551
|
+
let completeInitialScan;
|
|
82552
|
+
const initialScan = new Promise((resolve8) => {
|
|
82553
|
+
completeInitialScan = resolve8;
|
|
82554
|
+
});
|
|
82347
82555
|
connection.onInitialize((params) => {
|
|
82348
82556
|
console.error("[spindle-lsp] onInitialize called");
|
|
82349
82557
|
const initOptions = params.initializationOptions ?? {};
|
|
@@ -82371,7 +82579,10 @@ function startServer(args2) {
|
|
|
82371
82579
|
activePlugins = loadPlugins(allPlugins, config2);
|
|
82372
82580
|
console.error("[spindle-lsp] plugins loaded:", activePlugins.map((p) => p.id).join(", "));
|
|
82373
82581
|
const model = workspace;
|
|
82374
|
-
const pluginConnection = gateConnection(connection, () =>
|
|
82582
|
+
const pluginConnection = gateConnection(connection, async () => {
|
|
82583
|
+
await initialScan;
|
|
82584
|
+
return model.initialized && model.isSpindleProject();
|
|
82585
|
+
});
|
|
82375
82586
|
for (const plugin of activePlugins) {
|
|
82376
82587
|
plugin.initialize({ connection: pluginConnection, workspace, config: config2 });
|
|
82377
82588
|
}
|
|
@@ -82423,6 +82634,8 @@ function startServer(args2) {
|
|
|
82423
82634
|
console.error("[spindle-lsp] workspace initialized, macros:", workspace.macros.getAllMacros().length);
|
|
82424
82635
|
} catch (err) {
|
|
82425
82636
|
console.error("[spindle-lsp] workspace scan failed:", err);
|
|
82637
|
+
} finally {
|
|
82638
|
+
completeInitialScan();
|
|
82426
82639
|
}
|
|
82427
82640
|
});
|
|
82428
82641
|
}
|