diff --git a/.changeset/swc-sourcemaps.md b/.changeset/swc-sourcemaps.md new file mode 100644 index 00000000..295ce603 --- /dev/null +++ b/.changeset/swc-sourcemaps.md @@ -0,0 +1,5 @@ +--- +"@godot-js/editor": patch +--- + +**Feature:** Emit inline data-URL sourcemaps for transpiled `.ts` modules and remap runtime `Error.stack` frames back to their TypeScript source positions. diff --git a/.changeset/swc-transpiler.md b/.changeset/swc-transpiler.md new file mode 100644 index 00000000..d14712ed --- /dev/null +++ b/.changeset/swc-transpiler.md @@ -0,0 +1,5 @@ +--- +"@godot-js/editor": patch +--- + +**Feature:** Optionally embed an SWC-based TypeScript transpiler as a Rust staticlib and load `.ts` modules directly by transpiling them in-process. Opt-in via the `use_typescript_transpiler=yes` build flag (off by default; the default build is unchanged and needs no Rust toolchain). diff --git a/SCsub b/SCsub index 80ec1729..f33b52cc 100644 --- a/SCsub +++ b/SCsub @@ -465,6 +465,79 @@ module_obj = [] print(f"godot engine: {version_info['major']}.{version_info['minor']}") check("regex" in env.module_list, "Currently, the 'regex' module is required for using GodotJS. Please rebuild the engine with it enabled.") +# --- transpiler-ffi: SWC-based TypeScript transpiler (Rust staticlib) ---------- +# Compiles the crate under transpiler-ffi/ and exposes the FFI header to all +# GodotJS C++ sources. Owns the `godotjs_transpile_ts()` entry point used by +# the runtime loader to turn .ts source into CommonJS at load time. +def rust_target_triple_for(platform, arch): + return { + ("macos", "arm64"): "aarch64-apple-darwin", + ("macos", "x86_64"): "x86_64-apple-darwin", + ("linux", "x86_64"): "x86_64-unknown-linux-gnu", + ("linux", "arm64"): "aarch64-unknown-linux-gnu", + ("windows", "x86_64"): "x86_64-pc-windows-msvc", + ("windows", "arm64"): "aarch64-pc-windows-msvc", + }.get((platform, arch)) + +def build_transpiler_ffi(): + triple = rust_target_triple_for(jsb_platform, jsb_arch) + check(triple is not None, + f"transpiler-ffi: no Rust target triple mapped for {jsb_platform}/{jsb_arch}") + + cargo = shutil.which("cargo") + check(cargo is not None, + "transpiler-ffi: 'cargo' not found on PATH — install the Rust toolchain (rustup.rs)") + + manifest = "transpiler-ffi/Cargo.toml" + print_info(f"transpiler-ffi: cargo build --release --target {triple}") + rc = subprocess.run( + [cargo, "build", "--release", "--manifest-path", manifest, "--target", triple], + check=False, + ) + check(rc.returncode == 0, + f"transpiler-ffi: cargo build failed (exit {rc.returncode})") + + lib_name = "godotjs_transpiler_ffi.lib" if jsb_platform == "windows" else "libgodotjs_transpiler_ffi.a" + lib_path = f"transpiler-ffi/target/{triple}/release/{lib_name}" + check(os.path.exists(lib_path), + f"transpiler-ffi: expected staticlib at {lib_path} after cargo build") + return lib_path + +# transpiler-ffi is opt-in (scons use_typescript_transpiler=yes) and only builds +# for native desktop targets that have a Rust target triple mapped (macos/linux/ +# windows). With the flag off (the default) no Rust toolchain is needed and the +# build is unchanged. web/android/ios have no triple here: they ship +# pre-transpiled .js (export-time pre-transpile) and use their own JS engine, so +# they skip the staticlib and compile out the runtime .ts load path via the +# JSB_WITH_TYPESCRIPT_TRANSPILER define below. +want_transpiler = env["use_typescript_transpiler"] +has_transpiler = want_transpiler and rust_target_triple_for(jsb_platform, jsb_arch) is not None +if want_transpiler and not has_transpiler: + print_warning(f"transpiler-ffi: no Rust target triple mapped for {jsb_platform}/{jsb_arch}; building without the TypeScript transpiler (use export-time pre-transpiled .js)") +env_jsb.Append(CPPDEFINES=[("JSB_WITH_TYPESCRIPT_TRANSPILER", 1 if has_transpiler else 0)]) +if has_transpiler: + transpiler_ffi_lib = build_transpiler_ffi() + env_jsb.Append(CPPPATH=[f"#modules/{module_name}/transpiler-ffi/include"]) + env.Append(LIBS=[File(transpiler_ffi_lib)]) + + # Rust staticlibs may pull in platform frameworks/libs that Godot doesn't + # already link. SWC's tree is mostly pure Rust; these cover the OS-specific + # system bits its transitive deps reach for. Refine if the linker complains. + # + # The --allow-multiple-definition / /FORCE:MULTIPLE flags below cover a + # specific clash: our staticlib and Godot's prebuilt accesskit staticlib both + # bundle rust_eh_personality (and a few other libstd symbols) from rustc's + # libstd, compiled against different rustc versions. GNU ld and MSVC link.exe + # error on the duplicate; macOS ld64 silently picks one. The clash is benign + # — both copies are ABI-compatible personality routines. + if jsb_platform == "macos": + env.Append(LINKFLAGS=["-framework", "CoreFoundation", "-framework", "Security"]) + elif jsb_platform == "linux": + env.Append(LINKFLAGS=["-Wl,--allow-multiple-definition"]) + elif jsb_platform == "windows": + env.Append(LINKFLAGS=["userenv.lib", "ntdll.lib", "bcrypt.lib", "/FORCE:MULTIPLE"]) +# ------------------------------------------------------------------------------- + # Build JS files before generating if not env["skip_js_runtime"]: pnpm_command = shutil.which("pnpm") diff --git a/bridge/jsb_environment.cpp b/bridge/jsb_environment.cpp index e121efab..6e677b1c 100644 --- a/bridge/jsb_environment.cpp +++ b/bridge/jsb_environment.cpp @@ -248,6 +248,51 @@ namespace jsb const String str = impl::Helper::to_string_without_side_effect(isolate, message.GetValue()); JSB_LOG(Error, "unhandled promise rejection: %s", str); } + +#if JSB_WITH_V8 + // Called by V8 the first time `error.stack` is read. V8 12.4 in this build + // doesn't auto-apply source maps to the runtime Error.stack string (DevTools + // is fine because it uses the sourcemap separately). We build the default + // V8 stack format ourselves via each CallSite's `toString`, then pass the + // result through SourceMapCache which rewrites .ts/.js positions back to + // the original source thanks to the inline sourcemap fed in at transpile + // time. If anything goes wrong, return empty so V8 falls back to its + // built-in (raw) formatter. + v8::MaybeLocal PrepareStackTraceCallback_(v8::Local context, + v8::Local error, + v8::Local sites) + { + v8::Isolate* isolate = context->GetIsolate(); + Environment* env = Environment::wrap(isolate); + + String stack = impl::Helper::to_string_without_side_effect(isolate, error); + + const v8::Local to_string_key = impl::Helper::new_string_ascii(isolate, "toString"); + const uint32_t count = sites->Length(); + for (uint32_t i = 0; i < count; ++i) + { + v8::Local site_val; + if (!sites->Get(context, i).ToLocal(&site_val) || !site_val->IsObject()) continue; + const v8::Local site = site_val.As(); + + v8::Local to_string_val; + if (!site->Get(context, to_string_key).ToLocal(&to_string_val) || !to_string_val->IsFunction()) continue; + const v8::Local to_string_fn = to_string_val.As(); + + v8::Local frame_val; + if (!to_string_fn->Call(context, site, 0, nullptr).ToLocal(&frame_val)) continue; + + stack += "\n at " + impl::Helper::to_string(isolate, frame_val); + } + + if (env) + { + stack = env->get_source_map_cache().process_source_position(stack); + } + + return impl::Helper::new_string(isolate, stack).As(); + } +#endif } Environment::Environment(const CreateParams& p_params) @@ -273,6 +318,9 @@ namespace jsb isolate_ = v8::Isolate::New(create_params); isolate_->SetData(kIsolateEmbedderData, this); isolate_->SetPromiseRejectCallback(PromiseRejectCallback_); +#if JSB_WITH_V8 + isolate_->SetPrepareStackTraceCallback(PrepareStackTraceCallback_); +#endif #if JSB_PRINT_GC_TIME isolate_->AddGCPrologueCallback(&OnPreGCCallback); isolate_->AddGCEpilogueCallback(&OnPostGCCallback); diff --git a/bridge/jsb_module_resolver.cpp b/bridge/jsb_module_resolver.cpp index e0ecfdb4..46f9bac7 100644 --- a/bridge/jsb_module_resolver.cpp +++ b/bridge/jsb_module_resolver.cpp @@ -2,9 +2,129 @@ #include "jsb_environment.h" #include "../internal/jsb_path_util.h" +#include "core/crypto/crypto_core.h" + +#if JSB_WITH_TYPESCRIPT_TRANSPILER +extern "C" { +#include "godotjs_transpiler.h" +} +#endif namespace jsb { + namespace + { +#if JSB_WITH_TYPESCRIPT_TRANSPILER + // Transpile a TypeScript source into the same `(function(exports,require,module,__filename,__dirname){ ... \n})` + // wrapper that `read_all_bytes_with_shebang` produces for `.js` sources. + // When SWC produced a sourcemap, the `//# sourceMappingURL=` + // comment is inserted on its own line just before the closing `})`. + // Keeping the comment INSIDE the wrapper (not before it) preserves the + // body's line numbering relative to wrapped positions, so V8's stack + // frames map cleanly through the sourcemap for everything past line 0. + // The decoded sourcemap is also fed into Environment::source_map_cache_ + // so the V8 PrepareStackTrace callback can remap runtime Error.stack + // frames back to .ts positions (V8 12.4 doesn't auto-apply source maps + // to Error.stack, only DevTools). + bool transpile_typescript_to_wrapped_source(Environment* p_env, + const String& p_source_url, + const internal::ISourceReader& p_reader, + Vector& o_wrapped, + String& r_error) + { + static constexpr char header[] = "(function(exports,require,module,__filename,__dirname){"; + static constexpr char footer[] = "\n})"; + static constexpr char sourcemap_prefix[] = "\n//# sourceMappingURL="; + + const uint64_t raw_len = p_reader.get_length(); + Vector raw; + raw.resize((int) raw_len); + if (raw_len > 0 && p_reader.get_buffer(raw.ptrw(), raw_len) != raw_len) + { + r_error = "failed to read typescript source"; + return false; + } + + // SWC's `sources` entry becomes the path SourceMapCache exposes when + // remapping stacks. Use the same string V8 will report in frames so + // a single key lookup hits in the cache (otherwise the bridge would + // pass `res://…` while V8 reports the absolute file path). + const CharString filename_utf8 = p_source_url.utf8(); + GodotJSTranspileResult* result = godotjs_transpile_ts( + raw.ptr(), (size_t) raw_len, + (const uint8_t*) filename_utf8.get_data(), (size_t) filename_utf8.length(), + 0 + ); + + if (!result) + { + r_error = "godotjs_transpile_ts returned null"; + return false; + } + + if (result->error) + { + r_error = String::utf8((const char*) result->error, (int) result->error_len); + godotjs_free_transpile_result(result); + return false; + } + + const size_t header_size = ::std::size(header) - 1; + const size_t code_len = result->code_len; + const size_t sm_len = result->sourcemap ? result->sourcemap_len : 0; + const size_t sm_prefix_size = sm_len > 0 ? ::std::size(sourcemap_prefix) - 1 : 0; + + o_wrapped.resize((int) (header_size + code_len + sm_prefix_size + sm_len + ::std::size(footer))); + size_t offset = 0; + memcpy(o_wrapped.ptrw() + offset, header, header_size); + offset += header_size; + if (code_len > 0) + { + memcpy(o_wrapped.ptrw() + offset, result->code, code_len); + offset += code_len; + } + if (sm_len > 0) + { + memcpy(o_wrapped.ptrw() + offset, sourcemap_prefix, sm_prefix_size); + offset += sm_prefix_size; + memcpy(o_wrapped.ptrw() + offset, result->sourcemap, sm_len); + offset += sm_len; + } + memcpy(o_wrapped.ptrw() + offset, footer, ::std::size(footer)); // includes trailing zero + + // Pull the base64 payload out of `data:application/json;…;base64,` + // and feed the decoded JSON into the source map cache so runtime stack + // remap can find it by the same key V8 will report. + if (p_env && sm_len > 0) + { + const uint8_t* url = result->sourcemap; + size_t url_len = result->sourcemap_len; + const uint8_t* comma = (const uint8_t*) memchr(url, ',', url_len); + if (comma) + { + const size_t b64_off = (comma - url) + 1; + if (url_len > b64_off) + { + const uint8_t* b64_ptr = url + b64_off; + const size_t b64_len = url_len - b64_off; + Vector json_buf; + json_buf.resize((int) (b64_len * 3 / 4 + 4)); + size_t out_len = 0; + if (CryptoCore::b64_decode(json_buf.ptrw(), (size_t) json_buf.size(), &out_len, b64_ptr, b64_len) == OK && out_len > 0) + { + const String json = String::utf8((const char*) json_buf.ptr(), (int) out_len); + p_env->get_source_map_cache().feed(p_source_url, json); + } + } + } + } + + godotjs_free_transpile_result(result); + return true; + } +#endif + } + namespace { // the cost of copy return is acceptable since Vector copy constructor is by-reference under the hood @@ -116,6 +236,19 @@ namespace jsb return true; } +#if JSB_WITH_TYPESCRIPT_TRANSPILER + // try .ts (source-of-truth — probed after .js so an existing emitted + // artefact still wins; only with the embedded transpiler, which loads + // it in-process). Without the transpiler this probe is compiled out so + // resolution is identical to a build that never knew about .ts. + const String ts_path = internal::PathUtil::extends_with(p_module_id, "." JSB_TYPESCRIPT_EXT); + if (FileAccess::exists(ts_path)) + { + o_path = ts_path; + return true; + } +#endif + // try .cjs const String cjs_path = internal::PathUtil::extends_with(p_module_id, "." JSB_COMMONJS_EXT); if (FileAccess::exists(cjs_path)) @@ -556,8 +689,9 @@ namespace jsb return load_as_json(p_env, p_module, p_asset_path, source, len); } + const bool is_typescript = p_asset_path.ends_with("." JSB_TYPESCRIPT_EXT); #if JSB_DEBUG - if (!internal::PathUtil::is_recognized_javascript_extension(p_asset_path)) + if (!is_typescript && !internal::PathUtil::is_recognized_javascript_extension(p_asset_path)) { JSB_LOG(Warning, "%s is suspiciously not JS", p_asset_path); } @@ -571,7 +705,27 @@ namespace jsb const String source_url = p_reader.get_source_url(); Vector source; - const size_t len = read_all_bytes_with_shebang(p_reader, source); + size_t len; + if (is_typescript) + { +#if JSB_WITH_TYPESCRIPT_TRANSPILER + String transpile_error; + if (!transpile_typescript_to_wrapped_source(p_env, source_url, p_reader, source, transpile_error)) + { + JSB_LOG(Error, "ts transpile failed for %s: %s", p_asset_path, transpile_error); + impl::Helper::throw_error(isolate, jsb_format("ts transpile failed for %s: %s", p_asset_path, transpile_error)); + return false; + } + len = source.size() - 1; // exclude trailing zero +#else + impl::Helper::throw_error(isolate, jsb_format("cannot load .ts at runtime on this platform (no embedded transpiler); pre-transpile to .js at export time: %s", p_asset_path)); + return false; +#endif + } + else + { + len = read_all_bytes_with_shebang(p_reader, source); + } jsb_check((size_t)(int)len == len); // source evaluator (the module protocol) diff --git a/config.py b/config.py index 31c50aaa..51015cdf 100644 --- a/config.py +++ b/config.py @@ -15,6 +15,7 @@ def get_opts(platform): return [ BoolVariable("skip_js_runtime", "Skip building GodotJS JavaScript runtime files", False), BoolVariable("use_typescript", "Build with typescript support (enabled by default)", True), + BoolVariable("use_typescript_transpiler", "Embed the SWC TypeScript transpiler to load .ts directly (requires the Rust toolchain; desktop platforms only)", False), BoolVariable("use_jsc", "Prefer to use JavaScriptCore (only for macos and ios)", False), BoolVariable("use_quickjs", "Prefer to use QuickJS rather than the default VM on the current platform", False), BoolVariable("use_quickjs_ng", "Prefer to use QuickJS-NG rather than the default VM on the current platform", False), diff --git a/impl/v8/jsb_v8_helper.h b/impl/v8/jsb_v8_helper.h index f301f8e7..f9bfc83f 100644 --- a/impl/v8/jsb_v8_helper.h +++ b/impl/v8/jsb_v8_helper.h @@ -190,7 +190,12 @@ namespace jsb::impl v8::Local filename_value = v8::String::NewFromUtf8(isolate, filename.utf8().ptr(), v8::NewStringType::kNormal, filename.length()).ToLocalChecked(); v8::Local source_map_url_value; - if (source_map_base_url.length() > 0) + // For `.ts` sources the embedded SWC transpiler already emits + // an inline `//# sourceMappingURL=data:…` URL inside the wrapped + // source; setting ScriptOrigin's source_map_url here would shadow + // it with the debugger's HTTP `.map` URL (which doesn't exist). + const bool prefer_inline_source_map = p_source_origin.ends_with(".ts"); + if (source_map_base_url.length() > 0 && !prefer_inline_source_map) { String source_map_url = source_map_base_url + (source_map_base_url.ends_with("/") ? filename : '/' + filename) + ".map"; source_map_url_value = v8::String::NewFromUtf8(isolate, source_map_url.utf8().ptr(), v8::NewStringType::kNormal, source_map_url.length()).ToLocalChecked(); diff --git a/internal/jsb_source_map_cache.cpp b/internal/jsb_source_map_cache.cpp index b6bd432e..8ade29f2 100644 --- a/internal/jsb_source_map_cache.cpp +++ b/internal/jsb_source_map_cache.cpp @@ -10,7 +10,7 @@ namespace jsb::internal bool SourceMapCache::match(const String& p_line, MatchResult& r_result) { #if JSB_WITH_QUICKJS - if (source_map_match1_.is_null()) source_map_match1_ = RegEx::create_from_string(R"(\s+at\s(.+)\s\((.+\.js):(\d+)\))"); // e.g. at xxx (file.js:1) + if (source_map_match1_.is_null()) source_map_match1_ = RegEx::create_from_string(R"(\s+at\s(.+)\s\((.+\.(?:js|ts|tsx|mjs|cjs)):(\d+)\))"); // e.g. at xxx (file.js:1) or (file.ts:1) const Ref& regex = source_map_match1_; const Ref match = regex->search(p_line); if (!match.is_valid()) return false; @@ -22,8 +22,8 @@ namespace jsb::internal r_result.col = 0; return true; #else - if (source_map_match1_.is_null()) source_map_match1_ = RegEx::create_from_string(R"(\s+at\s(.+)\s\((.+\.js):(\d+):(\d+)\))"); // e.g. at xxx (file.js:1:2) - if (source_map_match2_.is_null()) source_map_match2_ = RegEx::create_from_string(R"(\s+at\s(.+\.js):(\d+):(\d+))"); // e.g. at file.js:1:2 + if (source_map_match1_.is_null()) source_map_match1_ = RegEx::create_from_string(R"(\s+at\s(.+)\s\((.+\.(?:js|ts|tsx|mjs|cjs)):(\d+):(\d+)\))"); // e.g. at xxx (file.js:1:2) or (file.ts:1:2) + if (source_map_match2_.is_null()) source_map_match2_ = RegEx::create_from_string(R"(\s+at\s(.+\.(?:js|ts|tsx|mjs|cjs)):(\d+):(\d+))"); // e.g. at file.js:1:2 or file.ts:1:2 const Ref& regex = p_line.contains("(") && p_line.contains(")") ? source_map_match1_ : source_map_match2_; @@ -56,7 +56,15 @@ namespace jsb::internal if (!map->find(result.line, result.col, position)) continue; const String& source = map->get_source(position.index); const String& source_root = map->get_source_root(); - const String original_path = PathUtil::to_platform_specific_path(PathUtil::combine("res://", source_root, source)); + // SWC's inline sourcemap stores `sources` already as the absolute + // V8-visible path, so combining with "res://" + source_root would + // produce `res:///Users/...`. Only fall back to the legacy + // "res:// + source_root + source" layout when the source is a bare + // relative path (the shape tsc-emitted .map files used). + const bool source_is_addressable = source.begins_with("res://") || PathUtil::is_absolute_path(source); + const String original_path = source_is_addressable + ? PathUtil::to_platform_specific_path(source) + : PathUtil::to_platform_specific_path(PathUtil::combine("res://", source_root, source)); if (result.function.is_empty()) st_line = jsb_format(" at %s:%d:%d", original_path, position.line, position.column); else st_line = jsb_format(" at %s (%s:%d:%d)", result.function, original_path, position.line, position.column); @@ -92,6 +100,13 @@ namespace jsb::internal } } + void SourceMapCache::feed(const String& p_filename, const String& p_json) + { + if (p_json.is_empty()) return; + cached_source_maps_[p_filename] = {}; + cached_source_maps_[p_filename].parse(p_json); + } + void SourceMapCache::clear() { source_map_match1_.unref(); @@ -119,7 +134,8 @@ namespace jsb::internal return ↦ } #else - String SourceMapCache::process_source_position(const String& p_stacktrace) { return p_stacktrace; } + String SourceMapCache::process_source_position(const String& p_stacktrace, SourcePosition* r_position) { return p_stacktrace; } + void SourceMapCache::feed(const String& p_filename, const String& p_json) {} void SourceMapCache::invalidate(const String& p_filename) {} #endif } diff --git a/internal/jsb_source_map_cache.h b/internal/jsb_source_map_cache.h index d1e2ede6..811d46b2 100644 --- a/internal/jsb_source_map_cache.h +++ b/internal/jsb_source_map_cache.h @@ -12,6 +12,11 @@ namespace jsb::internal // try to translate the source positions in stacktrace String process_source_position(const String& p_stacktrace, SourcePosition* r_position = nullptr); + // populate the cache directly with the source map JSON for `p_filename`, + // used by the .ts loader to wire SWC's inline sourcemap into V8 stack remap. + // overwrites any previously cached entry for `p_filename`. + void feed(const String& p_filename, const String& p_json); + void invalidate(const String& p_filename); void clear(); diff --git a/transpiler-ffi/.gitignore b/transpiler-ffi/.gitignore new file mode 100644 index 00000000..a7950983 --- /dev/null +++ b/transpiler-ffi/.gitignore @@ -0,0 +1,4 @@ +target/ +spike/host +spike/host.dSYM/ +Cargo.lock.bak diff --git a/transpiler-ffi/Cargo.lock b/transpiler-ffi/Cargo.lock new file mode 100644 index 00000000..62d68b6e --- /dev/null +++ b/transpiler-ffi/Cargo.lock @@ -0,0 +1,1930 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "ar_archive_writer" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" +dependencies = [ + "object", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ascii" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" + +[[package]] +name = "ast_node" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a184645bcc6f52d69d8e7639720699c6a99efb711f886e251ed1d16db8dd90e" +dependencies = [ + "quote", + "swc_macros_common", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "better_scoped_tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd228125315b132eed175bf47619ac79b945b26e56b848ba203ae4ea8603609" +dependencies = [ + "scoped-tls", +] + +[[package]] +name = "bitflags" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "bytes-str" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "577d2bf5650f8554d5a372af5ac93535110a0fc75b3e702bb853369febf227c2" +dependencies = [ + "bytes", + "serde", +] + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0061da739915fae12ea00e16397555ed4371a6bb285431aab930f61b0aa4ba" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "cargo_metadata" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cc" +version = "1.2.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "compact_str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "ryu", + "static_assertions", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "serde", + "uuid", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "from_variant" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308530a56b099da144ebc5d8e179f343ad928fa2b3558d1eb3db9af18d6eff43" +dependencies = [ + "swc_macros_common", + "syn", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "godotjs_transpiler_ffi" +version = "0.1.0" +dependencies = [ + "swc_core", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hstr" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f11d91d7befd2ffd9d216e9e5ea1fae6174b20a2a1b67a688138003d2f4122" +dependencies = [ + "hashbrown 0.14.5", + "new_debug_unreachable", + "once_cell", + "rustc-hash", + "triomphe", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "if_chain" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd62e6b5e86ea8eeeb8db1de02880a6abc01a397b2ebb64b5d74ac255318f5cb" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "is-macro" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57a3e447e24c22647738e4607f1df1e0ec6f72e16182c4cd199f647cdfb0e4" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "memchr" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + +[[package]] +name = "par-core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96cbd21255b7fb29a5d51ef38a779b517a91abd59e2756c039583f43ef4c90f" +dependencies = [ + "once_cell", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "path-clean" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.3", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "ryu-js" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd29631678d6fb0903b69223673e122c32e9ae559d0960a38d574695ebc0ea15" + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "static_assertions", + "version_check", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stacker" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_enum" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae36a4951ca7bd1cfd991c241584a9824a70f6aff1e7d4f693fb3f2465e4030e" +dependencies = [ + "quote", + "swc_macros_common", + "syn", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "swc_allocator" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d7eefd2c8b228a8c73056482b2ae4b3a1071fbe07638e3b55ceca8570cc48bb" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.14.5", + "rustc-hash", +] + +[[package]] +name = "swc_atoms" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3500dcf04c84606b38464561edc5e46f5132201cb3e23cf9613ed4033d6b1bb2" +dependencies = [ + "hstr", + "once_cell", + "serde", +] + +[[package]] +name = "swc_common" +version = "14.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2bb772b3a26b8b71d4e8c112ced5b5867be2266364b58517407a270328a2696" +dependencies = [ + "anyhow", + "ast_node", + "better_scoped_tls", + "bytes-str", + "either", + "from_variant", + "new_debug_unreachable", + "num-bigint", + "once_cell", + "rustc-hash", + "serde", + "siphasher 0.3.11", + "swc_atoms", + "swc_eq_ignore_macros", + "swc_sourcemap", + "swc_visit", + "tracing", + "unicode-width", + "url", +] + +[[package]] +name = "swc_config" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e90b52ee734ded867104612218101722ad87ff4cf74fe30383bd244a533f97" +dependencies = [ + "anyhow", + "bytes-str", + "dashmap", + "globset", + "indexmap", + "once_cell", + "regex", + "rustc-hash", + "serde", + "serde_json", + "swc_config_macro", +] + +[[package]] +name = "swc_config_macro" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b416e8ce6de17dc5ea496e10c7012b35bbc0e3fef38d2e065eed936490db0b3" +dependencies = [ + "proc-macro2", + "quote", + "swc_macros_common", + "syn", +] + +[[package]] +name = "swc_core" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c510e9365a2e6f86a392d62074b4d78f6dd5c3ed54ccf57b0512a96546092d07" +dependencies = [ + "swc_allocator", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_transforms_module", + "swc_ecma_transforms_proposal", + "swc_ecma_transforms_typescript", + "swc_ecma_visit", + "vergen", +] + +[[package]] +name = "swc_ecma_ast" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c25af97d53cf8aab66a6c68f3418663313fc969ad267fc2a4d19402c329be1" +dependencies = [ + "bitflags", + "is-macro", + "num-bigint", + "once_cell", + "phf", + "rustc-hash", + "string_enum", + "swc_atoms", + "swc_common", + "swc_visit", + "unicode-id-start", +] + +[[package]] +name = "swc_ecma_codegen" +version = "17.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf55c2d7555c93f4945e29f93b7529562be97ba16e60dd94c25724d746174ac" +dependencies = [ + "ascii", + "compact_str", + "memchr", + "num-bigint", + "once_cell", + "regex", + "rustc-hash", + "ryu-js", + "serde", + "swc_allocator", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_codegen_macros", + "swc_sourcemap", + "tracing", +] + +[[package]] +name = "swc_ecma_codegen_macros" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e276dc62c0a2625a560397827989c82a93fd545fcf6f7faec0935a82cc4ddbb8" +dependencies = [ + "proc-macro2", + "swc_macros_common", + "syn", +] + +[[package]] +name = "swc_ecma_lexer" +version = "23.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "017d06ea85008234aa9fb34d805c7dc563f2ea6e03869ed5ac5a2dc27d561e4d" +dependencies = [ + "arrayvec", + "bitflags", + "either", + "num-bigint", + "phf", + "rustc-hash", + "seq-macro", + "serde", + "smallvec", + "smartstring", + "stacker", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "tracing", +] + +[[package]] +name = "swc_ecma_loader" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c675d14700c92f12585049b22b02356f1e142f4b0c32a4d0eb4b7a968a4c0c1e" +dependencies = [ + "anyhow", + "pathdiff", + "rustc-hash", + "serde", + "swc_atoms", + "swc_common", + "tracing", +] + +[[package]] +name = "swc_ecma_parser" +version = "23.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9166873bb660bed50b5f422233537d3e946336398570a4a13e57d8c63d6a01c5" +dependencies = [ + "either", + "num-bigint", + "serde", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_lexer", + "tracing", +] + +[[package]] +name = "swc_ecma_transforms_base" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cc6454e1cf587b1d50509116350b503e7d647dbcc41bb5be9bf9a40fd792037" +dependencies = [ + "better_scoped_tls", + "indexmap", + "once_cell", + "par-core", + "phf", + "rustc-hash", + "serde", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_utils", + "swc_ecma_visit", + "tracing", +] + +[[package]] +name = "swc_ecma_transforms_classes" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c48790332195e4163f1f49713a14f91a5614048ca6638c664050fe577c3fad5a" +dependencies = [ + "swc_common", + "swc_ecma_ast", + "swc_ecma_transforms_base", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_transforms_module" +version = "27.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3dc988f1b06f5bb96eb76f25d193329cb070a2e4be4d48c795feb54879ecc60" +dependencies = [ + "Inflector", + "anyhow", + "bitflags", + "indexmap", + "is-macro", + "path-clean", + "pathdiff", + "regex", + "rustc-hash", + "serde", + "swc_atoms", + "swc_common", + "swc_config", + "swc_ecma_ast", + "swc_ecma_loader", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_utils", + "swc_ecma_visit", + "tracing", +] + +[[package]] +name = "swc_ecma_transforms_proposal" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a1d5b2190c134d9b5c9b4d8c0d4b23b4fb5c433a7ae470f1c2103b8ff99160c" +dependencies = [ + "either", + "rustc-hash", + "serde", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_transforms_base", + "swc_ecma_transforms_classes", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_transforms_react" +version = "28.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc9a3fe915e9b4e289edc78f060b8edda8633bc44234c5cf167e359befa18267" +dependencies = [ + "base64", + "bytes-str", + "indexmap", + "once_cell", + "rustc-hash", + "serde", + "sha1", + "string_enum", + "swc_atoms", + "swc_common", + "swc_config", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_transforms_typescript" +version = "28.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e62c7ec4f9667b9a85270125443fee6a7c2f357272d3d9eafc75a2f6fb0bca9" +dependencies = [ + "bytes-str", + "rustc-hash", + "serde", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_transforms_base", + "swc_ecma_transforms_react", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_utils" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83259addd99ed4022aa9fc4d39428c008d3d42533769e1a005529da18cde4568" +dependencies = [ + "indexmap", + "num_cpus", + "once_cell", + "par-core", + "rustc-hash", + "ryu-js", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_visit", + "tracing", +] + +[[package]] +name = "swc_ecma_visit" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a579aa8f9e212af521588df720ccead079c09fe5c8f61007cf724324aed3a0" +dependencies = [ + "new_debug_unreachable", + "num-bigint", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_visit", + "tracing", +] + +[[package]] +name = "swc_eq_ignore_macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c16ce73424a6316e95e09065ba6a207eba7765496fed113702278b7711d4b632" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "swc_macros_common" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1efbaa74943dc5ad2a2fb16cbd78b77d7e4d63188f3c5b4df2b4dcd2faaae" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "swc_sourcemap" +version = "9.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de08ef00f816acdd1a58ee8a81c0e1a59eefef2093aefe5611f256fa6b64c4d7" +dependencies = [ + "base64-simd", + "bitvec", + "bytes-str", + "data-encoding", + "debugid", + "if_chain", + "rustc-hash", + "serde", + "serde_json", + "unicode-id-start", + "url", +] + +[[package]] +name = "swc_visit" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62fb71484b486c185e34d2172f0eabe7f4722742aad700f426a494bb2de232a2" +dependencies = [ + "either", + "new_debug_unreachable", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "triomphe" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" +dependencies = [ + "serde", + "stable_deref_trait", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-id-start" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b79ad29b5e19de4260020f8919b443b2ef0277d242ce532ec7b7a2cc8b6007" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "vergen" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75" +dependencies = [ + "anyhow", + "cargo_metadata", + "derive_builder", + "regex", + "rustversion", + "vergen-lib", +] + +[[package]] +name = "vergen-lib" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + +[[package]] +name = "wasm-bindgen" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/transpiler-ffi/Cargo.toml b/transpiler-ffi/Cargo.toml new file mode 100644 index 00000000..18414727 --- /dev/null +++ b/transpiler-ffi/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "godotjs_transpiler_ffi" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["staticlib", "rlib"] + +[dependencies] +swc_core = { version = "37", features = [ + "common", + "common_sourcemap", + "ecma_ast", + "ecma_parser", + "ecma_parser_typescript", + "ecma_codegen", + "ecma_visit", + "ecma_transforms", + "ecma_transforms_typescript", + "ecma_transforms_module", + # Legacy/TC39 decorators live here, not in ecma_transforms_typescript. + "ecma_transforms_proposal", + # Inline _interop_require_default etc. into the file rather than emitting + # `import { _ } from "@swc/helpers/_/..."` — the engine has no @swc/helpers + # at runtime and can't follow ESM-style imports anyway (the wrapper around + # transpiled output is CommonJS). + "ecma_helpers_inline", +] } + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 diff --git a/transpiler-ffi/include/godotjs_transpiler.h b/transpiler-ffi/include/godotjs_transpiler.h new file mode 100644 index 00000000..344f1fd6 --- /dev/null +++ b/transpiler-ffi/include/godotjs_transpiler.h @@ -0,0 +1,51 @@ +// FFI surface for godotjs_transpiler_ffi (Rust staticlib). +// +// Owns the implementation in transpiler-ffi/src/lib.rs. Hand-written instead +// of cbindgen-generated — the surface is two functions and one struct, so the +// bookkeeping cost of cbindgen exceeds its value. + +#ifndef GODOTJS_TRANSPILER_H +#define GODOTJS_TRANSPILER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GodotJSTranspileResult { + uint8_t* code; + size_t code_len; + uint8_t* sourcemap; + size_t sourcemap_len; + uint8_t* error; + size_t error_len; +} GodotJSTranspileResult; + +// Transpile TypeScript source to CommonJS JavaScript. +// +// `source`/`filename` must point to `*_len` valid UTF-8 bytes (neither is +// expected to be null-terminated). `opts` is reserved (pass 0). +// +// On success, `code`/`code_len` hold the emitted JS and `error` is null. +// `sourcemap`/`sourcemap_len` hold the `data:application/json;…;base64,<…>` +// URL of an inline source map (suitable for embedding directly after +// `//# sourceMappingURL=`); both are zero when sourcemap generation is +// skipped or empty. On failure, `error`/`error_len` hold a UTF-8 message +// and `code` is null. +// +// The returned pointer is always non-null and must be freed via +// godotjs_free_transpile_result(). +GodotJSTranspileResult* godotjs_transpile_ts( + const uint8_t* source, size_t source_len, + const uint8_t* filename, size_t filename_len, + uint32_t opts); + +void godotjs_free_transpile_result(GodotJSTranspileResult* r); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // GODOTJS_TRANSPILER_H diff --git a/transpiler-ffi/spike/host.cpp b/transpiler-ffi/spike/host.cpp new file mode 100644 index 00000000..8968802c --- /dev/null +++ b/transpiler-ffi/spike/host.cpp @@ -0,0 +1,65 @@ +// M0 spike: read .ts from stdin, transpile via the godotjs_transpiler_ffi +// staticlib, write JS to stdout (error → stderr, nonzero exit). + +#include +#include +#include +#include +#include +#include +#include + +extern "C" { + +struct TranspileResult { + uint8_t* code; + size_t code_len; + uint8_t* sourcemap; + size_t sourcemap_len; + uint8_t* error; + size_t error_len; +}; + +TranspileResult* godotjs_transpile_ts( + const uint8_t* source, size_t source_len, + const uint8_t* filename, size_t filename_len, + uint32_t opts); + +void godotjs_free_transpile_result(TranspileResult* r); + +} // extern "C" + +int main(int argc, char** argv) { + std::string filename = (argc > 1) ? argv[1] : ".ts"; + + std::stringstream ss; + ss << std::cin.rdbuf(); + std::string source = ss.str(); + + TranspileResult* r = godotjs_transpile_ts( + reinterpret_cast(source.data()), source.size(), + reinterpret_cast(filename.data()), filename.size(), + 0); + + if (!r) { + std::fprintf(stderr, "godotjs_transpile_ts returned null\n"); + return 2; + } + + int rc = 0; + if (r->error) { + std::fwrite(r->error, 1, r->error_len, stderr); + std::fputc('\n', stderr); + rc = 1; + } else if (r->code) { + std::fwrite(r->code, 1, r->code_len, stdout); + if (r->sourcemap) { + std::fprintf(stderr, "[sourcemap %zu bytes] ", r->sourcemap_len); + std::fwrite(r->sourcemap, 1, r->sourcemap_len, stderr); + std::fputc('\n', stderr); + } + } + + godotjs_free_transpile_result(r); + return rc; +} diff --git a/transpiler-ffi/src/lib.rs b/transpiler-ffi/src/lib.rs new file mode 100644 index 00000000..ee873ebf --- /dev/null +++ b/transpiler-ffi/src/lib.rs @@ -0,0 +1,253 @@ +use std::slice; + +#[repr(C)] +pub struct TranspileResult { + pub code: *mut u8, + pub code_len: usize, + pub sourcemap: *mut u8, + pub sourcemap_len: usize, + pub error: *mut u8, + pub error_len: usize, +} + +/// # Safety +/// `source`/`filename` must point to `*_len` valid bytes. The returned +/// pointer must be freed via [`godotjs_free_transpile_result`]. +/// +/// A panic inside the transpiler (e.g. an SWC internal assertion on malformed +/// input) is caught at this boundary and turned into an error result — it must +/// never unwind across the C ABI into the engine (that would be UB). +#[no_mangle] +pub unsafe extern "C" fn godotjs_transpile_ts( + source: *const u8, + source_len: usize, + filename: *const u8, + filename_len: usize, + opts: u32, +) -> *mut TranspileResult { + match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe { + transpile_ts_impl(source, source_len, filename, filename_len, opts) + })) { + Ok(result) => result, + Err(_) => make_error(b"transpiler panicked"), + } +} + +/// # Safety +/// Same contract as [`godotjs_transpile_ts`]; this is the inner implementation +/// run inside the panic boundary. +unsafe fn transpile_ts_impl( + source: *const u8, + source_len: usize, + filename: *const u8, + filename_len: usize, + _opts: u32, +) -> *mut TranspileResult { + let source_bytes = unsafe { slice::from_raw_parts(source, source_len) }; + let filename_bytes = unsafe { slice::from_raw_parts(filename, filename_len) }; + + let source_str = match std::str::from_utf8(source_bytes) { + Ok(s) => s, + Err(_) => return make_error(b"source is not valid UTF-8"), + }; + let filename_str = match std::str::from_utf8(filename_bytes) { + Ok(s) => s, + Err(_) => return make_error(b"filename is not valid UTF-8"), + }; + + match transpile(source_str, filename_str) { + Ok((code, sourcemap)) => make_ok(code, sourcemap), + Err(msg) => make_error(msg.as_bytes()), + } +} + +/// # Safety +/// `p` must be a pointer returned by [`godotjs_transpile_ts`]. +#[no_mangle] +pub unsafe extern "C" fn godotjs_free_transpile_result(p: *mut TranspileResult) { + if p.is_null() { + return; + } + let r = unsafe { Box::from_raw(p) }; + if !r.code.is_null() { + unsafe { drop(Box::from_raw(std::ptr::slice_from_raw_parts_mut(r.code, r.code_len))) }; + } + if !r.sourcemap.is_null() { + unsafe { drop(Box::from_raw(std::ptr::slice_from_raw_parts_mut(r.sourcemap, r.sourcemap_len))) }; + } + if !r.error.is_null() { + unsafe { drop(Box::from_raw(std::ptr::slice_from_raw_parts_mut(r.error, r.error_len))) }; + } +} + +// Hand a buffer to C as (ptr, len). Round-trips through Box<[u8]> so capacity +// always equals len — freeing via Box::from_raw(slice_from_raw_parts_mut) is +// then sound. (A Vec's capacity may exceed its len, so reconstructing a Vec +// with capacity == len in the free path would be undefined behavior.) +fn vec_to_raw(v: Vec) -> (*mut u8, usize) { + let boxed: Box<[u8]> = v.into_boxed_slice(); + let len = boxed.len(); + let ptr = Box::into_raw(boxed) as *mut u8; + (ptr, len) +} + +fn make_ok(code: Vec, sourcemap: Vec) -> *mut TranspileResult { + let (code_ptr, code_len) = vec_to_raw(code); + let (sm_ptr, sm_len) = if sourcemap.is_empty() { + (std::ptr::null_mut(), 0) + } else { + vec_to_raw(sourcemap) + }; + Box::into_raw(Box::new(TranspileResult { + code: code_ptr, + code_len, + sourcemap: sm_ptr, + sourcemap_len: sm_len, + error: std::ptr::null_mut(), + error_len: 0, + })) +} + +fn make_error(msg: &[u8]) -> *mut TranspileResult { + let (err_ptr, err_len) = vec_to_raw(msg.to_vec()); + Box::into_raw(Box::new(TranspileResult { + code: std::ptr::null_mut(), + code_len: 0, + sourcemap: std::ptr::null_mut(), + sourcemap_len: 0, + error: err_ptr, + error_len: err_len, + })) +} + +struct SmConfig; + +impl swc_core::common::source_map::SourceMapGenConfig for SmConfig { + fn file_name_to_source(&self, f: &swc_core::common::FileName) -> String { + f.to_string() + } + + // The default impl excludes FileName::Custom from inlining; we want it on + // so the data URL is fully self-contained — DevTools and stack traces can + // resolve `.ts` source without a separate HTTP fetch. + fn inline_sources_content(&self, _f: &swc_core::common::FileName) -> bool { + true + } +} + +fn transpile(source: &str, filename: &str) -> Result<(Vec, Vec), String> { + use swc_core::common::{sync::Lrc, BytePos, FileName, Globals, LineCol, Mark, SourceMap, GLOBALS}; + use swc_core::ecma::ast::{EsVersion, Pass}; + use swc_core::ecma::codegen::{text_writer::JsWriter, Config, Emitter}; + use swc_core::ecma::parser::{lexer::Lexer, Parser, StringInput, Syntax, TsSyntax}; + use swc_core::ecma::transforms::base::fixer::fixer; + use swc_core::ecma::transforms::base::helpers::{inject_helpers, Helpers, HELPERS}; + use swc_core::ecma::transforms::base::hygiene::hygiene; + use swc_core::ecma::transforms::base::resolver; + use swc_core::ecma::transforms::module::{common_js, path::Resolver as ModResolver}; + use swc_core::ecma::transforms::proposal::decorator_2022_03::decorator_2022_03; + use swc_core::ecma::transforms::typescript::strip; + + let is_tsx = filename.ends_with(".tsx"); + + let cm: Lrc = Default::default(); + let fm = cm.new_source_file( + Lrc::new(FileName::Custom(filename.to_string())), + source.to_string(), + ); + + let lexer = Lexer::new( + Syntax::Typescript(TsSyntax { + tsx: is_tsx, + decorators: true, + ..Default::default() + }), + EsVersion::Es2022, + StringInput::from(&*fm), + None, + ); + + let mut parser = Parser::new_from(lexer); + let mut program = parser + .parse_program() + .map_err(|e| format!("parse error: {e:?}"))?; + + let globals = Globals::new(); + let (buf, src_map_buf) = GLOBALS.set( + &globals, + || -> Result<(Vec, Vec<(BytePos, LineCol)>), String> { + // common_js (and other passes) reach into HELPERS — a separate scoped + // TLS for the `_define`/`_object_spread`/etc. helper-injection table. + // Without it, the lazy_require path inside panics. + HELPERS.set( + &Helpers::new(false), + || -> Result<(Vec, Vec<(BytePos, LineCol)>), String> { + let unresolved_mark = Mark::new(); + let top_level_mark = Mark::new(); + + let mut passes = ( + resolver(unresolved_mark, top_level_mark, true), + // Strip TS-only syntax (type annotations, declare, generics) first, + // then lower TC39 decorators + `accessor` fields against plain JS. + strip(unresolved_mark, top_level_mark), + decorator_2022_03(), + common_js( + ModResolver::default(), + unresolved_mark, + Default::default(), + Default::default(), + ), + // Inline definitions for _interop_require_default etc. that + // common_js emits. Without this, the generated CJS references + // helpers that the engine has no way to resolve at runtime. + inject_helpers(unresolved_mark), + // Disambiguates same-named identifiers by syntax context — the + // decorator pass mints private `_dec` / `_init_*` placeholders + // that collide without renaming, collapsing every decorator to + // the last-assigned value. + hygiene(), + // Wraps low-precedence sub-expressions in parens so codegen is + // syntactically correct — without it, common_js's `(0, foo.bar)()` + // indirect-eval pattern emits as `0, foo.bar()` which parses as + // two `const` declarators when the result is assigned to a const. + fixer(None), + ); + passes.process(&mut program); + + // Emitter must run inside GLOBALS — emit_program walks AST nodes + // whose SyntaxContext lookups touch the thread-local globals. + let mut buf = Vec::new(); + let mut src_map_buf: Vec<(BytePos, LineCol)> = Vec::new(); + { + let writer = JsWriter::new( + cm.clone(), + "\n", + &mut buf, + Some(&mut src_map_buf), + ); + let mut emitter = Emitter { + cfg: Config::default(), + cm: cm.clone(), + comments: None, + wr: writer, + }; + emitter + .emit_program(&program) + .map_err(|e| format!("emit error: {e:?}"))?; + } + Ok((buf, src_map_buf)) + }, + ) + }, + )?; + + // Build the sourcemap and encode as a `data:` URL. Returned alongside the + // emitted JS; the bridge embeds it into the wrapped source as a + // `//# sourceMappingURL=…` comment so V8 picks it up for stack traces. + let sm = cm.build_source_map(&src_map_buf, None, SmConfig); + let data_url = sm + .to_data_url() + .map_err(|e| format!("sourcemap encode error: {e:?}"))?; + + Ok((buf, data_url.into_bytes())) +} diff --git a/weaver/jsb_script.cpp b/weaver/jsb_script.cpp index 8c8b4ab1..ae92a16b 100644 --- a/weaver/jsb_script.cpp +++ b/weaver/jsb_script.cpp @@ -519,7 +519,15 @@ void GodotJSScript::load_module_immediately() if (loaded_) return; JSB_BENCHMARK_SCOPE(GodotJSScript, load_module); +#if JSB_WITH_TYPESCRIPT_TRANSPILER + // Embedded transpiler present: load the .ts source directly; the module + // resolver invokes SWC in-process. + const String path = get_path(); +#else + // No embedded transpiler (the default build): keep loading the tsc-emitted + // .js at the converted path, exactly as before this stack. const String path = jsb::internal::PathUtil::convert_typescript_path(get_path()); +#endif jsb::JSEnvironment env(get_path(), true); loaded_ = true;