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 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.