luaut-language-server 1.0.0 → 1.0.1

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/README.md CHANGED
@@ -1,100 +1,100 @@
1
- # luaut-language-server
2
-
3
- Language server (LSP) for **luaut** — the TypeScript-flavoured language that
4
- compiles to Luau. It is a thin layer over [`luaut-parser`][parser]: the parser
5
- does the parsing, scope analysis and flow-sensitive type analysis, and this
6
- package answers editor questions from the tables it produces.
7
-
8
- [parser]: https://www.npmjs.com/package/luaut-parser
9
-
10
- ```bash
11
- npm install luaut-language-server
12
- luaut-language-server --stdio
13
- ```
14
-
15
- ## What it does
16
-
17
- | request | notes |
18
- |---|---|
19
- | `publishDiagnostics` | syntax, scope (redeclare, assign-to-`const`) and type errors, on open and on every keystroke |
20
- | `hover` | the type as luaut writes it — the **narrowed** type at a reference, so a guarded `v` reads `string`, not `string \| nil` |
21
- | `definition` | the binding's declaration |
22
- | `references`, `documentHighlight` | every use of the binding |
23
- | `rename`, `prepareRename` | refuses names that are not identifiers, and builtins from the definitions files |
24
- | `completion` | members after `.` / `:`, names in scope, type names in a type position |
25
- | `signatureHelp` | every overload, with the active parameter — `:` calls count `self` for you |
26
- | `documentSymbol` | functions, type aliases, top-level bindings |
27
-
28
- Single file, for now: `import` resolves to `any`, so cross-file navigation is
29
- not there yet. See [Not yet](#not-yet).
30
-
31
- ## How it is put together
32
-
33
- ```
34
- src/
35
- server.ts LSP wiring, and nothing else
36
- analysis.ts parse -> scopes -> types, cached per document version
37
- ast-utils.ts 1-based spans <-> 0-based LSP positions, position -> node
38
- features/ one file per feature; plain functions, no LSP plumbing
39
- ```
40
-
41
- A feature is `(analysis, position) -> answer`. Nothing in `features/` opens a
42
- connection or knows about documents, which is why `scripts/test.ts` can drive
43
- all of them in-process without spawning a server, and why an editor extension
44
- can call them directly:
45
-
46
- ```ts
47
- import { Analyzer, hover, diagnostics } from "luaut-language-server"
48
-
49
- const analyzer = new Analyzer() // or { libs: [...] } for your own definitions
50
- const analysis = analyzer.get(document) // a vscode-languageserver TextDocument
51
- hover(analysis, { line: 3, character: 12 })
52
- diagnostics(analysis)
53
- ```
54
-
55
- ### Speculative parsing
56
-
57
- `x.` and `add(1, ` are syntax errors — the text you are in the middle of
58
- typing usually is. Completion and signature help therefore analyze a
59
- *repaired copy* of the document: a placeholder identifier at the cursor for
60
- completion, and the shortest of `nil`, `nil)`, `)` that parses for signature
61
- help. The user's document is never touched and the repaired copy is never
62
- cached.
63
-
64
- ### Globals
65
-
66
- The names a file may use undeclared are not hard-coded: they are read out of
67
- the `declare` statements in the definitions passed to `Analyzer`. Adding a
68
- global to a `.d.luaut` is all it takes for the editor to stop calling it
69
- undefined.
70
-
71
- ## Not yet
72
-
73
- - **One file at a time.** No workspace indexing, so no cross-file
74
- go-to-definition, `workspace/symbol`, or diagnostics for files you have not
75
- opened.
76
- - **No formatting** — there is no luaut printer yet (the compiler owns
77
- emitting Luau, and it emits *Luau*, not luaut).
78
- - No code actions, inlay hints, semantic tokens, or folding ranges.
79
- - Everything `luaut-parser` does not check is invisible here too: unknown
80
- properties, writes to `readonly`, generic constraints at call sites,
81
- metatables.
82
-
83
- ## Editors
84
-
85
- VS Code: [`luaut-vscode`](../luaut-vscode) — a separate project next door. It
86
- bundles this server into the extension, so its `.vsix` is self-contained.
87
-
88
- Anything else that speaks LSP: launch `luaut-language-server --stdio` (or
89
- `--node-ipc`) and attach it to the `luaut` language / `.luaut` files.
90
-
91
- ## Development
92
-
93
- ```bash
94
- npm run typecheck
95
- npm test # features in-process, then the built binary over stdio
96
- npm run build
97
- ```
98
-
99
- `scripts/test.ts` marks the cursor with `‸` in each fixture (not `|` — that is
100
- the union operator). `scripts/e2e.ts` speaks real LSP to `dist/cli.js`.
1
+ # luaut-language-server
2
+
3
+ Language server (LSP) for **luaut** — the TypeScript-flavoured language that
4
+ compiles to Luau. It is a thin layer over [`luaut-parser`][parser]: the parser
5
+ does the parsing, scope analysis and flow-sensitive type analysis, and this
6
+ package answers editor questions from the tables it produces.
7
+
8
+ [parser]: https://www.npmjs.com/package/luaut-parser
9
+
10
+ ```bash
11
+ npm install luaut-language-server
12
+ luaut-language-server --stdio
13
+ ```
14
+
15
+ ## What it does
16
+
17
+ | request | notes |
18
+ |---|---|
19
+ | `publishDiagnostics` | syntax, scope (redeclare, assign-to-`const`) and type errors, on open and on every keystroke |
20
+ | `hover` | the type as luaut writes it — the **narrowed** type at a reference, so a guarded `v` reads `string`, not `string \| nil` |
21
+ | `definition` | the binding's declaration |
22
+ | `references`, `documentHighlight` | every use of the binding |
23
+ | `rename`, `prepareRename` | refuses names that are not identifiers, and builtins from the definitions files |
24
+ | `completion` | members after `.` / `:`, names in scope, type names in a type position |
25
+ | `signatureHelp` | every overload, with the active parameter — `:` calls count `self` for you |
26
+ | `documentSymbol` | functions, type aliases, top-level bindings |
27
+
28
+ Single file, for now: `import` resolves to `any`, so cross-file navigation is
29
+ not there yet. See [Not yet](#not-yet).
30
+
31
+ ## How it is put together
32
+
33
+ ```
34
+ src/
35
+ server.ts LSP wiring, and nothing else
36
+ analysis.ts parse -> scopes -> types, cached per document version
37
+ ast-utils.ts 1-based spans <-> 0-based LSP positions, position -> node
38
+ features/ one file per feature; plain functions, no LSP plumbing
39
+ ```
40
+
41
+ A feature is `(analysis, position) -> answer`. Nothing in `features/` opens a
42
+ connection or knows about documents, which is why `scripts/test.ts` can drive
43
+ all of them in-process without spawning a server, and why an editor extension
44
+ can call them directly:
45
+
46
+ ```ts
47
+ import { Analyzer, hover, diagnostics } from "luaut-language-server"
48
+
49
+ const analyzer = new Analyzer() // or { libs: [...] } for your own definitions
50
+ const analysis = analyzer.get(document) // a vscode-languageserver TextDocument
51
+ hover(analysis, { line: 3, character: 12 })
52
+ diagnostics(analysis)
53
+ ```
54
+
55
+ ### Speculative parsing
56
+
57
+ `x.` and `add(1, ` are syntax errors — the text you are in the middle of
58
+ typing usually is. Completion and signature help therefore analyze a
59
+ *repaired copy* of the document: a placeholder identifier at the cursor for
60
+ completion, and the shortest of `nil`, `nil)`, `)` that parses for signature
61
+ help. The user's document is never touched and the repaired copy is never
62
+ cached.
63
+
64
+ ### Globals
65
+
66
+ The names a file may use undeclared are not hard-coded: they are read out of
67
+ the `declare` statements in the definitions passed to `Analyzer`. Adding a
68
+ global to a `.d.luaut` is all it takes for the editor to stop calling it
69
+ undefined.
70
+
71
+ ## Not yet
72
+
73
+ - **One file at a time.** No workspace indexing, so no cross-file
74
+ go-to-definition, `workspace/symbol`, or diagnostics for files you have not
75
+ opened.
76
+ - **No formatting** — there is no luaut printer yet (the compiler owns
77
+ emitting Luau, and it emits *Luau*, not luaut).
78
+ - No code actions, inlay hints, semantic tokens, or folding ranges.
79
+ - Everything `luaut-parser` does not check is invisible here too: unknown
80
+ properties, writes to `readonly`, generic constraints at call sites,
81
+ metatables.
82
+
83
+ ## Editors
84
+
85
+ VS Code: [`luaut-vscode`](../luaut-vscode) — a separate project next door. It
86
+ bundles this server into the extension, so its `.vsix` is self-contained.
87
+
88
+ Anything else that speaks LSP: launch `luaut-language-server --stdio` (or
89
+ `--node-ipc`) and attach it to the `luaut` language / `.luaut` files.
90
+
91
+ ## Development
92
+
93
+ ```bash
94
+ npm run typecheck
95
+ npm test # features in-process, then the built binary over stdio
96
+ npm run build
97
+ ```
98
+
99
+ `scripts/test.ts` marks the cursor with `‸` in each fixture (not `|` — that is
100
+ the union operator). `scripts/e2e.ts` speaks real LSP to `dist/cli.js`.
@@ -3,7 +3,8 @@ import {
3
3
  parseWithRecovery,
4
4
  analyzeScopes,
5
5
  analyzeTypes,
6
- defaultLibs
6
+ defaultLibs,
7
+ getBinding
7
8
  } from "luaut-parser";
8
9
  function globalsOf(libs) {
9
10
  const names = /* @__PURE__ */ new Set();
@@ -15,6 +16,23 @@ function collect(statements, into) {
15
16
  if (statement.type === "DeclareStatement") into.add(statement.name);
16
17
  }
17
18
  }
19
+ function bindingOfNode(analysis, node) {
20
+ const used = getBinding(analysis.scopes, node);
21
+ if (used) return used;
22
+ return declarationIndex(analysis).get(node);
23
+ }
24
+ var declarationIndexes = /* @__PURE__ */ new WeakMap();
25
+ function declarationIndex(analysis) {
26
+ let index = declarationIndexes.get(analysis);
27
+ if (!index) {
28
+ index = /* @__PURE__ */ new Map();
29
+ for (const binding of analysis.scopes.bindings.values()) {
30
+ if (binding.declarationNode) index.set(binding.declarationNode, binding);
31
+ }
32
+ declarationIndexes.set(analysis, index);
33
+ }
34
+ return index;
35
+ }
18
36
  var Analyzer = class {
19
37
  libs;
20
38
  builtinGlobals;
@@ -156,7 +174,7 @@ function diagnostics(analysis) {
156
174
  }
157
175
 
158
176
  // src/features/hover.ts
159
- import { formatType, getBinding } from "luaut-parser";
177
+ import { formatType } from "luaut-parser";
160
178
  function hover(analysis, position) {
161
179
  const path = pathAt(analysis.program, position, true);
162
180
  for (let i = path.length - 1; i >= 0; i--) {
@@ -167,7 +185,7 @@ function hover(analysis, position) {
167
185
  return null;
168
186
  }
169
187
  function describe(analysis, node, parent) {
170
- const { types, scopes } = analysis;
188
+ const { types } = analysis;
171
189
  if (node.type === "TypeAliasStatement" || node.type === "ExportTypeAliasStatement") {
172
190
  const name = node.name;
173
191
  const alias = types.aliases.get(name);
@@ -177,7 +195,7 @@ function describe(analysis, node, parent) {
177
195
  const identifier = node;
178
196
  const narrowed = types.narrowedTypeOf.get(identifier);
179
197
  if (narrowed) return `${identifier.name}: ${formatType(narrowed)}`;
180
- const binding = getBinding(scopes, identifier);
198
+ const binding = bindingOfNode(analysis, identifier);
181
199
  if (binding) {
182
200
  const type2 = types.bindingType.get(binding.id);
183
201
  if (type2) return `${keyword(binding)} ${binding.name}: ${formatType(type2)}`;
@@ -187,8 +205,8 @@ function describe(analysis, node, parent) {
187
205
  if (type2) return `${identifier.name}: ${formatType(type2)}`;
188
206
  }
189
207
  }
190
- if (node.type === "IdentifierPattern") {
191
- const binding = getBinding(scopes, node);
208
+ if (node.type === "IdentifierPattern" || node.type === "FunctionParameter" || node.type === "TypedIdentifier") {
209
+ const binding = bindingOfNode(analysis, node);
192
210
  if (binding) {
193
211
  const type2 = types.bindingType.get(binding.id);
194
212
  if (type2) return `${keyword(binding)} ${binding.name}: ${formatType(type2)}`;
@@ -211,13 +229,13 @@ function code(text) {
211
229
  import {
212
230
  DocumentHighlightKind
213
231
  } from "vscode-languageserver";
214
- import { getBinding as getBinding2 } from "luaut-parser";
232
+ var NAMING = /* @__PURE__ */ new Set(["Identifier", "IdentifierPattern", "FunctionParameter", "TypedIdentifier"]);
215
233
  function bindingAt(analysis, position) {
216
234
  const path = pathAt(analysis.program, position, true);
217
235
  for (let i = path.length - 1; i >= 0; i--) {
218
236
  const node = path[i];
219
- if (node.type !== "Identifier" && node.type !== "IdentifierPattern") continue;
220
- const binding = getBinding2(analysis.scopes, node);
237
+ if (!node.type || !NAMING.has(node.type)) continue;
238
+ const binding = bindingOfNode(analysis, node);
221
239
  if (binding) return binding;
222
240
  }
223
241
  return void 0;
@@ -252,7 +270,7 @@ function prepareRename(analysis, position) {
252
270
  if (!binding) return null;
253
271
  if (binding.isBuiltin || !binding.declarationNode) return null;
254
272
  const path = pathAt(analysis.program, position, true);
255
- const identifier = [...path].reverse().find((n) => n.type === "Identifier" || n.type === "IdentifierPattern");
273
+ const identifier = [...path].reverse().find((n) => !!n.type && NAMING.has(n.type));
256
274
  if (!identifier) return null;
257
275
  return { range: toRange(identifier), placeholder: binding.name };
258
276
  }
@@ -544,7 +562,7 @@ function activeArgument(call, position) {
544
562
 
545
563
  // src/features/symbols.ts
546
564
  import { SymbolKind } from "vscode-languageserver";
547
- import { formatType as formatType4, getBinding as getBinding3 } from "luaut-parser";
565
+ import { formatType as formatType4 } from "luaut-parser";
548
566
  function documentSymbols(analysis) {
549
567
  const out = [];
550
568
  walk(analysis.program, (node) => {
@@ -590,7 +608,7 @@ function functionName(node) {
590
608
  function detailOf(analysis, node) {
591
609
  const name = node.name;
592
610
  if (name && typeof name === "object") {
593
- const binding = getBinding3(analysis.scopes, name);
611
+ const binding = bindingOfNode(analysis, name);
594
612
  const type = binding && analysis.types.bindingType.get(binding.id);
595
613
  if (type) return formatType4(type);
596
614
  }
@@ -730,4 +748,4 @@ export {
730
748
  createServer,
731
749
  startServer
732
750
  };
733
- //# sourceMappingURL=chunk-RHII344O.js.map
751
+ //# sourceMappingURL=chunk-FMWNSXUC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/analysis.ts","../src/ast-utils.ts","../src/features/diagnostics.ts","../src/features/hover.ts","../src/features/navigation.ts","../src/features/members.ts","../src/features/completion.ts","../src/features/signatureHelp.ts","../src/features/symbols.ts","../src/server.ts"],"sourcesContent":["/**\n * Analysis cache.\n *\n * The three parser passes are cheap (single-digit milliseconds for a normal\n * file) but not free, and every LSP request wants the same result for the same\n * document version — so each document is analyzed once per version and the\n * result is reused by hover, definition, completion and the rest.\n */\nimport {\n parseWithRecovery, analyzeScopes, analyzeTypes, defaultLibs, getBinding,\n type Program, type ScopeAnalysis, type TypeAnalysis, type ParseError,\n type DeclareStatement, type Statement, type Binding, type Identifier,\n} from \"luaut-parser\"\nimport type { TextDocument } from \"vscode-languageserver-textdocument\"\n\nexport interface Analysis {\n readonly uri: string\n readonly version: number\n readonly source: string\n readonly program: Program\n readonly parseErrors: readonly ParseError[]\n readonly scopes: ScopeAnalysis\n readonly types: TypeAnalysis\n}\n\nexport interface AnalyzerOptions {\n /** Definitions to analyze against. Defaults to core Luau + Roblox. */\n libs?: readonly Program[]\n}\n\n/** Names every file may use undeclared: whatever the definitions declare.\n * Derived rather than hard-coded, so adding a `declare` to a `.d.luaut` is\n * all it takes for the name to stop looking undefined. */\nfunction globalsOf(libs: readonly Program[]): string[] {\n const names = new Set<string>()\n for (const lib of libs) collect(lib.body.statements, names)\n return [...names]\n}\n\nfunction collect(statements: readonly Statement[], into: Set<string>): void {\n for (const statement of statements) {\n if (statement.type === \"DeclareStatement\") into.add((statement as DeclareStatement).name)\n }\n}\n\n/** The binding a node names, whether it *uses* the binding or *declares* it.\n *\n * Scope analysis indexes the two differently: every use is in `bindingOf`,\n * but a declaration only appears as its binding's `declarationNode`. Asking\n * `bindingOf` alone is why hovering `const x` — as opposed to a later `x` —\n * used to show nothing. */\nexport function bindingOfNode(analysis: Analysis, node: object): Binding | undefined {\n const used = getBinding(analysis.scopes, node as Identifier)\n if (used) return used\n return declarationIndex(analysis).get(node)\n}\n\nconst declarationIndexes = new WeakMap<Analysis, Map<object, Binding>>()\n\nfunction declarationIndex(analysis: Analysis): Map<object, Binding> {\n let index = declarationIndexes.get(analysis)\n if (!index) {\n index = new Map()\n for (const binding of analysis.scopes.bindings.values()) {\n if (binding.declarationNode) index.set(binding.declarationNode, binding)\n }\n declarationIndexes.set(analysis, index)\n }\n return index\n}\n\nexport class Analyzer {\n private readonly libs: readonly Program[]\n private readonly builtinGlobals: string[]\n private readonly cache = new Map<string, Analysis>()\n\n constructor(options: AnalyzerOptions = {}) {\n this.libs = options.libs ?? defaultLibs\n this.builtinGlobals = globalsOf(this.libs)\n }\n\n /** Analyze `document`, reusing the previous result if its version is\n * unchanged. */\n get(document: TextDocument): Analysis {\n const cached = this.cache.get(document.uri)\n const source = document.getText()\n // The version alone would do for a real editor, where it only ever\n // increases — comparing the text too costs nothing next to an\n // analysis and makes the cache safe for any caller.\n if (cached && cached.version === document.version && cached.source === source) return cached\n const analysis = this.analyze(document.uri, document.version, source)\n this.cache.set(document.uri, analysis)\n return analysis\n }\n\n /** Analyze source text that is not a tracked document — used by\n * completion, which analyzes a speculatively edited copy of the file. */\n analyze(uri: string, version: number, source: string): Analysis {\n const { program, errors } = parseWithRecovery(source)\n const scopes = analyzeScopes(program, { builtinGlobals: this.builtinGlobals })\n const types = analyzeTypes(program, scopes, { libs: this.libs })\n return { uri, version, source, program, parseErrors: errors, scopes, types }\n }\n\n forget(uri: string): void {\n this.cache.delete(uri)\n }\n}\n","/**\n * Position mapping and AST lookup.\n *\n * luaut spans are 1-based with an exclusive end column; LSP positions are\n * 0-based. Every conversion between the two lives here so the features never\n * do the arithmetic themselves.\n */\nimport type { Position, Range } from \"vscode-languageserver\"\n\n/** The shape every luaut AST node shares. */\nexport interface Spanned {\n type?: string\n line: { start: number; end: number }\n column: { start: number; end: number }\n}\n\nexport function isSpanned(v: unknown): v is Spanned {\n if (!v || typeof v !== \"object\") return false\n const n = v as Record<string, unknown>\n return typeof n.line === \"object\" && n.line !== null && typeof n.column === \"object\" && n.column !== null\n}\n\nexport function toRange(node: Spanned): Range {\n return {\n start: { line: node.line.start - 1, character: node.column.start - 1 },\n end: { line: node.line.end - 1, character: node.column.end - 1 },\n }\n}\n\n/** A one-character range, for a diagnostic on a node with a collapsed span. */\nexport function toPosition(line: number, column: number): Position {\n return { line: line - 1, character: column - 1 }\n}\n\n/** Is `pos` inside `node`'s span? The end is exclusive, except that `inclusive`\n * admits a cursor sitting immediately after the node — which is where it is\n * while you are still typing the identifier under it. */\nexport function containsPosition(node: Spanned, pos: Position, inclusive = false): boolean {\n const startLine = node.line.start - 1\n const endLine = node.line.end - 1\n if (pos.line < startLine || pos.line > endLine) return false\n if (pos.line === startLine && pos.character < node.column.start - 1) return false\n if (pos.line === endLine) {\n const end = node.column.end - 1\n if (inclusive ? pos.character > end : pos.character >= end) return false\n }\n return true\n}\n\n/** Every child node of `node`, in source order-ish (declaration order of the\n * fields). Generic on purpose: it walks the object graph rather than knowing\n * the node types, so a new node kind in the parser needs no change here. */\nexport function children(node: Spanned): Spanned[] {\n const out: Spanned[] = []\n for (const key of Object.keys(node)) {\n if (key === \"line\" || key === \"column\") continue\n const value = (node as unknown as Record<string, unknown>)[key]\n if (Array.isArray(value)) {\n for (const item of value) if (isSpanned(item)) out.push(item)\n } else if (isSpanned(value)) {\n out.push(value)\n }\n }\n return out\n}\n\n/** The chain of nodes containing `pos`, outermost first — the last entry is\n * the innermost node at the cursor and the ones before it are its ancestors.\n *\n * It descends through every child rather than only children that contain\n * `pos`, because a parent's span does not always cover its child's: a\n * binding's span is the name alone, while its type annotation sits after it.\n * So an ancestor in this path is a real ancestor, but not necessarily one\n * whose own span contains the cursor. */\nexport function pathAt(root: Spanned, pos: Position, inclusive = false): Spanned[] {\n let best: Spanned[] | undefined\n\n const descend = (node: Spanned, ancestors: Spanned[]): void => {\n const here = [...ancestors, node]\n if (containsPosition(node, pos, inclusive)) {\n // Prefer the narrowest hit, and among equals the deepest — that is\n // the node the cursor is really \"on\".\n const incumbent = best?.[best.length - 1]\n if (!incumbent\n || spanLength(node) < spanLength(incumbent)\n || (spanLength(node) === spanLength(incumbent) && here.length > best!.length)) {\n best = here\n }\n }\n for (const child of children(node)) descend(child, here)\n }\n\n descend(root, [])\n return best ?? []\n}\n\n/** The innermost node containing `pos`. */\nexport function nodeAt(root: Spanned, pos: Position, inclusive = false): Spanned | undefined {\n const path = pathAt(root, pos, inclusive)\n return path[path.length - 1]\n}\n\n/** The innermost node of one of `types` containing `pos`. */\nexport function enclosing<T extends Spanned>(\n root: Spanned,\n pos: Position,\n types: readonly string[],\n inclusive = false,\n): T | undefined {\n const path = pathAt(root, pos, inclusive)\n for (let i = path.length - 1; i >= 0; i--) {\n if (path[i].type && types.includes(path[i].type as string)) return path[i] as T\n }\n return undefined\n}\n\nfunction spanLength(node: Spanned): number {\n // Line count dominates: a node spanning fewer lines is nested deeper.\n return (node.line.end - node.line.start) * 10000 + (node.column.end - node.column.start)\n}\n\n/** Walk every node under `root`, depth first. */\nexport function walk(root: Spanned, visit: (node: Spanned, parent?: Spanned) => void, parent?: Spanned): void {\n visit(root, parent)\n for (const child of children(root)) walk(child, visit, root)\n}\n","/** Syntax errors, scope errors and type errors, as one list. */\nimport { DiagnosticSeverity, type Diagnostic } from \"vscode-languageserver\"\nimport type { Analysis } from \"../analysis.js\"\nimport { toRange, toPosition } from \"../ast-utils.js\"\n\nexport function diagnostics(analysis: Analysis): Diagnostic[] {\n const out: Diagnostic[] = []\n\n for (const error of analysis.parseErrors) {\n // A parse error points at a token, not a span; highlight to the end of\n // the word under it so the squiggle is visible.\n const start = toPosition(error.line, error.column)\n out.push({\n range: { start, end: { line: start.line, character: start.character + 1 } },\n severity: DiagnosticSeverity.Error,\n source: \"luaut\",\n code: \"syntax\",\n // The parser appends `(line:column)`; the range already says that.\n message: error.message.replace(/\\s*\\(\\d+:\\d+\\)$/, \"\"),\n })\n }\n\n for (const d of analysis.scopes.diagnostics) {\n out.push({\n range: toRange(d.node),\n severity: DiagnosticSeverity.Error,\n source: \"luaut\",\n code: d.kind,\n message: d.message,\n })\n }\n\n for (const d of analysis.types.diagnostics) {\n out.push({\n range: toRange(d.node),\n severity: DiagnosticSeverity.Error,\n source: \"luaut\",\n code: \"type\",\n message: d.message,\n })\n }\n\n return out\n}\n","/** Hover: the type of the thing under the cursor, as luaut would write it. */\nimport type { Hover, Position } from \"vscode-languageserver\"\nimport { formatType, type Identifier, type Expression, type Type } from \"luaut-parser\"\nimport { bindingOfNode, type Analysis } from \"../analysis.js\"\nimport { pathAt, toRange, type Spanned } from \"../ast-utils.js\"\n\nexport function hover(analysis: Analysis, position: Position): Hover | null {\n const path = pathAt(analysis.program, position, true)\n for (let i = path.length - 1; i >= 0; i--) {\n const node = path[i]\n const found = describe(analysis, node, path[i - 1])\n if (found) return { contents: { kind: \"markdown\", value: code(found) }, range: toRange(node) }\n }\n return null\n}\n\nfunction describe(analysis: Analysis, node: Spanned, parent?: Spanned): string | undefined {\n const { types } = analysis\n\n // A type alias reads as its definition rather than as a value.\n if (node.type === \"TypeAliasStatement\" || node.type === \"ExportTypeAliasStatement\") {\n const name = (node as unknown as { name: string }).name\n const alias = types.aliases.get(name)\n if (alias) return `type ${name} = ${formatType(alias)}`\n }\n\n if (node.type === \"Identifier\") {\n const identifier = node as unknown as Identifier\n // A reference: prefer the narrowed type — that is what the code sees\n // at this point, and the difference is the whole reason for narrowing.\n const narrowed = types.narrowedTypeOf.get(identifier)\n if (narrowed) return `${identifier.name}: ${formatType(narrowed)}`\n const binding = bindingOfNode(analysis, identifier)\n if (binding) {\n const type = types.bindingType.get(binding.id)\n if (type) return `${keyword(binding)} ${binding.name}: ${formatType(type)}`\n }\n // A property name: `x.foo` has no binding, but the member expression\n // it belongs to has a type.\n if (parent && (parent.type === \"MemberExpression\" || parent.type === \"MethodCallExpression\")) {\n const type = types.typeOf.get(parent as unknown as Expression)\n if (type) return `${identifier.name}: ${formatType(type)}`\n }\n }\n\n // Declarations: `const x`, a parameter, `const function f`.\n if (node.type === \"IdentifierPattern\" || node.type === \"FunctionParameter\"\n || node.type === \"TypedIdentifier\") {\n const binding = bindingOfNode(analysis, node)\n if (binding) {\n const type = types.bindingType.get(binding.id)\n if (type) return `${keyword(binding)} ${binding.name}: ${formatType(type)}`\n }\n }\n\n const type: Type | undefined = types.typeOf.get(node as unknown as Expression)\n return type ? formatType(type) : undefined\n}\n\nfunction keyword(binding: { kind: string; isConst?: boolean }): string {\n if (binding.kind === \"param\" || binding.kind === \"self\") return \"(parameter)\"\n if (binding.kind === \"global\") return \"(global)\"\n if (binding.kind.startsWith(\"for-\")) return \"(loop variable)\"\n return binding.isConst ? \"const\" : \"let\"\n}\n\nfunction code(text: string): string {\n return \"```luaut\\n\" + text + \"\\n```\"\n}\n","/**\n * Go-to-definition, find-references, rename and document highlight — all four\n * are the same question (\"which binding is this, and where else does it\n * appear?\") asked with different answers.\n */\nimport {\n DocumentHighlightKind,\n type DocumentHighlight, type Location, type Position, type Range,\n type TextEdit, type WorkspaceEdit,\n} from \"vscode-languageserver\"\nimport type { Binding } from \"luaut-parser\"\nimport { bindingOfNode, type Analysis } from \"../analysis.js\"\nimport { pathAt, toRange, type Spanned } from \"../ast-utils.js\"\n\n/** Nodes that can name a binding — as a use or as its declaration. */\nconst NAMING = new Set([\"Identifier\", \"IdentifierPattern\", \"FunctionParameter\", \"TypedIdentifier\"])\n\n/** The binding referred to at `position`, if the cursor is on a variable —\n * a use of it or its declaration. */\nexport function bindingAt(analysis: Analysis, position: Position): Binding | undefined {\n const path = pathAt(analysis.program, position, true)\n for (let i = path.length - 1; i >= 0; i--) {\n const node = path[i]\n if (!node.type || !NAMING.has(node.type)) continue\n const binding = bindingOfNode(analysis, node)\n if (binding) return binding\n }\n return undefined\n}\n\n/** Every place the binding appears: its declaration plus every reference. */\nfunction sites(binding: Binding): Spanned[] {\n const out: Spanned[] = []\n if (binding.declarationNode) out.push(binding.declarationNode as unknown as Spanned)\n out.push(...(binding.references as unknown as Spanned[]))\n return out\n}\n\nexport function definition(analysis: Analysis, position: Position): Location | null {\n const binding = bindingAt(analysis, position)\n if (!binding?.declarationNode) return null\n return { uri: analysis.uri, range: toRange(binding.declarationNode as unknown as Spanned) }\n}\n\nexport function references(\n analysis: Analysis,\n position: Position,\n includeDeclaration: boolean,\n): Location[] {\n const binding = bindingAt(analysis, position)\n if (!binding) return []\n const nodes = includeDeclaration ? sites(binding) : (binding.references as unknown as Spanned[])\n return nodes.map(node => ({ uri: analysis.uri, range: toRange(node) }))\n}\n\nexport function highlights(analysis: Analysis, position: Position): DocumentHighlight[] {\n const binding = bindingAt(analysis, position)\n if (!binding) return []\n return sites(binding).map(node => ({\n range: toRange(node),\n kind: node === binding.declarationNode\n ? DocumentHighlightKind.Write\n : DocumentHighlightKind.Read,\n }))\n}\n\n/** The range rename would replace, and the current name — so the editor can\n * refuse before it asks for a new one. */\nexport function prepareRename(\n analysis: Analysis,\n position: Position,\n): { range: Range; placeholder: string } | null {\n const binding = bindingAt(analysis, position)\n if (!binding) return null\n // A builtin lives in a definitions file; renaming it here would rename the\n // uses and leave the declaration behind.\n if (binding.isBuiltin || !binding.declarationNode) return null\n const path = pathAt(analysis.program, position, true)\n const identifier = [...path].reverse().find(n => !!n.type && NAMING.has(n.type))\n if (!identifier) return null\n return { range: toRange(identifier), placeholder: binding.name }\n}\n\nexport function rename(analysis: Analysis, position: Position, newName: string): WorkspaceEdit | null {\n if (!isIdentifier(newName)) return null\n const binding = bindingAt(analysis, position)\n if (!binding || binding.isBuiltin || !binding.declarationNode) return null\n const edits: TextEdit[] = sites(binding).map(node => ({ range: toRange(node), newText: newName }))\n return { changes: { [analysis.uri]: edits } }\n}\n\nconst IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/\nfunction isIdentifier(name: string): boolean {\n return IDENTIFIER.test(name)\n}\n","/** What members a type has — shared by completion and signature help. */\nimport { formatType, type FunctionType, type ObjectProperty, type Type } from \"luaut-parser\"\n\nexport interface Member {\n name: string\n property: ObjectProperty\n /** True when the member is a function whose first parameter is `self` —\n * i.e. it is meant to be called with `:`. */\n isMethod: boolean\n}\n\n/** The members of `type`, following aliases, merging intersections and keeping\n * only what every member of a union has (you can only reach a property that\n * is there whichever way the union went). */\nexport function membersOf(\n type: Type | undefined,\n aliases: ReadonlyMap<string, Type>,\n seen = new Set<Type>(),\n): Member[] {\n if (!type || seen.has(type)) return []\n seen.add(type)\n\n switch (type.kind) {\n case \"object\": {\n const out: Member[] = []\n for (const [name, property] of type.properties) {\n out.push({ name, property, isMethod: takesSelf(property.type) })\n }\n return out\n }\n case \"intersection\": {\n // Overload sets are intersections of functions and have no\n // members of their own; a `A & B` object contributes both sides.\n const merged = new Map<string, Member>()\n for (const part of type.types) {\n for (const member of membersOf(part, aliases, seen)) merged.set(member.name, member)\n }\n return [...merged.values()]\n }\n case \"union\": {\n const perBranch = type.types.map(part => membersOf(part, aliases, seen))\n if (!perBranch.length) return []\n const [first, ...rest] = perBranch\n return first.filter(member => rest.every(other => other.some(m => m.name === member.name)))\n }\n case \"genericRef\": {\n const alias = aliases.get(type.name)\n return alias ? membersOf(alias, aliases, seen) : []\n }\n case \"typeParam\":\n return membersOf(type.constraint, aliases, seen)\n default:\n return []\n }\n}\n\nexport function takesSelf(type: Type): boolean {\n for (const signature of signaturesOf(type)) {\n if (signature.params[0]?.name === \"self\") return true\n }\n return false\n}\n\n/** Every call signature of `type` — one for a function, several for an\n * overload set (which is an intersection of function types). */\nexport function signaturesOf(type: Type | undefined, aliases?: ReadonlyMap<string, Type>): FunctionType[] {\n if (!type) return []\n if (type.kind === \"function\") return [type]\n if (type.kind === \"intersection\") return type.types.flatMap(t => signaturesOf(t, aliases))\n if (type.kind === \"genericRef\" && aliases) {\n const alias = aliases.get(type.name)\n return alias ? signaturesOf(alias, aliases) : []\n }\n return []\n}\n\n/** `(a: number, b?: string) -> boolean`, and the pieces of it, for signature\n * help — which needs each parameter's own label to highlight the active one. */\nexport function signatureLabel(signature: FunctionType): { label: string; parameters: string[] } {\n const parameters = signature.params.map((p, i) => {\n const name = p.name ?? `arg${i + 1}`\n return `${name}${p.optional ? \"?\" : \"\"}: ${formatType(p.type)}`\n })\n const generics = signature.typeParams?.length ? `<${signature.typeParams.join(\", \")}>` : \"\"\n const varargs = signature.varargs ? [`...: ${formatType(signature.varargs)}`] : []\n const label = `${generics}(${[...parameters, ...varargs].join(\", \")}) -> ${formatType(signature.returns)}`\n return { label, parameters }\n}\n","/**\n * Completion.\n *\n * `x.` and `x:` are syntax errors, so the file as typed cannot answer \"what\n * are `x`'s members?\". The trick every language server of this shape uses:\n * substitute a placeholder identifier at the cursor, analyze *that* text, and\n * read the answer off the AST it produces. The user's document is untouched —\n * only the speculative copy is analyzed, and it is never cached.\n */\nimport {\n CompletionItemKind, InsertTextFormat,\n type CompletionItem, type Position,\n} from \"vscode-languageserver\"\nimport type { TextDocument } from \"vscode-languageserver-textdocument\"\nimport { formatType, type Expression, type Type } from \"luaut-parser\"\nimport type { Analyzer } from \"../analysis.js\"\nimport { pathAt, type Spanned } from \"../ast-utils.js\"\nimport { membersOf, signaturesOf, signatureLabel } from \"./members.js\"\n\nconst PLACEHOLDER = \"__luautCompletion__\"\nconst IDENTIFIER_CHAR = /[A-Za-z0-9_]/\n\nexport function completion(\n analyzer: Analyzer,\n document: TextDocument,\n position: Position,\n): CompletionItem[] {\n const source = document.getText()\n const offset = document.offsetAt(position)\n\n // The word being typed, if any — replaced wholesale so a half-written\n // name cannot break the speculative parse.\n let start = offset\n while (start > 0 && IDENTIFIER_CHAR.test(source[start - 1])) start--\n let end = offset\n while (end < source.length && IDENTIFIER_CHAR.test(source[end])) end++\n\n // A method name has to be called to parse (`part:foo` alone is not a\n // statement), so the placeholder brings its own argument list unless the\n // source already has one.\n const afterColon = source[start - 1] === \":\"\n const alreadyCalled = /^\\s*\\(/.test(source.slice(end))\n const stand_in = afterColon && !alreadyCalled ? `${PLACEHOLDER}()` : PLACEHOLDER\n const patched = source.slice(0, start) + stand_in + source.slice(end)\n const analysis = analyzer.analyze(document.uri, -1, patched)\n\n // Where the placeholder sits, in the patched document's coordinates —\n // the same line, since the patch never spans one.\n const at: Position = { line: position.line, character: position.character - (offset - start) }\n const path = pathAt(analysis.program, at, true)\n const placeholder = [...path].reverse().find(\n n => n.type === \"Identifier\" && (n as unknown as { name: string }).name === PLACEHOLDER,\n )\n const parent = placeholder ? path[path.indexOf(placeholder) - 1] : path[path.length - 1]\n\n // Member access: `x.foo` / `x:foo`.\n if (parent && (parent.type === \"MemberExpression\" || parent.type === \"MethodCallExpression\")) {\n const object = (parent as unknown as { object: Expression }).object\n const type = analysis.types.typeOf.get(object)\n const wantMethods = parent.type === \"MethodCallExpression\"\n return membersOf(type, analysis.types.aliases)\n .filter(member => (wantMethods ? member.isMethod : true))\n .map(member => memberItem(member.name, member.property.type, member.property.readonly))\n }\n\n // A type position wants type names, not values.\n if (inTypePosition(path)) {\n const named: CompletionItem[] = [...analysis.types.aliases.keys()].map(name => ({\n label: name,\n kind: CompletionItemKind.Interface,\n detail: \"type\",\n }))\n const primitives: CompletionItem[] = PRIMITIVES.map(name => ({\n label: name,\n kind: CompletionItemKind.Keyword,\n detail: \"type\",\n }))\n return [...named, ...primitives]\n }\n\n return valueItems(analysis, at)\n}\n\n/** Names in scope at `at`. Scope analysis records where each binding is\n * declared but not the extent of its scope, so this approximates: everything\n * declared earlier in the file, plus the globals, which are visible\n * everywhere. Over-offering is the right failure — a name the editor lists\n * and the file rejects is a diagnostic away from being obvious. */\nfunction valueItems(analysis: ReturnType<Analyzer[\"analyze\"]>, at: Position): CompletionItem[] {\n const items: CompletionItem[] = []\n const seen = new Set<string>()\n for (const binding of analysis.scopes.bindings.values()) {\n if (binding.name === PLACEHOLDER || seen.has(binding.name)) continue\n const declaration = binding.declarationNode as unknown as Spanned | undefined\n if (declaration && declaration.line.start - 1 > at.line) continue\n seen.add(binding.name)\n const type = analysis.types.bindingType.get(binding.id)\n items.push({\n label: binding.name,\n kind: kindOf(type, binding.kind),\n detail: type ? formatType(type) : undefined,\n // Locals before globals, and globals before library names.\n sortText: `${binding.isBuiltin ? 2 : binding.kind === \"global\" ? 1 : 0}${binding.name}`,\n })\n }\n for (const keyword of KEYWORDS) {\n items.push({ label: keyword, kind: CompletionItemKind.Keyword, sortText: `3${keyword}` })\n }\n return items\n}\n\nfunction memberItem(name: string, type: Type, readonly?: boolean): CompletionItem {\n const signatures = signaturesOf(type)\n if (signatures.length) {\n return {\n label: name,\n kind: CompletionItemKind.Method,\n detail: signatureLabel(signatures[0]).label,\n insertText: `${name}($0)`,\n insertTextFormat: InsertTextFormat.Snippet,\n }\n }\n return {\n label: name,\n kind: CompletionItemKind.Field,\n detail: `${readonly ? \"readonly \" : \"\"}${formatType(type)}`,\n }\n}\n\nfunction kindOf(type: Type | undefined, bindingKind: string): CompletionItemKind {\n if (type && signaturesOf(type).length) return CompletionItemKind.Function\n if (bindingKind === \"param\" || bindingKind === \"self\") return CompletionItemKind.Variable\n return CompletionItemKind.Variable\n}\n\n/** Is the cursor inside a type annotation? Every type node's name ends in\n * `TypeNode`, plus the couple that do not. */\nfunction inTypePosition(path: readonly Spanned[]): boolean {\n return path.some(n =>\n !!n.type && (n.type.endsWith(\"TypeNode\") || n.type === \"TypeReference\"\n || n.type === \"TypeAliasStatement\" || n.type === \"ExportTypeAliasStatement\"),\n )\n}\n\nconst PRIMITIVES = [\n \"any\", \"unknown\", \"never\", \"nil\", \"boolean\", \"number\", \"string\", \"thread\", \"buffer\",\n]\n\nconst KEYWORDS = [\n \"const\", \"let\", \"function\", \"return\", \"if\", \"then\", \"elseif\", \"else\", \"end\",\n \"for\", \"in\", \"while\", \"do\", \"repeat\", \"until\", \"break\", \"continue\",\n \"type\", \"declare\", \"export\", \"import\", \"and\", \"or\", \"not\", \"true\", \"false\", \"nil\",\n]\n","/**\n * Signature help: the parameter list of the call the cursor sits inside.\n *\n * A call being typed is usually not yet a call — `add(1, ` has no argument\n * after the comma and no closing paren, and the parser drops the statement.\n * So, like completion, this analyzes a repaired copy of the text: the fewest\n * characters that make the call parse, tried in order.\n */\nimport type { Position, SignatureHelp, SignatureInformation } from \"vscode-languageserver\"\nimport type { TextDocument } from \"vscode-languageserver-textdocument\"\nimport type { Expression } from \"luaut-parser\"\nimport type { Analyzer, Analysis } from \"../analysis.js\"\nimport { containsPosition, pathAt, type Spanned } from \"../ast-utils.js\"\nimport { signaturesOf, signatureLabel } from \"./members.js\"\n\ninterface CallLike extends Spanned {\n type: \"CallExpression\" | \"MethodCallExpression\"\n arguments: Expression[]\n}\n\nexport function signatureHelp(\n analyzer: Analyzer,\n document: TextDocument,\n position: Position,\n): SignatureHelp | null {\n const source = document.getText()\n const offset = document.offsetAt(position)\n for (const repair of [\"\", \"nil\", \"nil)\", \")\"]) {\n const text = source.slice(0, offset) + repair + source.slice(offset)\n const analysis = analyzer.analyze(document.uri, -1, text)\n const found = helpAt(analysis, position)\n if (found) return found\n }\n return null\n}\n\nfunction helpAt(analysis: Analysis, position: Position): SignatureHelp | null {\n const path = pathAt(analysis.program, position, true)\n const call = [...path].reverse().find(\n n => n.type === \"CallExpression\" || n.type === \"MethodCallExpression\",\n ) as CallLike | undefined\n if (!call) return null\n\n const callee = call.type === \"CallExpression\"\n ? (call as unknown as { callee: Expression }).callee\n : (call as unknown as Expression)\n // For a method call the callee has no node of its own, so read the type of\n // the whole `obj:m` receiver path from the object plus the method name.\n const calleeType = call.type === \"CallExpression\"\n ? analysis.types.typeOf.get(callee)\n : methodType(analysis, call)\n\n const signatures = signaturesOf(calleeType, analysis.types.aliases)\n if (!signatures.length) return null\n\n // `:` supplies `self`, so the first written argument is the second param.\n const selfOffset = call.type === \"MethodCallExpression\" ? 1 : 0\n const written = activeArgument(call, position)\n\n const infos: SignatureInformation[] = signatures.map(signature => {\n const { label, parameters } = signatureLabel(signature)\n return { label, parameters: parameters.map(p => ({ label: p })) }\n })\n\n // Pick the overload that could still accept this many arguments.\n const wanted = written + selfOffset + 1\n let active = signatures.findIndex(s => s.params.length >= wanted || s.varargs)\n if (active < 0) active = 0\n\n return {\n signatures: infos,\n activeSignature: active,\n activeParameter: Math.min(\n written + selfOffset,\n Math.max(0, signatures[active].params.length - 1),\n ),\n }\n}\n\nfunction methodType(analysis: Analysis, call: CallLike): undefined | ReturnType<Analysis[\"types\"][\"typeOf\"][\"get\"]> {\n const object = (call as unknown as { object: Expression }).object\n const method = (call as unknown as { method: { name: string } }).method\n const objectType = analysis.types.typeOf.get(object)\n if (!objectType) return undefined\n return memberType(objectType, method.name, analysis)\n}\n\nfunction memberType(\n type: NonNullable<ReturnType<Analysis[\"types\"][\"typeOf\"][\"get\"]>>,\n name: string,\n analysis: Analysis,\n): ReturnType<Analysis[\"types\"][\"typeOf\"][\"get\"]> {\n if (type.kind === \"object\") return type.properties.get(name)?.type\n if (type.kind === \"intersection\") {\n for (const part of type.types) {\n const found = memberType(part, name, analysis)\n if (found) return found\n }\n }\n if (type.kind === \"genericRef\") {\n const alias = analysis.types.aliases.get(type.name)\n if (alias) return memberType(alias, name, analysis)\n }\n return undefined\n}\n\n/** Which argument the cursor is in — counted by which argument spans it, or\n * by how many end before it when the cursor is in the gap after a comma. */\nfunction activeArgument(call: CallLike, position: Position): number {\n const args = call.arguments\n for (let i = 0; i < args.length; i++) {\n if (containsPosition(args[i] as unknown as Spanned, position, true)) return i\n }\n let count = 0\n for (const arg of args as unknown as Spanned[]) {\n const before = arg.line.end - 1 < position.line\n || (arg.line.end - 1 === position.line && arg.column.end - 1 <= position.character)\n if (before) count++\n }\n return count\n}\n","/** Document symbols: the outline of a file. */\nimport { SymbolKind, type DocumentSymbol } from \"vscode-languageserver\"\nimport { formatType, type Identifier } from \"luaut-parser\"\nimport { bindingOfNode, type Analysis } from \"../analysis.js\"\nimport { toRange, walk, type Spanned } from \"../ast-utils.js\"\n\nexport function documentSymbols(analysis: Analysis): DocumentSymbol[] {\n const out: DocumentSymbol[] = []\n\n walk(analysis.program, node => {\n switch (node.type) {\n case \"FunctionDeclaration\":\n case \"FunctionDeclarationStatement\": {\n const name = functionName(node)\n if (name) out.push(symbol(name, SymbolKind.Function, node, detailOf(analysis, node)))\n break\n }\n case \"TypeAliasStatement\":\n case \"ExportTypeAliasStatement\": {\n // The alias name is an Identifier node here, a bare string on\n // a `declare` — take either.\n const named = (node as unknown as { name?: string | { name?: string } }).name\n const name = typeof named === \"string\" ? named : named?.name\n if (name) {\n const alias = analysis.types.aliases.get(name)\n out.push(symbol(name, SymbolKind.Interface, node, alias ? formatType(alias) : undefined))\n }\n break\n }\n case \"VariableDeclaration\": {\n for (const target of (node as unknown as { names?: Spanned[] }).names ?? []) {\n const name = (target as unknown as { name?: string }).name\n if (name) out.push(symbol(name, SymbolKind.Variable, target))\n }\n break\n }\n }\n })\n\n return out\n}\n\nfunction functionName(node: Spanned): string | undefined {\n const named = node as unknown as {\n name?: string | { name?: string }\n target?: { base?: { name?: string }; path?: { name?: string }[]; method?: { name: string } }\n }\n if (typeof named.name === \"string\") return named.name\n if (named.name && typeof named.name === \"object\") return named.name.name\n if (named.target?.base?.name) {\n const path = (named.target.path ?? []).map(p => p.name).filter(Boolean)\n const dotted = [named.target.base.name, ...path].join(\".\")\n return named.target.method ? `${dotted}:${named.target.method.name}` : dotted\n }\n return undefined\n}\n\n/** A function declaration is a statement, not an expression, so its type\n * comes from the binding it creates rather than from `typeOf`. */\nfunction detailOf(analysis: Analysis, node: Spanned): string | undefined {\n const name = (node as unknown as { name?: Identifier }).name\n if (name && typeof name === \"object\") {\n const binding = bindingOfNode(analysis, name)\n const type = binding && analysis.types.bindingType.get(binding.id)\n if (type) return formatType(type)\n }\n return undefined\n}\n\nfunction symbol(name: string, kind: SymbolKind, node: Spanned, detail?: string): DocumentSymbol {\n const range = toRange(node)\n return { name, kind, detail, range, selectionRange: range }\n}\n","/**\n * The language server: LSP wiring only.\n *\n * Every handler is the same three steps — get the cached analysis for the\n * document, ask one feature module a question, hand back the answer. The\n * thinking lives in `features/`; nothing here knows about luaut.\n */\nimport {\n createConnection, ProposedFeatures, TextDocuments, TextDocumentSyncKind,\n type Connection, type InitializeParams, type InitializeResult,\n} from \"vscode-languageserver/node\"\nimport { TextDocument } from \"vscode-languageserver-textdocument\"\nimport { Analyzer, type AnalyzerOptions } from \"./analysis.js\"\nimport { diagnostics } from \"./features/diagnostics.js\"\nimport { hover } from \"./features/hover.js\"\nimport { definition, references, highlights, prepareRename, rename } from \"./features/navigation.js\"\nimport { completion } from \"./features/completion.js\"\nimport { signatureHelp } from \"./features/signatureHelp.js\"\nimport { documentSymbols } from \"./features/symbols.js\"\n\nexport interface ServerOptions extends AnalyzerOptions {}\n\n/** Attach the luaut language server to a connection. Exported separately from\n * `startServer` so an editor extension can run it in-process over its own\n * transport, and so the tests can drive it without spawning anything. */\nexport function createServer(connection: Connection, options: ServerOptions = {}): void {\n const analyzer = new Analyzer(options)\n const documents = new TextDocuments(TextDocument)\n\n connection.onInitialize((_params: InitializeParams): InitializeResult => ({\n capabilities: {\n textDocumentSync: TextDocumentSyncKind.Incremental,\n hoverProvider: true,\n definitionProvider: true,\n referencesProvider: true,\n documentHighlightProvider: true,\n documentSymbolProvider: true,\n renameProvider: { prepareProvider: true },\n completionProvider: {\n // `.` and `:` open a member list; the rest of the time\n // completion is asked for as you type a word.\n triggerCharacters: [\".\", \":\"],\n resolveProvider: false,\n },\n signatureHelpProvider: { triggerCharacters: [\"(\", \",\"], retriggerCharacters: [\",\"] },\n },\n serverInfo: { name: \"luaut-language-server\" },\n }))\n\n // --- diagnostics -------------------------------------------------------\n const publish = (document: TextDocument): void => {\n void connection.sendDiagnostics({\n uri: document.uri,\n version: document.version,\n diagnostics: diagnostics(analyzer.get(document)),\n })\n }\n\n documents.onDidOpen(e => publish(e.document))\n documents.onDidChangeContent(e => publish(e.document))\n documents.onDidClose(e => {\n analyzer.forget(e.document.uri)\n void connection.sendDiagnostics({ uri: e.document.uri, diagnostics: [] })\n })\n\n // --- language features -------------------------------------------------\n const withDocument = <T>(uri: string, f: (document: TextDocument) => T, fallback: T): T => {\n const document = documents.get(uri)\n return document ? f(document) : fallback\n }\n\n connection.onHover(p => withDocument(\n p.textDocument.uri, d => hover(analyzer.get(d), p.position), null,\n ))\n\n connection.onDefinition(p => withDocument(\n p.textDocument.uri, d => definition(analyzer.get(d), p.position), null,\n ))\n\n connection.onReferences(p => withDocument(\n p.textDocument.uri,\n d => references(analyzer.get(d), p.position, p.context.includeDeclaration),\n [],\n ))\n\n connection.onDocumentHighlight(p => withDocument(\n p.textDocument.uri, d => highlights(analyzer.get(d), p.position), [],\n ))\n\n connection.onDocumentSymbol(p => withDocument(\n p.textDocument.uri, d => documentSymbols(analyzer.get(d)), [],\n ))\n\n connection.onPrepareRename(p => withDocument(\n p.textDocument.uri,\n d => {\n const prepared = prepareRename(analyzer.get(d), p.position)\n return prepared ? { range: prepared.range, placeholder: prepared.placeholder } : null\n },\n null,\n ))\n\n connection.onRenameRequest(p => withDocument(\n p.textDocument.uri, d => rename(analyzer.get(d), p.position, p.newName), null,\n ))\n\n connection.onCompletion(p => withDocument(\n p.textDocument.uri, d => completion(analyzer, d, p.position), [],\n ))\n\n connection.onSignatureHelp(p => withDocument(\n p.textDocument.uri, d => signatureHelp(analyzer, d, p.position), null,\n ))\n\n documents.listen(connection)\n connection.listen()\n}\n\n/** Run the server over stdio — the transport editors launch it with. */\nexport function startServer(options: ServerOptions = {}): void {\n createServer(createConnection(ProposedFeatures.all), options)\n}\n"],"mappings":"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","names":["type","formatType","formatType","formatType","keyword","formatType","formatType"]}
package/dist/cli.cjs CHANGED
@@ -17,6 +17,23 @@ function collect(statements, into) {
17
17
  if (statement.type === "DeclareStatement") into.add(statement.name);
18
18
  }
19
19
  }
20
+ function bindingOfNode(analysis, node) {
21
+ const used = (0, import_luaut_parser.getBinding)(analysis.scopes, node);
22
+ if (used) return used;
23
+ return declarationIndex(analysis).get(node);
24
+ }
25
+ var declarationIndexes = /* @__PURE__ */ new WeakMap();
26
+ function declarationIndex(analysis) {
27
+ let index = declarationIndexes.get(analysis);
28
+ if (!index) {
29
+ index = /* @__PURE__ */ new Map();
30
+ for (const binding of analysis.scopes.bindings.values()) {
31
+ if (binding.declarationNode) index.set(binding.declarationNode, binding);
32
+ }
33
+ declarationIndexes.set(analysis, index);
34
+ }
35
+ return index;
36
+ }
20
37
  var Analyzer = class {
21
38
  libs;
22
39
  builtinGlobals;
@@ -160,7 +177,7 @@ function hover(analysis, position) {
160
177
  return null;
161
178
  }
162
179
  function describe(analysis, node, parent) {
163
- const { types, scopes } = analysis;
180
+ const { types } = analysis;
164
181
  if (node.type === "TypeAliasStatement" || node.type === "ExportTypeAliasStatement") {
165
182
  const name = node.name;
166
183
  const alias = types.aliases.get(name);
@@ -170,7 +187,7 @@ function describe(analysis, node, parent) {
170
187
  const identifier = node;
171
188
  const narrowed = types.narrowedTypeOf.get(identifier);
172
189
  if (narrowed) return `${identifier.name}: ${(0, import_luaut_parser2.formatType)(narrowed)}`;
173
- const binding = (0, import_luaut_parser2.getBinding)(scopes, identifier);
190
+ const binding = bindingOfNode(analysis, identifier);
174
191
  if (binding) {
175
192
  const type2 = types.bindingType.get(binding.id);
176
193
  if (type2) return `${keyword(binding)} ${binding.name}: ${(0, import_luaut_parser2.formatType)(type2)}`;
@@ -180,8 +197,8 @@ function describe(analysis, node, parent) {
180
197
  if (type2) return `${identifier.name}: ${(0, import_luaut_parser2.formatType)(type2)}`;
181
198
  }
182
199
  }
183
- if (node.type === "IdentifierPattern") {
184
- const binding = (0, import_luaut_parser2.getBinding)(scopes, node);
200
+ if (node.type === "IdentifierPattern" || node.type === "FunctionParameter" || node.type === "TypedIdentifier") {
201
+ const binding = bindingOfNode(analysis, node);
185
202
  if (binding) {
186
203
  const type2 = types.bindingType.get(binding.id);
187
204
  if (type2) return `${keyword(binding)} ${binding.name}: ${(0, import_luaut_parser2.formatType)(type2)}`;
@@ -202,13 +219,13 @@ function code(text) {
202
219
 
203
220
  // src/features/navigation.ts
204
221
  var import_vscode_languageserver2 = require("vscode-languageserver");
205
- var import_luaut_parser3 = require("luaut-parser");
222
+ var NAMING = /* @__PURE__ */ new Set(["Identifier", "IdentifierPattern", "FunctionParameter", "TypedIdentifier"]);
206
223
  function bindingAt(analysis, position) {
207
224
  const path = pathAt(analysis.program, position, true);
208
225
  for (let i = path.length - 1; i >= 0; i--) {
209
226
  const node = path[i];
210
- if (node.type !== "Identifier" && node.type !== "IdentifierPattern") continue;
211
- const binding = (0, import_luaut_parser3.getBinding)(analysis.scopes, node);
227
+ if (!node.type || !NAMING.has(node.type)) continue;
228
+ const binding = bindingOfNode(analysis, node);
212
229
  if (binding) return binding;
213
230
  }
214
231
  return void 0;
@@ -243,7 +260,7 @@ function prepareRename(analysis, position) {
243
260
  if (!binding) return null;
244
261
  if (binding.isBuiltin || !binding.declarationNode) return null;
245
262
  const path = pathAt(analysis.program, position, true);
246
- const identifier = [...path].reverse().find((n) => n.type === "Identifier" || n.type === "IdentifierPattern");
263
+ const identifier = [...path].reverse().find((n) => !!n.type && NAMING.has(n.type));
247
264
  if (!identifier) return null;
248
265
  return { range: toRange(identifier), placeholder: binding.name };
249
266
  }
@@ -261,10 +278,10 @@ function isIdentifier(name) {
261
278
 
262
279
  // src/features/completion.ts
263
280
  var import_vscode_languageserver3 = require("vscode-languageserver");
264
- var import_luaut_parser5 = require("luaut-parser");
281
+ var import_luaut_parser4 = require("luaut-parser");
265
282
 
266
283
  // src/features/members.ts
267
- var import_luaut_parser4 = require("luaut-parser");
284
+ var import_luaut_parser3 = require("luaut-parser");
268
285
  function membersOf(type, aliases, seen = /* @__PURE__ */ new Set()) {
269
286
  if (!type || seen.has(type)) return [];
270
287
  seen.add(type);
@@ -318,11 +335,11 @@ function signaturesOf(type, aliases) {
318
335
  function signatureLabel(signature) {
319
336
  const parameters = signature.params.map((p, i) => {
320
337
  const name = p.name ?? `arg${i + 1}`;
321
- return `${name}${p.optional ? "?" : ""}: ${(0, import_luaut_parser4.formatType)(p.type)}`;
338
+ return `${name}${p.optional ? "?" : ""}: ${(0, import_luaut_parser3.formatType)(p.type)}`;
322
339
  });
323
340
  const generics = signature.typeParams?.length ? `<${signature.typeParams.join(", ")}>` : "";
324
- const varargs = signature.varargs ? [`...: ${(0, import_luaut_parser4.formatType)(signature.varargs)}`] : [];
325
- const label = `${generics}(${[...parameters, ...varargs].join(", ")}) -> ${(0, import_luaut_parser4.formatType)(signature.returns)}`;
341
+ const varargs = signature.varargs ? [`...: ${(0, import_luaut_parser3.formatType)(signature.varargs)}`] : [];
342
+ const label = `${generics}(${[...parameters, ...varargs].join(", ")}) -> ${(0, import_luaut_parser3.formatType)(signature.returns)}`;
326
343
  return { label, parameters };
327
344
  }
328
345
 
@@ -380,7 +397,7 @@ function valueItems(analysis, at) {
380
397
  items.push({
381
398
  label: binding.name,
382
399
  kind: kindOf(type, binding.kind),
383
- detail: type ? (0, import_luaut_parser5.formatType)(type) : void 0,
400
+ detail: type ? (0, import_luaut_parser4.formatType)(type) : void 0,
384
401
  // Locals before globals, and globals before library names.
385
402
  sortText: `${binding.isBuiltin ? 2 : binding.kind === "global" ? 1 : 0}${binding.name}`
386
403
  });
@@ -404,7 +421,7 @@ function memberItem(name, type, readonly) {
404
421
  return {
405
422
  label: name,
406
423
  kind: import_vscode_languageserver3.CompletionItemKind.Field,
407
- detail: `${readonly ? "readonly " : ""}${(0, import_luaut_parser5.formatType)(type)}`
424
+ detail: `${readonly ? "readonly " : ""}${(0, import_luaut_parser4.formatType)(type)}`
408
425
  };
409
426
  }
410
427
  function kindOf(type, bindingKind) {
@@ -534,7 +551,7 @@ function activeArgument(call, position) {
534
551
 
535
552
  // src/features/symbols.ts
536
553
  var import_vscode_languageserver4 = require("vscode-languageserver");
537
- var import_luaut_parser6 = require("luaut-parser");
554
+ var import_luaut_parser5 = require("luaut-parser");
538
555
  function documentSymbols(analysis) {
539
556
  const out = [];
540
557
  walk(analysis.program, (node) => {
@@ -551,7 +568,7 @@ function documentSymbols(analysis) {
551
568
  const name = typeof named === "string" ? named : named?.name;
552
569
  if (name) {
553
570
  const alias = analysis.types.aliases.get(name);
554
- out.push(symbol(name, import_vscode_languageserver4.SymbolKind.Interface, node, alias ? (0, import_luaut_parser6.formatType)(alias) : void 0));
571
+ out.push(symbol(name, import_vscode_languageserver4.SymbolKind.Interface, node, alias ? (0, import_luaut_parser5.formatType)(alias) : void 0));
555
572
  }
556
573
  break;
557
574
  }
@@ -580,9 +597,9 @@ function functionName(node) {
580
597
  function detailOf(analysis, node) {
581
598
  const name = node.name;
582
599
  if (name && typeof name === "object") {
583
- const binding = (0, import_luaut_parser6.getBinding)(analysis.scopes, name);
600
+ const binding = bindingOfNode(analysis, name);
584
601
  const type = binding && analysis.types.bindingType.get(binding.id);
585
- if (type) return (0, import_luaut_parser6.formatType)(type);
602
+ if (type) return (0, import_luaut_parser5.formatType)(type);
586
603
  }
587
604
  return void 0;
588
605
  }