luaut-language-server 1.0.0 → 1.1.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/README.md +123 -100
- package/dist/chunk-HK7PKBDB.js +1535 -0
- package/dist/chunk-HK7PKBDB.js.map +1 -0
- package/dist/cli.cjs +945 -161
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +961 -161
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +136 -63
- package/dist/index.d.ts +136 -63
- package/dist/index.js +17 -1
- package/package.json +53 -49
- package/dist/chunk-RHII344O.js +0 -733
- package/dist/chunk-RHII344O.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,100 +1,123 @@
|
|
|
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
|
-
| `
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
| `
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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`. Also every name in a type or definitions file: `declare` names (with their overload count), alias names, object-type properties, type parameters, `infer` names, and any type annotation, which reads as what it resolves to |
|
|
21
|
+
| `semanticTokens` | colours from the parser, not from patterns — see [Highlighting](#highlighting) |
|
|
22
|
+
| `definition` | the binding's declaration — and from an `import`, the export in the other module |
|
|
23
|
+
| `references`, `documentHighlight` | every use of the binding |
|
|
24
|
+
| `rename`, `prepareRename` | refuses names that are not identifiers, and builtins from the definitions files |
|
|
25
|
+
| `completion` | members after `.` / `:` (never the globals there), names in scope, type names in a type position; inside an `import`, module paths and the exported names |
|
|
26
|
+
| `signatureHelp` | every overload, with the active parameter — `:` calls count `self` for you |
|
|
27
|
+
| `documentSymbol` | functions, type aliases, top-level bindings |
|
|
28
|
+
|
|
29
|
+
### Modules
|
|
30
|
+
|
|
31
|
+
An `import` resolves to a file relative to the importer (`./x`, `../x`; the
|
|
32
|
+
extension may be left off, and a folder means its `index.luaut`). That module
|
|
33
|
+
is analyzed too, and its exports become the importer's types — so imported
|
|
34
|
+
values are type-checked, imported types work in annotations, and a missing
|
|
35
|
+
module or export is a diagnostic. Open documents are read before disk, so an
|
|
36
|
+
import sees unsaved edits, and a cached result is dropped as soon as anything
|
|
37
|
+
it imports changes.
|
|
38
|
+
|
|
39
|
+
## How it is put together
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
src/
|
|
43
|
+
server.ts LSP wiring, and nothing else
|
|
44
|
+
analysis.ts parse -> scopes -> types, cached per document version
|
|
45
|
+
ast-utils.ts 1-based spans <-> 0-based LSP positions, position -> node
|
|
46
|
+
features/ one file per feature; plain functions, no LSP plumbing
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
A feature is `(analysis, position) -> answer`. Nothing in `features/` opens a
|
|
50
|
+
connection or knows about documents, which is why `scripts/test.ts` can drive
|
|
51
|
+
all of them in-process without spawning a server, and why an editor extension
|
|
52
|
+
can call them directly:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { Analyzer, hover, diagnostics } from "luaut-language-server"
|
|
56
|
+
|
|
57
|
+
const analyzer = new Analyzer() // or { libs: [...] } for your own definitions
|
|
58
|
+
const analysis = analyzer.get(document) // a vscode-languageserver TextDocument
|
|
59
|
+
hover(analysis, { line: 3, character: 12 })
|
|
60
|
+
diagnostics(analysis)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Speculative parsing
|
|
64
|
+
|
|
65
|
+
`x.` and `add(1, ` are syntax errors — the text you are in the middle of
|
|
66
|
+
typing usually is. Completion and signature help therefore analyze a
|
|
67
|
+
*repaired copy* of the document: a placeholder identifier at the cursor for
|
|
68
|
+
completion, and the shortest of `nil`, `nil)`, `)` that parses for signature
|
|
69
|
+
help. The user's document is never touched and the repaired copy is never
|
|
70
|
+
cached.
|
|
71
|
+
|
|
72
|
+
### Globals
|
|
73
|
+
|
|
74
|
+
The names a file may use undeclared are not hard-coded: they are read out of
|
|
75
|
+
the `declare` statements in the definitions passed to `Analyzer`. Adding a
|
|
76
|
+
global to a `.d.luaut` is all it takes for the editor to stop calling it
|
|
77
|
+
undefined.
|
|
78
|
+
|
|
79
|
+
### Highlighting
|
|
80
|
+
|
|
81
|
+
A word's role in luaut depends on where it stands: `extends` is a keyword in a
|
|
82
|
+
type and a name elsewhere, `type Foo = ...` declares an alias while `type(x)`
|
|
83
|
+
calls a builtin, `typeof x` in a type is a query while `typeof(v)` in code is a
|
|
84
|
+
call. A TextMate grammar only sees characters, so it can only guess — and
|
|
85
|
+
guessed `extends (` into a function call.
|
|
86
|
+
|
|
87
|
+
So `semanticTokens` classifies every token from the same lexer and AST the
|
|
88
|
+
analyzer uses: declarations, parameters, properties, methods, types, type
|
|
89
|
+
parameters, and soft keywords only where the AST did not claim the word as a
|
|
90
|
+
name. The grammar in the editor extension keeps just what characters decide
|
|
91
|
+
alone — comments, strings, numbers, reserved words — so a file looks right
|
|
92
|
+
before the server answers, and never disagrees with it after.
|
|
93
|
+
|
|
94
|
+
## Not yet
|
|
95
|
+
|
|
96
|
+
- **One file at a time.** No workspace indexing, so no cross-file
|
|
97
|
+
go-to-definition, `workspace/symbol`, or diagnostics for files you have not
|
|
98
|
+
opened.
|
|
99
|
+
- **No formatting** — there is no luaut printer yet (the compiler owns
|
|
100
|
+
emitting Luau, and it emits *Luau*, not luaut).
|
|
101
|
+
- No code actions, inlay hints, or folding ranges.
|
|
102
|
+
- Everything `luaut-parser` does not check is invisible here too: unknown
|
|
103
|
+
properties, writes to `readonly`, generic constraints at call sites,
|
|
104
|
+
metatables.
|
|
105
|
+
|
|
106
|
+
## Editors
|
|
107
|
+
|
|
108
|
+
VS Code: [`luaut-vscode`](../luaut-vscode) — a separate project next door. It
|
|
109
|
+
bundles this server into the extension, so its `.vsix` is self-contained.
|
|
110
|
+
|
|
111
|
+
Anything else that speaks LSP: launch `luaut-language-server --stdio` (or
|
|
112
|
+
`--node-ipc`) and attach it to the `luaut` language / `.luaut` files.
|
|
113
|
+
|
|
114
|
+
## Development
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npm run typecheck
|
|
118
|
+
npm test # features in-process, then the built binary over stdio
|
|
119
|
+
npm run build
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`scripts/test.ts` marks the cursor with `‸` in each fixture (not `|` — that is
|
|
123
|
+
the union operator). `scripts/e2e.ts` speaks real LSP to `dist/cli.js`.
|