xbintsc 0.5.6 → 0.5.21

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 (490) hide show
  1. package/AGENTS.md +20 -10
  2. package/README.md +8 -7
  3. package/README.zh-CN.md +6 -6
  4. package/dist/src/binder/declarations.js +14 -3
  5. package/dist/src/binder/declarations.js.map +1 -1
  6. package/dist/src/cli/hints.js +7 -1
  7. package/dist/src/cli/hints.js.map +1 -1
  8. package/dist/src/cli/main.js +115 -15
  9. package/dist/src/cli/main.js.map +1 -1
  10. package/dist/src/cli/watch.d.ts +25 -0
  11. package/dist/src/cli/watch.js +93 -0
  12. package/dist/src/cli/watch.js.map +1 -0
  13. package/dist/src/codegen/generator/calls/access.js +11 -2
  14. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  15. package/dist/src/codegen/generator/calls/closures.js +12 -4
  16. package/dist/src/codegen/generator/calls/closures.js.map +1 -1
  17. package/dist/src/codegen/generator/context.d.ts +8 -0
  18. package/dist/src/codegen/generator/context.js +22 -3
  19. package/dist/src/codegen/generator/context.js.map +1 -1
  20. package/dist/src/codegen/generator/expressions/operators.js +17 -15
  21. package/dist/src/codegen/generator/expressions/operators.js.map +1 -1
  22. package/dist/src/codegen/generator/expressions/primary.js +5 -0
  23. package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
  24. package/dist/src/codegen/generator/module.js +0 -7
  25. package/dist/src/codegen/generator/module.js.map +1 -1
  26. package/dist/src/codegen/generator/numeric.d.ts +6 -3
  27. package/dist/src/codegen/generator/numeric.js +54 -11
  28. package/dist/src/codegen/generator/numeric.js.map +1 -1
  29. package/dist/src/codegen/generator/state.js +23 -0
  30. package/dist/src/codegen/generator/state.js.map +1 -1
  31. package/dist/src/codegen/generator/statements/control-flow.js +1 -4
  32. package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
  33. package/dist/src/codegen/generator/statements/loops.js +48 -16
  34. package/dist/src/codegen/generator/statements/loops.js.map +1 -1
  35. package/dist/src/codegen/generator/tables.js +26 -1
  36. package/dist/src/codegen/generator/tables.js.map +1 -1
  37. package/dist/src/diagnostics/diagnostic.d.ts +3 -1
  38. package/dist/src/diagnostics/diagnostic.js +23 -3
  39. package/dist/src/diagnostics/diagnostic.js.map +1 -1
  40. package/dist/src/driver/app-artifacts.d.ts +42 -0
  41. package/dist/src/driver/app-artifacts.js +53 -0
  42. package/dist/src/driver/app-artifacts.js.map +1 -0
  43. package/dist/src/driver/build-key.d.ts +29 -0
  44. package/dist/src/driver/build-key.js +35 -0
  45. package/dist/src/driver/build-key.js.map +1 -0
  46. package/dist/src/driver/bundler/graph.js +61 -12
  47. package/dist/src/driver/bundler/graph.js.map +1 -1
  48. package/dist/src/driver/bundler/merge.js +7 -1
  49. package/dist/src/driver/bundler/merge.js.map +1 -1
  50. package/dist/src/driver/compiler.d.ts +10 -67
  51. package/dist/src/driver/compiler.js +95 -234
  52. package/dist/src/driver/compiler.js.map +1 -1
  53. package/dist/src/driver/config.d.ts +3 -0
  54. package/dist/src/driver/config.js +8 -0
  55. package/dist/src/driver/config.js.map +1 -1
  56. package/dist/src/driver/frontend.d.ts +37 -0
  57. package/dist/src/driver/frontend.js +92 -0
  58. package/dist/src/driver/frontend.js.map +1 -0
  59. package/dist/src/driver/index.d.ts +1 -1
  60. package/dist/src/driver/index.js.map +1 -1
  61. package/dist/src/driver/options.d.ts +64 -0
  62. package/dist/src/driver/options.js +9 -0
  63. package/dist/src/driver/options.js.map +1 -0
  64. package/dist/src/driver/runtime-objects.d.ts +38 -0
  65. package/dist/src/driver/runtime-objects.js +112 -0
  66. package/dist/src/driver/runtime-objects.js.map +1 -0
  67. package/dist/src/driver/toolchain-provider.d.ts +4 -0
  68. package/dist/src/driver/toolchain-provider.js +4 -0
  69. package/dist/src/driver/toolchain-provider.js.map +1 -1
  70. package/dist/src/driver/toolchain.d.ts +32 -1
  71. package/dist/src/driver/toolchain.js +115 -11
  72. package/dist/src/driver/toolchain.js.map +1 -1
  73. package/dist/src/driver/version.d.ts +12 -0
  74. package/dist/src/driver/version.js +13 -0
  75. package/dist/src/driver/version.js.map +1 -0
  76. package/dist/src/driver/win-icon.d.ts +7 -9
  77. package/dist/src/driver/win-icon.js +37 -35
  78. package/dist/src/driver/win-icon.js.map +1 -1
  79. package/dist/src/extensions/node/fs/index.d.ts +4 -3
  80. package/dist/src/extensions/node/fs/index.js +12 -3
  81. package/dist/src/extensions/node/fs/index.js.map +1 -1
  82. package/dist/src/extensions/node/fs-promises/index.d.ts +5 -5
  83. package/dist/src/extensions/node/fs-promises/index.js +15 -6
  84. package/dist/src/extensions/node/fs-promises/index.js.map +1 -1
  85. package/dist/src/parser/declarations/classes.js +5 -0
  86. package/dist/src/parser/declarations/classes.js.map +1 -1
  87. package/dist/src/parser/declarations/functions.js +13 -1
  88. package/dist/src/parser/declarations/functions.js.map +1 -1
  89. package/dist/src/parser/modules.js +8 -3
  90. package/dist/src/parser/modules.js.map +1 -1
  91. package/dist/src/parser/parser.d.ts +1 -0
  92. package/dist/src/parser/parser.js +23 -0
  93. package/dist/src/parser/parser.js.map +1 -1
  94. package/dist/tests/cli/check.test.d.ts +6 -0
  95. package/dist/tests/cli/check.test.js +68 -0
  96. package/dist/tests/cli/check.test.js.map +1 -0
  97. package/dist/tests/cli/main.test.js +19 -0
  98. package/dist/tests/cli/main.test.js.map +1 -1
  99. package/dist/tests/cli/watch.test.d.ts +6 -0
  100. package/dist/tests/cli/watch.test.js +72 -0
  101. package/dist/tests/cli/watch.test.js.map +1 -0
  102. package/dist/tests/codegen/expressions.test.js +15 -3
  103. package/dist/tests/codegen/expressions.test.js.map +1 -1
  104. package/dist/tests/codegen/llvm.test.js +16 -0
  105. package/dist/tests/codegen/llvm.test.js.map +1 -1
  106. package/dist/tests/diagnostics/diagnostic.test.js +8 -0
  107. package/dist/tests/diagnostics/diagnostic.test.js.map +1 -1
  108. package/dist/tests/docs/structure.test.d.ts +1 -0
  109. package/dist/tests/docs/structure.test.js +92 -0
  110. package/dist/tests/docs/structure.test.js.map +1 -0
  111. package/dist/tests/driver/compiler.test.js +6 -0
  112. package/dist/tests/driver/compiler.test.js.map +1 -1
  113. package/dist/tests/driver/config.test.js +9 -0
  114. package/dist/tests/driver/config.test.js.map +1 -1
  115. package/dist/tests/driver/icon.test.js +19 -32
  116. package/dist/tests/driver/icon.test.js.map +1 -1
  117. package/dist/tests/driver/invalid-input.test.d.ts +10 -0
  118. package/dist/tests/driver/invalid-input.test.js +29 -0
  119. package/dist/tests/driver/invalid-input.test.js.map +1 -0
  120. package/dist/tests/driver/modules.test.js +42 -3
  121. package/dist/tests/driver/modules.test.js.map +1 -1
  122. package/dist/tests/driver/toolchain-provider.test.js +27 -1
  123. package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
  124. package/dist/tests/driver/toolchain.test.js +60 -2
  125. package/dist/tests/driver/toolchain.test.js.map +1 -1
  126. package/dist/tests/e2e/array-buffer.test.d.ts +5 -0
  127. package/dist/tests/e2e/array-buffer.test.js +38 -0
  128. package/dist/tests/e2e/array-buffer.test.js.map +1 -0
  129. package/dist/tests/e2e/array-from-iterables.test.d.ts +7 -0
  130. package/dist/tests/e2e/array-from-iterables.test.js +34 -0
  131. package/dist/tests/e2e/array-from-iterables.test.js.map +1 -0
  132. package/dist/tests/e2e/array-symbol-iterator.test.d.ts +8 -0
  133. package/dist/tests/e2e/array-symbol-iterator.test.js +42 -0
  134. package/dist/tests/e2e/array-symbol-iterator.test.js.map +1 -0
  135. package/dist/tests/e2e/async-await.test.js +1 -1
  136. package/dist/tests/e2e/async-fs.test.d.ts +9 -0
  137. package/dist/tests/e2e/async-fs.test.js +119 -0
  138. package/dist/tests/e2e/async-fs.test.js.map +1 -0
  139. package/dist/tests/e2e/async-generators.test.d.ts +1 -0
  140. package/dist/tests/e2e/async-generators.test.js +154 -0
  141. package/dist/tests/e2e/async-generators.test.js.map +1 -0
  142. package/dist/tests/e2e/await-ordering.test.d.ts +5 -0
  143. package/dist/tests/e2e/await-ordering.test.js +37 -0
  144. package/dist/tests/e2e/await-ordering.test.js.map +1 -0
  145. package/dist/tests/e2e/compile-builtins.test.js +1 -1
  146. package/dist/tests/e2e/compile-modules.test.js +7 -0
  147. package/dist/tests/e2e/compile-modules.test.js.map +1 -1
  148. package/dist/tests/e2e/date-parse.test.d.ts +8 -0
  149. package/dist/tests/e2e/date-parse.test.js +38 -0
  150. package/dist/tests/e2e/date-parse.test.js.map +1 -0
  151. package/dist/tests/e2e/default-anonymous-exports.test.d.ts +7 -0
  152. package/dist/tests/e2e/default-anonymous-exports.test.js +23 -0
  153. package/dist/tests/e2e/default-anonymous-exports.test.js.map +1 -0
  154. package/dist/tests/e2e/fetch.test.js +24 -0
  155. package/dist/tests/e2e/fetch.test.js.map +1 -1
  156. package/dist/tests/e2e/globals-microtask.test.d.ts +9 -0
  157. package/dist/tests/e2e/globals-microtask.test.js +37 -0
  158. package/dist/tests/e2e/globals-microtask.test.js.map +1 -0
  159. package/dist/tests/e2e/gui-inline-svg.test.d.ts +11 -0
  160. package/dist/tests/e2e/gui-inline-svg.test.js +160 -0
  161. package/dist/tests/e2e/gui-inline-svg.test.js.map +1 -0
  162. package/dist/tests/e2e/gui-media.test.js +8 -1
  163. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  164. package/dist/tests/e2e/inspect-builtins.test.d.ts +10 -0
  165. package/dist/tests/e2e/inspect-builtins.test.js +43 -0
  166. package/dist/tests/e2e/inspect-builtins.test.js.map +1 -0
  167. package/dist/tests/e2e/json-builtin-objects.test.d.ts +9 -0
  168. package/dist/tests/e2e/json-builtin-objects.test.js +23 -0
  169. package/dist/tests/e2e/json-builtin-objects.test.js.map +1 -0
  170. package/dist/tests/e2e/json-circular.test.d.ts +6 -0
  171. package/dist/tests/e2e/json-circular.test.js +43 -0
  172. package/dist/tests/e2e/json-circular.test.js.map +1 -0
  173. package/dist/tests/e2e/json-parse-reviver.test.d.ts +6 -0
  174. package/dist/tests/e2e/json-parse-reviver.test.js +29 -0
  175. package/dist/tests/e2e/json-parse-reviver.test.js.map +1 -0
  176. package/dist/tests/e2e/json-stringify-replacer.test.d.ts +6 -0
  177. package/dist/tests/e2e/json-stringify-replacer.test.js +27 -0
  178. package/dist/tests/e2e/json-stringify-replacer.test.js.map +1 -0
  179. package/dist/tests/e2e/json-stringify-space.test.d.ts +6 -0
  180. package/dist/tests/e2e/json-stringify-space.test.js +23 -0
  181. package/dist/tests/e2e/json-stringify-space.test.js.map +1 -0
  182. package/dist/tests/e2e/method-dispatch-errors.test.d.ts +9 -0
  183. package/dist/tests/e2e/method-dispatch-errors.test.js +38 -0
  184. package/dist/tests/e2e/method-dispatch-errors.test.js.map +1 -0
  185. package/dist/tests/e2e/native-extensions.test.js +1 -1
  186. package/dist/tests/e2e/native-extensions.test.js.map +1 -1
  187. package/dist/tests/e2e/promise-with-resolvers.test.d.ts +5 -0
  188. package/dist/tests/e2e/promise-with-resolvers.test.js +20 -0
  189. package/dist/tests/e2e/promise-with-resolvers.test.js.map +1 -0
  190. package/dist/tests/e2e/property-descriptors.test.d.ts +5 -0
  191. package/dist/tests/e2e/property-descriptors.test.js +25 -0
  192. package/dist/tests/e2e/property-descriptors.test.js.map +1 -0
  193. package/dist/tests/e2e/property-ic.test.d.ts +1 -0
  194. package/dist/tests/e2e/property-ic.test.js +55 -0
  195. package/dist/tests/e2e/property-ic.test.js.map +1 -0
  196. package/dist/tests/e2e/runtime-errors.test.d.ts +10 -0
  197. package/dist/tests/e2e/runtime-errors.test.js +52 -0
  198. package/dist/tests/e2e/runtime-errors.test.js.map +1 -0
  199. package/dist/tests/e2e/structured-clone.test.d.ts +6 -0
  200. package/dist/tests/e2e/structured-clone.test.js +49 -0
  201. package/dist/tests/e2e/structured-clone.test.js.map +1 -0
  202. package/dist/tests/e2e/text-codec.test.d.ts +6 -0
  203. package/dist/tests/e2e/text-codec.test.js +24 -0
  204. package/dist/tests/e2e/text-codec.test.js.map +1 -0
  205. package/dist/tests/e2e/typed-array-views.test.d.ts +6 -0
  206. package/dist/tests/e2e/typed-array-views.test.js +39 -0
  207. package/dist/tests/e2e/typed-array-views.test.js.map +1 -0
  208. package/dist/tests/e2e/url-search-params.test.d.ts +5 -0
  209. package/dist/tests/e2e/url-search-params.test.js +30 -0
  210. package/dist/tests/e2e/url-search-params.test.js.map +1 -0
  211. package/dist/tests/e2e/weak-collections.test.d.ts +1 -0
  212. package/dist/tests/e2e/weak-collections.test.js +88 -0
  213. package/dist/tests/e2e/weak-collections.test.js.map +1 -0
  214. package/dist/tests/parser/declarations.test.js +12 -0
  215. package/dist/tests/parser/declarations.test.js.map +1 -1
  216. package/dist/tests/parser/module-syntax.test.js +9 -0
  217. package/dist/tests/parser/module-syntax.test.js.map +1 -1
  218. package/dist/tests/parser/parser.test.js +7 -0
  219. package/dist/tests/parser/parser.test.js.map +1 -1
  220. package/dist/tests/version.test.js +5 -1
  221. package/dist/tests/version.test.js.map +1 -1
  222. package/doc/ai/README.md +4 -3
  223. package/doc/ai/cli.md +41 -0
  224. package/doc/ai/contributing.md +20 -16
  225. package/doc/ai/extensions.md +13 -10
  226. package/doc/ai/language-support.md +19 -14
  227. package/doc/ai/troubleshooting.md +11 -9
  228. package/doc/ai/zh-CN/README.md +3 -2
  229. package/doc/ai/zh-CN/cli.md +35 -0
  230. package/doc/ai/zh-CN/contributing.md +16 -15
  231. package/doc/ai/zh-CN/extensions.md +12 -9
  232. package/doc/ai/zh-CN/language-support.md +19 -15
  233. package/doc/ai/zh-CN/troubleshooting.md +9 -8
  234. package/doc/gui/api.md +8 -0
  235. package/doc/gui/build.md +13 -4
  236. package/doc/gui/known-issues.md +19 -14
  237. package/doc/gui/media.md +32 -3
  238. package/doc/gui/rendering.md +3 -1
  239. package/doc/gui.md +28 -5
  240. package/doc/icon.md +5 -4
  241. package/doc/implemented/async.md +51 -0
  242. package/doc/implemented/binder.md +13 -0
  243. package/doc/implemented/cli.md +47 -0
  244. package/doc/implemented/codegen.md +33 -0
  245. package/doc/implemented/collections.md +26 -0
  246. package/doc/implemented/driver.md +19 -0
  247. package/doc/implemented/extensions.md +19 -0
  248. package/doc/implemented/fetch.md +44 -0
  249. package/doc/implemented/lexer.md +23 -0
  250. package/doc/implemented/modules.md +28 -0
  251. package/doc/implemented/node/assert.md +17 -0
  252. package/doc/implemented/node/buffer.md +29 -0
  253. package/doc/implemented/node/child-process.md +29 -0
  254. package/doc/implemented/node/crypto.md +9 -0
  255. package/doc/implemented/node/dgram.md +15 -0
  256. package/doc/implemented/node/events.md +37 -0
  257. package/doc/implemented/node/fs-promises.md +49 -0
  258. package/doc/implemented/node/fs.md +112 -0
  259. package/doc/implemented/node/http.md +21 -0
  260. package/doc/implemented/node/net.md +17 -0
  261. package/doc/implemented/node/os.md +22 -0
  262. package/doc/implemented/node/path.md +33 -0
  263. package/doc/implemented/node/process.md +23 -0
  264. package/doc/implemented/node/querystring.md +20 -0
  265. package/doc/implemented/node/stream-promises.md +8 -0
  266. package/doc/implemented/node/stream.md +19 -0
  267. package/doc/implemented/node/test.md +10 -0
  268. package/doc/implemented/node/url.md +8 -0
  269. package/doc/implemented/node/util.md +25 -0
  270. package/doc/implemented/node/worker-threads.md +10 -0
  271. package/doc/implemented/node/zlib.md +8 -0
  272. package/doc/implemented/node.md +48 -0
  273. package/doc/implemented/operators.md +38 -0
  274. package/doc/implemented/parser.md +58 -0
  275. package/doc/implemented/pipeline.md +28 -0
  276. package/doc/implemented/runtime-core.md +32 -0
  277. package/doc/implemented/stdlib.md +78 -0
  278. package/doc/implemented/strings.md +27 -0
  279. package/doc/implemented/tests.md +10 -0
  280. package/doc/implemented/typed-arrays.md +26 -0
  281. package/doc/implemented/value-model.md +18 -0
  282. package/doc/implemented.md +54 -355
  283. package/doc/node-implemented.md +3 -585
  284. package/doc/node-unimplemented.md +3 -164
  285. package/doc/requirements.md +23 -8
  286. package/doc/unimplemented/classes.md +22 -0
  287. package/doc/unimplemented/deviations.md +27 -0
  288. package/doc/unimplemented/expressions.md +26 -0
  289. package/doc/unimplemented/functions.md +21 -0
  290. package/doc/unimplemented/modules.md +22 -0
  291. package/doc/unimplemented/node/async.md +20 -0
  292. package/doc/unimplemented/node/bun.md +9 -0
  293. package/doc/unimplemented/node/fs-promises.md +20 -0
  294. package/doc/unimplemented/node/fs.md +30 -0
  295. package/doc/unimplemented/node/globals.md +23 -0
  296. package/doc/unimplemented/node/modules.md +21 -0
  297. package/doc/unimplemented/node.md +21 -0
  298. package/doc/unimplemented/statements.md +18 -0
  299. package/doc/unimplemented/stdlib.md +54 -0
  300. package/doc/unimplemented/toolchain.md +14 -0
  301. package/doc/unimplemented/types.md +12 -0
  302. package/doc/unimplemented.md +18 -275
  303. package/doc/xbintsc.config.schema.json +12 -0
  304. package/doc/zh-CN/gui/api.md +7 -0
  305. package/doc/zh-CN/gui/build.md +11 -3
  306. package/doc/zh-CN/gui/known-issues.md +17 -11
  307. package/doc/zh-CN/gui/media.md +26 -2
  308. package/doc/zh-CN/gui/rendering.md +2 -1
  309. package/doc/zh-CN/gui.md +21 -3
  310. package/doc/zh-CN/icon.md +5 -4
  311. package/doc/zh-CN/implemented/async.md +49 -0
  312. package/doc/zh-CN/implemented/binder.md +13 -0
  313. package/doc/zh-CN/implemented/cli.md +46 -0
  314. package/doc/zh-CN/implemented/codegen.md +33 -0
  315. package/doc/zh-CN/implemented/collections.md +26 -0
  316. package/doc/zh-CN/implemented/driver.md +19 -0
  317. package/doc/zh-CN/implemented/extensions.md +19 -0
  318. package/doc/zh-CN/implemented/fetch.md +31 -0
  319. package/doc/zh-CN/implemented/lexer.md +23 -0
  320. package/doc/zh-CN/implemented/modules.md +28 -0
  321. package/doc/zh-CN/implemented/node/assert.md +17 -0
  322. package/doc/zh-CN/implemented/node/buffer.md +25 -0
  323. package/doc/zh-CN/implemented/node/child-process.md +27 -0
  324. package/doc/zh-CN/implemented/node/crypto.md +9 -0
  325. package/doc/zh-CN/implemented/node/dgram.md +15 -0
  326. package/doc/zh-CN/implemented/node/events.md +36 -0
  327. package/doc/zh-CN/implemented/node/fs-promises.md +30 -0
  328. package/doc/zh-CN/implemented/node/fs.md +105 -0
  329. package/doc/zh-CN/implemented/node/http.md +17 -0
  330. package/doc/zh-CN/implemented/node/net.md +17 -0
  331. package/doc/zh-CN/implemented/node/os.md +21 -0
  332. package/doc/zh-CN/implemented/node/path.md +26 -0
  333. package/doc/zh-CN/implemented/node/process.md +23 -0
  334. package/doc/zh-CN/implemented/node/querystring.md +20 -0
  335. package/doc/zh-CN/implemented/node/stream-promises.md +8 -0
  336. package/doc/zh-CN/implemented/node/stream.md +15 -0
  337. package/doc/zh-CN/implemented/node/test.md +10 -0
  338. package/doc/zh-CN/implemented/node/url.md +8 -0
  339. package/doc/zh-CN/implemented/node/util.md +25 -0
  340. package/doc/zh-CN/implemented/node/worker-threads.md +9 -0
  341. package/doc/zh-CN/implemented/node/zlib.md +8 -0
  342. package/doc/zh-CN/implemented/node.md +45 -0
  343. package/doc/zh-CN/implemented/operators.md +38 -0
  344. package/doc/zh-CN/implemented/parser.md +58 -0
  345. package/doc/zh-CN/implemented/pipeline.md +25 -0
  346. package/doc/zh-CN/implemented/runtime-core.md +31 -0
  347. package/doc/zh-CN/implemented/stdlib.md +76 -0
  348. package/doc/zh-CN/implemented/strings.md +27 -0
  349. package/doc/zh-CN/implemented/tests.md +10 -0
  350. package/doc/zh-CN/implemented/typed-arrays.md +26 -0
  351. package/doc/zh-CN/implemented/value-model.md +18 -0
  352. package/doc/zh-CN/implemented.md +50 -350
  353. package/doc/zh-CN/node-implemented.md +4 -531
  354. package/doc/zh-CN/node-unimplemented.md +4 -139
  355. package/doc/zh-CN/plan-require-node-modules.md +4 -4
  356. package/doc/zh-CN/requirements.md +20 -6
  357. package/doc/zh-CN/unimplemented/classes.md +22 -0
  358. package/doc/zh-CN/unimplemented/deviations.md +24 -0
  359. package/doc/zh-CN/unimplemented/expressions.md +24 -0
  360. package/doc/zh-CN/unimplemented/functions.md +21 -0
  361. package/doc/zh-CN/unimplemented/modules.md +19 -0
  362. package/doc/zh-CN/unimplemented/node/async.md +20 -0
  363. package/doc/zh-CN/unimplemented/node/bun.md +8 -0
  364. package/doc/zh-CN/unimplemented/node/fs-promises.md +12 -0
  365. package/doc/zh-CN/unimplemented/node/fs.md +24 -0
  366. package/doc/zh-CN/unimplemented/node/globals.md +14 -0
  367. package/doc/zh-CN/unimplemented/node/modules.md +15 -0
  368. package/doc/zh-CN/unimplemented/node.md +18 -0
  369. package/doc/zh-CN/unimplemented/statements.md +15 -0
  370. package/doc/zh-CN/unimplemented/stdlib.md +54 -0
  371. package/doc/zh-CN/unimplemented/toolchain.md +14 -0
  372. package/doc/zh-CN/unimplemented/types.md +11 -0
  373. package/doc/zh-CN/unimplemented.md +14 -237
  374. package/llms.txt +32 -4
  375. package/package.json +1 -1
  376. package/runtime/ext_gui/inline_svg.cpp +219 -0
  377. package/runtime/ext_gui/inline_svg.h +41 -0
  378. package/runtime/ext_gui/layout.cpp +18 -0
  379. package/runtime/ext_gui/layout.h +7 -0
  380. package/runtime/ext_gui/layout_flow.cpp +4 -3
  381. package/runtime/ext_gui/paint.cpp +14 -0
  382. package/runtime/ext_gui/paint.h +5 -1
  383. package/runtime/ext_gui/renderer_image.cpp +53 -25
  384. package/runtime/ext_gui/renderer_shaders.h +2 -2
  385. package/runtime/ext_gui/stb_image.h +1 -17
  386. package/runtime/ext_gui/style_ua.cpp +3 -0
  387. package/runtime/ext_gui/svg.cpp +122 -39
  388. package/runtime/ext_gui/svg.h +14 -3
  389. package/runtime/ext_gui/window.cpp +28 -0
  390. package/runtime/ext_node/child_process/child_process.c +173 -73
  391. package/runtime/ext_node/fs/async_api.c +314 -0
  392. package/runtime/ext_node/fs/async_complete.c +99 -0
  393. package/runtime/ext_node/fs/async_fh.c +206 -0
  394. package/runtime/ext_node/fs/async_job.c +81 -0
  395. package/runtime/ext_node/fs/async_job.h +132 -0
  396. package/runtime/ext_node/fs/async_worker.c +534 -0
  397. package/runtime/ext_node/fs/async_worker_dir.c +439 -0
  398. package/runtime/ext_node/fs/async_worker_dir.h +33 -0
  399. package/runtime/ext_node/fs/async_worker_fd.c +74 -0
  400. package/runtime/ext_node/fs/dir.c +60 -15
  401. package/runtime/ext_node/fs/fs_common.h +9 -0
  402. package/runtime/ext_node/fs/fs_ops.c +18 -29
  403. package/runtime/ext_node/fs/parts/builtins.inc +34 -0
  404. package/runtime/ext_node/fs/parts/platform.inc +66 -0
  405. package/runtime/ext_node/fs/promises.c +44 -234
  406. package/runtime/rt.h +15 -0
  407. package/runtime/rt_internal.h +108 -0
  408. package/runtime/xt_alloc.c +43 -7
  409. package/runtime/xt_array_buffer.c +284 -0
  410. package/runtime/xt_async.c +46 -21
  411. package/runtime/xt_async_io.c +333 -0
  412. package/runtime/xt_async_io.h +47 -0
  413. package/runtime/xt_bigint/helpers.inc +3 -3
  414. package/runtime/xt_builtins.c +21 -17
  415. package/runtime/xt_constructors.c +12 -2
  416. package/runtime/xt_containers/access.inc +148 -3
  417. package/runtime/xt_containers/objects.inc +26 -2
  418. package/runtime/xt_containers/shapes.inc +71 -0
  419. package/runtime/xt_containers.c +1 -0
  420. package/runtime/xt_coroutine.c +17 -0
  421. package/runtime/xt_fetch/async.inc +295 -0
  422. package/runtime/xt_fetch/request.inc +6 -183
  423. package/runtime/xt_fetch/socket.inc +5 -4
  424. package/runtime/xt_fetch.c +6 -4
  425. package/runtime/xt_generator.c +299 -10
  426. package/runtime/xt_io/inspect.inc +112 -0
  427. package/runtime/xt_loop.c +79 -7
  428. package/runtime/xt_performance.c +37 -0
  429. package/runtime/xt_promise.c +63 -1
  430. package/runtime/xt_stdlib/arrays.inc +1 -1
  431. package/runtime/xt_stdlib/dispatch.inc +46 -11
  432. package/runtime/xt_stdlib/strings.inc +1 -1
  433. package/runtime/xt_stdlib2/array-statics.inc +25 -0
  434. package/runtime/xt_stdlib2/arrays.inc +5 -3
  435. package/runtime/xt_stdlib2/container.inc +5 -0
  436. package/runtime/xt_stdlib2/date.inc +111 -3
  437. package/runtime/xt_stdlib2/error.inc +24 -0
  438. package/runtime/xt_stdlib2/json.inc +310 -19
  439. package/runtime/xt_stdlib2/number-string-statics.inc +1 -1
  440. package/runtime/xt_stdlib2/objects.inc +122 -0
  441. package/runtime/xt_stdlib2/set.inc +1 -1
  442. package/runtime/xt_structured_clone.c +159 -0
  443. package/runtime/xt_symbol.c +2 -2
  444. package/runtime/xt_text_codec.c +69 -0
  445. package/runtime/xt_typed_array/construction.inc +35 -5
  446. package/runtime/xt_typed_array/elements.inc +159 -0
  447. package/runtime/xt_typed_array/methods.inc +21 -5
  448. package/runtime/xt_typed_array.c +7 -10
  449. package/runtime/xt_url.c +375 -0
  450. package/runtime/xt_values/arithmetic.inc +2 -2
  451. package/runtime/xt_values/conversions.inc +1 -1
  452. package/runtime/xt_weak.c +281 -0
  453. package/scripts/build-gui.ts +133 -60
  454. package/scripts/check-version.ts +3 -3
  455. package/src/binder/declarations.ts +14 -3
  456. package/src/cli/hints.ts +8 -1
  457. package/src/cli/main.ts +119 -18
  458. package/src/cli/watch.ts +101 -0
  459. package/src/codegen/generator/calls/access.ts +10 -2
  460. package/src/codegen/generator/calls/closures.ts +12 -4
  461. package/src/codegen/generator/context.ts +23 -3
  462. package/src/codegen/generator/expressions/operators.ts +27 -13
  463. package/src/codegen/generator/expressions/primary.ts +4 -0
  464. package/src/codegen/generator/module.ts +0 -7
  465. package/src/codegen/generator/numeric.ts +85 -11
  466. package/src/codegen/generator/state.ts +23 -0
  467. package/src/codegen/generator/statements/control-flow.ts +1 -4
  468. package/src/codegen/generator/statements/loops.ts +50 -16
  469. package/src/codegen/generator/tables.ts +26 -1
  470. package/src/diagnostics/diagnostic.ts +23 -3
  471. package/src/driver/app-artifacts.ts +77 -0
  472. package/src/driver/build-key.ts +55 -0
  473. package/src/driver/bundler/graph.ts +63 -13
  474. package/src/driver/bundler/merge.ts +4 -1
  475. package/src/driver/compiler.ts +94 -328
  476. package/src/driver/config.ts +11 -0
  477. package/src/driver/frontend.ts +120 -0
  478. package/src/driver/index.ts +0 -1
  479. package/src/driver/options.ts +70 -0
  480. package/src/driver/runtime-objects.ts +134 -0
  481. package/src/driver/toolchain-provider.ts +4 -0
  482. package/src/driver/toolchain.ts +154 -10
  483. package/src/driver/version.ts +12 -0
  484. package/src/driver/win-icon.ts +36 -36
  485. package/src/extensions/node/fs/index.ts +12 -3
  486. package/src/extensions/node/fs-promises/index.ts +15 -6
  487. package/src/parser/declarations/classes.ts +4 -0
  488. package/src/parser/declarations/functions.ts +12 -1
  489. package/src/parser/modules.ts +8 -4
  490. package/src/parser/parser.ts +28 -0
@@ -44,7 +44,8 @@ float Layouter::verticalEdges(const LayoutBox *box) const {
44
44
  float Layouter::preferredContentWidth(const LayoutBox *box, float available) const {
45
45
  const XtStyle &style = *box->style;
46
46
  if (!isAuto(style.width)) return px(style.width, available, style.font_size, 0.0f);
47
- if ((box->is_image || box->is_canvas) && box->intrinsic_width > 0) return box->intrinsic_width;
47
+ if ((box->is_image || box->is_canvas || box->is_inline_svg) && box->intrinsic_width > 0)
48
+ return box->intrinsic_width;
48
49
  float best = 0;
49
50
  for (const std::unique_ptr<LayoutBox> &child : box->children) {
50
51
  if (child->display == Display::None) continue;
@@ -225,8 +226,8 @@ float Layouter::layoutBlock(LayoutBox *box, float x, float y, float availableWid
225
226
  if (contentHeight < 0) contentHeight = 0;
226
227
  }
227
228
  /* Replaced elements keep their aspect ratio when only one axis is set. */
228
- if ((box->is_image || box->is_canvas) && forcedContentHeight < 0 && isAuto(style.height) &&
229
- box->intrinsic_width > 0 && box->intrinsic_height > 0) {
229
+ if ((box->is_image || box->is_canvas || box->is_inline_svg) && forcedContentHeight < 0 &&
230
+ isAuto(style.height) && box->intrinsic_width > 0 && box->intrinsic_height > 0) {
230
231
  contentHeight = contentWidth * box->intrinsic_height / box->intrinsic_width;
231
232
  }
232
233
  box->content_height = contentHeight;
@@ -187,6 +187,16 @@ void paintBox(const LayoutBox *box, DisplayList &out, const PaintClip &clip) {
187
187
  image.media_id = box->media_id;
188
188
  image.transform = matrix;
189
189
  addImage(image, out, clip);
190
+ } else if (box->is_inline_svg && !box->svg_markup.empty() && box->content_width > 0.0f &&
191
+ box->content_height > 0.0f) {
192
+ PaintImage image;
193
+ image.x = box->content_x;
194
+ image.y = box->content_y;
195
+ image.width = box->content_width;
196
+ image.height = box->content_height;
197
+ image.svg = box->svg_markup;
198
+ image.transform = matrix;
199
+ addImage(image, out, clip);
190
200
  } else if (box->is_image && !box->image_src.empty() && box->content_width > 0.0f &&
191
201
  box->content_height > 0.0f) {
192
202
  PaintImage image;
@@ -243,6 +253,10 @@ std::string DisplayList::dump() const {
243
253
  std::snprintf(buffer, sizeof(buffer), "image x=%.1f y=%.1f w=%.1f h=%.1f media=%llu",
244
254
  image.x, image.y, image.width, image.height,
245
255
  (unsigned long long)image.media_id);
256
+ } else if (!image.svg.empty()) {
257
+ std::snprintf(buffer, sizeof(buffer),
258
+ "image x=%.1f y=%.1f w=%.1f h=%.1f inline-svg=%zu", image.x, image.y,
259
+ image.width, image.height, image.svg.size());
246
260
  } else if (image.canvas_id != 0) {
247
261
  std::snprintf(buffer, sizeof(buffer), "image x=%.1f y=%.1f w=%.1f h=%.1f canvas=%llu",
248
262
  image.x, image.y, image.width, image.height,
@@ -51,13 +51,17 @@ struct PaintText {
51
51
  /** An image to draw, scaled into the given rectangle (viewport-relative).
52
52
  * A non-zero `media_id` names a live `<video>` frame owned by the media
53
53
  * subsystem; a non-zero `canvas_id` names a live `<canvas>` bitmap owned by the
54
- * DOM; `src` is then empty and the renderer binds that subsystem's texture. */
54
+ * DOM; `src` is then empty and the renderer binds that subsystem's texture.
55
+ * A non-empty `svg` carries the serialized `<svg>` subtree of an inline SVG
56
+ * element, which the renderer rasterises at the drawn device size (there is no
57
+ * file to load). */
55
58
  struct PaintImage {
56
59
  float x = 0;
57
60
  float y = 0;
58
61
  float width = 0;
59
62
  float height = 0;
60
63
  std::string src;
64
+ std::string svg;
61
65
  uint64_t media_id = 0;
62
66
  uint64_t canvas_id = 0;
63
67
  Matrix2D transform;
@@ -12,6 +12,7 @@
12
12
  #include "canvas.h"
13
13
  #include "image.h"
14
14
  #include "media.h"
15
+ #include "svg.h"
15
16
 
16
17
  #include "renderer_shaders.h"
17
18
 
@@ -227,6 +228,32 @@ SDL_GPUGraphicsPipeline *createImagePipeline(SDL_GPUDevice *device, SDL_Window *
227
228
  return pipeline;
228
229
  }
229
230
 
231
+ /** Create an RGBA texture holding `image` and upload its pixels. Returns null
232
+ * (after reporting the SDL error) when either step fails. */
233
+ SDL_GPUTexture *createImageTexture(SDL_GPUDevice *device, const xtgui::Image &image) {
234
+ SDL_GPUTextureCreateInfo info;
235
+ memset(&info, 0, sizeof(info));
236
+ info.type = SDL_GPU_TEXTURETYPE_2D;
237
+ info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
238
+ info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
239
+ info.width = (Uint32)image.width;
240
+ info.height = (Uint32)image.height;
241
+ info.layer_count_or_depth = 1;
242
+ info.num_levels = 1;
243
+ info.sample_count = SDL_GPU_SAMPLECOUNT_1;
244
+ SDL_GPUTexture *texture = SDL_CreateGPUTexture(device, &info);
245
+ if (texture == nullptr) {
246
+ fprintf(stderr, "xt_gui: image texture creation failed: %s\n", SDL_GetError());
247
+ return nullptr;
248
+ }
249
+ uint32_t bytes = (uint32_t)(image.pixels.size());
250
+ if (!uploadPixels(device, texture, image.width, image.height, image.pixels.data(), bytes)) {
251
+ SDL_ReleaseGPUTexture(device, texture);
252
+ return nullptr;
253
+ }
254
+ return texture;
255
+ }
256
+
230
257
  /** Decode `src` (cached) and upload it as an RGBA texture. Vector sources are
231
258
  * rasterised at the drawn pixel size and cached by that size; bitmaps decode at
232
259
  * their intrinsic size and are cached by path. */
@@ -246,30 +273,29 @@ SDL_GPUTexture *ensureImageTexture(SDL_GPUDevice *device, const std::string &src
246
273
  return nullptr;
247
274
  }
248
275
 
249
- SDL_GPUTextureCreateInfo info;
250
- memset(&info, 0, sizeof(info));
251
- info.type = SDL_GPU_TEXTURETYPE_2D;
252
- info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
253
- info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
254
- info.width = (Uint32)image->width;
255
- info.height = (Uint32)image->height;
256
- info.layer_count_or_depth = 1;
257
- info.num_levels = 1;
258
- info.sample_count = SDL_GPU_SAMPLECOUNT_1;
259
- SDL_GPUTexture *texture = SDL_CreateGPUTexture(device, &info);
260
- if (texture == nullptr) {
261
- fprintf(stderr, "xt_gui: image texture creation failed: %s\n", SDL_GetError());
262
- g_image_textures.emplace(key, nullptr);
263
- return nullptr;
264
- }
276
+ SDL_GPUTexture *texture = createImageTexture(device, *image);
277
+ g_image_textures.emplace(key, texture);
278
+ return texture;
279
+ }
265
280
 
266
- uint32_t bytes = (uint32_t)(image->pixels.size());
267
- if (!uploadPixels(device, texture, image->width, image->height, image->pixels.data(), bytes)) {
268
- SDL_ReleaseGPUTexture(device, texture);
281
+ /** Rasterise the serialized subtree of an inline `<svg>` at the drawn pixel
282
+ * size and upload it. The markup is the cache key: a static document therefore
283
+ * rasterises once per drawn size, and an edited one gets a fresh texture. */
284
+ SDL_GPUTexture *ensureInlineSvgTexture(SDL_GPUDevice *device, const std::string &markup,
285
+ int pixel_width, int pixel_height) {
286
+ std::string key = "inline-svg@" + std::to_string(pixel_width) + "x" +
287
+ std::to_string(pixel_height) + ":" + markup;
288
+ auto found = g_image_textures.find(key);
289
+ if (found != g_image_textures.end()) return found->second;
290
+
291
+ xtgui::Image image;
292
+ if (!xtgui::xt_svg_markup_render(markup, pixel_width, pixel_height, &image)) {
293
+ fprintf(stderr, "xt_gui: could not rasterise inline SVG\n");
269
294
  g_image_textures.emplace(key, nullptr);
270
295
  return nullptr;
271
296
  }
272
297
 
298
+ SDL_GPUTexture *texture = createImageTexture(device, image);
273
299
  g_image_textures.emplace(key, texture);
274
300
  return texture;
275
301
  }
@@ -298,18 +324,20 @@ void xt_gui_image_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
298
324
  for (size_t index = 0; index < list.images.size(); index++) {
299
325
  const xtgui::PaintImage &image = list.images[index];
300
326
  if (image.width <= 0.0f || image.height <= 0.0f) continue;
327
+ /* Draw-time device pixels: an SVG (file or inline) is rasterised at this
328
+ * size so it stays crisp on HiDPI and when scaled. */
329
+ int pixel_width = (int)(image.width * scale + 0.5f);
330
+ int pixel_height = (int)(image.height * scale + 0.5f);
331
+ if (pixel_width < 1) pixel_width = 1;
332
+ if (pixel_height < 1) pixel_height = 1;
301
333
  SDL_GPUTexture *texture = nullptr;
302
334
  if (image.canvas_id != 0) {
303
335
  texture = ensureCanvasTexture(device, image.canvas_id);
304
336
  } else if (image.media_id != 0) {
305
337
  texture = ensureMediaTexture(device, image.media_id);
338
+ } else if (!image.svg.empty()) {
339
+ texture = ensureInlineSvgTexture(device, image.svg, pixel_width, pixel_height);
306
340
  } else {
307
- /* Draw-time device pixels: an SVG is rasterised at this size so it stays
308
- * crisp on HiDPI and when scaled. */
309
- int pixel_width = (int)(image.width * scale + 0.5f);
310
- int pixel_height = (int)(image.height * scale + 0.5f);
311
- if (pixel_width < 1) pixel_width = 1;
312
- if (pixel_height < 1) pixel_height = 1;
313
341
  texture = ensureImageTexture(device, image.src, pixel_width, pixel_height);
314
342
  }
315
343
  if (texture == nullptr) continue;
@@ -6,8 +6,8 @@
6
6
  * them, one per SDL_GPU backend:
7
7
  *
8
8
  * - Metal: the MSL string literals below, which SDL_GPU compiles at runtime.
9
- * - Vulkan: SPIR-V blobs in `renderer_shaders_data.h`, compiled from
10
- * `spirv/*.{vert,frag}` by `scripts/build-gui-shaders.mjs`.
9
+ * - Vulkan: SPIR-V blobs in `renderer_shaders_data.h`, compiled from the
10
+ * `.vert`/`.frag` sources in `spirv/` by `scripts/build-gui-shaders.mjs`.
11
11
  * - Direct3D 12: DXIL blobs from the same header, compiled from `shaders.hlsl`.
12
12
  *
13
13
  * `selectShader` resolves a logical program and stage to whichever of those the
@@ -706,21 +706,6 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
706
706
  #define STBI_NO_SIMD
707
707
  #endif
708
708
 
709
- #if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
710
- // Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
711
- //
712
- // 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
713
- // Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
714
- // As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
715
- // simultaneously enabling "-mstackrealign".
716
- //
717
- // See https://github.com/nothings/stb/issues/81 for more information.
718
- //
719
- // So default to no SSE2 on 32-bit MinGW. If you've read this far and added
720
- // -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
721
- #define STBI_NO_SIMD
722
- #endif
723
-
724
709
  #if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))
725
710
  #define STBI_SSE2
726
711
  #include <emmintrin.h>
@@ -7805,10 +7790,9 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user
7805
7790
  bug with < 92 byte PIC,PNM,HDR,TGA
7806
7791
  2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value
7807
7792
  2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
7808
- 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
7809
7793
  2.03 (2015-04-12) extra corruption checking (mmozeiko)
7810
7794
  stbi_set_flip_vertically_on_load (nguillemot)
7811
- fix NEON support; fix mingw support
7795
+ fix NEON support
7812
7796
  2.02 (2015-01-19) fix incorrect assert, fix warning
7813
7797
  2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
7814
7798
  2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
@@ -40,6 +40,9 @@ void xt_style_apply_user_agent(const Node *node, XtStyle *style) {
40
40
  style->display = Display::InlineBlock;
41
41
  }
42
42
  if (tag == "img") style->display = Display::InlineBlock;
43
+ /* An inline `<svg>` is a replaced inline-block too: its intrinsic size comes
44
+ * from the SVG document and its subtree is vector art, not HTML boxes. */
45
+ if (tag == "svg") style->display = Display::InlineBlock;
43
46
  /* `<video>` mirrors `<img>` (a replaced inline-block; 300x150 by default from
44
47
  * layout), while `<audio>` and its `<source>`/`<track>` children have no
45
48
  * rendered box of their own. */
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * The heavy lifting is the vendored NanoSVG library (`nanosvg.h` +
5
5
  * `nanosvgrast.h`, zlib licence, fetched verbatim). This file is only the glue:
6
- * path detection, a parsed-document cache and the scale-to-fit call. NanoSVG
7
- * emits straight (non-premultiplied) RGBA8, which is exactly the `Image`
8
- * layout the rest of the engine expects.
6
+ * path detection, parsed-document caches (per file and per inline markup) and
7
+ * the scale-to-fit call. NanoSVG emits straight (non-premultiplied) RGBA8,
8
+ * which is exactly the `Image` layout the rest of the engine expects.
9
9
  */
10
10
 
11
11
  #include "svg.h"
@@ -31,6 +31,7 @@
31
31
 
32
32
  #include <algorithm>
33
33
  #include <cctype>
34
+ #include <cstdint>
34
35
  #include <cstdio>
35
36
  #include <fstream>
36
37
  #include <string>
@@ -89,16 +90,13 @@ NSVGrasterizer *&rasterizer() {
89
90
  return value;
90
91
  }
91
92
 
92
- /** Parse `path` once and remember the result (including failures, so a missing
93
- * file is not retried every frame). */
94
- NSVGimage *parseCached(const std::string &path) {
95
- auto &cache = parsedCache();
96
- auto found = cache.find(path);
97
- if (found != cache.end()) return found->second;
98
- NSVGimage *image = nsvgParseFromFile(path.c_str(), "px", 96.0f);
99
- cache.emplace(path, image);
100
- return image;
101
- }
93
+ /** One parsed inline-SVG document in the markup cache. `stamp` is the last use
94
+ * (see `parseMarkup`); `image` is null when the markup failed to parse so a
95
+ * broken document is not retried on every layout. */
96
+ struct MarkupDocument {
97
+ NSVGimage *image = nullptr;
98
+ uint64_t stamp = 0;
99
+ };
102
100
 
103
101
  float intrinsicWidth(const NSVGimage *image) {
104
102
  return image->width > 0.0f ? image->width : kDefaultWidth;
@@ -108,33 +106,53 @@ float intrinsicHeight(const NSVGimage *image) {
108
106
  return image->height > 0.0f ? image->height : kDefaultHeight;
109
107
  }
110
108
 
111
- } // namespace
109
+ /** Inline SVG markup is authored in the document and can change at any time, so
110
+ * unlike the per-path file cache this one is bounded: a script that animates an
111
+ * inline `<svg>` attribute every frame would otherwise add one parse (and its
112
+ * NSVGimage tree) per frame forever. */
113
+ constexpr size_t kMaxMarkupDocuments = 256;
112
114
 
113
- bool xt_svg_is_svg(const std::string &path) {
114
- auto &cache = detectCache();
115
- auto found = cache.find(path);
116
- if (found != cache.end()) return found->second;
117
- bool result = hasSvgExtension(path) || prefixLooksLikeSvg(path);
118
- cache.emplace(path, result);
119
- return result;
115
+ std::unordered_map<std::string, MarkupDocument> &markupCache() {
116
+ static std::unordered_map<std::string, MarkupDocument> cache;
117
+ return cache;
120
118
  }
121
119
 
122
- bool xt_svg_size(const std::string &path, int *width, int *height) {
123
- NSVGimage *image = parseCached(path);
124
- if (image == nullptr) return false;
125
- float w = intrinsicWidth(image);
126
- float h = intrinsicHeight(image);
127
- if (w <= 0.0f || h <= 0.0f) return false;
128
- if (width != nullptr) *width = (int)(w + 0.5f);
129
- if (height != nullptr) *height = (int)(h + 0.5f);
130
- return true;
120
+ uint64_t nextStamp() {
121
+ static uint64_t counter = 0;
122
+ return ++counter;
131
123
  }
132
124
 
133
- bool xt_svg_render(const std::string &path, int width, int height, Image *out) {
134
- if (out == nullptr) return false;
135
- NSVGimage *image = parseCached(path);
136
- if (image == nullptr) return false;
125
+ /** Parse an inline SVG document once and remember the result. Evicts the
126
+ * least-recently-used entry when the table is full; nothing outside this module
127
+ * keeps an `NSVGimage*`, so a parse can always be dropped safely. */
128
+ NSVGimage *parseMarkup(const std::string &markup) {
129
+ auto &cache = markupCache();
130
+ uint64_t stamp = nextStamp();
131
+ auto found = cache.find(markup);
132
+ if (found != cache.end()) {
133
+ found->second.stamp = stamp;
134
+ return found->second.image;
135
+ }
136
+ if (cache.size() >= kMaxMarkupDocuments) {
137
+ auto oldest = cache.begin();
138
+ for (auto it = cache.begin(); it != cache.end(); ++it) {
139
+ if (it->second.stamp < oldest->second.stamp) oldest = it;
140
+ }
141
+ if (oldest->second.image != nullptr) nsvgDelete(oldest->second.image);
142
+ cache.erase(oldest);
143
+ }
144
+ /* NanoSVG's XML parser NUL-terminates tags in place, so it needs its own
145
+ * mutable copy of the document. */
146
+ std::string document = markup;
147
+ NSVGimage *image = nsvgParse(document.data(), "px", 96.0f);
148
+ cache.emplace(markup, MarkupDocument{image, stamp});
149
+ return image;
150
+ }
137
151
 
152
+ /** Rasterise a parsed document at `width` x `height` device pixels, at the
153
+ * larger axis scale so neither axis is under-sampled. Returns false when the
154
+ * size is unusable or the rasteriser cannot be created. */
155
+ bool rasterize(NSVGimage *image, int width, int height, Image *out) {
138
156
  float source_width = intrinsicWidth(image);
139
157
  float source_height = intrinsicHeight(image);
140
158
  int target_width = width > 0 ? width : (int)(source_width + 0.5f);
@@ -143,11 +161,6 @@ bool xt_svg_render(const std::string &path, int width, int height, Image *out) {
143
161
  target_width = std::min(target_width, kMaxDimension);
144
162
  target_height = std::min(target_height, kMaxDimension);
145
163
 
146
- /* Rasterise at the source aspect ratio, at the larger of the two axis scales
147
- * (so neither axis is under-sampled), then let the quad stretch the texture
148
- * to the box — exactly how a bitmap would behave under CSS `object-fit:
149
- * fill`. The common case (layout preserved the aspect ratio) makes this equal
150
- * to the requested size. */
151
164
  float scale = std::max((float)target_width / source_width, (float)target_height / source_height);
152
165
  scale = std::min(scale, (float)kMaxDimension / source_width);
153
166
  scale = std::min(scale, (float)kMaxDimension / source_height);
@@ -167,12 +180,82 @@ bool xt_svg_render(const std::string &path, int width, int height, Image *out) {
167
180
  return true;
168
181
  }
169
182
 
183
+ /** Parse `path` once and remember the result (including failures, so a missing
184
+ * file is not retried every frame). */
185
+ NSVGimage *parseCached(const std::string &path) {
186
+ auto &cache = parsedCache();
187
+ auto found = cache.find(path);
188
+ if (found != cache.end()) return found->second;
189
+ NSVGimage *image = nsvgParseFromFile(path.c_str(), "px", 96.0f);
190
+ cache.emplace(path, image);
191
+ return image;
192
+ }
193
+
194
+ } // namespace
195
+
196
+ bool xt_svg_is_svg(const std::string &path) {
197
+ auto &cache = detectCache();
198
+ auto found = cache.find(path);
199
+ if (found != cache.end()) return found->second;
200
+ bool result = hasSvgExtension(path) || prefixLooksLikeSvg(path);
201
+ cache.emplace(path, result);
202
+ return result;
203
+ }
204
+
205
+ bool xt_svg_size(const std::string &path, int *width, int *height) {
206
+ NSVGimage *image = parseCached(path);
207
+ if (image == nullptr) return false;
208
+ float w = intrinsicWidth(image);
209
+ float h = intrinsicHeight(image);
210
+ if (w <= 0.0f || h <= 0.0f) return false;
211
+ if (width != nullptr) *width = (int)(w + 0.5f);
212
+ if (height != nullptr) *height = (int)(h + 0.5f);
213
+ return true;
214
+ }
215
+
216
+ bool xt_svg_render(const std::string &path, int width, int height, Image *out) {
217
+ if (out == nullptr) return false;
218
+ NSVGimage *image = parseCached(path);
219
+ if (image == nullptr) return false;
220
+ return rasterize(image, width, height, out);
221
+ }
222
+
223
+ bool xt_svg_markup_size(const std::string &markup, int *width, int *height) {
224
+ NSVGimage *image = parseMarkup(markup);
225
+ if (image == nullptr) return false;
226
+ float w = intrinsicWidth(image);
227
+ float h = intrinsicHeight(image);
228
+ if (w <= 0.0f || h <= 0.0f) return false;
229
+ if (width != nullptr) *width = (int)(w + 0.5f);
230
+ if (height != nullptr) *height = (int)(h + 0.5f);
231
+ return true;
232
+ }
233
+
234
+ bool xt_svg_markup_render(const std::string &markup, int width, int height, Image *out) {
235
+ if (out == nullptr) return false;
236
+ NSVGimage *image = parseMarkup(markup);
237
+ if (image == nullptr) return false;
238
+ return rasterize(image, width, height, out);
239
+ }
240
+
241
+ int xt_svg_markup_shapes(const std::string &markup) {
242
+ NSVGimage *image = parseMarkup(markup);
243
+ if (image == nullptr) return 0;
244
+ int count = 0;
245
+ for (const NSVGshape *shape = image->shapes; shape != nullptr; shape = shape->next) count++;
246
+ return count;
247
+ }
248
+
170
249
  void xt_svg_shutdown() {
171
250
  for (auto &entry : parsedCache()) {
172
251
  if (entry.second != nullptr) nsvgDelete(entry.second);
173
252
  }
174
253
  parsedCache().clear();
175
254
  detectCache().clear();
255
+ for (auto &entry : markupCache()) {
256
+ if (entry.second.image != nullptr) nsvgDelete(entry.second.image);
257
+ }
258
+ markupCache().clear();
176
259
  if (rasterizer() != nullptr) {
177
260
  nsvgDeleteRasterizer(rasterizer());
178
261
  rasterizer() = nullptr;
@@ -9,9 +9,10 @@
9
9
  * (`nanosvg.h` + `nanosvgrast.h`) — the same class of low-level, third-party
10
10
  * image library `stb_image` is (see doc/gui.md).
11
11
  *
12
- * Only *files* are handled: `<img src="logo.svg">`. Inline `<svg>` trees in a
13
- * document are still ordinary unknown elements to the HTML parser and generate
14
- * no boxes.
12
+ * Both SVG *files* (`<img src="logo.svg">`) and inline `<svg>` trees go through
13
+ * this module: an inline element's DOM subtree is serialized into a document by
14
+ * `inline_svg.{h,cpp}` and parsed with the markup entry points below, so both
15
+ * kinds produce the same RGBA8 `Image` at the drawn device size.
15
16
  */
16
17
  #ifndef XT_GUI_SVG_H
17
18
  #define XT_GUI_SVG_H
@@ -30,6 +31,16 @@ bool xt_svg_is_svg(const std::string &path);
30
31
  * false when the file is missing or cannot be parsed. Cached per path. */
31
32
  bool xt_svg_size(const std::string &path, int *width, int *height);
32
33
 
34
+ /** The same two operations for an SVG *document string* rather than a file:
35
+ * the markup of an inline `<svg>` subtree (see `inline_svg.h`). The parse is
36
+ * cached by content (least-recently-used, so an animated document cannot grow
37
+ * the cache without bound); each rasterisation is fresh. */
38
+ bool xt_svg_markup_size(const std::string &markup, int *width, int *height);
39
+ bool xt_svg_markup_render(const std::string &markup, int width, int height, Image *out);
40
+
41
+ /** Number of shapes NanoSVG parsed out of `markup` (diagnostics/tests). */
42
+ int xt_svg_markup_shapes(const std::string &markup);
43
+
33
44
  /** Rasterise `path` to RGBA8. `width`/`height` are the requested pixel size;
34
45
  * when either is `<= 0` the intrinsic SVG size is used. The viewBox is scaled
35
46
  * uniformly at the larger of the two axis scales (preserving the SVG's aspect
@@ -12,6 +12,7 @@
12
12
 
13
13
  #include <algorithm>
14
14
 
15
+ #include "inline_svg.h"
15
16
  #include "paint.h"
16
17
  #include "text.h"
17
18
 
@@ -216,6 +217,32 @@ static xt_value win_paint_count(xt_value self, xt_value env, int32_t argc, xt_va
216
217
  return xt_number((double)list.rects.size());
217
218
  }
218
219
 
220
+ /** Diagnostic/test hook: the serialized SVG document of the first `<svg>`
221
+ * element matching `selector`, plus the intrinsic size and shape count the
222
+ * NanoSVG parse yields. Returns `undefined` when there is no such element. */
223
+ static xt_value win_inline_svg(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
224
+ (void)env;
225
+ XtGuiWindow *win = xt_gui_window_from_this(self);
226
+ if (win == nullptr || win->document == nullptr || argc < 1) return XT_UNDEFINED;
227
+ xt_gui_flush_dom(win);
228
+ xt_value selectorValue = xt_to_string(xt_arg(argc, argv, 0));
229
+ const char *selector = xt_string_data(selectorValue);
230
+ if (selector == nullptr) return XT_UNDEFINED;
231
+ const xtgui::Node *node = win->document->querySelector(selector);
232
+ if (!xtgui::xt_inline_svg_is_root(node)) return XT_UNDEFINED;
233
+ std::string markup = xtgui::xt_inline_svg_serialize(node);
234
+ int width = 0;
235
+ int height = 0;
236
+ xtgui::xt_svg_markup_size(markup, &width, &height);
237
+ xt_value object = xt_object_new();
238
+ xt_object_set(object, xt_string_from_cstr("markup"), xt_string_from_cstr(markup.c_str()));
239
+ xt_object_set(object, xt_string_from_cstr("width"), xt_number(width));
240
+ xt_object_set(object, xt_string_from_cstr("height"), xt_number(height));
241
+ xt_object_set(object, xt_string_from_cstr("shapes"),
242
+ xt_number(xtgui::xt_svg_markup_shapes(markup)));
243
+ return object;
244
+ }
245
+
219
246
  /** Diagnostic/test hook: advance the CSS transition clock by `ms`. */
220
247
  static xt_value win_advance(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
221
248
  (void)env;
@@ -527,6 +554,7 @@ xt_value xt_gui_window_proto(void) {
527
554
  define_method(proto, "setBackground", (void *)win_set_background);
528
555
  define_method(proto, "paintList", (void *)win_paint_list);
529
556
  define_method(proto, "paintCount", (void *)win_paint_count);
557
+ define_method(proto, "inlineSvg", (void *)win_inline_svg);
530
558
  define_method(proto, "advance", (void *)win_advance);
531
559
  define_method(proto, "measureText", (void *)win_measure_text);
532
560
  define_method(proto, "fontMetrics", (void *)win_font_metrics);