xbintsc 0.3.25 → 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 (154) 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.js +14 -0
  15. package/dist/src/driver/bundler/graph.js.map +1 -1
  16. package/dist/src/driver/bundler/merge.js +14 -0
  17. package/dist/src/driver/bundler/merge.js.map +1 -1
  18. package/dist/src/driver/bundler/types.d.ts +8 -0
  19. package/dist/src/driver/compiler.d.ts +8 -1
  20. package/dist/src/driver/compiler.js +73 -5
  21. package/dist/src/driver/compiler.js.map +1 -1
  22. package/dist/src/driver/config.d.ts +53 -0
  23. package/dist/src/driver/config.js +141 -0
  24. package/dist/src/driver/config.js.map +1 -0
  25. package/dist/src/driver/icon.d.ts +62 -0
  26. package/dist/src/driver/icon.js +151 -0
  27. package/dist/src/driver/icon.js.map +1 -0
  28. package/dist/src/driver/index.d.ts +4 -0
  29. package/dist/src/driver/index.js +4 -0
  30. package/dist/src/driver/index.js.map +1 -1
  31. package/dist/src/driver/mac-bundle.d.ts +41 -0
  32. package/dist/src/driver/mac-bundle.js +123 -0
  33. package/dist/src/driver/mac-bundle.js.map +1 -0
  34. package/dist/src/driver/win-icon.d.ts +27 -0
  35. package/dist/src/driver/win-icon.js +80 -0
  36. package/dist/src/driver/win-icon.js.map +1 -0
  37. package/dist/src/parser/statements.js +17 -4
  38. package/dist/src/parser/statements.js.map +1 -1
  39. package/dist/tests/cli/main.test.js +46 -1
  40. package/dist/tests/cli/main.test.js.map +1 -1
  41. package/dist/tests/driver/config.test.d.ts +1 -0
  42. package/dist/tests/driver/config.test.js +124 -0
  43. package/dist/tests/driver/config.test.js.map +1 -0
  44. package/dist/tests/driver/icon.test.d.ts +1 -0
  45. package/dist/tests/driver/icon.test.js +421 -0
  46. package/dist/tests/driver/icon.test.js.map +1 -0
  47. package/dist/tests/driver/modules.test.js +109 -0
  48. package/dist/tests/driver/modules.test.js.map +1 -1
  49. package/dist/tests/e2e/fetch.test.d.ts +12 -0
  50. package/dist/tests/e2e/fetch.test.js +272 -0
  51. package/dist/tests/e2e/fetch.test.js.map +1 -0
  52. package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
  53. package/dist/tests/e2e/gui-dom.test.js +102 -0
  54. package/dist/tests/e2e/gui-dom.test.js.map +1 -0
  55. package/dist/tests/e2e/gui-events.test.d.ts +5 -0
  56. package/dist/tests/e2e/gui-events.test.js +60 -0
  57. package/dist/tests/e2e/gui-events.test.js.map +1 -0
  58. package/dist/tests/e2e/gui-helpers.d.ts +31 -0
  59. package/dist/tests/e2e/gui-helpers.js +74 -0
  60. package/dist/tests/e2e/gui-helpers.js.map +1 -0
  61. package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
  62. package/dist/tests/e2e/gui-layout.test.js +88 -0
  63. package/dist/tests/e2e/gui-layout.test.js.map +1 -0
  64. package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
  65. package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
  66. package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
  67. package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
  68. package/dist/tests/e2e/gui-paint.test.js +111 -0
  69. package/dist/tests/e2e/gui-paint.test.js.map +1 -0
  70. package/dist/tests/e2e/gui-script.test.d.ts +5 -0
  71. package/dist/tests/e2e/gui-script.test.js +78 -0
  72. package/dist/tests/e2e/gui-script.test.js.map +1 -0
  73. package/dist/tests/e2e/gui-style.test.d.ts +5 -0
  74. package/dist/tests/e2e/gui-style.test.js +175 -0
  75. package/dist/tests/e2e/gui-style.test.js.map +1 -0
  76. package/dist/tests/e2e/icon.test.d.ts +7 -0
  77. package/dist/tests/e2e/icon.test.js +80 -0
  78. package/dist/tests/e2e/icon.test.js.map +1 -0
  79. package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
  80. package/dist/tests/e2e/npm-modules.test.js +47 -1
  81. package/dist/tests/e2e/npm-modules.test.js.map +1 -1
  82. package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
  83. package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
  84. package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
  85. package/dist/tests/parser/statements.test.js +11 -0
  86. package/dist/tests/parser/statements.test.js.map +1 -1
  87. package/package.json +1 -1
  88. package/runtime/ext_gui/css.cpp +4 -517
  89. package/runtime/ext_gui/css_internal.h +27 -0
  90. package/runtime/ext_gui/css_match.cpp +195 -0
  91. package/runtime/ext_gui/css_selector.cpp +207 -0
  92. package/runtime/ext_gui/css_sheet.cpp +129 -0
  93. package/runtime/ext_gui/dom.cpp +7 -403
  94. package/runtime/ext_gui/dom_api.cpp +63 -1146
  95. package/runtime/ext_gui/dom_api_document.cpp +96 -0
  96. package/runtime/ext_gui/dom_api_events.cpp +123 -0
  97. package/runtime/ext_gui/dom_api_internal.h +135 -0
  98. package/runtime/ext_gui/dom_api_node.cpp +329 -0
  99. package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
  100. package/runtime/ext_gui/dom_api_proto.cpp +130 -0
  101. package/runtime/ext_gui/dom_api_style.cpp +192 -0
  102. package/runtime/ext_gui/dom_internal.h +39 -0
  103. package/runtime/ext_gui/dom_parse.cpp +348 -0
  104. package/runtime/ext_gui/dom_serialize.cpp +54 -0
  105. package/runtime/ext_gui/gui.cpp +56 -286
  106. package/runtime/ext_gui/gui_events.cpp +294 -0
  107. package/runtime/ext_gui/gui_internal.h +29 -0
  108. package/runtime/ext_gui/layout.cpp +6 -597
  109. package/runtime/ext_gui/layout_flex.cpp +200 -0
  110. package/runtime/ext_gui/layout_flow.cpp +191 -0
  111. package/runtime/ext_gui/layout_flow_internal.h +149 -0
  112. package/runtime/ext_gui/layout_inline.cpp +181 -0
  113. package/runtime/ext_gui/layout_internal.h +20 -0
  114. package/runtime/ext_gui/renderer.cpp +15 -679
  115. package/runtime/ext_gui/renderer_image.cpp +233 -0
  116. package/runtime/ext_gui/renderer_internal.h +112 -0
  117. package/runtime/ext_gui/renderer_shaders.h +108 -0
  118. package/runtime/ext_gui/renderer_text.cpp +342 -0
  119. package/runtime/ext_gui/style.cpp +12 -660
  120. package/runtime/ext_gui/style_internal.h +33 -0
  121. package/runtime/ext_gui/style_print.cpp +113 -0
  122. package/runtime/ext_gui/style_ua.cpp +98 -0
  123. package/runtime/ext_gui/style_values.cpp +468 -0
  124. package/runtime/rt.h +6 -0
  125. package/runtime/rt_internal.h +4 -0
  126. package/runtime/xt_builtins.c +1 -0
  127. package/runtime/xt_containers/access.inc +32 -1
  128. package/runtime/xt_fetch/buffer.inc +64 -0
  129. package/runtime/xt_fetch/headers.inc +312 -0
  130. package/runtime/xt_fetch/request.inc +386 -0
  131. package/runtime/xt_fetch/response.inc +107 -0
  132. package/runtime/xt_fetch/socket.inc +72 -0
  133. package/runtime/xt_fetch/url.inc +108 -0
  134. package/runtime/xt_fetch.c +39 -0
  135. package/runtime/xt_stdlib2/set.inc +1 -1
  136. package/runtime/xt_typed_array.c +614 -0
  137. package/src/cli/main.ts +137 -29
  138. package/src/codegen/generator/calls/access.ts +9 -1
  139. package/src/codegen/generator/state.ts +20 -0
  140. package/src/codegen/generator/tables.ts +40 -0
  141. package/src/driver/bundler/commonjs.ts +553 -0
  142. package/src/driver/bundler/graph.ts +14 -0
  143. package/src/driver/bundler/merge.ts +15 -0
  144. package/src/driver/bundler/types.ts +8 -0
  145. package/src/driver/compiler.ts +83 -5
  146. package/src/driver/config.ts +173 -0
  147. package/src/driver/icon.ts +184 -0
  148. package/src/driver/index.ts +30 -0
  149. package/src/driver/mac-bundle.ts +156 -0
  150. package/src/driver/win-icon.ts +96 -0
  151. package/src/parser/statements.ts +17 -4
  152. package/dist/tests/e2e/gui.test.d.ts +0 -12
  153. package/dist/tests/e2e/gui.test.js +0 -702
  154. package/dist/tests/e2e/gui.test.js.map +0 -1
@@ -0,0 +1,156 @@
1
+ /**
2
+ * macOS `.app` bundle generation.
3
+ *
4
+ * A bare Mach-O executable cannot carry a Finder icon, so when `app.bundle` is
5
+ * enabled on macOS the driver lays out a minimal bundle next to the executable:
6
+ *
7
+ * Demo.app/Contents/Info.plist
8
+ * Demo.app/Contents/MacOS/Demo
9
+ * Demo.app/Contents/Resources/AppIcon.icns
10
+ *
11
+ * An `.icns` input is copied verbatim; a `.png` is converted with the system
12
+ * `sips` + `iconutil` tools when available, otherwise the PNG is shipped and the
13
+ * app relies on the runtime Dock icon (set by the `gui` extension).
14
+ */
15
+
16
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
17
+ import { dirname, join } from "node:path";
18
+ import type { IconInfo } from "./icon.js";
19
+ import type { Runner } from "./toolchain.js";
20
+
21
+ export interface MacBundleOptions {
22
+ readonly executablePath: string;
23
+ /** Display name; also the executable name inside the bundle. */
24
+ readonly name: string;
25
+ readonly bundleId: string;
26
+ readonly icon?: IconInfo;
27
+ readonly runner: Runner;
28
+ readonly env?: Record<string, string>;
29
+ }
30
+
31
+ /** `<dir>/<name>.app` for an executable at `<dir>/<name>`. */
32
+ export function bundlePathFor(executablePath: string, name: string): string {
33
+ return join(dirname(executablePath), `${name}.app`);
34
+ }
35
+
36
+ /** Escape the five XML predefined entities for the plist values. */
37
+ function xmlEscape(text: string): string {
38
+ return text
39
+ .replace(/&/g, "&amp;")
40
+ .replace(/</g, "&lt;")
41
+ .replace(/>/g, "&gt;")
42
+ .replace(/"/g, "&quot;");
43
+ }
44
+
45
+ export interface PlistOptions {
46
+ readonly name: string;
47
+ readonly bundleId: string;
48
+ readonly executable: string;
49
+ readonly iconFile?: string;
50
+ }
51
+
52
+ /** Render a minimal `Info.plist` for a GUI application bundle. */
53
+ export function infoPlist(options: PlistOptions): string {
54
+ const entries: [string, string][] = [
55
+ ["CFBundleName", options.name],
56
+ ["CFBundleDisplayName", options.name],
57
+ ["CFBundleIdentifier", options.bundleId],
58
+ ["CFBundleExecutable", options.executable],
59
+ ["CFBundlePackageType", "APPL"],
60
+ ["CFBundleInfoDictionaryVersion", "6.0"],
61
+ ["CFBundleShortVersionString", "1.0.0"],
62
+ ["CFBundleVersion", "1"],
63
+ ["LSMinimumSystemVersion", "10.13"],
64
+ ["NSHighResolutionCapable", "true"],
65
+ ];
66
+ if (options.iconFile) entries.push(["CFBundleIconFile", options.iconFile]);
67
+ const body = entries
68
+ .map(([key, value]) => `\t<key>${key}</key>\n\t<string>${xmlEscape(value)}</string>`)
69
+ .join("\n");
70
+ return [
71
+ '<?xml version="1.0" encoding="UTF-8"?>',
72
+ '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
73
+ '<plist version="1.0">',
74
+ "<dict>",
75
+ body,
76
+ "</dict>",
77
+ "</plist>",
78
+ "",
79
+ ].join("\n");
80
+ }
81
+
82
+ const ICONSET_SIZES = [16, 32, 64, 128, 256, 512] as const;
83
+
84
+ /** Convert a PNG to `.icns` via `sips` + `iconutil`; false when unavailable. */
85
+ function convertPngToIcns(
86
+ runner: Runner,
87
+ pngPath: string,
88
+ outIcns: string,
89
+ env?: Record<string, string>,
90
+ ): boolean {
91
+ const iconsetDir = join(dirname(outIcns), "AppIcon.iconset");
92
+ mkdirSync(iconsetDir, { recursive: true });
93
+ try {
94
+ for (const size of ICONSET_SIZES) {
95
+ for (const scale of [1, 2] as const) {
96
+ const pixels = size * scale;
97
+ if (pixels > 1024) continue;
98
+ const suffix = scale === 1 ? "" : "@2x";
99
+ const out = join(iconsetDir, `icon_${size}x${size}${suffix}.png`);
100
+ const result = runner.run(
101
+ "sips",
102
+ ["-z", String(pixels), String(pixels), pngPath, "--out", out],
103
+ { env },
104
+ );
105
+ if (result.status !== 0) return false;
106
+ }
107
+ }
108
+ const result = runner.run("iconutil", ["-c", "icns", iconsetDir, "-o", outIcns], { env });
109
+ return result.status === 0 && existsSync(outIcns);
110
+ } catch {
111
+ return false;
112
+ } finally {
113
+ rmSync(iconsetDir, { recursive: true, force: true });
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Lay out the `.app` bundle containing a copy of `executablePath` and, when
119
+ * available, the icon. Returns the bundle path. Never throws for a missing
120
+ * image-conversion tool: it falls back to shipping the PNG.
121
+ */
122
+ export function packageMacApp(options: MacBundleOptions): string {
123
+ const { executablePath, name, bundleId, icon, runner } = options;
124
+ const bundleDir = bundlePathFor(executablePath, name);
125
+ const contents = join(bundleDir, "Contents");
126
+ const macosDir = join(contents, "MacOS");
127
+ const resourcesDir = join(contents, "Resources");
128
+ mkdirSync(macosDir, { recursive: true });
129
+ mkdirSync(resourcesDir, { recursive: true });
130
+
131
+ const innerExecutable = join(macosDir, name);
132
+ copyFileSync(executablePath, innerExecutable);
133
+ chmodSync(innerExecutable, 0o755);
134
+
135
+ let iconFile: string | undefined;
136
+ if (icon) {
137
+ const icnsPath = join(resourcesDir, "AppIcon.icns");
138
+ if (icon.format === "icns") {
139
+ copyFileSync(icon.path, icnsPath);
140
+ iconFile = "AppIcon";
141
+ } else if (icon.format === "png") {
142
+ if (convertPngToIcns(runner, icon.path, icnsPath, options.env)) {
143
+ iconFile = "AppIcon";
144
+ } else {
145
+ copyFileSync(icon.path, join(resourcesDir, "AppIcon.png"));
146
+ iconFile = "AppIcon.png";
147
+ }
148
+ }
149
+ }
150
+
151
+ writeFileSync(
152
+ join(contents, "Info.plist"),
153
+ infoPlist({ name, bundleId, executable: name, ...(iconFile ? { iconFile } : {}) }),
154
+ );
155
+ return bundleDir;
156
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Windows PE icon resource.
3
+ *
4
+ * Windows reads the application icon from a resource section in the `.exe`, so
5
+ * an embedded blob is not enough: the icon is wrapped in a `.rc` script and
6
+ * compiled to a resource object that is linked into the executable. `llvm-rc`
7
+ * (shipping with clang) is preferred; MinGW `windres` is the fallback. Both are
8
+ * optional — a missing resource compiler degrades to the runtime window icon
9
+ * instead of failing the build.
10
+ */
11
+
12
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
13
+ import { dirname, join } from "node:path";
14
+ import { hashParts } from "./cache.js";
15
+ import { IconError, toIcoBytes, type IconInfo } from "./icon.js";
16
+ import type { Runner } from "./toolchain.js";
17
+
18
+ export type ResourceCompilerKind = "llvm-rc" | "windres";
19
+
20
+ export interface ResourceCompiler {
21
+ readonly tool: string;
22
+ readonly kind: ResourceCompilerKind;
23
+ }
24
+
25
+ /**
26
+ * Locate a resource compiler. `xbintsc_RC` wins, then `llvm-rc` next to the
27
+ * resolved clang, then `llvm-rc` and `windres` on `PATH`.
28
+ */
29
+ export function resolveResourceCompiler(runner: Runner, clang: string): ResourceCompiler | undefined {
30
+ const exe = process.platform === "win32" ? ".exe" : "";
31
+ // An explicit override is trusted: probe it and fall back rather than
32
+ // rejecting it on a path prefix check (it may be a bare command on PATH).
33
+ const override = process.env.xbintsc_RC;
34
+ if (override) {
35
+ const kind: ResourceCompilerKind = /windres/i.test(override) ? "windres" : "llvm-rc";
36
+ try {
37
+ if (runner.run(override, ["--version"]).status === 0) return { tool: override, kind };
38
+ } catch {
39
+ // Fall through to the discovered compilers.
40
+ }
41
+ }
42
+ const candidates: ResourceCompiler[] = [];
43
+ if (clang && (clang.includes("/") || clang.includes("\\"))) {
44
+ candidates.push({ tool: join(dirname(clang), `llvm-rc${exe}`), kind: "llvm-rc" });
45
+ }
46
+ candidates.push({ tool: `llvm-rc${exe}`, kind: "llvm-rc" });
47
+ candidates.push({ tool: `windres${exe}`, kind: "windres" });
48
+
49
+ for (const candidate of candidates) {
50
+ if ((candidate.tool.includes("/") || candidate.tool.includes("\\")) && !existsSync(candidate.tool)) continue;
51
+ try {
52
+ if (runner.run(candidate.tool, ["--version"]).status === 0) return candidate;
53
+ } catch {
54
+ // Not runnable; try the next candidate.
55
+ }
56
+ }
57
+ return undefined;
58
+ }
59
+
60
+ /**
61
+ * Compile the icon into a linkable PE resource object (`.res` for llvm-rc, a
62
+ * COFF `.o` for windres). Cached by contents and compiler kind.
63
+ */
64
+ export function ensureWindowsIconResource(
65
+ runner: Runner,
66
+ cacheDir: string,
67
+ icon: IconInfo,
68
+ compiler: ResourceCompiler,
69
+ env?: Record<string, string>,
70
+ ): string {
71
+ const icoBytes = toIcoBytes(icon);
72
+ const key = hashParts(["icon-res", compiler.kind, Buffer.from(icoBytes).toString("base64")]);
73
+ const icoName = `icon-${key}.ico`;
74
+ const icoPath = join(cacheDir, icoName);
75
+ const rcPath = join(cacheDir, `icon-${key}.rc`);
76
+ const objectPath = join(cacheDir, `icon-${key}.${compiler.kind === "windres" ? "o" : "res"}`);
77
+ if (existsSync(objectPath)) return objectPath;
78
+
79
+ mkdirSync(cacheDir, { recursive: true });
80
+ writeFileSync(icoPath, icoBytes);
81
+ // The .rc references the .ico by name; the compiler runs with `cacheDir` as
82
+ // its working directory so the relative path resolves.
83
+ writeFileSync(rcPath, `1 ICON "${icoName}"\n`);
84
+
85
+ const args =
86
+ compiler.kind === "windres"
87
+ ? [rcPath, "-O", "coff", "-o", objectPath]
88
+ : ["/fo", objectPath, rcPath];
89
+ const result = runner.run(compiler.tool, args, { cwd: cacheDir, env });
90
+ if (result.status !== 0 || !existsSync(objectPath)) {
91
+ throw new IconError(
92
+ `Failed to compile the Windows icon resource with ${compiler.tool}:\n${result.stderr || result.stdout}`,
93
+ );
94
+ }
95
+ return objectPath;
96
+ }
@@ -195,8 +195,16 @@ export const statementMethods: StatementMethods = {
195
195
  case TokenKind.EnumKeyword:
196
196
  return this.parseEnumDeclaration([]);
197
197
  case TokenKind.NamespaceKeyword:
198
- case TokenKind.ModuleKeyword:
199
- return this.parseModuleDeclaration([]);
198
+ case TokenKind.ModuleKeyword: {
199
+ // `module` is a contextual keyword: `module.exports` / `module(x)` are
200
+ // ordinary expressions, only `module Foo {}` / `module "x" {}` is a
201
+ // declaration.
202
+ const next = this.lookAhead(1);
203
+ if (this.isIdentifierLike(next) || next.kind === TokenKind.StringLiteral) {
204
+ return this.parseModuleDeclaration([]);
205
+ }
206
+ break;
207
+ }
200
208
  case TokenKind.DeclareKeyword: {
201
209
  const modifiers = this.tryParseModifiers();
202
210
  return this.parseStatementWithModifiers(modifiers);
@@ -228,8 +236,13 @@ export const statementMethods: StatementMethods = {
228
236
  case TokenKind.EnumKeyword:
229
237
  return this.parseEnumDeclaration(modifiers);
230
238
  case TokenKind.NamespaceKeyword:
231
- case TokenKind.ModuleKeyword:
232
- return this.parseModuleDeclaration(modifiers);
239
+ case TokenKind.ModuleKeyword: {
240
+ const next = this.lookAhead(1);
241
+ if (this.isIdentifierLike(next) || next.kind === TokenKind.StringLiteral) {
242
+ return this.parseModuleDeclaration(modifiers);
243
+ }
244
+ return this.parseExpressionStatement();
245
+ }
233
246
  default:
234
247
  return this.parseExpressionStatement();
235
248
  }
@@ -1,12 +0,0 @@
1
- /**
2
- * End-to-end tests for the `gui` extension.
3
- *
4
- * The suite compiles TypeScript programs that import `gui`, links them against
5
- * the prebuilt `runtime/lib/<os>-<arch>/gui.a` and runs them. Programs close
6
- * themselves through the `XT_GUI_AUTOCLOSE_MS` hook, so the tests never block on
7
- * a real window.
8
- *
9
- * It is skipped when the GUI archive has not been built (run `npm run gui`
10
- * first) and on Windows, where the archive is not produced yet.
11
- */
12
- export {};