luaut-parser 1.0.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 +129 -0
- package/dist/index.cjs +5582 -0
- package/dist/index.d.cts +1102 -0
- package/dist/index.d.ts +1102 -0
- package/dist/index.js +5489 -0
- package/dist/luau.d.luaut +244 -0
- package/dist/roblox.d.luaut +503 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# luaut-parser
|
|
2
|
+
|
|
3
|
+
Front end for **luaut** — a TypeScript-flavoured language that compiles to Luau.
|
|
4
|
+
Source → tokens → AST → scope analysis → flow-sensitive type analysis.
|
|
5
|
+
|
|
6
|
+
This package is the front end only. Lowering the luaut AST to Luau is the
|
|
7
|
+
compiler's job and lives elsewhere; there is deliberately no printer here.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install luaut-parser
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import {
|
|
15
|
+
parse, analyzeScopes, analyzeTypes, formatType, defaultLibs,
|
|
16
|
+
} from "luaut-parser"
|
|
17
|
+
|
|
18
|
+
const program = parse(source)
|
|
19
|
+
const scopes = analyzeScopes(program, {})
|
|
20
|
+
const types = analyzeTypes(program, scopes, { libs: defaultLibs })
|
|
21
|
+
|
|
22
|
+
for (const d of [...scopes.diagnostics, ...types.diagnostics]) console.log(d.message)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## The three passes
|
|
26
|
+
|
|
27
|
+
| | produces | use it for |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `parse(source)` | `Program` — every node carries `line`/`column` spans | everything |
|
|
30
|
+
| `analyzeScopes(program, opts)` | `bindingOf`, `bindings`, `references`, `diagnostics` | go-to-definition, find-references, rename |
|
|
31
|
+
| `analyzeTypes(program, scopes, opts)` | `typeOf`, `narrowedTypeOf`, `bindingType`, `aliases`, `diagnostics` | hover, assignability errors |
|
|
32
|
+
|
|
33
|
+
`parseWithRecovery(source)` returns `{ program, errors }` instead of throwing —
|
|
34
|
+
use it for editors, where the text is usually mid-edit.
|
|
35
|
+
|
|
36
|
+
Neither analysis mutates the AST; both return side tables.
|
|
37
|
+
|
|
38
|
+
## Definitions
|
|
39
|
+
|
|
40
|
+
`type` / `typeof` are **not** special-cased in the analyzer. They are ordinary
|
|
41
|
+
overload sets declared in `luau.d.luaut`, and narrowing is derived from them.
|
|
42
|
+
Pass the definitions or those built-ins narrow nothing:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
analyzeTypes(program, scopes, { libs: defaultLibs }) // core Luau + Roblox
|
|
46
|
+
analyzeTypes(program, scopes, { libs: [luauLib] }) // core Luau only
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The same trick drives the Roblox layer: `IsA`, `GetService` and `Instance.new`
|
|
50
|
+
are each one generic signature indexing a map of names to types, so adding a
|
|
51
|
+
class is adding a line to `roblox.d.luaut`. Ship your own definitions by
|
|
52
|
+
parsing them the same way:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
analyzeTypes(program, scopes, { libs: [luauLib, parse(myDefs)] })
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`luauDefs` / `robloxDefs` expose the raw text (the loaders read from disk, so a
|
|
59
|
+
browser consumer should parse the text itself).
|
|
60
|
+
|
|
61
|
+
## The language, in brief
|
|
62
|
+
|
|
63
|
+
TypeScript syntax and semantics wherever they fit, Lua semantics where they
|
|
64
|
+
must.
|
|
65
|
+
|
|
66
|
+
**Declarations** — `const` and `let` only; Lua's `local` is gone.
|
|
67
|
+
|
|
68
|
+
**Optionality** — there is no `T?` shorthand. `?` in type position always
|
|
69
|
+
belongs to a conditional type, and in expression position to a ternary.
|
|
70
|
+
|
|
71
|
+
```luau
|
|
72
|
+
name?: T -- may be absent; its type is `T | nil`
|
|
73
|
+
name: T | nil -- must be written, but may be nil
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Omitting an argument requires `?` (or a default), as in TypeScript — a
|
|
77
|
+
parameter typed `T | nil` still has to be passed something.
|
|
78
|
+
|
|
79
|
+
**Narrowing** follows TypeScript's model: references (`x`, `x.a.b`, `x["k"]`)
|
|
80
|
+
rather than just variables, discriminated unions at any depth, `and`/`or`,
|
|
81
|
+
early return, `break`/`continue`, `error()` (declared `-> never`), user type
|
|
82
|
+
guards (`v is T`), and assertion signatures (`asserts v`).
|
|
83
|
+
|
|
84
|
+
Only `nil` and `false` are falsy — `0` and `""` are truthy, unlike JavaScript.
|
|
85
|
+
|
|
86
|
+
**Types** — unions, intersections, tuples `[A, B]`, type packs `(A, B)` (the
|
|
87
|
+
several values a function returns), `keyof`, `T[K]`, conditional types with
|
|
88
|
+
`infer`, mapped types with `as` remapping, template literal types
|
|
89
|
+
(`` `on${Event}` ``), and set difference `A - B`. The utility types
|
|
90
|
+
(`Partial`, `Pick`, `Omit`, `ReturnType`, `Parameters`, `Exclude`, …) are
|
|
91
|
+
written in luaut on top of those, not built in.
|
|
92
|
+
|
|
93
|
+
`<const T>` infers an argument at its narrowest, as in TypeScript 5.
|
|
94
|
+
|
|
95
|
+
## Options
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
analyzeScopes(program, {
|
|
99
|
+
builtinGlobals: ["print", "game"], // names that may be used undeclared
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
analyzeTypes(program, scopes, {
|
|
103
|
+
libs: defaultLibs, // parsed `.d.luaut` definitions
|
|
104
|
+
globalTypes: { … }, // types for specific globals; wins over `libs`
|
|
105
|
+
libTypes: { … }, // extra named types for annotations
|
|
106
|
+
diagnostics: true, // emit assignability errors (default)
|
|
107
|
+
})
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Known limitations
|
|
111
|
+
|
|
112
|
+
- Cross-module `import` resolves to `any`.
|
|
113
|
+
- `setmetatable` and metatables are not modelled.
|
|
114
|
+
- Accessing a property a type does not have yields `unknown` rather than an
|
|
115
|
+
error; assigning to a `readonly` property is not reported; generic
|
|
116
|
+
constraints are not checked at call sites.
|
|
117
|
+
|
|
118
|
+
## Development
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npm install
|
|
122
|
+
npm test # parses smoketest/*.luaut, writes AST + inferred types to generated/
|
|
123
|
+
npm run build
|
|
124
|
+
npm run typecheck
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`smoketest/` is the test suite. Each file annotates its bindings with the type
|
|
128
|
+
they should infer to, so a wrong result surfaces as a diagnostic rather than
|
|
129
|
+
something to eyeball.
|