xbintsc 0.5.45 → 0.5.52

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 (286) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +5 -4
  3. package/README.zh-CN.md +4 -3
  4. package/dist/src/cli/extensions.d.ts +24 -0
  5. package/dist/src/cli/extensions.js +62 -0
  6. package/dist/src/cli/extensions.js.map +1 -0
  7. package/dist/src/cli/help.d.ts +1 -1
  8. package/dist/src/cli/help.js +3 -1
  9. package/dist/src/cli/help.js.map +1 -1
  10. package/dist/src/cli/hints.js +8 -3
  11. package/dist/src/cli/hints.js.map +1 -1
  12. package/dist/src/cli/main.js +21 -28
  13. package/dist/src/cli/main.js.map +1 -1
  14. package/dist/src/diagnostics/diagnostic.d.ts +3 -1
  15. package/dist/src/diagnostics/diagnostic.js +2 -0
  16. package/dist/src/diagnostics/diagnostic.js.map +1 -1
  17. package/dist/src/driver/build-key.d.ts +2 -0
  18. package/dist/src/driver/build-key.js +1 -0
  19. package/dist/src/driver/build-key.js.map +1 -1
  20. package/dist/src/driver/compiler.js +61 -8
  21. package/dist/src/driver/compiler.js.map +1 -1
  22. package/dist/src/driver/config.d.ts +4 -0
  23. package/dist/src/driver/config.js +2 -0
  24. package/dist/src/driver/config.js.map +1 -1
  25. package/dist/src/driver/link-features.d.ts +37 -0
  26. package/dist/src/driver/link-features.js +123 -0
  27. package/dist/src/driver/link-features.js.map +1 -0
  28. package/dist/src/driver/options.d.ts +10 -0
  29. package/dist/src/driver/runtime-objects.d.ts +5 -0
  30. package/dist/src/driver/runtime-objects.js +20 -1
  31. package/dist/src/driver/runtime-objects.js.map +1 -1
  32. package/dist/src/driver/usage.d.ts +23 -0
  33. package/dist/src/driver/usage.js +353 -0
  34. package/dist/src/driver/usage.js.map +1 -0
  35. package/dist/src/driver/version.d.ts +1 -1
  36. package/dist/src/driver/version.js +1 -1
  37. package/dist/src/extensions/catalog.js +1 -2
  38. package/dist/src/extensions/catalog.js.map +1 -1
  39. package/dist/src/extensions/gui/features.d.ts +34 -0
  40. package/dist/src/extensions/gui/features.js +165 -0
  41. package/dist/src/extensions/gui/features.js.map +1 -0
  42. package/dist/src/extensions/gui/index.js +10 -4
  43. package/dist/src/extensions/gui/index.js.map +1 -1
  44. package/dist/src/extensions/link-feature.d.ts +70 -0
  45. package/dist/src/extensions/link-feature.js +18 -0
  46. package/dist/src/extensions/link-feature.js.map +1 -0
  47. package/dist/src/extensions/registry.d.ts +24 -4
  48. package/dist/src/extensions/registry.js +26 -3
  49. package/dist/src/extensions/registry.js.map +1 -1
  50. package/dist/src/index.d.ts +3 -2
  51. package/dist/src/index.js +0 -1
  52. package/dist/src/index.js.map +1 -1
  53. package/dist/tests/cli/hints.test.js +5 -7
  54. package/dist/tests/cli/hints.test.js.map +1 -1
  55. package/dist/tests/driver/link-features.test.js +105 -0
  56. package/dist/tests/driver/link-features.test.js.map +1 -0
  57. package/dist/tests/driver/usage.test.d.ts +1 -0
  58. package/dist/tests/driver/usage.test.js +88 -0
  59. package/dist/tests/driver/usage.test.js.map +1 -0
  60. package/dist/tests/e2e/gui-audio.test.js +4 -4
  61. package/dist/tests/e2e/gui-audio.test.js.map +1 -1
  62. package/dist/tests/e2e/gui-css-coverage.test.d.ts +9 -0
  63. package/dist/tests/e2e/gui-css-coverage.test.js +333 -0
  64. package/dist/tests/e2e/gui-css-coverage.test.js.map +1 -0
  65. package/dist/tests/e2e/gui-css-features.test.d.ts +6 -0
  66. package/dist/tests/e2e/gui-css-features.test.js +270 -0
  67. package/dist/tests/e2e/gui-css-features.test.js.map +1 -0
  68. package/dist/tests/e2e/gui-effects.test.js +92 -11
  69. package/dist/tests/e2e/gui-effects.test.js.map +1 -1
  70. package/dist/tests/e2e/gui-feature-linking.test.d.ts +9 -0
  71. package/dist/tests/e2e/gui-feature-linking.test.js +68 -0
  72. package/dist/tests/e2e/gui-feature-linking.test.js.map +1 -0
  73. package/dist/tests/e2e/gui-font-face.test.d.ts +10 -0
  74. package/dist/tests/e2e/gui-font-face.test.js +142 -0
  75. package/dist/tests/e2e/gui-font-face.test.js.map +1 -0
  76. package/dist/tests/e2e/gui-fonts.test.d.ts +10 -0
  77. package/dist/tests/e2e/gui-fonts.test.js +150 -0
  78. package/dist/tests/e2e/gui-fonts.test.js.map +1 -0
  79. package/dist/tests/e2e/gui-helpers.d.ts +10 -1
  80. package/dist/tests/e2e/gui-helpers.js +6 -0
  81. package/dist/tests/e2e/gui-helpers.js.map +1 -1
  82. package/dist/tests/e2e/gui-layout.test.js +7 -3
  83. package/dist/tests/e2e/gui-layout.test.js.map +1 -1
  84. package/dist/tests/e2e/gui-media-disabled.test.d.ts +5 -4
  85. package/dist/tests/e2e/gui-media-disabled.test.js +7 -6
  86. package/dist/tests/e2e/gui-media-disabled.test.js.map +1 -1
  87. package/dist/tests/e2e/gui-media.test.d.ts +5 -4
  88. package/dist/tests/e2e/gui-media.test.js +9 -9
  89. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  90. package/dist/tests/e2e/gui-paint.test.js +5 -2
  91. package/dist/tests/e2e/gui-paint.test.js.map +1 -1
  92. package/dist/tests/e2e/gui-shaping.test.d.ts +5 -0
  93. package/dist/tests/e2e/gui-shaping.test.js +47 -0
  94. package/dist/tests/e2e/gui-shaping.test.js.map +1 -0
  95. package/dist/tests/e2e/gui-track-sizing.test.d.ts +6 -0
  96. package/dist/tests/e2e/gui-track-sizing.test.js +173 -0
  97. package/dist/tests/e2e/gui-track-sizing.test.js.map +1 -0
  98. package/dist/tests/e2e/gui-transform.test.js +3 -2
  99. package/dist/tests/e2e/gui-transform.test.js.map +1 -1
  100. package/dist/tests/e2e/gui-webgl-pipeline-cache.test.d.ts +18 -0
  101. package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js +120 -0
  102. package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js.map +1 -0
  103. package/dist/tests/extensions/gui-features.test.d.ts +1 -0
  104. package/dist/tests/extensions/gui-features.test.js +175 -0
  105. package/dist/tests/extensions/gui-features.test.js.map +1 -0
  106. package/doc/ai/cli.md +5 -1
  107. package/doc/ai/extensions.md +56 -26
  108. package/doc/ai/troubleshooting.md +10 -7
  109. package/doc/ai/zh-CN/cli.md +5 -1
  110. package/doc/ai/zh-CN/extensions.md +48 -22
  111. package/doc/ai/zh-CN/troubleshooting.md +6 -5
  112. package/doc/gui/animation.md +39 -9
  113. package/doc/gui/api.md +2 -1
  114. package/doc/gui/build.md +137 -19
  115. package/doc/gui/canvas.md +1 -1
  116. package/doc/gui/dom.md +20 -4
  117. package/doc/gui/known-issues.md +63 -26
  118. package/doc/gui/layout.md +31 -8
  119. package/doc/gui/media.md +13 -7
  120. package/doc/gui/rendering.md +114 -39
  121. package/doc/gui/runtime.md +5 -0
  122. package/doc/gui/webgl.md +24 -6
  123. package/doc/gui.md +110 -47
  124. package/doc/implemented/cli.md +2 -0
  125. package/doc/implemented/extensions.md +9 -3
  126. package/doc/npm-package.md +4 -4
  127. package/doc/xbintsc.config.schema.json +10 -0
  128. package/doc/zh-CN/gui/animation.md +33 -10
  129. package/doc/zh-CN/gui/api.md +2 -1
  130. package/doc/zh-CN/gui/build.md +110 -16
  131. package/doc/zh-CN/gui/canvas.md +1 -1
  132. package/doc/zh-CN/gui/dom.md +16 -3
  133. package/doc/zh-CN/gui/known-issues.md +45 -15
  134. package/doc/zh-CN/gui/layout.md +23 -6
  135. package/doc/zh-CN/gui/media.md +11 -6
  136. package/doc/zh-CN/gui/rendering.md +84 -26
  137. package/doc/zh-CN/gui/runtime.md +3 -0
  138. package/doc/zh-CN/gui/webgl.md +3 -3
  139. package/doc/zh-CN/gui.md +92 -41
  140. package/doc/zh-CN/implemented/cli.md +2 -0
  141. package/doc/zh-CN/implemented/extensions.md +9 -3
  142. package/doc/zh-CN/npm-package.md +4 -3
  143. package/package.json +7 -7
  144. package/runtime/ext_gui/animation_values.cpp +425 -0
  145. package/runtime/ext_gui/animation_values.h +64 -0
  146. package/runtime/ext_gui/browser.cpp +22 -15
  147. package/runtime/ext_gui/browser_loop.cpp +13 -1
  148. package/runtime/ext_gui/canvas.h +1 -1
  149. package/runtime/ext_gui/canvas_raster.cpp +1 -1
  150. package/runtime/ext_gui/canvas_text.cpp +1 -1
  151. package/runtime/ext_gui/css.cpp +172 -21
  152. package/runtime/ext_gui/css.h +75 -4
  153. package/runtime/ext_gui/css_match.cpp +4 -0
  154. package/runtime/ext_gui/css_sheet.cpp +218 -2
  155. package/runtime/ext_gui/document.cpp +42 -192
  156. package/runtime/ext_gui/document.h +25 -12
  157. package/runtime/ext_gui/document_animation.cpp +428 -0
  158. package/runtime/ext_gui/dom_api_canvas.cpp +15 -8
  159. package/runtime/ext_gui/dom_api_canvas_extra.cpp +44 -20
  160. package/runtime/ext_gui/dom_api_canvas_image.cpp +3 -1
  161. package/runtime/ext_gui/dom_api_node_read.cpp +10 -0
  162. package/runtime/ext_gui/dom_api_offscreen.cpp +3 -1
  163. package/runtime/ext_gui/dom_api_style.cpp +7 -0
  164. package/runtime/ext_gui/dom_api_webgl_internal.h +4 -0
  165. package/runtime/ext_gui/dom_api_webgl_source.cpp +5 -2
  166. package/runtime/ext_gui/effect_values.cpp +245 -21
  167. package/runtime/ext_gui/gpu_bridge.c +28 -0
  168. package/runtime/ext_gui/gpu_feature.cpp +30 -0
  169. package/runtime/ext_gui/gpu_shader.cpp +22 -0
  170. package/runtime/ext_gui/gpu_shader_api.h +50 -0
  171. package/runtime/ext_gui/gradient_values.cpp +24 -0
  172. package/runtime/ext_gui/grid_values.cpp +23 -0
  173. package/runtime/ext_gui/gui.cpp +6 -37
  174. package/runtime/ext_gui/gui_canvas.cpp +14 -6
  175. package/runtime/ext_gui/gui_cursor.cpp +50 -0
  176. package/runtime/ext_gui/gui_engine.h +1 -18
  177. package/runtime/ext_gui/gui_events.cpp +19 -6
  178. package/runtime/ext_gui/gui_internal.h +3 -0
  179. package/runtime/ext_gui/gui_webgl.cpp +25 -10
  180. package/runtime/ext_gui/image_api.cpp +18 -0
  181. package/runtime/ext_gui/image_api.h +43 -0
  182. package/runtime/ext_gui/image_bitmap_browser.cpp +20 -11
  183. package/runtime/ext_gui/image_bridge.c +22 -0
  184. package/runtime/ext_gui/image_feature.cpp +107 -0
  185. package/runtime/ext_gui/inline_svg.cpp +95 -8
  186. package/runtime/ext_gui/inline_svg.h +5 -1
  187. package/runtime/ext_gui/layout.cpp +15 -9
  188. package/runtime/ext_gui/layout.h +8 -2
  189. package/runtime/ext_gui/layout_flex.cpp +134 -29
  190. package/runtime/ext_gui/layout_flow.cpp +58 -7
  191. package/runtime/ext_gui/layout_flow_internal.h +39 -4
  192. package/runtime/ext_gui/layout_grid.cpp +31 -0
  193. package/runtime/ext_gui/layout_inline.cpp +26 -2
  194. package/runtime/ext_gui/layout_vertical.cpp +196 -0
  195. package/runtime/ext_gui/media.cpp +4 -2
  196. package/runtime/ext_gui/media.h +3 -3
  197. package/runtime/ext_gui/media_api.h +7 -6
  198. package/runtime/ext_gui/paint.cpp +67 -9
  199. package/runtime/ext_gui/paint.h +61 -8
  200. package/runtime/ext_gui/paint_backdrop.cpp +211 -0
  201. package/runtime/ext_gui/paint_background.cpp +175 -97
  202. package/runtime/ext_gui/paint_effects.cpp +12 -6
  203. package/runtime/ext_gui/paint_internal.h +27 -0
  204. package/runtime/ext_gui/paint_outline.cpp +44 -0
  205. package/runtime/ext_gui/paint_shadow.cpp +368 -0
  206. package/runtime/ext_gui/renderer.cpp +15 -7
  207. package/runtime/ext_gui/renderer.h +11 -2
  208. package/runtime/ext_gui/renderer_backdrop.cpp +374 -0
  209. package/runtime/ext_gui/renderer_bitmap.cpp +82 -0
  210. package/runtime/ext_gui/renderer_gradient.cpp +51 -17
  211. package/runtime/ext_gui/renderer_image.cpp +19 -7
  212. package/runtime/ext_gui/renderer_internal.h +21 -0
  213. package/runtime/ext_gui/renderer_layer.cpp +37 -6
  214. package/runtime/ext_gui/renderer_text.cpp +2 -1
  215. package/runtime/ext_gui/stb_truetype.h +5077 -0
  216. package/runtime/ext_gui/style.cpp +62 -8
  217. package/runtime/ext_gui/style.h +111 -4
  218. package/runtime/ext_gui/style_cascade.cpp +83 -0
  219. package/runtime/ext_gui/style_internal.h +13 -1
  220. package/runtime/ext_gui/style_length.cpp +92 -0
  221. package/runtime/ext_gui/style_print.cpp +83 -2
  222. package/runtime/ext_gui/style_svg.cpp +40 -0
  223. package/runtime/ext_gui/style_text.cpp +302 -0
  224. package/runtime/ext_gui/style_ui.cpp +150 -0
  225. package/runtime/ext_gui/style_values.cpp +76 -62
  226. package/runtime/ext_gui/style_values_internal.h +23 -0
  227. package/runtime/ext_gui/text.cpp +27 -499
  228. package/runtime/ext_gui/text.h +18 -9
  229. package/runtime/ext_gui/text_api.h +45 -0
  230. package/runtime/ext_gui/text_bridge.c +23 -0
  231. package/runtime/ext_gui/text_cache.cpp +12 -3
  232. package/runtime/ext_gui/text_font_db.cpp +427 -0
  233. package/runtime/ext_gui/text_font_paths.cpp +250 -0
  234. package/runtime/ext_gui/text_font_paths.h +39 -0
  235. package/runtime/ext_gui/text_font_sfnt.cpp +396 -0
  236. package/runtime/ext_gui/text_font_sfnt.h +44 -0
  237. package/runtime/ext_gui/text_fonts.cpp +348 -0
  238. package/runtime/ext_gui/text_fonts.h +78 -0
  239. package/runtime/ext_gui/text_fonts_internal.h +77 -0
  240. package/runtime/ext_gui/text_glyph_cache.cpp +2 -2
  241. package/runtime/ext_gui/text_hb.cpp +438 -0
  242. package/runtime/ext_gui/text_stb.cpp +369 -0
  243. package/runtime/ext_gui/transform.cpp +107 -9
  244. package/runtime/ext_gui/transform.h +5 -0
  245. package/runtime/ext_gui/webgl_api.cpp +19 -0
  246. package/runtime/ext_gui/webgl_api.h +53 -0
  247. package/runtime/ext_gui/webgl_bridge.c +25 -0
  248. package/runtime/ext_gui/webgl_draw_setup.cpp +42 -1
  249. package/runtime/ext_gui/webgl_feature.cpp +82 -0
  250. package/runtime/ext_gui/webgl_feature.h +28 -0
  251. package/runtime/ext_gui/webgl_msl.cpp +41 -0
  252. package/runtime/ext_gui/webgl_msl.h +6 -0
  253. package/runtime/ext_gui/webgl_shader.cpp +40 -32
  254. package/runtime/ext_gui/window.cpp +7 -7
  255. package/runtime/ext_media/decode_audio.cpp +1 -1
  256. package/runtime/ext_media/media.cpp +1 -1
  257. package/runtime/ext_media/media_bridge.c +7 -7
  258. package/scripts/build-gui.ts +97 -98
  259. package/scripts/check-file-length.ts +1 -0
  260. package/scripts/gui-build-options.ts +122 -0
  261. package/src/cli/extensions.ts +72 -0
  262. package/src/cli/help.ts +3 -1
  263. package/src/cli/hints.ts +9 -3
  264. package/src/cli/main.ts +21 -27
  265. package/src/diagnostics/diagnostic.ts +2 -0
  266. package/src/driver/build-key.ts +3 -0
  267. package/src/driver/compiler.ts +63 -8
  268. package/src/driver/config.ts +6 -0
  269. package/src/driver/link-features.ts +163 -0
  270. package/src/driver/options.ts +10 -0
  271. package/src/driver/runtime-objects.ts +26 -1
  272. package/src/driver/usage.ts +376 -0
  273. package/src/driver/version.ts +1 -1
  274. package/src/extensions/catalog.ts +1 -2
  275. package/src/extensions/gui/features.ts +166 -0
  276. package/src/extensions/gui/index.ts +10 -4
  277. package/src/extensions/link-feature.ts +72 -0
  278. package/src/extensions/registry.ts +45 -4
  279. package/src/index.ts +3 -2
  280. package/dist/src/extensions/media/index.d.ts +0 -28
  281. package/dist/src/extensions/media/index.js +0 -59
  282. package/dist/src/extensions/media/index.js.map +0 -1
  283. package/dist/tests/extensions/media.test.js +0 -63
  284. package/dist/tests/extensions/media.test.js.map +0 -1
  285. package/src/extensions/media/index.ts +0 -65
  286. /package/dist/tests/{extensions/media.test.d.ts → driver/link-features.test.d.ts} +0 -0
@@ -11,6 +11,8 @@
11
11
  * extensions they need before invoking the driver.
12
12
  */
13
13
 
14
+ import type { LinkFeature } from "./link-feature.js";
15
+
14
16
  export interface BuiltinFunction {
15
17
  /** Exported C symbol, called as `xt_value symbol(int32_t argc, xt_value *argv)`. */
16
18
  readonly symbol: string;
@@ -109,7 +111,7 @@ export interface Extension {
109
111
  /**
110
112
  * Other extensions this one needs. The registry rejects a build that enables
111
113
  * it without them, so a dependent extension fails with an actionable message
112
- * instead of an unresolved symbol at link time (e.g. `media` needs `gui`).
114
+ * instead of an unresolved symbol at link time.
113
115
  */
114
116
  readonly requires?: readonly string[];
115
117
  /** C/asm sources compiled and linked alongside the generated module. */
@@ -144,6 +146,19 @@ export interface Extension {
144
146
  * learns about any particular asset format.
145
147
  */
146
148
  assetLoaders?(): Readonly<Record<string, AssetLoader>>;
149
+ /**
150
+ * Optional heavy capabilities this extension can contribute only when a
151
+ * program may use them (`media`, `gpu`, `images`, `shaping`, `webgl`, …). The driver selects among them
152
+ * from the bundled source and links their registration source and archives
153
+ * only when active; see {@link LinkFeature}.
154
+ */
155
+ linkFeatures?(): readonly LinkFeature[];
156
+ }
157
+
158
+ /** A link feature together with the extension that declared it. */
159
+ export interface LinkFeatureDeclaration {
160
+ readonly feature: LinkFeature;
161
+ readonly extension: string;
147
162
  }
148
163
 
149
164
  export class ExtensionRegistry {
@@ -190,11 +205,13 @@ export class ExtensionRegistry {
190
205
  }
191
206
 
192
207
  /**
193
- * Throw when a registered extension requires one that is not registered.
194
- * Called before a build so `--ext media` without `--ext gui` reports which
195
- * flags to pass instead of failing later with an unresolved symbol.
208
+ * Throw when a registered extension requires one that is not registered, or
209
+ * when two extensions declare the same link feature.
210
+ * Called before a build so a missing dependency reports which flags to pass
211
+ * instead of failing later with an unresolved symbol.
196
212
  */
197
213
  validate(): this {
214
+ const features = new Map<string, string>();
198
215
  for (const extension of this.extensions.values()) {
199
216
  for (const dependency of extension.requires ?? []) {
200
217
  if (this.extensions.has(dependency)) continue;
@@ -203,6 +220,15 @@ export class ExtensionRegistry {
203
220
  `pass --ext ${dependency},${extension.name}`,
204
221
  );
205
222
  }
223
+ for (const feature of extension.linkFeatures?.() ?? []) {
224
+ const owner = features.get(feature.name);
225
+ if (owner !== undefined && owner !== extension.name) {
226
+ throw new Error(
227
+ `link feature '${feature.name}' is declared by both '${owner}' and '${extension.name}'`,
228
+ );
229
+ }
230
+ features.set(feature.name, extension.name);
231
+ }
206
232
  }
207
233
  return this;
208
234
  }
@@ -270,6 +296,21 @@ export class ExtensionRegistry {
270
296
  return merged;
271
297
  }
272
298
 
299
+ /**
300
+ * Every optional link feature declared by the registered extensions, paired
301
+ * with its provider. Features of extensions that are not enabled are absent,
302
+ * so a program cannot accidentally link `media` through `node`.
303
+ */
304
+ linkFeatures(): readonly LinkFeatureDeclaration[] {
305
+ const declarations: LinkFeatureDeclaration[] = [];
306
+ for (const extension of this.extensions.values()) {
307
+ for (const feature of extension.linkFeatures?.() ?? []) {
308
+ declarations.push({ feature, extension: extension.name });
309
+ }
310
+ }
311
+ return declarations;
312
+ }
313
+
273
314
  runtimeSources(): readonly string[] {
274
315
  const sources: string[] = [];
275
316
  for (const extension of this.extensions.values()) {
package/src/index.ts CHANGED
@@ -30,10 +30,11 @@ export {
30
30
  numberLiteral,
31
31
  booleanLiteral,
32
32
  } from "./codegen/values.js";
33
- export { ExtensionRegistry, createDefaultRegistry, coreExtension, type Extension, type ExtensionModule, type ModuleExport, type ModuleExports, type AssetLoader, type AssetLoadResult } from "./extensions/registry.js";
33
+ export { ExtensionRegistry, createDefaultRegistry, coreExtension, type Extension, type ExtensionModule, type ModuleExport, type ModuleExports, type AssetLoader, type AssetLoadResult, type LinkFeatureDeclaration } from "./extensions/registry.js";
34
+ export type { LinkFeature, ProgramUsage } from "./extensions/link-feature.js";
35
+ export type { LinkFeatureRequest, ResolvedLinkFeature } from "./driver/link-features.js";
34
36
  export { bundledExtensions } from "./extensions/catalog.js";
35
37
  export { nodeExtension } from "./extensions/node/index.js";
36
- export { mediaExtension } from "./extensions/media/index.js";
37
38
  export type { NodeModule } from "./extensions/node/module.js";
38
39
  export {
39
40
  NativeExtensionError,
@@ -1,28 +0,0 @@
1
- /**
2
- * Media extension: `<video>` / `<audio>` decoding for the GUI engine.
3
- *
4
- * The GUI extension is deliberately decoder-free: it models media elements,
5
- * renders their frames and routes the DOM API, but keeps FFmpeg out of `gui.a`
6
- * so a program that only needs windows and HTML/CSS does not pay for a media
7
- * stack it never uses. This extension supplies the decoding half:
8
- *
9
- * - `media.a` (`media.lib` with the MSVC ABI on Windows, built by
10
- * `npm run media`) contains the FFmpeg-linked player from
11
- * `runtime/ext_media/media.cpp` and the static FFmpeg libraries;
12
- * - `runtime/ext_media/media_bridge.c` is compiled and linked directly. Its
13
- * constructor installs the player table into the GUI engine and references
14
- * the backend entry points, which makes the linker extract the archive
15
- * member — a static archive whose only entry point is a constructor would
16
- * otherwise never be pulled in.
17
- *
18
- * There is no importable TypeScript module: the feature is the DOM media
19
- * surface that the `gui` module already exposes. Enable both extensions:
20
- *
21
- * xbintsc run app.ts --ext gui,media
22
- *
23
- * The archive is built for every host platform. On Windows FFmpeg is compiled
24
- * with the MSVC-targeting clang-cl so its COFF objects and static CRT match
25
- * `gui.lib`; see `doc/gui/build.md`.
26
- */
27
- import type { Extension } from "../registry.js";
28
- export declare const mediaExtension: Extension;
@@ -1,59 +0,0 @@
1
- /**
2
- * Media extension: `<video>` / `<audio>` decoding for the GUI engine.
3
- *
4
- * The GUI extension is deliberately decoder-free: it models media elements,
5
- * renders their frames and routes the DOM API, but keeps FFmpeg out of `gui.a`
6
- * so a program that only needs windows and HTML/CSS does not pay for a media
7
- * stack it never uses. This extension supplies the decoding half:
8
- *
9
- * - `media.a` (`media.lib` with the MSVC ABI on Windows, built by
10
- * `npm run media`) contains the FFmpeg-linked player from
11
- * `runtime/ext_media/media.cpp` and the static FFmpeg libraries;
12
- * - `runtime/ext_media/media_bridge.c` is compiled and linked directly. Its
13
- * constructor installs the player table into the GUI engine and references
14
- * the backend entry points, which makes the linker extract the archive
15
- * member — a static archive whose only entry point is a constructor would
16
- * otherwise never be pulled in.
17
- *
18
- * There is no importable TypeScript module: the feature is the DOM media
19
- * surface that the `gui` module already exposes. Enable both extensions:
20
- *
21
- * xbintsc run app.ts --ext gui,media
22
- *
23
- * The archive is built for every host platform. On Windows FFmpeg is compiled
24
- * with the MSVC-targeting clang-cl so its COFF objects and static CRT match
25
- * `gui.lib`; see `doc/gui/build.md`.
26
- */
27
- import { join } from "node:path";
28
- import { findRuntimeDir, platformSlug } from "../../driver/paths.js";
29
- import { findRuntimeLibrary, runtimeLibDir } from "../../driver/runtime-lib.js";
30
- /** Absolute path to the per-platform prebuilt media archive. */
31
- function mediaArchive() {
32
- return join(runtimeLibDir(), process.platform === "win32" ? "media.lib" : "media.a");
33
- }
34
- export const mediaExtension = {
35
- name: "media",
36
- description: "Video/audio decoding for <video>/<audio> (requires gui, links FFmpeg)",
37
- requires: ["gui"],
38
- /**
39
- * The registration bridge is a tiny C file linked as a normal object, so its
40
- * constructor always runs. Keeping it out of `media.a` is what guarantees the
41
- * archive is searched (see the header comment).
42
- */
43
- runtimeSources: () => [join(findRuntimeDir(), "ext_media", "media_bridge.c")],
44
- nativeObjects: () => {
45
- const archive = findRuntimeLibrary("media");
46
- if (archive === undefined) {
47
- throw new Error(`media native library not found at ${mediaArchive()} (media.a or media.lib).\n` +
48
- `The optional @xbintsc/${platformSlug()} package ships it: reinstall xbintsc ` +
49
- `without --omit=optional, or build it with \`npm run media\` (see doc/gui/build.md).`);
50
- }
51
- return [archive];
52
- },
53
- /** `media.a` is C++ and FFmpeg itself needs libm; the GUI extension already
54
- * contributes the C++ runtime and the OS frameworks. On Windows the FFmpeg
55
- * objects reference the Win32 crypto/COM services (`bcrypt`, `ole32`) and
56
- * `user32`. */
57
- linkerFlags: () => process.platform === "win32" ? ["-lbcrypt", "-lole32", "-luser32"] : ["-lm"],
58
- };
59
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extensions/media/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEhF,gEAAgE;AAChE,SAAS,YAAY;IACnB,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AACvF,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,IAAI,EAAE,OAAO;IACb,WAAW,EAAE,uEAAuE;IACpF,QAAQ,EAAE,CAAC,KAAK,CAAC;IACjB;;;;OAIG;IACH,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAC7E,aAAa,EAAE,GAAG,EAAE;QAClB,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,qCAAqC,YAAY,EAAE,4BAA4B;gBAC7E,yBAAyB,YAAY,EAAE,uCAAuC;gBAC9E,qFAAqF,CACxF,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;IACD;;;mBAGe;IACf,WAAW,EAAE,GAAG,EAAE,CAChB,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;CAC/E,CAAC"}
@@ -1,63 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from "vitest";
2
- const mocks = vi.hoisted(() => ({ findRuntimeLibrary: vi.fn() }));
3
- /* Keep the archive lookup deterministic so both the success and the
4
- * "not built yet" branches of `nativeObjects` can be exercised. */
5
- vi.mock("../../src/driver/runtime-lib.js", () => ({
6
- findRuntimeLibrary: mocks.findRuntimeLibrary,
7
- runtimeLibDir: () => "/tmp/runtime/lib/darwin-x64",
8
- }));
9
- import { bundledExtensions } from "../../src/extensions/catalog.js";
10
- import { createDefaultRegistry } from "../../src/extensions/registry.js";
11
- import { guiExtension } from "../../src/extensions/gui/index.js";
12
- import { mediaExtension } from "../../src/extensions/media/index.js";
13
- afterEach(() => {
14
- vi.restoreAllMocks();
15
- mocks.findRuntimeLibrary.mockReset();
16
- });
17
- /** Pretend to be a POSIX host, so the archive name in messages is `media.a`. */
18
- function posixHost() {
19
- vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
20
- }
21
- describe("media extension object", () => {
22
- it("is a separate extension that depends on gui", () => {
23
- expect(mediaExtension.name).toBe("media");
24
- expect(mediaExtension.description).toMatch(/FFmpeg/);
25
- expect(mediaExtension.requires).toEqual(["gui"]);
26
- // Media is advertised as a bundled extension, but is not enabled by
27
- // enabling `gui`: that separation is the point of the split.
28
- expect(bundledExtensions().map((extension) => extension.name)).toContain("media");
29
- });
30
- it("links the bridge object and the prebuilt archive", () => {
31
- posixHost();
32
- mocks.findRuntimeLibrary.mockReturnValue("/tmp/media.a");
33
- const sources = mediaExtension.runtimeSources?.() ?? [];
34
- expect(sources).toHaveLength(1);
35
- expect(sources[0]).toMatch(/runtime[\\/]ext_media[\\/]media_bridge\.c$/);
36
- expect(mediaExtension.nativeObjects?.()).toEqual(["/tmp/media.a"]);
37
- expect(mocks.findRuntimeLibrary).toHaveBeenCalledWith("media");
38
- });
39
- it("fails with an actionable message when the archive is missing", () => {
40
- posixHost();
41
- mocks.findRuntimeLibrary.mockReturnValue(undefined);
42
- expect(() => mediaExtension.nativeObjects?.()).toThrow(/media native library not found/);
43
- expect(() => mediaExtension.nativeObjects?.()).toThrow(/npm run media/);
44
- });
45
- it("links media.lib and the Win32 system libraries on Windows", () => {
46
- vi.spyOn(process, "platform", "get").mockReturnValue("win32");
47
- mocks.findRuntimeLibrary.mockReturnValue("C:/repo/runtime/lib/win32-x64/media.lib");
48
- expect(mediaExtension.nativeObjects?.()).toEqual(["C:/repo/runtime/lib/win32-x64/media.lib"]);
49
- /* FFmpeg's avutil/avcodec reference bcrypt, ole32 and user32; the GUI
50
- * extension already contributes the rest. */
51
- expect(mediaExtension.linkerFlags?.()).toEqual(["-lbcrypt", "-lole32", "-luser32"]);
52
- });
53
- it("rejects a build that enables media without gui", () => {
54
- const registry = createDefaultRegistry().register(mediaExtension);
55
- expect(() => registry.validate()).toThrow(/requires the 'gui' extension/);
56
- expect(() => registry.validate()).toThrow(/--ext gui,media/);
57
- });
58
- it("accepts gui + media together", () => {
59
- const registry = createDefaultRegistry().register(guiExtension).register(mediaExtension);
60
- expect(() => registry.validate()).not.toThrow();
61
- });
62
- });
63
- //# sourceMappingURL=media.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"media.test.js","sourceRoot":"","sources":["../../../tests/extensions/media.test.ts"],"names":[],"mappings":"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"}
@@ -1,65 +0,0 @@
1
- /**
2
- * Media extension: `<video>` / `<audio>` decoding for the GUI engine.
3
- *
4
- * The GUI extension is deliberately decoder-free: it models media elements,
5
- * renders their frames and routes the DOM API, but keeps FFmpeg out of `gui.a`
6
- * so a program that only needs windows and HTML/CSS does not pay for a media
7
- * stack it never uses. This extension supplies the decoding half:
8
- *
9
- * - `media.a` (`media.lib` with the MSVC ABI on Windows, built by
10
- * `npm run media`) contains the FFmpeg-linked player from
11
- * `runtime/ext_media/media.cpp` and the static FFmpeg libraries;
12
- * - `runtime/ext_media/media_bridge.c` is compiled and linked directly. Its
13
- * constructor installs the player table into the GUI engine and references
14
- * the backend entry points, which makes the linker extract the archive
15
- * member — a static archive whose only entry point is a constructor would
16
- * otherwise never be pulled in.
17
- *
18
- * There is no importable TypeScript module: the feature is the DOM media
19
- * surface that the `gui` module already exposes. Enable both extensions:
20
- *
21
- * xbintsc run app.ts --ext gui,media
22
- *
23
- * The archive is built for every host platform. On Windows FFmpeg is compiled
24
- * with the MSVC-targeting clang-cl so its COFF objects and static CRT match
25
- * `gui.lib`; see `doc/gui/build.md`.
26
- */
27
-
28
- import { join } from "node:path";
29
- import type { Extension } from "../registry.js";
30
- import { findRuntimeDir, platformSlug } from "../../driver/paths.js";
31
- import { findRuntimeLibrary, runtimeLibDir } from "../../driver/runtime-lib.js";
32
-
33
- /** Absolute path to the per-platform prebuilt media archive. */
34
- function mediaArchive(): string {
35
- return join(runtimeLibDir(), process.platform === "win32" ? "media.lib" : "media.a");
36
- }
37
-
38
- export const mediaExtension: Extension = {
39
- name: "media",
40
- description: "Video/audio decoding for <video>/<audio> (requires gui, links FFmpeg)",
41
- requires: ["gui"],
42
- /**
43
- * The registration bridge is a tiny C file linked as a normal object, so its
44
- * constructor always runs. Keeping it out of `media.a` is what guarantees the
45
- * archive is searched (see the header comment).
46
- */
47
- runtimeSources: () => [join(findRuntimeDir(), "ext_media", "media_bridge.c")],
48
- nativeObjects: () => {
49
- const archive = findRuntimeLibrary("media");
50
- if (archive === undefined) {
51
- throw new Error(
52
- `media native library not found at ${mediaArchive()} (media.a or media.lib).\n` +
53
- `The optional @xbintsc/${platformSlug()} package ships it: reinstall xbintsc ` +
54
- `without --omit=optional, or build it with \`npm run media\` (see doc/gui/build.md).`,
55
- );
56
- }
57
- return [archive];
58
- },
59
- /** `media.a` is C++ and FFmpeg itself needs libm; the GUI extension already
60
- * contributes the C++ runtime and the OS frameworks. On Windows the FFmpeg
61
- * objects reference the Win32 crypto/COM services (`bcrypt`, `ole32`) and
62
- * `user32`. */
63
- linkerFlags: () =>
64
- process.platform === "win32" ? ["-lbcrypt", "-lole32", "-luser32"] : ["-lm"],
65
- };