xbintsc 0.3.18 → 0.3.35

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 (194) hide show
  1. package/README.md +33 -0
  2. package/dist/src/cli/main.js +124 -30
  3. package/dist/src/cli/main.js.map +1 -1
  4. package/dist/src/codegen/generator/calls/access.js +8 -1
  5. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  6. package/dist/src/codegen/generator/state.js +20 -0
  7. package/dist/src/codegen/generator/state.js.map +1 -1
  8. package/dist/src/codegen/generator/tables.d.ts +6 -0
  9. package/dist/src/codegen/generator/tables.js +38 -0
  10. package/dist/src/codegen/generator/tables.js.map +1 -1
  11. package/dist/src/driver/bundler/commonjs.d.ts +52 -0
  12. package/dist/src/driver/bundler/commonjs.js +493 -0
  13. package/dist/src/driver/bundler/commonjs.js.map +1 -0
  14. package/dist/src/driver/bundler/graph.d.ts +2 -1
  15. package/dist/src/driver/bundler/graph.js +32 -3
  16. package/dist/src/driver/bundler/graph.js.map +1 -1
  17. package/dist/src/driver/bundler/merge.d.ts +2 -1
  18. package/dist/src/driver/bundler/merge.js +16 -2
  19. package/dist/src/driver/bundler/merge.js.map +1 -1
  20. package/dist/src/driver/bundler/types.d.ts +8 -0
  21. package/dist/src/driver/compiler.d.ts +8 -1
  22. package/dist/src/driver/compiler.js +75 -7
  23. package/dist/src/driver/compiler.js.map +1 -1
  24. package/dist/src/driver/config.d.ts +53 -0
  25. package/dist/src/driver/config.js +141 -0
  26. package/dist/src/driver/config.js.map +1 -0
  27. package/dist/src/driver/icon.d.ts +62 -0
  28. package/dist/src/driver/icon.js +151 -0
  29. package/dist/src/driver/icon.js.map +1 -0
  30. package/dist/src/driver/index.d.ts +4 -0
  31. package/dist/src/driver/index.js +4 -0
  32. package/dist/src/driver/index.js.map +1 -1
  33. package/dist/src/driver/mac-bundle.d.ts +41 -0
  34. package/dist/src/driver/mac-bundle.js +123 -0
  35. package/dist/src/driver/mac-bundle.js.map +1 -0
  36. package/dist/src/driver/win-icon.d.ts +27 -0
  37. package/dist/src/driver/win-icon.js +80 -0
  38. package/dist/src/driver/win-icon.js.map +1 -0
  39. package/dist/src/extensions/gui/html.d.ts +25 -0
  40. package/dist/src/extensions/gui/html.js +203 -0
  41. package/dist/src/extensions/gui/html.js.map +1 -0
  42. package/dist/src/extensions/gui/index.js +11 -0
  43. package/dist/src/extensions/gui/index.js.map +1 -1
  44. package/dist/src/extensions/registry.d.ts +29 -0
  45. package/dist/src/extensions/registry.js +14 -0
  46. package/dist/src/extensions/registry.js.map +1 -1
  47. package/dist/src/index.d.ts +1 -1
  48. package/dist/src/index.js.map +1 -1
  49. package/dist/src/lexer/scanner/identifiers.js +4 -12
  50. package/dist/src/lexer/scanner/identifiers.js.map +1 -1
  51. package/dist/src/parser/statements.js +17 -4
  52. package/dist/src/parser/statements.js.map +1 -1
  53. package/dist/tests/cli/main.test.js +46 -1
  54. package/dist/tests/cli/main.test.js.map +1 -1
  55. package/dist/tests/driver/bundler-resolve.test.d.ts +1 -0
  56. package/dist/tests/driver/bundler-resolve.test.js +230 -0
  57. package/dist/tests/driver/bundler-resolve.test.js.map +1 -0
  58. package/dist/tests/driver/config.test.d.ts +1 -0
  59. package/dist/tests/driver/config.test.js +124 -0
  60. package/dist/tests/driver/config.test.js.map +1 -0
  61. package/dist/tests/driver/icon.test.d.ts +1 -0
  62. package/dist/tests/driver/icon.test.js +421 -0
  63. package/dist/tests/driver/icon.test.js.map +1 -0
  64. package/dist/tests/driver/modules.test.js +177 -0
  65. package/dist/tests/driver/modules.test.js.map +1 -1
  66. package/dist/tests/e2e/fetch.test.d.ts +12 -0
  67. package/dist/tests/e2e/fetch.test.js +272 -0
  68. package/dist/tests/e2e/fetch.test.js.map +1 -0
  69. package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
  70. package/dist/tests/e2e/gui-dom.test.js +102 -0
  71. package/dist/tests/e2e/gui-dom.test.js.map +1 -0
  72. package/dist/tests/e2e/gui-events.test.d.ts +5 -0
  73. package/dist/tests/e2e/gui-events.test.js +60 -0
  74. package/dist/tests/e2e/gui-events.test.js.map +1 -0
  75. package/dist/tests/e2e/gui-helpers.d.ts +31 -0
  76. package/dist/tests/e2e/gui-helpers.js +74 -0
  77. package/dist/tests/e2e/gui-helpers.js.map +1 -0
  78. package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
  79. package/dist/tests/e2e/gui-layout.test.js +88 -0
  80. package/dist/tests/e2e/gui-layout.test.js.map +1 -0
  81. package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
  82. package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
  83. package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
  84. package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
  85. package/dist/tests/e2e/gui-paint.test.js +111 -0
  86. package/dist/tests/e2e/gui-paint.test.js.map +1 -0
  87. package/dist/tests/e2e/gui-script.test.d.ts +5 -0
  88. package/dist/tests/e2e/gui-script.test.js +78 -0
  89. package/dist/tests/e2e/gui-script.test.js.map +1 -0
  90. package/dist/tests/e2e/gui-style.test.d.ts +5 -0
  91. package/dist/tests/e2e/gui-style.test.js +175 -0
  92. package/dist/tests/e2e/gui-style.test.js.map +1 -0
  93. package/dist/tests/e2e/icon.test.d.ts +7 -0
  94. package/dist/tests/e2e/icon.test.js +80 -0
  95. package/dist/tests/e2e/icon.test.js.map +1 -0
  96. package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
  97. package/dist/tests/e2e/npm-modules.test.js +47 -1
  98. package/dist/tests/e2e/npm-modules.test.js.map +1 -1
  99. package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
  100. package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
  101. package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
  102. package/dist/tests/extensions/gui-index.test.d.ts +1 -0
  103. package/dist/tests/extensions/gui-index.test.js +49 -0
  104. package/dist/tests/extensions/gui-index.test.js.map +1 -0
  105. package/dist/tests/extensions/gui.test.d.ts +1 -0
  106. package/dist/tests/extensions/gui.test.js +177 -0
  107. package/dist/tests/extensions/gui.test.js.map +1 -0
  108. package/dist/tests/extensions/registry.test.js +36 -0
  109. package/dist/tests/extensions/registry.test.js.map +1 -1
  110. package/dist/tests/parser/statements.test.js +11 -0
  111. package/dist/tests/parser/statements.test.js.map +1 -1
  112. package/dist/tests/public-api.test.d.ts +1 -0
  113. package/dist/tests/public-api.test.js +31 -0
  114. package/dist/tests/public-api.test.js.map +1 -0
  115. package/package.json +1 -1
  116. package/runtime/ext_gui/css.cpp +4 -517
  117. package/runtime/ext_gui/css_internal.h +27 -0
  118. package/runtime/ext_gui/css_match.cpp +195 -0
  119. package/runtime/ext_gui/css_selector.cpp +207 -0
  120. package/runtime/ext_gui/css_sheet.cpp +129 -0
  121. package/runtime/ext_gui/document.cpp +90 -0
  122. package/runtime/ext_gui/document.h +23 -0
  123. package/runtime/ext_gui/dom.cpp +43 -403
  124. package/runtime/ext_gui/dom.h +7 -0
  125. package/runtime/ext_gui/dom_api.cpp +164 -0
  126. package/runtime/ext_gui/dom_api.h +12 -0
  127. package/runtime/ext_gui/dom_api_document.cpp +96 -0
  128. package/runtime/ext_gui/dom_api_events.cpp +123 -0
  129. package/runtime/ext_gui/dom_api_internal.h +135 -0
  130. package/runtime/ext_gui/dom_api_node.cpp +329 -0
  131. package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
  132. package/runtime/ext_gui/dom_api_proto.cpp +130 -0
  133. package/runtime/ext_gui/dom_api_style.cpp +192 -0
  134. package/runtime/ext_gui/dom_internal.h +39 -0
  135. package/runtime/ext_gui/dom_parse.cpp +348 -0
  136. package/runtime/ext_gui/dom_serialize.cpp +54 -0
  137. package/runtime/ext_gui/gui.cpp +61 -245
  138. package/runtime/ext_gui/gui_engine.h +54 -0
  139. package/runtime/ext_gui/gui_events.cpp +294 -0
  140. package/runtime/ext_gui/gui_internal.h +29 -0
  141. package/runtime/ext_gui/layout.cpp +6 -597
  142. package/runtime/ext_gui/layout_flex.cpp +200 -0
  143. package/runtime/ext_gui/layout_flow.cpp +191 -0
  144. package/runtime/ext_gui/layout_flow_internal.h +149 -0
  145. package/runtime/ext_gui/layout_inline.cpp +181 -0
  146. package/runtime/ext_gui/layout_internal.h +20 -0
  147. package/runtime/ext_gui/renderer.cpp +15 -679
  148. package/runtime/ext_gui/renderer_image.cpp +233 -0
  149. package/runtime/ext_gui/renderer_internal.h +112 -0
  150. package/runtime/ext_gui/renderer_shaders.h +108 -0
  151. package/runtime/ext_gui/renderer_text.cpp +342 -0
  152. package/runtime/ext_gui/script.cpp +63 -0
  153. package/runtime/ext_gui/style.cpp +12 -660
  154. package/runtime/ext_gui/style_internal.h +33 -0
  155. package/runtime/ext_gui/style_print.cpp +113 -0
  156. package/runtime/ext_gui/style_ua.cpp +98 -0
  157. package/runtime/ext_gui/style_values.cpp +468 -0
  158. package/runtime/ext_gui/window.cpp +60 -0
  159. package/runtime/rt.h +6 -0
  160. package/runtime/rt_internal.h +4 -0
  161. package/runtime/xt_builtins.c +1 -0
  162. package/runtime/xt_containers/access.inc +32 -1
  163. package/runtime/xt_fetch/buffer.inc +64 -0
  164. package/runtime/xt_fetch/headers.inc +312 -0
  165. package/runtime/xt_fetch/request.inc +386 -0
  166. package/runtime/xt_fetch/response.inc +107 -0
  167. package/runtime/xt_fetch/socket.inc +72 -0
  168. package/runtime/xt_fetch/url.inc +108 -0
  169. package/runtime/xt_fetch.c +39 -0
  170. package/runtime/xt_stdlib2/set.inc +1 -1
  171. package/runtime/xt_typed_array.c +614 -0
  172. package/src/cli/main.ts +137 -29
  173. package/src/codegen/generator/calls/access.ts +9 -1
  174. package/src/codegen/generator/state.ts +20 -0
  175. package/src/codegen/generator/tables.ts +40 -0
  176. package/src/driver/bundler/commonjs.ts +553 -0
  177. package/src/driver/bundler/graph.ts +35 -2
  178. package/src/driver/bundler/merge.ts +18 -1
  179. package/src/driver/bundler/types.ts +8 -0
  180. package/src/driver/compiler.ts +85 -7
  181. package/src/driver/config.ts +173 -0
  182. package/src/driver/icon.ts +184 -0
  183. package/src/driver/index.ts +30 -0
  184. package/src/driver/mac-bundle.ts +156 -0
  185. package/src/driver/win-icon.ts +96 -0
  186. package/src/extensions/gui/html.ts +236 -0
  187. package/src/extensions/gui/index.ts +11 -0
  188. package/src/extensions/registry.ts +39 -0
  189. package/src/index.ts +1 -1
  190. package/src/lexer/scanner/identifiers.ts +4 -11
  191. package/src/parser/statements.ts +17 -4
  192. package/dist/tests/e2e/gui.test.d.ts +0 -12
  193. package/dist/tests/e2e/gui.test.js +0 -493
  194. package/dist/tests/e2e/gui.test.js.map +0 -1
package/src/cli/main.ts CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  import { spawnSync } from "node:child_process";
16
16
  import { readFileSync } from "node:fs";
17
+ import { dirname, resolve } from "node:path";
17
18
  import { pathToFileURL } from "node:url";
18
19
  import { formatDiagnostic, type Diagnostic } from "../diagnostics/diagnostic.js";
19
20
  import { SourceFile } from "../diagnostics/source.js";
@@ -25,6 +26,15 @@ import { realRunner } from "../driver/toolchain.js";
25
26
  import { createDefaultRegistry, type ExtensionRegistry } from "../extensions/registry.js";
26
27
  import { bundledExtensions } from "../extensions/catalog.js";
27
28
  import { nativeExtensionFromManifest } from "../extensions/native.js";
29
+ import { resolveResourceCompiler } from "../driver/win-icon.js";
30
+ import {
31
+ CONFIG_FILE_NAME,
32
+ findProjectConfig,
33
+ loadProjectConfig,
34
+ resolveConfigPaths,
35
+ type AppConfig,
36
+ type ProjectConfig,
37
+ } from "../driver/config.js";
28
38
 
29
39
  export interface CliIo {
30
40
  readonly stdout: (text: string) => void;
@@ -43,7 +53,18 @@ interface ParsedArgs {
43
53
  readonly passthrough: string[];
44
54
  }
45
55
 
46
- const VALUE_FLAGS = new Set(["output", "out", "emit", "optimize", "ext", "ext-native"]);
56
+ const VALUE_FLAGS = new Set([
57
+ "output",
58
+ "out",
59
+ "emit",
60
+ "optimize",
61
+ "ext",
62
+ "ext-native",
63
+ "config",
64
+ "icon",
65
+ "app-id",
66
+ "app-name",
67
+ ]);
47
68
 
48
69
  function parseArgs(argv: readonly string[]): ParsedArgs {
49
70
  const positionals: string[] = [];
@@ -95,29 +116,22 @@ function parseArgs(argv: readonly string[]): ParsedArgs {
95
116
  return { command: positionals.shift(), positionals, flags, passthrough };
96
117
  }
97
118
 
98
- function buildRegistry(flags: Map<string, string | boolean>): ExtensionRegistry {
119
+ function buildRegistry(extNames: readonly string[], nativeManifests: readonly string[]): ExtensionRegistry {
99
120
  const registry = createDefaultRegistry();
100
- const requested = flags.get("ext");
101
- if (typeof requested === "string") {
102
- const bundled = bundledExtensions();
103
- for (const name of requested.split(",").map((n) => n.trim()).filter(Boolean)) {
104
- const extension = bundled.find((candidate) => candidate.name === name);
105
- if (!extension) throw new Error(`Unknown extension '${name}'`);
106
- registry.register(extension);
107
- }
121
+ const bundled = bundledExtensions();
122
+ for (const name of extNames) {
123
+ const extension = bundled.find((candidate) => candidate.name === name);
124
+ if (!extension) throw new Error(`Unknown extension '${name}'`);
125
+ registry.register(extension);
108
126
  }
109
- // Each `--ext-native` value is a manifest path describing a pre-built C++ or
110
- // Rust library; several manifests may be comma separated.
111
- const native = flags.get("ext-native");
112
- if (typeof native === "string") {
113
- for (const manifest of native.split(",").map((n) => n.trim()).filter(Boolean)) {
114
- registry.register(nativeExtensionFromManifest(manifest));
115
- }
127
+ // Each manifest describes a pre-built C++ or Rust library.
128
+ for (const manifest of nativeManifests) {
129
+ registry.register(nativeExtensionFromManifest(manifest));
116
130
  }
117
131
  // Hint the extensions that ship with xbintsc but were not enabled, so a
118
132
  // missing `import` of a known module points at the flag that enables it
119
133
  // (`pass --ext node`) instead of failing later with a confusing error.
120
- for (const extension of bundledExtensions()) {
134
+ for (const extension of bundled) {
121
135
  if (!registry.has(extension.name)) registry.hintExtension(extension);
122
136
  }
123
137
  return registry;
@@ -131,6 +145,11 @@ function printDiagnostics(diagnostics: readonly Diagnostic[], fileName: string,
131
145
  source = undefined;
132
146
  }
133
147
  for (const diagnostic of diagnostics) {
148
+ // Driver-level diagnostics (icon, config, …) have no source location.
149
+ if (diagnostic.fileName === undefined && diagnostic.start === undefined) {
150
+ io.stderr(`error TS${diagnostic.code}: ${diagnostic.message}\n`);
151
+ continue;
152
+ }
134
153
  io.stderr(formatDiagnostic(diagnostic, source) + "\n");
135
154
  }
136
155
  }
@@ -153,6 +172,13 @@ Options:
153
172
  --ext <names> Comma separated extensions (e.g. node)
154
173
  --ext-native <m> Register a C++/Rust extension from a JSON manifest
155
174
  (comma separated for several)
175
+ --config <path> Use a project config (default: auto-detect
176
+ ${CONFIG_FILE_NAME})
177
+ --no-config Do not read any project config
178
+ --icon <path> Embed an application icon (PNG/ICO/ICNS)
179
+ --bundle macOS: also produce a .app bundle
180
+ --app-name <name> Bundle / display name
181
+ --app-id <id> macOS bundle identifier (e.g. com.example.demo)
156
182
  --force Ignore the incremental cache
157
183
  --verbose Print progress information
158
184
  `;
@@ -190,9 +216,70 @@ function doctor(io: CliIo): number {
190
216
  } catch {
191
217
  io.stdout("runtime lib: unavailable\n");
192
218
  }
219
+
220
+ try {
221
+ const toolchain = resolveToolchain();
222
+ const resource = resolveResourceCompiler(realRunner, toolchain.clang);
223
+ io.stdout(`icon res : ${resource ? `${resource.tool} (${resource.kind})` : "none (.exe icon disabled)"}\n`);
224
+ } catch {
225
+ io.stdout("icon res : unknown\n");
226
+ }
193
227
  return 0;
194
228
  }
195
229
 
230
+ type ConfigResolution =
231
+ | { readonly ok: true; readonly config: ProjectConfig }
232
+ | { readonly ok: false; readonly error: string };
233
+
234
+ /**
235
+ * Resolve the project config for a command: `--config <path>` selects one
236
+ * explicitly, `--no-config` disables discovery, otherwise we walk up from the
237
+ * entry file (or the cwd) looking for {@link CONFIG_FILE_NAME}.
238
+ */
239
+ function resolveProjectConfig(
240
+ flags: Map<string, string | boolean>,
241
+ cliEntry: string | undefined,
242
+ ): ConfigResolution {
243
+ try {
244
+ const explicit = flags.get("config");
245
+ if (typeof explicit === "string") {
246
+ return { ok: true, config: resolveConfigPaths(loadProjectConfig(explicit)) };
247
+ }
248
+ if (flags.has("no-config")) return { ok: true, config: {} };
249
+ const startDir = cliEntry ? dirname(resolve(cliEntry)) : process.cwd();
250
+ const found = findProjectConfig(startDir);
251
+ if (!found) return { ok: true, config: {} };
252
+ return { ok: true, config: resolveConfigPaths(loadProjectConfig(found)) };
253
+ } catch (error) {
254
+ return { ok: false, error: (error as Error).message };
255
+ }
256
+ }
257
+
258
+ /** Merge `app.*` config with the CLI overrides (`--icon`, `--bundle`, …). */
259
+ function mergeAppConfig(flags: Map<string, string | boolean>, config: ProjectConfig): AppConfig {
260
+ const base = config.app ?? {};
261
+ const name = typeof flags.get("app-name") === "string" ? (flags.get("app-name") as string) : base.name;
262
+ const bundleId = typeof flags.get("app-id") === "string" ? (flags.get("app-id") as string) : base.bundleId;
263
+ const bundle = flags.has("bundle") ? true : base.bundle;
264
+ const icon = typeof flags.get("icon") === "string" ? (flags.get("icon") as string) : base.icon;
265
+ return {
266
+ ...(name !== undefined ? { name } : {}),
267
+ ...(bundleId !== undefined ? { bundleId } : {}),
268
+ ...(bundle !== undefined ? { bundle } : {}),
269
+ ...(icon !== undefined ? { icon } : {}),
270
+ };
271
+ }
272
+
273
+ /** Split a comma-separated CLI flag into a trimmed, non-empty list. */
274
+ function listFlag(flags: Map<string, string | boolean>, name: string): string[] | undefined {
275
+ const value = flags.get(name);
276
+ if (typeof value !== "string") return undefined;
277
+ return value
278
+ .split(",")
279
+ .map((entry) => entry.trim())
280
+ .filter(Boolean);
281
+ }
282
+
196
283
  export function run(argv: readonly string[], io: CliIo = defaultIo): number {
197
284
  const args = parseArgs(argv);
198
285
  const command = args.command;
@@ -212,12 +299,20 @@ export function run(argv: readonly string[], io: CliIo = defaultIo): number {
212
299
  }
213
300
 
214
301
  if (command === "emit") {
215
- const entry = args.positionals[0];
302
+ const cliEntry = args.positionals[0];
303
+ const resolved = resolveProjectConfig(args.flags, cliEntry);
304
+ if (!resolved.ok) {
305
+ io.stderr(`xbintsc: ${resolved.error}\n`);
306
+ return 1;
307
+ }
308
+ const entry = cliEntry ?? resolved.config.entry;
216
309
  if (!entry) {
217
- io.stderr("xbintsc: emit requires a source file\n");
310
+ io.stderr(`xbintsc: emit requires a source file (or 'entry' in ${CONFIG_FILE_NAME})\n`);
218
311
  return 1;
219
312
  }
220
- const registry = buildRegistry(args.flags);
313
+ const extNames = listFlag(args.flags, "ext") ?? resolved.config.extensions ?? [];
314
+ const nativeManifests = listFlag(args.flags, "ext-native") ?? resolved.config.extNative ?? [];
315
+ const registry = buildRegistry(extNames, nativeManifests);
221
316
  const { ir, diagnostics } = compileEntry(entry, registry);
222
317
  if (diagnostics.some((d) => d.category === "error")) {
223
318
  printDiagnostics(diagnostics, entry, io);
@@ -228,21 +323,33 @@ export function run(argv: readonly string[], io: CliIo = defaultIo): number {
228
323
  }
229
324
 
230
325
  if (command === "build" || command === "run") {
231
- const entry = args.positionals[0];
326
+ const cliEntry = args.positionals[0];
327
+ const resolved = resolveProjectConfig(args.flags, cliEntry);
328
+ if (!resolved.ok) {
329
+ io.stderr(`xbintsc: ${resolved.error}\n`);
330
+ return 1;
331
+ }
332
+ const config = resolved.config;
333
+ const entry = cliEntry ?? config.entry;
232
334
  if (!entry) {
233
- io.stderr(`xbintsc: ${command} requires a source file\n`);
335
+ io.stderr(`xbintsc: ${command} requires a source file (or 'entry' in ${CONFIG_FILE_NAME})\n`);
234
336
  return 1;
235
337
  }
236
338
  const emit = (args.flags.get("emit") as EmitKind | undefined) ?? "exe";
237
- const optimize = (args.flags.get("optimize") as string | undefined) ?? "2";
339
+ const optimize = (args.flags.get("optimize") as string | undefined) ?? config.optimize ?? "2";
340
+ const extNames = listFlag(args.flags, "ext") ?? config.extensions ?? [];
341
+ const nativeManifests = listFlag(args.flags, "ext-native") ?? config.extNative ?? [];
342
+ const registry = buildRegistry(extNames, nativeManifests);
343
+
238
344
  const result = build(entry, {
239
- output: typeof args.flags.get("output") === "string" ? (args.flags.get("output") as string) : undefined,
240
- outDir: typeof args.flags.get("out") === "string" ? (args.flags.get("out") as string) : undefined,
345
+ output: typeof args.flags.get("output") === "string" ? (args.flags.get("output") as string) : config.output,
346
+ outDir: typeof args.flags.get("out") === "string" ? (args.flags.get("out") as string) : config.outDir,
241
347
  emit,
242
348
  optimize: optimize as "0" | "1" | "2" | "3",
243
- force: Boolean(args.flags.get("force")),
349
+ force: Boolean(args.flags.get("force")) || config.force === true,
244
350
  verbose: Boolean(args.flags.get("verbose")),
245
- extensions: buildRegistry(args.flags),
351
+ extensions: registry,
352
+ app: mergeAppConfig(args.flags, config),
246
353
  });
247
354
 
248
355
  if (result.diagnostics.some((d) => d.category === "error")) {
@@ -251,7 +358,8 @@ export function run(argv: readonly string[], io: CliIo = defaultIo): number {
251
358
  }
252
359
 
253
360
  if (command === "build") {
254
- io.stdout(`xbintsc: wrote ${result.outputPath}${result.cached ? " (cached)" : ""}\n`);
361
+ const bundle = result.bundlePath ? ` (bundle: ${result.bundlePath})` : "";
362
+ io.stdout(`xbintsc: wrote ${result.outputPath}${result.cached ? " (cached)" : ""}${bundle}\n`);
255
363
  return 0;
256
364
  }
257
365
 
@@ -13,7 +13,7 @@ import {
13
13
  type PropertyAccessExpression,
14
14
  } from "../../../ast/nodes.js";
15
15
  import { i64, numberLiteral, XT_TRUE, XT_UNDEFINED } from "../../values.js";
16
- import { MATH_CONSTANTS, NAMESPACE_PROPERTIES, NUMBER_CONSTANTS } from "../tables.js";
16
+ import { MATH_CONSTANTS, NAMESPACE_PROPERTIES, NUMBER_CONSTANTS, TYPED_ARRAYS } from "../tables.js";
17
17
  import type { Generator } from "../generator.js";
18
18
 
19
19
  export interface AccessCallMethods {
@@ -121,6 +121,14 @@ export const accessCallMethods: AccessCallMethods = {
121
121
  return result;
122
122
  }
123
123
  }
124
+ if (
125
+ node.expression.kind === SyntaxKind.Identifier &&
126
+ !this.binding.symbolOfIdentifier.get(node.expression as Identifier) &&
127
+ node.name.text === "BYTES_PER_ELEMENT"
128
+ ) {
129
+ const typed = TYPED_ARRAYS[(node.expression as Identifier).text];
130
+ if (typed) return numberLiteral(typed.bytes);
131
+ }
124
132
  const object = this.emitExpression(node.expression);
125
133
  return this.emitPropertyGet(object, node.name.text);
126
134
  },
@@ -116,6 +116,24 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
116
116
  "declare i64 @xt_os_static(i64, i32, i64*)",
117
117
  "declare i64 @xt_buffer_static(i64, i32, i64*)",
118
118
  "declare i64 @xt_buffer_ctor(i32, i64*)",
119
+ "declare i64 @xt_ta_u8_ctor(i32, i64*)",
120
+ "declare i64 @xt_ta_u8_static(i64, i32, i64*)",
121
+ "declare i64 @xt_ta_i8_ctor(i32, i64*)",
122
+ "declare i64 @xt_ta_i8_static(i64, i32, i64*)",
123
+ "declare i64 @xt_ta_u8c_ctor(i32, i64*)",
124
+ "declare i64 @xt_ta_u8c_static(i64, i32, i64*)",
125
+ "declare i64 @xt_ta_u16_ctor(i32, i64*)",
126
+ "declare i64 @xt_ta_u16_static(i64, i32, i64*)",
127
+ "declare i64 @xt_ta_i16_ctor(i32, i64*)",
128
+ "declare i64 @xt_ta_i16_static(i64, i32, i64*)",
129
+ "declare i64 @xt_ta_u32_ctor(i32, i64*)",
130
+ "declare i64 @xt_ta_u32_static(i64, i32, i64*)",
131
+ "declare i64 @xt_ta_i32_ctor(i32, i64*)",
132
+ "declare i64 @xt_ta_i32_static(i64, i32, i64*)",
133
+ "declare i64 @xt_ta_f32_ctor(i32, i64*)",
134
+ "declare i64 @xt_ta_f32_static(i64, i32, i64*)",
135
+ "declare i64 @xt_ta_f64_ctor(i32, i64*)",
136
+ "declare i64 @xt_ta_f64_static(i64, i32, i64*)",
119
137
  "declare i64 @xt_stream_static(i64, i32, i64*)",
120
138
  "declare i64 @xt_readable_ctor(i32, i64*)",
121
139
  "declare i64 @xt_writable_ctor(i32, i64*)",
@@ -219,6 +237,7 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
219
237
  "declare i64 @xt_clear_timeout(i32, i64*)",
220
238
  "declare i64 @xt_set_interval(i32, i64*)",
221
239
  "declare i64 @xt_clear_interval(i32, i64*)",
240
+ "declare i64 @xt_fetch(i32, i64*)",
222
241
  "declare i64 @xt_number_ctor(i32, i64*)",
223
242
  "declare i64 @xt_bigint_ctor(i32, i64*)",
224
243
  "declare i64 @xt_bigint_static(i64, i32, i64*)",
@@ -254,6 +273,7 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
254
273
  "declare i64 @xt_builtin_value_clearTimeout(i64, i64, i32, i64*)",
255
274
  "declare i64 @xt_builtin_value_setInterval(i64, i64, i32, i64*)",
256
275
  "declare i64 @xt_builtin_value_clearInterval(i64, i64, i32, i64*)",
276
+ "declare i64 @xt_builtin_value_fetch(i64, i64, i32, i64*)",
257
277
  "declare i64 @xt_builtin_value_number(i64, i64, i32, i64*)",
258
278
  "declare i64 @xt_builtin_value_string(i64, i64, i32, i64*)",
259
279
  "declare i64 @xt_builtin_value_boolean(i64, i64, i32, i64*)",
@@ -127,6 +127,7 @@ export const GLOBAL_FUNCTIONS: Record<string, string> = {
127
127
  clearTimeout: "xt_clear_timeout",
128
128
  setInterval: "xt_set_interval",
129
129
  clearInterval: "xt_clear_interval",
130
+ fetch: "xt_fetch",
130
131
  Number: "xt_number_ctor",
131
132
  String: "xt_string_ctor",
132
133
  Boolean: "xt_boolean_ctor",
@@ -150,6 +151,7 @@ export const BUILTIN_FUNCTION_VALUES: Record<string, string> = {
150
151
  clearTimeout: "xt_builtin_value_clearTimeout",
151
152
  setInterval: "xt_builtin_value_setInterval",
152
153
  clearInterval: "xt_builtin_value_clearInterval",
154
+ fetch: "xt_builtin_value_fetch",
153
155
  Number: "xt_builtin_value_number",
154
156
  String: "xt_builtin_value_string",
155
157
  Boolean: "xt_builtin_value_boolean",
@@ -157,6 +159,42 @@ export const BUILTIN_FUNCTION_VALUES: Record<string, string> = {
157
159
  Symbol: "xt_builtin_value_symbol",
158
160
  };
159
161
 
162
+ /** Typed-array globals: constructor, static dispatcher and element width. */
163
+ export const TYPED_ARRAYS: Record<string, { ctor: string; static: string; bytes: number }> = {
164
+ Uint8Array: { ctor: "xt_ta_u8_ctor", static: "xt_ta_u8_static", bytes: 1 },
165
+ Int8Array: { ctor: "xt_ta_i8_ctor", static: "xt_ta_i8_static", bytes: 1 },
166
+ Uint8ClampedArray: { ctor: "xt_ta_u8c_ctor", static: "xt_ta_u8c_static", bytes: 1 },
167
+ Uint16Array: { ctor: "xt_ta_u16_ctor", static: "xt_ta_u16_static", bytes: 2 },
168
+ Int16Array: { ctor: "xt_ta_i16_ctor", static: "xt_ta_i16_static", bytes: 2 },
169
+ Uint32Array: { ctor: "xt_ta_u32_ctor", static: "xt_ta_u32_static", bytes: 4 },
170
+ Int32Array: { ctor: "xt_ta_i32_ctor", static: "xt_ta_i32_static", bytes: 4 },
171
+ Float32Array: { ctor: "xt_ta_f32_ctor", static: "xt_ta_f32_static", bytes: 4 },
172
+ Float64Array: { ctor: "xt_ta_f64_ctor", static: "xt_ta_f64_static", bytes: 8 },
173
+ };
174
+
175
+ const TYPED_ARRAY_CTORS: Record<string, string> = {
176
+ Uint8Array: "xt_ta_u8_ctor",
177
+ Int8Array: "xt_ta_i8_ctor",
178
+ Uint8ClampedArray: "xt_ta_u8c_ctor",
179
+ Uint16Array: "xt_ta_u16_ctor",
180
+ Int16Array: "xt_ta_i16_ctor",
181
+ Uint32Array: "xt_ta_u32_ctor",
182
+ Int32Array: "xt_ta_i32_ctor",
183
+ Float32Array: "xt_ta_f32_ctor",
184
+ Float64Array: "xt_ta_f64_ctor",
185
+ };
186
+ const TYPED_ARRAY_STATICS: Record<string, string> = {
187
+ Uint8Array: "xt_ta_u8_static",
188
+ Int8Array: "xt_ta_i8_static",
189
+ Uint8ClampedArray: "xt_ta_u8c_static",
190
+ Uint16Array: "xt_ta_u16_static",
191
+ Int16Array: "xt_ta_i16_static",
192
+ Uint32Array: "xt_ta_u32_static",
193
+ Int32Array: "xt_ta_i32_static",
194
+ Float32Array: "xt_ta_f32_static",
195
+ Float64Array: "xt_ta_f64_static",
196
+ };
197
+
160
198
  /** Global namespaces whose static methods map to runtime dispatchers. */
161
199
  export const NAMESPACE_STATICS: Record<string, string> = {
162
200
  Math: "xt_math_call",
@@ -186,6 +224,7 @@ export const NAMESPACE_STATICS: Record<string, string> = {
186
224
  util: "xt_util_static",
187
225
  querystring: "xt_querystring_static",
188
226
  assert: "xt_assert_static",
227
+ ...TYPED_ARRAY_STATICS,
189
228
  };
190
229
 
191
230
  /** Namespace identifiers whose property access maps to a runtime getter. */
@@ -213,6 +252,7 @@ export const CTOR_FUNCTIONS: Record<string, string> = {
213
252
  Server: "xt_net_server_ctor",
214
253
  EventEmitter: "xt_event_emitter_ctor",
215
254
  ...ERROR_CONSTRUCTORS,
255
+ ...TYPED_ARRAY_CTORS,
216
256
  };
217
257
 
218
258
  export const BUILTIN_METHODS = new Set<string>([