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.
- package/AGENTS.md +20 -10
- package/README.md +8 -7
- package/README.zh-CN.md +6 -6
- package/dist/src/binder/declarations.js +14 -3
- package/dist/src/binder/declarations.js.map +1 -1
- package/dist/src/cli/hints.js +7 -1
- package/dist/src/cli/hints.js.map +1 -1
- package/dist/src/cli/main.js +115 -15
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/cli/watch.d.ts +25 -0
- package/dist/src/cli/watch.js +93 -0
- package/dist/src/cli/watch.js.map +1 -0
- package/dist/src/codegen/generator/calls/access.js +11 -2
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/closures.js +12 -4
- package/dist/src/codegen/generator/calls/closures.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +8 -0
- package/dist/src/codegen/generator/context.js +22 -3
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/operators.js +17 -15
- package/dist/src/codegen/generator/expressions/operators.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.js +5 -0
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/module.js +0 -7
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/numeric.d.ts +6 -3
- package/dist/src/codegen/generator/numeric.js +54 -11
- package/dist/src/codegen/generator/numeric.js.map +1 -1
- package/dist/src/codegen/generator/state.js +23 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js +1 -4
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
- package/dist/src/codegen/generator/statements/loops.js +48 -16
- package/dist/src/codegen/generator/statements/loops.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +26 -1
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +3 -1
- package/dist/src/diagnostics/diagnostic.js +23 -3
- package/dist/src/diagnostics/diagnostic.js.map +1 -1
- package/dist/src/driver/app-artifacts.d.ts +42 -0
- package/dist/src/driver/app-artifacts.js +53 -0
- package/dist/src/driver/app-artifacts.js.map +1 -0
- package/dist/src/driver/build-key.d.ts +29 -0
- package/dist/src/driver/build-key.js +35 -0
- package/dist/src/driver/build-key.js.map +1 -0
- package/dist/src/driver/bundler/graph.js +61 -12
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +7 -1
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +10 -67
- package/dist/src/driver/compiler.js +95 -234
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +3 -0
- package/dist/src/driver/config.js +8 -0
- package/dist/src/driver/config.js.map +1 -1
- package/dist/src/driver/frontend.d.ts +37 -0
- package/dist/src/driver/frontend.js +92 -0
- package/dist/src/driver/frontend.js.map +1 -0
- package/dist/src/driver/index.d.ts +1 -1
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/options.d.ts +64 -0
- package/dist/src/driver/options.js +9 -0
- package/dist/src/driver/options.js.map +1 -0
- package/dist/src/driver/runtime-objects.d.ts +38 -0
- package/dist/src/driver/runtime-objects.js +112 -0
- package/dist/src/driver/runtime-objects.js.map +1 -0
- package/dist/src/driver/toolchain-provider.d.ts +4 -0
- package/dist/src/driver/toolchain-provider.js +4 -0
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.d.ts +32 -1
- package/dist/src/driver/toolchain.js +115 -11
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/driver/version.d.ts +12 -0
- package/dist/src/driver/version.js +13 -0
- package/dist/src/driver/version.js.map +1 -0
- package/dist/src/driver/win-icon.d.ts +7 -9
- package/dist/src/driver/win-icon.js +37 -35
- package/dist/src/driver/win-icon.js.map +1 -1
- package/dist/src/extensions/node/fs/index.d.ts +4 -3
- package/dist/src/extensions/node/fs/index.js +12 -3
- package/dist/src/extensions/node/fs/index.js.map +1 -1
- package/dist/src/extensions/node/fs-promises/index.d.ts +5 -5
- package/dist/src/extensions/node/fs-promises/index.js +15 -6
- package/dist/src/extensions/node/fs-promises/index.js.map +1 -1
- package/dist/src/parser/declarations/classes.js +5 -0
- package/dist/src/parser/declarations/classes.js.map +1 -1
- package/dist/src/parser/declarations/functions.js +13 -1
- package/dist/src/parser/declarations/functions.js.map +1 -1
- package/dist/src/parser/modules.js +8 -3
- package/dist/src/parser/modules.js.map +1 -1
- package/dist/src/parser/parser.d.ts +1 -0
- package/dist/src/parser/parser.js +23 -0
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/tests/cli/check.test.d.ts +6 -0
- package/dist/tests/cli/check.test.js +68 -0
- package/dist/tests/cli/check.test.js.map +1 -0
- package/dist/tests/cli/main.test.js +19 -0
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/cli/watch.test.d.ts +6 -0
- package/dist/tests/cli/watch.test.js +72 -0
- package/dist/tests/cli/watch.test.js.map +1 -0
- package/dist/tests/codegen/expressions.test.js +15 -3
- package/dist/tests/codegen/expressions.test.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +16 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/diagnostics/diagnostic.test.js +8 -0
- package/dist/tests/diagnostics/diagnostic.test.js.map +1 -1
- package/dist/tests/docs/structure.test.d.ts +1 -0
- package/dist/tests/docs/structure.test.js +92 -0
- package/dist/tests/docs/structure.test.js.map +1 -0
- package/dist/tests/driver/compiler.test.js +6 -0
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/driver/config.test.js +9 -0
- package/dist/tests/driver/config.test.js.map +1 -1
- package/dist/tests/driver/icon.test.js +19 -32
- package/dist/tests/driver/icon.test.js.map +1 -1
- package/dist/tests/driver/invalid-input.test.d.ts +10 -0
- package/dist/tests/driver/invalid-input.test.js +29 -0
- package/dist/tests/driver/invalid-input.test.js.map +1 -0
- package/dist/tests/driver/modules.test.js +42 -3
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/driver/toolchain-provider.test.js +27 -1
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/driver/toolchain.test.js +60 -2
- package/dist/tests/driver/toolchain.test.js.map +1 -1
- package/dist/tests/e2e/array-buffer.test.d.ts +5 -0
- package/dist/tests/e2e/array-buffer.test.js +38 -0
- package/dist/tests/e2e/array-buffer.test.js.map +1 -0
- package/dist/tests/e2e/array-from-iterables.test.d.ts +7 -0
- package/dist/tests/e2e/array-from-iterables.test.js +34 -0
- package/dist/tests/e2e/array-from-iterables.test.js.map +1 -0
- package/dist/tests/e2e/array-symbol-iterator.test.d.ts +8 -0
- package/dist/tests/e2e/array-symbol-iterator.test.js +42 -0
- package/dist/tests/e2e/array-symbol-iterator.test.js.map +1 -0
- package/dist/tests/e2e/async-await.test.js +1 -1
- package/dist/tests/e2e/async-fs.test.d.ts +9 -0
- package/dist/tests/e2e/async-fs.test.js +119 -0
- package/dist/tests/e2e/async-fs.test.js.map +1 -0
- package/dist/tests/e2e/async-generators.test.d.ts +1 -0
- package/dist/tests/e2e/async-generators.test.js +154 -0
- package/dist/tests/e2e/async-generators.test.js.map +1 -0
- package/dist/tests/e2e/await-ordering.test.d.ts +5 -0
- package/dist/tests/e2e/await-ordering.test.js +37 -0
- package/dist/tests/e2e/await-ordering.test.js.map +1 -0
- package/dist/tests/e2e/compile-builtins.test.js +1 -1
- package/dist/tests/e2e/compile-modules.test.js +7 -0
- package/dist/tests/e2e/compile-modules.test.js.map +1 -1
- package/dist/tests/e2e/date-parse.test.d.ts +8 -0
- package/dist/tests/e2e/date-parse.test.js +38 -0
- package/dist/tests/e2e/date-parse.test.js.map +1 -0
- package/dist/tests/e2e/default-anonymous-exports.test.d.ts +7 -0
- package/dist/tests/e2e/default-anonymous-exports.test.js +23 -0
- package/dist/tests/e2e/default-anonymous-exports.test.js.map +1 -0
- package/dist/tests/e2e/fetch.test.js +24 -0
- package/dist/tests/e2e/fetch.test.js.map +1 -1
- package/dist/tests/e2e/globals-microtask.test.d.ts +9 -0
- package/dist/tests/e2e/globals-microtask.test.js +37 -0
- package/dist/tests/e2e/globals-microtask.test.js.map +1 -0
- package/dist/tests/e2e/gui-inline-svg.test.d.ts +11 -0
- package/dist/tests/e2e/gui-inline-svg.test.js +160 -0
- package/dist/tests/e2e/gui-inline-svg.test.js.map +1 -0
- package/dist/tests/e2e/gui-media.test.js +8 -1
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/inspect-builtins.test.d.ts +10 -0
- package/dist/tests/e2e/inspect-builtins.test.js +43 -0
- package/dist/tests/e2e/inspect-builtins.test.js.map +1 -0
- package/dist/tests/e2e/json-builtin-objects.test.d.ts +9 -0
- package/dist/tests/e2e/json-builtin-objects.test.js +23 -0
- package/dist/tests/e2e/json-builtin-objects.test.js.map +1 -0
- package/dist/tests/e2e/json-circular.test.d.ts +6 -0
- package/dist/tests/e2e/json-circular.test.js +43 -0
- package/dist/tests/e2e/json-circular.test.js.map +1 -0
- package/dist/tests/e2e/json-parse-reviver.test.d.ts +6 -0
- package/dist/tests/e2e/json-parse-reviver.test.js +29 -0
- package/dist/tests/e2e/json-parse-reviver.test.js.map +1 -0
- package/dist/tests/e2e/json-stringify-replacer.test.d.ts +6 -0
- package/dist/tests/e2e/json-stringify-replacer.test.js +27 -0
- package/dist/tests/e2e/json-stringify-replacer.test.js.map +1 -0
- package/dist/tests/e2e/json-stringify-space.test.d.ts +6 -0
- package/dist/tests/e2e/json-stringify-space.test.js +23 -0
- package/dist/tests/e2e/json-stringify-space.test.js.map +1 -0
- package/dist/tests/e2e/method-dispatch-errors.test.d.ts +9 -0
- package/dist/tests/e2e/method-dispatch-errors.test.js +38 -0
- package/dist/tests/e2e/method-dispatch-errors.test.js.map +1 -0
- package/dist/tests/e2e/native-extensions.test.js +1 -1
- package/dist/tests/e2e/native-extensions.test.js.map +1 -1
- package/dist/tests/e2e/promise-with-resolvers.test.d.ts +5 -0
- package/dist/tests/e2e/promise-with-resolvers.test.js +20 -0
- package/dist/tests/e2e/promise-with-resolvers.test.js.map +1 -0
- package/dist/tests/e2e/property-descriptors.test.d.ts +5 -0
- package/dist/tests/e2e/property-descriptors.test.js +25 -0
- package/dist/tests/e2e/property-descriptors.test.js.map +1 -0
- package/dist/tests/e2e/property-ic.test.d.ts +1 -0
- package/dist/tests/e2e/property-ic.test.js +55 -0
- package/dist/tests/e2e/property-ic.test.js.map +1 -0
- package/dist/tests/e2e/runtime-errors.test.d.ts +10 -0
- package/dist/tests/e2e/runtime-errors.test.js +52 -0
- package/dist/tests/e2e/runtime-errors.test.js.map +1 -0
- package/dist/tests/e2e/structured-clone.test.d.ts +6 -0
- package/dist/tests/e2e/structured-clone.test.js +49 -0
- package/dist/tests/e2e/structured-clone.test.js.map +1 -0
- package/dist/tests/e2e/text-codec.test.d.ts +6 -0
- package/dist/tests/e2e/text-codec.test.js +24 -0
- package/dist/tests/e2e/text-codec.test.js.map +1 -0
- package/dist/tests/e2e/typed-array-views.test.d.ts +6 -0
- package/dist/tests/e2e/typed-array-views.test.js +39 -0
- package/dist/tests/e2e/typed-array-views.test.js.map +1 -0
- package/dist/tests/e2e/url-search-params.test.d.ts +5 -0
- package/dist/tests/e2e/url-search-params.test.js +30 -0
- package/dist/tests/e2e/url-search-params.test.js.map +1 -0
- package/dist/tests/e2e/weak-collections.test.d.ts +1 -0
- package/dist/tests/e2e/weak-collections.test.js +88 -0
- package/dist/tests/e2e/weak-collections.test.js.map +1 -0
- package/dist/tests/parser/declarations.test.js +12 -0
- package/dist/tests/parser/declarations.test.js.map +1 -1
- package/dist/tests/parser/module-syntax.test.js +9 -0
- package/dist/tests/parser/module-syntax.test.js.map +1 -1
- package/dist/tests/parser/parser.test.js +7 -0
- package/dist/tests/parser/parser.test.js.map +1 -1
- package/dist/tests/version.test.js +5 -1
- package/dist/tests/version.test.js.map +1 -1
- package/doc/ai/README.md +4 -3
- package/doc/ai/cli.md +41 -0
- package/doc/ai/contributing.md +20 -16
- package/doc/ai/extensions.md +13 -10
- package/doc/ai/language-support.md +19 -14
- package/doc/ai/troubleshooting.md +11 -9
- package/doc/ai/zh-CN/README.md +3 -2
- package/doc/ai/zh-CN/cli.md +35 -0
- package/doc/ai/zh-CN/contributing.md +16 -15
- package/doc/ai/zh-CN/extensions.md +12 -9
- package/doc/ai/zh-CN/language-support.md +19 -15
- package/doc/ai/zh-CN/troubleshooting.md +9 -8
- package/doc/gui/api.md +8 -0
- package/doc/gui/build.md +13 -4
- package/doc/gui/known-issues.md +19 -14
- package/doc/gui/media.md +32 -3
- package/doc/gui/rendering.md +3 -1
- package/doc/gui.md +28 -5
- package/doc/icon.md +5 -4
- package/doc/implemented/async.md +51 -0
- package/doc/implemented/binder.md +13 -0
- package/doc/implemented/cli.md +47 -0
- package/doc/implemented/codegen.md +33 -0
- package/doc/implemented/collections.md +26 -0
- package/doc/implemented/driver.md +19 -0
- package/doc/implemented/extensions.md +19 -0
- package/doc/implemented/fetch.md +44 -0
- package/doc/implemented/lexer.md +23 -0
- package/doc/implemented/modules.md +28 -0
- package/doc/implemented/node/assert.md +17 -0
- package/doc/implemented/node/buffer.md +29 -0
- package/doc/implemented/node/child-process.md +29 -0
- package/doc/implemented/node/crypto.md +9 -0
- package/doc/implemented/node/dgram.md +15 -0
- package/doc/implemented/node/events.md +37 -0
- package/doc/implemented/node/fs-promises.md +49 -0
- package/doc/implemented/node/fs.md +112 -0
- package/doc/implemented/node/http.md +21 -0
- package/doc/implemented/node/net.md +17 -0
- package/doc/implemented/node/os.md +22 -0
- package/doc/implemented/node/path.md +33 -0
- package/doc/implemented/node/process.md +23 -0
- package/doc/implemented/node/querystring.md +20 -0
- package/doc/implemented/node/stream-promises.md +8 -0
- package/doc/implemented/node/stream.md +19 -0
- package/doc/implemented/node/test.md +10 -0
- package/doc/implemented/node/url.md +8 -0
- package/doc/implemented/node/util.md +25 -0
- package/doc/implemented/node/worker-threads.md +10 -0
- package/doc/implemented/node/zlib.md +8 -0
- package/doc/implemented/node.md +48 -0
- package/doc/implemented/operators.md +38 -0
- package/doc/implemented/parser.md +58 -0
- package/doc/implemented/pipeline.md +28 -0
- package/doc/implemented/runtime-core.md +32 -0
- package/doc/implemented/stdlib.md +78 -0
- package/doc/implemented/strings.md +27 -0
- package/doc/implemented/tests.md +10 -0
- package/doc/implemented/typed-arrays.md +26 -0
- package/doc/implemented/value-model.md +18 -0
- package/doc/implemented.md +54 -355
- package/doc/node-implemented.md +3 -585
- package/doc/node-unimplemented.md +3 -164
- package/doc/requirements.md +23 -8
- package/doc/unimplemented/classes.md +22 -0
- package/doc/unimplemented/deviations.md +27 -0
- package/doc/unimplemented/expressions.md +26 -0
- package/doc/unimplemented/functions.md +21 -0
- package/doc/unimplemented/modules.md +22 -0
- package/doc/unimplemented/node/async.md +20 -0
- package/doc/unimplemented/node/bun.md +9 -0
- package/doc/unimplemented/node/fs-promises.md +20 -0
- package/doc/unimplemented/node/fs.md +30 -0
- package/doc/unimplemented/node/globals.md +23 -0
- package/doc/unimplemented/node/modules.md +21 -0
- package/doc/unimplemented/node.md +21 -0
- package/doc/unimplemented/statements.md +18 -0
- package/doc/unimplemented/stdlib.md +54 -0
- package/doc/unimplemented/toolchain.md +14 -0
- package/doc/unimplemented/types.md +12 -0
- package/doc/unimplemented.md +18 -275
- package/doc/xbintsc.config.schema.json +12 -0
- package/doc/zh-CN/gui/api.md +7 -0
- package/doc/zh-CN/gui/build.md +11 -3
- package/doc/zh-CN/gui/known-issues.md +17 -11
- package/doc/zh-CN/gui/media.md +26 -2
- package/doc/zh-CN/gui/rendering.md +2 -1
- package/doc/zh-CN/gui.md +21 -3
- package/doc/zh-CN/icon.md +5 -4
- package/doc/zh-CN/implemented/async.md +49 -0
- package/doc/zh-CN/implemented/binder.md +13 -0
- package/doc/zh-CN/implemented/cli.md +46 -0
- package/doc/zh-CN/implemented/codegen.md +33 -0
- package/doc/zh-CN/implemented/collections.md +26 -0
- package/doc/zh-CN/implemented/driver.md +19 -0
- package/doc/zh-CN/implemented/extensions.md +19 -0
- package/doc/zh-CN/implemented/fetch.md +31 -0
- package/doc/zh-CN/implemented/lexer.md +23 -0
- package/doc/zh-CN/implemented/modules.md +28 -0
- package/doc/zh-CN/implemented/node/assert.md +17 -0
- package/doc/zh-CN/implemented/node/buffer.md +25 -0
- package/doc/zh-CN/implemented/node/child-process.md +27 -0
- package/doc/zh-CN/implemented/node/crypto.md +9 -0
- package/doc/zh-CN/implemented/node/dgram.md +15 -0
- package/doc/zh-CN/implemented/node/events.md +36 -0
- package/doc/zh-CN/implemented/node/fs-promises.md +30 -0
- package/doc/zh-CN/implemented/node/fs.md +105 -0
- package/doc/zh-CN/implemented/node/http.md +17 -0
- package/doc/zh-CN/implemented/node/net.md +17 -0
- package/doc/zh-CN/implemented/node/os.md +21 -0
- package/doc/zh-CN/implemented/node/path.md +26 -0
- package/doc/zh-CN/implemented/node/process.md +23 -0
- package/doc/zh-CN/implemented/node/querystring.md +20 -0
- package/doc/zh-CN/implemented/node/stream-promises.md +8 -0
- package/doc/zh-CN/implemented/node/stream.md +15 -0
- package/doc/zh-CN/implemented/node/test.md +10 -0
- package/doc/zh-CN/implemented/node/url.md +8 -0
- package/doc/zh-CN/implemented/node/util.md +25 -0
- package/doc/zh-CN/implemented/node/worker-threads.md +9 -0
- package/doc/zh-CN/implemented/node/zlib.md +8 -0
- package/doc/zh-CN/implemented/node.md +45 -0
- package/doc/zh-CN/implemented/operators.md +38 -0
- package/doc/zh-CN/implemented/parser.md +58 -0
- package/doc/zh-CN/implemented/pipeline.md +25 -0
- package/doc/zh-CN/implemented/runtime-core.md +31 -0
- package/doc/zh-CN/implemented/stdlib.md +76 -0
- package/doc/zh-CN/implemented/strings.md +27 -0
- package/doc/zh-CN/implemented/tests.md +10 -0
- package/doc/zh-CN/implemented/typed-arrays.md +26 -0
- package/doc/zh-CN/implemented/value-model.md +18 -0
- package/doc/zh-CN/implemented.md +50 -350
- package/doc/zh-CN/node-implemented.md +4 -531
- package/doc/zh-CN/node-unimplemented.md +4 -139
- package/doc/zh-CN/plan-require-node-modules.md +4 -4
- package/doc/zh-CN/requirements.md +20 -6
- package/doc/zh-CN/unimplemented/classes.md +22 -0
- package/doc/zh-CN/unimplemented/deviations.md +24 -0
- package/doc/zh-CN/unimplemented/expressions.md +24 -0
- package/doc/zh-CN/unimplemented/functions.md +21 -0
- package/doc/zh-CN/unimplemented/modules.md +19 -0
- package/doc/zh-CN/unimplemented/node/async.md +20 -0
- package/doc/zh-CN/unimplemented/node/bun.md +8 -0
- package/doc/zh-CN/unimplemented/node/fs-promises.md +12 -0
- package/doc/zh-CN/unimplemented/node/fs.md +24 -0
- package/doc/zh-CN/unimplemented/node/globals.md +14 -0
- package/doc/zh-CN/unimplemented/node/modules.md +15 -0
- package/doc/zh-CN/unimplemented/node.md +18 -0
- package/doc/zh-CN/unimplemented/statements.md +15 -0
- package/doc/zh-CN/unimplemented/stdlib.md +54 -0
- package/doc/zh-CN/unimplemented/toolchain.md +14 -0
- package/doc/zh-CN/unimplemented/types.md +11 -0
- package/doc/zh-CN/unimplemented.md +14 -237
- package/llms.txt +32 -4
- package/package.json +1 -1
- package/runtime/ext_gui/inline_svg.cpp +219 -0
- package/runtime/ext_gui/inline_svg.h +41 -0
- package/runtime/ext_gui/layout.cpp +18 -0
- package/runtime/ext_gui/layout.h +7 -0
- package/runtime/ext_gui/layout_flow.cpp +4 -3
- package/runtime/ext_gui/paint.cpp +14 -0
- package/runtime/ext_gui/paint.h +5 -1
- package/runtime/ext_gui/renderer_image.cpp +53 -25
- package/runtime/ext_gui/renderer_shaders.h +2 -2
- package/runtime/ext_gui/stb_image.h +1 -17
- package/runtime/ext_gui/style_ua.cpp +3 -0
- package/runtime/ext_gui/svg.cpp +122 -39
- package/runtime/ext_gui/svg.h +14 -3
- package/runtime/ext_gui/window.cpp +28 -0
- package/runtime/ext_node/child_process/child_process.c +173 -73
- package/runtime/ext_node/fs/async_api.c +314 -0
- package/runtime/ext_node/fs/async_complete.c +99 -0
- package/runtime/ext_node/fs/async_fh.c +206 -0
- package/runtime/ext_node/fs/async_job.c +81 -0
- package/runtime/ext_node/fs/async_job.h +132 -0
- package/runtime/ext_node/fs/async_worker.c +534 -0
- package/runtime/ext_node/fs/async_worker_dir.c +439 -0
- package/runtime/ext_node/fs/async_worker_dir.h +33 -0
- package/runtime/ext_node/fs/async_worker_fd.c +74 -0
- package/runtime/ext_node/fs/dir.c +60 -15
- package/runtime/ext_node/fs/fs_common.h +9 -0
- package/runtime/ext_node/fs/fs_ops.c +18 -29
- package/runtime/ext_node/fs/parts/builtins.inc +34 -0
- package/runtime/ext_node/fs/parts/platform.inc +66 -0
- package/runtime/ext_node/fs/promises.c +44 -234
- package/runtime/rt.h +15 -0
- package/runtime/rt_internal.h +108 -0
- package/runtime/xt_alloc.c +43 -7
- package/runtime/xt_array_buffer.c +284 -0
- package/runtime/xt_async.c +46 -21
- package/runtime/xt_async_io.c +333 -0
- package/runtime/xt_async_io.h +47 -0
- package/runtime/xt_bigint/helpers.inc +3 -3
- package/runtime/xt_builtins.c +21 -17
- package/runtime/xt_constructors.c +12 -2
- package/runtime/xt_containers/access.inc +148 -3
- package/runtime/xt_containers/objects.inc +26 -2
- package/runtime/xt_containers/shapes.inc +71 -0
- package/runtime/xt_containers.c +1 -0
- package/runtime/xt_coroutine.c +17 -0
- package/runtime/xt_fetch/async.inc +295 -0
- package/runtime/xt_fetch/request.inc +6 -183
- package/runtime/xt_fetch/socket.inc +5 -4
- package/runtime/xt_fetch.c +6 -4
- package/runtime/xt_generator.c +299 -10
- package/runtime/xt_io/inspect.inc +112 -0
- package/runtime/xt_loop.c +79 -7
- package/runtime/xt_performance.c +37 -0
- package/runtime/xt_promise.c +63 -1
- package/runtime/xt_stdlib/arrays.inc +1 -1
- package/runtime/xt_stdlib/dispatch.inc +46 -11
- package/runtime/xt_stdlib/strings.inc +1 -1
- package/runtime/xt_stdlib2/array-statics.inc +25 -0
- package/runtime/xt_stdlib2/arrays.inc +5 -3
- package/runtime/xt_stdlib2/container.inc +5 -0
- package/runtime/xt_stdlib2/date.inc +111 -3
- package/runtime/xt_stdlib2/error.inc +24 -0
- package/runtime/xt_stdlib2/json.inc +310 -19
- package/runtime/xt_stdlib2/number-string-statics.inc +1 -1
- package/runtime/xt_stdlib2/objects.inc +122 -0
- package/runtime/xt_stdlib2/set.inc +1 -1
- package/runtime/xt_structured_clone.c +159 -0
- package/runtime/xt_symbol.c +2 -2
- package/runtime/xt_text_codec.c +69 -0
- package/runtime/xt_typed_array/construction.inc +35 -5
- package/runtime/xt_typed_array/elements.inc +159 -0
- package/runtime/xt_typed_array/methods.inc +21 -5
- package/runtime/xt_typed_array.c +7 -10
- package/runtime/xt_url.c +375 -0
- package/runtime/xt_values/arithmetic.inc +2 -2
- package/runtime/xt_values/conversions.inc +1 -1
- package/runtime/xt_weak.c +281 -0
- package/scripts/build-gui.ts +133 -60
- package/scripts/check-version.ts +3 -3
- package/src/binder/declarations.ts +14 -3
- package/src/cli/hints.ts +8 -1
- package/src/cli/main.ts +119 -18
- package/src/cli/watch.ts +101 -0
- package/src/codegen/generator/calls/access.ts +10 -2
- package/src/codegen/generator/calls/closures.ts +12 -4
- package/src/codegen/generator/context.ts +23 -3
- package/src/codegen/generator/expressions/operators.ts +27 -13
- package/src/codegen/generator/expressions/primary.ts +4 -0
- package/src/codegen/generator/module.ts +0 -7
- package/src/codegen/generator/numeric.ts +85 -11
- package/src/codegen/generator/state.ts +23 -0
- package/src/codegen/generator/statements/control-flow.ts +1 -4
- package/src/codegen/generator/statements/loops.ts +50 -16
- package/src/codegen/generator/tables.ts +26 -1
- package/src/diagnostics/diagnostic.ts +23 -3
- package/src/driver/app-artifacts.ts +77 -0
- package/src/driver/build-key.ts +55 -0
- package/src/driver/bundler/graph.ts +63 -13
- package/src/driver/bundler/merge.ts +4 -1
- package/src/driver/compiler.ts +94 -328
- package/src/driver/config.ts +11 -0
- package/src/driver/frontend.ts +120 -0
- package/src/driver/index.ts +0 -1
- package/src/driver/options.ts +70 -0
- package/src/driver/runtime-objects.ts +134 -0
- package/src/driver/toolchain-provider.ts +4 -0
- package/src/driver/toolchain.ts +154 -10
- package/src/driver/version.ts +12 -0
- package/src/driver/win-icon.ts +36 -36
- package/src/extensions/node/fs/index.ts +12 -3
- package/src/extensions/node/fs-promises/index.ts +15 -6
- package/src/parser/declarations/classes.ts +4 -0
- package/src/parser/declarations/functions.ts +12 -1
- package/src/parser/modules.ts +8 -4
- package/src/parser/parser.ts +28 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/* -- asynchronous request/response exchange ------------------------------- */
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* `fetch` is a state machine over the async I/O pool. The main thread validates
|
|
5
|
+
* the URL, turns `init.headers` into a `Headers` object and serialises the
|
|
6
|
+
* request; a worker performs the blocking `getaddrinfo`/connect/send/recv
|
|
7
|
+
* exchange; the main thread parses the raw response, follows redirects and
|
|
8
|
+
* builds the `Response`. Nothing observed from JavaScript blocks the reactor, so
|
|
9
|
+
* timers and sockets keep running while a request is in flight.
|
|
10
|
+
*
|
|
11
|
+
* The worker only sees plain C memory. The values that must survive across the
|
|
12
|
+
* suspension (`promise`, `headers`) are held in the job's `roots` slots and
|
|
13
|
+
* scanned by the collector.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
typedef struct xt_fetch_state xt_fetch_state;
|
|
17
|
+
|
|
18
|
+
typedef struct {
|
|
19
|
+
xt_async_job base;
|
|
20
|
+
xt_fetch_state *state;
|
|
21
|
+
char *request;
|
|
22
|
+
size_t request_length;
|
|
23
|
+
xt_fetch_buffer raw;
|
|
24
|
+
int failed;
|
|
25
|
+
} xt_fetch_hop;
|
|
26
|
+
|
|
27
|
+
struct xt_fetch_state {
|
|
28
|
+
xt_value promise;
|
|
29
|
+
xt_value headers_source;
|
|
30
|
+
char *url;
|
|
31
|
+
char method[16];
|
|
32
|
+
char redirect[16];
|
|
33
|
+
xt_fetch_buffer body;
|
|
34
|
+
int redirects;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
static void xt_fetch_start(xt_fetch_state *state);
|
|
38
|
+
|
|
39
|
+
static void xt_fetch_state_free(xt_fetch_state *state) {
|
|
40
|
+
if (!state) return;
|
|
41
|
+
free(state->url);
|
|
42
|
+
xt_fetch_buffer_free(&state->body);
|
|
43
|
+
free(state);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static void xt_fetch_state_reject(xt_fetch_state *state, const char *message) {
|
|
47
|
+
xt_value argument = xt_string_from_cstr(message);
|
|
48
|
+
xt_value error = xt_type_error_ctor(1, &argument);
|
|
49
|
+
xt_value promise = state->promise;
|
|
50
|
+
xt_fetch_state_free(state);
|
|
51
|
+
xt_promise_reject_value(promise, error);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static void xt_fetch_hop_release(xt_async_job *job) {
|
|
55
|
+
xt_fetch_hop *hop = (xt_fetch_hop *)job;
|
|
56
|
+
free(hop->request);
|
|
57
|
+
xt_fetch_buffer_free(&hop->raw);
|
|
58
|
+
free(hop);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Worker thread: connect, write the request, read until the response is
|
|
62
|
+
* complete (or the peer closes). Only plain C memory is touched here. */
|
|
63
|
+
static void xt_fetch_hop_run(xt_async_job *job) {
|
|
64
|
+
xt_fetch_hop *hop = (xt_fetch_hop *)job;
|
|
65
|
+
xt_fetch_url parsed;
|
|
66
|
+
if (xt_fetch_parse_url(hop->state->url, &parsed) != 0) {
|
|
67
|
+
hop->failed = 1;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
int fd = xt_fetch_connect(&parsed);
|
|
71
|
+
if (fd < 0) {
|
|
72
|
+
hop->failed = 1;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (xt_fetch_send_all(fd, hop->request, hop->request_length) != 0) {
|
|
76
|
+
xt_fetch_close_socket(fd);
|
|
77
|
+
hop->failed = 1;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
char chunk[16384];
|
|
82
|
+
for (;;) {
|
|
83
|
+
int headEnd = xt_fetch_head_end(&hop->raw);
|
|
84
|
+
if (headEnd > 0) {
|
|
85
|
+
int status = 0;
|
|
86
|
+
char statusText[256];
|
|
87
|
+
size_t headerStart = 0;
|
|
88
|
+
if (xt_fetch_parse_status_line(hop->raw.data, hop->raw.length, &status, statusText, sizeof(statusText),
|
|
89
|
+
&headerStart) == 0) {
|
|
90
|
+
int stop = 0;
|
|
91
|
+
if (status == 204 || status == 304 || (status >= 100 && status < 200) ||
|
|
92
|
+
strcmp(hop->state->method, "HEAD") == 0) {
|
|
93
|
+
stop = 1;
|
|
94
|
+
} else {
|
|
95
|
+
size_t contentLength = 0;
|
|
96
|
+
int hasContentLength = 0;
|
|
97
|
+
int chunked = 0;
|
|
98
|
+
xt_fetch_scan_headers(hop->raw.data, headerStart, (size_t)headEnd - 2, &contentLength, &hasContentLength,
|
|
99
|
+
&chunked);
|
|
100
|
+
if (chunked) {
|
|
101
|
+
size_t decoded = 0;
|
|
102
|
+
if (xt_fetch_chunked_complete(hop->raw.data, hop->raw.length, (size_t)headEnd, &decoded) == 1) stop = 1;
|
|
103
|
+
} else if (hasContentLength && hop->raw.length - (size_t)headEnd >= contentLength) {
|
|
104
|
+
stop = 1;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (stop) break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
int count = xt_fetch_recv(fd, chunk, sizeof(chunk));
|
|
111
|
+
if (count > 0) {
|
|
112
|
+
xt_fetch_buffer_append(&hop->raw, chunk, (size_t)count);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
xt_fetch_close_socket(fd);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
#define XT_FETCH_HOP(c) ((xt_fetch_hop *)(c))
|
|
121
|
+
|
|
122
|
+
/* Main thread: parse the raw response and either follow a redirect (starting a
|
|
123
|
+
* fresh hop) or build the `Response` and settle the promise. */
|
|
124
|
+
static void xt_fetch_hop_complete(xt_async_job *job) {
|
|
125
|
+
xt_fetch_hop *hop = XT_FETCH_HOP(job);
|
|
126
|
+
xt_fetch_state *state = hop->state;
|
|
127
|
+
if (hop->failed) {
|
|
128
|
+
xt_fetch_state_reject(state, "fetch failed");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
xt_fetch_buffer *raw = &hop->raw;
|
|
133
|
+
int headEnd = xt_fetch_head_end(raw);
|
|
134
|
+
int status = 0;
|
|
135
|
+
char statusText[256];
|
|
136
|
+
size_t headerStart = 0;
|
|
137
|
+
if (headEnd <= 0 ||
|
|
138
|
+
xt_fetch_parse_status_line(raw->data, raw->length, &status, statusText, sizeof(statusText), &headerStart) != 0) {
|
|
139
|
+
xt_fetch_state_reject(state, "fetch failed: invalid response");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
xt_value responseHeaders = xt_headers_new();
|
|
144
|
+
xt_headers_parse_block(responseHeaders, raw->data + headerStart, (size_t)headEnd - 2 - headerStart);
|
|
145
|
+
|
|
146
|
+
int isRedirect = status == 301 || status == 302 || status == 303 || status == 307 || status == 308;
|
|
147
|
+
if (isRedirect && strcmp(state->redirect, "error") == 0) {
|
|
148
|
+
xt_fetch_state_reject(state, "fetch failed: redirect not allowed");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (isRedirect && strcmp(state->redirect, "manual") != 0 && state->redirects < 20) {
|
|
152
|
+
xt_fetch_url parsed;
|
|
153
|
+
if (xt_fetch_parse_url(state->url, &parsed) == 0) {
|
|
154
|
+
const char *location = xt_headers_lookup(responseHeaders, "location");
|
|
155
|
+
char resolved[4096];
|
|
156
|
+
if (location && xt_fetch_resolve_location(&parsed, location, resolved, sizeof(resolved)) == 0) {
|
|
157
|
+
if (status == 303 || ((status == 301 || status == 302) && strcmp(state->method, "POST") == 0)) {
|
|
158
|
+
snprintf(state->method, sizeof(state->method), "GET");
|
|
159
|
+
state->body.length = 0;
|
|
160
|
+
}
|
|
161
|
+
free(state->url);
|
|
162
|
+
size_t length = strlen(resolved);
|
|
163
|
+
state->url = (char *)malloc(length + 1);
|
|
164
|
+
if (!state->url) {
|
|
165
|
+
xt_fetch_state_reject(state, "fetch failed");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
memcpy(state->url, resolved, length + 1);
|
|
169
|
+
state->redirects++;
|
|
170
|
+
xt_fetch_start(state);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
size_t contentLength = 0;
|
|
177
|
+
int hasContentLength = 0;
|
|
178
|
+
int chunked = 0;
|
|
179
|
+
xt_fetch_scan_headers(raw->data, headerStart, (size_t)headEnd - 2, &contentLength, &hasContentLength, &chunked);
|
|
180
|
+
xt_fetch_buffer responseBody;
|
|
181
|
+
xt_fetch_buffer_init(&responseBody);
|
|
182
|
+
if (status == 204 || status == 304 || (status >= 100 && status < 200) || strcmp(state->method, "HEAD") == 0) {
|
|
183
|
+
/* No body by definition. */
|
|
184
|
+
} else if (chunked) {
|
|
185
|
+
xt_fetch_decode_chunked(raw->data, raw->length, (size_t)headEnd, &responseBody);
|
|
186
|
+
} else if (hasContentLength) {
|
|
187
|
+
size_t available = raw->length - (size_t)headEnd;
|
|
188
|
+
size_t take = contentLength < available ? contentLength : available;
|
|
189
|
+
xt_fetch_buffer_append(&responseBody, raw->data + headEnd, take);
|
|
190
|
+
} else {
|
|
191
|
+
xt_fetch_buffer_append(&responseBody, raw->data + headEnd, raw->length - (size_t)headEnd);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
xt_value response = xt_response_new(responseHeaders, status, statusText, state->url,
|
|
195
|
+
responseBody.data ? responseBody.data : "", responseBody.length);
|
|
196
|
+
xt_fetch_buffer_free(&responseBody);
|
|
197
|
+
xt_value promise = state->promise;
|
|
198
|
+
xt_fetch_state_free(state);
|
|
199
|
+
xt_promise_fulfill(promise, response);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* Main thread: validate the current URL and queue one exchange. */
|
|
203
|
+
static void xt_fetch_start(xt_fetch_state *state) {
|
|
204
|
+
xt_fetch_url parsed;
|
|
205
|
+
if (xt_fetch_parse_url(state->url, &parsed) != 0) {
|
|
206
|
+
xt_fetch_state_reject(state, "Failed to parse URL");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (parsed.secure) {
|
|
210
|
+
xt_fetch_state_reject(state, "fetch failed: https is not supported");
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
xt_value requestHeaders = xt_headers_from_source(state->headers_source);
|
|
215
|
+
xt_fetch_buffer request;
|
|
216
|
+
xt_fetch_buffer_init(&request);
|
|
217
|
+
xt_fetch_build_request(state->method, &parsed, requestHeaders, state->body.length > 0 ? &state->body : NULL,
|
|
218
|
+
&request);
|
|
219
|
+
|
|
220
|
+
xt_fetch_hop *hop = (xt_fetch_hop *)calloc(1, sizeof(xt_fetch_hop));
|
|
221
|
+
if (!hop) abort();
|
|
222
|
+
hop->base.roots[0] = state->promise;
|
|
223
|
+
hop->base.roots[1] = state->headers_source;
|
|
224
|
+
hop->base.run = xt_fetch_hop_run;
|
|
225
|
+
hop->base.complete = xt_fetch_hop_complete;
|
|
226
|
+
hop->base.release = xt_fetch_hop_release;
|
|
227
|
+
hop->state = state;
|
|
228
|
+
hop->request = request.data;
|
|
229
|
+
hop->request_length = request.length;
|
|
230
|
+
xt_fetch_buffer_init(&hop->raw);
|
|
231
|
+
xt_async_submit(&hop->base);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Implements the global `fetch(input, init)`. The returned promise settles
|
|
235
|
+
* once a worker has completed the exchange and the reactor dispatches it. */
|
|
236
|
+
xt_value xt_fetch(int32_t argc, xt_value *argv) {
|
|
237
|
+
xt_value input = xt_arg_at(argc, argv, 0);
|
|
238
|
+
xt_value init = xt_arg_at(argc, argv, 1);
|
|
239
|
+
if (input == XT_UNDEFINED || input == XT_NULL) {
|
|
240
|
+
xt_value argument = xt_string_from_cstr("Failed to parse URL from undefined");
|
|
241
|
+
return xt_promise_reject(xt_type_error_ctor(1, &argument));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
xt_value urlValue = input;
|
|
245
|
+
if (XT_IS_OBJECT(input)) {
|
|
246
|
+
xt_value candidate = xt_object_get_cstr(input, "url");
|
|
247
|
+
if (XT_IS_STRING(candidate)) urlValue = candidate;
|
|
248
|
+
}
|
|
249
|
+
const char *urlText = xt_string_data(xt_to_string(urlValue));
|
|
250
|
+
if (!urlText) {
|
|
251
|
+
xt_value argument = xt_string_from_cstr("Failed to parse URL");
|
|
252
|
+
return xt_promise_reject(xt_type_error_ctor(1, &argument));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
xt_fetch_state *state = (xt_fetch_state *)calloc(1, sizeof(xt_fetch_state));
|
|
256
|
+
if (!state) abort();
|
|
257
|
+
size_t urlLength = strlen(urlText);
|
|
258
|
+
state->url = (char *)malloc(urlLength + 1);
|
|
259
|
+
if (!state->url) abort();
|
|
260
|
+
memcpy(state->url, urlText, urlLength + 1);
|
|
261
|
+
snprintf(state->method, sizeof(state->method), "GET");
|
|
262
|
+
snprintf(state->redirect, sizeof(state->redirect), "follow");
|
|
263
|
+
xt_fetch_buffer_init(&state->body);
|
|
264
|
+
state->headers_source = XT_UNDEFINED;
|
|
265
|
+
state->redirects = 0;
|
|
266
|
+
|
|
267
|
+
if (XT_IS_OBJECT(init)) {
|
|
268
|
+
xt_value methodValue = xt_object_get_cstr(init, "method");
|
|
269
|
+
if (XT_IS_STRING(methodValue)) {
|
|
270
|
+
const char *text = xt_string_data(methodValue);
|
|
271
|
+
size_t i = 0;
|
|
272
|
+
for (; text && text[i] && i + 1 < sizeof(state->method); i++) {
|
|
273
|
+
char c = text[i];
|
|
274
|
+
state->method[i] = (c >= 'a' && c <= 'z') ? (char)(c - 32) : c;
|
|
275
|
+
}
|
|
276
|
+
state->method[i] = '\0';
|
|
277
|
+
}
|
|
278
|
+
state->headers_source = xt_object_get_cstr(init, "headers");
|
|
279
|
+
xt_value bodySource = xt_object_get_cstr(init, "body");
|
|
280
|
+
if (bodySource != XT_UNDEFINED && bodySource != XT_NULL) {
|
|
281
|
+
xt_value text = xt_to_string(bodySource);
|
|
282
|
+
const char *data = xt_string_data(text);
|
|
283
|
+
if (data) xt_fetch_buffer_append(&state->body, data, (size_t)xt_string_length_value(text));
|
|
284
|
+
}
|
|
285
|
+
xt_value redirectValue = xt_object_get_cstr(init, "redirect");
|
|
286
|
+
if (XT_IS_STRING(redirectValue)) {
|
|
287
|
+
snprintf(state->redirect, sizeof(state->redirect), "%s", xt_string_data(redirectValue));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
state->promise = xt_promise_create();
|
|
292
|
+
xt_value promise = state->promise;
|
|
293
|
+
xt_fetch_start(state);
|
|
294
|
+
return promise;
|
|
295
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/* -- request / response exchange ------------------------------------------ */
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Request serialisation, response framing and header parsing for `fetch`. The
|
|
5
|
+
* blocking exchange itself runs on an async I/O worker (see `async.inc`); these
|
|
6
|
+
* helpers are shared by the main thread (building the request, parsing the
|
|
7
|
+
* completed response) and the worker (deciding when the response is complete).
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
/** Index just past the blank line that terminates the response headers. */
|
|
@@ -204,183 +205,5 @@ static void xt_fetch_build_request(const char *method, const xt_fetch_url *url,
|
|
|
204
205
|
if (body && body->length > 0) xt_fetch_buffer_append(out, body->data, body->length);
|
|
205
206
|
}
|
|
206
207
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
return xt_promise_reject(xt_type_error_ctor(1, &argument));
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
xt_value xt_fetch(int32_t argc, xt_value *argv) {
|
|
213
|
-
xt_value input = xt_arg_at(argc, argv, 0);
|
|
214
|
-
xt_value init = xt_arg_at(argc, argv, 1);
|
|
215
|
-
if (input == XT_UNDEFINED || input == XT_NULL) return xt_fetch_reject("Failed to parse URL from undefined");
|
|
216
|
-
|
|
217
|
-
xt_value urlValue = input;
|
|
218
|
-
if (XT_IS_OBJECT(input)) {
|
|
219
|
-
xt_value candidate = xt_object_get_cstr(input, "url");
|
|
220
|
-
if (XT_IS_STRING(candidate)) urlValue = candidate;
|
|
221
|
-
}
|
|
222
|
-
const char *urlText = xt_string_data(xt_to_string(urlValue));
|
|
223
|
-
if (!urlText) return xt_fetch_reject("Failed to parse URL");
|
|
224
|
-
|
|
225
|
-
char currentUrl[4096];
|
|
226
|
-
snprintf(currentUrl, sizeof(currentUrl), "%s", urlText);
|
|
227
|
-
|
|
228
|
-
char method[16];
|
|
229
|
-
snprintf(method, sizeof(method), "GET");
|
|
230
|
-
xt_value headersSource = XT_UNDEFINED;
|
|
231
|
-
xt_value bodySource = XT_UNDEFINED;
|
|
232
|
-
const char *redirectMode = "follow";
|
|
233
|
-
if (XT_IS_OBJECT(init)) {
|
|
234
|
-
xt_value methodValue = xt_object_get_cstr(init, "method");
|
|
235
|
-
if (XT_IS_STRING(methodValue)) {
|
|
236
|
-
const char *text = xt_string_data(methodValue);
|
|
237
|
-
size_t i = 0;
|
|
238
|
-
for (; text && text[i] && i + 1 < sizeof(method); i++) {
|
|
239
|
-
char c = text[i];
|
|
240
|
-
method[i] = (c >= 'a' && c <= 'z') ? (char)(c - 32) : c;
|
|
241
|
-
}
|
|
242
|
-
method[i] = '\0';
|
|
243
|
-
}
|
|
244
|
-
headersSource = xt_object_get_cstr(init, "headers");
|
|
245
|
-
bodySource = xt_object_get_cstr(init, "body");
|
|
246
|
-
xt_value redirectValue = xt_object_get_cstr(init, "redirect");
|
|
247
|
-
if (XT_IS_STRING(redirectValue)) redirectMode = xt_string_data(redirectValue);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
xt_fetch_buffer body;
|
|
251
|
-
xt_fetch_buffer_init(&body);
|
|
252
|
-
if (bodySource != XT_UNDEFINED && bodySource != XT_NULL) {
|
|
253
|
-
xt_value text = xt_to_string(bodySource);
|
|
254
|
-
const char *data = xt_string_data(text);
|
|
255
|
-
if (data) xt_fetch_buffer_append(&body, data, (size_t)xt_string_length_value(text));
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
for (int redirects = 0; redirects <= 20; redirects++) {
|
|
259
|
-
xt_fetch_url parsed;
|
|
260
|
-
if (xt_fetch_parse_url(currentUrl, &parsed) != 0) {
|
|
261
|
-
xt_fetch_buffer_free(&body);
|
|
262
|
-
return xt_fetch_reject("Failed to parse URL");
|
|
263
|
-
}
|
|
264
|
-
if (parsed.secure) {
|
|
265
|
-
xt_fetch_buffer_free(&body);
|
|
266
|
-
return xt_fetch_reject("fetch failed: https is not supported");
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
int fd = xt_fetch_connect(&parsed);
|
|
270
|
-
if (fd < 0) {
|
|
271
|
-
xt_fetch_buffer_free(&body);
|
|
272
|
-
return xt_fetch_reject("fetch failed");
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
xt_value requestHeaders = xt_headers_from_source(headersSource);
|
|
276
|
-
xt_fetch_buffer request;
|
|
277
|
-
xt_fetch_buffer_init(&request);
|
|
278
|
-
xt_fetch_build_request(method, &parsed, requestHeaders, body.length > 0 ? &body : NULL, &request);
|
|
279
|
-
if (xt_fetch_send_all(fd, request.data, request.length) != 0) {
|
|
280
|
-
xt_fetch_close_socket(fd);
|
|
281
|
-
xt_fetch_buffer_free(&request);
|
|
282
|
-
xt_fetch_buffer_free(&body);
|
|
283
|
-
return xt_fetch_reject("fetch failed");
|
|
284
|
-
}
|
|
285
|
-
xt_fetch_buffer_free(&request);
|
|
286
|
-
|
|
287
|
-
xt_fetch_buffer raw;
|
|
288
|
-
xt_fetch_buffer_init(&raw);
|
|
289
|
-
char chunk[16384];
|
|
290
|
-
for (;;) {
|
|
291
|
-
int headEnd = xt_fetch_head_end(&raw);
|
|
292
|
-
if (headEnd > 0) {
|
|
293
|
-
int status = 0;
|
|
294
|
-
char statusText[256];
|
|
295
|
-
size_t headerStart = 0;
|
|
296
|
-
if (xt_fetch_parse_status_line(raw.data, raw.length, &status, statusText, sizeof(statusText), &headerStart) == 0) {
|
|
297
|
-
int stop = 0;
|
|
298
|
-
if (status == 204 || status == 304 || (status >= 100 && status < 200) || strcmp(method, "HEAD") == 0) {
|
|
299
|
-
stop = 1;
|
|
300
|
-
} else {
|
|
301
|
-
size_t contentLength = 0;
|
|
302
|
-
int hasContentLength = 0;
|
|
303
|
-
int chunked = 0;
|
|
304
|
-
xt_fetch_scan_headers(raw.data, headerStart, (size_t)headEnd - 2, &contentLength, &hasContentLength, &chunked);
|
|
305
|
-
if (chunked) {
|
|
306
|
-
size_t decoded = 0;
|
|
307
|
-
if (xt_fetch_chunked_complete(raw.data, raw.length, (size_t)headEnd, &decoded) == 1) stop = 1;
|
|
308
|
-
} else if (hasContentLength && raw.length - (size_t)headEnd >= contentLength) {
|
|
309
|
-
stop = 1;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
if (stop) break;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
int count = xt_fetch_recv(fd, chunk, sizeof(chunk));
|
|
316
|
-
if (count > 0) {
|
|
317
|
-
xt_fetch_buffer_append(&raw, chunk, (size_t)count);
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
break;
|
|
321
|
-
}
|
|
322
|
-
xt_fetch_close_socket(fd);
|
|
323
|
-
|
|
324
|
-
int headEnd = xt_fetch_head_end(&raw);
|
|
325
|
-
int status = 0;
|
|
326
|
-
char statusText[256];
|
|
327
|
-
size_t headerStart = 0;
|
|
328
|
-
if (headEnd <= 0 ||
|
|
329
|
-
xt_fetch_parse_status_line(raw.data, raw.length, &status, statusText, sizeof(statusText), &headerStart) != 0) {
|
|
330
|
-
xt_fetch_buffer_free(&raw);
|
|
331
|
-
xt_fetch_buffer_free(&body);
|
|
332
|
-
return xt_fetch_reject("fetch failed: invalid response");
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
xt_value responseHeaders = xt_headers_new();
|
|
336
|
-
xt_headers_parse_block(responseHeaders, raw.data + headerStart, (size_t)headEnd - 2 - headerStart);
|
|
337
|
-
|
|
338
|
-
int isRedirect = status == 301 || status == 302 || status == 303 || status == 307 || status == 308;
|
|
339
|
-
if (isRedirect && strcmp(redirectMode, "error") == 0) {
|
|
340
|
-
xt_fetch_buffer_free(&raw);
|
|
341
|
-
xt_fetch_buffer_free(&body);
|
|
342
|
-
return xt_fetch_reject("fetch failed: redirect not allowed");
|
|
343
|
-
}
|
|
344
|
-
if (isRedirect && strcmp(redirectMode, "manual") != 0 && redirects < 20) {
|
|
345
|
-
const char *location = xt_headers_lookup(responseHeaders, "location");
|
|
346
|
-
char resolved[4096];
|
|
347
|
-
if (location && xt_fetch_resolve_location(&parsed, location, resolved, sizeof(resolved)) == 0) {
|
|
348
|
-
if (status == 303 || ((status == 301 || status == 302) && strcmp(method, "POST") == 0)) {
|
|
349
|
-
snprintf(method, sizeof(method), "GET");
|
|
350
|
-
body.length = 0;
|
|
351
|
-
}
|
|
352
|
-
snprintf(currentUrl, sizeof(currentUrl), "%s", resolved);
|
|
353
|
-
xt_fetch_buffer_free(&raw);
|
|
354
|
-
continue;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
size_t contentLength = 0;
|
|
359
|
-
int hasContentLength = 0;
|
|
360
|
-
int chunked = 0;
|
|
361
|
-
xt_fetch_scan_headers(raw.data, headerStart, (size_t)headEnd - 2, &contentLength, &hasContentLength, &chunked);
|
|
362
|
-
xt_fetch_buffer responseBody;
|
|
363
|
-
xt_fetch_buffer_init(&responseBody);
|
|
364
|
-
if (status == 204 || status == 304 || (status >= 100 && status < 200) || strcmp(method, "HEAD") == 0) {
|
|
365
|
-
/* No body by definition. */
|
|
366
|
-
} else if (chunked) {
|
|
367
|
-
xt_fetch_decode_chunked(raw.data, raw.length, (size_t)headEnd, &responseBody);
|
|
368
|
-
} else if (hasContentLength) {
|
|
369
|
-
size_t available = raw.length - (size_t)headEnd;
|
|
370
|
-
size_t take = contentLength < available ? contentLength : available;
|
|
371
|
-
xt_fetch_buffer_append(&responseBody, raw.data + headEnd, take);
|
|
372
|
-
} else {
|
|
373
|
-
xt_fetch_buffer_append(&responseBody, raw.data + headEnd, raw.length - (size_t)headEnd);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
xt_value response = xt_response_new(responseHeaders, status, statusText, currentUrl,
|
|
377
|
-
responseBody.data ? responseBody.data : "", responseBody.length);
|
|
378
|
-
xt_fetch_buffer_free(&responseBody);
|
|
379
|
-
xt_fetch_buffer_free(&raw);
|
|
380
|
-
xt_fetch_buffer_free(&body);
|
|
381
|
-
return xt_promise_resolve(response);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
xt_fetch_buffer_free(&body);
|
|
385
|
-
return xt_fetch_reject("fetch failed: too many redirects");
|
|
386
|
-
}
|
|
208
|
+
/* The async exchange itself lives in `async.inc`; it reuses the parsers and
|
|
209
|
+
* request builder above. */
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/* -- TCP socket helpers --------------------------------------------------- */
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
|
-
* `fetch` performs a conventional blocking request/response exchange
|
|
5
|
-
* write the request, read until the response is
|
|
6
|
-
* The socket carries a receive timeout so a
|
|
7
|
-
*
|
|
4
|
+
* `fetch` performs a conventional blocking request/response exchange on an
|
|
5
|
+
* async I/O worker: connect, write the request, read until the response is
|
|
6
|
+
* complete (or the peer closes). The socket carries a receive timeout so a
|
|
7
|
+
* stalled server cannot pin a worker forever; the timeout surfaces as a
|
|
8
|
+
* rejected promise.
|
|
8
9
|
*/
|
|
9
10
|
#define XT_FETCH_TIMEOUT_SECONDS 30
|
|
10
11
|
|
package/runtime/xt_fetch.c
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
* xbintsc runtime — the global `fetch` API.
|
|
3
3
|
*
|
|
4
4
|
* This is a small, dependency-free HTTP/1.1 client exposed as the platform
|
|
5
|
-
* `fetch` global. The
|
|
6
|
-
*
|
|
7
|
-
* and
|
|
8
|
-
* `http://` URLs are accepted;
|
|
5
|
+
* `fetch` global. The blocking socket exchange runs on the async I/O pool
|
|
6
|
+
* (`xt_async_io.c`), so a request in flight does not stall the reactor: timers,
|
|
7
|
+
* sockets and other `await`s keep running until the response is dispatched on
|
|
8
|
+
* the main thread. TLS is not implemented, so only `http://` URLs are accepted;
|
|
9
|
+
* `https://` rejects with a `TypeError`.
|
|
9
10
|
*
|
|
10
11
|
* The implementation is grouped by concern under `xt_fetch/` and `#include`d
|
|
11
12
|
* here as a single translation unit, following the other runtime modules.
|
|
@@ -37,3 +38,4 @@ typedef socklen_t xt_fetch_socklen_t;
|
|
|
37
38
|
#include "xt_fetch/headers.inc"
|
|
38
39
|
#include "xt_fetch/response.inc"
|
|
39
40
|
#include "xt_fetch/request.inc"
|
|
41
|
+
#include "xt_fetch/async.inc"
|