@rohal12/spindle-lsp 0.7.1 → 0.8.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 CHANGED
@@ -448,8 +448,10 @@ var init_variable_tracker = __esm({
448
448
  VariableTracker = class {
449
449
  declared = /* @__PURE__ */ new Map();
450
450
  _hasStoryVariables = false;
451
+ _nullDeclarations = [];
451
452
  declaredTransient = /* @__PURE__ */ new Map();
452
453
  _hasStoryTransients = false;
454
+ _nullTransientDeclarations = [];
453
455
  /** Per-URI list of variable usages. */
454
456
  usagesByUri = /* @__PURE__ */ new Map();
455
457
  /** Per-URI list of transient variable usages. */
@@ -458,17 +460,32 @@ var init_variable_tracker = __esm({
458
460
  * Parse the StoryVariables passage content for declarations.
459
461
  * Each line like `$name = value` becomes a declaration.
460
462
  */
461
- parseStoryVariables(content) {
463
+ parseStoryVariables(content, contentStartLine = 0) {
462
464
  this.declared.clear();
463
465
  this._hasStoryVariables = true;
466
+ this._nullDeclarations = [];
464
467
  const lines = content.split("\n");
465
- for (const line of lines) {
466
- const trimmed = line.trim();
468
+ for (let i = 0; i < lines.length; i++) {
469
+ const trimmed = lines[i].trim();
467
470
  if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("<!--")) continue;
468
471
  const match = /^\$([A-Za-z_$][\w$]*)\s*=\s*(.*)$/.exec(trimmed);
469
472
  if (!match) continue;
470
473
  const name = match[1];
471
474
  const expr = match[2].trim();
475
+ if (expr === "null") {
476
+ const charIdx = lines[i].indexOf("null", lines[i].indexOf("="));
477
+ const absLine = contentStartLine + i;
478
+ this._nullDeclarations.push({
479
+ name,
480
+ sigil: "$",
481
+ range: {
482
+ start: { line: absLine, character: charIdx },
483
+ end: { line: absLine, character: charIdx + 4 }
484
+ }
485
+ });
486
+ this.declared.set(name, { name, sigil: "$" });
487
+ continue;
488
+ }
472
489
  const decl = { name, sigil: "$" };
473
490
  if (expr.startsWith("{")) {
474
491
  const fieldRegex = /(\w+)\s*:/g;
@@ -488,17 +505,32 @@ var init_variable_tracker = __esm({
488
505
  * Parse the StoryTransients passage content for declarations.
489
506
  * Each line like `%name = value` becomes a declaration.
490
507
  */
491
- parseStoryTransients(content) {
508
+ parseStoryTransients(content, contentStartLine = 0) {
492
509
  this.declaredTransient.clear();
493
510
  this._hasStoryTransients = true;
511
+ this._nullTransientDeclarations = [];
494
512
  const lines = content.split("\n");
495
- for (const line of lines) {
496
- const trimmed = line.trim();
513
+ for (let i = 0; i < lines.length; i++) {
514
+ const trimmed = lines[i].trim();
497
515
  if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("<!--")) continue;
498
516
  const match = /^%([A-Za-z_$][\w$]*)\s*=\s*(.*)$/.exec(trimmed);
499
517
  if (!match) continue;
500
518
  const name = match[1];
501
519
  const expr = match[2].trim();
520
+ if (expr === "null") {
521
+ const charIdx = lines[i].indexOf("null", lines[i].indexOf("="));
522
+ const absLine = contentStartLine + i;
523
+ this._nullTransientDeclarations.push({
524
+ name,
525
+ sigil: "%",
526
+ range: {
527
+ start: { line: absLine, character: charIdx },
528
+ end: { line: absLine, character: charIdx + 4 }
529
+ }
530
+ });
531
+ this.declaredTransient.set(name, { name, sigil: "%" });
532
+ continue;
533
+ }
502
534
  const decl = { name, sigil: "%" };
503
535
  if (expr.startsWith("{")) {
504
536
  const fieldRegex = /(\w+)\s*:/g;
@@ -660,6 +692,14 @@ var init_variable_tracker = __esm({
660
692
  hasStoryTransients() {
661
693
  return this._hasStoryTransients;
662
694
  }
695
+ /** Get variables declared with null values in StoryVariables. */
696
+ getNullDeclarations() {
697
+ return this._nullDeclarations;
698
+ }
699
+ /** Get transient variables declared with null values in StoryTransients. */
700
+ getNullTransientDeclarations() {
701
+ return this._nullTransientDeclarations;
702
+ }
663
703
  };
664
704
  }
665
705
  });
@@ -1238,7 +1278,7 @@ var init_workspace_model = __esm({
1238
1278
  }
1239
1279
  }
1240
1280
  const content = lines.slice(contentStart, contentEnd).join("\n");
1241
- this.variables.parseStoryVariables(content);
1281
+ this.variables.parseStoryVariables(content, contentStart);
1242
1282
  }
1243
1283
  }
1244
1284
  const storyTransients = this.passages.getStoryTransients();
@@ -1255,7 +1295,7 @@ var init_workspace_model = __esm({
1255
1295
  }
1256
1296
  }
1257
1297
  const content = lines.slice(contentStart, contentEnd).join("\n");
1258
- this.variables.parseStoryTransients(content);
1298
+ this.variables.parseStoryTransients(content, contentStart);
1259
1299
  }
1260
1300
  }
1261
1301
  for (const uri of this.documents.getUris()) {
@@ -1306,6 +1346,7 @@ var init_diagnostic_codes = __esm({
1306
1346
  UndeclaredField: "SP201",
1307
1347
  NoStoryVariables: "SP202",
1308
1348
  UndeclaredTransient: "SP203",
1349
+ NullVariableValue: "SP204",
1309
1350
  BrokenPassageLink: "SP300",
1310
1351
  WidgetArgCountMismatch: "SP301",
1311
1352
  DeadEndPassage: "SP400",
@@ -1324,10 +1365,11 @@ var init_diagnostic_codes = __esm({
1324
1365
  SP112: "warning",
1325
1366
  SP114: "error",
1326
1367
  SP115: "error",
1327
- SP200: "warning",
1368
+ SP200: "error",
1328
1369
  SP201: "warning",
1329
1370
  SP202: "info",
1330
1371
  SP203: "warning",
1372
+ SP204: "error",
1331
1373
  SP300: "warning",
1332
1374
  SP301: "warning",
1333
1375
  SP400: "hint",
@@ -2434,6 +2476,16 @@ function validateVariables(uri, workspace, diagnostics) {
2434
2476
  `Variable '$${u.name}' is not declared in StoryVariables`
2435
2477
  ));
2436
2478
  }
2479
+ const storyVars = workspace.passages.getStoryVariables();
2480
+ if (storyVars && storyVars.uri === uri) {
2481
+ for (const nd of workspace.variables.getNullDeclarations()) {
2482
+ diagnostics.push(makeDiag(
2483
+ nd.range,
2484
+ DiagnosticCode.NullVariableValue,
2485
+ `Variable '$${nd.name}' is set to null. Spindle does not support null \u2014 use a valid default (number, string, boolean, array, or object).`
2486
+ ));
2487
+ }
2488
+ }
2437
2489
  }
2438
2490
  if (workspace.variables.hasStoryTransients()) {
2439
2491
  const undeclaredTransient = workspace.variables.getUndeclaredTransient(uri);
@@ -2444,6 +2496,16 @@ function validateVariables(uri, workspace, diagnostics) {
2444
2496
  `Transient variable '%${u.name}' is not declared in StoryTransients`
2445
2497
  ));
2446
2498
  }
2499
+ const storyTransients = workspace.passages.getStoryTransients();
2500
+ if (storyTransients && storyTransients.uri === uri) {
2501
+ for (const nd of workspace.variables.getNullTransientDeclarations()) {
2502
+ diagnostics.push(makeDiag(
2503
+ nd.range,
2504
+ DiagnosticCode.NullVariableValue,
2505
+ `Transient variable '%${nd.name}' is set to null. Spindle does not support null \u2014 use a valid default (number, string, boolean, array, or object).`
2506
+ ));
2507
+ }
2508
+ }
2447
2509
  }
2448
2510
  }
2449
2511
  function validateLinks(text, passages, passageNames, diagnostics) {
@@ -5387,6 +5449,11 @@ function computeCodeActions(uri, diagnostics, workspace) {
5387
5449
  if (action) actions.push(action);
5388
5450
  break;
5389
5451
  }
5452
+ case DiagnosticCode.NullVariableValue: {
5453
+ const action = fixNullVariableValue(uri, diag);
5454
+ if (action) actions.push(action);
5455
+ break;
5456
+ }
5390
5457
  }
5391
5458
  }
5392
5459
  return actions;
@@ -5443,7 +5510,7 @@ function fixUndeclaredVariable(diag, workspace) {
5443
5510
  start: { line: insertLine, character: 0 },
5444
5511
  end: { line: insertLine, character: 0 }
5445
5512
  },
5446
- newText: `$${varName} = null
5513
+ newText: `$${varName} = 0
5447
5514
  `
5448
5515
  }]
5449
5516
  };
@@ -5498,11 +5565,23 @@ function fixUndeclaredTransient(diag, workspace) {
5498
5565
  start: { line: insertLine, character: 0 },
5499
5566
  end: { line: insertLine, character: 0 }
5500
5567
  },
5501
- newText: `%${varName} = null
5568
+ newText: `%${varName} = 0
5502
5569
  `
5503
5570
  }]
5504
5571
  };
5505
5572
  }
5573
+ function fixNullVariableValue(uri, diag) {
5574
+ return {
5575
+ title: "Replace null with 0",
5576
+ kind: "quickfix",
5577
+ diagnosticCodes: [DiagnosticCode.NullVariableValue],
5578
+ edits: [{
5579
+ uri,
5580
+ range: diag.range,
5581
+ newText: "0"
5582
+ }]
5583
+ };
5584
+ }
5506
5585
  function toLspRange6(r) {
5507
5586
  return {
5508
5587
  start: { line: r.start.line, character: r.start.character },