@rohal12/spindle-lsp 0.15.12 → 0.15.13

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.12";
58
+ VERSION = false ? pkg.version : "0.15.13";
59
59
  }
60
60
  });
61
61
 
@@ -31377,7 +31377,7 @@ var init_passage_index = __esm({
31377
31377
  /** The documents' URIs in a fixed (sorted) order, so lookups never depend on the order documents were opened. */
31378
31378
  sortedUris = null;
31379
31379
  uris() {
31380
- return this.sortedUris ??= [...this.byUri.keys()].sort();
31380
+ return this.sortedUris ??= [...this.byUri.keys()].sort(compareSourceUris);
31381
31381
  }
31382
31382
  /**
31383
31383
  * Parse all passage headers in the given document text and
@@ -31454,7 +31454,11 @@ var init_passage_index = __esm({
31454
31454
  }
31455
31455
  /** The compiler replaces duplicate passages with the later source declaration. */
31456
31456
  getEffectivePassage(name) {
31457
- return this.getPassages(name).sort((a, b) => compareSourceUris(a.uri, b.uri)).at(-1);
31457
+ return this.getPassages(name).at(-1);
31458
+ }
31459
+ /** Later duplicates replace the original slot, before any runtime role exclusions. */
31460
+ getEffectivePassages() {
31461
+ return [...new Map(this.getAllPassages().map((passage) => [passage.name, passage])).values()];
31458
31462
  }
31459
31463
  /** Get the passage containing a specific line in a document. */
31460
31464
  getPassageAt(uri, line) {
@@ -32915,28 +32919,44 @@ var init_widget_registry = __esm({
32915
32919
  /** Per-URI set of lower-cased macro names opened in that document. */
32916
32920
  invokedByUri = /* @__PURE__ */ new Map();
32917
32921
  /**
32918
- * Read the widget definitions of `passages` (all of them, in workspace
32919
- * order). Public tooling selects the closed definitions in runtime phase
32920
- * order, preserving their identities so the original source is retained.
32922
+ * Read effective story passages in compiler order. Superseded passages may
32923
+ * supply editor navigation while a replacement is incomplete; they cannot
32924
+ * register runtime widgets. Tooling selects definitions in runtime phase order.
32921
32925
  */
32922
- scan(passages, macros) {
32926
+ scan(passages, macros, superseded = []) {
32923
32927
  this.widgets.clear();
32924
32928
  this.incomplete.clear();
32925
- const sources = widgetSources(passages, [...macros]);
32929
+ const metadata2 = [...macros];
32930
+ const sources = widgetSources(passages, metadata2);
32926
32931
  const effective = new Set(effectiveWidgetDefinitions([...sources.keys()]));
32932
+ const incompletePassages = /* @__PURE__ */ new Map();
32933
+ const located = (definition2, markup) => ({
32934
+ tooling: definition2,
32935
+ name: definition2.name,
32936
+ params: definition2.params,
32937
+ uri: markup.passage.uri,
32938
+ range: markup.range(definition2.start, definition2.end),
32939
+ nameRange: markup.range(definition2.nameStart, definition2.nameEnd),
32940
+ block: definition2.block
32941
+ });
32927
32942
  for (const [definition2, markup] of sources) {
32928
- const widget = {
32929
- tooling: definition2,
32930
- name: definition2.name,
32931
- params: definition2.params,
32932
- uri: markup.passage.uri,
32933
- range: markup.range(definition2.start, definition2.end),
32934
- nameRange: markup.range(definition2.nameStart, definition2.nameEnd),
32935
- block: definition2.block
32936
- };
32943
+ const widget = located(definition2, markup);
32937
32944
  const key = definition2.name.toLowerCase();
32938
32945
  if (effective.has(definition2)) this.widgets.set(key, widget);
32939
- else if (definition2.closeStart === void 0) this.incomplete.set(key, widget);
32946
+ else if (definition2.closeStart === void 0) {
32947
+ this.incomplete.set(key, widget);
32948
+ incompletePassages.set(key, markup.passage.name);
32949
+ }
32950
+ }
32951
+ if (incompletePassages.size > 0) {
32952
+ const previous2 = widgetSources(superseded, metadata2);
32953
+ const candidates = [...previous2.keys()].filter((definition2) => {
32954
+ const name = definition2.name.toLowerCase();
32955
+ return !this.widgets.has(name) && incompletePassages.get(name) === previous2.get(definition2).passage.name;
32956
+ });
32957
+ for (const definition2 of effectiveWidgetDefinitions(candidates)) {
32958
+ this.incomplete.set(definition2.name.toLowerCase(), located(definition2, previous2.get(definition2)));
32959
+ }
32940
32960
  }
32941
32961
  }
32942
32962
  /** The effective definition, or an incomplete declaration while its first definition is being typed. */
@@ -33876,21 +33896,24 @@ var init_workspace_model = __esm({
33876
33896
  refreshDiscoveredMacros() {
33877
33897
  const found = [];
33878
33898
  const init = [];
33879
- for (const uri of this.documents.getUris().sort()) {
33899
+ const seen = /* @__PURE__ */ new Set();
33900
+ const effective = new Map(this.passages.getEffectivePassages().map((passage) => [passage.name, passage]));
33901
+ for (const uri of this.documents.getUris().sort(compareSourceUris)) {
33880
33902
  const text3 = this.documents.getText(uri);
33881
33903
  if (!text3) continue;
33882
33904
  if (isMacroSource(uri)) {
33883
33905
  found.push(...discoverMacros(text3));
33884
33906
  continue;
33885
33907
  }
33886
- let lines;
33887
- for (const passage of this.passages.getPassagesInDocument(uri)) {
33908
+ for (const source of this.passages.getPassagesInDocument(uri)) {
33909
+ if (seen.has(source.name)) continue;
33910
+ seen.add(source.name);
33911
+ const passage = effective.get(source.name);
33888
33912
  if (passage.tags?.includes("Twine.private")) continue;
33889
33913
  const isStoryInit = passage.name === "StoryInit" && isRuntimePassage(passage);
33890
33914
  const isScript = passage.tags?.includes("script") ?? false;
33891
33915
  if (!isStoryInit && !isScript) continue;
33892
- lines ??= text3.split("\n");
33893
- const content2 = lines.slice(passage.headerEnd.end.line + 1, passage.range.end.line + 1).join("\n");
33916
+ const content2 = this.markup.get(passage.uri)?.passages.find((p) => p.passage === passage)?.content ?? "";
33894
33917
  if (isScript) found.push(...discoverMacros(content2));
33895
33918
  else init.push(...storyInitMacros(content2));
33896
33919
  }
@@ -33926,15 +33949,18 @@ var init_workspace_model = __esm({
33926
33949
  });
33927
33950
  const markups = /* @__PURE__ */ new Map();
33928
33951
  for (const doc of readDocuments()) for (const passage of doc.passages) markups.set(passage.passage, passage);
33952
+ const effective = new Set(this.passages.getEffectivePassages());
33929
33953
  this.widgets.scan(
33930
- this.passages.getAllPassages().flatMap((passage) => markups.get(passage) ?? []),
33931
- this.macros.toolingMacros()
33954
+ [...effective].flatMap((passage) => markups.get(passage) ?? []),
33955
+ this.macros.toolingMacros(),
33956
+ [...markups].filter(([passage]) => !effective.has(passage)).map(([, markup]) => markup)
33932
33957
  );
33933
33958
  this.markup.invalidate();
33934
33959
  this.widgets.clearInvocations();
33935
33960
  for (const doc of readDocuments()) {
33936
- this.variables.scanDocument(doc.uri, doc.text, doc);
33937
- this.widgets.recordInvocations(doc.uri, doc.passages);
33961
+ const passages = doc.passages.filter((p) => effective.has(p.passage));
33962
+ this.variables.scanDocument(doc.uri, doc.text, { passages });
33963
+ this.widgets.recordInvocations(doc.uri, passages);
33938
33964
  }
33939
33965
  }
33940
33966
  /** All runtime metadata, with real macros taking precedence over widgets. */
@@ -34312,7 +34338,9 @@ function computeDiagnostics(uri, workspace, options) {
34312
34338
  }
34313
34339
  };
34314
34340
  const story = storyReport(workspace);
34341
+ const effective = new Set(workspace.passages.getEffectivePassages());
34315
34342
  for (const passage of doc.passages) {
34343
+ if (!effective.has(passage.passage)) continue;
34316
34344
  attempt(() => diagnostics.push(...markupDiagnostics(passage, story, workspace)));
34317
34345
  attempt(() => diagnostics.push(...variableDiagnostics(passage, story)));
34318
34346
  attempt(() => diagnostics.push(...structureDiagnostics(passage, workspace)));
@@ -34322,7 +34350,10 @@ function computeDiagnostics(uri, workspace, options) {
34322
34350
  attempt(() => diagnostics.push(...versionDiagnostics(uri, doc, workspace)));
34323
34351
  attempt(() => diagnostics.push(...storyVariablesDiagnostics(uri, doc, story, workspace)));
34324
34352
  attempt(() => diagnostics.push(...arrayMemberDiagnostics(uri, workspace)));
34325
- attempt(() => diagnostics.push(...linkDiagnostics(doc)));
34353
+ attempt(() => diagnostics.push(...linkDiagnostics(doc).filter((diagnostic) => {
34354
+ const passage = doc.passageAt(diagnostic.range.start);
34355
+ return passage !== void 0 && effective.has(passage.passage);
34356
+ })));
34326
34357
  attempt(() => diagnostics.push(...unusedWidgetDiagnostics(doc, story)));
34327
34358
  if (options?.maxLineLength) {
34328
34359
  const maxLength = options.maxLineLength;
@@ -34349,12 +34380,13 @@ function buildReport(documents, workspace) {
34349
34380
  const storeVar = workspace.macros.getMacro(macro.name)?.storeVar;
34350
34381
  return storeVar ? { ...macro, storeVar } : macro;
34351
34382
  });
34352
- const passages = [];
34383
+ const markups = /* @__PURE__ */ new Map();
34353
34384
  for (const doc of documents) {
34354
34385
  for (const passage of doc.passages) {
34355
- if (isRuntimePassage(passage.passage)) passages.push(passage);
34386
+ markups.set(passage.passage, passage);
34356
34387
  }
34357
34388
  }
34389
+ const passages = workspace.passages.getEffectivePassages().filter(isRuntimePassage).flatMap((passage) => markups.get(passage) ?? []);
34358
34390
  const markup = /* @__PURE__ */ new Map();
34359
34391
  const validationMacros = toolingMacros.map((macro) => workspace.macros.hasConfiguredParameters(macro.name) ? { ...macro, widget: void 0 } : macro);
34360
34392
  const found = validateStoryMarkup(
@@ -34390,6 +34422,7 @@ function buildReport(documents, workspace) {
34390
34422
  }
34391
34423
  return {
34392
34424
  documents,
34425
+ passages,
34393
34426
  macros,
34394
34427
  markup,
34395
34428
  widgets,
@@ -34503,11 +34536,11 @@ function storyVariablesDiagnostics(uri, doc, story, workspace) {
34503
34536
  }
34504
34537
  function storyUsesVariables(story) {
34505
34538
  const excluded = /* @__PURE__ */ new Set(["StoryVariables", "StoryInit", "StoryData", "StoryScript", "StoryInterface"]);
34506
- return story.documents.some((doc) => doc.passages.some((passage) => passage.isMarkup && !excluded.has(passage.passage.name) && validateVariableReferences(
34539
+ return story.passages.some((passage) => passage.isMarkup && !excluded.has(passage.passage.name) && validateVariableReferences(
34507
34540
  [{ name: passage.passage.name, content: passage.content }],
34508
34541
  { variables: /* @__PURE__ */ new Map() },
34509
34542
  story.macros
34510
- ).some((diagnostic) => diagnostic.code === "undeclared-variable")));
34543
+ ).some((diagnostic) => diagnostic.code === "undeclared-variable"));
34511
34544
  }
34512
34545
  function arrayMemberDiagnostics(uri, workspace) {
34513
34546
  return workspace.variables.getArrayMemberAccesses(uri).map((access) => {
@@ -34708,7 +34741,7 @@ function isReadInBody(passage, bodyStart, bodyEnd, name, macroStart, macroEnd) {
34708
34741
  }
34709
34742
  function argumentDiagnostics(passage, workspace) {
34710
34743
  const diagnostics = [];
34711
- const passageNames = workspace.passages.getAllPassages().filter(isRuntimePassage).map((candidate) => candidate.name);
34744
+ const passageNames = workspace.passages.getEffectivePassages().filter(isRuntimePassage).map((candidate) => candidate.name);
34712
34745
  for (const token of passage.isMarkup ? macroTokens(passage) : []) {
34713
34746
  if (token.type !== "macro" || token.isClose) continue;
34714
34747
  const info = workspace.macros.getMacro(token.name);
@@ -34761,7 +34794,7 @@ function widgetDiagnostics(passage, story, workspace) {
34761
34794
  }
34762
34795
  for (const piece of passage.pieces) {
34763
34796
  if (piece.kind !== "passage" || piece.macro !== "include") continue;
34764
- const target = workspace.passages.getPassage(piece.name);
34797
+ const target = workspace.passages.getEffectivePassage(piece.name);
34765
34798
  if (!target?.tags?.includes("widget")) continue;
34766
34799
  const defined = story.widgetList.filter((widget) => widget.passage.passage === target).map((widget) => widget.definition.name);
34767
34800
  if (defined.length === 0) continue;
@@ -79946,7 +79979,7 @@ function linkable(name) {
79946
79979
  return tokens2.length === 1 && link.type === "link" && link.target === name && !bracketLinkMismatch("label", name);
79947
79980
  }
79948
79981
  function getPassageNameCompletions(workspace) {
79949
- return workspace.passages.getAllPassages().filter((p) => isRuntimePassage(p) && linkable(p.name)).map((p) => ({
79982
+ return workspace.passages.getEffectivePassages().filter((p) => isRuntimePassage(p) && linkable(p.name)).map((p) => ({
79950
79983
  label: p.name,
79951
79984
  kind: 18,
79952
79985
  // CompletionItemKind.Reference
@@ -81913,7 +81946,7 @@ __export(server_exports2, {
81913
81946
  });
81914
81947
  import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL6 } from "node:url";
81915
81948
  import { readFileSync as readFileSync8 } from "node:fs";
81916
- import { basename as basename3 } from "node:path";
81949
+ import { basename as basename3, dirname as dirname6 } from "node:path";
81917
81950
  function uriToFsPath(uri) {
81918
81951
  try {
81919
81952
  return fileURLToPath5(uri);
@@ -82050,7 +82083,7 @@ function startServer(args2) {
82050
82083
  if (workspace) {
82051
82084
  try {
82052
82085
  const fsPath = uriToFsPath(textDocument.uri);
82053
- if (isExcludedProjectFile(fsPath, workspaceRoot)) {
82086
+ if (isExcludedProjectFile(fsPath, workspaceRoot) || !canDiscoverProjectPath(fsPath, workspaceRoot ?? dirname6(fsPath))) {
82054
82087
  workspace.documents.close(textDocument.uri);
82055
82088
  } else {
82056
82089
  const text3 = readFileSync8(fsPath, "utf-8");
@@ -82081,15 +82114,16 @@ function startServer(args2) {
82081
82114
  configChanged = true;
82082
82115
  continue;
82083
82116
  }
82084
- if (isExcludedProjectFile(uriToFsPath(change.uri), workspaceRoot)) {
82117
+ if (documents.has(change.uri)) continue;
82118
+ const fsPath = uriToFsPath(change.uri);
82119
+ if (isExcludedProjectFile(fsPath, workspaceRoot) || !canDiscoverProjectPath(fsPath, workspaceRoot ?? dirname6(fsPath))) {
82120
+ workspace.documents.close(change.uri);
82085
82121
  continue;
82086
82122
  }
82087
- if (documents.has(change.uri)) continue;
82088
82123
  if (change.type === import_node.FileChangeType.Deleted) {
82089
82124
  workspace.documents.close(change.uri);
82090
82125
  } else {
82091
82126
  try {
82092
- const fsPath = uriToFsPath(change.uri);
82093
82127
  const text3 = readFileSync8(fsPath, "utf-8");
82094
82128
  if (workspace.documents.has(change.uri)) {
82095
82129
  workspace.documents.update(change.uri, text3);