@rohal12/spindle-lsp 0.5.4 → 0.7.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/bin.js +481 -25
- package/dist/bin.js.map +3 -3
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -210,6 +210,10 @@ var init_passage_index = __esm({
|
|
|
210
210
|
getStoryVariables() {
|
|
211
211
|
return this.getPassage("StoryVariables");
|
|
212
212
|
}
|
|
213
|
+
/** Get the StoryTransients passage, if any. */
|
|
214
|
+
getStoryTransients() {
|
|
215
|
+
return this.getPassage("StoryTransients");
|
|
216
|
+
}
|
|
213
217
|
/** Get the StoryInit passage, if any. */
|
|
214
218
|
getStoryInit() {
|
|
215
219
|
return this.getPassage("StoryInit");
|
|
@@ -412,14 +416,16 @@ var init_macro_registry = __esm({
|
|
|
412
416
|
});
|
|
413
417
|
|
|
414
418
|
// src/core/workspace/variable-tracker.ts
|
|
415
|
-
var varRefRegex, EXCLUDED_PASSAGES, CLEAN_PATTERNS, VariableTracker;
|
|
419
|
+
var varRefRegex, transientRefRegex, EXCLUDED_PASSAGES, CLEAN_PATTERNS, VariableTracker;
|
|
416
420
|
var init_variable_tracker = __esm({
|
|
417
421
|
"src/core/workspace/variable-tracker.ts"() {
|
|
418
422
|
"use strict";
|
|
419
423
|
init_passage_parser();
|
|
420
424
|
varRefRegex = /\$([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g;
|
|
425
|
+
transientRefRegex = /(?<!\w)%([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g;
|
|
421
426
|
EXCLUDED_PASSAGES = /* @__PURE__ */ new Set([
|
|
422
427
|
"StoryVariables",
|
|
428
|
+
"StoryTransients",
|
|
423
429
|
"StoryInit",
|
|
424
430
|
"StoryData",
|
|
425
431
|
"StoryScript",
|
|
@@ -442,8 +448,12 @@ var init_variable_tracker = __esm({
|
|
|
442
448
|
VariableTracker = class {
|
|
443
449
|
declared = /* @__PURE__ */ new Map();
|
|
444
450
|
_hasStoryVariables = false;
|
|
451
|
+
declaredTransient = /* @__PURE__ */ new Map();
|
|
452
|
+
_hasStoryTransients = false;
|
|
445
453
|
/** Per-URI list of variable usages. */
|
|
446
454
|
usagesByUri = /* @__PURE__ */ new Map();
|
|
455
|
+
/** Per-URI list of transient variable usages. */
|
|
456
|
+
transientUsagesByUri = /* @__PURE__ */ new Map();
|
|
447
457
|
/**
|
|
448
458
|
* Parse the StoryVariables passage content for declarations.
|
|
449
459
|
* Each line like `$name = value` becomes a declaration.
|
|
@@ -474,14 +484,46 @@ var init_variable_tracker = __esm({
|
|
|
474
484
|
this.declared.set(name, decl);
|
|
475
485
|
}
|
|
476
486
|
}
|
|
487
|
+
/**
|
|
488
|
+
* Parse the StoryTransients passage content for declarations.
|
|
489
|
+
* Each line like `%name = value` becomes a declaration.
|
|
490
|
+
*/
|
|
491
|
+
parseStoryTransients(content) {
|
|
492
|
+
this.declaredTransient.clear();
|
|
493
|
+
this._hasStoryTransients = true;
|
|
494
|
+
const lines = content.split("\n");
|
|
495
|
+
for (const line of lines) {
|
|
496
|
+
const trimmed = line.trim();
|
|
497
|
+
if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("<!--")) continue;
|
|
498
|
+
const match = /^%([A-Za-z_$][\w$]*)\s*=\s*(.*)$/.exec(trimmed);
|
|
499
|
+
if (!match) continue;
|
|
500
|
+
const name = match[1];
|
|
501
|
+
const expr = match[2].trim();
|
|
502
|
+
const decl = { name, sigil: "%" };
|
|
503
|
+
if (expr.startsWith("{")) {
|
|
504
|
+
const fieldRegex = /(\w+)\s*:/g;
|
|
505
|
+
let fieldMatch;
|
|
506
|
+
const fields = [];
|
|
507
|
+
while ((fieldMatch = fieldRegex.exec(expr)) !== null) {
|
|
508
|
+
fields.push(fieldMatch[1]);
|
|
509
|
+
}
|
|
510
|
+
if (fields.length > 0) {
|
|
511
|
+
decl.fields = fields;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
this.declaredTransient.set(name, decl);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
477
517
|
/**
|
|
478
518
|
* Scan a document for variable usages.
|
|
479
519
|
* Identifies passages in the document and scans non-special ones.
|
|
480
520
|
*/
|
|
481
521
|
scanDocument(uri, text, _macros) {
|
|
482
522
|
this.usagesByUri.delete(uri);
|
|
523
|
+
this.transientUsagesByUri.delete(uri);
|
|
483
524
|
const lines = text.split("\n");
|
|
484
525
|
const usages = [];
|
|
526
|
+
const transientUsages = [];
|
|
485
527
|
const passageBoundaries = [];
|
|
486
528
|
for (let i = 0; i < lines.length; i++) {
|
|
487
529
|
const header = parsePassageHeader(lines[i], i);
|
|
@@ -523,10 +565,32 @@ var init_variable_tracker = __esm({
|
|
|
523
565
|
};
|
|
524
566
|
usages.push({ uri, baseName, fullName, range });
|
|
525
567
|
}
|
|
568
|
+
const tre = new RegExp(transientRefRegex.source, "g");
|
|
569
|
+
let tmatch;
|
|
570
|
+
while ((tmatch = tre.exec(cleaned)) !== null) {
|
|
571
|
+
const fullName = tmatch[1];
|
|
572
|
+
const baseName = fullName.split(".")[0];
|
|
573
|
+
const charOffset = tmatch.index;
|
|
574
|
+
let localLine = 0;
|
|
575
|
+
for (let i = 0; i < lineOffsets.length; i++) {
|
|
576
|
+
if (lineOffsets[i] > charOffset) break;
|
|
577
|
+
localLine = i;
|
|
578
|
+
}
|
|
579
|
+
const character = charOffset - lineOffsets[localLine];
|
|
580
|
+
const absoluteLine = contentStartLine + localLine;
|
|
581
|
+
const range = {
|
|
582
|
+
start: { line: absoluteLine, character },
|
|
583
|
+
end: { line: absoluteLine, character: character + tmatch[0].length }
|
|
584
|
+
};
|
|
585
|
+
transientUsages.push({ uri, baseName, fullName, range });
|
|
586
|
+
}
|
|
526
587
|
}
|
|
527
588
|
if (usages.length > 0) {
|
|
528
589
|
this.usagesByUri.set(uri, usages);
|
|
529
590
|
}
|
|
591
|
+
if (transientUsages.length > 0) {
|
|
592
|
+
this.transientUsagesByUri.set(uri, transientUsages);
|
|
593
|
+
}
|
|
530
594
|
}
|
|
531
595
|
/** Get all declared variables. */
|
|
532
596
|
getDeclared() {
|
|
@@ -562,6 +626,40 @@ var init_variable_tracker = __esm({
|
|
|
562
626
|
hasStoryVariables() {
|
|
563
627
|
return this._hasStoryVariables;
|
|
564
628
|
}
|
|
629
|
+
/** Get all declared transient variables. */
|
|
630
|
+
getDeclaredTransient() {
|
|
631
|
+
return this.declaredTransient;
|
|
632
|
+
}
|
|
633
|
+
/** Get all usages of a transient variable by base name. */
|
|
634
|
+
getTransientUsages(name) {
|
|
635
|
+
const results = [];
|
|
636
|
+
for (const usages of this.transientUsagesByUri.values()) {
|
|
637
|
+
for (const u of usages) {
|
|
638
|
+
if (u.baseName === name) {
|
|
639
|
+
results.push({ uri: u.uri, range: u.range });
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
return results;
|
|
644
|
+
}
|
|
645
|
+
/** Get undeclared transient variable usages in a specific document. */
|
|
646
|
+
getUndeclaredTransient(uri) {
|
|
647
|
+
const usages = this.transientUsagesByUri.get(uri);
|
|
648
|
+
if (!usages) return [];
|
|
649
|
+
const results = [];
|
|
650
|
+
const seen = /* @__PURE__ */ new Set();
|
|
651
|
+
for (const u of usages) {
|
|
652
|
+
if (!this.declaredTransient.has(u.baseName) && !seen.has(u.baseName)) {
|
|
653
|
+
seen.add(u.baseName);
|
|
654
|
+
results.push({ name: u.baseName, range: u.range });
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return results;
|
|
658
|
+
}
|
|
659
|
+
/** Whether a StoryTransients passage has been parsed. */
|
|
660
|
+
hasStoryTransients() {
|
|
661
|
+
return this._hasStoryTransients;
|
|
662
|
+
}
|
|
565
663
|
};
|
|
566
664
|
}
|
|
567
665
|
});
|
|
@@ -721,7 +819,7 @@ var variableInterpolationRegex, macroRegex;
|
|
|
721
819
|
var init_macro_parser = __esm({
|
|
722
820
|
"src/core/parsing/macro-parser.ts"() {
|
|
723
821
|
"use strict";
|
|
724
|
-
variableInterpolationRegex = /(?<!\\)\{([$_
|
|
822
|
+
variableInterpolationRegex = /(?<!\\)\{([$_@%][A-Za-z_$][\w$.]*)\}/g;
|
|
725
823
|
macroRegex = /(?<!\\)\{(\/)?(?:((?:[#.][a-zA-Z][\w-]*\s*)*)([A-Za-z][\w-]*))(?:\s+((?:(?:`(?:\\.|[^`\\])*?`)|(?:"(?:\\.|[^"\\])*?")|(?:'(?:\\.|[^'\\])*?')|(?:\[(?:[<>]?[Ii][Mm][Gg])?\[[^\r\n]*?\]\]+)|[^}]|(?:}))*?))?\}/gmi;
|
|
726
824
|
}
|
|
727
825
|
});
|
|
@@ -799,12 +897,12 @@ var init_macro_supplements = __esm({
|
|
|
799
897
|
},
|
|
800
898
|
set: {
|
|
801
899
|
name: "set",
|
|
802
|
-
description: "Sets variables based on the given expression.\n\nUsage: `{set $var to value}`\n\nSupports `$var` (story), `_var` (temporary),
|
|
900
|
+
description: "Sets variables based on the given expression.\n\nUsage: `{set $var to value}`\n\nSupports `$var` (story), `_var` (temporary), `@var` (local), and `%var` (transient) variables.",
|
|
803
901
|
parameters: ["...text"]
|
|
804
902
|
},
|
|
805
903
|
unset: {
|
|
806
904
|
name: "unset",
|
|
807
|
-
description: "Unsets one or more variables.\n\nUsage: `{unset $var}`",
|
|
905
|
+
description: "Unsets one or more variables.\n\nUsage: `{unset $var}`\n\nSupports `$var` (story), `_var` (temporary), `@var` (local), and `%var` (transient) variables.",
|
|
808
906
|
parameters: ["...text"]
|
|
809
907
|
},
|
|
810
908
|
computed: {
|
|
@@ -1143,6 +1241,23 @@ var init_workspace_model = __esm({
|
|
|
1143
1241
|
this.variables.parseStoryVariables(content);
|
|
1144
1242
|
}
|
|
1145
1243
|
}
|
|
1244
|
+
const storyTransients = this.passages.getStoryTransients();
|
|
1245
|
+
if (storyTransients) {
|
|
1246
|
+
const text = this.documents.getText(storyTransients.uri);
|
|
1247
|
+
if (text) {
|
|
1248
|
+
const lines = text.split("\n");
|
|
1249
|
+
const contentStart = storyTransients.headerEnd.end.line + 1;
|
|
1250
|
+
let contentEnd = lines.length;
|
|
1251
|
+
for (let i = contentStart; i < lines.length; i++) {
|
|
1252
|
+
if (/^::\s+/.test(lines[i])) {
|
|
1253
|
+
contentEnd = i;
|
|
1254
|
+
break;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
const content = lines.slice(contentStart, contentEnd).join("\n");
|
|
1258
|
+
this.variables.parseStoryTransients(content);
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1146
1261
|
for (const uri of this.documents.getUris()) {
|
|
1147
1262
|
const text = this.documents.getText(uri);
|
|
1148
1263
|
if (text) {
|
|
@@ -1190,10 +1305,12 @@ var init_diagnostic_codes = __esm({
|
|
|
1190
1305
|
UndeclaredVariable: "SP200",
|
|
1191
1306
|
UndeclaredField: "SP201",
|
|
1192
1307
|
NoStoryVariables: "SP202",
|
|
1308
|
+
UndeclaredTransient: "SP203",
|
|
1193
1309
|
BrokenPassageLink: "SP300",
|
|
1194
1310
|
WidgetArgCountMismatch: "SP301",
|
|
1195
1311
|
DeadEndPassage: "SP400",
|
|
1196
|
-
UnreachablePassage: "SP401"
|
|
1312
|
+
UnreachablePassage: "SP401",
|
|
1313
|
+
LineTooLong: "SP500"
|
|
1197
1314
|
};
|
|
1198
1315
|
severityMap = {
|
|
1199
1316
|
SP100: "warning",
|
|
@@ -1210,10 +1327,12 @@ var init_diagnostic_codes = __esm({
|
|
|
1210
1327
|
SP200: "warning",
|
|
1211
1328
|
SP201: "warning",
|
|
1212
1329
|
SP202: "info",
|
|
1330
|
+
SP203: "warning",
|
|
1213
1331
|
SP300: "warning",
|
|
1214
1332
|
SP301: "warning",
|
|
1215
1333
|
SP400: "hint",
|
|
1216
|
-
SP401: "hint"
|
|
1334
|
+
SP401: "hint",
|
|
1335
|
+
SP500: "warning"
|
|
1217
1336
|
};
|
|
1218
1337
|
}
|
|
1219
1338
|
});
|
|
@@ -1409,7 +1528,7 @@ var varTestRegexp, EOF, Lexer, notSpaceRegex, spaceRegex;
|
|
|
1409
1528
|
var init_argument_lexer = __esm({
|
|
1410
1529
|
"src/core/parsing/argument-lexer.ts"() {
|
|
1411
1530
|
"use strict";
|
|
1412
|
-
varTestRegexp = /^[$_
|
|
1531
|
+
varTestRegexp = /^[$_@%][$A-Z_a-z][$0-9A-Z_.a-z]*/;
|
|
1413
1532
|
EOF = -1;
|
|
1414
1533
|
Lexer = class {
|
|
1415
1534
|
source;
|
|
@@ -2092,7 +2211,7 @@ var init_link_parser = __esm({
|
|
|
2092
2211
|
});
|
|
2093
2212
|
|
|
2094
2213
|
// src/plugins/diagnostics.ts
|
|
2095
|
-
function computeDiagnostics(uri, workspace) {
|
|
2214
|
+
function computeDiagnostics(uri, workspace, options) {
|
|
2096
2215
|
if (!workspace.initialized) return [];
|
|
2097
2216
|
try {
|
|
2098
2217
|
const text = workspace.documents.getText(uri);
|
|
@@ -2124,6 +2243,12 @@ function computeDiagnostics(uri, workspace) {
|
|
|
2124
2243
|
validateWidgetInvocations(macros, workspace, diagnostics);
|
|
2125
2244
|
} catch {
|
|
2126
2245
|
}
|
|
2246
|
+
if (options?.maxLineLength) {
|
|
2247
|
+
try {
|
|
2248
|
+
validateLineLength(text, passages, options.maxLineLength, diagnostics);
|
|
2249
|
+
} catch {
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2127
2252
|
return diagnostics;
|
|
2128
2253
|
} catch {
|
|
2129
2254
|
return [];
|
|
@@ -2284,7 +2409,7 @@ function validateArguments(macros, workspace, passageNames, diagnostics) {
|
|
|
2284
2409
|
}
|
|
2285
2410
|
function validateVariables(uri, workspace, diagnostics) {
|
|
2286
2411
|
if (!workspace.variables.hasStoryVariables()) {
|
|
2287
|
-
const
|
|
2412
|
+
const undeclared = workspace.variables.getUndeclared(uri);
|
|
2288
2413
|
const text = workspace.documents.getText(uri);
|
|
2289
2414
|
if (text && /\$[A-Za-z_$]/.test(text)) {
|
|
2290
2415
|
const passages = workspace.passages.getPassagesInDocument(uri);
|
|
@@ -2300,15 +2425,25 @@ function validateVariables(uri, workspace, diagnostics) {
|
|
|
2300
2425
|
));
|
|
2301
2426
|
}
|
|
2302
2427
|
}
|
|
2303
|
-
|
|
2428
|
+
} else {
|
|
2429
|
+
const undeclared = workspace.variables.getUndeclared(uri);
|
|
2430
|
+
for (const u of undeclared) {
|
|
2431
|
+
diagnostics.push(makeDiag(
|
|
2432
|
+
u.range,
|
|
2433
|
+
DiagnosticCode.UndeclaredVariable,
|
|
2434
|
+
`Variable '$${u.name}' is not declared in StoryVariables`
|
|
2435
|
+
));
|
|
2436
|
+
}
|
|
2304
2437
|
}
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2438
|
+
if (workspace.variables.hasStoryTransients()) {
|
|
2439
|
+
const undeclaredTransient = workspace.variables.getUndeclaredTransient(uri);
|
|
2440
|
+
for (const u of undeclaredTransient) {
|
|
2441
|
+
diagnostics.push(makeDiag(
|
|
2442
|
+
u.range,
|
|
2443
|
+
DiagnosticCode.UndeclaredTransient,
|
|
2444
|
+
`Transient variable '%${u.name}' is not declared in StoryTransients`
|
|
2445
|
+
));
|
|
2446
|
+
}
|
|
2312
2447
|
}
|
|
2313
2448
|
}
|
|
2314
2449
|
function validateLinks(text, passages, passageNames, diagnostics) {
|
|
@@ -2342,6 +2477,26 @@ function validateWidgetInvocations(macros, workspace, diagnostics) {
|
|
|
2342
2477
|
}
|
|
2343
2478
|
}
|
|
2344
2479
|
}
|
|
2480
|
+
function validateLineLength(text, passages, maxLength, diagnostics) {
|
|
2481
|
+
const excludedTags = /* @__PURE__ */ new Set(["script", "stylesheet"]);
|
|
2482
|
+
const excludedPassages = new Set(passages.filter((p) => p.tags?.some((t) => excludedTags.has(t))).map((p) => p.name));
|
|
2483
|
+
const lines = text.split("\n");
|
|
2484
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2485
|
+
const line = lines[i];
|
|
2486
|
+
if (/^::\s+/.test(line)) continue;
|
|
2487
|
+
if (/^\s*<[a-zA-Z]/.test(line)) continue;
|
|
2488
|
+
if (line.length > maxLength) {
|
|
2489
|
+
diagnostics.push(makeDiag(
|
|
2490
|
+
{
|
|
2491
|
+
start: { line: i, character: maxLength },
|
|
2492
|
+
end: { line: i, character: line.length }
|
|
2493
|
+
},
|
|
2494
|
+
DiagnosticCode.LineTooLong,
|
|
2495
|
+
`Line exceeds ${maxLength} characters (${line.length})`
|
|
2496
|
+
));
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2345
2500
|
function makeDiag(range, code, message) {
|
|
2346
2501
|
return {
|
|
2347
2502
|
range,
|
|
@@ -2639,6 +2794,7 @@ function parseArgs(args2) {
|
|
|
2639
2794
|
format: "pretty",
|
|
2640
2795
|
severity: null,
|
|
2641
2796
|
configPath: null,
|
|
2797
|
+
maxLineLength: null,
|
|
2642
2798
|
patterns: []
|
|
2643
2799
|
};
|
|
2644
2800
|
let i = 0;
|
|
@@ -2674,6 +2830,14 @@ function parseArgs(args2) {
|
|
|
2674
2830
|
} else if (arg.startsWith("--config=")) {
|
|
2675
2831
|
options.configPath = arg.slice("--config=".length);
|
|
2676
2832
|
i++;
|
|
2833
|
+
} else if (arg === "--max-line-length" && i + 1 < args2.length) {
|
|
2834
|
+
const n = parseInt(args2[i + 1], 10);
|
|
2835
|
+
if (!isNaN(n) && n > 0) options.maxLineLength = n;
|
|
2836
|
+
i += 2;
|
|
2837
|
+
} else if (arg.startsWith("--max-line-length=")) {
|
|
2838
|
+
const n = parseInt(arg.slice("--max-line-length=".length), 10);
|
|
2839
|
+
if (!isNaN(n) && n > 0) options.maxLineLength = n;
|
|
2840
|
+
i++;
|
|
2677
2841
|
} else if (!arg.startsWith("--")) {
|
|
2678
2842
|
options.patterns.push(arg);
|
|
2679
2843
|
i++;
|
|
@@ -2751,10 +2915,14 @@ async function runCheck(args2) {
|
|
|
2751
2915
|
if (Object.keys(projectConfig.macros).length > 0) {
|
|
2752
2916
|
workspace.macros.loadSupplements(projectConfig.macros);
|
|
2753
2917
|
}
|
|
2918
|
+
const diagOptions = {};
|
|
2919
|
+
if (options.maxLineLength !== null) {
|
|
2920
|
+
diagOptions.maxLineLength = options.maxLineLength;
|
|
2921
|
+
}
|
|
2754
2922
|
const allResults = [];
|
|
2755
2923
|
let hasErrors = false;
|
|
2756
2924
|
for (const uri of fileContents.keys()) {
|
|
2757
|
-
let diags = computeDiagnostics(uri, workspace);
|
|
2925
|
+
let diags = computeDiagnostics(uri, workspace, diagOptions);
|
|
2758
2926
|
if (options.severity) {
|
|
2759
2927
|
diags = filterBySeverity(diags, options.severity);
|
|
2760
2928
|
}
|
|
@@ -3175,7 +3343,10 @@ async function formatDocument(text, options) {
|
|
|
3175
3343
|
}
|
|
3176
3344
|
continue;
|
|
3177
3345
|
}
|
|
3178
|
-
|
|
3346
|
+
let indented = indentMacros(region.lines, isBlock, isDedenting);
|
|
3347
|
+
if (options?.maxLineLength) {
|
|
3348
|
+
indented = wrapLines(indented, options.maxLineLength);
|
|
3349
|
+
}
|
|
3179
3350
|
resultLines.push(...indented);
|
|
3180
3351
|
}
|
|
3181
3352
|
}
|
|
@@ -3209,12 +3380,78 @@ function indentMacros(lines, isBlock, isDedenting) {
|
|
|
3209
3380
|
if (openMatch && isBlock(openMatch[1])) {
|
|
3210
3381
|
indentLevel++;
|
|
3211
3382
|
}
|
|
3383
|
+
const closeGlobal = /\{\/[A-Za-z][\w-]*\s*\}/g;
|
|
3384
|
+
let cm;
|
|
3385
|
+
while ((cm = closeGlobal.exec(trimmed)) !== null) {
|
|
3386
|
+
if (cm.index > 0) {
|
|
3387
|
+
indentLevel = Math.max(0, indentLevel - 1);
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3212
3390
|
}
|
|
3213
3391
|
return result;
|
|
3214
3392
|
}
|
|
3215
3393
|
async function formatRange(text, _range, options) {
|
|
3216
3394
|
return formatDocument(text, options);
|
|
3217
3395
|
}
|
|
3396
|
+
function wrapLines(lines, maxLen) {
|
|
3397
|
+
const result = [];
|
|
3398
|
+
for (const line of lines) {
|
|
3399
|
+
if (line.length <= maxLen) {
|
|
3400
|
+
result.push(line);
|
|
3401
|
+
continue;
|
|
3402
|
+
}
|
|
3403
|
+
const trimmed = line.trim();
|
|
3404
|
+
if (trimmed === "" || /^::/.test(trimmed) || /^\{[\/#.]/.test(trimmed) || // closing/opening-only macro lines
|
|
3405
|
+
/^\[\[/.test(trimmed) || // links
|
|
3406
|
+
/^\{choice\b/.test(trimmed) || // choice macros
|
|
3407
|
+
/^\{choices\b/.test(trimmed)) {
|
|
3408
|
+
result.push(line);
|
|
3409
|
+
continue;
|
|
3410
|
+
}
|
|
3411
|
+
const indentMatch = line.match(/^(\s*)/);
|
|
3412
|
+
const indent = indentMatch ? indentMatch[1] : "";
|
|
3413
|
+
const wrapped = wordWrap(trimmed, maxLen, indent);
|
|
3414
|
+
result.push(...wrapped);
|
|
3415
|
+
}
|
|
3416
|
+
return result;
|
|
3417
|
+
}
|
|
3418
|
+
function wordWrap(text, maxLen, indent) {
|
|
3419
|
+
const lines = [];
|
|
3420
|
+
let remaining = text;
|
|
3421
|
+
while (remaining.length > 0) {
|
|
3422
|
+
const currentMax = lines.length === 0 ? maxLen - indent.length : maxLen - indent.length;
|
|
3423
|
+
if (remaining.length <= currentMax) {
|
|
3424
|
+
lines.push(indent + remaining);
|
|
3425
|
+
break;
|
|
3426
|
+
}
|
|
3427
|
+
let breakIdx = -1;
|
|
3428
|
+
let inMacro = 0;
|
|
3429
|
+
for (let i = 0; i < remaining.length && i <= currentMax; i++) {
|
|
3430
|
+
if (remaining[i] === "{") inMacro++;
|
|
3431
|
+
else if (remaining[i] === "}") inMacro = Math.max(0, inMacro - 1);
|
|
3432
|
+
else if (remaining[i] === " " && inMacro === 0 && i > 0) {
|
|
3433
|
+
breakIdx = i;
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
if (breakIdx === -1) {
|
|
3437
|
+
for (let i = currentMax + 1; i < remaining.length; i++) {
|
|
3438
|
+
if (remaining[i] === "{") inMacro++;
|
|
3439
|
+
else if (remaining[i] === "}") inMacro = Math.max(0, inMacro - 1);
|
|
3440
|
+
else if (remaining[i] === " " && inMacro === 0) {
|
|
3441
|
+
breakIdx = i;
|
|
3442
|
+
break;
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
if (breakIdx === -1) {
|
|
3447
|
+
lines.push(indent + remaining);
|
|
3448
|
+
break;
|
|
3449
|
+
}
|
|
3450
|
+
lines.push(indent + remaining.substring(0, breakIdx));
|
|
3451
|
+
remaining = remaining.substring(breakIdx + 1);
|
|
3452
|
+
}
|
|
3453
|
+
return lines;
|
|
3454
|
+
}
|
|
3218
3455
|
function normalizePassageHeader(line) {
|
|
3219
3456
|
const headerMatch = line.match(/^::\s+(.*)/);
|
|
3220
3457
|
if (!headerMatch) return line;
|
|
@@ -3304,13 +3541,28 @@ import { glob as glob2 } from "glob";
|
|
|
3304
3541
|
function parseArgs2(args2) {
|
|
3305
3542
|
const options = {
|
|
3306
3543
|
check: false,
|
|
3544
|
+
maxLineLength: null,
|
|
3307
3545
|
patterns: []
|
|
3308
3546
|
};
|
|
3309
|
-
|
|
3547
|
+
let i = 0;
|
|
3548
|
+
while (i < args2.length) {
|
|
3549
|
+
const arg = args2[i];
|
|
3310
3550
|
if (arg === "--check") {
|
|
3311
3551
|
options.check = true;
|
|
3552
|
+
i++;
|
|
3553
|
+
} else if (arg === "--max-line-length" && i + 1 < args2.length) {
|
|
3554
|
+
const n = parseInt(args2[i + 1], 10);
|
|
3555
|
+
if (!isNaN(n) && n > 0) options.maxLineLength = n;
|
|
3556
|
+
i += 2;
|
|
3557
|
+
} else if (arg.startsWith("--max-line-length=")) {
|
|
3558
|
+
const n = parseInt(arg.slice("--max-line-length=".length), 10);
|
|
3559
|
+
if (!isNaN(n) && n > 0) options.maxLineLength = n;
|
|
3560
|
+
i++;
|
|
3312
3561
|
} else if (!arg.startsWith("--")) {
|
|
3313
3562
|
options.patterns.push(arg);
|
|
3563
|
+
i++;
|
|
3564
|
+
} else {
|
|
3565
|
+
i++;
|
|
3314
3566
|
}
|
|
3315
3567
|
}
|
|
3316
3568
|
if (options.patterns.length === 0) {
|
|
@@ -3335,11 +3587,15 @@ async function runFormat(args2) {
|
|
|
3335
3587
|
console.log("No files found");
|
|
3336
3588
|
return 0;
|
|
3337
3589
|
}
|
|
3590
|
+
const formatOpts = {};
|
|
3591
|
+
if (options.maxLineLength !== null) {
|
|
3592
|
+
formatOpts.maxLineLength = options.maxLineLength;
|
|
3593
|
+
}
|
|
3338
3594
|
const unformatted = [];
|
|
3339
3595
|
for (const filePath of uniqueFiles) {
|
|
3340
3596
|
try {
|
|
3341
3597
|
const text = readFileSync5(filePath, "utf-8");
|
|
3342
|
-
const formatted = await formatDocument(text);
|
|
3598
|
+
const formatted = await formatDocument(text, formatOpts);
|
|
3343
3599
|
if (formatted !== text) {
|
|
3344
3600
|
if (options.check) {
|
|
3345
3601
|
const relative = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
|
|
@@ -3615,6 +3871,10 @@ function getCompletions(uri, position, triggerChar, workspace) {
|
|
|
3615
3871
|
if (/\{\/[A-Za-z\w-]*$/.test(lineText)) {
|
|
3616
3872
|
return getClosingMacroCompletions(text, position, workspace);
|
|
3617
3873
|
}
|
|
3874
|
+
const transientDotPathMatch = /%([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)?$/.exec(lineText);
|
|
3875
|
+
if (transientDotPathMatch) {
|
|
3876
|
+
return getTransientDotPathCompletions(transientDotPathMatch[1], workspace);
|
|
3877
|
+
}
|
|
3618
3878
|
const dotPathMatch = /\$([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)?$/.exec(lineText);
|
|
3619
3879
|
if (dotPathMatch) {
|
|
3620
3880
|
return getDotPathCompletions(dotPathMatch[1], workspace);
|
|
@@ -3628,6 +3888,9 @@ function getCompletions(uri, position, triggerChar, workspace) {
|
|
|
3628
3888
|
if (/@[A-Za-z_$]?[\w$]*$/.test(lineText)) {
|
|
3629
3889
|
return getLocalVariableCompletions(text);
|
|
3630
3890
|
}
|
|
3891
|
+
if (/%[A-Za-z_$]?[\w$]*$/.test(lineText) && !/%[A-Za-z_$][\w$]*\./.test(lineText)) {
|
|
3892
|
+
return getTransientVariableCompletions(workspace);
|
|
3893
|
+
}
|
|
3631
3894
|
if (/\[\[[^\]]*$/.test(lineText)) {
|
|
3632
3895
|
return getPassageNameCompletions(workspace);
|
|
3633
3896
|
}
|
|
@@ -3755,6 +4018,33 @@ function getDotPathCompletions(varName, workspace) {
|
|
|
3755
4018
|
detail: `field of $${varName}`
|
|
3756
4019
|
}));
|
|
3757
4020
|
}
|
|
4021
|
+
function getTransientVariableCompletions(workspace) {
|
|
4022
|
+
const declared = workspace.variables.getDeclaredTransient();
|
|
4023
|
+
if (declared.size === 0) return [];
|
|
4024
|
+
const items = [];
|
|
4025
|
+
for (const [name, decl] of declared) {
|
|
4026
|
+
items.push({
|
|
4027
|
+
label: `%${name}`,
|
|
4028
|
+
kind: 6,
|
|
4029
|
+
// CompletionItemKind.Variable
|
|
4030
|
+
detail: "transient variable",
|
|
4031
|
+
insertText: name,
|
|
4032
|
+
documentation: decl.fields && decl.fields.length > 0 ? `Fields: ${decl.fields.join(", ")}` : void 0
|
|
4033
|
+
});
|
|
4034
|
+
}
|
|
4035
|
+
return items;
|
|
4036
|
+
}
|
|
4037
|
+
function getTransientDotPathCompletions(varName, workspace) {
|
|
4038
|
+
const declared = workspace.variables.getDeclaredTransient();
|
|
4039
|
+
const decl = declared.get(varName);
|
|
4040
|
+
if (!decl || !decl.fields || decl.fields.length === 0) return [];
|
|
4041
|
+
return decl.fields.map((field) => ({
|
|
4042
|
+
label: field,
|
|
4043
|
+
kind: 5,
|
|
4044
|
+
// CompletionItemKind.Field
|
|
4045
|
+
detail: `field of %${varName}`
|
|
4046
|
+
}));
|
|
4047
|
+
}
|
|
3758
4048
|
function getPassageNameCompletions(workspace) {
|
|
3759
4049
|
const passages = workspace.passages.getAllPassages();
|
|
3760
4050
|
if (passages.length === 0) return [];
|
|
@@ -3774,7 +4064,7 @@ var init_completions = __esm({
|
|
|
3774
4064
|
id: "completions",
|
|
3775
4065
|
capabilities: {
|
|
3776
4066
|
completionProvider: {
|
|
3777
|
-
triggerCharacters: ["{", "$", "_", "@", "[", "."]
|
|
4067
|
+
triggerCharacters: ["{", "$", "_", "@", "%", "[", "."]
|
|
3778
4068
|
}
|
|
3779
4069
|
},
|
|
3780
4070
|
initialize(ctx) {
|
|
@@ -3898,6 +4188,28 @@ Fields: ${decl.fields.map((f) => `\`${f}\``).join(", ")}` : "";
|
|
|
3898
4188
|
}
|
|
3899
4189
|
}
|
|
3900
4190
|
}
|
|
4191
|
+
{
|
|
4192
|
+
const re = /(?<!\w)%([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g;
|
|
4193
|
+
let match;
|
|
4194
|
+
while ((match = re.exec(line)) !== null) {
|
|
4195
|
+
const start = match.index;
|
|
4196
|
+
const end = start + match[0].length;
|
|
4197
|
+
if (position.character >= start && position.character <= end) {
|
|
4198
|
+
const baseName = match[1].split(".")[0];
|
|
4199
|
+
const decl = workspace.variables.getDeclaredTransient().get(baseName);
|
|
4200
|
+
const typeInfo = decl?.fields && decl.fields.length > 0 ? `
|
|
4201
|
+
|
|
4202
|
+
Fields: ${decl.fields.map((f) => `\`${f}\``).join(", ")}` : "";
|
|
4203
|
+
return {
|
|
4204
|
+
contents: `**Transient variable** \`%${match[1]}\`${typeInfo}`,
|
|
4205
|
+
range: {
|
|
4206
|
+
start: { line: position.line, character: start },
|
|
4207
|
+
end: { line: position.line, character: end }
|
|
4208
|
+
}
|
|
4209
|
+
};
|
|
4210
|
+
}
|
|
4211
|
+
}
|
|
4212
|
+
}
|
|
3901
4213
|
return null;
|
|
3902
4214
|
}
|
|
3903
4215
|
function getWidgetHover(line, position, workspace) {
|
|
@@ -4180,6 +4492,18 @@ function findReferences(uri, position, workspace, includeDeclaration) {
|
|
|
4180
4492
|
}
|
|
4181
4493
|
}
|
|
4182
4494
|
}
|
|
4495
|
+
{
|
|
4496
|
+
const transRegex = /(?<!\w)%([A-Za-z_$][\w$]*)/g;
|
|
4497
|
+
let match;
|
|
4498
|
+
while ((match = transRegex.exec(line)) !== null) {
|
|
4499
|
+
const start = match.index;
|
|
4500
|
+
const end = start + match[0].length;
|
|
4501
|
+
if (position.character >= start && position.character <= end) {
|
|
4502
|
+
const varName = match[1];
|
|
4503
|
+
return findTransientReferences(varName, workspace, includeDeclaration);
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4183
4507
|
{
|
|
4184
4508
|
const widgetRegex = /\{([A-Za-z_$][\w$]*)/g;
|
|
4185
4509
|
let match;
|
|
@@ -4274,6 +4598,20 @@ function findVariableReferences(varName, workspace, includeDeclaration) {
|
|
|
4274
4598
|
}
|
|
4275
4599
|
return locations;
|
|
4276
4600
|
}
|
|
4601
|
+
function findTransientReferences(varName, workspace, includeDeclaration) {
|
|
4602
|
+
const results = [];
|
|
4603
|
+
if (includeDeclaration) {
|
|
4604
|
+
const decl = workspace.variables.getDeclaredTransient().get(varName);
|
|
4605
|
+
if (decl?.declarationUri && decl.declarationRange) {
|
|
4606
|
+
results.push({ uri: decl.declarationUri, range: decl.declarationRange });
|
|
4607
|
+
}
|
|
4608
|
+
}
|
|
4609
|
+
const usages = workspace.variables.getTransientUsages(varName);
|
|
4610
|
+
for (const u of usages) {
|
|
4611
|
+
results.push({ uri: u.uri, range: u.range });
|
|
4612
|
+
}
|
|
4613
|
+
return results;
|
|
4614
|
+
}
|
|
4277
4615
|
function findWidgetReferences(widgetName, workspace, includeDeclaration) {
|
|
4278
4616
|
const locations = [];
|
|
4279
4617
|
if (includeDeclaration) {
|
|
@@ -4366,8 +4704,9 @@ function computeRename(uri, position, newName, workspace) {
|
|
|
4366
4704
|
break;
|
|
4367
4705
|
}
|
|
4368
4706
|
case "variable": {
|
|
4369
|
-
const bareName = newName.startsWith("$") ? newName.slice(1) : newName;
|
|
4370
|
-
const
|
|
4707
|
+
const bareName = newName.startsWith("$") ? newName.slice(1) : newName.startsWith("%") ? newName.slice(1) : newName;
|
|
4708
|
+
const isTransient = workspace.variables.getDeclaredTransient().has(symbol.name);
|
|
4709
|
+
const refs = isTransient ? findTransientReferences(symbol.name, workspace, true) : findVariableReferences(symbol.name, workspace, true);
|
|
4371
4710
|
for (const ref of refs) {
|
|
4372
4711
|
addEdit(ref.uri, ref.range, bareName);
|
|
4373
4712
|
}
|
|
@@ -4446,6 +4785,24 @@ function resolveSymbolAtCursor(uri, position, workspace) {
|
|
|
4446
4785
|
}
|
|
4447
4786
|
}
|
|
4448
4787
|
}
|
|
4788
|
+
{
|
|
4789
|
+
const transRegex = /(?<!\w)%([A-Za-z_$][\w$]*)/g;
|
|
4790
|
+
let match;
|
|
4791
|
+
while ((match = transRegex.exec(line)) !== null) {
|
|
4792
|
+
const start = match.index;
|
|
4793
|
+
const end = start + match[0].length;
|
|
4794
|
+
if (position.character >= start && position.character <= end) {
|
|
4795
|
+
return {
|
|
4796
|
+
kind: "variable",
|
|
4797
|
+
name: match[1],
|
|
4798
|
+
range: {
|
|
4799
|
+
start: { line: position.line, character: start },
|
|
4800
|
+
end: { line: position.line, character: end }
|
|
4801
|
+
}
|
|
4802
|
+
};
|
|
4803
|
+
}
|
|
4804
|
+
}
|
|
4805
|
+
}
|
|
4449
4806
|
{
|
|
4450
4807
|
const widgetDefRegex2 = /\{widget\s+"([^"]+)"/gi;
|
|
4451
4808
|
let match;
|
|
@@ -4643,6 +5000,7 @@ function computeInlayHints(uri, range, workspace) {
|
|
|
4643
5000
|
const hints = [];
|
|
4644
5001
|
addWidgetParamHints(text, range, workspace, hints);
|
|
4645
5002
|
addVariableTypeHints(uri, text, range, workspace, hints);
|
|
5003
|
+
addTransientTypeHints(uri, text, range, workspace, hints);
|
|
4646
5004
|
return hints;
|
|
4647
5005
|
}
|
|
4648
5006
|
function addWidgetParamHints(text, range, workspace, hints) {
|
|
@@ -4699,6 +5057,28 @@ function addVariableTypeHints(uri, text, range, workspace, hints) {
|
|
|
4699
5057
|
});
|
|
4700
5058
|
}
|
|
4701
5059
|
}
|
|
5060
|
+
function addTransientTypeHints(uri, text, range, workspace, hints) {
|
|
5061
|
+
const storyTransientsPassage = workspace.passages.getStoryTransients();
|
|
5062
|
+
if (!storyTransientsPassage) return;
|
|
5063
|
+
if (storyTransientsPassage.uri !== uri) return;
|
|
5064
|
+
const lines = text.split("\n");
|
|
5065
|
+
const startLine = Math.max(range.start.line, 0);
|
|
5066
|
+
const endLine = Math.min(range.end.line, lines.length - 1);
|
|
5067
|
+
for (let lineNum = startLine; lineNum <= endLine; lineNum++) {
|
|
5068
|
+
const line = lines[lineNum];
|
|
5069
|
+
const declMatch = line.match(/^%([A-Za-z_$][\w$]*)\s*=\s*(.+)$/);
|
|
5070
|
+
if (!declMatch) continue;
|
|
5071
|
+
const valueStr = declMatch[2].trim();
|
|
5072
|
+
const inferredType = inferType(valueStr);
|
|
5073
|
+
if (!inferredType) continue;
|
|
5074
|
+
const eqIdx = line.indexOf("=");
|
|
5075
|
+
hints.push({
|
|
5076
|
+
position: { line: lineNum, character: eqIdx },
|
|
5077
|
+
label: `: ${inferredType}`,
|
|
5078
|
+
kind: "type"
|
|
5079
|
+
});
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
4702
5082
|
function inferType(value) {
|
|
4703
5083
|
if (/^\d+(\.\d+)?$/.test(value)) return "number";
|
|
4704
5084
|
if (/^"[^"]*"$/.test(value) || /^'[^']*'$/.test(value)) return "string";
|
|
@@ -4803,6 +5183,7 @@ function computeSemanticTokensAbsolute(uri, workspace) {
|
|
|
4803
5183
|
const storyVarRegex = /(?<!\w)\$([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g;
|
|
4804
5184
|
const tempVarRegex = /(?<!\w)_([A-Za-z_$][\w$]*)/g;
|
|
4805
5185
|
const localVarRegex = /(?<!\w)@([A-Za-z_$][\w$]*)/g;
|
|
5186
|
+
const transientVarRegex = /(?<!\w)%([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g;
|
|
4806
5187
|
const sugarKeywordRegex = /\b(to|is|isnot|eq|neq|gt|gte|lt|lte|and|or|not|def|ndef)\b/g;
|
|
4807
5188
|
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
4808
5189
|
if (headerLines.has(lineIndex)) continue;
|
|
@@ -4838,6 +5219,16 @@ function computeSemanticTokensAbsolute(uri, workspace) {
|
|
|
4838
5219
|
tokenModifiers: encodeModifiers(["readonly"])
|
|
4839
5220
|
});
|
|
4840
5221
|
}
|
|
5222
|
+
transientVarRegex.lastIndex = 0;
|
|
5223
|
+
while ((m = transientVarRegex.exec(line)) !== null) {
|
|
5224
|
+
tokens.push({
|
|
5225
|
+
line: lineIndex,
|
|
5226
|
+
startChar: m.index,
|
|
5227
|
+
length: m[0].length,
|
|
5228
|
+
tokenType: encodeType("variable"),
|
|
5229
|
+
tokenModifiers: encodeModifiers(["defaultLibrary"])
|
|
5230
|
+
});
|
|
5231
|
+
}
|
|
4841
5232
|
sugarKeywordRegex.lastIndex = 0;
|
|
4842
5233
|
while ((m = sugarKeywordRegex.exec(line)) !== null) {
|
|
4843
5234
|
tokens.push({
|
|
@@ -4942,6 +5333,11 @@ function computeCodeActions(uri, diagnostics, workspace) {
|
|
|
4942
5333
|
if (action) actions.push(action);
|
|
4943
5334
|
break;
|
|
4944
5335
|
}
|
|
5336
|
+
case DiagnosticCode.UndeclaredTransient: {
|
|
5337
|
+
const action = fixUndeclaredTransient(diag, workspace);
|
|
5338
|
+
if (action) actions.push(action);
|
|
5339
|
+
break;
|
|
5340
|
+
}
|
|
4945
5341
|
}
|
|
4946
5342
|
}
|
|
4947
5343
|
return actions;
|
|
@@ -5024,6 +5420,40 @@ function fixNoStoryVariables(uri, workspace) {
|
|
|
5024
5420
|
}]
|
|
5025
5421
|
};
|
|
5026
5422
|
}
|
|
5423
|
+
function fixUndeclaredTransient(diag, workspace) {
|
|
5424
|
+
const match = diag.message.match(/'%(\w+)'/);
|
|
5425
|
+
if (!match) return null;
|
|
5426
|
+
const varName = match[1];
|
|
5427
|
+
const storyTransients = workspace.passages.getStoryTransients();
|
|
5428
|
+
if (!storyTransients) return null;
|
|
5429
|
+
const storyTransientsUri = storyTransients.uri;
|
|
5430
|
+
const text = workspace.documents.getText(storyTransientsUri);
|
|
5431
|
+
if (text === void 0) return null;
|
|
5432
|
+
const lines = text.split("\n");
|
|
5433
|
+
const contentStart = storyTransients.headerEnd.end.line + 1;
|
|
5434
|
+
let contentEnd = lines.length;
|
|
5435
|
+
for (let i = contentStart; i < lines.length; i++) {
|
|
5436
|
+
if (/^::\s+/.test(lines[i])) {
|
|
5437
|
+
contentEnd = i;
|
|
5438
|
+
break;
|
|
5439
|
+
}
|
|
5440
|
+
}
|
|
5441
|
+
const insertLine = contentEnd;
|
|
5442
|
+
return {
|
|
5443
|
+
title: `Declare '%${varName}' in StoryTransients`,
|
|
5444
|
+
kind: "quickfix",
|
|
5445
|
+
diagnosticCodes: [DiagnosticCode.UndeclaredTransient],
|
|
5446
|
+
edits: [{
|
|
5447
|
+
uri: storyTransientsUri,
|
|
5448
|
+
range: {
|
|
5449
|
+
start: { line: insertLine, character: 0 },
|
|
5450
|
+
end: { line: insertLine, character: 0 }
|
|
5451
|
+
},
|
|
5452
|
+
newText: `%${varName} = null
|
|
5453
|
+
`
|
|
5454
|
+
}]
|
|
5455
|
+
};
|
|
5456
|
+
}
|
|
5027
5457
|
function toLspRange6(r) {
|
|
5028
5458
|
return {
|
|
5029
5459
|
start: { line: r.start.line, character: r.start.character },
|
|
@@ -5589,8 +6019,34 @@ var init_server2 = __esm({
|
|
|
5589
6019
|
});
|
|
5590
6020
|
|
|
5591
6021
|
// src/bin.ts
|
|
6022
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
5592
6023
|
var args = process.argv.slice(2);
|
|
5593
|
-
|
|
6024
|
+
var VERSION = createRequire2(import.meta.url)("../package.json").version;
|
|
6025
|
+
var HELP = `spindle-lsp v${VERSION}
|
|
6026
|
+
Language Server Protocol server for Spindle story format
|
|
6027
|
+
|
|
6028
|
+
Usage:
|
|
6029
|
+
spindle-lsp Start the LSP server (stdio)
|
|
6030
|
+
spindle-lsp check <files> Lint .twee/.tw files
|
|
6031
|
+
spindle-lsp format <files> Format .twee/.tw files in place
|
|
6032
|
+
spindle-lsp mcp Start the MCP server
|
|
6033
|
+
|
|
6034
|
+
Options:
|
|
6035
|
+
--help, -h Show this help message
|
|
6036
|
+
--version, -v Show version number
|
|
6037
|
+
|
|
6038
|
+
Check options:
|
|
6039
|
+
--format <pretty|json|sarif> Output format (default: pretty)
|
|
6040
|
+
--severity <level> Minimum severity: error, warning, info, hint
|
|
6041
|
+
--config <path> Path to config file
|
|
6042
|
+
--max-line-length <n> Warn on lines exceeding n characters`;
|
|
6043
|
+
if (args.includes("--help") || args.includes("-h") || args.length === 0) {
|
|
6044
|
+
console.log(HELP);
|
|
6045
|
+
process.exit(0);
|
|
6046
|
+
} else if (args.includes("--version") || args.includes("-v")) {
|
|
6047
|
+
console.log(VERSION);
|
|
6048
|
+
process.exit(0);
|
|
6049
|
+
} else if (args[0] === "check") {
|
|
5594
6050
|
const { runCheck: runCheck2 } = await Promise.resolve().then(() => (init_check(), check_exports));
|
|
5595
6051
|
const exitCode = await runCheck2(args.slice(1));
|
|
5596
6052
|
process.exit(exitCode);
|