@velarscript/compiler 0.10.1

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 (159) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +70 -0
  3. package/dist/analyzer.d.ts +1175 -0
  4. package/dist/analyzer.d.ts.map +1 -0
  5. package/dist/analyzer.js +12130 -0
  6. package/dist/analyzer.js.map +1 -0
  7. package/dist/application-package-host.d.ts +28 -0
  8. package/dist/application-package-host.d.ts.map +1 -0
  9. package/dist/application-package-host.js +2 -0
  10. package/dist/application-package-host.js.map +1 -0
  11. package/dist/ast.d.ts +853 -0
  12. package/dist/ast.d.ts.map +1 -0
  13. package/dist/ast.js +245 -0
  14. package/dist/ast.js.map +1 -0
  15. package/dist/class-runtime.d.ts +6 -0
  16. package/dist/class-runtime.d.ts.map +1 -0
  17. package/dist/class-runtime.js +45 -0
  18. package/dist/class-runtime.js.map +1 -0
  19. package/dist/collection-lowering-runtime.d.ts +7 -0
  20. package/dist/collection-lowering-runtime.d.ts.map +1 -0
  21. package/dist/collection-lowering-runtime.js +952 -0
  22. package/dist/collection-lowering-runtime.js.map +1 -0
  23. package/dist/collection-runtime.d.ts +16 -0
  24. package/dist/collection-runtime.d.ts.map +1 -0
  25. package/dist/collection-runtime.js +231 -0
  26. package/dist/collection-runtime.js.map +1 -0
  27. package/dist/core-vocabulary.d.ts +141 -0
  28. package/dist/core-vocabulary.d.ts.map +1 -0
  29. package/dist/core-vocabulary.js +88 -0
  30. package/dist/core-vocabulary.js.map +1 -0
  31. package/dist/diagnostic.d.ts +42 -0
  32. package/dist/diagnostic.d.ts.map +1 -0
  33. package/dist/diagnostic.js +66 -0
  34. package/dist/diagnostic.js.map +1 -0
  35. package/dist/embedded-javascript.d.ts +74 -0
  36. package/dist/embedded-javascript.d.ts.map +1 -0
  37. package/dist/embedded-javascript.js +341 -0
  38. package/dist/embedded-javascript.js.map +1 -0
  39. package/dist/embedded-module.d.ts +11 -0
  40. package/dist/embedded-module.d.ts.map +1 -0
  41. package/dist/embedded-module.js +67 -0
  42. package/dist/embedded-module.js.map +1 -0
  43. package/dist/embedded-source.d.ts +19 -0
  44. package/dist/embedded-source.d.ts.map +1 -0
  45. package/dist/embedded-source.js +61 -0
  46. package/dist/embedded-source.js.map +1 -0
  47. package/dist/emitter.d.ts +188 -0
  48. package/dist/emitter.d.ts.map +1 -0
  49. package/dist/emitter.js +3254 -0
  50. package/dist/emitter.js.map +1 -0
  51. package/dist/error-runtime.d.ts +17 -0
  52. package/dist/error-runtime.d.ts.map +1 -0
  53. package/dist/error-runtime.js +109 -0
  54. package/dist/error-runtime.js.map +1 -0
  55. package/dist/extension.d.ts +373 -0
  56. package/dist/extension.d.ts.map +1 -0
  57. package/dist/extension.js +25 -0
  58. package/dist/extension.js.map +1 -0
  59. package/dist/formatter.d.ts +13 -0
  60. package/dist/formatter.d.ts.map +1 -0
  61. package/dist/formatter.js +1440 -0
  62. package/dist/formatter.js.map +1 -0
  63. package/dist/framework-host.d.ts +87 -0
  64. package/dist/framework-host.d.ts.map +1 -0
  65. package/dist/framework-host.js +2 -0
  66. package/dist/framework-host.js.map +1 -0
  67. package/dist/index.d.ts +75 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +932 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/interpolated-string.d.ts +47 -0
  72. package/dist/interpolated-string.d.ts.map +1 -0
  73. package/dist/interpolated-string.js +344 -0
  74. package/dist/interpolated-string.js.map +1 -0
  75. package/dist/json-runtime.d.ts +2 -0
  76. package/dist/json-runtime.d.ts.map +1 -0
  77. package/dist/json-runtime.js +193 -0
  78. package/dist/json-runtime.js.map +1 -0
  79. package/dist/language-guidance.d.ts +31 -0
  80. package/dist/language-guidance.d.ts.map +1 -0
  81. package/dist/language-guidance.js +187 -0
  82. package/dist/language-guidance.js.map +1 -0
  83. package/dist/lexer.d.ts +85 -0
  84. package/dist/lexer.d.ts.map +1 -0
  85. package/dist/lexer.js +1004 -0
  86. package/dist/lexer.js.map +1 -0
  87. package/dist/limits.d.ts +2 -0
  88. package/dist/limits.d.ts.map +1 -0
  89. package/dist/limits.js +2 -0
  90. package/dist/limits.js.map +1 -0
  91. package/dist/mechanical-fix.d.ts +26 -0
  92. package/dist/mechanical-fix.d.ts.map +1 -0
  93. package/dist/mechanical-fix.js +61 -0
  94. package/dist/mechanical-fix.js.map +1 -0
  95. package/dist/narrowing-runtime.d.ts +5 -0
  96. package/dist/narrowing-runtime.d.ts.map +1 -0
  97. package/dist/narrowing-runtime.js +27 -0
  98. package/dist/narrowing-runtime.js.map +1 -0
  99. package/dist/number-runtime.d.ts +3 -0
  100. package/dist/number-runtime.d.ts.map +1 -0
  101. package/dist/number-runtime.js +37 -0
  102. package/dist/number-runtime.js.map +1 -0
  103. package/dist/parser.d.ts +245 -0
  104. package/dist/parser.d.ts.map +1 -0
  105. package/dist/parser.js +3582 -0
  106. package/dist/parser.js.map +1 -0
  107. package/dist/primitive-runtime.d.ts +4 -0
  108. package/dist/primitive-runtime.d.ts.map +1 -0
  109. package/dist/primitive-runtime.js +39 -0
  110. package/dist/primitive-runtime.js.map +1 -0
  111. package/dist/promise-runtime.d.ts +6 -0
  112. package/dist/promise-runtime.d.ts.map +1 -0
  113. package/dist/promise-runtime.js +86 -0
  114. package/dist/promise-runtime.js.map +1 -0
  115. package/dist/reactive-bridge-runtime.d.ts +7 -0
  116. package/dist/reactive-bridge-runtime.d.ts.map +1 -0
  117. package/dist/reactive-bridge-runtime.js +112 -0
  118. package/dist/reactive-bridge-runtime.js.map +1 -0
  119. package/dist/runtime-abi.d.ts +24 -0
  120. package/dist/runtime-abi.d.ts.map +1 -0
  121. package/dist/runtime-abi.js +24 -0
  122. package/dist/runtime-abi.js.map +1 -0
  123. package/dist/semantic.d.ts +142 -0
  124. package/dist/semantic.d.ts.map +1 -0
  125. package/dist/semantic.js +845 -0
  126. package/dist/semantic.js.map +1 -0
  127. package/dist/source-names.d.ts +32 -0
  128. package/dist/source-names.d.ts.map +1 -0
  129. package/dist/source-names.js +101 -0
  130. package/dist/source-names.js.map +1 -0
  131. package/dist/source.d.ts +19 -0
  132. package/dist/source.d.ts.map +1 -0
  133. package/dist/source.js +64 -0
  134. package/dist/source.js.map +1 -0
  135. package/dist/text-runtime.d.ts +2 -0
  136. package/dist/text-runtime.d.ts.map +1 -0
  137. package/dist/text-runtime.js +285 -0
  138. package/dist/text-runtime.js.map +1 -0
  139. package/dist/token.d.ts +19 -0
  140. package/dist/token.d.ts.map +1 -0
  141. package/dist/token.js +51 -0
  142. package/dist/token.js.map +1 -0
  143. package/dist/type-registry-runtime.d.ts +7 -0
  144. package/dist/type-registry-runtime.d.ts.map +1 -0
  145. package/dist/type-registry-runtime.js +51 -0
  146. package/dist/type-registry-runtime.js.map +1 -0
  147. package/dist/type-validation-runtime.d.ts +17 -0
  148. package/dist/type-validation-runtime.d.ts.map +1 -0
  149. package/dist/type-validation-runtime.js +150 -0
  150. package/dist/type-validation-runtime.js.map +1 -0
  151. package/dist/types.d.ts +356 -0
  152. package/dist/types.d.ts.map +1 -0
  153. package/dist/types.js +1170 -0
  154. package/dist/types.js.map +1 -0
  155. package/dist/utf8-runtime.d.ts +7 -0
  156. package/dist/utf8-runtime.d.ts.map +1 -0
  157. package/dist/utf8-runtime.js +43 -0
  158. package/dist/utf8-runtime.js.map +1 -0
  159. package/package.json +48 -0
@@ -0,0 +1,3254 @@
1
+ import { blockContainsDirectAwait, expressionContainsDirectAwait as containsDirectAwait, testFunctionName } from "./ast.js";
2
+ import { VELAR_CLASS_FIELD_MODULE, VELAR_CLASS_FIELD_RUNTIME } from "./class-runtime.js";
3
+ import { VELAR_COLLECTION_HOST_EXPORTS, VELAR_COLLECTION_HOST_MODULE, VELAR_COLLECTION_IDENTITY_RUNTIME, VELAR_COLLECTION_LIST_RUNTIME, VELAR_COLLECTION_RECORD_RUNTIME, VELAR_COLLECTION_SET_MAP_RUNTIME, VELAR_COLLECTION_TYPE_RUNTIME } from "./collection-runtime.js";
4
+ import { VELAR_COLLECTION_LOWERING_EXPORTS, VELAR_COLLECTION_LOWERING_MODULE, VELAR_COLLECTION_LOWERING_RUNTIME } from "./collection-lowering-runtime.js";
5
+ import { describeType, formatTypeReference, formatTypeSyntax, mapNestedTypes, resolveTypeReference, semanticTypeIdentity, typeContainsParameter } from "./types.js";
6
+ import { disposeMemberKey, iterateMemberKey } from "./analyzer.js";
7
+ import { VELAR_ERROR_NORMALIZATION_MODULE, VELAR_ERROR_NORMALIZATION_RUNTIME, VELAR_HOST_ERROR_NAMES, VELAR_HOST_ERROR_RUNTIME } from "./error-runtime.js";
8
+ import { embeddedJavaScriptSpecifier } from "./embedded-module.js";
9
+ import { VELAR_NARROWING_MODULE, VELAR_NARROWING_RUNTIME } from "./narrowing-runtime.js";
10
+ import { VELAR_NUMBER_METHOD_RUNTIME } from "./number-runtime.js";
11
+ import { VELAR_PRIMITIVE_METHOD_MODULE } from "./primitive-runtime.js";
12
+ import { VELAR_PROMISE_NORMALIZATION_MODULE, VELAR_PROMISE_NORMALIZATION_RUNTIME } from "./promise-runtime.js";
13
+ import { VELAR_REACTIVE_BRIDGE_MODULE, VELAR_REACTIVE_BRIDGE_RUNTIME, VELAR_REACTIVE_COLLECTION_BRIDGE_RUNTIME } from "./reactive-bridge-runtime.js";
14
+ import { spanIdentity } from "./source.js";
15
+ import { VELAR_TEXT_METHOD_RUNTIME } from "./text-runtime.js";
16
+ import { VELAR_TYPE_REGISTRY_RUNTIME } from "./type-registry-runtime.js";
17
+ import { VELAR_RUNTIME_TYPE_COLLECTION_RUNTIME, VELAR_TYPE_VALIDATION_MODULE, VELAR_TYPE_VALIDATION_RUNTIME, VELAR_VALIDATION_ERROR_RUNTIME, } from "./type-validation-runtime.js";
18
+ const javaScriptNodeMarker = /\u0000VELAR_MAP_(\d+)\u0000/gu;
19
+ // ENM-U4 + COL-U5: the compiler-raised error types are nameable in source;
20
+ // their runtime classes carry compiler-owned names. The source names are
21
+ // reserved Core bindings, so a bare reference is always the builtin.
22
+ const builtinErrorRuntimeNames = new Map([
23
+ ["ValidationError", "__VelarValidationError"],
24
+ ["NarrowingError", "__VelarNarrowingError"],
25
+ ["IndexError", "__VelarIndexError"],
26
+ ]);
27
+ export class JavaScriptEmitter {
28
+ typeDeclarations = new Map();
29
+ runtimeTypes = new Set();
30
+ expandedRuntimeTypes = new Set();
31
+ /**
32
+ * D55 rule 121: the type parameters of the generic record currently being
33
+ * emitted. Inside that body a `T`-typed position is checked by the argument
34
+ * predicate the instantiation supplied, which is the only reading of `T` a
35
+ * validator can have once the type is erased.
36
+ */
37
+ genericTypeParameters = null;
38
+ /** Hoisted `function __velarTypeOf_N()` bodies for instantiations written outside a generic. */
39
+ hoistedGenericInstances = new Map();
40
+ externModuleExports = new Map();
41
+ needsExternExportHelper = false;
42
+ hints;
43
+ forcedFunctionExports;
44
+ sharedRuntimeModules;
45
+ requiredRuntimeModules = new Set();
46
+ needsIndexHelpers = false;
47
+ needsBinaryHelpers = false;
48
+ needsBitwiseHelpers = false;
49
+ needsCollectionHelpers = false;
50
+ needsPrimitiveHelpers = false;
51
+ needsRecordHelpers = false;
52
+ needsObjectBindingHelpers = false;
53
+ needsListBindingHelpers = false;
54
+ needsDirectCollectionInfrastructure = false;
55
+ needsRuntimeTypeHelpers = false;
56
+ needsNumberHelper = false;
57
+ needsThrownValueHelper = false;
58
+ needsErrorCodeHelper = false;
59
+ requiredHostErrorClasses = new Set();
60
+ needsDetachedTaskHelper = false;
61
+ needsDisposalHelper = false;
62
+ needsIntegrityFailureHelper = false;
63
+ needsNarrowingErrorClass = false;
64
+ suppressPromiseNormalization = 0;
65
+ nextJavaScriptNodeId = 0;
66
+ javaScriptNodeSpans = new Map();
67
+ generatedMappings = [];
68
+ generatedCode = "";
69
+ sourcePath;
70
+ embeddedJavaScript = new Map();
71
+ constructor(hints, forcedFunctionExports = new Set(), options = {}) {
72
+ this.hints = hints;
73
+ this.forcedFunctionExports = forcedFunctionExports;
74
+ this.sharedRuntimeModules = options.sharedRuntimeModules === true;
75
+ this.sourcePath = options.sourcePath ?? "<source>";
76
+ }
77
+ emit(program) {
78
+ this.nextJavaScriptNodeId = 0;
79
+ this.javaScriptNodeSpans.clear();
80
+ this.requiredRuntimeModules.clear();
81
+ this.requiredHostErrorClasses.clear();
82
+ this.prepareEmbeddedJavaScript(program);
83
+ this.collectDeclarations(program);
84
+ this.collectRuntimeUses(program);
85
+ const statements = program.body
86
+ .map((statement) => this.emitJavaScriptNode(statement.span, () => this.emitStatement(statement, 0)))
87
+ .filter((item) => item.code.length > 0);
88
+ const needsDirectCollectionInfrastructure = this.needsDirectCollectionInfrastructure
89
+ || this.needsRecordHelpers
90
+ || this.needsObjectBindingHelpers
91
+ || this.needsListBindingHelpers;
92
+ const helpers = [...this.additionalHelpers(program)];
93
+ const builtinValues = new Set(this.hints.builtinValueReferences.values());
94
+ if (builtinValues.has("Json")) {
95
+ helpers.push('import * as __velarJsonNamespace from "velar/json";');
96
+ this.requiredRuntimeModules.add("velar/json");
97
+ }
98
+ if (builtinValues.has("Promise")) {
99
+ helpers.push('import * as __velarPromiseNamespace from "velar/async";');
100
+ this.requiredRuntimeModules.add("velar/async");
101
+ }
102
+ if (builtinValues.has("Text")) {
103
+ helpers.push('import * as __velarTextNamespace from "velar/text";');
104
+ this.requiredRuntimeModules.add("velar/text");
105
+ }
106
+ if (builtinValues.has("Math")) {
107
+ helpers.push('import * as __velarMathNamespace from "velar/math";');
108
+ this.requiredRuntimeModules.add("velar/math");
109
+ }
110
+ if (builtinValues.has("range")) {
111
+ helpers.push('import { range as __velarRange } from "velar/collections";');
112
+ this.requiredRuntimeModules.add("velar/collections");
113
+ }
114
+ if (this.hints.nativeRangeForStatements.size > 0) {
115
+ helpers.push('import { range as __velarCountedRangeOwner } from "velar/collections";');
116
+ this.requiredRuntimeModules.add("velar/collections");
117
+ }
118
+ if (this.needsBinaryHelpers) {
119
+ helpers.push('import { Bytes as __velarBinaryRuntime } from "velar/binary";');
120
+ this.requiredRuntimeModules.add("velar/binary");
121
+ }
122
+ if (this.needsBitwiseHelpers) {
123
+ helpers.push([
124
+ "const __velarBitwiseApply = Reflect.apply;",
125
+ "const __velarBitwiseNumber = Number;",
126
+ "const __velarBitwiseNumberIsInteger = Number.isInteger;",
127
+ "const __velarBitwiseTypeError = TypeError;",
128
+ "const __velarBitwiseRangeError = RangeError;",
129
+ "function __velarBitwiseOperand(value, operator) {",
130
+ " if (typeof value !== \"number\" || !__velarBitwiseApply(__velarBitwiseNumberIsInteger, __velarBitwiseNumber, [value])) throw new __velarBitwiseTypeError(\"Bitwise '\" + operator + \"' requires integer operands\");",
131
+ " if (value < -2147483648 || value > 4294967295) throw new __velarBitwiseRangeError(\"Bitwise '\" + operator + \"' requires 32-bit integer operands\");",
132
+ " return value;",
133
+ "}",
134
+ "function __velarBitwiseUnary(value) { value = __velarBitwiseOperand(value, \"~\"); return ~value; }",
135
+ "function __velarBitwiseBinary(left, operator, right) {",
136
+ " left = __velarBitwiseOperand(left, operator);",
137
+ " if (operator === \"<<\" || operator === \">>\" || operator === \">>>\") {",
138
+ " if (typeof right !== \"number\" || !__velarBitwiseApply(__velarBitwiseNumberIsInteger, __velarBitwiseNumber, [right])) throw new __velarBitwiseTypeError(\"Bitwise '\" + operator + \"' requires an integer shift count\");",
139
+ " if (right < 0 || right > 31) throw new __velarBitwiseRangeError(\"Bitwise '\" + operator + \"' requires a shift count from 0 to 31\");",
140
+ " return operator === \"<<\" ? left << right : operator === \">>\" ? left >> right : left >>> right;",
141
+ " }",
142
+ " right = __velarBitwiseOperand(right, operator);",
143
+ " return operator === \"&\" ? left & right : operator === \"|\" ? left | right : left ^ right;",
144
+ "}",
145
+ ].join("\n"));
146
+ }
147
+ if ([...this.hints.extensionCalls.values()].includes("core.duration-arithmetic"))
148
+ helpers.push([
149
+ "const __velarDurationApply = Reflect.apply;",
150
+ "const __velarDurationPattern = /^([+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+))(ms|s)$/;",
151
+ "const __velarDurationRegExpExec = RegExp.prototype.exec;",
152
+ "const __velarDurationNumber = Number;",
153
+ "const __velarDurationNumberIsFinite = Number.isFinite;",
154
+ "const __velarDurationObjectIs = Object.is;",
155
+ "const __velarDurationString = String;",
156
+ "const __velarDurationTypeError = TypeError;",
157
+ "const __velarDurationRangeError = RangeError;",
158
+ "function __velarDurationMilliseconds(value) {",
159
+ " if (typeof value !== \"string\") throw new __velarDurationTypeError(\"Duration arithmetic requires Duration values\");",
160
+ " const match = __velarDurationApply(__velarDurationRegExpExec, __velarDurationPattern, [value]);",
161
+ " if (!match) throw new __velarDurationTypeError(\"Duration arithmetic requires Duration values\");",
162
+ " const milliseconds = __velarDurationNumber(match[1]) * (match[2] === \"s\" ? 1000 : 1);",
163
+ " if (!__velarDurationNumberIsFinite(milliseconds)) throw new __velarDurationRangeError(\"Duration arithmetic must produce a finite value\");",
164
+ " return milliseconds;",
165
+ "}",
166
+ "function __velarDurationValue(milliseconds) {",
167
+ " if (!__velarDurationNumberIsFinite(milliseconds)) throw new __velarDurationRangeError(\"Duration arithmetic must produce a finite value\");",
168
+ " return __velarDurationString(__velarDurationObjectIs(milliseconds, -0) ? 0 : milliseconds) + \"ms\";",
169
+ "}",
170
+ "function __velarDurationUnary(operator, value) { const milliseconds = __velarDurationMilliseconds(value); return __velarDurationValue(operator === \"-\" ? -milliseconds : milliseconds); }",
171
+ "function __velarDurationMath(operator, left, right) {",
172
+ " if (operator === \"+\" || operator === \"-\") { const a = __velarDurationMilliseconds(left), b = __velarDurationMilliseconds(right); return __velarDurationValue(operator === \"+\" ? a + b : a - b); }",
173
+ " if (operator === \"*\" && typeof left === \"number\") return __velarDurationValue(left * __velarDurationMilliseconds(right));",
174
+ " const milliseconds = __velarDurationMilliseconds(left);",
175
+ " if (typeof right !== \"number\" || !__velarDurationNumberIsFinite(right)) throw new __velarDurationTypeError(\"Duration scaling requires a finite number\");",
176
+ " if (operator === \"/\" && right === 0) throw new __velarDurationRangeError(\"Duration arithmetic cannot divide by zero\");",
177
+ " return __velarDurationValue(operator === \"*\" ? milliseconds * right : milliseconds / right);",
178
+ "}",
179
+ ].join("\n"));
180
+ helpers.push(...this.reactiveBridgeHelpers(this.hints.javaScriptCallBoundaries.size > 0, this.sharedRuntimeModules ? needsDirectCollectionInfrastructure : this.needsCollectionHelpers));
181
+ // Runtime imports are selected from JavaScript identifier tokens, not raw
182
+ // substrings. Raw text produces two wrong answers: a user string such as
183
+ // "__velarStringTrim" looks like a call, and a real
184
+ // __velarStringReplaceAll call also looks like __velarStringReplace.
185
+ // Generated helper names are reserved, so an identifier token is an exact
186
+ // compiler-owned use once string/comment/template text has been skipped.
187
+ const generatedIdentifiers = javaScriptIdentifiers([
188
+ ...statements.map((statement) => statement.code),
189
+ ...helpers,
190
+ ]);
191
+ const usesGeneratedName = (name) => generatedIdentifiers.has(name);
192
+ if (this.needsExternExportHelper) {
193
+ // W-22: an extern module declaration is trusted for shapes, but the
194
+ // declared export must actually exist. The bridge verifies presence at
195
+ // module initialization with one property probe per imported name; a
196
+ // declared export that legitimately holds undefined stays importable
197
+ // because the boundary is membership in the module namespace, not the
198
+ // value.
199
+ helpers.push([
200
+ "function __velarExternExport(namespace, name, source) {",
201
+ " const value = namespace[name];",
202
+ " if (value === undefined && !(name in namespace)) {",
203
+ " throw new TypeError(name === \"default\"",
204
+ " ? `Extern module '${source}' declares 'default', but the JavaScript module has no default export; declare the module's real named exports instead`",
205
+ " : `Extern module '${source}' declares '${name}', but the JavaScript module has no such export; prototype methods and instance members belong on a declared class or singleton const, not module exports`);",
206
+ " }",
207
+ " return value;",
208
+ "}",
209
+ ].join("\n"));
210
+ }
211
+ if (this.needsPrimitiveHelpers) {
212
+ if (this.sharedRuntimeModules) {
213
+ this.requiredRuntimeModules.add(VELAR_PRIMITIVE_METHOD_MODULE);
214
+ const imports = [
215
+ ["stringSize", "__velarStringSize"], ["stringTrim", "__velarStringTrim"], ["stringUpper", "__velarStringUpper"], ["stringLower", "__velarStringLower"],
216
+ ["stringSlice", "__velarStringSlice"], ["stringChar", "__velarStringChar"], ["stringHas", "__velarStringHas"], ["stringIndex", "__velarStringIndex"],
217
+ ["stringCount", "__velarStringCount"], ["stringStartsWith", "__velarStringStartsWith"], ["stringEndsWith", "__velarStringEndsWith"],
218
+ ["stringSplit", "__velarStringSplit"], ["stringReplace", "__velarStringReplace"], ["stringReplaceAll", "__velarStringReplaceAll"],
219
+ ["stringPadStart", "__velarStringPadStart"], ["stringPadEnd", "__velarStringPadEnd"], ["stringRepeat", "__velarStringRepeat"],
220
+ ["stringIsBlank", "__velarStringIsBlank"], ["stringCompare", "__velarStringCompare"], ["orderCompare", "__velarOrderCompare"],
221
+ ["numberAbs", "__velarNumberAbs"], ["numberRound", "__velarNumberRound"], ["numberFloor", "__velarNumberFloor"],
222
+ ["numberCeil", "__velarNumberCeil"], ["numberToFixed", "__velarNumberToFixed"],
223
+ ["numberIsInteger", "__velarNumberIsInteger"], ["numberIsNaN", "__velarNumberIsNaN"], ["numberIsFinite", "__velarNumberIsFinite"],
224
+ ].filter(([, local]) => usesGeneratedName(local));
225
+ helpers.push(`import { ${imports.map(([exported, local]) => `${exported} as ${local}`).join(", ")} } from ${JSON.stringify(VELAR_PRIMITIVE_METHOD_MODULE)};`);
226
+ }
227
+ else {
228
+ helpers.push(VELAR_TEXT_METHOD_RUNTIME);
229
+ helpers.push(VELAR_NUMBER_METHOD_RUNTIME);
230
+ }
231
+ }
232
+ if (this.hints.instanceFieldReads.size > 0 || this.hints.privateInstanceFieldReads.size > 0 || this.hints.staticFieldReads.size > 0) {
233
+ if (this.sharedRuntimeModules) {
234
+ this.requiredRuntimeModules.add(VELAR_CLASS_FIELD_MODULE);
235
+ const imports = [
236
+ ["readInstanceField", "__velarReadInstanceField"],
237
+ ["readPrivateField", "__velarReadPrivateField"],
238
+ ["readStaticField", "__velarReadStaticField"],
239
+ ].filter(([, local]) => usesGeneratedName(local));
240
+ helpers.push(`import { ${imports.map(([exported, local]) => `${exported} as ${local}`).join(", ")} } from ${JSON.stringify(VELAR_CLASS_FIELD_MODULE)};`);
241
+ }
242
+ else {
243
+ helpers.push(VELAR_CLASS_FIELD_RUNTIME);
244
+ }
245
+ }
246
+ if (this.hints.runtimeNarrowings.size > 0 || this.needsNarrowingErrorClass) {
247
+ if (this.sharedRuntimeModules) {
248
+ this.requireRuntimeModule(VELAR_NARROWING_MODULE);
249
+ const imports = [
250
+ ...(this.hints.runtimeNarrowings.size > 0 ? ["narrow as __velarNarrow"] : []),
251
+ ...(this.needsNarrowingErrorClass ? ["NarrowingError as __VelarNarrowingError"] : []),
252
+ ];
253
+ helpers.push(`import { ${imports.join(", ")} } from ${JSON.stringify(VELAR_NARROWING_MODULE)};`);
254
+ }
255
+ else {
256
+ helpers.push(VELAR_NARROWING_RUNTIME);
257
+ }
258
+ }
259
+ const needsPromiseNormalization = this.hints.normalizedPromiseValues.size > 0
260
+ || this.hints.asyncResolvedValues.size > 0
261
+ || this.hints.asyncForStatements.size > 0;
262
+ if (needsPromiseNormalization) {
263
+ if (this.sharedRuntimeModules) {
264
+ this.requireRuntimeModule(VELAR_PROMISE_NORMALIZATION_MODULE);
265
+ const imports = [
266
+ ...(this.hints.normalizedPromiseValues.size > 0 || this.hints.asyncForStatements.size > 0
267
+ ? ["normalizePromiseValue as __velarNormalizePromiseValue"]
268
+ : []),
269
+ ...(this.hints.asyncResolvedValues.size > 0
270
+ ? ["asyncResolvedValue as __velarAsyncResolvedValue"]
271
+ : []),
272
+ ];
273
+ helpers.push(`import { ${imports.join(", ")} } from ${JSON.stringify(VELAR_PROMISE_NORMALIZATION_MODULE)};`);
274
+ }
275
+ else {
276
+ helpers.push(VELAR_PROMISE_NORMALIZATION_RUNTIME);
277
+ }
278
+ }
279
+ if (this.hints.asyncForStatements.size > 0) {
280
+ helpers.push([
281
+ "const __velarAsyncPullGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;",
282
+ "const __velarAsyncPullGetPrototypeOf = Object.getPrototypeOf;",
283
+ "const __velarAsyncPullApply = Reflect.apply;",
284
+ "const __velarAsyncPullArguments = [];",
285
+ "const __velarAsyncPullTypeError = TypeError;",
286
+ // Class methods live on the prototype (charter section 18), so the
287
+ // capture walks the chain with descriptor reads. The first level that
288
+ // declares 'next' decides: only a data-valued function is accepted,
289
+ // and an accessor is rejected without ever being invoked.
290
+ "function __velarAsyncPullNext(source) {",
291
+ " if ((typeof source !== \"object\" && typeof source !== \"function\") || source === null) {",
292
+ " throw new __velarAsyncPullTypeError(\"async for requires a data-valued next method\");",
293
+ " }",
294
+ " for (let owner = source; owner !== null; owner = __velarAsyncPullGetPrototypeOf(owner)) {",
295
+ " const descriptor = __velarAsyncPullGetOwnPropertyDescriptor(owner, \"next\");",
296
+ " if (!descriptor) continue;",
297
+ " if (!(\"value\" in descriptor) || typeof descriptor.value !== \"function\") {",
298
+ " throw new __velarAsyncPullTypeError(\"async for requires a data-valued next method\");",
299
+ " }",
300
+ " return descriptor.value;",
301
+ " }",
302
+ " throw new __velarAsyncPullTypeError(\"async for requires a data-valued next method\");",
303
+ "}",
304
+ "function __velarAsyncPullCall(source, next) {",
305
+ " return __velarAsyncPullApply(next, source, __velarAsyncPullArguments);",
306
+ "}",
307
+ ].join("\n"));
308
+ }
309
+ if (this.needsDetachedTaskHelper) {
310
+ helpers.push(...this.detachedTaskHelpers());
311
+ }
312
+ if (this.needsDisposalHelper) {
313
+ helpers.push(...this.disposalHelpers());
314
+ }
315
+ if (this.needsIntegrityFailureHelper) {
316
+ helpers.push(...this.integrityFailureHelpers());
317
+ }
318
+ const needsErrorNormalizationRuntime = this.needsThrownValueHelper || this.needsErrorCodeHelper;
319
+ if (needsErrorNormalizationRuntime && !this.includesErrorNormalizationRuntime()) {
320
+ if (this.sharedRuntimeModules) {
321
+ this.requireRuntimeModule(VELAR_ERROR_NORMALIZATION_MODULE);
322
+ const imports = [
323
+ ...(this.needsErrorCodeHelper ? ["errorCode as __velarErrorCode"] : []),
324
+ ...(this.needsThrownValueHelper ? ["normalizeError as __velarNormalizeError"] : []),
325
+ ];
326
+ helpers.push(`import { ${imports.join(", ")} } from ${JSON.stringify(VELAR_ERROR_NORMALIZATION_MODULE)};`);
327
+ }
328
+ else {
329
+ helpers.push(VELAR_ERROR_NORMALIZATION_RUNTIME);
330
+ }
331
+ }
332
+ // D50 rule 89: a named capability error is a leaf class the compiler owns,
333
+ // so a source reference resolves to the one runtime class every capability
334
+ // constructs — the same wiring the three compiler-raised errors use.
335
+ if (this.requiredHostErrorClasses.size > 0) {
336
+ const imports = [...this.requiredHostErrorClasses].sort().map((name) => `${name} as __Velar${name}`);
337
+ if (this.sharedRuntimeModules) {
338
+ this.requireRuntimeModule(VELAR_ERROR_NORMALIZATION_MODULE);
339
+ helpers.push(`import { ${imports.join(", ")} } from ${JSON.stringify(VELAR_ERROR_NORMALIZATION_MODULE)};`);
340
+ }
341
+ else {
342
+ helpers.push(VELAR_HOST_ERROR_RUNTIME);
343
+ }
344
+ }
345
+ const needsRuntimeTypeRuntime = this.needsRuntimeTypeHelpers || this.runtimeTypes.size > 0
346
+ || program.body.some((statement) => statement.kind === "EnumDeclaration");
347
+ if (needsDirectCollectionInfrastructure && this.sharedRuntimeModules) {
348
+ this.requireRuntimeModule(VELAR_COLLECTION_HOST_MODULE);
349
+ helpers.push([
350
+ "import {",
351
+ ...VELAR_COLLECTION_HOST_EXPORTS.map((name) => ` ${name},`),
352
+ `} from ${JSON.stringify(VELAR_COLLECTION_HOST_MODULE)};`,
353
+ ].join("\n"));
354
+ }
355
+ else if (!this.sharedRuntimeModules && (this.needsCollectionHelpers || needsRuntimeTypeRuntime)) {
356
+ helpers.push(VELAR_COLLECTION_IDENTITY_RUNTIME);
357
+ }
358
+ if (needsRuntimeTypeRuntime) {
359
+ if (this.sharedRuntimeModules) {
360
+ this.requireRuntimeModule(VELAR_TYPE_VALIDATION_MODULE);
361
+ const imports = [
362
+ ["registerRuntimeType", "__velarRegisterRuntimeType"], ["ValidationError", "__VelarValidationError"],
363
+ ["validationState", "__velarValidationState"], ["validationSet", "__velarValidationSet"],
364
+ ["validationWeakMapGet", "__velarValidationWeakMapGet"], ["validationWeakMapSet", "__velarValidationWeakMapSet"], ["validationWeakMapDelete", "__velarValidationWeakMapDelete"],
365
+ ["validationSetHas", "__velarValidationSetHas"], ["validationSetAdd", "__velarValidationSetAdd"], ["validationSetDelete", "__velarValidationSetDelete"], ["validationSetSize", "__velarValidationSetSize"],
366
+ ["validationIsArray", "__velarValidationIsArray"], ["validationOwnDescriptor", "__velarValidationOwnDescriptor"],
367
+ ["validationIsInstance", "__velarValidationIsInstance"], ["validationIsPromise", "__velarValidationIsPromise"],
368
+ ["validationIsPlainObject", "__velarValidationIsPlainObject"], ["validationRejectionHint", "__velarValidationRejectionHint"],
369
+ ["validationFreeze", "__velarValidationFreeze"],
370
+ ["listTypeIs", "__velarListTypeIs"], ["setTypeIs", "__velarSetTypeIs"], ["mapTypeIs", "__velarMapTypeIs"], ["recordTypeIs", "__velarRecordTypeIs"],
371
+ ].filter(([, local]) => usesGeneratedName(local));
372
+ helpers.push(`import { ${imports.map(([exported, local]) => `${exported} as ${local}`).join(", ")} } from ${JSON.stringify(VELAR_TYPE_VALIDATION_MODULE)};`);
373
+ }
374
+ else {
375
+ helpers.push(VELAR_COLLECTION_TYPE_RUNTIME);
376
+ helpers.push(VELAR_TYPE_REGISTRY_RUNTIME);
377
+ helpers.push(VELAR_TYPE_VALIDATION_RUNTIME);
378
+ helpers.push(VELAR_RUNTIME_TYPE_COLLECTION_RUNTIME);
379
+ helpers.push(VELAR_VALIDATION_ERROR_RUNTIME);
380
+ }
381
+ }
382
+ if (this.needsCollectionHelpers) {
383
+ if (this.sharedRuntimeModules) {
384
+ this.requireRuntimeModule(VELAR_COLLECTION_LOWERING_MODULE);
385
+ const imports = VELAR_COLLECTION_LOWERING_EXPORTS.filter((name) => usesGeneratedName(name)
386
+ || (this.needsListBindingHelpers && name === "__velarValidateDenseList"));
387
+ helpers.push([
388
+ "import {",
389
+ ...imports.map((name) => ` ${name},`),
390
+ `} from ${JSON.stringify(VELAR_COLLECTION_LOWERING_MODULE)};`,
391
+ ].join("\n"));
392
+ }
393
+ else {
394
+ helpers.push(VELAR_COLLECTION_LIST_RUNTIME);
395
+ helpers.push(VELAR_COLLECTION_SET_MAP_RUNTIME);
396
+ helpers.push(VELAR_COLLECTION_RECORD_RUNTIME);
397
+ helpers.push(VELAR_COLLECTION_LOWERING_RUNTIME);
398
+ }
399
+ }
400
+ if (this.needsRecordHelpers) {
401
+ helpers.push([
402
+ "const __velarMaxRecordFields = 1000000;",
403
+ "",
404
+ "function __velarSetRecordField(output, field, value, count) {",
405
+ " const present = __velarCollectionRecordGetOwnPropertyDescriptor(output, field) !== undefined;",
406
+ " if (!present && count >= __velarMaxRecordFields) throw new __velarCollectionRecordNativeRangeError(\"A record cannot exceed 1000000 fields\");",
407
+ " __velarCollectionRecordDefineProperty(output, field, { value: value ?? null, writable: true, enumerable: true, configurable: true });",
408
+ " return present ? count : count + 1;",
409
+ "}",
410
+ "function __velarSpreadRecord(output, value, count) {",
411
+ " if (value === null || typeof value !== \"object\" || __velarCollectionListIsArray(value)) throw new __velarCollectionNativeTypeError(\"Object spread requires a record object\");",
412
+ " if (__velarCollectionRecordOwnSymbols(value).length > 0) throw new __velarCollectionNativeTypeError(\"Object spread cannot copy symbol fields\");",
413
+ " __velarReactiveCollectionTrack(value);",
414
+ " const fields = __velarCollectionRecordOwnNames(value);",
415
+ " if (fields.length > __velarMaxRecordFields) throw new __velarCollectionRecordNativeRangeError(\"Object spread cannot inspect more than 1000000 fields\");",
416
+ " for (let index = 0; index < fields.length; index += 1) {",
417
+ " const field = fields[index];",
418
+ " const descriptor = __velarCollectionRecordGetOwnPropertyDescriptor(value, field);",
419
+ " if (!descriptor) throw new __velarCollectionNativeTypeError(\"Object spread source changed while it was being copied\");",
420
+ " if (!descriptor.enumerable) continue;",
421
+ " if (!(\"value\" in descriptor)) throw new __velarCollectionNativeTypeError(\"Object spread cannot copy accessor field '\" + field + \"'\");",
422
+ " count = __velarSetRecordField(output, field, __velarReactiveCollectionRead(value, field, descriptor.value), count);",
423
+ " }",
424
+ " return count;",
425
+ "}",
426
+ "function __velarCreateRecord(parts) {",
427
+ " const output = {};",
428
+ " let count = 0;",
429
+ " for (let index = 0; index < parts.length; index += 1) {",
430
+ " const spread = parts[index][0];",
431
+ " const field = parts[index][1];",
432
+ " const read = parts[index][2];",
433
+ " if (spread) count = __velarSpreadRecord(output, read(), count);",
434
+ " else {",
435
+ " count = __velarSetRecordField(output, field, read(), count);",
436
+ " }",
437
+ " }",
438
+ " return output;",
439
+ "}",
440
+ "async function __velarCreateRecordAsync(parts) {",
441
+ " const output = {};",
442
+ " let count = 0;",
443
+ " for (let index = 0; index < parts.length; index += 1) {",
444
+ " const spread = parts[index][0];",
445
+ " const field = parts[index][1];",
446
+ " const asynchronous = parts[index][2];",
447
+ " const read = parts[index][3];",
448
+ " if (spread) count = __velarSpreadRecord(output, asynchronous ? await read() : read(), count);",
449
+ " else {",
450
+ " count = __velarSetRecordField(output, field, asynchronous ? await read() : read(), count);",
451
+ " }",
452
+ " }",
453
+ " return output;",
454
+ "}",
455
+ ].join("\n"));
456
+ }
457
+ if (this.needsObjectBindingHelpers) {
458
+ helpers.push([
459
+ "const __velarMaxBindingFields = 1000000;",
460
+ "",
461
+ "function __velarRequireBindingObject(value, name) {",
462
+ " if (value === null || typeof value !== \"object\" || __velarCollectionListIsArray(value)) throw new __velarCollectionNativeTypeError(name + \" object binding requires a record object\");",
463
+ " return value;",
464
+ "}",
465
+ "function __velarReadBindingField(value, field, optional, name) {",
466
+ " __velarReactiveCollectionTrack(value, field);",
467
+ " const descriptor = __velarCollectionRecordGetOwnPropertyDescriptor(value, field);",
468
+ " if (descriptor === undefined) {",
469
+ " if (optional) return null;",
470
+ " throw new __velarCollectionNativeTypeError(name + \" object binding requires own data field '\" + field + \"'\");",
471
+ " }",
472
+ " if (!descriptor.enumerable || !(\"value\" in descriptor)) throw new __velarCollectionNativeTypeError(name + \" object binding requires enumerable data field '\" + field + \"'\");",
473
+ " return __velarReactiveCollectionRead(value, field, descriptor.value) ?? null;",
474
+ "}",
475
+ "function __velarBindingObjectRest(value, excluded, name) {",
476
+ " if (__velarCollectionRecordOwnSymbols(value).length > 0) throw new __velarCollectionNativeTypeError(name + \" object rest cannot copy symbol fields\");",
477
+ " __velarReactiveCollectionTrack(value);",
478
+ " const fields = __velarCollectionRecordOwnNames(value);",
479
+ " if (fields.length > __velarMaxBindingFields) throw new __velarCollectionRecordNativeRangeError(name + \" object rest cannot copy more than 1000000 fields\");",
480
+ " const output = {};",
481
+ " for (let fieldIndex = 0; fieldIndex < fields.length; fieldIndex += 1) {",
482
+ " const field = fields[fieldIndex];",
483
+ " let selected = false;",
484
+ " for (let index = 0; index < excluded.length; index += 1) if (excluded[index] === field) { selected = true; break; }",
485
+ " if (selected) continue;",
486
+ " const descriptor = __velarCollectionRecordGetOwnPropertyDescriptor(value, field);",
487
+ " if (!descriptor?.enumerable) continue;",
488
+ " if (!(\"value\" in descriptor)) throw new __velarCollectionNativeTypeError(name + \" object rest cannot copy accessor field '\" + field + \"'\");",
489
+ " __velarCollectionRecordDefineProperty(output, field, { value: __velarReactiveCollectionRead(value, field, descriptor.value) ?? null, writable: true, enumerable: true, configurable: true });",
490
+ " }",
491
+ " return output;",
492
+ "}",
493
+ ].join("\n"));
494
+ }
495
+ if (this.needsListBindingHelpers) {
496
+ helpers.push([
497
+ "function __velarRequireBindingList(value, size, hasRest, name) {",
498
+ " __velarValidateDenseList(value, name + \" List binding\");",
499
+ " __velarReactiveCollectionTrack(value);",
500
+ " const valid = hasRest ? value.length >= size : value.length === size;",
501
+ " if (!valid) throw new __velarCollectionListNativeRangeError(name + \" List binding\" + (hasRest ? \" requires at least \" : \" requires exactly \") + size + (size === 1 ? \" item\" : \" items\") + \", received \" + value.length);",
502
+ " return value;",
503
+ "}",
504
+ "function __velarReadBindingListItem(value, index) {",
505
+ " return __velarReactiveCollectionRead(value, index, __velarCollectionListGetOwnPropertyDescriptor(value, index).value) ?? null;",
506
+ "}",
507
+ "function __velarBindingListRest(value, start) {",
508
+ " const output = new __velarCollectionNativeArray(value.length - start);",
509
+ " for (let index = start; index < value.length; index += 1) output[index - start] = __velarReactiveCollectionRead(value, index, __velarCollectionListGetOwnPropertyDescriptor(value, index).value) ?? null;",
510
+ " return output;",
511
+ "}",
512
+ ].join("\n"));
513
+ }
514
+ if (this.needsNumberHelper) {
515
+ helpers.push([
516
+ "function __velarNumber(value) {",
517
+ " if (typeof value !== \"string\") throw new TypeError(\"number(text) requires a string\");",
518
+ " const text = value.trim();",
519
+ " if (!/^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?$/u.test(text)) return null;",
520
+ " const parsed = Number(text);",
521
+ " return Number.isFinite(parsed) ? parsed : null;",
522
+ "}",
523
+ ].join("\n"));
524
+ }
525
+ // D55 rule 121: one memoized accessor per instantiation written outside a
526
+ // generic body. They are `function` declarations so that
527
+ // `type Boxed = Box<string>` above the declaration of `Box` still reads a
528
+ // hoisted name instead of a `const` in its temporal dead zone.
529
+ const instances = [...this.hoistedGenericInstances].map(([expression, name]) => `function ${name}() {\n return ${expression};\n}`);
530
+ const chunks = [
531
+ ...helpers.map((code) => ({ code, mappings: [] })),
532
+ ...instances.map((code) => ({ code, mappings: [] })),
533
+ ...statements.map((node) => this.renderJavaScriptNode(node)),
534
+ ];
535
+ let output = "";
536
+ const mappings = [];
537
+ for (const chunk of chunks) {
538
+ if (output.length > 0)
539
+ output += "\n\n";
540
+ const offset = output.length;
541
+ output += chunk.code;
542
+ mappings.push(...chunk.mappings.map((mapping) => ({ ...mapping, offset: offset + mapping.offset })));
543
+ }
544
+ this.generatedCode = `${output}${output.length > 0 ? "\n" : ""}`;
545
+ this.generatedMappings = mappings.sort((left, right) => left.offset - right.offset);
546
+ return this.generatedCode;
547
+ }
548
+ sourceMap(source) {
549
+ return sourceMapFor(this.generatedCode, this.generatedMappings, source);
550
+ }
551
+ embeddedModules(source) {
552
+ return [...this.embeddedJavaScript.values()].map((module) => ({
553
+ specifier: module.specifier,
554
+ code: module.code,
555
+ sourceMap: sourceMapFor(module.code, module.mappings, source),
556
+ sourceSpan: module.statement.sourceSpan,
557
+ }));
558
+ }
559
+ runtimeModules() {
560
+ return [...this.requiredRuntimeModules].sort();
561
+ }
562
+ emitJavaScriptNode(sourceSpan, render) {
563
+ const node = { id: this.nextJavaScriptNodeId++, code: render(), sourceSpan };
564
+ this.javaScriptNodeSpans.set(node.id, sourceSpan);
565
+ return node;
566
+ }
567
+ markJavaScriptNode(node) {
568
+ return node.code.length === 0 ? "" : `\u0000VELAR_MAP_${node.id}\u0000${node.code}`;
569
+ }
570
+ emitMappedJavaScript(sourceSpan, render) {
571
+ return this.markJavaScriptNode(this.emitJavaScriptNode(sourceSpan, render));
572
+ }
573
+ renderJavaScriptNode(node) {
574
+ let code = "";
575
+ let cursor = 0;
576
+ const mappings = [{ offset: 0, sourceSpan: node.sourceSpan }];
577
+ for (const marker of node.code.matchAll(javaScriptNodeMarker)) {
578
+ const markerIndex = marker.index;
579
+ code += node.code.slice(cursor, markerIndex);
580
+ const sourceSpan = this.javaScriptNodeSpans.get(Number(marker[1]));
581
+ if (!sourceSpan)
582
+ throw new Error("A generated JavaScript mapping marker has no source node");
583
+ mappings.push({ offset: code.length, sourceSpan });
584
+ cursor = markerIndex + marker[0].length;
585
+ }
586
+ code += node.code.slice(cursor);
587
+ return { code, mappings };
588
+ }
589
+ additionalHelpers(_program) {
590
+ return [];
591
+ }
592
+ reactiveBridgeHelpers(needsJavaScriptCallBoundary, needsCollections) {
593
+ if (!needsJavaScriptCallBoundary && !needsCollections)
594
+ return [];
595
+ if (this.sharedRuntimeModules) {
596
+ this.requiredRuntimeModules.add(VELAR_REACTIVE_BRIDGE_MODULE);
597
+ const imports = [
598
+ "reactiveRaw as __velarReactiveRaw",
599
+ "hostRaw as __velarHostRaw",
600
+ ...(needsCollections ? [
601
+ "reactiveIterateKey as __velarReactiveIterateKey",
602
+ "reactiveStructureKey as __velarReactiveStructureKey",
603
+ "reactiveCollectionRead as __velarReactiveCollectionRead",
604
+ "reactiveCollectionTrack as __velarReactiveCollectionTrack",
605
+ "reactiveCollectionLink as __velarReactiveCollectionLink",
606
+ "reactiveCollectionTrigger as __velarReactiveCollectionTrigger",
607
+ "reactiveCollectionUnlink as __velarReactiveCollectionUnlink",
608
+ ] : []),
609
+ ];
610
+ return [`import { ${imports.join(", ")} } from ${JSON.stringify(VELAR_REACTIVE_BRIDGE_MODULE)};`];
611
+ }
612
+ return [VELAR_REACTIVE_BRIDGE_RUNTIME, ...(needsCollections ? [VELAR_REACTIVE_COLLECTION_BRIDGE_RUNTIME] : [])];
613
+ }
614
+ usesSharedRuntimeModules() {
615
+ return this.sharedRuntimeModules;
616
+ }
617
+ // The compiler-owned observer behind the 'async <expression>' statement
618
+ // (docs/contributing/runtime-boundary.md, B-DETACHED-ASYNC). The Promise and Reflect
619
+ // operations and the console channel are captured at module initialization;
620
+ // rejection is normalized to Error and reported on the host error channel
621
+ // without ending the process. Hosts with their own error chain override
622
+ // this (the Web emitter routes the report through the velar/app chain).
623
+ //
624
+ // The reporter itself must never fail outward: a rejection value carries a
625
+ // foreign error object whose 'stack' or 'message' may be a throwing getter,
626
+ // and a throw inside a rejection handler becomes an unhandled rejection that
627
+ // ends the Node process — the exact program termination this boundary
628
+ // forbids. Every foreign read is therefore guarded, and the Promise derived
629
+ // from adopting the task is observed rather than discarded.
630
+ detachedTaskHelpers() {
631
+ return [[
632
+ "const __velarDetachedPromiseThen = globalThis.Promise.prototype.then;",
633
+ "const __velarDetachedApply = Reflect.apply;",
634
+ "const __velarDetachedConsole = globalThis.console;",
635
+ "const __velarDetachedConsoleError = __velarDetachedConsole ? __velarDetachedConsole.error : null;",
636
+ "function __velarDetachedTrace(error) {",
637
+ " try { const trace = error.stack; if (typeof trace === \"string\" && trace !== \"\") return trace; } catch {}",
638
+ " try { const message = error.message; if (typeof message === \"string\" && message !== \"\") return message; } catch {}",
639
+ " return \"A detached task failed\";",
640
+ "}",
641
+ "function __velarDetachedReport(failure) {",
642
+ " try {",
643
+ " if (typeof __velarDetachedConsoleError !== \"function\") return null;",
644
+ " let error = null;",
645
+ " try { error = __velarNormalizeError(failure); } catch {}",
646
+ " const trace = error === null ? \"A detached task failed\" : __velarDetachedTrace(error);",
647
+ " __velarDetachedApply(__velarDetachedConsoleError, __velarDetachedConsole, [\"Detached async task failed: \" + trace]);",
648
+ " } catch {}",
649
+ " return null;",
650
+ "}",
651
+ "function __velarDetachedTask(task) {",
652
+ " try {",
653
+ " const observed = __velarDetachedApply(__velarDetachedPromiseThen, task, [null, __velarDetachedReport]);",
654
+ " __velarDetachedApply(__velarDetachedPromiseThen, observed, [null, __velarDetachedReport]);",
655
+ " } catch (failure) {",
656
+ " __velarDetachedReport(failure);",
657
+ " }",
658
+ " return null;",
659
+ "}",
660
+ ].join("\n")];
661
+ }
662
+ /**
663
+ * D43 item 69 rule 8: a release that fails while an error is already in
664
+ * flight must not replace it. The original error keeps the throw; the release
665
+ * failure is normalized and reported through the host channel. The reporter
666
+ * itself never fails outward, for the same reason the detached-task reporter
667
+ * does not — a throw inside it would end the process.
668
+ */
669
+ disposalHelpers() {
670
+ return [[
671
+ "const __velarDisposalApply = Reflect.apply;",
672
+ "const __velarDisposalConsole = globalThis.console;",
673
+ "const __velarDisposalConsoleError = __velarDisposalConsole ? __velarDisposalConsole.error : null;",
674
+ "function __velarDisposalTrace(error) {",
675
+ " try { const trace = error.stack; if (typeof trace === \"string\" && trace !== \"\") return trace; } catch {}",
676
+ " try { const message = error.message; if (typeof message === \"string\" && message !== \"\") return message; } catch {}",
677
+ " return \"A resource release failed\";",
678
+ "}",
679
+ "function __velarDisposalReport(failure) {",
680
+ " try {",
681
+ " if (typeof __velarDisposalConsoleError !== \"function\") return null;",
682
+ " let error = null;",
683
+ " try { error = __velarNormalizeError(failure); } catch {}",
684
+ " const trace = error === null ? \"A resource release failed\" : __velarDisposalTrace(error);",
685
+ " __velarDisposalApply(__velarDisposalConsoleError, __velarDisposalConsole, [\"Resource release failed while another error was in flight: \" + trace]);",
686
+ " } catch {}",
687
+ " return null;",
688
+ "}",
689
+ ].join("\n")];
690
+ }
691
+ /**
692
+ * D51 rule 103: the three failures that mean "this program has a bug", by the
693
+ * one name each of them stamps on itself. A forged name can only make a
694
+ * failure propagate instead of becoming `null`, which is the safe direction:
695
+ * `try` never hides a guard, and `catch` still receives everything.
696
+ */
697
+ integrityFailureHelpers() {
698
+ return [[
699
+ "const __velarIntegrityDescriptor = Object.getOwnPropertyDescriptor;",
700
+ "function __velarIsIntegrityFailure(value) {",
701
+ " if (value === null || (typeof value !== \"object\" && typeof value !== \"function\")) return false;",
702
+ " const descriptor = __velarIntegrityDescriptor(value, \"name\");",
703
+ " if (!descriptor || !(\"value\" in descriptor)) return false;",
704
+ " const name = descriptor.value;",
705
+ " return name === \"AssertionError\" || name === \"NarrowingError\" || name === \"IndexError\";",
706
+ "}",
707
+ ].join("\n")];
708
+ }
709
+ requireRuntimeModule(source) {
710
+ this.requiredRuntimeModules.add(source);
711
+ }
712
+ includesErrorNormalizationRuntime() {
713
+ return false;
714
+ }
715
+ visitExtensionRuntimeExpression(_expression, _visitExpression) {
716
+ return false;
717
+ }
718
+ visitExtensionRuntimeStatement(_statement, _visitExpression, _visitStatement) {
719
+ return false;
720
+ }
721
+ extensionExpressionContainsDirectAwait(_expression, _contains) {
722
+ return undefined;
723
+ }
724
+ extensionStatementContainsDirectAwait(_statement, _containsExpression, _containsBlock) {
725
+ return undefined;
726
+ }
727
+ collectDeclarations(program) {
728
+ for (const statement of program.body) {
729
+ if (statement.kind === "TypeDeclaration" || statement.kind === "TypeAliasDeclaration") {
730
+ this.typeDeclarations.set(statement.name, statement);
731
+ if (statement.exported) {
732
+ this.runtimeTypes.add(statement.name);
733
+ }
734
+ }
735
+ else if (statement.kind === "ExternModuleDeclaration") {
736
+ const names = new Set(this.externModuleExports.get(statement.source));
737
+ for (const declaration of statement.functions)
738
+ names.add(declaration.name);
739
+ for (const declaration of statement.constants)
740
+ names.add(declaration.name);
741
+ for (const declaration of statement.classes)
742
+ names.add(declaration.name);
743
+ this.externModuleExports.set(statement.source, names);
744
+ }
745
+ }
746
+ for (const name of [...this.runtimeTypes]) {
747
+ this.markRuntimeType({ kind: "named", name });
748
+ }
749
+ }
750
+ collectRuntimeUses(program) {
751
+ for (const guard of this.hints.runtimeNarrowings.values())
752
+ this.markRuntimeNarrowingType(guard.expected);
753
+ const visitExpression = (expression) => {
754
+ if (this.visitExtensionRuntimeExpression(expression, visitExpression))
755
+ return;
756
+ switch (expression.kind) {
757
+ case "FStringExpression":
758
+ for (const part of expression.parts) {
759
+ if (part.kind === "expression")
760
+ visitExpression(part.value);
761
+ }
762
+ break;
763
+ case "ListExpression":
764
+ expression.elements.forEach(visitExpression);
765
+ break;
766
+ case "ObjectExpression":
767
+ expression.properties.forEach((property) => visitExpression(property.value));
768
+ break;
769
+ case "SpreadExpression":
770
+ visitExpression(expression.value);
771
+ break;
772
+ case "UnaryExpression":
773
+ visitExpression(expression.operand);
774
+ break;
775
+ case "TryExpression":
776
+ visitExpression(expression.value);
777
+ break;
778
+ case "BinaryExpression":
779
+ visitExpression(expression.left);
780
+ visitExpression(expression.right);
781
+ break;
782
+ case "ComparisonChainExpression":
783
+ expression.operands.forEach(visitExpression);
784
+ break;
785
+ case "ConditionalExpression":
786
+ visitExpression(expression.condition);
787
+ visitExpression(expression.thenValue);
788
+ visitExpression(expression.elseValue);
789
+ break;
790
+ case "IsExpression":
791
+ this.markRuntimeType(resolveTypeReference(expression.type));
792
+ visitExpression(expression.value);
793
+ break;
794
+ case "ArrowFunctionExpression":
795
+ visitExpression(expression.body);
796
+ break;
797
+ case "CallExpression":
798
+ if (expression.callee.kind === "MemberExpression"
799
+ && expression.callee.object.kind === "IdentifierExpression"
800
+ && expression.callee.property === "parse"
801
+ && this.typeDeclarations.has(expression.callee.object.name)) {
802
+ this.markRuntimeType({ kind: "named", name: expression.callee.object.name });
803
+ }
804
+ if (expression.callee.kind === "MemberExpression"
805
+ && this.collectionHelper(expression.callee)) {
806
+ this.needsCollectionHelpers = true;
807
+ }
808
+ if (expression.callee.kind === "MemberExpression"
809
+ && this.binaryHelper(expression.callee)) {
810
+ this.needsBinaryHelpers = true;
811
+ }
812
+ visitExpression(expression.callee);
813
+ expression.arguments.forEach(visitExpression);
814
+ break;
815
+ case "MemberExpression":
816
+ if (this.binaryHelper(expression) || this.hints.binarySizes.has(expression.span.end)) {
817
+ this.needsBinaryHelpers = true;
818
+ }
819
+ visitExpression(expression.object);
820
+ break;
821
+ case "IndexExpression":
822
+ if (this.hints.binaryIndexes.has(spanIdentity(expression.span)))
823
+ this.needsBinaryHelpers = true;
824
+ else
825
+ this.needsIndexHelpers = true;
826
+ visitExpression(expression.object);
827
+ visitExpression(expression.index);
828
+ break;
829
+ case "LiteralExpression":
830
+ break;
831
+ case "IdentifierExpression":
832
+ if (this.typeDeclarations.has(expression.name)) {
833
+ this.markRuntimeType({ kind: "named", name: expression.name });
834
+ }
835
+ break;
836
+ case "SuperExpression":
837
+ case "DynamicImportExpression":
838
+ break;
839
+ }
840
+ };
841
+ const visitStatement = (statement) => {
842
+ if (this.visitExtensionRuntimeStatement(statement, visitExpression, visitStatement))
843
+ return;
844
+ switch (statement.kind) {
845
+ case "VariableDeclaration":
846
+ visitExpression(statement.initializer);
847
+ break;
848
+ case "TestDeclaration":
849
+ statement.body.forEach(visitStatement);
850
+ break;
851
+ case "UsingDeclaration":
852
+ // Releasing a resource reports its own failure through the host
853
+ // channel, which carries the error-normalization runtime with it.
854
+ this.needsDisposalHelper = true;
855
+ this.needsThrownValueHelper = true;
856
+ visitExpression(statement.initializer);
857
+ break;
858
+ case "FunctionDeclaration":
859
+ statement.parameters.forEach((parameter) => { if (parameter.defaultValue)
860
+ visitExpression(parameter.defaultValue); });
861
+ statement.body.forEach(visitStatement);
862
+ break;
863
+ case "ClassDeclaration":
864
+ statement.parameters.forEach((parameter) => { if (parameter.defaultValue)
865
+ visitExpression(parameter.defaultValue); });
866
+ statement.base?.arguments.forEach(visitExpression);
867
+ statement.fields.forEach((field) => { if (field.initializer)
868
+ visitExpression(field.initializer); });
869
+ statement.initialization?.body.forEach(visitStatement);
870
+ statement.getters.forEach(visitStatement);
871
+ statement.methods.forEach(visitStatement);
872
+ statement.dispose?.body.forEach(visitStatement);
873
+ statement.iterate?.body.forEach(visitStatement);
874
+ break;
875
+ case "ReturnStatement":
876
+ if (statement.value)
877
+ visitExpression(statement.value);
878
+ break;
879
+ case "ThrowStatement":
880
+ visitExpression(statement.value);
881
+ break;
882
+ case "AssertStatement":
883
+ visitExpression(statement.condition);
884
+ if (statement.message)
885
+ visitExpression(statement.message);
886
+ break;
887
+ case "IfStatement":
888
+ visitExpression(statement.condition);
889
+ statement.thenBody.forEach(visitStatement);
890
+ statement.elseBody?.forEach(visitStatement);
891
+ break;
892
+ case "MatchStatement":
893
+ visitExpression(statement.value);
894
+ statement.cases.forEach((branch) => {
895
+ visitMatchPattern(branch.pattern);
896
+ if (branch.guard)
897
+ visitExpression(branch.guard);
898
+ branch.body.forEach(visitStatement);
899
+ });
900
+ break;
901
+ case "ForStatement":
902
+ visitExpression(statement.iterable);
903
+ statement.body.forEach(visitStatement);
904
+ break;
905
+ case "WhileStatement":
906
+ visitExpression(statement.condition);
907
+ statement.body.forEach(visitStatement);
908
+ break;
909
+ case "TryStatement":
910
+ statement.tryBody.forEach(visitStatement);
911
+ statement.catchBody?.forEach(visitStatement);
912
+ statement.finallyBody?.forEach(visitStatement);
913
+ break;
914
+ case "AssignmentStatement":
915
+ visitExpression(statement.target);
916
+ visitExpression(statement.value);
917
+ break;
918
+ case "ExpressionStatement":
919
+ visitExpression(statement.expression);
920
+ break;
921
+ case "AsyncStatement":
922
+ // The detached-task observer normalizes rejection values, so the
923
+ // error-normalization runtime travels with it.
924
+ this.needsDetachedTaskHelper = true;
925
+ this.needsThrownValueHelper = true;
926
+ visitExpression(statement.expression);
927
+ break;
928
+ case "EmbeddedJavaScriptDeclaration":
929
+ statement.captures.forEach((capture) => visitExpression({
930
+ kind: "IdentifierExpression",
931
+ name: capture.name,
932
+ span: capture.nameSpan,
933
+ }));
934
+ break;
935
+ case "ImportDeclaration":
936
+ case "ReExportDeclaration":
937
+ case "ExternModuleDeclaration":
938
+ case "TypeDeclaration":
939
+ case "TypeAliasDeclaration":
940
+ case "EnumDeclaration":
941
+ case "BreakStatement":
942
+ case "ContinueStatement":
943
+ case "PassStatement":
944
+ break;
945
+ }
946
+ };
947
+ const visitMatchPattern = (pattern) => {
948
+ switch (pattern.kind) {
949
+ case "MatchValuePattern":
950
+ pattern.values.forEach(visitExpression);
951
+ break;
952
+ case "MatchTypePattern":
953
+ this.markRuntimeType(resolveTypeReference(pattern.type));
954
+ break;
955
+ case "MatchAsPattern":
956
+ visitMatchPattern(pattern.pattern);
957
+ break;
958
+ case "MatchObjectPattern":
959
+ pattern.entries.forEach((entry) => visitMatchPattern(entry.pattern));
960
+ break;
961
+ case "MatchListPattern":
962
+ pattern.elements.forEach(visitMatchPattern);
963
+ break;
964
+ case "MatchWildcardPattern":
965
+ case "MatchCapturePattern":
966
+ break;
967
+ }
968
+ };
969
+ program.body.forEach(visitStatement);
970
+ }
971
+ markRuntimeType(type) {
972
+ this.needsRuntimeTypeHelpers = true;
973
+ const visit = (value) => {
974
+ // D55 rule 121: `Box<string>` needs `Box`'s factory emitted and every
975
+ // argument's own runtime types marked; the application's display name is
976
+ // not a declaration, so the walk asks the application which one it is.
977
+ if (value.kind === "named" && value.application) {
978
+ for (const argument of value.application.arguments)
979
+ visit(argument);
980
+ visit({ kind: "named", name: value.application.name });
981
+ return;
982
+ }
983
+ if (value.kind === "named" && this.typeDeclarations.has(value.name) && !this.runtimeTypes.has(value.name)) {
984
+ this.runtimeTypes.add(value.name);
985
+ }
986
+ if (value.kind === "named" && this.typeDeclarations.has(value.name) && !this.expandedRuntimeTypes.has(value.name)) {
987
+ this.expandedRuntimeTypes.add(value.name);
988
+ const declaration = this.typeDeclarations.get(value.name);
989
+ if (declaration.kind === "TypeDeclaration") {
990
+ declaration.fields.forEach((field) => visit(resolveTypeReference(field.type)));
991
+ }
992
+ else {
993
+ visit(resolveTypeReference(declaration.target));
994
+ }
995
+ }
996
+ else if (value.kind === "optional") {
997
+ visit(value.inner);
998
+ }
999
+ else if (value.kind === "list") {
1000
+ visit(value.element);
1001
+ }
1002
+ else if (value.kind === "set") {
1003
+ visit(value.element);
1004
+ }
1005
+ else if (value.kind === "map") {
1006
+ visit(value.key);
1007
+ visit(value.value);
1008
+ }
1009
+ else if (value.kind === "record") {
1010
+ visit(value.value);
1011
+ }
1012
+ else if (value.kind === "promise") {
1013
+ visit(value.value);
1014
+ }
1015
+ else if (value.kind === "union") {
1016
+ value.members.forEach(visit);
1017
+ }
1018
+ };
1019
+ visit(type);
1020
+ }
1021
+ markRuntimeNarrowingType(type) {
1022
+ if (type.kind === "optional") {
1023
+ this.markRuntimeNarrowingType(type.inner);
1024
+ return;
1025
+ }
1026
+ if (type.kind === "union") {
1027
+ for (const member of type.members)
1028
+ this.markRuntimeNarrowingType(member);
1029
+ return;
1030
+ }
1031
+ if (type.kind === "list" || type.kind === "set" || type.kind === "map" || type.kind === "record"
1032
+ || type.kind === "promise" || type.kind === "named" || type.kind === "class") {
1033
+ this.markRuntimeType(type);
1034
+ }
1035
+ }
1036
+ emitMappedStatement(statement, depth) {
1037
+ return this.emitMappedJavaScript(statement.span, () => this.emitStatement(statement, depth));
1038
+ }
1039
+ /**
1040
+ * D43 item 69: a `using` binding owns the rest of its block, so a statement
1041
+ * list is emitted as a whole. Everything after the binding moves inside the
1042
+ * release frame; a second `using` nests inside the first, which is what makes
1043
+ * release order the reverse of declaration order.
1044
+ */
1045
+ emitStatementLines(statements, depth) {
1046
+ const owned = statements.findIndex((statement) => statement.kind === "UsingDeclaration");
1047
+ const plain = (values) => values.map((child) => this.emitMappedStatement(child, depth)).filter(Boolean);
1048
+ if (owned < 0)
1049
+ return plain(statements);
1050
+ return [
1051
+ ...plain(statements.slice(0, owned)),
1052
+ ...this.emitUsingScope(statements[owned], statements.slice(owned + 1), depth),
1053
+ ];
1054
+ }
1055
+ emitUsingScope(statement, rest, depth) {
1056
+ const indentation = " ".repeat(depth);
1057
+ const contract = this.hints.usingDisposals.get(spanIdentity(statement.span));
1058
+ const initializer = this.emitMappedJavaScript(statement.span, () => `const ${statement.name} = ${this.emitMappedExpression(statement.initializer)};`);
1059
+ // A value with no resolved contract was already diagnosed; emitting the
1060
+ // binding alone keeps the rest of the block readable in a failed compile.
1061
+ if (!contract)
1062
+ return [`${indentation}${initializer}`, ...this.emitStatementLines(rest, depth)];
1063
+ const body = this.emitStatementLines(rest, depth + 1);
1064
+ this.needsDisposalHelper = true;
1065
+ const suffix = statement.span.start;
1066
+ const member = contract.owner === "class" ? `[${JSON.stringify(contract.member)}]` : `.${contract.member}`;
1067
+ const call = `${contract.asynchronous ? "await " : ""}${statement.name}${member}()`;
1068
+ const released = `__velarReleased${suffix}`;
1069
+ const failure = `__velarUsingFailure${suffix}`;
1070
+ return [
1071
+ `${indentation}${initializer}`,
1072
+ `${indentation}let ${released} = false;`,
1073
+ `${indentation}try {`,
1074
+ ...body,
1075
+ // An error already in flight owns the failure: the release still runs,
1076
+ // but its own failure is reported to the host instead of replacing the
1077
+ // error the author is about to see (D43 item 69 rule 8).
1078
+ `${indentation}} catch (${failure}) {`,
1079
+ `${indentation} ${released} = true;`,
1080
+ `${indentation} try { ${call}; } catch (__velarDisposeFailure${suffix}) { __velarDisposalReport(__velarDisposeFailure${suffix}); }`,
1081
+ `${indentation} throw ${failure};`,
1082
+ `${indentation}} finally {`,
1083
+ // Normal completion, `return`, `break`, and `continue` all arrive here,
1084
+ // and a release failure on those paths throws normally.
1085
+ `${indentation} if (!${released}) ${call};`,
1086
+ `${indentation}}`,
1087
+ ];
1088
+ }
1089
+ emitStatement(statement, depth) {
1090
+ const indentation = " ".repeat(depth);
1091
+ switch (statement.kind) {
1092
+ case "ImportDeclaration":
1093
+ return this.emitImport(statement, indentation);
1094
+ case "ReExportDeclaration": {
1095
+ const emittedSource = statement.source.endsWith(".vel") ? `${statement.source.slice(0, -4)}.js` : statement.source;
1096
+ const names = statement.specifiers
1097
+ .map((specifier) => specifier.imported === specifier.exported ? specifier.imported : `${specifier.imported} as ${specifier.exported}`)
1098
+ .join(", ");
1099
+ return `${indentation}export {${names.length > 0 ? ` ${names} ` : ""}} from ${JSON.stringify(emittedSource)};`;
1100
+ }
1101
+ case "ExternModuleDeclaration":
1102
+ return "";
1103
+ case "EmbeddedJavaScriptDeclaration":
1104
+ return this.emitEmbeddedJavaScript(statement, indentation);
1105
+ case "TypeDeclaration":
1106
+ return this.runtimeTypes.has(statement.name) ? this.emitTypeDeclaration(statement, depth) : "";
1107
+ case "TypeAliasDeclaration":
1108
+ return this.runtimeTypes.has(statement.name) ? this.emitTypeAliasDeclaration(statement, depth) : "";
1109
+ case "EnumDeclaration":
1110
+ return this.emitEnumDeclaration(statement, depth);
1111
+ case "ClassDeclaration":
1112
+ return this.emitClass(statement, depth);
1113
+ case "VariableDeclaration": {
1114
+ const initializer = this.emitMappedExpression(statement.initializer);
1115
+ if (statement.pattern.kind === "NameBindingPattern") {
1116
+ return `${indentation}${statement.exported ? "export " : ""}${statement.binding} ${statement.pattern.name} = ${initializer};`;
1117
+ }
1118
+ const valueName = `__velarBindingValue${statement.pattern.span.start}`;
1119
+ return [
1120
+ `${indentation}const ${valueName} = ${initializer};`,
1121
+ ...this.emitBindingPatternStatements(statement.pattern, valueName, statement.binding, statement.exported, depth, "Variable"),
1122
+ ].join("\n");
1123
+ }
1124
+ // D39 item 53: a test is an exported async function the runner calls by
1125
+ // its generated name; the author's name travels in the module interface
1126
+ // so the reporter can quote it verbatim.
1127
+ case "TestDeclaration": {
1128
+ const lines = [
1129
+ ...this.emitStatementLines(statement.body, depth + 1),
1130
+ `${" ".repeat(depth + 1)}return null;`,
1131
+ ];
1132
+ return `${indentation}export async function ${testFunctionName(statement)}() {\n${lines.join("\n")}\n${indentation}}`;
1133
+ }
1134
+ case "FunctionDeclaration": {
1135
+ const prefix = `${statement.exported || this.forcedFunctionExports.has(statement.name) ? "export " : ""}${statement.asynchronous ? "async " : ""}function`;
1136
+ const parameters = statement.parameters.map((parameter) => this.emitParameter(parameter.name, parameter.defaultValue, parameter.rest)).join(", ");
1137
+ const lines = [...this.emitStatementLines(statement.body, depth + 1)];
1138
+ if (!this.blockAlwaysReturns(statement.body))
1139
+ lines.push(`${" ".repeat(depth + 1)}return null;`);
1140
+ const body = lines.join("\n");
1141
+ return `${indentation}${prefix} ${statement.name}(${parameters}) {${body.length > 0 ? `\n${body}\n${indentation}` : ""}}`;
1142
+ }
1143
+ case "ReturnStatement": {
1144
+ if (!statement.value)
1145
+ return `${indentation}return null;`;
1146
+ const value = this.emitMappedExpression(statement.value);
1147
+ return `${indentation}return ${this.hints.asyncResolvedValues.has(spanIdentity(statement.value.span)) ? `__velarAsyncResolvedValue(${value})` : value};`;
1148
+ }
1149
+ case "ThrowStatement":
1150
+ return `${indentation}throw ${this.emitMappedExpression(statement.value)};`;
1151
+ case "AssertStatement": {
1152
+ const message = statement.message ? this.emitMappedExpression(statement.message) : JSON.stringify("Assertion failed");
1153
+ return [
1154
+ `${indentation}if (!(${this.emitCondition(statement.condition)})) {`,
1155
+ `${indentation} const __velarAssertionError = new Error(${message});`,
1156
+ `${indentation} __velarAssertionError.name = "AssertionError";`,
1157
+ `${indentation} throw __velarAssertionError;`,
1158
+ `${indentation}}`,
1159
+ ].join("\n");
1160
+ }
1161
+ case "IfStatement": {
1162
+ const thenBody = this.emitStatementLines(statement.thenBody, depth + 1).join("\n");
1163
+ let output = `${indentation}if (${this.emitCondition(statement.condition)}) {${thenBody.length > 0 ? `\n${thenBody}\n${indentation}` : ""}}`;
1164
+ if (statement.elseBody) {
1165
+ const chained = statement.elseBody.length === 1 && statement.elseBody[0]?.kind === "IfStatement"
1166
+ ? this.emitMappedStatement(statement.elseBody[0], 0)
1167
+ : null;
1168
+ if (chained) {
1169
+ output += ` else ${chained}`;
1170
+ }
1171
+ else {
1172
+ const elseBody = this.emitStatementLines(statement.elseBody, depth + 1).join("\n");
1173
+ output += ` else {${elseBody.length > 0 ? `\n${elseBody}\n${indentation}` : ""}}`;
1174
+ }
1175
+ }
1176
+ return output;
1177
+ }
1178
+ case "MatchStatement": {
1179
+ const suffix = statement.span.start;
1180
+ const valueName = `__velarMatchValue${suffix}`;
1181
+ const matchedName = `__velarMatchDone${suffix}`;
1182
+ const lines = [
1183
+ `${indentation}{`,
1184
+ `${indentation} const ${valueName} = ${this.emitMappedExpression(statement.value)};`,
1185
+ `${indentation} let ${matchedName} = false;`,
1186
+ ];
1187
+ for (const branch of statement.cases) {
1188
+ const attemptName = `__velarMatchCase${branch.pattern.span.start}`;
1189
+ const attempt = this.emitMatchPatternAttempt(branch.pattern, valueName, `${indentation} `);
1190
+ lines.push(`${indentation} let ${attemptName} = null;`);
1191
+ lines.push(`${indentation} if (!${matchedName} && (${attemptName} = (() => {`);
1192
+ lines.push(...attempt.lines);
1193
+ lines.push(`${indentation} return [${attempt.bindings.map((binding) => binding.value).join(", ")}];`);
1194
+ lines.push(`${indentation} })()) !== null) {`);
1195
+ attempt.bindings.forEach((binding, index) => {
1196
+ lines.push(`${indentation} const ${binding.name} = ${attemptName}[${index}];`);
1197
+ });
1198
+ if (branch.guard) {
1199
+ lines.push(`${indentation} if (${this.emitCondition(branch.guard)}) {`);
1200
+ lines.push(`${indentation} ${matchedName} = true;`);
1201
+ lines.push(...this.emitStatementLines(branch.body, depth + 3));
1202
+ lines.push(`${indentation} }`);
1203
+ }
1204
+ else {
1205
+ lines.push(`${indentation} ${matchedName} = true;`);
1206
+ lines.push(...this.emitStatementLines(branch.body, depth + 2));
1207
+ }
1208
+ lines.push(`${indentation} }`);
1209
+ }
1210
+ lines.push(`${indentation}}`);
1211
+ return lines.join("\n");
1212
+ }
1213
+ case "ForStatement": {
1214
+ if (statement.asynchronous) {
1215
+ const suffix = statement.span.start;
1216
+ const sourceName = `__velarAsyncForSource${suffix}`;
1217
+ const nextName = `__velarAsyncForNext${suffix}`;
1218
+ const valueName = `__velarAsyncForValue${suffix}`;
1219
+ const indexName = `__velarAsyncForIndex${suffix}`;
1220
+ const bodyDepth = depth + 2;
1221
+ const lines = [
1222
+ `${indentation}{`,
1223
+ `${" ".repeat(depth + 1)}const ${sourceName} = ${this.emitMappedExpression(statement.iterable)};`,
1224
+ `${" ".repeat(depth + 1)}const ${nextName} = __velarAsyncPullNext(${sourceName});`,
1225
+ `${" ".repeat(depth + 1)}let ${indexName} = 0;`,
1226
+ `${" ".repeat(depth + 1)}while (true) {`,
1227
+ `${" ".repeat(bodyDepth)}const ${valueName} = await __velarNormalizePromiseValue(__velarAsyncPullCall(${sourceName}, ${nextName}));`,
1228
+ `${" ".repeat(bodyDepth)}if (${valueName} === null) break;`,
1229
+ ...this.emitBindingPatternStatements(statement.pattern, valueName, "const", false, bodyDepth, "Async for"),
1230
+ ...(statement.secondPattern
1231
+ ? this.emitBindingPatternStatements(statement.secondPattern, indexName, "const", false, bodyDepth, "Async for second slot")
1232
+ : []),
1233
+ `${" ".repeat(bodyDepth)}${indexName} += 1;`,
1234
+ ...this.emitStatementLines(statement.body, bodyDepth),
1235
+ `${" ".repeat(depth + 1)}}`,
1236
+ `${indentation}}`,
1237
+ ];
1238
+ return lines.join("\n");
1239
+ }
1240
+ if (this.hints.nativeRangeForStatements.has(statement.span.start)
1241
+ && statement.iterable.kind === "CallExpression"
1242
+ && statement.pattern.kind === "NameBindingPattern") {
1243
+ const call = statement.iterable;
1244
+ const sourceArguments = call.arguments.map((argument) => this.emitMappedExpression(argument));
1245
+ const namedOrder = this.hints.namedArgumentOrders.get(spanIdentity(call.span));
1246
+ const arguments_ = namedOrder
1247
+ ? namedOrder.map((source) => source === -1 ? "undefined" : `__velarNamedArguments[${source}]`)
1248
+ : sourceArguments;
1249
+ const emittedArguments = namedOrder
1250
+ ? `...((__velarNamedArguments) => [${arguments_.join(", ")}])([${sourceArguments.join(", ")}])`
1251
+ : arguments_.join(", ");
1252
+ const suffix = statement.span.start;
1253
+ const boundsName = `__velarRangeBounds${suffix}`;
1254
+ const counterName = `__velarRangeCounter${suffix}`;
1255
+ const endName = `__velarRangeEnd${suffix}`;
1256
+ const stepName = `__velarRangeStep${suffix}`;
1257
+ const valueName = statement.pattern.name;
1258
+ const body = this.emitStatementLines(statement.body, depth + 2).join("\n");
1259
+ return [
1260
+ `${indentation}{`,
1261
+ `${indentation} const ${boundsName} = __velarCountedRangeOwner.__velarCounted(${emittedArguments});`,
1262
+ `${indentation} let ${counterName} = ${boundsName}[0];`,
1263
+ `${indentation} const ${endName} = ${boundsName}[1];`,
1264
+ `${indentation} const ${stepName} = ${boundsName}[2];`,
1265
+ `${indentation} for (; ${stepName} > 0 ? ${counterName} < ${endName} : ${counterName} > ${endName}; ${counterName} += ${stepName}) {`,
1266
+ `${indentation} const ${valueName} = ${counterName};${body.length > 0 ? `\n${body}` : ""}`,
1267
+ `${indentation} }`,
1268
+ `${indentation}}`,
1269
+ ].join("\n");
1270
+ }
1271
+ this.needsCollectionHelpers = true;
1272
+ const iterable = this.emitMappedExpression(statement.iterable);
1273
+ if (!statement.secondPattern && statement.pattern.kind === "NameBindingPattern") {
1274
+ const body = this.emitStatementLines(statement.body, depth + 1).join("\n");
1275
+ return `${indentation}for (const ${statement.pattern.name} of __velarCollectionIterator(${iterable})) {${body.length > 0 ? `\n${body}\n${indentation}` : ""}}`;
1276
+ }
1277
+ if (statement.secondPattern) {
1278
+ const pairName = `__velarForPair${statement.pattern.span.start}`;
1279
+ const lines = [
1280
+ ...this.emitBindingPatternStatements(statement.pattern, `${pairName}[0]`, "const", false, depth + 1, "For first slot"),
1281
+ ...this.emitBindingPatternStatements(statement.secondPattern, `${pairName}[1]`, "const", false, depth + 1, "For second slot"),
1282
+ ...this.emitStatementLines(statement.body, depth + 1),
1283
+ ];
1284
+ return `${indentation}for (const ${pairName} of __velarCollectionPairIterator(${iterable})) {${lines.length > 0 ? `\n${lines.join("\n")}\n${indentation}` : ""}}`;
1285
+ }
1286
+ const valueName = `__velarForValue${statement.pattern.span.start}`;
1287
+ const lines = [
1288
+ ...this.emitBindingPatternStatements(statement.pattern, valueName, "const", false, depth + 1, "For"),
1289
+ ...this.emitStatementLines(statement.body, depth + 1),
1290
+ ];
1291
+ return `${indentation}for (const ${valueName} of __velarCollectionIterator(${iterable})) {${lines.length > 0 ? `\n${lines.join("\n")}\n${indentation}` : ""}}`;
1292
+ }
1293
+ case "WhileStatement": {
1294
+ const body = this.emitStatementLines(statement.body, depth + 1).join("\n");
1295
+ return `${indentation}while (${this.emitCondition(statement.condition)}) {${body.length > 0 ? `\n${body}\n${indentation}` : ""}}`;
1296
+ }
1297
+ case "BreakStatement":
1298
+ return `${indentation}break;`;
1299
+ case "ContinueStatement":
1300
+ return `${indentation}continue;`;
1301
+ case "PassStatement":
1302
+ return "";
1303
+ case "TryStatement": {
1304
+ const tryBody = this.emitStatementLines(statement.tryBody, depth + 1).join("\n");
1305
+ let output = `${indentation}try {${tryBody.length > 0 ? `\n${tryBody}\n${indentation}` : ""}}`;
1306
+ if (statement.catchBody) {
1307
+ this.needsThrownValueHelper = true;
1308
+ const catchBody = this.emitStatementLines(statement.catchBody, depth + 1).join("\n");
1309
+ const catchName = statement.catchName ?? "error";
1310
+ const normalization = `${" ".repeat(depth + 1)}${catchName} = __velarNormalizeError(${catchName});`;
1311
+ output += ` catch (${catchName}) {\n${normalization}${catchBody.length > 0 ? `\n${catchBody}` : ""}\n${indentation}}`;
1312
+ }
1313
+ if (statement.finallyBody) {
1314
+ const finallyBody = this.emitStatementLines(statement.finallyBody, depth + 1).join("\n");
1315
+ output += ` finally {${finallyBody.length > 0 ? `\n${finallyBody}\n${indentation}` : ""}}`;
1316
+ }
1317
+ return output;
1318
+ }
1319
+ case "AssignmentStatement":
1320
+ if (statement.target.kind === "IndexExpression") {
1321
+ const binaryKind = this.hints.binaryIndexes.get(spanIdentity(statement.target.span));
1322
+ if (binaryKind)
1323
+ this.needsBinaryHelpers = true;
1324
+ else {
1325
+ this.needsIndexHelpers = true;
1326
+ this.needsCollectionHelpers = true;
1327
+ }
1328
+ const object = this.emitMappedExpression(statement.target.object);
1329
+ const index = this.emitMappedExpression(statement.target.index);
1330
+ if (binaryKind === "bytes") {
1331
+ return `${indentation}__velarBinaryRuntime.__velarSetIndex(${object}, ${index}, ${this.emitMappedExpression(statement.value)});`;
1332
+ }
1333
+ if (binaryKind) {
1334
+ const setHelper = this.binarySetIndexHelper(binaryKind);
1335
+ const getHelper = this.binaryIndexHelper(binaryKind);
1336
+ if (statement.operator === "=") {
1337
+ return `${indentation}__velarBinaryRuntime.${setHelper}(${object}, ${index}, ${this.emitMappedExpression(statement.value)});`;
1338
+ }
1339
+ const suffix = statement.span.start;
1340
+ const objectName = `__velarIndexObject${suffix}`;
1341
+ const keyName = `__velarIndexKey${suffix}`;
1342
+ const value = this.emitMappedExpression(statement.value);
1343
+ return [
1344
+ `${indentation}{`,
1345
+ `${indentation} const ${objectName} = ${object};`,
1346
+ `${indentation} const ${keyName} = ${index};`,
1347
+ `${indentation} __velarBinaryRuntime.${setHelper}(${objectName}, ${keyName}, ${this.emitCompoundOperation(`__velarBinaryRuntime.${getHelper}(${objectName}, ${keyName})`, statement.operator, value)});`,
1348
+ `${indentation}}`,
1349
+ ].join("\n");
1350
+ }
1351
+ if (statement.operator === "=") {
1352
+ return `${indentation}__velarSetIndex(${object}, ${index}, ${this.emitMappedExpression(statement.value)});`;
1353
+ }
1354
+ const suffix = statement.span.start;
1355
+ const objectName = `__velarIndexObject${suffix}`;
1356
+ const keyName = `__velarIndexKey${suffix}`;
1357
+ const value = this.emitMappedExpression(statement.value);
1358
+ return [
1359
+ `${indentation}{`,
1360
+ `${indentation} const ${objectName} = ${object};`,
1361
+ `${indentation} const ${keyName} = ${index};`,
1362
+ `${indentation} __velarSetIndex(${objectName}, ${keyName}, ${this.emitCompoundOperation(`__velarIndex(${objectName}, ${keyName})`, statement.operator, value)});`,
1363
+ `${indentation}}`,
1364
+ ].join("\n");
1365
+ }
1366
+ if (statement.operator !== "=" && statement.target.kind === "MemberExpression") {
1367
+ const key = spanIdentity(statement.target.span);
1368
+ const staticFieldOwnerDepth = this.hints.staticFieldReads.get(key);
1369
+ const guardedInstanceField = this.hints.instanceFieldReads.has(key);
1370
+ const guardedPrivateField = this.hints.privateInstanceFieldReads.has(key);
1371
+ if (staticFieldOwnerDepth !== undefined || guardedInstanceField || guardedPrivateField) {
1372
+ const suffix = statement.span.start;
1373
+ const objectName = `__velarMemberObject${suffix}`;
1374
+ const privateProperty = this.hints.privateMembers.has(key);
1375
+ const property = `${privateProperty ? "#" : ""}${statement.target.property}`;
1376
+ const read = staticFieldOwnerDepth !== undefined
1377
+ ? `__velarReadStaticField(${objectName}, ${JSON.stringify(statement.target.property)}, ${staticFieldOwnerDepth})`
1378
+ : guardedPrivateField
1379
+ ? `__velarReadPrivateField(${objectName}.${property}, ${JSON.stringify(statement.target.property)})`
1380
+ : `__velarReadInstanceField(${objectName}, ${JSON.stringify(statement.target.property)})`;
1381
+ const operation = this.emitCompoundOperation(read, statement.operator, this.emitMappedExpression(statement.value));
1382
+ return [
1383
+ `${indentation}{`,
1384
+ `${indentation} const ${objectName} = ${this.emitMappedExpression(statement.target.object)};`,
1385
+ `${indentation} ${objectName}.${property} = ${operation};`,
1386
+ `${indentation}}`,
1387
+ ].join("\n");
1388
+ }
1389
+ if (this.bitwiseAssignmentOperator(statement.operator)) {
1390
+ const suffix = statement.span.start;
1391
+ const objectName = `__velarMemberObject${suffix}`;
1392
+ const privateProperty = this.hints.privateMembers.has(key);
1393
+ const property = `${privateProperty ? "#" : ""}${statement.target.property}`;
1394
+ const value = this.emitMappedExpression(statement.value);
1395
+ return [
1396
+ `${indentation}{`,
1397
+ `${indentation} const ${objectName} = ${this.emitMappedExpression(statement.target.object)};`,
1398
+ `${indentation} ${objectName}.${property} = ${this.emitCompoundOperation(`${objectName}.${property}`, statement.operator, value)};`,
1399
+ `${indentation}}`,
1400
+ ].join("\n");
1401
+ }
1402
+ }
1403
+ {
1404
+ const target = this.emitMappedAssignmentTarget(statement.target);
1405
+ const value = this.emitMappedExpression(statement.value);
1406
+ if (statement.operator !== "=" && this.bitwiseAssignmentOperator(statement.operator)) {
1407
+ return `${indentation}${target} = ${this.emitCompoundOperation(target, statement.operator, value)};`;
1408
+ }
1409
+ return `${indentation}${target} ${statement.operator} ${value};`;
1410
+ }
1411
+ case "ExpressionStatement":
1412
+ return `${indentation}${this.emitMappedExpression(statement.expression, false)};`;
1413
+ case "AsyncStatement":
1414
+ // Detached execution never floats: the compiler-owned observer
1415
+ // adopts the Promise, normalizes rejection to Error, and reports it
1416
+ // through the host error channel (see docs/contributing/runtime-boundary.md,
1417
+ // B-DETACHED-ASYNC). The expression takes the same Promise
1418
+ // normalization every other Promise consumer applies, so a foreign
1419
+ // thenable or an `undefined` from an extern boundary fails as an owned
1420
+ // 'Expected an actual Promise' instead of a host-voiced
1421
+ // 'Promise.prototype.then called on incompatible receiver'.
1422
+ return `${indentation}__velarDetachedTask(${this.emitMappedExpression(statement.expression)});`;
1423
+ default:
1424
+ return "";
1425
+ }
1426
+ }
1427
+ emitImport(statement, indentation) {
1428
+ const source = statement.source;
1429
+ const emittedSource = source.endsWith(".vel") ? `${source.slice(0, -4)}.js` : source;
1430
+ const first = statement.specifiers[0];
1431
+ if (first?.namespace) {
1432
+ const declared = statement.javascript && !statement.unsafe
1433
+ ? this.externModuleExports.get(source)
1434
+ : undefined;
1435
+ if (!declared)
1436
+ return `${indentation}import * as ${first.local} from ${JSON.stringify(emittedSource)};`;
1437
+ this.needsExternExportHelper = true;
1438
+ return [
1439
+ `${indentation}import * as ${first.local} from ${JSON.stringify(emittedSource)};`,
1440
+ ...[...declared].sort().map((name) => (`${indentation}__velarExternExport(${first.local}, ${JSON.stringify(name)}, ${JSON.stringify(source)});`)),
1441
+ ].join("\n");
1442
+ }
1443
+ // W-22: names governed by an extern module declaration import through the
1444
+ // module namespace so a declared-but-missing export fails at this import
1445
+ // site with a velar-voiced error instead of linking to undefined (bundled
1446
+ // CommonJS interop) or a host-voiced link refusal. Only the genuinely
1447
+ // imported declared names are checked; specifiers the declaration does not
1448
+ // name keep the native import form.
1449
+ const declared = statement.javascript && !statement.unsafe
1450
+ ? this.externModuleExports.get(source)
1451
+ : undefined;
1452
+ const checked = declared ? statement.specifiers.filter((specifier) => declared.has(specifier.imported)) : [];
1453
+ const native = declared ? statement.specifiers.filter((specifier) => !declared.has(specifier.imported)) : statement.specifiers;
1454
+ const lines = [];
1455
+ if (native.length === 1 && native[0].imported === "default") {
1456
+ lines.push(`${indentation}import ${native[0].local} from ${JSON.stringify(emittedSource)};`);
1457
+ }
1458
+ else if (native.length > 0 || checked.length === 0) {
1459
+ const names = native.map((specifier) => specifier.imported === specifier.local ? specifier.imported : `${specifier.imported} as ${specifier.local}`).join(", ");
1460
+ lines.push(`${indentation}import { ${names} } from ${JSON.stringify(emittedSource)};`);
1461
+ }
1462
+ if (checked.length > 0) {
1463
+ this.needsExternExportHelper = true;
1464
+ const namespaceName = `__velarExternModule${statement.span.start}`;
1465
+ lines.push(`${indentation}import * as ${namespaceName} from ${JSON.stringify(emittedSource)};`);
1466
+ for (const specifier of checked) {
1467
+ lines.push(`${indentation}const ${specifier.local} = __velarExternExport(${namespaceName}, ${JSON.stringify(specifier.imported)}, ${JSON.stringify(source)});`);
1468
+ }
1469
+ }
1470
+ return lines.join("\n");
1471
+ }
1472
+ prepareEmbeddedJavaScript(program) {
1473
+ this.embeddedJavaScript.clear();
1474
+ let ordinal = 0;
1475
+ for (const statement of program.body) {
1476
+ if (statement.kind !== "EmbeddedJavaScriptDeclaration")
1477
+ continue;
1478
+ const specifier = embeddedJavaScriptSpecifier(this.sourcePath, ordinal);
1479
+ const occupiedJavaScriptNames = new Set(statement.bindings.map((binding) => binding.name));
1480
+ let factoryName = statement.contract ? `__velarEmbeddedFactory_${ordinal}` : null;
1481
+ while (factoryName && occupiedJavaScriptNames.has(factoryName))
1482
+ factoryName += "_";
1483
+ const localFactoryName = statement.contract ? `__velarEmbeddedFactoryBinding_${ordinal}` : null;
1484
+ const generated = statement.contract
1485
+ ? emitCheckedEmbeddedJavaScript(statement, factoryName)
1486
+ : mappedSource(statement.source, statement.sourceSpan.start);
1487
+ this.embeddedJavaScript.set(statement, {
1488
+ statement,
1489
+ specifier,
1490
+ factoryName,
1491
+ localFactoryName,
1492
+ code: generated.code,
1493
+ mappings: generated.mappings,
1494
+ });
1495
+ ordinal += 1;
1496
+ }
1497
+ }
1498
+ emitEmbeddedJavaScript(statement, indentation) {
1499
+ const prepared = this.embeddedJavaScript.get(statement);
1500
+ if (!prepared)
1501
+ throw new Error("An embedded JavaScript declaration has no prepared sibling module");
1502
+ if (!statement.contract) {
1503
+ const imported = {
1504
+ kind: "ImportDeclaration",
1505
+ source: prepared.specifier,
1506
+ sourceSpan: statement.sourceSpan,
1507
+ javascript: true,
1508
+ unsafe: true,
1509
+ specifiers: statement.exports.map((item) => ({
1510
+ imported: item.name,
1511
+ local: item.name,
1512
+ namespace: false,
1513
+ span: item.nameSpan,
1514
+ })),
1515
+ span: statement.span,
1516
+ };
1517
+ return this.emitImport(imported, indentation);
1518
+ }
1519
+ const names = [
1520
+ ...statement.contract.functions.map((item) => item.name),
1521
+ ...statement.contract.constants.map((item) => item.name),
1522
+ ...statement.contract.classes.map((item) => item.name),
1523
+ ];
1524
+ const captureValues = statement.captures.map((capture) => this.emitMappedExpression({
1525
+ kind: "IdentifierExpression",
1526
+ name: capture.name,
1527
+ span: capture.nameSpan,
1528
+ })).join(", ");
1529
+ const call = `${prepared.localFactoryName}(${captureValues})`;
1530
+ return [
1531
+ `${indentation}import { ${prepared.factoryName} as ${prepared.localFactoryName} } from ${JSON.stringify(prepared.specifier)};`,
1532
+ names.length > 0
1533
+ ? `${indentation}const { ${names.join(", ")} } = ${call};`
1534
+ : `${indentation}${call};`,
1535
+ ].join("\n");
1536
+ }
1537
+ emitTypeDeclaration(statement, depth) {
1538
+ const parameters = statement.typeParameters?.map((parameter) => parameter.name) ?? null;
1539
+ if (!parameters)
1540
+ return this.emitRecordTypeDeclaration(statement, depth);
1541
+ this.genericTypeParameters = parameters;
1542
+ try {
1543
+ return this.emitRecordTypeDeclaration(statement, depth);
1544
+ }
1545
+ finally {
1546
+ this.genericTypeParameters = null;
1547
+ }
1548
+ }
1549
+ emitRecordTypeDeclaration(statement, depth) {
1550
+ const indentation = " ".repeat(depth);
1551
+ const generic = this.genericTypeParameters;
1552
+ const checkName = this.runtimeTypeCheckName(statement.name);
1553
+ const fields = statement.fields.map((field, index) => ({
1554
+ field,
1555
+ descriptor: `__velarField${index}`,
1556
+ type: this.resolveDeclarationType(field.type),
1557
+ }));
1558
+ const checks = fields.map(({ descriptor, type }) => {
1559
+ const present = `${descriptor}?.enumerable && "value" in ${descriptor} && ${this.emitTypeCheck(type, `${descriptor}.value`, "__state")}`;
1560
+ return type.kind === "optional" ? `(${descriptor} === undefined || (${present}))` : present;
1561
+ });
1562
+ const predicate = checks.length > 0 ? checks.join(" && ") : "true";
1563
+ const exportPrefix = statement.exported ? "export " : "";
1564
+ // COL-U5: parse failures name the failing field. The explain companion
1565
+ // re-runs the per-field checks only on the failure path, so is() and the
1566
+ // success path stay exactly as cheap as before.
1567
+ const explainName = `__velarTypeExplain_${statement.name}`;
1568
+ // D55 rule 121: a generic record's validator is the same validator with the
1569
+ // erased positions supplied from outside — the arguments carry a predicate,
1570
+ // a display text, and a key per type argument, so `parse` still names the
1571
+ // type the author wrote and the memo still answers with one Type object per
1572
+ // instantiation.
1573
+ const argumentsParameter = generic ? ", __velarArguments" : "";
1574
+ const displayName = generic ? "__velarArguments.name" : JSON.stringify(statement.name);
1575
+ const pathText = (suffix) => generic
1576
+ ? (suffix === "" ? displayName : `${displayName} + ${JSON.stringify(suffix)}`)
1577
+ : JSON.stringify(`${statement.name}${suffix}`);
1578
+ const explainLines = [
1579
+ `${indentation}function ${explainName}(value${argumentsParameter}) {`,
1580
+ `${indentation} if (value === null || typeof value !== "object" || __velarValidationIsArray(value) || !__velarValidationIsPlainObject(value)) {`,
1581
+ `${indentation} return { path: ${pathText("")}, field: null, reason: "the value is not a record" };`,
1582
+ `${indentation} }`,
1583
+ ...fields.flatMap(({ field, type }) => {
1584
+ const descriptor = "__velarExplainField";
1585
+ const typeText = this.typeTextExpression(type, field.type.syntax);
1586
+ const lines = [
1587
+ `${indentation} {`,
1588
+ `${indentation} const ${descriptor} = __velarValidationOwnDescriptor(value, ${JSON.stringify(field.name)});`,
1589
+ ];
1590
+ if (type.kind === "optional") {
1591
+ lines.push(`${indentation} if (${descriptor} !== undefined && !(${descriptor}.enumerable && "value" in ${descriptor} && ${this.emitTypeCheck(type, `${descriptor}.value`, "__velarValidationState()")})) {`);
1592
+ }
1593
+ else {
1594
+ lines.push(`${indentation} if (${descriptor} === undefined) {`);
1595
+ lines.push(`${indentation} return { path: ${pathText(`.${field.name}`)}, field: ${JSON.stringify(field.name)}, reason: ${JSON.stringify(`field '${field.name}' is missing`)} };`);
1596
+ lines.push(`${indentation} }`);
1597
+ lines.push(`${indentation} if (!(${descriptor}.enumerable && "value" in ${descriptor} && ${this.emitTypeCheck(type, `${descriptor}.value`, "__velarValidationState()")})) {`);
1598
+ }
1599
+ lines.push(`${indentation} return { path: ${pathText(`.${field.name}`)}, field: ${JSON.stringify(field.name)}, reason: ${JSON.stringify(`field '${field.name}' does not match `)} + ${typeText} };`);
1600
+ lines.push(`${indentation} }`);
1601
+ lines.push(`${indentation} }`);
1602
+ return lines;
1603
+ }),
1604
+ `${indentation} return { path: ${pathText("")}, field: null, reason: null };`,
1605
+ `${indentation}}`,
1606
+ "",
1607
+ ];
1608
+ const typeObject = [
1609
+ `${indentation} is(value, __state) {`,
1610
+ `${indentation} return ${checkName}(value, __state${generic ? ", __velarArguments" : ""});`,
1611
+ `${indentation} },`,
1612
+ `${indentation} parse(value) {`,
1613
+ `${indentation} if (!${checkName}(value, __velarValidationState()${generic ? ", __velarArguments" : ""})) {`,
1614
+ `${indentation} const __velarDetail = ${explainName}(value${generic ? ", __velarArguments" : ""});`,
1615
+ `${indentation} throw new __VelarValidationError(${generic ? `"Value does not match " + ${displayName}` : JSON.stringify(`Value does not match ${statement.name}`)} + (__velarDetail.reason ? " — " + __velarDetail.reason : "") + __velarValidationRejectionHint(value), __velarDetail);`,
1616
+ `${indentation} }`,
1617
+ `${indentation} return value;`,
1618
+ `${indentation} },`,
1619
+ ];
1620
+ if (generic) {
1621
+ const instances = `__velarGenericInstances_${statement.name}`;
1622
+ return [
1623
+ ...explainLines,
1624
+ ...this.recordCheckFunctionLines(statement, fields, predicate, checkName, indentation, argumentsParameter),
1625
+ "",
1626
+ `${indentation}const ${instances} = [];`,
1627
+ // The instantiation memo: one frozen Type object per set of arguments,
1628
+ // found by a key the emitter builds from the arguments' own identities.
1629
+ // It is what makes `type Tree<T>: kids: List<Tree<T>>` terminate — the
1630
+ // body's reference to its own instantiation is a lookup, not a rebuild.
1631
+ `${indentation}${exportPrefix}const ${statement.name} = __velarValidationFreeze({`,
1632
+ `${indentation} of(__velarKeys, __velarTexts, __velarChecks) {`,
1633
+ `${indentation} let __velarKey = ${JSON.stringify(statement.name)};`,
1634
+ `${indentation} for (let __velarIndex = 0; __velarIndex < __velarKeys.length; __velarIndex += 1) __velarKey += "\\u0000" + __velarKeys[__velarIndex];`,
1635
+ `${indentation} for (let __velarIndex = 0; __velarIndex < ${instances}.length; __velarIndex += 1) {`,
1636
+ `${indentation} if (${instances}[__velarIndex].key === __velarKey) return ${instances}[__velarIndex].type;`,
1637
+ `${indentation} }`,
1638
+ `${indentation} let __velarName = ${JSON.stringify(`${statement.name}<`)};`,
1639
+ `${indentation} for (let __velarIndex = 0; __velarIndex < __velarTexts.length; __velarIndex += 1) __velarName += (__velarIndex === 0 ? "" : ", ") + __velarTexts[__velarIndex];`,
1640
+ `${indentation} __velarName += ">";`,
1641
+ `${indentation} const __velarArguments = { keys: __velarKeys, texts: __velarTexts, checks: __velarChecks, name: __velarName };`,
1642
+ `${indentation} const __velarType = __velarRegisterRuntimeType(__velarValidationFreeze({`,
1643
+ ...typeObject.map((line) => `${indentation} ${line}`),
1644
+ `${indentation} }));`,
1645
+ `${indentation} ${instances}[${instances}.length] = { key: __velarKey, type: __velarType };`,
1646
+ `${indentation} return __velarType;`,
1647
+ `${indentation} },`,
1648
+ `${indentation}});`,
1649
+ ].join("\n");
1650
+ }
1651
+ return [
1652
+ ...explainLines,
1653
+ ...this.recordCheckFunctionLines(statement, fields, predicate, checkName, indentation, ""),
1654
+ "",
1655
+ `${indentation}${exportPrefix}const ${statement.name} = __velarRegisterRuntimeType(__velarValidationFreeze({`,
1656
+ ...typeObject,
1657
+ `${indentation}}));`,
1658
+ ].join("\n");
1659
+ }
1660
+ /** The record predicate itself: identical for a plain record and a generic one but for the arguments it carries. */
1661
+ recordCheckFunctionLines(statement, fields, predicate, checkName, indentation, argumentsParameter) {
1662
+ // The per-value cycle guard is keyed by the *instantiation*, not by the
1663
+ // function: `Tree<string>` and `Tree<number>` share one predicate, and a
1664
+ // value reached under both in one traversal is two questions, not one.
1665
+ const guard = argumentsParameter ? "__velarArguments" : checkName;
1666
+ return [
1667
+ `${indentation}function ${checkName}(value, __state = __velarValidationState()${argumentsParameter}) {`,
1668
+ // D44 rule 70: a record contract accepts only plain data objects, so a
1669
+ // class instance can never satisfy it — otherwise the validated record
1670
+ // view would alias the live instance and write through its const fields.
1671
+ `${indentation} if (value === null || typeof value !== "object" || __velarValidationIsArray(value) || !__velarValidationIsPlainObject(value) || __state.depth >= 1000) return false;`,
1672
+ `${indentation} let __active = __velarValidationWeakMapGet(__state.active, value);`,
1673
+ `${indentation} if (__active && __velarValidationSetHas(__active, ${guard})) return false;`,
1674
+ `${indentation} if (!__active) {`,
1675
+ `${indentation} __active = __velarValidationSet();`,
1676
+ `${indentation} __velarValidationWeakMapSet(__state.active, value, __active);`,
1677
+ `${indentation} }`,
1678
+ `${indentation} __velarValidationSetAdd(__active, ${guard});`,
1679
+ `${indentation} __state.depth += 1;`,
1680
+ `${indentation} try {`,
1681
+ ...fields.map(({ field, descriptor }) => `${indentation} const ${descriptor} = __velarValidationOwnDescriptor(value, ${JSON.stringify(field.name)});`),
1682
+ `${indentation} return !!(${predicate});`,
1683
+ `${indentation} } finally {`,
1684
+ `${indentation} __state.depth -= 1;`,
1685
+ `${indentation} __velarValidationSetDelete(__active, ${guard});`,
1686
+ `${indentation} if (__velarValidationSetSize(__active) === 0) __velarValidationWeakMapDelete(__state.active, value);`,
1687
+ `${indentation} }`,
1688
+ `${indentation}}`,
1689
+ ];
1690
+ }
1691
+ emitTypeAliasDeclaration(statement, depth) {
1692
+ const indentation = " ".repeat(depth);
1693
+ // ENM-I4: identities follow aliases, so an alias whose target resolves to
1694
+ // an enum IS that enum object at runtime — members, is, parse, and
1695
+ // values() all answer through the one frozen object.
1696
+ const enumTarget = this.enumAliasTarget(statement.name);
1697
+ if (enumTarget !== null) {
1698
+ return `${indentation}${statement.exported ? "export " : ""}const ${statement.name} = ${enumTarget};`;
1699
+ }
1700
+ // D55 rule 123 on ENM-I4's precedent: naming an instantiation is *the*
1701
+ // idiom that gives a generic record a runtime Type object, so the name IS
1702
+ // that instantiation's Type object rather than a wrapper around it. One
1703
+ // object per instantiation program-wide, and `parse` answers with the
1704
+ // record's own per-field explanation instead of a bare refusal.
1705
+ const target = resolveTypeReference(statement.target);
1706
+ if (target.kind === "named" && target.application && this.genericTypeBinding(target.application.name)) {
1707
+ this.needsRuntimeTypeHelpers = true;
1708
+ return `${indentation}${statement.exported ? "export " : ""}const ${statement.name} = ${this.genericInstanceExpression(target.application)};`;
1709
+ }
1710
+ const checkName = this.runtimeTypeCheckName(statement.name);
1711
+ const predicate = this.emitTypeCheck(resolveTypeReference(statement.target), "value", "__state");
1712
+ const exportPrefix = statement.exported ? "export " : "";
1713
+ return [
1714
+ `${indentation}function ${checkName}(value, __state = __velarValidationState()) {`,
1715
+ `${indentation} return ${predicate};`,
1716
+ `${indentation}}`,
1717
+ "",
1718
+ `${indentation}${exportPrefix}const ${statement.name} = __velarRegisterRuntimeType(__velarValidationFreeze({`,
1719
+ `${indentation} is(value, __state) {`,
1720
+ `${indentation} return ${checkName}(value, __state);`,
1721
+ `${indentation} },`,
1722
+ `${indentation} parse(value) {`,
1723
+ `${indentation} if (!${checkName}(value)) {`,
1724
+ `${indentation} throw new __VelarValidationError(${JSON.stringify(`Value does not match ${statement.name}`)}, { path: ${JSON.stringify(statement.name)} });`,
1725
+ `${indentation} }`,
1726
+ `${indentation} return value;`,
1727
+ `${indentation} },`,
1728
+ `${indentation}}));`,
1729
+ ].join("\n");
1730
+ }
1731
+ emitEnumDeclaration(statement, depth) {
1732
+ const indentation = " ".repeat(depth);
1733
+ const values = statement.members.map((member) => JSON.stringify(member.value));
1734
+ const members = statement.members.map((member) => `${indentation} ${member.name}: ${JSON.stringify(member.value)},`);
1735
+ const predicate = values.length === 1
1736
+ ? `value === ${values[0]}`
1737
+ : values.map((value) => `value === ${value}`).join(" || ");
1738
+ return [
1739
+ `${indentation}${statement.exported ? "export " : ""}const ${statement.name} = __velarRegisterRuntimeType(__velarValidationFreeze({`,
1740
+ ...members,
1741
+ `${indentation} is(value) {`,
1742
+ `${indentation} return ${predicate};`,
1743
+ `${indentation} },`,
1744
+ `${indentation} parse(value) {`,
1745
+ `${indentation} if (!${statement.name}.is(value)) {`,
1746
+ `${indentation} throw new __VelarValidationError(${JSON.stringify(`Value does not match ${statement.name}`)}, { path: ${JSON.stringify(statement.name)} });`,
1747
+ `${indentation} }`,
1748
+ `${indentation} return value;`,
1749
+ `${indentation} },`,
1750
+ // ENM-U1: the members in declaration order, a fresh mutable List per call.
1751
+ `${indentation} values() {`,
1752
+ `${indentation} return [${values.join(", ")}];`,
1753
+ `${indentation} },`,
1754
+ `${indentation}}));`,
1755
+ ].join("\n");
1756
+ }
1757
+ emitTypeCheck(type, value, state = "undefined") {
1758
+ switch (type.kind) {
1759
+ case "unknown":
1760
+ case "any":
1761
+ return "true";
1762
+ case "null":
1763
+ return `${value} == null`;
1764
+ case "string":
1765
+ case "number":
1766
+ case "bool":
1767
+ return `typeof ${value} === ${JSON.stringify(type.kind === "bool" ? "boolean" : type.kind)}`;
1768
+ case "optional":
1769
+ return `(${value} == null || ${this.emitTypeCheck(type.inner, value, state)})`;
1770
+ case "list":
1771
+ return `__velarListTypeIs(${value}, (item) => ${this.emitTypeCheck(type.element, "item", state)})`;
1772
+ case "set":
1773
+ return `__velarSetTypeIs(${value}, (item) => ${this.emitTypeCheck(type.element, "item", state)})`;
1774
+ case "map":
1775
+ return `__velarMapTypeIs(${value}, (key, item) => ${this.emitTypeCheck(type.key, "key", state)} && ${this.emitTypeCheck(type.value, "item", state)})`;
1776
+ case "record":
1777
+ return `__velarRecordTypeIs(${value}, (item) => ${this.emitTypeCheck(type.value, "item", state)})`;
1778
+ case "promise":
1779
+ return `__velarValidationIsPromise(${value})`;
1780
+ case "named":
1781
+ // D55 rule 121: an instantiation's validator is the declaration's,
1782
+ // supplied with this application's argument predicates. The factory
1783
+ // memoizes, so the object is built once however many times it is asked
1784
+ // for — and a recursive record's reference to itself is a memo hit.
1785
+ if (type.application && this.genericTypeBinding(type.application.name)) {
1786
+ this.needsRuntimeTypeHelpers = true;
1787
+ return `${this.genericInstanceExpression(type.application)}.is(${value}, ${state})`;
1788
+ }
1789
+ if (type.name === "Duration")
1790
+ return `typeof ${value} === "string" && /^[+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:ms|s)$/.test(${value})`;
1791
+ if (this.hints.enumNames.has(type.name))
1792
+ return `${type.name}.is(${value})`;
1793
+ if (this.hints.classNames.has(type.name)) {
1794
+ return `__velarValidationIsInstance(${value}, ${this.builtinErrorRuntimeName(type.name) ?? type.name})`;
1795
+ }
1796
+ // An alias of an enum is lowered as the enum object itself, so its
1797
+ // check delegates the same way a direct enum name does (ENM-I4).
1798
+ if (this.enumAliasTarget(type.name) !== null)
1799
+ return `${type.name}.is(${value})`;
1800
+ if (this.typeDeclarations.has(type.name))
1801
+ return `${this.runtimeTypeCheckName(type.name)}(${value}, ${state})`;
1802
+ // D60 rule 148: only a name that actually binds a runtime Type object
1803
+ // may be written into the output. See `runtimeTypeBinding`.
1804
+ return this.runtimeTypeBinding(type.name) ? `${type.name}.is(${value}, ${state})` : "false";
1805
+ case "class":
1806
+ return `__velarValidationIsInstance(${value}, ${this.builtinErrorRuntimeName(type.name) ?? type.name})`;
1807
+ case "enum":
1808
+ return `${type.name}.is(${value})`;
1809
+ case "enumMember":
1810
+ return `${value} === ${type.name}.${type.member}`;
1811
+ case "union":
1812
+ return `(${type.members.map((member) => this.emitTypeCheck(member, value, state)).join(" || ")})`;
1813
+ case "object":
1814
+ return `${value} !== null && typeof ${value} === "object"`;
1815
+ case "function":
1816
+ case "action":
1817
+ case "intrinsic":
1818
+ return `typeof ${value} === "function"`;
1819
+ // D55 rule 121: inside a generic record's own validator a type parameter
1820
+ // is not unknowable — the instantiation handed in the predicate for it.
1821
+ case "parameter":
1822
+ return this.genericTypeParameters?.length
1823
+ ? `__velarArguments.checks[${type.index}](${value}, ${state === "undefined" ? "__velarValidationState()" : state})`
1824
+ : "false";
1825
+ case "typeObject":
1826
+ case "runtimeType":
1827
+ case "enumObject":
1828
+ case "classConstructor":
1829
+ case "extension":
1830
+ // Static Type<T> carriers are erased; the analyzer rejects them in any
1831
+ // recursively runtime-checked position before emission can happen.
1832
+ return "false";
1833
+ }
1834
+ }
1835
+ emitIsCheck(type, value) {
1836
+ if (type.kind === "named" && type.name === "Duration")
1837
+ return `typeof ${value} === "string" && /^[+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:ms|s)$/.test(${value})`;
1838
+ // D60 rule 148: a name with no runtime Type object behind it is not a
1839
+ // callable receiver, so the check falls through to the structural form
1840
+ // instead of naming a binding that does not exist.
1841
+ return type.kind === "named" && this.runtimeTypeBinding(type.name)
1842
+ ? `${type.name}.is(${value})`
1843
+ : this.emitTypeCheck(type, value);
1844
+ }
1845
+ emitNarrowingCheck(type, value, state = "undefined") {
1846
+ switch (type.kind) {
1847
+ case "optional":
1848
+ return `(${value} == null || ${this.emitNarrowingCheck(type.inner, value, state)})`;
1849
+ case "list":
1850
+ return `__velarListTypeIs(${value}, (item) => ${this.emitNarrowingCheck(type.element, "item", state)})`;
1851
+ case "set":
1852
+ return `__velarSetTypeIs(${value}, (item) => ${this.emitNarrowingCheck(type.element, "item", state)})`;
1853
+ case "map":
1854
+ return `__velarMapTypeIs(${value}, (key, item) => ${this.emitNarrowingCheck(type.key, "key", state)} && ${this.emitNarrowingCheck(type.value, "item", state)})`;
1855
+ case "record":
1856
+ return `__velarRecordTypeIs(${value}, (item) => ${this.emitNarrowingCheck(type.value, "item", state)})`;
1857
+ case "union":
1858
+ return `(${type.members.map((member) => this.emitNarrowingCheck(member, value, state)).join(" || ")})`;
1859
+ case "named":
1860
+ // FLW-U1: an imported record type (or alias) is not in this module's
1861
+ // typeDeclarations, but its runtime Type object is an in-scope
1862
+ // binding, so the recheck routes through `Name.is(value)` exactly as
1863
+ // `is` tests already do. Only names with no runtime Type binding at
1864
+ // all — extension host types such as DOM interfaces — degrade to the
1865
+ // presence-only check.
1866
+ if (type.application && this.genericTypeBinding(type.application.name))
1867
+ return this.emitTypeCheck(type, value, state);
1868
+ if (!this.runtimeTypeBinding(type.name))
1869
+ return `${value} != null`;
1870
+ return this.emitTypeCheck(type, value, state);
1871
+ case "parameter":
1872
+ case "typeObject":
1873
+ case "runtimeType":
1874
+ case "enumObject":
1875
+ case "classConstructor":
1876
+ case "extension":
1877
+ return `${value} != null`;
1878
+ default:
1879
+ return this.emitTypeCheck(type, value, state);
1880
+ }
1881
+ }
1882
+ runtimeTypeCheckName(name) {
1883
+ return `__velarTypeCheck_${name}`;
1884
+ }
1885
+ /**
1886
+ * D55 rule 121: the name a module writes for a generic record is a JavaScript
1887
+ * binding holding its instantiation factory — declared here, or imported from
1888
+ * the module that declares it. Nothing else may be written into `.of(...)`.
1889
+ */
1890
+ genericTypeBinding(name) {
1891
+ if (this.hints.genericTypeNames.has(name))
1892
+ return true;
1893
+ const declaration = this.typeDeclarations.get(name);
1894
+ return declaration?.kind === "TypeDeclaration" && (declaration.typeParameters?.length ?? 0) > 0;
1895
+ }
1896
+ /** The instantiation a `named` application stands for, as a JavaScript expression. */
1897
+ genericInstanceExpression(application) {
1898
+ const keys = application.arguments.map((argument) => this.genericArgumentExpression(argument, "key"));
1899
+ const texts = application.arguments.map((argument) => this.genericArgumentExpression(argument, "text"));
1900
+ const checks = application.arguments.map((argument) => `(value, __state) => ${this.emitTypeCheck(argument, "value", "__state")}`);
1901
+ const expression = `${application.name}.of([${keys.join(", ")}], [${texts.join(", ")}], [${checks.join(", ")}])`;
1902
+ // Outside a generic body the arguments are closed, so the whole
1903
+ // instantiation is hoisted into one memoized function: a `function`
1904
+ // declaration, which hoists past the temporal dead zone a `const` would
1905
+ // create for `type Boxed = Box<string>` written above the declaration.
1906
+ if (this.genericTypeParameters?.length)
1907
+ return expression;
1908
+ const hoisted = this.hoistedGenericInstances.get(expression)
1909
+ ?? `__velarTypeOf${this.hoistedGenericInstances.size}`;
1910
+ this.hoistedGenericInstances.set(expression, hoisted);
1911
+ return `${hoisted}()`;
1912
+ }
1913
+ /**
1914
+ * A type argument's memo key or display text. Both are plain strings when the
1915
+ * argument is closed; inside a generic body a mention of the enclosing
1916
+ * parameters reads them off the arguments the instantiation supplied, so
1917
+ * `type Wrapper<T>: inner: Box<List<T>>` keys and prints correctly at every
1918
+ * instantiation without the emitter having seen one.
1919
+ */
1920
+ genericArgumentExpression(type, mode) {
1921
+ const parameters = this.genericTypeParameters;
1922
+ if (!parameters?.length || !typeContainsParameter(type)) {
1923
+ return JSON.stringify(mode === "key" ? semanticTypeIdentity(type) : describeType(type));
1924
+ }
1925
+ const nested = (value) => this.genericArgumentExpression(value, mode);
1926
+ const wrap = (prefix, parts, suffix) => [JSON.stringify(prefix), ...parts.flatMap((part, index) => index === 0 ? [part] : [JSON.stringify(mode === "key" ? "," : ", "), part]), JSON.stringify(suffix)].join(" + ");
1927
+ switch (type.kind) {
1928
+ case "parameter":
1929
+ return `__velarArguments.${mode === "key" ? "keys" : "texts"}[${type.index}]`;
1930
+ case "optional":
1931
+ return `${nested(type.inner)} + ${JSON.stringify("?")}`;
1932
+ case "list":
1933
+ return wrap("List<", [nested(type.element)], ">");
1934
+ case "set":
1935
+ return wrap("Set<", [nested(type.element)], ">");
1936
+ case "map":
1937
+ return wrap("Map<", [nested(type.key), nested(type.value)], ">");
1938
+ case "record":
1939
+ return wrap("Record<", [nested(type.value)], ">");
1940
+ case "promise":
1941
+ return wrap("Promise<", [nested(type.value)], ">");
1942
+ case "named":
1943
+ return type.application
1944
+ ? wrap(`${type.application.name}<`, type.application.arguments.map(nested), ">")
1945
+ : JSON.stringify(mode === "key" ? semanticTypeIdentity(type) : describeType(type));
1946
+ case "union":
1947
+ return type.members.map(nested).join(` + ${JSON.stringify(mode === "key" ? "|" : " | ")} + `);
1948
+ default:
1949
+ return JSON.stringify(mode === "key" ? semanticTypeIdentity(type) : describeType(type));
1950
+ }
1951
+ }
1952
+ /**
1953
+ * The display text of a field's declared type, as a JavaScript expression.
1954
+ * A generic record's `parse` failure names the type the caller instantiated
1955
+ * — `field 'value' does not match string`, not `does not match T`.
1956
+ */
1957
+ typeTextExpression(type, syntax) {
1958
+ return this.genericTypeParameters?.length
1959
+ ? this.genericArgumentExpression(type, "text")
1960
+ : JSON.stringify(formatTypeSyntax(syntax));
1961
+ }
1962
+ /**
1963
+ * A declared type inside a generic record's body. The emitter has no analyzer
1964
+ * frame, so the declaration's own parameter names are turned into `parameter`
1965
+ * kinds here — the one place the emitter learns that `T` is erased rather
1966
+ * than unknown.
1967
+ */
1968
+ resolveDeclarationType(reference) {
1969
+ const parameters = this.genericTypeParameters;
1970
+ const resolved = resolveTypeReference(reference);
1971
+ if (!parameters?.length)
1972
+ return resolved;
1973
+ const bindParameters = (type) => {
1974
+ if (type.kind === "named" && !type.application) {
1975
+ const index = parameters.indexOf(type.name);
1976
+ if (index >= 0)
1977
+ return { kind: "parameter", name: type.name, index };
1978
+ }
1979
+ return mapNestedTypes(type, bindParameters);
1980
+ };
1981
+ return bindParameters(resolved);
1982
+ }
1983
+ /**
1984
+ * D60 rule 148: a `named` ValueType carries the type's *display* name, which
1985
+ * is a runtime binding only when this module really has a Type object under
1986
+ * it — a local `type` declaration, an imported one, an enum, or a class. An
1987
+ * unresolved generic formats to type text (`Component<(label: string) ->
1988
+ * WebNode>`) that is not even a JavaScript identifier, and an extension host
1989
+ * scalar (`Color`, `Length`, `WebNode`) has no binding at all. Writing either
1990
+ * into the output is how `velar check` passed and `velar build` then failed
1991
+ * to parse its own emission; the narrowing path (FLW-U1) already asks this
1992
+ * question, and every other check path now asks it too.
1993
+ */
1994
+ runtimeTypeBinding(name) {
1995
+ return this.hints.enumNames.has(name)
1996
+ || this.hints.classNames.has(name)
1997
+ || this.typeDeclarations.has(name)
1998
+ || this.hints.runtimeTypeObjectNames.has(name);
1999
+ }
2000
+ /** The runtime class behind a nameable builtin error type, marking the runtime it needs. */
2001
+ builtinErrorRuntimeName(name) {
2002
+ if (VELAR_HOST_ERROR_NAMES.includes(name)) {
2003
+ this.requiredHostErrorClasses.add(name);
2004
+ return `__Velar${name}`;
2005
+ }
2006
+ const runtime = builtinErrorRuntimeNames.get(name);
2007
+ if (!runtime)
2008
+ return null;
2009
+ if (name === "ValidationError")
2010
+ this.needsRuntimeTypeHelpers = true;
2011
+ else if (name === "NarrowingError")
2012
+ this.needsNarrowingErrorClass = true;
2013
+ else
2014
+ this.needsCollectionHelpers = true;
2015
+ return runtime;
2016
+ }
2017
+ /** The enum an alias (or alias chain) resolves to, or null when the name is not an alias of an enum. */
2018
+ enumAliasTarget(name, seen = []) {
2019
+ if (seen.includes(name))
2020
+ return null;
2021
+ const declaration = this.typeDeclarations.get(name);
2022
+ if (!declaration || declaration.kind !== "TypeAliasDeclaration")
2023
+ return null;
2024
+ const target = resolveTypeReference(declaration.target);
2025
+ if (target.kind !== "named")
2026
+ return null;
2027
+ if (this.hints.enumNames.has(target.name))
2028
+ return target.name;
2029
+ return this.enumAliasTarget(target.name, [...seen, name]);
2030
+ }
2031
+ emitClass(statement, depth) {
2032
+ const indentation = " ".repeat(depth);
2033
+ const parameters = statement.parameters.map((parameter) => this.emitParameter(parameter.name, parameter.defaultValue, parameter.rest)).join(", ");
2034
+ const constructorLines = [];
2035
+ const constructorBody = [...(statement.initialization?.body ?? [])];
2036
+ const explicitSuper = constructorBody[0]?.kind === "ExpressionStatement"
2037
+ && constructorBody[0].expression.kind === "CallExpression"
2038
+ && constructorBody[0].expression.callee.kind === "SuperExpression";
2039
+ if (statement.base) {
2040
+ constructorLines.push(explicitSuper
2041
+ ? this.emitMappedStatement(constructorBody.shift(), depth + 2)
2042
+ : `${indentation} super();`);
2043
+ }
2044
+ // Error subclasses report under their declared name — the JavaScript
2045
+ // default leaves `.name` at "Error", which mislabels every report header
2046
+ // (audit 4's micro-ruling).
2047
+ if (statement.base && this.hints.errorSubclassNames.has(statement.name)) {
2048
+ constructorLines.push(`${indentation} this.name = ${JSON.stringify(statement.name)};`);
2049
+ }
2050
+ for (const parameter of statement.parameters) {
2051
+ if (parameter.binding) {
2052
+ constructorLines.push(`${indentation} this.${parameter.private ? "#" : ""}${parameter.name} = ${parameter.name};`);
2053
+ }
2054
+ }
2055
+ for (const field of statement.fields) {
2056
+ if (!field.static && field.initializer)
2057
+ constructorLines.push(`${indentation} this.${field.private ? "#" : ""}${field.name} = ${this.emitMappedExpression(field.initializer)};`);
2058
+ }
2059
+ if (statement.initialization) {
2060
+ constructorLines.push(`${indentation} const self = this;`);
2061
+ constructorLines.push(...this.emitStatementLines(constructorBody, depth + 2));
2062
+ }
2063
+ const constructor = [
2064
+ `${indentation} constructor(${parameters}) {`,
2065
+ ...constructorLines,
2066
+ `${indentation} }`,
2067
+ ].join("\n");
2068
+ const methodBody = (method, methodDepth) => {
2069
+ const lines = method.abstract
2070
+ ? [`${" ".repeat(methodDepth)}throw new Error(${JSON.stringify(`Abstract ${"accessor" in method ? "getter" : "method"} ${statement.name}.${method.name}${"accessor" in method ? "" : "()"} must be implemented`)});`]
2071
+ : [
2072
+ ...(method.static ? [] : [`${" ".repeat(methodDepth)}const self = this;`]),
2073
+ ...this.emitStatementLines(method.body, methodDepth),
2074
+ ];
2075
+ if (!method.abstract && !this.blockAlwaysReturns(method.body))
2076
+ lines.push(`${" ".repeat(methodDepth)}return null;`);
2077
+ return lines;
2078
+ };
2079
+ // Methods — public, static, and private alike — live on the class body as
2080
+ // native (private) methods, so instances carry data fields only and one
2081
+ // method object serves every instance (charter section 18).
2082
+ const methods = statement.methods.map((method) => {
2083
+ const methodParameters = method.parameters.map((parameter) => this.emitParameter(parameter.name, parameter.defaultValue, parameter.rest)).join(", ");
2084
+ const lines = methodBody(method, depth + 2);
2085
+ const body = lines.join("\n");
2086
+ return `${indentation} ${method.static ? "static " : ""}${method.asynchronous ? "async " : ""}${method.private ? "#" : ""}${method.name}(${methodParameters}) {${body.length > 0 ? `\n${body}\n${indentation} ` : ""}}`;
2087
+ });
2088
+ const getters = statement.getters.map((getter) => {
2089
+ const lines = methodBody(getter, depth + 2);
2090
+ const body = lines.join("\n");
2091
+ return `${indentation} ${getter.static ? "static " : ""}get ${getter.private ? "#" : ""}${getter.name}() {${body.length > 0 ? `\n${body}\n${indentation} ` : ""}}`;
2092
+ });
2093
+ const privateFields = [
2094
+ ...statement.parameters.filter((parameter) => parameter.private).map((parameter) => parameter.name),
2095
+ ...statement.fields.filter((field) => field.private && !field.static).map((field) => field.name),
2096
+ ].map((name) => `${indentation} #${name};`);
2097
+ const staticFields = statement.fields
2098
+ .filter((field) => field.static)
2099
+ .map((field) => `${indentation} static ${field.private ? "#" : ""}${field.name} = ${field.initializer ? this.emitMappedExpression(field.initializer) : "null"};`);
2100
+ // D43 item 69: `@dispose:` becomes one prototype member under a key no
2101
+ // source member name can spell, so the release contract cannot be called
2102
+ // from source and cannot collide with a member the author declares.
2103
+ const dispose = [];
2104
+ if (statement.dispose) {
2105
+ // D51 rule 102: a derived `@dispose:` adds to the base's, it does not
2106
+ // replace it. The compiler composes the contract because `@dispose` is
2107
+ // not callable from source (D43 item 69), so an author could not forward
2108
+ // it by hand even if every author remembered to.
2109
+ const chained = this.hints.classDisposeChains.get(spanIdentity(statement.span)) ?? null;
2110
+ const disposeDepth = depth + (chained ? 3 : 2);
2111
+ const indent = " ".repeat(disposeDepth);
2112
+ const asynchronous = chained === "async"
2113
+ || blockContainsDirectAwait(statement.dispose.body, (value, contains) => this.extensionExpressionContainsDirectAwait(value, contains), (owned, containsExpression, containsBlock) => this.extensionStatementContainsDirectAwait(owned, containsExpression, containsBlock));
2114
+ const body = [
2115
+ `${indent}const self = this;`,
2116
+ ...this.emitStatementLines(statement.dispose.body, disposeDepth),
2117
+ `${indent}return null;`,
2118
+ ];
2119
+ const lines = chained ? this.chainedDisposeLines(body, chained, statement.span.start, depth + 2) : body;
2120
+ dispose.push(`${indentation} ${asynchronous ? "async " : ""}[${JSON.stringify(disposeMemberKey)}]() {\n${lines.join("\n")}\n${indentation} }`);
2121
+ }
2122
+ // D68 rule 177: `@iterate:` lands the same way, under its own unspellable
2123
+ // key. It is a plain prototype member, so a derived block simply shadows
2124
+ // the base's — overriding replaces, which is what "one answer" means.
2125
+ const iterate = [];
2126
+ if (statement.iterate) {
2127
+ const iterateDepth = depth + 2;
2128
+ const indent = " ".repeat(iterateDepth);
2129
+ const body = [
2130
+ `${indent}const self = this;`,
2131
+ ...this.emitStatementLines(statement.iterate.body, iterateDepth),
2132
+ `${indent}return null;`,
2133
+ ];
2134
+ iterate.push(`${indentation} [${JSON.stringify(iterateMemberKey)}]() {\n${body.join("\n")}\n${indentation} }`);
2135
+ }
2136
+ const extension = statement.base ? ` extends ${statement.base.name}` : "";
2137
+ return `${indentation}${statement.exported ? "export " : ""}class ${statement.name}${extension} {\n${[...privateFields, ...staticFields, constructor, ...getters, ...methods, ...dispose, ...iterate].join("\n\n")}\n${indentation}}`;
2138
+ }
2139
+ /**
2140
+ * D51 rule 102: derived first, base after — construction order reversed, the
2141
+ * same intuition LIFO release already has. The base runs on every exit from
2142
+ * the derived body, including a `return`, and when the derived part already
2143
+ * failed the base failure is reported to the host instead of replacing the
2144
+ * error in flight, exactly as rule 8 of D43 item 69 decides for `using`.
2145
+ */
2146
+ chainedDisposeLines(body, inherited, suffix, depth) {
2147
+ const indentation = " ".repeat(depth);
2148
+ this.needsDisposalHelper = true;
2149
+ this.needsThrownValueHelper = true;
2150
+ const call = `${inherited === "async" ? "await " : ""}super[${JSON.stringify(disposeMemberKey)}]()`;
2151
+ const released = `__velarBaseReleased${suffix}`;
2152
+ const failure = `__velarDisposeChainFailure${suffix}`;
2153
+ return [
2154
+ `${indentation}let ${released} = false;`,
2155
+ `${indentation}try {`,
2156
+ ...body,
2157
+ `${indentation}} catch (${failure}) {`,
2158
+ `${indentation} ${released} = true;`,
2159
+ `${indentation} try { ${call}; } catch (__velarBaseDisposeFailure${suffix}) { __velarDisposalReport(__velarBaseDisposeFailure${suffix}); }`,
2160
+ `${indentation} throw ${failure};`,
2161
+ `${indentation}} finally {`,
2162
+ `${indentation} if (!${released}) ${call};`,
2163
+ `${indentation}}`,
2164
+ ];
2165
+ }
2166
+ emitParameter(name, defaultValue, rest = false) {
2167
+ if (rest)
2168
+ return `...${name}`;
2169
+ return defaultValue ? `${name} = ${this.emitMappedExpression(defaultValue)}` : name;
2170
+ }
2171
+ emitMappedExpression(expression, normalizeNull = true) {
2172
+ return this.emitMappedJavaScript(expression.span, () => {
2173
+ const key = spanIdentity(expression.span);
2174
+ const normalizePromise = normalizeNull
2175
+ && this.suppressPromiseNormalization === 0
2176
+ && this.hints.normalizedPromiseValues.has(key);
2177
+ if (normalizePromise)
2178
+ this.suppressPromiseNormalization += 1;
2179
+ let emitted;
2180
+ try {
2181
+ emitted = this.emitExpression(expression);
2182
+ }
2183
+ finally {
2184
+ if (normalizePromise)
2185
+ this.suppressPromiseNormalization -= 1;
2186
+ }
2187
+ const narrowing = this.hints.runtimeNarrowings.get(key);
2188
+ if (narrowing) {
2189
+ emitted = `(__velarValue => __velarNarrow(__velarValue, ${this.emitNarrowingCheck(narrowing.expected, "__velarValue")}, ${JSON.stringify(describeType(narrowing.expected))}, ${JSON.stringify(narrowing.description)}, ${expression.span.start}))(${emitted})`;
2190
+ }
2191
+ // D68 rule 177: the projection lives here rather than in each of the
2192
+ // eight consumers, because "iterating a class means iterating what
2193
+ // `@iterate:` answers" is one fact about the operand, and the consumers'
2194
+ // own lowerings then receive the List, Set, Map, or Record they already
2195
+ // knew how to handle.
2196
+ if (this.hints.iterationContracts.has(key))
2197
+ emitted = `(${emitted})[${JSON.stringify(iterateMemberKey)}]()`;
2198
+ if (!normalizeNull)
2199
+ return emitted;
2200
+ if (normalizePromise)
2201
+ return `__velarNormalizePromiseValue(${emitted})`;
2202
+ if (this.hints.normalizedNullResults.has(key))
2203
+ return `(${emitted}, null)`;
2204
+ if (this.hints.normalizedUndefinedExpressions.has(key))
2205
+ return `(${emitted} ?? null)`;
2206
+ return emitted;
2207
+ });
2208
+ }
2209
+ emitMappedAssignmentTarget(expression) {
2210
+ return this.emitMappedJavaScript(expression.span, () => {
2211
+ if (expression.kind === "IdentifierExpression")
2212
+ return this.emitExpression(expression);
2213
+ const property = `${this.hints.privateMembers.has(spanIdentity(expression.span)) ? "#" : ""}${expression.property}`;
2214
+ return `${this.emitPostfixReceiver(expression.object)}.${property}`;
2215
+ });
2216
+ }
2217
+ bitwiseAssignmentOperator(operator) {
2218
+ return operator === "&=" || operator === "|=" || operator === "^=" || operator === "<<=" || operator === ">>=" || operator === ">>>="
2219
+ ? operator.slice(0, -1)
2220
+ : null;
2221
+ }
2222
+ emitCompoundOperation(read, operator, value) {
2223
+ const bitwise = this.bitwiseAssignmentOperator(operator);
2224
+ if (bitwise) {
2225
+ this.needsBitwiseHelpers = true;
2226
+ return `__velarBitwiseBinary(${read}, ${JSON.stringify(bitwise)}, ${value})`;
2227
+ }
2228
+ return `${read} ${operator.slice(0, -1)} ${value}`;
2229
+ }
2230
+ emitExpression(expression) {
2231
+ if (expression.kind === "ExtensionExpression:core:duration") {
2232
+ return JSON.stringify(expression.raw);
2233
+ }
2234
+ if (expression.kind === "UnaryExpression" && (expression.operator === "+" || expression.operator === "-")
2235
+ && this.hints.extensionCalls.get(spanIdentity(expression.span)) === "core.duration-arithmetic") {
2236
+ return `__velarDurationUnary(${JSON.stringify(expression.operator)}, ${this.emitMappedExpression(expression.operand)})`;
2237
+ }
2238
+ if (expression.kind === "BinaryExpression"
2239
+ && this.hints.extensionCalls.get(spanIdentity(expression.span)) === "core.duration-arithmetic") {
2240
+ return `__velarDurationMath(${JSON.stringify(expression.operator)}, ${this.emitMappedExpression(expression.left)}, ${this.emitMappedExpression(expression.right)})`;
2241
+ }
2242
+ switch (expression.kind) {
2243
+ case "LiteralExpression":
2244
+ return expression.value === null ? "null" : typeof expression.value === "string" ? JSON.stringify(expression.value) : String(expression.value);
2245
+ case "FStringExpression":
2246
+ return `\`${expression.parts.map((part) => part.kind === "text" ? this.escapeTemplateText(part.value) : `\${${this.emitMappedExpression(part.value)}}`).join("")}\``;
2247
+ case "IdentifierExpression":
2248
+ {
2249
+ const builtin = this.hints.builtinValueReferences.get(spanIdentity(expression.span));
2250
+ if (builtin === "Json")
2251
+ return "__velarJsonNamespace";
2252
+ if (builtin === "Promise")
2253
+ return "__velarPromiseNamespace";
2254
+ if (builtin === "Text")
2255
+ return "__velarTextNamespace";
2256
+ if (builtin === "Math")
2257
+ return "__velarMathNamespace";
2258
+ if (builtin === "range")
2259
+ return "__velarRange";
2260
+ }
2261
+ if (expression.name === "number") {
2262
+ this.needsNumberHelper = true;
2263
+ return "__velarNumber";
2264
+ }
2265
+ return expression.name === "str" ? "String"
2266
+ : expression.name === "print" ? "console.log"
2267
+ : this.builtinErrorRuntimeName(expression.name) ?? expression.name;
2268
+ case "SuperExpression":
2269
+ return "super";
2270
+ case "DynamicImportExpression": {
2271
+ const source = expression.source.endsWith(".vel") ? `${expression.source.slice(0, -4)}.js` : expression.source;
2272
+ return `import(${JSON.stringify(source)})`;
2273
+ }
2274
+ case "ListExpression":
2275
+ if (expression.elements.some((element) => element.kind === "SpreadExpression")) {
2276
+ this.needsCollectionHelpers = true;
2277
+ const asynchronous = expression.elements.some((element) => this.expressionContainsDirectAwait(element));
2278
+ const parts = expression.elements.map((element) => {
2279
+ const directAwait = this.expressionContainsDirectAwait(element);
2280
+ const value = element.kind === "SpreadExpression" ? element.value : element;
2281
+ const read = `${directAwait ? "async " : ""}() => (${this.emitMappedExpression(value)})`;
2282
+ return asynchronous ? `[${element.kind === "SpreadExpression"}, ${directAwait}, ${read}]` : `[${element.kind === "SpreadExpression"}, ${read}]`;
2283
+ });
2284
+ return `${asynchronous ? "await __velarCreateListAsync" : "__velarCreateList"}([${parts.join(", ")}])`;
2285
+ }
2286
+ return `[${expression.elements.map((element) => this.emitMappedExpression(element)).join(", ")}]`;
2287
+ case "ObjectExpression": {
2288
+ const needsControlledConstruction = expression.properties.some((property) => property.kind === "ObjectSpread"
2289
+ || property.name === "__proto__");
2290
+ if (!needsControlledConstruction) {
2291
+ return `{ ${expression.properties.map((property) => property.kind === "ObjectProperty"
2292
+ ? `${this.emitObjectKey(property.name)}: ${this.emitMappedExpression(property.value)}`
2293
+ : "").join(", ")} }`;
2294
+ }
2295
+ this.needsCollectionHelpers = true;
2296
+ this.needsRecordHelpers = true;
2297
+ const asynchronous = expression.properties.some((property) => this.expressionContainsDirectAwait(property.value));
2298
+ const parts = expression.properties.map((property) => {
2299
+ const directAwait = this.expressionContainsDirectAwait(property.value);
2300
+ const read = `${directAwait ? "async " : ""}() => (${this.emitMappedExpression(property.value)})`;
2301
+ const name = property.kind === "ObjectProperty" ? JSON.stringify(property.name) : "null";
2302
+ return asynchronous
2303
+ ? `[${property.kind === "ObjectSpread"}, ${name}, ${directAwait}, ${read}]`
2304
+ : `[${property.kind === "ObjectSpread"}, ${name}, ${read}]`;
2305
+ });
2306
+ return `${asynchronous ? "await __velarCreateRecordAsync" : "__velarCreateRecord"}([${parts.join(", ")}])`;
2307
+ }
2308
+ case "SpreadExpression":
2309
+ this.needsCollectionHelpers = true;
2310
+ return `...__velarCopyList(${this.emitMappedExpression(expression.value)}, "Call spread")`;
2311
+ // D39 item 51: the attempt runs in its own frame so any failure inside
2312
+ // the whole chain becomes null, and nothing else in the surrounding
2313
+ // expression is skipped.
2314
+ case "TryExpression": {
2315
+ // D51 rule 103: `try` turns an *expected* failure into an optional.
2316
+ // AssertionError, NarrowingError, and IndexError are the language
2317
+ // saying "your program has a bug", so they pass straight through
2318
+ // instead of arriving as a `null` that reads like "not found". A
2319
+ // `catch` block still catches all three — that one is explicit.
2320
+ this.needsIntegrityFailureHelper = true;
2321
+ const asynchronous = this.expressionContainsDirectAwait(expression.value);
2322
+ const failure = `__velarTryFailure${expression.span.start}`;
2323
+ const attempt = `{ try { return ${this.emitMappedExpression(expression.value)}; } `
2324
+ + `catch (${failure}) { if (__velarIsIntegrityFailure(${failure})) throw ${failure}; return null; } }`;
2325
+ return `${asynchronous ? "await " : ""}(${asynchronous ? "async " : ""}() => ${attempt})()`;
2326
+ }
2327
+ case "UnaryExpression":
2328
+ if (expression.operator === "await") {
2329
+ return `await ${this.emitMappedExpression(expression.operand)}`;
2330
+ }
2331
+ if (expression.operator === "~") {
2332
+ this.needsBitwiseHelpers = true;
2333
+ return `__velarBitwiseUnary(${this.emitMappedExpression(expression.operand)})`;
2334
+ }
2335
+ return expression.operator === "not"
2336
+ ? `!(${this.emitCondition(expression.operand)})`
2337
+ : `${expression.operator}(${this.emitMappedExpression(expression.operand)})`;
2338
+ case "BinaryExpression": {
2339
+ if (expression.operator === "and" || expression.operator === "or") {
2340
+ const operator = expression.operator === "and" ? "&&" : "||";
2341
+ return `(${this.emitCondition(expression.left)} ${operator} ${this.emitCondition(expression.right)})`;
2342
+ }
2343
+ if (expression.operator === "in" || expression.operator === "not in") {
2344
+ this.needsCollectionHelpers = true;
2345
+ const membership = `__velarContains(${this.emitMappedExpression(expression.left)}, ${this.emitMappedExpression(expression.right)})`;
2346
+ return expression.operator === "not in" ? `!(${membership})` : membership;
2347
+ }
2348
+ if (["&", "|", "^", "<<", ">>", ">>>"].includes(expression.operator)) {
2349
+ this.needsBitwiseHelpers = true;
2350
+ return `__velarBitwiseBinary(${this.emitMappedExpression(expression.left)}, ${JSON.stringify(expression.operator)}, ${this.emitMappedExpression(expression.right)})`;
2351
+ }
2352
+ // D36 item 41: `==`/`!=` are SameValueZero. The analyzer proves which
2353
+ // comparisons can actually meet two NaN operands; everything else
2354
+ // elides the repair and stays plain strict equality.
2355
+ if ((expression.operator === "==" || expression.operator === "!=")
2356
+ && this.hints.sameValueZeroEqualities.has(spanIdentity(expression.span))) {
2357
+ this.needsCollectionHelpers = true;
2358
+ const equality = `__velarSameValueZero(${this.emitBinaryOperand(expression.left)}, ${this.emitBinaryOperand(expression.right)})`;
2359
+ return expression.operator === "==" ? equality : `!${equality}`;
2360
+ }
2361
+ // TXT-D1: string orderings compare by code point everywhere; the
2362
+ // analyzer marks exactly the ordered comparisons whose operands are
2363
+ // strings, so numbers keep the plain operator.
2364
+ if (["<", "<=", ">", ">="].includes(expression.operator)
2365
+ && this.hints.stringOrderings.has(spanIdentity(expression.span))) {
2366
+ this.needsPrimitiveHelpers = true;
2367
+ return `(__velarStringCompare(${this.emitBinaryOperand(expression.left)}, ${this.emitBinaryOperand(expression.right)}) ${expression.operator} 0)`;
2368
+ }
2369
+ // D41 item 61: a comparison between Comparable-bounded parameters
2370
+ // dispatches on the runtime category instead of guessing one.
2371
+ if (["<", "<=", ">", ">="].includes(expression.operator)
2372
+ && this.hints.dynamicOrderings.has(spanIdentity(expression.span))) {
2373
+ this.needsPrimitiveHelpers = true;
2374
+ return `(__velarOrderCompare(${this.emitBinaryOperand(expression.left)}, ${this.emitBinaryOperand(expression.right)}) ${expression.operator} 0)`;
2375
+ }
2376
+ const operator = expression.operator === "==" ? "===" : expression.operator === "!=" ? "!==" : expression.operator;
2377
+ const left = expression.operator === "**" && expression.left.kind === "UnaryExpression"
2378
+ ? `(${this.emitMappedExpression(expression.left)})`
2379
+ : this.emitBinaryOperand(expression.left);
2380
+ return `(${left} ${operator} ${this.emitBinaryOperand(expression.right)})`;
2381
+ }
2382
+ case "ComparisonChainExpression":
2383
+ return this.emitComparisonChain(expression);
2384
+ case "ConditionalExpression":
2385
+ return `(${this.emitCondition(expression.condition)} ? ${this.emitMappedExpression(expression.thenValue)} : ${this.emitMappedExpression(expression.elseValue)})`;
2386
+ case "IsExpression":
2387
+ {
2388
+ const value = `__velarIs${expression.span.start}`;
2389
+ const checked = resolveTypeReference(expression.type);
2390
+ const classCheck = this.hints.classChecks.has(spanIdentity(expression.span));
2391
+ const test = classCheck
2392
+ ? `${value} instanceof ${this.typeRuntimeName(expression.type)}`
2393
+ : this.emitIsCheck(checked, value);
2394
+ const emittedValue = this.emitMappedExpression(expression.value);
2395
+ // Keep the common one-read checks direct. Union, optional, and
2396
+ // structural checks that reference the value more than once capture
2397
+ // it first so an arbitrary source expression still runs exactly once.
2398
+ const uses = test.split(value).length - 1;
2399
+ // GRM-D1: a nested `is` (or unary) operand spliced into the direct
2400
+ // check would rebind under the generated operator — `typeof typeof
2401
+ // x` — so those operands keep explicit parentheses.
2402
+ const operand = expression.value.kind === "IsExpression" || expression.value.kind === "UnaryExpression"
2403
+ ? `(${emittedValue})`
2404
+ : emittedValue;
2405
+ const result = uses === 1
2406
+ ? classCheck
2407
+ ? `${operand} instanceof ${this.typeRuntimeName(expression.type)}`
2408
+ : this.emitIsCheck(checked, operand)
2409
+ : `(${value} => ${test})(${emittedValue})`;
2410
+ return expression.operator === "is not" ? `!(${result})` : result;
2411
+ }
2412
+ case "ArrowFunctionExpression": {
2413
+ const body = this.emitMappedExpression(expression.body);
2414
+ const resolvedBody = this.hints.asyncResolvedValues.has(spanIdentity(expression.body.span)) ? `__velarAsyncResolvedValue(${body})` : body;
2415
+ const emittedBody = expression.body.kind === "ObjectExpression" ? `(${resolvedBody})` : resolvedBody;
2416
+ return `${expression.asynchronous ? "async " : ""}${expression.parameters.length === 1 && !expression.parameters[0].rest && !expression.parameters[0].defaultValue
2417
+ ? expression.parameters[0].name
2418
+ : `(${expression.parameters.map((parameter) => this.emitParameter(parameter.name, parameter.defaultValue, parameter.rest)).join(", ")})`} => ${emittedBody}`;
2419
+ }
2420
+ case "CallExpression": {
2421
+ if (expression.callee.kind === "MemberExpression") {
2422
+ const binaryHelper = this.binaryHelper(expression.callee);
2423
+ if (binaryHelper) {
2424
+ this.needsBinaryHelpers = true;
2425
+ const object = this.emitMappedExpression(expression.callee.object);
2426
+ const sourceArguments = expression.arguments.map((argument) => this.emitMappedExpression(argument));
2427
+ const namedOrder = this.hints.namedArgumentOrders.get(spanIdentity(expression.span));
2428
+ const arguments_ = namedOrder
2429
+ ? namedOrder.map((source) => source === -1 ? "undefined" : `__velarNamedArguments[${source}]`)
2430
+ : sourceArguments;
2431
+ const emittedArguments = namedOrder
2432
+ ? `...((__velarNamedArguments) => [${arguments_.join(", ")}])([${sourceArguments.join(", ")}])`
2433
+ : arguments_.join(", ");
2434
+ const suffix = arguments_.length > 0 ? `, ${emittedArguments}` : "";
2435
+ const invocation = `${binaryHelper}(__velarValue${suffix})`;
2436
+ return this.hints.optionalCallees.has(spanIdentity(expression.span))
2437
+ ? `(__velarValue => __velarValue == null ? null : ${invocation})(${object})`
2438
+ : `${binaryHelper}(${object}${suffix})`;
2439
+ }
2440
+ const primitiveHelper = this.primitiveHelper(expression.callee);
2441
+ if (primitiveHelper) {
2442
+ this.needsPrimitiveHelpers = true;
2443
+ const object = this.emitMappedExpression(expression.callee.object);
2444
+ const sourceArguments = expression.arguments.map((argument) => this.emitMappedExpression(argument));
2445
+ const namedOrder = this.hints.namedArgumentOrders.get(spanIdentity(expression.span));
2446
+ const arguments_ = namedOrder
2447
+ ? namedOrder.map((source) => source === -1 ? "undefined" : `__velarNamedArguments[${source}]`)
2448
+ : sourceArguments;
2449
+ const emittedArguments = namedOrder
2450
+ ? `...((__velarNamedArguments) => [${arguments_.join(", ")}])([${sourceArguments.join(", ")}])`
2451
+ : arguments_.join(", ");
2452
+ const suffix = arguments_.length > 0 ? `, ${emittedArguments}` : "";
2453
+ const invocation = `${primitiveHelper}(__velarValue${suffix})`;
2454
+ return this.hints.optionalCallees.has(spanIdentity(expression.span))
2455
+ ? `(__velarValue => __velarValue == null ? null : ${invocation})(${object})`
2456
+ : `${primitiveHelper}(${object}${suffix})`;
2457
+ }
2458
+ const helper = this.collectionHelper(expression.callee);
2459
+ if (helper) {
2460
+ this.needsCollectionHelpers = true;
2461
+ const object = this.emitMappedExpression(expression.callee.object);
2462
+ const sourceArguments = expression.arguments.map((argument) => this.emitMappedExpression(argument));
2463
+ const namedOrder = this.hints.namedArgumentOrders.get(spanIdentity(expression.span));
2464
+ const arguments_ = namedOrder
2465
+ ? namedOrder.map((source) => source === -1 ? "undefined" : `__velarNamedArguments[${source}]`)
2466
+ : sourceArguments;
2467
+ const emitArguments = () => namedOrder
2468
+ ? `...((__velarNamedArguments) => [${arguments_.join(", ")}])([${sourceArguments.join(", ")}])`
2469
+ : arguments_.join(", ");
2470
+ const suffix = arguments_.length > 0 ? `, ${emitArguments()}` : "";
2471
+ if (this.hints.optionalCallees.has(spanIdentity(expression.span))) {
2472
+ const invocation = `${helper}(__velarValue${suffix})`;
2473
+ return `(__velarOptionalCollection(${object}, __velarValue => ${invocation}) ?? null)`;
2474
+ }
2475
+ return `${helper}(${object}${suffix})`;
2476
+ }
2477
+ }
2478
+ const hostBoundary = this.hints.javaScriptCallBoundaries.has(spanIdentity(expression.span));
2479
+ const sourceArguments = expression.arguments.map((argument) => {
2480
+ const emitted = this.emitMappedExpression(argument);
2481
+ return hostBoundary && argument.kind !== "SpreadExpression" ? `__velarHostRaw(${emitted})` : emitted;
2482
+ });
2483
+ const namedOrder = this.hints.namedArgumentOrders.get(spanIdentity(expression.span));
2484
+ const arguments_ = namedOrder
2485
+ ? namedOrder.map((source) => source === -1 ? "undefined" : `__velarNamedArguments[${source}]`)
2486
+ : sourceArguments;
2487
+ const emitArguments = () => namedOrder
2488
+ ? `...((__velarNamedArguments) => [${arguments_.join(", ")}])([${sourceArguments.join(", ")}])`
2489
+ : arguments_.join(", ");
2490
+ if (this.hints.optionalCallees.has(spanIdentity(expression.span))) {
2491
+ const call = expression.callee.kind === "MemberExpression"
2492
+ ? `${this.emitPostfixReceiver(expression.callee.object)}${expression.callee.optional ? "?." : "."}${expression.callee.property}?.(${emitArguments()})`
2493
+ : `${this.emitPostfixReceiver(expression.callee)}?.(${emitArguments()})`;
2494
+ return `(${call} ?? null)`;
2495
+ }
2496
+ if (expression.callee.kind === "MemberExpression" && expression.callee.optional) {
2497
+ const call = `${this.emitPostfixReceiver(expression.callee.object)}?.${expression.callee.property}(${emitArguments()})`;
2498
+ return `(${call} ?? null)`;
2499
+ }
2500
+ let callee;
2501
+ if (expression.callee.kind === "IdentifierExpression" && (expression.callee.name === "Map" || expression.callee.name === "Set")) {
2502
+ this.needsCollectionHelpers = true;
2503
+ callee = expression.callee.name === "Map" ? "__velarCreateMap" : "__velarCreateSet";
2504
+ }
2505
+ else if (expression.callee.kind === "IdentifierExpression" && this.hints.equalsCalls.has(spanIdentity(expression.span))) {
2506
+ this.needsCollectionHelpers = true;
2507
+ callee = "__velarEquals";
2508
+ }
2509
+ else {
2510
+ if (this.hints.constructorCalls.has(spanIdentity(expression.span))) {
2511
+ // A callee that is not a plain name path may be wrapped (for
2512
+ // example by a narrowing recheck IIFE), and `new (arrow)(x)(args)`
2513
+ // binds `(x)` as the construction arguments — the wrapper, not
2514
+ // the class, gets constructed. Parentheses restore the callee
2515
+ // boundary; plain name paths skip them to keep output readable.
2516
+ // Source-map markers are invisible in final output and ignored.
2517
+ const constructed = this.emitMappedExpression(expression.callee);
2518
+ callee = /^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z0-9_$]+)*$/u.test(constructed.replaceAll(javaScriptNodeMarker, ""))
2519
+ ? `new ${constructed}`
2520
+ : `new (${constructed})`;
2521
+ }
2522
+ else {
2523
+ callee = this.emitPostfixReceiver(expression.callee);
2524
+ }
2525
+ }
2526
+ const formRead = this.hints.formReads.get(spanIdentity(expression.span));
2527
+ if (formRead)
2528
+ arguments_.push(JSON.stringify(formRead));
2529
+ const call = `${callee}(${emitArguments()})`;
2530
+ const result = this.hints.optionalCalls.has(spanIdentity(expression.span)) ? `(${call} ?? null)` : call;
2531
+ // BRG-U10: a synchronous non-Error throw from an extern call during
2532
+ // module initialization would reach the host raw (no catch, no
2533
+ // rejection path); rethrowing through the owned normalization keeps
2534
+ // the last bridge failure shape on the Error channel. Calls whose
2535
+ // arguments await are already rejection-owned and stay unwrapped.
2536
+ if (hostBoundary
2537
+ && this.hints.moduleTopLevelHostCalls.has(spanIdentity(expression.span))
2538
+ && !this.expressionContainsDirectAwait(expression)) {
2539
+ this.needsThrownValueHelper = true;
2540
+ return `(() => { try { return ${result}; } catch (__velarThrown) { throw __velarNormalizeError(__velarThrown); } })()`;
2541
+ }
2542
+ return result;
2543
+ }
2544
+ case "MemberExpression": {
2545
+ const binaryHelper = this.binaryHelper(expression);
2546
+ if (binaryHelper) {
2547
+ this.needsBinaryHelpers = true;
2548
+ const object = this.emitMappedExpression(expression.object);
2549
+ const bound = `(...__velarArguments) => ${binaryHelper}(__velarValue, ...__velarArguments)`;
2550
+ return expression.optional
2551
+ ? `(__velarValue => __velarValue == null ? null : ${bound})(${object})`
2552
+ : `(__velarValue => ${bound})(${object})`;
2553
+ }
2554
+ if (this.hints.binarySizes.has(expression.span.end)) {
2555
+ this.needsBinaryHelpers = true;
2556
+ const object = this.emitMappedExpression(expression.object);
2557
+ return expression.optional
2558
+ ? `(__velarValue => __velarValue == null ? null : __velarBinaryRuntime.__velarSize(__velarValue))(${object})`
2559
+ : `__velarBinaryRuntime.__velarSize(${object})`;
2560
+ }
2561
+ const primitiveHelper = this.primitiveHelper(expression);
2562
+ if (primitiveHelper) {
2563
+ this.needsPrimitiveHelpers = true;
2564
+ const object = this.emitMappedExpression(expression.object);
2565
+ const bound = `(...__velarArguments) => ${primitiveHelper}(__velarValue, ...__velarArguments)`;
2566
+ return expression.optional
2567
+ ? `(__velarValue => __velarValue == null ? null : ${bound})(${object})`
2568
+ : `(__velarValue => ${bound})(${object})`;
2569
+ }
2570
+ if (this.hints.stringSizes.has(expression.span.end)) {
2571
+ this.needsPrimitiveHelpers = true;
2572
+ const object = this.emitMappedExpression(expression.object);
2573
+ return expression.optional
2574
+ ? `(__velarValue => __velarValue == null ? null : __velarStringSize(__velarValue))(${object})`
2575
+ : `__velarStringSize(${object})`;
2576
+ }
2577
+ const collectionHelper = this.collectionHelper(expression);
2578
+ if (collectionHelper) {
2579
+ this.needsCollectionHelpers = true;
2580
+ const object = this.emitMappedExpression(expression.object);
2581
+ const bound = `(...__velarArguments) => ${collectionHelper}(__velarValue, ...__velarArguments)`;
2582
+ return expression.optional
2583
+ ? `(__velarValue => __velarValue == null ? null : ${bound})(${object})`
2584
+ : `(__velarValue => ${bound})(${object})`;
2585
+ }
2586
+ if (this.hints.collectionSizes.has(expression.span.end)) {
2587
+ this.needsCollectionHelpers = true;
2588
+ const object = this.emitMappedExpression(expression.object);
2589
+ return expression.optional
2590
+ ? `(__velarOptionalCollection(${object}, __velarCollectionSize) ?? null)`
2591
+ : `__velarCollectionSize(${object})`;
2592
+ }
2593
+ const staticFieldOwnerDepth = this.hints.staticFieldReads.get(spanIdentity(expression.span));
2594
+ if (staticFieldOwnerDepth !== undefined) {
2595
+ const object = this.emitMappedExpression(expression.object);
2596
+ const read = `__velarReadStaticField(__velarValue, ${JSON.stringify(expression.property)}, ${staticFieldOwnerDepth})`;
2597
+ return expression.optional
2598
+ ? `(__velarValue => __velarValue == null ? null : ${read})(${object})`
2599
+ : `__velarReadStaticField(${object}, ${JSON.stringify(expression.property)}, ${staticFieldOwnerDepth})`;
2600
+ }
2601
+ if (this.hints.errorCodeReads.has(spanIdentity(expression.span))) {
2602
+ this.needsErrorCodeHelper = true;
2603
+ const object = this.emitMappedExpression(expression.object);
2604
+ return expression.optional
2605
+ ? `($velarValue => $velarValue == null ? null : __velarErrorCode($velarValue))(${object})`
2606
+ : `__velarErrorCode(${object})`;
2607
+ }
2608
+ if (this.hints.instanceFieldReads.has(spanIdentity(expression.span))) {
2609
+ const object = this.emitMappedExpression(expression.object);
2610
+ const read = `__velarReadInstanceField(__velarValue, ${JSON.stringify(expression.property)})`;
2611
+ return expression.optional
2612
+ ? `(__velarValue => __velarValue == null ? null : ${read})(${object})`
2613
+ : `__velarReadInstanceField(${object}, ${JSON.stringify(expression.property)})`;
2614
+ }
2615
+ if (this.hints.privateInstanceFieldReads.has(spanIdentity(expression.span))) {
2616
+ if (expression.optional) {
2617
+ const object = this.emitMappedExpression(expression.object);
2618
+ const read = `__velarReadPrivateField(__velarValue.#${expression.property}, ${JSON.stringify(expression.property)})`;
2619
+ return `(__velarValue => __velarValue == null ? null : ${read})(${object})`;
2620
+ }
2621
+ return `__velarReadPrivateField(${this.emitPostfixReceiver(expression.object)}.#${expression.property}, ${JSON.stringify(expression.property)})`;
2622
+ }
2623
+ if (this.hints.classMethodReferences.has(spanIdentity(expression.span))) {
2624
+ // Methods live on the prototype, so a method read as a value
2625
+ // evaluates its receiver once and binds at the reference site —
2626
+ // the collection-method rule of charter section 8. `super` cannot
2627
+ // be captured by a temporary; it binds `this` directly.
2628
+ const property = `${this.hints.privateMembers.has(spanIdentity(expression.span)) ? "#" : ""}${expression.property}`;
2629
+ if (expression.object.kind === "SuperExpression") {
2630
+ return `super.${property}.bind(this)`;
2631
+ }
2632
+ const object = this.emitMappedExpression(expression.object);
2633
+ const bound = `__velarValue.${property}.bind(__velarValue)`;
2634
+ return expression.optional
2635
+ ? `(__velarValue => __velarValue == null ? null : ${bound})(${object})`
2636
+ : `(__velarValue => ${bound})(${object})`;
2637
+ }
2638
+ const publicProperty = expression.property;
2639
+ const property = `${this.hints.privateMembers.has(spanIdentity(expression.span)) ? "#" : ""}${publicProperty}`;
2640
+ const access = `${this.emitPostfixReceiver(expression.object)}${expression.optional ? "?." : "."}${property}`;
2641
+ return this.hints.optionalMembers.has(spanIdentity(expression.span)) ? `(${access} ?? null)` : access;
2642
+ }
2643
+ case "IndexExpression":
2644
+ {
2645
+ const binaryKind = this.hints.binaryIndexes.get(spanIdentity(expression.span));
2646
+ if (binaryKind) {
2647
+ this.needsBinaryHelpers = true;
2648
+ const helper = this.binaryIndexHelper(binaryKind);
2649
+ const object = this.emitMappedExpression(expression.object);
2650
+ if (this.hints.optionalIndexes.has(spanIdentity(expression.span))) {
2651
+ return `(__velarValue => __velarValue == null ? null : __velarBinaryRuntime.${helper}(__velarValue, ${this.emitMappedExpression(expression.index)}))(${object})`;
2652
+ }
2653
+ return `__velarBinaryRuntime.${helper}(${object}, ${this.emitMappedExpression(expression.index)})`;
2654
+ }
2655
+ }
2656
+ this.needsIndexHelpers = true;
2657
+ this.needsCollectionHelpers = true;
2658
+ return this.hints.optionalIndexes.has(spanIdentity(expression.span))
2659
+ ? `__velarOptionalIndex(${this.emitMappedExpression(expression.object)}, () => ${this.emitMappedExpression(expression.index)})`
2660
+ : `__velarIndex(${this.emitMappedExpression(expression.object)}, ${this.emitMappedExpression(expression.index)})`;
2661
+ default:
2662
+ return "null";
2663
+ }
2664
+ }
2665
+ // A 'bool?' condition asks whether the value is true, so it lowers to an
2666
+ // explicit '=== true'. Both 'false' and an absent value then take the same
2667
+ // else path instead of riding on JavaScript truthiness.
2668
+ emitCondition(expression) {
2669
+ const value = this.emitMappedExpression(expression);
2670
+ return this.hints.truthConditions.has(spanIdentity(expression.span)) ? `(${value} === true)` : value;
2671
+ }
2672
+ emitBinaryOperand(expression) {
2673
+ const emitted = this.emitMappedExpression(expression);
2674
+ return expression.kind === "ArrowFunctionExpression" ? `(${emitted})` : emitted;
2675
+ }
2676
+ emitPostfixReceiver(expression) {
2677
+ const emitted = this.emitMappedExpression(expression);
2678
+ if (expression.kind === "ArrowFunctionExpression"
2679
+ || expression.kind === "UnaryExpression"
2680
+ || expression.kind === "IsExpression"
2681
+ || (expression.kind === "LiteralExpression" && typeof expression.value === "number")) {
2682
+ return `(${emitted})`;
2683
+ }
2684
+ return emitted;
2685
+ }
2686
+ emitComparisonChain(expression) {
2687
+ const prefix = `__velarCompare${expression.span.start}`;
2688
+ const body = [`const ${prefix}_0 = ${this.emitMappedExpression(expression.operands[0])};`];
2689
+ for (let index = 1; index < expression.operands.length; index += 1) {
2690
+ body.push(`const ${prefix}_${index} = ${this.emitMappedExpression(expression.operands[index])};`);
2691
+ const sourceOperator = expression.operators[index - 1];
2692
+ const linkSpan = spanIdentity({
2693
+ start: expression.operands[index - 1].span.start,
2694
+ end: expression.operands[index].span.end,
2695
+ });
2696
+ if ((sourceOperator === "==" || sourceOperator === "!=") && this.hints.sameValueZeroEqualities.has(linkSpan)) {
2697
+ // Chain operands are already captured once, so the SameValueZero
2698
+ // repair inlines as its short-circuit shape (D36 item 41).
2699
+ const left = `${prefix}_${index - 1}`;
2700
+ const right = `${prefix}_${index}`;
2701
+ const equality = `${left} === ${right} || (${left} !== ${left} && ${right} !== ${right})`;
2702
+ body.push(sourceOperator === "=="
2703
+ ? `if (!(${equality})) return false;`
2704
+ : `if (${equality}) return false;`);
2705
+ continue;
2706
+ }
2707
+ // TXT-D1: string chain links compare by code point too.
2708
+ if (["<", "<=", ">", ">="].includes(sourceOperator) && this.hints.stringOrderings.has(linkSpan)) {
2709
+ this.needsPrimitiveHelpers = true;
2710
+ body.push(`if (!(__velarStringCompare(${prefix}_${index - 1}, ${prefix}_${index}) ${sourceOperator} 0)) return false;`);
2711
+ continue;
2712
+ }
2713
+ if (["<", "<=", ">", ">="].includes(sourceOperator) && this.hints.dynamicOrderings.has(linkSpan)) {
2714
+ this.needsPrimitiveHelpers = true;
2715
+ body.push(`if (!(__velarOrderCompare(${prefix}_${index - 1}, ${prefix}_${index}) ${sourceOperator} 0)) return false;`);
2716
+ continue;
2717
+ }
2718
+ const operator = sourceOperator === "==" ? "===" : sourceOperator === "!=" ? "!==" : sourceOperator;
2719
+ body.push(`if (!(${prefix}_${index - 1} ${operator} ${prefix}_${index})) return false;`);
2720
+ }
2721
+ const asynchronous = expression.operands.some((operand) => this.expressionContainsDirectAwait(operand));
2722
+ return `${asynchronous ? "await " : ""}(${asynchronous ? "async " : ""}() => { ${body.join(" ")} return true; })()`;
2723
+ }
2724
+ expressionContainsDirectAwait(expression) {
2725
+ return containsDirectAwait(expression, (value, contains) => this.extensionExpressionContainsDirectAwait(value, contains));
2726
+ }
2727
+ typeRuntimeName(reference) {
2728
+ const type = resolveTypeReference(reference);
2729
+ if (type.kind === "named")
2730
+ return this.builtinErrorRuntimeName(type.name) ?? type.name;
2731
+ return formatTypeReference(reference);
2732
+ }
2733
+ collectionHelper(expression) {
2734
+ switch (this.hints.collectionCalls.get(expression.span.end)) {
2735
+ case "get": return "__velarCollectionGet";
2736
+ case "slice": return "__velarCollectionSlice";
2737
+ case "listAppend": return "__velarListAppend";
2738
+ case "listExtend": return "__velarListExtend";
2739
+ case "listInsert": return "__velarListInsert";
2740
+ case "listRemove": return "__velarListRemove";
2741
+ case "listPop": return "__velarListPop";
2742
+ case "listCopy": return "__velarListCopy";
2743
+ case "listCount": return "__velarListCount";
2744
+ case "listFind": return "__velarListFind";
2745
+ case "listIndex": return "__velarListIndex";
2746
+ case "listSome": return "__velarListSome";
2747
+ case "listEvery": return "__velarListEvery";
2748
+ case "listMap": return "__velarListMap";
2749
+ case "listFilter": return "__velarListFilter";
2750
+ case "listFlatMap": return "__velarListFlatMap";
2751
+ case "listReduce": return "__velarListReduce";
2752
+ case "listJoin": return "__velarListJoin";
2753
+ case "listSorted": return "__velarListSorted";
2754
+ case "listReversed": return "__velarListReversed";
2755
+ case "listSum": return "__velarListSum";
2756
+ case "listMin": return "__velarListMin";
2757
+ case "listMax": return "__velarListMax";
2758
+ case "setAdd": return "__velarSetAdd";
2759
+ case "setUpdate": return "__velarSetUpdate";
2760
+ case "setCopy": return "__velarSetCopy";
2761
+ case "setUnion": return "__velarSetUnion";
2762
+ case "setIntersection": return "__velarSetIntersection";
2763
+ case "setDifference": return "__velarSetDifference";
2764
+ case "mapSet": return "__velarMapSet";
2765
+ case "mapUpdate": return "__velarMapUpdate";
2766
+ case "mapCopy": return "__velarMapCopy";
2767
+ case "recordSet": return "__velarRecordSet";
2768
+ case "recordCopy": return "__velarRecordCopy";
2769
+ case "has": return "__velarCollectionHas";
2770
+ case "remove": return "__velarCollectionRemove";
2771
+ case "clear": return "__velarCollectionClear";
2772
+ case "keys": return "__velarCollectionKeys";
2773
+ case "values": return "__velarCollectionValues";
2774
+ case "entries": return "__velarCollectionEntries";
2775
+ default: return null;
2776
+ }
2777
+ }
2778
+ binaryHelper(expression) {
2779
+ switch (this.hints.binaryCalls.get(expression.span.end)) {
2780
+ case "bufferCopy": return "__velarBinaryRuntime.__velarBufferCopy";
2781
+ case "bufferSlice": return "__velarBinaryRuntime.__velarBufferSlice";
2782
+ case "bufferToBytes": return "__velarBinaryRuntime.__velarBufferToBytes";
2783
+ default: return null;
2784
+ }
2785
+ }
2786
+ binaryIndexHelper(kind) {
2787
+ switch (kind) {
2788
+ case "bytes": return "__velarIndex";
2789
+ case "uint8": return "__velarUInt8Index";
2790
+ case "uint16": return "__velarUInt16Index";
2791
+ case "uint32": return "__velarUInt32Index";
2792
+ case "float32": return "__velarFloat32Index";
2793
+ }
2794
+ }
2795
+ binarySetIndexHelper(kind) {
2796
+ switch (kind) {
2797
+ case "uint8": return "__velarUInt8SetIndex";
2798
+ case "uint16": return "__velarUInt16SetIndex";
2799
+ case "uint32": return "__velarUInt32SetIndex";
2800
+ case "float32": return "__velarFloat32SetIndex";
2801
+ }
2802
+ }
2803
+ primitiveHelper(expression) {
2804
+ switch (this.hints.primitiveCalls.get(expression.span.end)) {
2805
+ case "stringTrim": return "__velarStringTrim";
2806
+ case "stringUpper": return "__velarStringUpper";
2807
+ case "stringLower": return "__velarStringLower";
2808
+ case "stringSlice": return "__velarStringSlice";
2809
+ case "stringChar": return "__velarStringChar";
2810
+ case "stringHas": return "__velarStringHas";
2811
+ case "stringIndex": return "__velarStringIndex";
2812
+ case "stringCount": return "__velarStringCount";
2813
+ case "stringStartsWith": return "__velarStringStartsWith";
2814
+ case "stringEndsWith": return "__velarStringEndsWith";
2815
+ case "stringSplit": return "__velarStringSplit";
2816
+ case "stringReplace": return "__velarStringReplace";
2817
+ case "stringReplaceAll": return "__velarStringReplaceAll";
2818
+ case "stringPadStart": return "__velarStringPadStart";
2819
+ case "stringPadEnd": return "__velarStringPadEnd";
2820
+ case "stringRepeat": return "__velarStringRepeat";
2821
+ case "stringIsBlank": return "__velarStringIsBlank";
2822
+ case "numberAbs": return "__velarNumberAbs";
2823
+ case "numberRound": return "__velarNumberRound";
2824
+ case "numberFloor": return "__velarNumberFloor";
2825
+ case "numberCeil": return "__velarNumberCeil";
2826
+ case "numberToFixed": return "__velarNumberToFixed";
2827
+ case "numberIsInteger": return "__velarNumberIsInteger";
2828
+ case "numberIsNaN": return "__velarNumberIsNaN";
2829
+ case "numberIsFinite": return "__velarNumberIsFinite";
2830
+ default: return null;
2831
+ }
2832
+ }
2833
+ emitObjectKey(name) {
2834
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
2835
+ }
2836
+ emitMatchPatternAttempt(pattern, valueName, indentation) {
2837
+ const lines = [];
2838
+ const bindings = new Map();
2839
+ let nextTemporary = 0;
2840
+ const temporary = (label) => `__velarPattern${pattern.span.start}${label}${nextTemporary++}`;
2841
+ const bind = (name, value) => {
2842
+ if (name !== "_" && !bindings.has(name))
2843
+ bindings.set(name, value);
2844
+ };
2845
+ const rejectUnless = (condition) => {
2846
+ lines.push(`${indentation}if (!(${condition})) return null;`);
2847
+ };
2848
+ const emit = (current, value) => {
2849
+ switch (current.kind) {
2850
+ case "MatchWildcardPattern":
2851
+ break;
2852
+ case "MatchCapturePattern":
2853
+ bind(current.binding.name, value);
2854
+ break;
2855
+ case "MatchAsPattern":
2856
+ emit(current.pattern, value);
2857
+ bind(current.binding.name, value);
2858
+ break;
2859
+ case "MatchValuePattern":
2860
+ // ENM-D2: a candidate whose value can be NaN compares by
2861
+ // SameValueZero so `case box.nan:` agrees with `==` (charter
2862
+ // section 8); every other candidate keeps plain `===`.
2863
+ rejectUnless(current.values.map((candidate) => {
2864
+ if (this.hints.sameValueZeroMatchValues.has(spanIdentity(candidate.span))) {
2865
+ this.needsCollectionHelpers = true;
2866
+ return `__velarSameValueZero(${value}, ${this.emitMappedExpression(candidate)})`;
2867
+ }
2868
+ return `${value} === ${this.emitMappedExpression(candidate)}`;
2869
+ }).join(" || ") || "false");
2870
+ break;
2871
+ case "MatchTypePattern":
2872
+ rejectUnless(this.emitTypeCheck(resolveTypeReference(current.type), value));
2873
+ break;
2874
+ case "MatchListPattern": {
2875
+ this.needsCollectionHelpers = true;
2876
+ this.needsDirectCollectionInfrastructure = true;
2877
+ const items = temporary("List");
2878
+ const length = current.elements.length;
2879
+ lines.push(`${indentation}__velarReactiveCollectionTrack(${value});`);
2880
+ rejectUnless(`__velarCollectionListIsArray(${value})`);
2881
+ const lengthDescriptor = temporary("Length");
2882
+ const listLength = temporary("Size");
2883
+ lines.push(`${indentation}const ${lengthDescriptor} = __velarCollectionListGetOwnPropertyDescriptor(${value}, "length");`);
2884
+ rejectUnless(`${lengthDescriptor} && ${lengthDescriptor}.writable && !${lengthDescriptor}.enumerable && !${lengthDescriptor}.configurable && "value" in ${lengthDescriptor}`);
2885
+ lines.push(`${indentation}const ${listLength} = ${lengthDescriptor}.value;`);
2886
+ rejectUnless(`${listLength} <= __velarMaxCollectionItems && ${listLength} ${current.rest ? ">=" : "==="} ${length} && __velarCollectionListOwnSymbols(${value}).length === 0 && __velarCollectionListOwnNames(${value}).length === ${listLength} + 1`);
2887
+ lines.push(`${indentation}const ${items} = new __velarCollectionNativeArray(${listLength});`);
2888
+ const cursor = temporary("Index");
2889
+ const descriptor = temporary("Item");
2890
+ lines.push(`${indentation}for (let ${cursor} = 0; ${cursor} < ${listLength}; ${cursor} += 1) {`);
2891
+ lines.push(`${indentation} const ${descriptor} = __velarCollectionListGetOwnPropertyDescriptor(${value}, ${cursor});`);
2892
+ lines.push(`${indentation} if (!${descriptor}?.enumerable || !${descriptor}.configurable || !${descriptor}.writable || !("value" in ${descriptor})) return null;`);
2893
+ lines.push(`${indentation} __velarCollectionListDefineProperty(${items}, ${cursor}, { value: __velarReactiveCollectionRead(${value}, ${cursor}, ${descriptor}.value), writable: true, enumerable: true, configurable: true });`);
2894
+ lines.push(`${indentation}}`);
2895
+ current.elements.forEach((child, index) => emit(child, `${items}[${index}]`));
2896
+ if (current.rest) {
2897
+ const rest = temporary("Rest");
2898
+ const restCursor = temporary("RestIndex");
2899
+ lines.push(`${indentation}const ${rest} = new __velarCollectionNativeArray(${listLength} - ${length});`);
2900
+ lines.push(`${indentation}for (let ${restCursor} = ${length}; ${restCursor} < ${listLength}; ${restCursor} += 1) {`);
2901
+ lines.push(`${indentation} __velarCollectionListDefineProperty(${rest}, ${restCursor} - ${length}, { value: ${items}[${restCursor}], writable: true, enumerable: true, configurable: true });`);
2902
+ lines.push(`${indentation}}`);
2903
+ bind(current.rest.name, rest);
2904
+ }
2905
+ break;
2906
+ }
2907
+ case "MatchObjectPattern": {
2908
+ this.needsCollectionHelpers = true;
2909
+ this.needsDirectCollectionInfrastructure = true;
2910
+ rejectUnless(`${value} !== null && typeof ${value} === "object" && !__velarCollectionListIsArray(${value})`);
2911
+ for (const entry of current.entries) {
2912
+ const descriptor = temporary("Field");
2913
+ const fieldValue = temporary("Value");
2914
+ lines.push(`${indentation}__velarReactiveCollectionTrack(${value}, ${JSON.stringify(entry.property)});`);
2915
+ lines.push(`${indentation}const ${descriptor} = __velarCollectionRecordGetOwnPropertyDescriptor(${value}, ${JSON.stringify(entry.property)});`);
2916
+ rejectUnless(`${descriptor}?.enumerable && "value" in ${descriptor}`);
2917
+ lines.push(`${indentation}const ${fieldValue} = __velarReactiveCollectionRead(${value}, ${JSON.stringify(entry.property)}, ${descriptor}.value);`);
2918
+ emit(entry.pattern, fieldValue);
2919
+ }
2920
+ if (current.rest) {
2921
+ const rest = temporary("Rest");
2922
+ const key = temporary("Key");
2923
+ const descriptor = temporary("RestField");
2924
+ const selected = current.entries.map((entry) => `${key} === ${JSON.stringify(entry.property)}`).join(" || ") || "false";
2925
+ rejectUnless(`__velarCollectionRecordOwnSymbols(${value}).length === 0`);
2926
+ lines.push(`${indentation}__velarReactiveCollectionTrack(${value});`);
2927
+ lines.push(`${indentation}const ${rest} = {};`);
2928
+ const fields = temporary("Fields");
2929
+ const fieldIndex = temporary("FieldIndex");
2930
+ lines.push(`${indentation}const ${fields} = __velarCollectionRecordOwnNames(${value});`);
2931
+ rejectUnless(`${fields}.length <= __velarMaxCollectionItems`);
2932
+ lines.push(`${indentation}for (let ${fieldIndex} = 0; ${fieldIndex} < ${fields}.length; ${fieldIndex} += 1) {`);
2933
+ lines.push(`${indentation} const ${key} = ${fields}[${fieldIndex}];`);
2934
+ lines.push(`${indentation} if (${selected}) continue;`);
2935
+ lines.push(`${indentation} const ${descriptor} = __velarCollectionRecordGetOwnPropertyDescriptor(${value}, ${key});`);
2936
+ lines.push(`${indentation} if (!${descriptor}?.enumerable) continue;`);
2937
+ lines.push(`${indentation} if (!("value" in ${descriptor})) return null;`);
2938
+ lines.push(`${indentation} __velarCollectionRecordDefineProperty(${rest}, ${key}, { value: __velarReactiveCollectionRead(${value}, ${key}, ${descriptor}.value), writable: true, enumerable: true, configurable: true });`);
2939
+ lines.push(`${indentation}}`);
2940
+ bind(current.rest.name, rest);
2941
+ }
2942
+ break;
2943
+ }
2944
+ }
2945
+ };
2946
+ emit(pattern, valueName);
2947
+ return { lines, bindings: [...bindings].map(([name, value]) => ({ name, value })) };
2948
+ }
2949
+ emitBindingPatternStatements(pattern, value, binding, exported, depth, label) {
2950
+ const lines = [];
2951
+ const indentation = " ".repeat(depth);
2952
+ let temporary = 0;
2953
+ const nextTemporary = (kind, current) => `__velarBinding${kind}${current.span.start}_${temporary++}`;
2954
+ const declare = (name, expression) => {
2955
+ lines.push(`${indentation}${exported ? "export " : ""}${binding} ${name} = ${expression};`);
2956
+ };
2957
+ const emit = (current, currentValue) => {
2958
+ if (current.kind === "NameBindingPattern") {
2959
+ declare(current.name, currentValue);
2960
+ return;
2961
+ }
2962
+ if (current.kind === "ObjectBindingPattern") {
2963
+ this.needsCollectionHelpers = true;
2964
+ this.needsObjectBindingHelpers = true;
2965
+ const object = nextTemporary("Object", current);
2966
+ lines.push(`${indentation}const ${object} = __velarRequireBindingObject(${currentValue}, ${JSON.stringify(label)});`);
2967
+ for (const entry of current.entries) {
2968
+ const read = `__velarReadBindingField(${object}, ${JSON.stringify(entry.property)}, ${this.hints.optionalBindingEntries.has(entry.span.start)}, ${JSON.stringify(label)})`;
2969
+ if (entry.pattern.kind === "NameBindingPattern") {
2970
+ declare(entry.pattern.name, read);
2971
+ }
2972
+ else {
2973
+ const field = nextTemporary("Field", entry.pattern);
2974
+ lines.push(`${indentation}const ${field} = ${read};`);
2975
+ emit(entry.pattern, field);
2976
+ }
2977
+ }
2978
+ if (current.rest) {
2979
+ declare(current.rest.name, `__velarBindingObjectRest(${object}, ${JSON.stringify(current.entries.map((entry) => entry.property))}, ${JSON.stringify(label)})`);
2980
+ }
2981
+ return;
2982
+ }
2983
+ this.needsCollectionHelpers = true;
2984
+ this.needsListBindingHelpers = true;
2985
+ const list = nextTemporary("List", current);
2986
+ lines.push(`${indentation}const ${list} = __velarRequireBindingList(${currentValue}, ${current.elements.length}, ${current.rest !== null}, ${JSON.stringify(label)});`);
2987
+ current.elements.forEach((element, index) => {
2988
+ if (!element)
2989
+ return;
2990
+ const read = `__velarReadBindingListItem(${list}, ${index})`;
2991
+ if (element.kind === "NameBindingPattern") {
2992
+ declare(element.name, read);
2993
+ }
2994
+ else {
2995
+ const item = nextTemporary("Item", element);
2996
+ lines.push(`${indentation}const ${item} = ${read};`);
2997
+ emit(element, item);
2998
+ }
2999
+ });
3000
+ if (current.rest) {
3001
+ declare(current.rest.name, `__velarBindingListRest(${list}, ${current.elements.length})`);
3002
+ }
3003
+ };
3004
+ emit(pattern, value);
3005
+ return lines;
3006
+ }
3007
+ escapeTemplateText(value) {
3008
+ return value.replaceAll("\\", "\\\\").replaceAll("\r", "\\r").replaceAll("`", "\\`").replaceAll("${", "\\${");
3009
+ }
3010
+ blockAlwaysReturns(statements) {
3011
+ for (const statement of statements) {
3012
+ if (statement.kind === "ReturnStatement" || statement.kind === "ThrowStatement")
3013
+ return true;
3014
+ if (statement.kind === "IfStatement" && statement.elseBody
3015
+ && this.blockAlwaysReturns(statement.thenBody) && this.blockAlwaysReturns(statement.elseBody))
3016
+ return true;
3017
+ if (statement.kind === "MatchStatement" && this.hints.exhaustiveMatches.has(statement.span.start)
3018
+ && statement.cases.every((branch) => this.blockAlwaysReturns(branch.body)))
3019
+ return true;
3020
+ if (statement.kind === "TryStatement") {
3021
+ if (statement.finallyBody && this.blockAlwaysReturns(statement.finallyBody))
3022
+ return true;
3023
+ if (statement.catchBody && this.blockAlwaysReturns(statement.tryBody) && this.blockAlwaysReturns(statement.catchBody))
3024
+ return true;
3025
+ }
3026
+ }
3027
+ return false;
3028
+ }
3029
+ }
3030
+ function javaScriptIdentifiers(sources) {
3031
+ const identifiers = new Set();
3032
+ const identifierStart = (character) => /[A-Za-z_$]/u.test(character);
3033
+ const identifierPart = (character) => /[A-Za-z0-9_$]/u.test(character);
3034
+ for (const source of sources) {
3035
+ let index = 0;
3036
+ const skipQuoted = (quote) => {
3037
+ index += 1;
3038
+ while (index < source.length) {
3039
+ if (source[index] === "\\")
3040
+ index += 2;
3041
+ else if (source[index] === quote) {
3042
+ index += 1;
3043
+ return;
3044
+ }
3045
+ else
3046
+ index += 1;
3047
+ }
3048
+ };
3049
+ const skipLineComment = () => {
3050
+ index += 2;
3051
+ while (index < source.length && source[index] !== "\n" && source[index] !== "\r")
3052
+ index += 1;
3053
+ };
3054
+ const skipBlockComment = () => {
3055
+ index += 2;
3056
+ while (index < source.length) {
3057
+ if (source[index] === "*" && source[index + 1] === "/") {
3058
+ index += 2;
3059
+ return;
3060
+ }
3061
+ index += 1;
3062
+ }
3063
+ };
3064
+ let scanCode;
3065
+ const skipTemplate = () => {
3066
+ index += 1;
3067
+ while (index < source.length) {
3068
+ if (source[index] === "\\")
3069
+ index += 2;
3070
+ else if (source[index] === "`") {
3071
+ index += 1;
3072
+ return;
3073
+ }
3074
+ else if (source[index] === "$" && source[index + 1] === "{") {
3075
+ index += 2;
3076
+ scanCode(true);
3077
+ }
3078
+ else
3079
+ index += 1;
3080
+ }
3081
+ };
3082
+ scanCode = (templateExpression) => {
3083
+ let braceDepth = 0;
3084
+ while (index < source.length) {
3085
+ const character = source[index];
3086
+ if (character === "'" || character === '"') {
3087
+ skipQuoted(character);
3088
+ continue;
3089
+ }
3090
+ if (character === "`") {
3091
+ skipTemplate();
3092
+ continue;
3093
+ }
3094
+ if (character === "/" && source[index + 1] === "/") {
3095
+ skipLineComment();
3096
+ continue;
3097
+ }
3098
+ if (character === "/" && source[index + 1] === "*") {
3099
+ skipBlockComment();
3100
+ continue;
3101
+ }
3102
+ if (character === "{") {
3103
+ braceDepth += 1;
3104
+ index += 1;
3105
+ continue;
3106
+ }
3107
+ if (character === "}" && templateExpression) {
3108
+ if (braceDepth === 0) {
3109
+ index += 1;
3110
+ return;
3111
+ }
3112
+ braceDepth -= 1;
3113
+ index += 1;
3114
+ continue;
3115
+ }
3116
+ if (identifierStart(character)) {
3117
+ const start = index;
3118
+ index += 1;
3119
+ while (index < source.length && identifierPart(source[index]))
3120
+ index += 1;
3121
+ identifiers.add(source.slice(start, index));
3122
+ continue;
3123
+ }
3124
+ index += 1;
3125
+ }
3126
+ };
3127
+ scanCode(false);
3128
+ }
3129
+ return identifiers;
3130
+ }
3131
+ const base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3132
+ function encodeVlq(value) {
3133
+ let remaining = value < 0 ? ((-value) << 1) | 1 : value << 1;
3134
+ let output = "";
3135
+ do {
3136
+ let digit = remaining & 31;
3137
+ remaining >>>= 5;
3138
+ if (remaining > 0)
3139
+ digit |= 32;
3140
+ output += base64[digit];
3141
+ } while (remaining > 0);
3142
+ return output;
3143
+ }
3144
+ function generatedLineAt(lineStarts, offset) {
3145
+ let low = 0;
3146
+ let high = lineStarts.length - 1;
3147
+ while (low <= high) {
3148
+ const middle = Math.floor((low + high) / 2);
3149
+ if (lineStarts[middle] <= offset)
3150
+ low = middle + 1;
3151
+ else
3152
+ high = middle - 1;
3153
+ }
3154
+ return Math.max(0, high);
3155
+ }
3156
+ function sourceMapFor(code, generatedMappings, source) {
3157
+ const lineStarts = [0];
3158
+ for (let index = 0; index < code.length; index += 1) {
3159
+ if (code[index] === "\n")
3160
+ lineStarts.push(index + 1);
3161
+ }
3162
+ const byLine = new Map();
3163
+ for (const mapping of generatedMappings) {
3164
+ const line = generatedLineAt(lineStarts, mapping.offset);
3165
+ const entries = byLine.get(line) ?? [];
3166
+ entries.push({ column: mapping.offset - lineStarts[line], span: mapping.sourceSpan });
3167
+ byLine.set(line, entries);
3168
+ }
3169
+ let previousSource = 0;
3170
+ let previousLine = 0;
3171
+ let previousColumn = 0;
3172
+ const mappings = lineStarts.map((_, line) => {
3173
+ let previousGeneratedColumn = 0;
3174
+ return (byLine.get(line) ?? []).sort((left, right) => left.column - right.column).map((mapped) => {
3175
+ const location = source.location(mapped.span.start);
3176
+ const originalLine = location.line - 1;
3177
+ const originalColumn = location.column - 1;
3178
+ const segment = [
3179
+ encodeVlq(mapped.column - previousGeneratedColumn),
3180
+ encodeVlq(-previousSource),
3181
+ encodeVlq(originalLine - previousLine),
3182
+ encodeVlq(originalColumn - previousColumn),
3183
+ ].join("");
3184
+ previousGeneratedColumn = mapped.column;
3185
+ previousSource = 0;
3186
+ previousLine = originalLine;
3187
+ previousColumn = originalColumn;
3188
+ return segment;
3189
+ }).join(",");
3190
+ }).join(";");
3191
+ return JSON.stringify({
3192
+ version: 3,
3193
+ // Source-map sources are URLs, not host path strings. A Windows drive path
3194
+ // starts with what URL parsers treat as a scheme (`C:`), so Node cannot
3195
+ // map the generated frame back to VelarScript unless the drive path is a
3196
+ // real file URL. POSIX and project-relative paths keep their existing form.
3197
+ sources: [/^[A-Za-z]:[\\/]/u.test(source.path)
3198
+ ? `file:///${source.path.replaceAll("\\", "/")}`
3199
+ : source.path.replaceAll("\\", "/")],
3200
+ sourcesContent: [source.text],
3201
+ names: [],
3202
+ mappings,
3203
+ });
3204
+ }
3205
+ function mappedSource(source, sourceStart) {
3206
+ const mappings = source.length > 0
3207
+ ? [{ offset: 0, sourceSpan: { start: sourceStart, end: sourceStart + 1 } }]
3208
+ : [];
3209
+ for (let index = 0; index < source.length; index += 1) {
3210
+ if (source[index] !== "\n" || index + 1 >= source.length)
3211
+ continue;
3212
+ mappings.push({
3213
+ offset: index + 1,
3214
+ sourceSpan: { start: sourceStart + index + 1, end: sourceStart + index + 2 },
3215
+ });
3216
+ }
3217
+ return { code: source, mappings };
3218
+ }
3219
+ function emitCheckedEmbeddedJavaScript(statement, factoryName) {
3220
+ const relative = (value) => ({
3221
+ start: value.start - statement.sourceSpan.start,
3222
+ end: value.end - statement.sourceSpan.start,
3223
+ });
3224
+ const blank = (value) => value.replace(/[^\r\n]/gu, " ");
3225
+ const body = [...statement.factoryEdits]
3226
+ .sort((left, right) => right.span.start - left.span.start)
3227
+ .reduce((current, edit) => {
3228
+ const target = relative(edit.span);
3229
+ const replacement = edit.replacement + blank(current.slice(target.start + edit.replacement.length, target.end));
3230
+ return `${current.slice(0, target.start)}${replacement}${current.slice(target.end)}`;
3231
+ }, statement.source);
3232
+ let code = "";
3233
+ const mappings = [];
3234
+ const appendMapped = (value, absoluteStart) => {
3235
+ const mapped = mappedSource(value, absoluteStart);
3236
+ const offset = code.length;
3237
+ code += value;
3238
+ mappings.push(...mapped.mappings.map((mapping) => ({ ...mapping, offset: offset + mapping.offset })));
3239
+ };
3240
+ for (const imported of statement.imports) {
3241
+ const target = relative(imported.span);
3242
+ appendMapped(statement.source.slice(target.start, target.end), imported.span.start);
3243
+ if (!code.endsWith("\n") && !code.endsWith("\r"))
3244
+ code += "\n";
3245
+ }
3246
+ code += `export function ${factoryName}(${statement.captures.map((capture) => capture.name).join(", ")}) {\n`;
3247
+ appendMapped(body, statement.sourceSpan.start);
3248
+ if (code.length > 0 && !code.endsWith("\n") && !code.endsWith("\r"))
3249
+ code += "\n";
3250
+ const entries = statement.exports.map((item) => `${JSON.stringify(item.name)}: ${item.local}`).join(", ");
3251
+ code += `return { ${entries} };\n}\n`;
3252
+ return { code, mappings };
3253
+ }
3254
+ //# sourceMappingURL=emitter.js.map