bonescript-compiler 0.5.3 → 0.5.5

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 (201) hide show
  1. package/LICENSE +21 -21
  2. package/dist/algorithm_catalog.js +166 -166
  3. package/dist/cli.d.ts +1 -2
  4. package/dist/cli.js +617 -75
  5. package/dist/cli.js.map +1 -1
  6. package/dist/emit_capability.d.ts +0 -13
  7. package/dist/emit_capability.js +134 -296
  8. package/dist/emit_capability.js.map +1 -1
  9. package/dist/emit_composition.js +3 -37
  10. package/dist/emit_composition.js.map +1 -1
  11. package/dist/emit_deploy.js +167 -165
  12. package/dist/emit_deploy.js.map +1 -1
  13. package/dist/emit_events.d.ts +0 -1
  14. package/dist/emit_events.js +275 -325
  15. package/dist/emit_events.js.map +1 -1
  16. package/dist/emit_extras.js +5 -3
  17. package/dist/emit_extras.js.map +1 -1
  18. package/dist/emit_full.js +112 -272
  19. package/dist/emit_full.js.map +1 -1
  20. package/dist/emit_maintenance.js +249 -249
  21. package/dist/emit_nakama.d.ts +23 -0
  22. package/dist/emit_nakama.js +510 -0
  23. package/dist/emit_nakama.js.map +1 -0
  24. package/dist/emit_runtime.d.ts +11 -17
  25. package/dist/emit_runtime.js +688 -29
  26. package/dist/emit_runtime.js.map +1 -1
  27. package/dist/emit_sourcemap.js +66 -66
  28. package/dist/emit_tests.js +12 -47
  29. package/dist/emit_tests.js.map +1 -1
  30. package/dist/emit_websocket.js +3 -0
  31. package/dist/emit_websocket.js.map +1 -1
  32. package/dist/emitter.js +49 -94
  33. package/dist/emitter.js.map +1 -1
  34. package/dist/extension_manager.d.ts +2 -2
  35. package/dist/extension_manager.js +20 -9
  36. package/dist/extension_manager.js.map +1 -1
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.js +3 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/ir.d.ts +0 -4
  41. package/dist/lowering.d.ts +14 -5
  42. package/dist/lowering.js +417 -66
  43. package/dist/lowering.js.map +1 -1
  44. package/dist/module_loader.d.ts +2 -2
  45. package/dist/module_loader.js +23 -20
  46. package/dist/module_loader.js.map +1 -1
  47. package/dist/optimizer.js +3 -6
  48. package/dist/optimizer.js.map +1 -1
  49. package/dist/scaffold.d.ts +2 -2
  50. package/dist/scaffold.js +319 -315
  51. package/dist/scaffold.js.map +1 -1
  52. package/dist/solver.js +1 -1
  53. package/dist/solver.js.map +1 -1
  54. package/dist/source_map.js.map +1 -0
  55. package/dist/test.js.map +1 -0
  56. package/dist/test_typechecker.d.ts +5 -0
  57. package/dist/test_typechecker.js +126 -0
  58. package/dist/test_typechecker.js.map +1 -0
  59. package/dist/typechecker.d.ts +0 -7
  60. package/dist/typechecker.js +16 -103
  61. package/dist/typechecker.js.map +1 -1
  62. package/dist/verifier.d.ts +1 -5
  63. package/dist/verifier.js +38 -142
  64. package/dist/verifier.js.map +1 -1
  65. package/package.json +53 -62
  66. package/src/algorithm_catalog.ts +345 -345
  67. package/src/ast.d.ts +244 -0
  68. package/src/ast.ts +334 -334
  69. package/src/cli.ts +704 -98
  70. package/src/emit_batch.ts +140 -140
  71. package/src/emit_capability.ts +436 -613
  72. package/src/emit_composition.ts +196 -229
  73. package/src/emit_deploy.ts +190 -187
  74. package/src/emit_events.ts +307 -362
  75. package/src/emit_extras.ts +240 -237
  76. package/src/emit_full.ts +309 -472
  77. package/src/emit_maintenance.ts +459 -459
  78. package/src/emit_nakama.ts +576 -0
  79. package/src/emit_runtime.ts +730 -17
  80. package/src/emit_sourcemap.ts +140 -140
  81. package/src/emit_tests.ts +205 -243
  82. package/src/emit_websocket.ts +229 -226
  83. package/src/emitter.ts +578 -626
  84. package/src/extension_manager.ts +187 -177
  85. package/src/formatter.ts +297 -297
  86. package/src/index.ts +90 -88
  87. package/src/ir.ts +215 -216
  88. package/src/lexer.d.ts +195 -0
  89. package/src/lexer.ts +630 -630
  90. package/src/lowering.ts +556 -168
  91. package/src/module_loader.ts +114 -112
  92. package/src/optimizer.ts +196 -199
  93. package/src/parse_decls.d.ts +13 -0
  94. package/src/parse_decls.ts +409 -409
  95. package/src/parse_decls2.d.ts +13 -0
  96. package/src/parse_decls2.ts +244 -244
  97. package/src/parse_expr.d.ts +7 -0
  98. package/src/parse_expr.ts +197 -197
  99. package/src/parse_types.d.ts +6 -0
  100. package/src/parse_types.ts +54 -54
  101. package/src/parser.d.ts +10 -0
  102. package/src/parser.ts +1 -1
  103. package/src/parser_base.d.ts +19 -0
  104. package/src/parser_base.ts +57 -57
  105. package/src/parser_recovery.ts +153 -153
  106. package/src/scaffold.ts +375 -371
  107. package/src/solver.ts +330 -330
  108. package/src/typechecker.d.ts +52 -0
  109. package/src/typechecker.ts +591 -700
  110. package/src/types.d.ts +38 -0
  111. package/src/types.ts +122 -122
  112. package/src/verifier.ts +49 -154
  113. package/README.md +0 -382
  114. package/dist/commands/check.d.ts +0 -5
  115. package/dist/commands/check.js +0 -34
  116. package/dist/commands/check.js.map +0 -1
  117. package/dist/commands/compile.d.ts +0 -5
  118. package/dist/commands/compile.js +0 -215
  119. package/dist/commands/compile.js.map +0 -1
  120. package/dist/commands/debug.d.ts +0 -5
  121. package/dist/commands/debug.js +0 -59
  122. package/dist/commands/debug.js.map +0 -1
  123. package/dist/commands/diff.d.ts +0 -5
  124. package/dist/commands/diff.js +0 -123
  125. package/dist/commands/diff.js.map +0 -1
  126. package/dist/commands/fmt.d.ts +0 -5
  127. package/dist/commands/fmt.js +0 -49
  128. package/dist/commands/fmt.js.map +0 -1
  129. package/dist/commands/init.d.ts +0 -5
  130. package/dist/commands/init.js +0 -96
  131. package/dist/commands/init.js.map +0 -1
  132. package/dist/commands/ir.d.ts +0 -5
  133. package/dist/commands/ir.js +0 -27
  134. package/dist/commands/ir.js.map +0 -1
  135. package/dist/commands/lex.d.ts +0 -5
  136. package/dist/commands/lex.js +0 -21
  137. package/dist/commands/lex.js.map +0 -1
  138. package/dist/commands/parse.d.ts +0 -5
  139. package/dist/commands/parse.js +0 -30
  140. package/dist/commands/parse.js.map +0 -1
  141. package/dist/commands/test.d.ts +0 -5
  142. package/dist/commands/test.js +0 -61
  143. package/dist/commands/test.js.map +0 -1
  144. package/dist/commands/verify_determinism.d.ts +0 -5
  145. package/dist/commands/verify_determinism.js +0 -64
  146. package/dist/commands/verify_determinism.js.map +0 -1
  147. package/dist/commands/watch.d.ts +0 -5
  148. package/dist/commands/watch.js +0 -50
  149. package/dist/commands/watch.js.map +0 -1
  150. package/dist/emit_auth.d.ts +0 -18
  151. package/dist/emit_auth.js +0 -507
  152. package/dist/emit_auth.js.map +0 -1
  153. package/dist/emit_database.d.ts +0 -7
  154. package/dist/emit_database.js +0 -72
  155. package/dist/emit_database.js.map +0 -1
  156. package/dist/emit_index.d.ts +0 -6
  157. package/dist/emit_index.js +0 -202
  158. package/dist/emit_index.js.map +0 -1
  159. package/dist/emit_models.d.ts +0 -12
  160. package/dist/emit_models.js +0 -171
  161. package/dist/emit_models.js.map +0 -1
  162. package/dist/emit_openapi.d.ts +0 -9
  163. package/dist/emit_openapi.js +0 -306
  164. package/dist/emit_openapi.js.map +0 -1
  165. package/dist/emit_package.d.ts +0 -7
  166. package/dist/emit_package.js +0 -68
  167. package/dist/emit_package.js.map +0 -1
  168. package/dist/emit_router.d.ts +0 -12
  169. package/dist/emit_router.js +0 -389
  170. package/dist/emit_router.js.map +0 -1
  171. package/dist/lowering_channels.d.ts +0 -11
  172. package/dist/lowering_channels.js +0 -103
  173. package/dist/lowering_channels.js.map +0 -1
  174. package/dist/lowering_entities.d.ts +0 -11
  175. package/dist/lowering_entities.js +0 -232
  176. package/dist/lowering_entities.js.map +0 -1
  177. package/dist/lowering_helpers.d.ts +0 -13
  178. package/dist/lowering_helpers.js +0 -76
  179. package/dist/lowering_helpers.js.map +0 -1
  180. package/src/commands/check.ts +0 -33
  181. package/src/commands/compile.ts +0 -191
  182. package/src/commands/debug.ts +0 -33
  183. package/src/commands/diff.ts +0 -105
  184. package/src/commands/fmt.ts +0 -22
  185. package/src/commands/init.ts +0 -72
  186. package/src/commands/ir.ts +0 -23
  187. package/src/commands/lex.ts +0 -17
  188. package/src/commands/parse.ts +0 -24
  189. package/src/commands/test.ts +0 -36
  190. package/src/commands/verify_determinism.ts +0 -66
  191. package/src/commands/watch.ts +0 -25
  192. package/src/emit_auth.ts +0 -513
  193. package/src/emit_database.ts +0 -72
  194. package/src/emit_index.ts +0 -210
  195. package/src/emit_models.ts +0 -176
  196. package/src/emit_openapi.ts +0 -315
  197. package/src/emit_package.ts +0 -66
  198. package/src/emit_router.ts +0 -408
  199. package/src/lowering_channels.ts +0 -108
  200. package/src/lowering_entities.ts +0 -258
  201. package/src/lowering_helpers.ts +0 -75
package/src/formatter.ts CHANGED
@@ -1,297 +1,297 @@
1
- /**
2
- * BoneScript Formatter — `bone fmt`
3
- * Canonicalizes whitespace and formatting in .bone source files.
4
- *
5
- * Rules:
6
- * - 2-space indentation
7
- * - One declaration per logical block, separated by one blank line
8
- * - Field lists: one per line if more than 2, otherwise inline
9
- * - Constraints: one per line
10
- * - Trailing newline at end of file
11
- * - LF line endings
12
- */
13
-
14
- import * as AST from "./ast";
15
-
16
- export class Formatter {
17
- private out: string[] = [];
18
- private indent = 0;
19
-
20
- format(program: AST.ProgramNode): string {
21
- this.out = [];
22
- this.indent = 0;
23
-
24
- for (let i = 0; i < program.systems.length; i++) {
25
- this.formatSystem(program.systems[i]);
26
- if (i < program.systems.length - 1) this.line("");
27
- }
28
-
29
- return this.out.join("\n") + "\n";
30
- }
31
-
32
- private line(s: string) {
33
- this.out.push(" ".repeat(this.indent) + s);
34
- }
35
-
36
- private blank() {
37
- this.out.push("");
38
- }
39
-
40
- private formatSystem(sys: AST.SystemDeclNode) {
41
- this.line(`system ${sys.name} {`);
42
- this.indent++;
43
-
44
- if (sys.domain) {
45
- this.line(`domain: ${sys.domain}`);
46
- this.blank();
47
- }
48
-
49
- for (let i = 0; i < sys.declarations.length; i++) {
50
- this.formatDeclaration(sys.declarations[i]);
51
- if (i < sys.declarations.length - 1) this.blank();
52
- }
53
-
54
- this.indent--;
55
- this.line(`}`);
56
- }
57
-
58
- private formatDeclaration(decl: AST.DeclarationNode) {
59
- switch (decl.kind) {
60
- case "EntityDecl": this.formatEntity(decl); break;
61
- case "CapabilityDecl": this.formatCapability(decl); break;
62
- case "ChannelDecl": this.formatChannel(decl); break;
63
- case "StoreDecl": this.formatStore(decl); break;
64
- case "EventDecl": this.formatEvent(decl); break;
65
- case "ConstraintDecl": this.formatConstraint(decl); break;
66
- case "PolicyDecl": this.formatPolicy(decl); break;
67
- case "FlowDecl": this.formatFlow(decl); break;
68
- case "ImportDecl": this.formatImport(decl); break;
69
- case "ExtensionPointDecl": this.formatExtensionPoint(decl); break;
70
- }
71
- }
72
-
73
- private formatEntity(e: AST.EntityDeclNode) {
74
- this.line(`entity ${e.name} {`);
75
- this.indent++;
76
-
77
- if (e.owns.length > 0) {
78
- if (e.owns.length <= 2) {
79
- const fields = e.owns.map(f => `${f.name}: ${this.formatType(f.type)}`).join(", ");
80
- this.line(`owns: [${fields}]`);
81
- } else {
82
- this.line(`owns: [`);
83
- this.indent++;
84
- for (let i = 0; i < e.owns.length; i++) {
85
- const f = e.owns[i];
86
- const comma = i < e.owns.length - 1 ? "," : "";
87
- this.line(`${f.name}: ${this.formatType(f.type)}${comma}`);
88
- }
89
- this.indent--;
90
- this.line(`]`);
91
- }
92
- }
93
-
94
- if (e.constraints.length > 0) {
95
- this.line(`constraints: [`);
96
- this.indent++;
97
- for (let i = 0; i < e.constraints.length; i++) {
98
- const comma = i < e.constraints.length - 1 ? "," : "";
99
- this.line(`${this.formatExpr(e.constraints[i])}${comma}`);
100
- }
101
- this.indent--;
102
- this.line(`]`);
103
- }
104
-
105
- if (e.states) {
106
- const path = e.states.nodes.map(n => n.name).join(" -> ");
107
- this.line(`states: ${path}`);
108
- }
109
-
110
- if (e.auth) this.line(`auth: ${e.auth}`);
111
-
112
- for (const idx of e.indexes) {
113
- this.line(`index: [${idx.join(", ")}]`);
114
- }
115
-
116
- this.indent--;
117
- this.line(`}`);
118
- }
119
-
120
- private formatCapability(c: AST.CapabilityDeclNode) {
121
- const params = c.params.map(p => `${p.name}: ${this.formatType(p.type)}`).join(", ");
122
- this.line(`capability ${c.name}(${params}) {`);
123
- this.indent++;
124
-
125
- if (c.requires.length > 0) {
126
- this.line(`requires: [`);
127
- this.indent++;
128
- for (let i = 0; i < c.requires.length; i++) {
129
- const comma = i < c.requires.length - 1 ? "," : "";
130
- this.line(`${this.formatExpr(c.requires[i])}${comma}`);
131
- }
132
- this.indent--;
133
- this.line(`]`);
134
- }
135
-
136
- if (c.effects.length > 0) {
137
- this.line(`effects: [`);
138
- this.indent++;
139
- for (let i = 0; i < c.effects.length; i++) {
140
- const eff = c.effects[i];
141
- const comma = i < c.effects.length - 1 ? "," : "";
142
- this.line(`${eff.target.path.join(".")} ${eff.op} ${this.formatExpr(eff.value)}${comma}`);
143
- }
144
- this.indent--;
145
- this.line(`]`);
146
- }
147
-
148
- if (c.emits.length > 0) {
149
- const emits = c.emits.map(e => {
150
- const args = e.args.map(a => this.formatExpr(a)).join(", ");
151
- return args ? `${e.eventName}(${args})` : e.eventName;
152
- }).join(", ");
153
- this.line(`emits: ${emits}`);
154
- }
155
-
156
- if (c.sync) this.line(`sync: ${c.sync}`);
157
- if (c.timeout) this.line(`timeout: ${c.timeout}`);
158
- if (c.idempotent !== null) this.line(`idempotent: ${c.idempotent}`);
159
-
160
- this.indent--;
161
- this.line(`}`);
162
- }
163
-
164
- private formatChannel(c: AST.ChannelDeclNode) {
165
- this.line(`channel ${c.name} {`);
166
- this.indent++;
167
- if (c.transport) this.line(`transport: ${c.transport}`);
168
- if (c.ordering) this.line(`ordering: ${c.ordering}`);
169
- if (c.participants) this.line(`participants: ${this.formatType(c.participants)}`);
170
- if (c.persistence) this.line(`persistence: ${c.persistence}`);
171
- if (c.maxSize !== null) this.line(`max_size: ${c.maxSize}`);
172
- if (c.filter) this.line(`filter: ${this.formatExpr(c.filter)}`);
173
- this.indent--;
174
- this.line(`}`);
175
- }
176
-
177
- private formatStore(s: AST.StoreDeclNode) {
178
- this.line(`store ${s.name} {`);
179
- this.indent++;
180
- if (s.engine) this.line(`engine: ${s.engine}`);
181
- if (s.schema.length > 0) {
182
- this.line(`schema: {`);
183
- this.indent++;
184
- for (let i = 0; i < s.schema.length; i++) {
185
- const f = s.schema[i];
186
- const comma = i < s.schema.length - 1 ? "," : "";
187
- this.line(`${f.name}: ${this.formatType(f.type)}${comma}`);
188
- }
189
- this.indent--;
190
- this.line(`}`);
191
- }
192
- if (s.retention) this.line(`retention: ${s.retention}`);
193
- if (s.partition) this.line(`partition: ${s.partition}`);
194
- if (s.replicas !== null) this.line(`replicas: ${s.replicas}`);
195
- this.indent--;
196
- this.line(`}`);
197
- }
198
-
199
- private formatEvent(e: AST.EventDeclNode) {
200
- this.line(`event ${e.name} {`);
201
- this.indent++;
202
- if (e.payload.length > 0) {
203
- this.line(`payload: {`);
204
- this.indent++;
205
- for (let i = 0; i < e.payload.length; i++) {
206
- const f = e.payload[i];
207
- const comma = i < e.payload.length - 1 ? "," : "";
208
- this.line(`${f.name}: ${this.formatType(f.type)}${comma}`);
209
- }
210
- this.indent--;
211
- this.line(`}`);
212
- }
213
- if (e.delivery) this.line(`delivery: ${e.delivery}`);
214
- if (e.ttl) this.line(`ttl: ${e.ttl}`);
215
- this.indent--;
216
- this.line(`}`);
217
- }
218
-
219
- private formatConstraint(c: AST.ConstraintDeclNode) {
220
- this.line(`constraint ${c.name}: ${this.formatExpr(c.expr)}`);
221
- }
222
-
223
- private formatPolicy(p: AST.PolicyDeclNode) {
224
- this.line(`policy ${p.name} {`);
225
- this.indent++;
226
- if (p.rateLimit) this.line(`rate_limit: ${p.rateLimit.count} per ${p.rateLimit.per}`);
227
- if (p.access.length > 0) this.line(`access: [${p.access.join(", ")}]`);
228
- if (p.audit !== null) this.line(`audit: ${p.audit}`);
229
- if (p.encryption) this.line(`encryption: ${p.encryption}`);
230
- this.indent--;
231
- this.line(`}`);
232
- }
233
-
234
- private formatFlow(f: AST.FlowDeclNode) {
235
- this.line(`flow ${f.name} {`);
236
- this.indent++;
237
- for (let i = 0; i < f.steps.length; i++) {
238
- const step = f.steps[i];
239
- const args = step.action.args.map(a => this.formatExpr(a)).join(", ");
240
- this.line(`step ${step.name}: ${step.action.name}(${args})`);
241
- if (step.compensate) {
242
- const cargs = step.compensate.args.map(a => this.formatExpr(a)).join(", ");
243
- this.indent++;
244
- this.line(`compensate: ${step.compensate.name}(${cargs})`);
245
- this.indent--;
246
- }
247
- if (i < f.steps.length - 1) this.blank();
248
- }
249
- this.indent--;
250
- this.line(`}`);
251
- }
252
-
253
- private formatImport(i: AST.ImportDeclNode) {
254
- this.line(`import ${i.name} from "${i.from}"`);
255
- }
256
-
257
- private formatType(t: AST.TypeExprNode): string {
258
- switch (t.kind) {
259
- case "PrimitiveType": return t.name;
260
- case "GenericType": return `${t.name}<${t.typeArgs.map(a => this.formatType(a)).join(", ")}>`;
261
- case "EntityRefType": return t.name;
262
- case "TupleType": return `(${t.elements.map(e => this.formatType(e)).join(", ")})`;
263
- case "UnionType": return t.members.map(m => this.formatType(m)).join(" | ");
264
- }
265
- }
266
-
267
- private formatExpr(e: AST.ExprNode): string {
268
- switch (e.kind) {
269
- case "Literal":
270
- if (e.type === "string") return `"${e.value}"`;
271
- if (e.type === "list") return `[${(e.value as AST.ExprNode[]).map(v => this.formatExpr(v)).join(", ")}]`;
272
- if (e.type === "none") return "none";
273
- return String(e.value);
274
- case "FieldRef":
275
- return e.path.join(".");
276
- case "BinaryExpr":
277
- if (e.op === "..") return `${this.formatExpr(e.left)}..${this.formatExpr(e.right)}`;
278
- return `${this.formatExpr(e.left)} ${e.op} ${this.formatExpr(e.right)}`;
279
- case "UnaryExpr":
280
- return `${e.op} ${this.formatExpr(e.operand)}`;
281
- case "CallExpr":
282
- return `${e.name}(${e.args.map(a => this.formatExpr(a)).join(", ")})`;
283
- case "TernaryExpr":
284
- return `${this.formatExpr(e.condition)} ? ${this.formatExpr(e.consequent)} : ${this.formatExpr(e.alternate)}`;
285
- }
286
- }
287
-
288
- private formatExtensionPoint(e: AST.ExtensionPointDeclNode) {
289
- const params = e.params.map(p => `${p.name}: ${this.formatType(p.type)}`).join(", ");
290
- this.line(`extension_point ${e.name}(${params}) {`);
291
- this.indent++;
292
- if (e.returns) this.line(`returns: ${this.formatType(e.returns)}`);
293
- this.line(`stable: ${e.stable}`);
294
- this.indent--;
295
- this.line(`}`);
296
- }
297
- }
1
+ /**
2
+ * BoneScript Formatter — `bone fmt`
3
+ * Canonicalizes whitespace and formatting in .bone source files.
4
+ *
5
+ * Rules:
6
+ * - 2-space indentation
7
+ * - One declaration per logical block, separated by one blank line
8
+ * - Field lists: one per line if more than 2, otherwise inline
9
+ * - Constraints: one per line
10
+ * - Trailing newline at end of file
11
+ * - LF line endings
12
+ */
13
+
14
+ import * as AST from "./ast";
15
+
16
+ export class Formatter {
17
+ private out: string[] = [];
18
+ private indent = 0;
19
+
20
+ format(program: AST.ProgramNode): string {
21
+ this.out = [];
22
+ this.indent = 0;
23
+
24
+ for (let i = 0; i < program.systems.length; i++) {
25
+ this.formatSystem(program.systems[i]);
26
+ if (i < program.systems.length - 1) this.line("");
27
+ }
28
+
29
+ return this.out.join("\n") + "\n";
30
+ }
31
+
32
+ private line(s: string) {
33
+ this.out.push(" ".repeat(this.indent) + s);
34
+ }
35
+
36
+ private blank() {
37
+ this.out.push("");
38
+ }
39
+
40
+ private formatSystem(sys: AST.SystemDeclNode) {
41
+ this.line(`system ${sys.name} {`);
42
+ this.indent++;
43
+
44
+ if (sys.domain) {
45
+ this.line(`domain: ${sys.domain}`);
46
+ this.blank();
47
+ }
48
+
49
+ for (let i = 0; i < sys.declarations.length; i++) {
50
+ this.formatDeclaration(sys.declarations[i]);
51
+ if (i < sys.declarations.length - 1) this.blank();
52
+ }
53
+
54
+ this.indent--;
55
+ this.line(`}`);
56
+ }
57
+
58
+ private formatDeclaration(decl: AST.DeclarationNode) {
59
+ switch (decl.kind) {
60
+ case "EntityDecl": this.formatEntity(decl); break;
61
+ case "CapabilityDecl": this.formatCapability(decl); break;
62
+ case "ChannelDecl": this.formatChannel(decl); break;
63
+ case "StoreDecl": this.formatStore(decl); break;
64
+ case "EventDecl": this.formatEvent(decl); break;
65
+ case "ConstraintDecl": this.formatConstraint(decl); break;
66
+ case "PolicyDecl": this.formatPolicy(decl); break;
67
+ case "FlowDecl": this.formatFlow(decl); break;
68
+ case "ImportDecl": this.formatImport(decl); break;
69
+ case "ExtensionPointDecl": this.formatExtensionPoint(decl); break;
70
+ }
71
+ }
72
+
73
+ private formatEntity(e: AST.EntityDeclNode) {
74
+ this.line(`entity ${e.name} {`);
75
+ this.indent++;
76
+
77
+ if (e.owns.length > 0) {
78
+ if (e.owns.length <= 2) {
79
+ const fields = e.owns.map(f => `${f.name}: ${this.formatType(f.type)}`).join(", ");
80
+ this.line(`owns: [${fields}]`);
81
+ } else {
82
+ this.line(`owns: [`);
83
+ this.indent++;
84
+ for (let i = 0; i < e.owns.length; i++) {
85
+ const f = e.owns[i];
86
+ const comma = i < e.owns.length - 1 ? "," : "";
87
+ this.line(`${f.name}: ${this.formatType(f.type)}${comma}`);
88
+ }
89
+ this.indent--;
90
+ this.line(`]`);
91
+ }
92
+ }
93
+
94
+ if (e.constraints.length > 0) {
95
+ this.line(`constraints: [`);
96
+ this.indent++;
97
+ for (let i = 0; i < e.constraints.length; i++) {
98
+ const comma = i < e.constraints.length - 1 ? "," : "";
99
+ this.line(`${this.formatExpr(e.constraints[i])}${comma}`);
100
+ }
101
+ this.indent--;
102
+ this.line(`]`);
103
+ }
104
+
105
+ if (e.states) {
106
+ const path = e.states.nodes.map(n => n.name).join(" -> ");
107
+ this.line(`states: ${path}`);
108
+ }
109
+
110
+ if (e.auth) this.line(`auth: ${e.auth}`);
111
+
112
+ for (const idx of e.indexes) {
113
+ this.line(`index: [${idx.join(", ")}]`);
114
+ }
115
+
116
+ this.indent--;
117
+ this.line(`}`);
118
+ }
119
+
120
+ private formatCapability(c: AST.CapabilityDeclNode) {
121
+ const params = c.params.map(p => `${p.name}: ${this.formatType(p.type)}`).join(", ");
122
+ this.line(`capability ${c.name}(${params}) {`);
123
+ this.indent++;
124
+
125
+ if (c.requires.length > 0) {
126
+ this.line(`requires: [`);
127
+ this.indent++;
128
+ for (let i = 0; i < c.requires.length; i++) {
129
+ const comma = i < c.requires.length - 1 ? "," : "";
130
+ this.line(`${this.formatExpr(c.requires[i])}${comma}`);
131
+ }
132
+ this.indent--;
133
+ this.line(`]`);
134
+ }
135
+
136
+ if (c.effects.length > 0) {
137
+ this.line(`effects: [`);
138
+ this.indent++;
139
+ for (let i = 0; i < c.effects.length; i++) {
140
+ const eff = c.effects[i];
141
+ const comma = i < c.effects.length - 1 ? "," : "";
142
+ this.line(`${eff.target.path.join(".")} ${eff.op} ${this.formatExpr(eff.value)}${comma}`);
143
+ }
144
+ this.indent--;
145
+ this.line(`]`);
146
+ }
147
+
148
+ if (c.emits.length > 0) {
149
+ const emits = c.emits.map(e => {
150
+ const args = e.args.map(a => this.formatExpr(a)).join(", ");
151
+ return args ? `${e.eventName}(${args})` : e.eventName;
152
+ }).join(", ");
153
+ this.line(`emits: ${emits}`);
154
+ }
155
+
156
+ if (c.sync) this.line(`sync: ${c.sync}`);
157
+ if (c.timeout) this.line(`timeout: ${c.timeout}`);
158
+ if (c.idempotent !== null) this.line(`idempotent: ${c.idempotent}`);
159
+
160
+ this.indent--;
161
+ this.line(`}`);
162
+ }
163
+
164
+ private formatChannel(c: AST.ChannelDeclNode) {
165
+ this.line(`channel ${c.name} {`);
166
+ this.indent++;
167
+ if (c.transport) this.line(`transport: ${c.transport}`);
168
+ if (c.ordering) this.line(`ordering: ${c.ordering}`);
169
+ if (c.participants) this.line(`participants: ${this.formatType(c.participants)}`);
170
+ if (c.persistence) this.line(`persistence: ${c.persistence}`);
171
+ if (c.maxSize !== null) this.line(`max_size: ${c.maxSize}`);
172
+ if (c.filter) this.line(`filter: ${this.formatExpr(c.filter)}`);
173
+ this.indent--;
174
+ this.line(`}`);
175
+ }
176
+
177
+ private formatStore(s: AST.StoreDeclNode) {
178
+ this.line(`store ${s.name} {`);
179
+ this.indent++;
180
+ if (s.engine) this.line(`engine: ${s.engine}`);
181
+ if (s.schema.length > 0) {
182
+ this.line(`schema: {`);
183
+ this.indent++;
184
+ for (let i = 0; i < s.schema.length; i++) {
185
+ const f = s.schema[i];
186
+ const comma = i < s.schema.length - 1 ? "," : "";
187
+ this.line(`${f.name}: ${this.formatType(f.type)}${comma}`);
188
+ }
189
+ this.indent--;
190
+ this.line(`}`);
191
+ }
192
+ if (s.retention) this.line(`retention: ${s.retention}`);
193
+ if (s.partition) this.line(`partition: ${s.partition}`);
194
+ if (s.replicas !== null) this.line(`replicas: ${s.replicas}`);
195
+ this.indent--;
196
+ this.line(`}`);
197
+ }
198
+
199
+ private formatEvent(e: AST.EventDeclNode) {
200
+ this.line(`event ${e.name} {`);
201
+ this.indent++;
202
+ if (e.payload.length > 0) {
203
+ this.line(`payload: {`);
204
+ this.indent++;
205
+ for (let i = 0; i < e.payload.length; i++) {
206
+ const f = e.payload[i];
207
+ const comma = i < e.payload.length - 1 ? "," : "";
208
+ this.line(`${f.name}: ${this.formatType(f.type)}${comma}`);
209
+ }
210
+ this.indent--;
211
+ this.line(`}`);
212
+ }
213
+ if (e.delivery) this.line(`delivery: ${e.delivery}`);
214
+ if (e.ttl) this.line(`ttl: ${e.ttl}`);
215
+ this.indent--;
216
+ this.line(`}`);
217
+ }
218
+
219
+ private formatConstraint(c: AST.ConstraintDeclNode) {
220
+ this.line(`constraint ${c.name}: ${this.formatExpr(c.expr)}`);
221
+ }
222
+
223
+ private formatPolicy(p: AST.PolicyDeclNode) {
224
+ this.line(`policy ${p.name} {`);
225
+ this.indent++;
226
+ if (p.rateLimit) this.line(`rate_limit: ${p.rateLimit.count} per ${p.rateLimit.per}`);
227
+ if (p.access.length > 0) this.line(`access: [${p.access.join(", ")}]`);
228
+ if (p.audit !== null) this.line(`audit: ${p.audit}`);
229
+ if (p.encryption) this.line(`encryption: ${p.encryption}`);
230
+ this.indent--;
231
+ this.line(`}`);
232
+ }
233
+
234
+ private formatFlow(f: AST.FlowDeclNode) {
235
+ this.line(`flow ${f.name} {`);
236
+ this.indent++;
237
+ for (let i = 0; i < f.steps.length; i++) {
238
+ const step = f.steps[i];
239
+ const args = step.action.args.map(a => this.formatExpr(a)).join(", ");
240
+ this.line(`step ${step.name}: ${step.action.name}(${args})`);
241
+ if (step.compensate) {
242
+ const cargs = step.compensate.args.map(a => this.formatExpr(a)).join(", ");
243
+ this.indent++;
244
+ this.line(`compensate: ${step.compensate.name}(${cargs})`);
245
+ this.indent--;
246
+ }
247
+ if (i < f.steps.length - 1) this.blank();
248
+ }
249
+ this.indent--;
250
+ this.line(`}`);
251
+ }
252
+
253
+ private formatImport(i: AST.ImportDeclNode) {
254
+ this.line(`import ${i.name} from "${i.from}"`);
255
+ }
256
+
257
+ private formatType(t: AST.TypeExprNode): string {
258
+ switch (t.kind) {
259
+ case "PrimitiveType": return t.name;
260
+ case "GenericType": return `${t.name}<${t.typeArgs.map(a => this.formatType(a)).join(", ")}>`;
261
+ case "EntityRefType": return t.name;
262
+ case "TupleType": return `(${t.elements.map(e => this.formatType(e)).join(", ")})`;
263
+ case "UnionType": return t.members.map(m => this.formatType(m)).join(" | ");
264
+ }
265
+ }
266
+
267
+ private formatExpr(e: AST.ExprNode): string {
268
+ switch (e.kind) {
269
+ case "Literal":
270
+ if (e.type === "string") return `"${e.value}"`;
271
+ if (e.type === "list") return `[${(e.value as AST.ExprNode[]).map(v => this.formatExpr(v)).join(", ")}]`;
272
+ if (e.type === "none") return "none";
273
+ return String(e.value);
274
+ case "FieldRef":
275
+ return e.path.join(".");
276
+ case "BinaryExpr":
277
+ if (e.op === "..") return `${this.formatExpr(e.left)}..${this.formatExpr(e.right)}`;
278
+ return `${this.formatExpr(e.left)} ${e.op} ${this.formatExpr(e.right)}`;
279
+ case "UnaryExpr":
280
+ return `${e.op} ${this.formatExpr(e.operand)}`;
281
+ case "CallExpr":
282
+ return `${e.name}(${e.args.map(a => this.formatExpr(a)).join(", ")})`;
283
+ case "TernaryExpr":
284
+ return `${this.formatExpr(e.condition)} ? ${this.formatExpr(e.consequent)} : ${this.formatExpr(e.alternate)}`;
285
+ }
286
+ }
287
+
288
+ private formatExtensionPoint(e: AST.ExtensionPointDeclNode) {
289
+ const params = e.params.map(p => `${p.name}: ${this.formatType(p.type)}`).join(", ");
290
+ this.line(`extension_point ${e.name}(${params}) {`);
291
+ this.indent++;
292
+ if (e.returns) this.line(`returns: ${this.formatType(e.returns)}`);
293
+ this.line(`stable: ${e.stable}`);
294
+ this.indent--;
295
+ this.line(`}`);
296
+ }
297
+ }