@rohal12/spindle-lsp 0.15.51 → 0.15.53

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
@@ -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.51";
58
+ VERSION = false ? pkg.version : "0.15.53";
59
59
  }
60
60
  });
61
61
 
@@ -32646,7 +32646,7 @@ function trimmedEnd(text3, end = text3.length) {
32646
32646
  function parsePassageHeader(rawLine, lineNumber) {
32647
32647
  const line = withoutCr(rawLine);
32648
32648
  const bomLength = /^\uFEFF*/.exec(line)[0].length;
32649
- const escaped = line.replace(/\\./g, "ec");
32649
+ const escaped = line.replace(/\\./gs, "ec");
32650
32650
  const prefix2 = new RegExp("^::\\p{White_Space}*", "u").exec(escaped.slice(bomLength));
32651
32651
  if (!prefix2) return null;
32652
32652
  const nameStart = bomLength + prefix2[0].length;
@@ -32655,7 +32655,7 @@ function parsePassageHeader(rawLine, lineNumber) {
32655
32655
  const first = delimiter.exec(escaped);
32656
32656
  const boundary = first?.index ?? line.length;
32657
32657
  const nameEnd = trimmedEnd(escaped, boundary);
32658
- const decodedName = line.slice(nameStart, nameEnd).replace(/\\(.|$)/g, "$1").replace(new RegExp("^\\p{White_Space}+", "u"), "");
32658
+ const decodedName = line.slice(nameStart, nameEnd).replace(/\\(.|$)/gs, "$1").replace(new RegExp("^\\p{White_Space}+", "u"), "");
32659
32659
  const name = decodedName.slice(0, trimmedEnd(decodedName));
32660
32660
  if (!name) return null;
32661
32661
  let rest = boundary;
@@ -32663,7 +32663,7 @@ function parsePassageHeader(rawLine, lineNumber) {
32663
32663
  if (escaped[rest] === "[") {
32664
32664
  const end = escaped.indexOf("]", rest + 1);
32665
32665
  if (end === -1 || /[\[{}]/.test(escaped.slice(rest + 1, end))) return null;
32666
- const decoded = line.slice(rest + 1, end).replace(/\\(.)/g, "$1");
32666
+ const decoded = line.slice(rest + 1, end).replace(/\\(.)/gs, "$1");
32667
32667
  tags = decoded.match(/[^\p{White_Space}]+/gu) ?? [];
32668
32668
  rest = end + 1;
32669
32669
  while (rest < line.length && new RegExp("\\p{White_Space}", "u").test(escaped[rest])) rest++;
@@ -33928,7 +33928,8 @@ var init_passage_markup = __esm({
33928
33928
  get invocations() {
33929
33929
  if (!this.cachedInvocations) {
33930
33930
  const macros = this.doc.context.macros;
33931
- const definitions = widgetDefinitions([{ ...this.passage, content: this.content }], macros);
33931
+ const customWidgetMacro = macros.find((macro) => macro.name.toLowerCase() === "widget")?.source === "user";
33932
+ const definitions = customWidgetMacro ? [] : widgetDefinitions([{ ...this.passage, content: this.content }], macros);
33932
33933
  const registration = new Set(definitions.map((definition2) => definition2.start));
33933
33934
  this.cachedInvocations = this.isMarkup ? macroCalls(this.content, macros).filter((call) => call.kind === "invocation" && !registration.has(call.token.start)).map((call) => call.token) : [];
33934
33935
  }
@@ -34291,12 +34292,18 @@ var init_variable_tracker = __esm({
34291
34292
  // src/core/markup/widgets.ts
34292
34293
  function widgetSources(passages, macros) {
34293
34294
  const sources = /* @__PURE__ */ new Map();
34294
- for (const passage of passages) {
34295
- if (!passage.isMarkup) continue;
34296
- const { name, tags } = passage.passage;
34297
- for (const definition2 of widgetDefinitions([{ name, tags, content: passage.content }], macros)) {
34298
- sources.set(definition2, passage);
34299
- }
34295
+ const markups = [...passages].filter((passage) => passage.isMarkup);
34296
+ const inputs = markups.map((passage, index) => ({
34297
+ name: String(index),
34298
+ // Keep StoryInit discoverable under its source key; tooling selects all
34299
+ // other passages using their original tags.
34300
+ tags: passage.passage.name === "StoryInit" ? [...passage.passage.tags ?? [], "widget"] : passage.passage.tags,
34301
+ content: passage.content
34302
+ }));
34303
+ for (const definition2 of widgetDefinitions(inputs, macros)) {
34304
+ const passage = markups[Number(definition2.passage)];
34305
+ definition2.passage = passage.passage.name;
34306
+ sources.set(definition2, passage);
34300
34307
  }
34301
34308
  return sources;
34302
34309
  }
@@ -36245,13 +36252,13 @@ function loopDiagnostics(passage, token, ancestors, workspace) {
36245
36252
  const close = loop?.node.body?.close;
36246
36253
  if (!loop || !close) return [];
36247
36254
  const targets = macro === "computed" ? computedTemporaryTarget(token.rawArgs) : setTemporaryTargets(token.rawArgs);
36248
- const view = sourceView(passage, token.argsStart, token.argsEnd);
36249
- const argsIndex = viewIndex(view, token.argsStart);
36255
+ let view;
36250
36256
  const bodyStart = loop.node.token.end;
36251
36257
  const diagnostics = [];
36252
36258
  for (const target of targets) {
36253
36259
  if (!isReadInBody(passage, bodyStart, close.start, target.name, token.start, token.end)) continue;
36254
- const start = argsIndex + target.offset;
36260
+ view ??= sourceView(passage, token.argsStart, token.argsEnd);
36261
+ const start = viewIndex(view, token.argsStart) + target.offset;
36255
36262
  diagnostics.push(makeDiag(
36256
36263
  passage.range(pieceOffset(view, start), pieceOffset(view, start + 1 + target.name.length)),
36257
36264
  DiagnosticCode.TemporaryAssignedInLoop,
@@ -36260,26 +36267,50 @@ function loopDiagnostics(passage, token, ancestors, workspace) {
36260
36267
  }
36261
36268
  return diagnostics;
36262
36269
  }
36263
- function isReadInBody(passage, bodyStart, bodyEnd, name, macroStart, macroEnd) {
36264
- const eligible = (offset2) => offset2 >= bodyStart && offset2 < bodyEnd && !(offset2 >= macroStart && offset2 < macroEnd);
36270
+ function temporaryReads(passage) {
36271
+ const cached2 = temporaryReadIndexes.get(passage);
36272
+ if (cached2) return cached2;
36273
+ const reads = /* @__PURE__ */ new Map();
36274
+ const add = (name, offset2) => {
36275
+ const offsets = reads.get(name);
36276
+ if (offsets) offsets.push(offset2);
36277
+ else reads.set(name, [offset2]);
36278
+ };
36265
36279
  for (const token of markupTokens(passage)) {
36266
- if (token.type === "variable" && token.scope === "temporary" && token.name.split(".")[0] === name && eligible(token.start)) return true;
36280
+ if (token.type === "variable" && token.scope === "temporary") add(token.name.split(".")[0], token.start);
36267
36281
  }
36268
36282
  for (const piece of passage.pieces) {
36269
36283
  if (piece.kind !== "code") continue;
36270
36284
  try {
36271
- if (parseCode(piece.code, piece.goal).refs.some(
36272
- (ref2) => ref2.sigil === "_" && ref2.name === name && ref2.read && eligible(pieceOffset(piece, ref2.start))
36273
- )) return true;
36285
+ for (const ref2 of parseCode(piece.code, piece.goal).refs) {
36286
+ if (ref2.sigil === "_" && ref2.read) add(ref2.name, pieceOffset(piece, ref2.start));
36287
+ }
36274
36288
  } catch {
36275
36289
  }
36276
36290
  }
36277
- return false;
36291
+ for (const offsets of reads.values()) offsets.sort((a, b) => a - b);
36292
+ temporaryReadIndexes.set(passage, reads);
36293
+ return reads;
36294
+ }
36295
+ function isReadInBody(passage, bodyStart, bodyEnd, name, macroStart, macroEnd) {
36296
+ const offsets = temporaryReads(passage).get(name);
36297
+ if (!offsets) return false;
36298
+ const firstAt = (start) => {
36299
+ let low = 0;
36300
+ let high = offsets.length;
36301
+ while (low < high) {
36302
+ const mid = low + high >>> 1;
36303
+ if (offsets[mid] < start) low = mid + 1;
36304
+ else high = mid;
36305
+ }
36306
+ return offsets[low] ?? Infinity;
36307
+ };
36308
+ const first = firstAt(bodyStart);
36309
+ return (first >= macroStart && first < macroEnd ? firstAt(macroEnd) : first) < bodyEnd;
36278
36310
  }
36279
36311
  function argumentDiagnostics(passage, workspace, getPassageNames) {
36280
36312
  const diagnostics = [];
36281
- for (const token of passage.isMarkup ? macroTokens(passage) : []) {
36282
- if (token.type !== "macro" || token.isClose) continue;
36313
+ for (const token of passage.invocations) {
36283
36314
  const info = workspace.getEffectiveMacro(token.name);
36284
36315
  if (!info?.parameters || info.skipArgs || info.parameterDefs?.length) continue;
36285
36316
  if (SPINDLE_MACROS.has(token.name.toLowerCase()) && !workspace.macros.hasDiscoveredMacro(token.name)) continue;
@@ -36290,21 +36321,26 @@ function argumentDiagnostics(passage, workspace, getPassageNames) {
36290
36321
  continue;
36291
36322
  }
36292
36323
  const range2 = passage.range(token.start, token.end);
36293
- const args2 = lexArguments(token.rawArgs);
36294
- if (params.isEmpty()) {
36295
- if (args2.length > 0) {
36296
- diagnostics.push(makeDiag(range2, DiagnosticCode.ExpectedNoArguments, `Expected no arguments for {${token.name}}, got ${args2.length}`));
36324
+ try {
36325
+ const args2 = lexArguments(token.rawArgs);
36326
+ if (params.isEmpty()) {
36327
+ if (args2.length > 0) {
36328
+ diagnostics.push(makeDiag(range2, DiagnosticCode.ExpectedNoArguments, `Expected no arguments for {${token.name}}, got ${args2.length}`));
36329
+ }
36330
+ continue;
36297
36331
  }
36298
- continue;
36299
- }
36300
- const result2 = params.validate(args2, { passages: getPassageNames() });
36301
- if (result2.variantIndex === null) continue;
36302
- for (const error62 of result2.errors) {
36303
- const code = error62.message.startsWith("Too many arguments") ? DiagnosticCode.TooManyArguments : DiagnosticCode.ParameterTypeError;
36304
- diagnostics.push(makeDiag(range2, code, `{${token.name}}: ${error62.message}`));
36305
- }
36306
- for (const warning of result2.warnings) {
36307
- diagnostics.push(makeDiag(range2, DiagnosticCode.ParameterWarning, `{${token.name}}: ${warning.message}`));
36332
+ const result2 = params.validate(args2, { passages: getPassageNames() });
36333
+ if (result2.variantIndex === null) continue;
36334
+ for (const error62 of result2.errors) {
36335
+ const code = error62.message.startsWith("Too many arguments") ? DiagnosticCode.TooManyArguments : DiagnosticCode.ParameterTypeError;
36336
+ diagnostics.push(makeDiag(range2, code, `{${token.name}}: ${error62.message}`));
36337
+ }
36338
+ for (const warning of result2.warnings) {
36339
+ diagnostics.push(makeDiag(range2, DiagnosticCode.ParameterWarning, `{${token.name}}: ${warning.message}`));
36340
+ }
36341
+ } catch (error62) {
36342
+ const reason = error62 instanceof Error ? error62.message : String(error62);
36343
+ diagnostics.push(makeDiag(range2, DiagnosticCode.ParameterTypeError, `{${token.name}}: Unable to validate arguments: ${reason}`));
36308
36344
  }
36309
36345
  }
36310
36346
  return diagnostics;
@@ -36327,6 +36363,7 @@ function widgetDiagnostics(passage, story, workspace) {
36327
36363
  ));
36328
36364
  }
36329
36365
  }
36366
+ if (workspace.getEffectiveMacro("include")?.source !== "builtin") return diagnostics;
36330
36367
  for (const piece of passage.pieces) {
36331
36368
  if (piece.kind !== "passage" || piece.macro !== "include") continue;
36332
36369
  const target = workspace.passages.getEffectivePassage(piece.name);
@@ -36432,7 +36469,7 @@ function toLspDiagnostic(d) {
36432
36469
  data: d.data
36433
36470
  };
36434
36471
  }
36435
- var tweeReports, reports, COMPILER_PASSAGES, MARKUP_CODES, text2, list2, VARIABLE_CODES, WILL_NOT_START, BRANCH_MACROS2, DIRECT_CHILD_MACROS, DEFERRED_CONTAINERS, SPINDLE_MACROS, diagnosticsPlugin;
36472
+ var tweeReports, reports, COMPILER_PASSAGES, MARKUP_CODES, text2, list2, VARIABLE_CODES, WILL_NOT_START, BRANCH_MACROS2, DIRECT_CHILD_MACROS, DEFERRED_CONTAINERS, temporaryReadIndexes, SPINDLE_MACROS, diagnosticsPlugin;
36436
36473
  var init_diagnostics = __esm({
36437
36474
  "src/plugins/diagnostics.ts"() {
36438
36475
  "use strict";
@@ -36487,6 +36524,7 @@ var init_diagnostics = __esm({
36487
36524
  BRANCH_MACROS2 = /* @__PURE__ */ new Set(["elseif", "else", "case", "default", "next"]);
36488
36525
  DIRECT_CHILD_MACROS = /* @__PURE__ */ new Set(["option"]);
36489
36526
  DEFERRED_CONTAINERS = /* @__PURE__ */ new Set(["link", "button"]);
36527
+ temporaryReadIndexes = /* @__PURE__ */ new WeakMap();
36490
36528
  SPINDLE_MACROS = /* @__PURE__ */ new Set([
36491
36529
  ...builtinMacros.flatMap((macro) => [macro.name, ...macro.subMacros]).map((name) => name.toLowerCase()),
36492
36530
  ...BRANCH_MACROS2