@words-lang/parser 0.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.
Files changed (41) hide show
  1. package/dist/analyser/analyser.d.ts +106 -0
  2. package/dist/analyser/analyser.d.ts.map +1 -0
  3. package/dist/analyser/analyser.js +291 -0
  4. package/dist/analyser/analyser.js.map +1 -0
  5. package/dist/analyser/diagnostics.d.ts +166 -0
  6. package/dist/analyser/diagnostics.d.ts.map +1 -0
  7. package/dist/analyser/diagnostics.js +139 -0
  8. package/dist/analyser/diagnostics.js.map +1 -0
  9. package/dist/analyser/workspace.d.ts +198 -0
  10. package/dist/analyser/workspace.d.ts.map +1 -0
  11. package/dist/analyser/workspace.js +403 -0
  12. package/dist/analyser/workspace.js.map +1 -0
  13. package/dist/index.d.ts +8 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +31 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/lexer/lexer.d.ts +120 -0
  18. package/dist/lexer/lexer.d.ts.map +1 -0
  19. package/dist/lexer/lexer.js +365 -0
  20. package/dist/lexer/lexer.js.map +1 -0
  21. package/dist/lexer/token.d.ts +247 -0
  22. package/dist/lexer/token.d.ts.map +1 -0
  23. package/dist/lexer/token.js +250 -0
  24. package/dist/lexer/token.js.map +1 -0
  25. package/dist/parser/ast.d.ts +685 -0
  26. package/dist/parser/ast.d.ts.map +1 -0
  27. package/dist/parser/ast.js +3 -0
  28. package/dist/parser/ast.js.map +1 -0
  29. package/dist/parser/parser.d.ts +411 -0
  30. package/dist/parser/parser.d.ts.map +1 -0
  31. package/dist/parser/parser.js +1600 -0
  32. package/dist/parser/parser.js.map +1 -0
  33. package/package.json +23 -0
  34. package/src/analyser/analyser.ts +403 -0
  35. package/src/analyser/diagnostics.ts +232 -0
  36. package/src/analyser/workspace.ts +457 -0
  37. package/src/index.ts +7 -0
  38. package/src/lexer/lexer.ts +379 -0
  39. package/src/lexer/token.ts +331 -0
  40. package/src/parser/ast.ts +798 -0
  41. package/src/parser/parser.ts +1815 -0
@@ -0,0 +1,798 @@
1
+ import { Token } from '../lexer/token'
2
+
3
+ // ── Base ──────────────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * Every AST node extends BaseNode.
7
+ * The `kind` discriminant lets TypeScript narrow union types safely.
8
+ * The `token` is the first token that produced this node — used by the
9
+ * analyser to report diagnostics at the correct source location, and by
10
+ * the LSP to implement go-to-definition and find-references.
11
+ */
12
+ export interface BaseNode {
13
+ kind: string
14
+ token: Token
15
+ }
16
+
17
+ // ── Types ─────────────────────────────────────────────────────────────────────
18
+
19
+ /**
20
+ * The built-in scalar types available in WORDS.
21
+ * `context` is a special type used only in the system interface declaration
22
+ * (getContext / setContext) to represent an opaque stored context value.
23
+ */
24
+ export type PrimitiveType = 'string' | 'integer' | 'float' | 'boolean' | 'context'
25
+
26
+ /**
27
+ * A scalar built-in type — string, integer, float, boolean, or context.
28
+ * e.g. `name(string)`, `total(float)`
29
+ */
30
+ export interface PrimitiveTypeNode extends BaseNode {
31
+ kind: 'PrimitiveType'
32
+ name: PrimitiveType
33
+ }
34
+
35
+ /**
36
+ * A parameterised list type.
37
+ * e.g. `list(OrderItem)`, `list(string)`
38
+ */
39
+ export interface ListTypeNode extends BaseNode {
40
+ kind: 'ListType'
41
+ elementType: TypeNode
42
+ }
43
+
44
+ /**
45
+ * A parameterised map type with explicit key and value types.
46
+ * e.g. `map(string, OrderSummary)`
47
+ */
48
+ export interface MapTypeNode extends BaseNode {
49
+ kind: 'MapType'
50
+ keyType: TypeNode
51
+ valueType: TypeNode
52
+ }
53
+
54
+ /**
55
+ * A reference to a named interface component used as a type.
56
+ * e.g. `Product`, `?AuthError`, `OrderItem`
57
+ * The `optional` flag is set when the type is prefixed with `?`.
58
+ */
59
+ export interface NamedTypeNode extends BaseNode {
60
+ kind: 'NamedType'
61
+ name: string
62
+ optional: boolean
63
+ }
64
+
65
+ /**
66
+ * Union of all type annotation forms that can appear after a name
67
+ * in a prop, method parameter, or returns clause.
68
+ */
69
+ export type TypeNode =
70
+ | PrimitiveTypeNode
71
+ | ListTypeNode
72
+ | MapTypeNode
73
+ | NamedTypeNode
74
+
75
+ // ── Qualified name ────────────────────────────────────────────────────────────
76
+
77
+ /**
78
+ * A dot-separated name that references a construct across module boundaries,
79
+ * or a runtime system call. Parts are stored as an array so the analyser can
80
+ * resolve each segment independently.
81
+ *
82
+ * Examples:
83
+ * UIModule.LoginForm → ['UIModule', 'LoginForm']
84
+ * system.setContext → ['system', 'setContext']
85
+ * system.RoutingModule.dispatch → ['system', 'RoutingModule', 'dispatch']
86
+ * SessionAdapter.checkSession → ['SessionAdapter', 'checkSession']
87
+ */
88
+ export interface QualifiedName extends BaseNode {
89
+ kind: 'QualifiedName'
90
+ parts: string[]
91
+ }
92
+
93
+ // ── Prop / field declaration ──────────────────────────────────────────────────
94
+
95
+ /**
96
+ * A single named, typed entry in a `props` or `state` block.
97
+ *
98
+ * Props declared with a type are data props:
99
+ * `error(AuthError)`
100
+ * → name='error', type=NamedTypeNode('AuthError'), argName=null
101
+ *
102
+ * Props declared with an argument name and type are interaction props.
103
+ * The argument name is the variable the parent passes into the handler body:
104
+ * `onSubmit credentials(AccountCredentials)`
105
+ * → name='onSubmit', type=NamedTypeNode('AccountCredentials'), argName='credentials'
106
+ *
107
+ * Props declared with no type are interaction props with no payload.
108
+ * The handler body receives no variable:
109
+ * `onConfirm`
110
+ * → name='onConfirm', type=null, argName=null
111
+ *
112
+ * Interaction prop names are chosen by the designer — there are no reserved
113
+ * names. `onSubmit`, `onConfirm`, `onDismiss`, `onLoad` are all plain prop
114
+ * names with no special meaning to the language.
115
+ *
116
+ * In a `state` block:
117
+ * `inputEmail(string) is ""`
118
+ * → name='inputEmail', type=PrimitiveTypeNode('string'), defaultValue=StringLiteralNode('')
119
+ *
120
+ * `optional` is true when the type is prefixed with `?` — e.g. `?Product`.
121
+ * `argName` is the argument variable name declared on an interaction prop,
122
+ * inferred by the parser and used downstream at call sites.
123
+ */
124
+ export interface PropNode extends BaseNode {
125
+ kind: 'Prop'
126
+ name: string
127
+ type: TypeNode | null
128
+ optional: boolean
129
+ defaultValue: LiteralNode | null
130
+ argName: string | null
131
+ }
132
+
133
+ // ── Literals ──────────────────────────────────────────────────────────────────
134
+
135
+ /** A double-quoted string value. e.g. `"The user authenticated successfully"` */
136
+ export interface StringLiteralNode extends BaseNode {
137
+ kind: 'StringLiteral'
138
+ value: string
139
+ }
140
+
141
+ /** A whole number value. e.g. `42`, `5000` */
142
+ export interface IntegerLiteralNode extends BaseNode {
143
+ kind: 'IntegerLiteral'
144
+ value: number
145
+ }
146
+
147
+ /** A decimal number value. e.g. `0.0`, `3.14` */
148
+ export interface FloatLiteralNode extends BaseNode {
149
+ kind: 'FloatLiteral'
150
+ value: number
151
+ }
152
+
153
+ /** A boolean value — `true` or `false`. */
154
+ export interface BooleanLiteralNode extends BaseNode {
155
+ kind: 'BooleanLiteral'
156
+ value: boolean
157
+ }
158
+
159
+ /**
160
+ * An empty list literal `[]`.
161
+ * Non-empty list literals do not appear in WORDS source — `[]` is the only
162
+ * form used as a default value in props and state declarations.
163
+ */
164
+ export interface ListLiteralNode extends BaseNode {
165
+ kind: 'ListLiteral'
166
+ elements: LiteralNode[]
167
+ }
168
+
169
+ /**
170
+ * An empty map literal `{}`.
171
+ * Non-empty map literals do not appear in WORDS source — `{}` is the only
172
+ * form used as a default value in props and state declarations.
173
+ */
174
+ export interface MapLiteralNode extends BaseNode {
175
+ kind: 'MapLiteral'
176
+ entries: Array<{ key: LiteralNode; value: LiteralNode }>
177
+ }
178
+
179
+ /**
180
+ * Union of all literal value forms.
181
+ * Literals appear as default values in props/state declarations and as
182
+ * argument values in component use and system calls.
183
+ */
184
+ export type LiteralNode =
185
+ | StringLiteralNode
186
+ | IntegerLiteralNode
187
+ | FloatLiteralNode
188
+ | BooleanLiteralNode
189
+ | ListLiteralNode
190
+ | MapLiteralNode
191
+
192
+ // ── Interface method declaration ──────────────────────────────────────────────
193
+
194
+ /**
195
+ * A method exposed by a provider, adapter, or interface component.
196
+ * Methods appear directly in the body after `props`, without a keyword prefix.
197
+ * Method names are chosen by the designer — there are no reserved names.
198
+ *
199
+ * Examples:
200
+ * `getProducts returns(list(Product)) "Returns all products"`
201
+ * `login credentials(AccountCredentials) returns(SystemUser) "Authenticates the user"`
202
+ * `clear "Empties the cart"` — no params, no return type
203
+ *
204
+ * `returnType` is null when the method produces no output.
205
+ * `description` is the optional quoted string following the method signature.
206
+ */
207
+ export interface MethodNode extends BaseNode {
208
+ kind: 'Method'
209
+ name: string
210
+ params: PropNode[]
211
+ returnType: TypeNode | null
212
+ description: string | null
213
+ }
214
+
215
+ // ── Returns clause ────────────────────────────────────────────────────────────
216
+
217
+ /**
218
+ * The simple form of a returns clause — a comma-separated list of context names.
219
+ * e.g. `returns AccountCredentials, AuthError`
220
+ * Each name must have a corresponding `when` rule in the module's process.
221
+ */
222
+ export interface SimpleReturnsNode extends BaseNode {
223
+ kind: 'SimpleReturns'
224
+ contexts: string[]
225
+ }
226
+
227
+ /**
228
+ * A side effect declared inside an expanded returns entry.
229
+ * Side effects execute before the context is produced and the module transitions.
230
+ *
231
+ * Examples:
232
+ * `system.setContext name is SessionToken, value is state.context`
233
+ * `system.dropContext name is SessionToken`
234
+ */
235
+ export interface SideEffectNode extends BaseNode {
236
+ kind: 'SideEffect'
237
+ call: QualifiedName
238
+ args: ArgumentNode[]
239
+ }
240
+
241
+ /**
242
+ * A single entry inside an expanded returns block — one context name with
243
+ * zero or more side effects that execute before the context is produced.
244
+ */
245
+ export interface ExpandedReturnNode extends BaseNode {
246
+ kind: 'ExpandedReturn'
247
+ contextName: string
248
+ sideEffects: SideEffectNode[]
249
+ }
250
+
251
+ /**
252
+ * The expanded form of a returns clause, used when one or more returned
253
+ * contexts need to carry side effects.
254
+ *
255
+ * Example:
256
+ * returns (
257
+ * SessionToken (
258
+ * system.setContext name is SessionToken, value is state.context
259
+ * )
260
+ * SessionValidationError (
261
+ * system.dropContext name is SessionToken
262
+ * )
263
+ * )
264
+ */
265
+ export interface ExpandedReturnsNode extends BaseNode {
266
+ kind: 'ExpandedReturns'
267
+ entries: ExpandedReturnNode[]
268
+ }
269
+
270
+ /**
271
+ * Union of the two forms a returns clause can take inside a state definition.
272
+ * The analyser resolves context names from both forms identically.
273
+ */
274
+ export type ReturnsNode = SimpleReturnsNode | ExpandedReturnsNode
275
+
276
+ // ── Argument (is-assignment) ──────────────────────────────────────────────────
277
+
278
+ /**
279
+ * A named argument passed to a component, system call, or method.
280
+ * Always written as `name is value`.
281
+ *
282
+ * The argument name on the left of `is` is either a prop name being wired up
283
+ * (e.g. `type`, `message`, `orderId`) or an interaction prop name defined by
284
+ * the designer on the target component (e.g. `onSubmit`, `onConfirm`, `onDismiss`).
285
+ *
286
+ * Examples:
287
+ * `type is "warning"`
288
+ * `message is state.context.reason`
289
+ * `name is SessionToken, value is state.context`
290
+ */
291
+ export interface ArgumentNode extends BaseNode {
292
+ kind: 'Argument'
293
+ name: string
294
+ value: ExpressionNode
295
+ }
296
+
297
+ // ── Expressions ───────────────────────────────────────────────────────────────
298
+
299
+ /**
300
+ * A dot-separated property access path.
301
+ * Used wherever a value is read from state, props, or a bound iteration variable.
302
+ *
303
+ * Examples:
304
+ * `state.context.fullName` → path = ['state', 'context', 'fullName']
305
+ * `props.items` → path = ['props', 'items']
306
+ * `notification.message` → path = ['notification', 'message']
307
+ */
308
+ export interface AccessExpressionNode extends BaseNode {
309
+ kind: 'AccessExpression'
310
+ path: string[]
311
+ }
312
+
313
+ /**
314
+ * A function or method call expression.
315
+ * Used for system calls and adapter method invocations with arguments.
316
+ *
317
+ * Examples:
318
+ * `system.getContext(SystemUser)`
319
+ * `props.onConfirm(orderId is props.orderId, action is "Confirmed")`
320
+ *
321
+ * Note: `onConfirm` in the second example is not a language keyword — it is
322
+ * an interaction prop name defined by the designer on the target component.
323
+ */
324
+ export interface CallExpressionNode extends BaseNode {
325
+ kind: 'CallExpression'
326
+ callee: AccessExpressionNode | QualifiedName
327
+ args: ArgumentNode[]
328
+ }
329
+
330
+ /**
331
+ * A `state.return(contextName)` expression — the mechanism through which
332
+ * a screen drives a state transition by producing a named context.
333
+ * The contextName must match one of the state's declared `returns` entries.
334
+ */
335
+ export interface StateReturnExpressionNode extends BaseNode {
336
+ kind: 'StateReturnExpression'
337
+ contextName: string
338
+ }
339
+
340
+ /**
341
+ * An inline block expression written as `( ... )`.
342
+ * Used as the value of an interaction prop argument to group one or more
343
+ * statements. The interaction prop name is defined by the designer — the
344
+ * language places no restriction on what it is called.
345
+ *
346
+ * Example:
347
+ * onSubmit is (
348
+ * state.return(credentials)
349
+ * )
350
+ *
351
+ * Here `onSubmit` is a prop name declared by the view designer, not a keyword.
352
+ */
353
+ export interface BlockExpressionNode extends BaseNode {
354
+ kind: 'BlockExpression'
355
+ statements: StatementNode[]
356
+ }
357
+
358
+ /**
359
+ * Union of all expression forms that can appear as the value of an argument,
360
+ * a condition operand, or a prop default.
361
+ */
362
+ export type ExpressionNode =
363
+ | AccessExpressionNode
364
+ | CallExpressionNode
365
+ | StateReturnExpressionNode
366
+ | BlockExpressionNode
367
+ | LiteralNode
368
+
369
+ // ── Statements (inside block expressions) ────────────────────────────────────
370
+
371
+ /**
372
+ * An assignment statement inside a block expression.
373
+ * Used inside interaction prop handler bodies to write values into
374
+ * the component's local state when the interaction fires.
375
+ *
376
+ * The prop name that wraps this block is defined by the designer
377
+ * (e.g. a prop named `onLoad` on a view, or `onSuccess` on an adapter use).
378
+ * The statement itself assigns the received value into a state field.
379
+ *
380
+ * Example: `state.reviews is reviews`
381
+ * — inside a block that is the value of a designer-named interaction prop.
382
+ */
383
+ export interface AssignmentStatementNode extends BaseNode {
384
+ kind: 'AssignmentStatement'
385
+ target: AccessExpressionNode
386
+ value: ExpressionNode
387
+ }
388
+
389
+ /**
390
+ * A `state.return(contextName)` statement inside a block expression.
391
+ * This is the statement form of StateReturnExpressionNode — it appears
392
+ * as the body of an interaction prop handler, driving the state transition
393
+ * when the user performs the corresponding action.
394
+ *
395
+ * The interaction prop that wraps this statement is named by the designer.
396
+ * e.g. `onConfirm is ( state.return(confirmDetails) )`
397
+ */
398
+ export interface StateReturnStatementNode extends BaseNode {
399
+ kind: 'StateReturnStatement'
400
+ contextName: string
401
+ }
402
+
403
+ /**
404
+ * Union of all statement forms that can appear inside a block expression body.
405
+ */
406
+ export type StatementNode =
407
+ | AssignmentStatementNode
408
+ | StateReturnStatementNode
409
+
410
+ // ── Conditional block ─────────────────────────────────────────────────────────
411
+
412
+ /**
413
+ * A boolean condition evaluated inside a `uses` block.
414
+ * The `left` side is always a property access — `state.context`,
415
+ * `state.context.status`, or `props.someField`.
416
+ * The `right` side is the value being compared against.
417
+ * `operator` is either `'is'` (equality) or `'is not'` (inequality).
418
+ *
419
+ * Examples:
420
+ * `state.context is AccountDeauthenticated`
421
+ * `state.context.status is "pending"`
422
+ * `state.context is not AccountRecovered`
423
+ */
424
+ export interface ConditionNode extends BaseNode {
425
+ kind: 'Condition'
426
+ left: AccessExpressionNode
427
+ operator: 'is' | 'is not'
428
+ right: ExpressionNode
429
+ }
430
+
431
+ /**
432
+ * A conditional component mount — `if <condition> ( ... )`.
433
+ * The body contains the same entries as a `uses` block and is only
434
+ * activated when the condition evaluates to true at runtime.
435
+ */
436
+ export interface ConditionalBlockNode extends BaseNode {
437
+ kind: 'ConditionalBlock'
438
+ condition: ConditionNode
439
+ body: UseEntryNode[]
440
+ }
441
+
442
+ // ── Iteration block ───────────────────────────────────────────────────────────
443
+
444
+ /**
445
+ * A `for <collection> as <binding> ( ... )` iteration block.
446
+ * Produces one instance of each child component per item in the collection.
447
+ *
448
+ * For a list: `bindings` has one entry — the item variable name.
449
+ * For a map: `bindings` has two entries — the key variable and the value variable.
450
+ *
451
+ * Examples:
452
+ * `for state.context.notifications as notification ( ... )`
453
+ * → collection = AccessExpression(['state','context','notifications']),
454
+ * bindings = ['notification']
455
+ * `for state.context.productsByCategoryMap as category, products ( ... )`
456
+ * → bindings = ['category', 'products']
457
+ */
458
+ export interface IterationBlockNode extends BaseNode {
459
+ kind: 'IterationBlock'
460
+ collection: AccessExpressionNode
461
+ bindings: string[]
462
+ body: UseEntryNode[]
463
+ }
464
+
465
+ // ── Component use entries ─────────────────────────────────────────────────────
466
+
467
+ /**
468
+ * A single component activation inside a `uses` block.
469
+ * Covers all five component kinds — screen, view, adapter, provider, interface.
470
+ *
471
+ * `name` is a QualifiedName because components can be referenced across modules:
472
+ * `view UIModule.LoginForm ( ... )`
473
+ * `adapter SessionAdapter.checkSession`
474
+ * `screen LoginScreen`
475
+ *
476
+ * `args` are the named arguments passed to the component via `is` assignments.
477
+ * Argument names on the left of `is` correspond to prop names declared by the
478
+ * designer on the target component — the language imposes no naming convention.
479
+ *
480
+ * `uses` holds any nested component uses declared inline (view composition).
481
+ */
482
+ export interface ComponentUseNode extends BaseNode {
483
+ kind: 'ComponentUse'
484
+ componentKind: 'screen' | 'view' | 'adapter' | 'provider' | 'interface'
485
+ name: QualifiedName
486
+ args: ArgumentNode[]
487
+ uses: UseEntryNode[]
488
+ }
489
+
490
+ /**
491
+ * Union of everything that can appear as an entry inside a `uses` block:
492
+ * - A direct component activation (screen, view, adapter, provider, interface)
493
+ * - A conditional block (`if ...`)
494
+ * - An iteration block (`for ... as ...`)
495
+ */
496
+ export type UseEntryNode =
497
+ | ComponentUseNode
498
+ | ConditionalBlockNode
499
+ | IterationBlockNode
500
+
501
+ // ── Process transition ────────────────────────────────────────────────────────
502
+
503
+ /**
504
+ * An inline context construction block following a transition narrative.
505
+ * Used when a state is entered from an external trigger (e.g. an implements
506
+ * handler) and the incoming data must be shaped into the context the
507
+ * receiving state expects.
508
+ *
509
+ * Example:
510
+ * enter Unauthenticated "The user's session has expired" (
511
+ * reason is "The session has expired"
512
+ * code is "ERR:01"
513
+ * )
514
+ */
515
+ export interface InlineContextNode extends BaseNode {
516
+ kind: 'InlineContext'
517
+ args: ArgumentNode[]
518
+ }
519
+
520
+ /**
521
+ * A single `when` rule inside a process body.
522
+ * Declares that when the module is in `currentState` and produces `producedContext`,
523
+ * it should enter `nextState`.
524
+ *
525
+ * `narrative` is the optional quoted explanation of why the transition occurs.
526
+ * `inlineContext` is present only when the transition is triggered externally
527
+ * and the context must be constructed inline.
528
+ */
529
+ export interface WhenRuleNode extends BaseNode {
530
+ kind: 'WhenRule'
531
+ currentState: string
532
+ producedContext: string
533
+ nextState: string
534
+ narrative: string | null
535
+ inlineContext: InlineContextNode | null
536
+ }
537
+
538
+ /**
539
+ * A process definition inside a module.
540
+ * Contains the complete transition map for one scenario — every state the
541
+ * module can be in under that scenario, what each state produces, and
542
+ * where the module goes next.
543
+ */
544
+ export interface ProcessNode extends BaseNode {
545
+ kind: 'Process'
546
+ name: string
547
+ description: string | null
548
+ rules: WhenRuleNode[]
549
+ }
550
+
551
+ // ── Implements block ──────────────────────────────────────────────────────────
552
+
553
+ /**
554
+ * The body of a single `if` branch inside an `implements` switch handler.
555
+ * Maps a path condition to a state transition.
556
+ *
557
+ * Example:
558
+ * if path is "/products"
559
+ * enter ProductList "The /products path activates the product list"
560
+ */
561
+ export interface ImplementsBranchNode extends BaseNode {
562
+ kind: 'ImplementsBranch'
563
+ condition: ConditionNode
564
+ targetState: string
565
+ narrative: string | null
566
+ }
567
+
568
+ /**
569
+ * An `implements ModuleName.HandlerInterface ( ... )` block inside a module.
570
+ * Declares that this module implements the named handler interface and
571
+ * provides the switch logic for routing incoming events to local states.
572
+ *
573
+ * Example:
574
+ * implements RoutingModule.RouteSwitchHandler (
575
+ * switch path(string) (
576
+ * if path is "/products"
577
+ * enter ProductList "The /products path activates the product list"
578
+ * )
579
+ * )
580
+ */
581
+ export interface ImplementsHandlerNode extends BaseNode {
582
+ kind: 'ImplementsHandler'
583
+ interfaceName: QualifiedName
584
+ switchParam: string
585
+ switchParamType: TypeNode
586
+ branches: ImplementsBranchNode[]
587
+ }
588
+
589
+ // ── Top-level constructs ──────────────────────────────────────────────────────
590
+
591
+ /**
592
+ * The root construct of a WORDS project — appears exactly once, in the
593
+ * system file at the project root.
594
+ * Names the application, lists every module it contains, and declares
595
+ * the three built-in system interface methods (getContext, setContext, dropContext).
596
+ */
597
+ export interface SystemNode extends BaseNode {
598
+ kind: 'System'
599
+ name: string
600
+ description: string | null
601
+ modules: string[]
602
+ interfaceMethods: MethodNode[]
603
+ }
604
+
605
+ /**
606
+ * A module definition — the primary organisational unit below the system level.
607
+ * Contains the module's process definitions, starting state, cross-module
608
+ * implements blocks, and any top-level system subscription calls.
609
+ *
610
+ * `startState` is the state the module enters autonomously on initialisation.
611
+ * It is null for stateless modules or modules triggered externally.
612
+ *
613
+ * `subscriptions` are top-level `system.ModuleName.subscribeRoute ...` calls
614
+ * declared directly in the module body.
615
+ *
616
+ * `inlineInterfaces` are interface declarations written inline inside the
617
+ * module body (e.g. handler interface shapes in RoutingModule).
618
+ */
619
+ export interface ModuleNode extends BaseNode {
620
+ kind: 'Module'
621
+ name: string
622
+ description: string | null
623
+ processes: ProcessNode[]
624
+ startState: string | null
625
+ implements: ImplementsHandlerNode[]
626
+ subscriptions: CallExpressionNode[]
627
+ inlineInterfaces: InterfaceNode[]
628
+ }
629
+
630
+ /**
631
+ * A state definition — the smallest behavioral unit in a WORDS specification.
632
+ * Represents a stable condition the module is in, what it expects on entry,
633
+ * what it can produce to drive the next transition, and what it uses while resident.
634
+ *
635
+ * `module` is the owning module name from the ownership declaration line.
636
+ * `receives` is the name of the context expected on entry, or null if the state
637
+ * takes no context. `receivesOptional` is true when prefixed with `?`.
638
+ * `returns` is null for transient states that produce no output.
639
+ * `uses` is empty for states with no components.
640
+ */
641
+ export interface StateNode extends BaseNode {
642
+ kind: 'State'
643
+ module: string
644
+ name: string
645
+ receives: string | null
646
+ receivesOptional: boolean
647
+ returns: ReturnsNode | null
648
+ uses: UseEntryNode[]
649
+ }
650
+
651
+ /**
652
+ * A context definition — the structured, typed data that flows between states.
653
+ * Every context is named, belongs to a module, and declares its fields as props.
654
+ * Referenced by name in state `receives` and `returns` clauses and in process
655
+ * `when` rules.
656
+ */
657
+ export interface ContextNode extends BaseNode {
658
+ kind: 'Context'
659
+ module: string
660
+ name: string
661
+ fields: PropNode[]
662
+ }
663
+
664
+ /**
665
+ * A screen definition — the top-level UI unit used by a state.
666
+ * Has implicit access to `state.context` and `state.return()`.
667
+ * Can only be used by a state, never by another component.
668
+ * Its `uses` block activates view components and may contain
669
+ * conditional blocks and iteration blocks.
670
+ */
671
+ export interface ScreenNode extends BaseNode {
672
+ kind: 'Screen'
673
+ module: string
674
+ name: string
675
+ description: string | null
676
+ uses: UseEntryNode[]
677
+ }
678
+
679
+ /**
680
+ * A view definition — a reusable rendering unit.
681
+ * Receives all data and interaction props via `props`.
682
+ * Interaction prop names are defined by the designer — the language
683
+ * imposes no naming convention on them.
684
+ * Has no access to `state.context` or `state.return()`.
685
+ * Can declare local mutable `state` for concerns it owns entirely
686
+ * (input values, toggle states, hover conditions).
687
+ * Can use other views in its own `uses` block.
688
+ */
689
+ export interface ViewNode extends BaseNode {
690
+ kind: 'View'
691
+ module: string
692
+ name: string
693
+ description: string | null
694
+ props: PropNode[]
695
+ state: PropNode[]
696
+ uses: UseEntryNode[]
697
+ }
698
+
699
+ /**
700
+ * A provider definition — computes and exposes in-memory derived data.
701
+ * Never performs I/O — delegates all external data fetching to adapters
702
+ * received through `props`. Exposes its data through named methods.
703
+ * Maintains its own internal `state` between method calls.
704
+ */
705
+ export interface ProviderNode extends BaseNode {
706
+ kind: 'Provider'
707
+ module: string
708
+ name: string
709
+ description: string | null
710
+ props: PropNode[]
711
+ state: PropNode[]
712
+ methods: MethodNode[]
713
+ }
714
+
715
+ /**
716
+ * An adapter definition — the I/O boundary of the system.
717
+ * The only construct permitted to communicate with the outside world
718
+ * (HTTP APIs, databases, local storage, hardware).
719
+ * The only construct permitted to be async.
720
+ * Receives environment-level configuration through `props`.
721
+ * Maintains runtime state (connection state, cached tokens, retry counters)
722
+ * in its own `state` block.
723
+ * Exposes all external communication through named methods.
724
+ * Method names are defined by the designer.
725
+ */
726
+ export interface AdapterNode extends BaseNode {
727
+ kind: 'Adapter'
728
+ module: string
729
+ name: string
730
+ description: string | null
731
+ props: PropNode[]
732
+ state: PropNode[]
733
+ methods: MethodNode[]
734
+ }
735
+
736
+ /**
737
+ * An interface component definition — a named, typed contract for anything
738
+ * that does not fit the role of screen, view, provider, or adapter.
739
+ * Used as a data model (Product, CartItem), a helper (CatalogueFilter),
740
+ * a handler shape (RouteSwitchHandler), or a callable contract (Pagination).
741
+ *
742
+ * Interface components are the typed vocabulary that all other components
743
+ * reference in their own props and method declarations.
744
+ *
745
+ * When an interface component has a `uses` block, it activates adapters
746
+ * or providers to populate its internal `state`. The interaction props
747
+ * that wire adapter results into state are declared by the designer on
748
+ * the interface component itself — they are plain prop names, not keywords.
749
+ */
750
+ export interface InterfaceNode extends BaseNode {
751
+ kind: 'Interface'
752
+ module: string
753
+ name: string
754
+ description: string | null
755
+ props: PropNode[]
756
+ state: PropNode[]
757
+ methods: MethodNode[]
758
+ uses: UseEntryNode[]
759
+ }
760
+
761
+ // ── Top-level union ───────────────────────────────────────────────────────────
762
+
763
+ /**
764
+ * Union of all constructs that can appear as top-level nodes in a document.
765
+ * A document typically contains exactly one top-level node (e.g. one state,
766
+ * one screen, one context) plus an optional ownership declaration line.
767
+ * The system file and module files may contain more complex structures.
768
+ */
769
+ export type TopLevelNode =
770
+ | SystemNode
771
+ | ModuleNode
772
+ | StateNode
773
+ | ContextNode
774
+ | ScreenNode
775
+ | ViewNode
776
+ | ProviderNode
777
+ | AdapterNode
778
+ | InterfaceNode
779
+
780
+ // ── Document root ─────────────────────────────────────────────────────────────
781
+
782
+ /**
783
+ * The root node produced by parsing a single `.wds` file.
784
+ *
785
+ * `ownerModule` captures the bare `module ModuleName` ownership declaration
786
+ * that appears on its own line at the top of component files (states, screens,
787
+ * views, etc.). It is null in the system file and in module files where the
788
+ * module declaration opens a body block rather than standing alone.
789
+ *
790
+ * `nodes` contains all top-level constructs found in the file. Most component
791
+ * files will have exactly one node. Module files may have one (the module itself).
792
+ * The system file will have one SystemNode.
793
+ */
794
+ export interface DocumentNode {
795
+ kind: 'Document'
796
+ ownerModule: string | null
797
+ nodes: TopLevelNode[]
798
+ }