├── testdata ├── external.ts ├── error_with_bare_import.ts ├── subdir │ ├── foo.js │ ├── foo.ts │ ├── foo2.ts │ ├── print_hello.ts │ ├── escape.json │ ├── circular2.ts │ ├── object.json │ ├── app.jsx │ ├── mod2.ts │ └── more_decorators.ts ├── hello_world.ts ├── js_module.js ├── jsx │ └── main.tsx ├── top_level_await.ts ├── import_map │ ├── main.ts │ └── import_map.json ├── jsx_import_from_ts.ts ├── json_import.ts ├── json_import_escape.ts ├── shebang.ts ├── circular1.ts ├── exports_with_alias.ts ├── mod1.ts ├── es_decorators.ts └── ts_decorators.ts ├── tests ├── __snapshots__ │ ├── common │ │ ├── external │ │ │ ├── bundle.js │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ └── external.ts │ │ │ │ └── modules.json │ │ ├── hello_world │ │ │ ├── bundle.js │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ └── hello_world.ts │ │ │ │ └── modules.json │ │ ├── js │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ │ ├── subdir │ │ │ │ │ │ └── foo.js │ │ │ │ │ └── js_module.js │ │ │ │ └── modules.json │ │ │ └── bundle.js │ │ ├── load_override │ │ │ ├── bundle.js │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ └── src.ts │ │ │ │ └── modules.json │ │ ├── exports │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ │ ├── subdir │ │ │ │ │ │ ├── print_hello.ts │ │ │ │ │ │ └── mod2.ts │ │ │ │ │ └── mod1.ts │ │ │ │ └── modules.json │ │ │ └── bundle.js │ │ ├── file_url_as_object │ │ │ ├── bundle.js │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ └── hello_world.ts │ │ │ │ └── modules.json │ │ ├── file_url_as_string │ │ │ ├── bundle.js │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ └── hello_world.ts │ │ │ │ └── modules.json │ │ ├── es_decorators │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── modules.json │ │ │ │ └── local │ │ │ │ └── subdir │ │ │ │ └── more_decorators.ts │ │ ├── ts_decorators │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── modules.json │ │ │ │ └── local │ │ │ │ │ ├── subdir │ │ │ │ │ └── more_decorators.ts │ │ │ │ │ └── ts_decorators.ts │ │ │ └── bundle.js │ │ ├── hello_world_relative_path │ │ │ ├── bundle.js │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ └── hello_world.ts │ │ │ │ └── modules.json │ │ ├── jsx_import_from_ts │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ │ ├── jsx_import_from_ts.ts │ │ │ │ │ └── subdir │ │ │ │ │ │ └── app.jsx │ │ │ │ └── modules.json │ │ │ └── bundle.js │ │ ├── top_level_await │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ │ └── top_level_await.ts │ │ │ │ └── modules.json │ │ │ └── bundle.js │ │ ├── export_specifier_with_alias │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ │ ├── subdir │ │ │ │ │ │ └── foo.ts │ │ │ │ │ └── exports_with_alias.ts │ │ │ │ └── modules.json │ │ │ └── bundle.js │ │ ├── remote_url_as_object │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── remote │ │ │ │ └── NNRNTa3nQ9cRguYpg8Fa19sQDzU │ │ │ │ │ └── std@0.140.0 │ │ │ │ │ ├── io │ │ │ │ │ └── types.d.ts │ │ │ │ │ ├── path │ │ │ │ │ ├── _interface.ts │ │ │ │ │ ├── separator.ts │ │ │ │ │ ├── mod.ts │ │ │ │ │ ├── common.ts │ │ │ │ │ ├── _constants.ts │ │ │ │ │ ├── _util.ts │ │ │ │ │ └── glob.ts │ │ │ │ │ ├── _util │ │ │ │ │ ├── assert.ts │ │ │ │ │ └── os.ts │ │ │ │ │ ├── bytes │ │ │ │ │ ├── equals.ts │ │ │ │ │ ├── bytes_list.ts │ │ │ │ │ └── mod.ts │ │ │ │ │ └── examples │ │ │ │ │ └── chat │ │ │ │ │ └── server.ts │ │ │ │ └── modules.json │ │ └── remote_url_as_string │ │ │ └── transpile │ │ │ ├── deno.json │ │ │ ├── remote │ │ │ └── NNRNTa3nQ9cRguYpg8Fa19sQDzU │ │ │ │ └── std@0.140.0 │ │ │ │ ├── io │ │ │ │ └── types.d.ts │ │ │ │ ├── path │ │ │ │ ├── _interface.ts │ │ │ │ ├── separator.ts │ │ │ │ ├── mod.ts │ │ │ │ ├── common.ts │ │ │ │ ├── _constants.ts │ │ │ │ ├── _util.ts │ │ │ │ └── glob.ts │ │ │ │ ├── _util │ │ │ │ ├── assert.ts │ │ │ │ └── os.ts │ │ │ │ ├── bytes │ │ │ │ ├── equals.ts │ │ │ │ ├── bytes_list.ts │ │ │ │ └── mod.ts │ │ │ │ └── examples │ │ │ │ └── chat │ │ │ │ └── server.ts │ │ │ └── modules.json │ ├── jsx │ │ ├── jsx_type_preserve │ │ │ ├── deno.json │ │ │ ├── bundle.js │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ │ └── jsx │ │ │ │ │ │ └── main.tsx │ │ │ │ └── modules.json │ │ │ ├── local │ │ │ │ └── jsx │ │ │ │ │ └── main.tsx │ │ │ └── modules.json │ │ ├── jsx_type_reactjsx │ │ │ ├── deno.json │ │ │ ├── modules.json │ │ │ └── local │ │ │ │ └── jsx │ │ │ │ └── main.tsx │ │ ├── jsx_default │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── modules.json │ │ │ │ └── local │ │ │ │ │ └── jsx │ │ │ │ │ └── main.tsx │ │ │ └── bundle.js │ │ ├── jsx_type_precompile │ │ │ ├── deno.json │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── modules.json │ │ │ │ └── local │ │ │ │ │ └── jsx │ │ │ │ │ └── main.tsx │ │ │ ├── modules.json │ │ │ └── local │ │ │ │ └── jsx │ │ │ │ └── main.tsx │ │ ├── jsx_type_reactnative │ │ │ ├── bundle.js │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ └── jsx │ │ │ │ │ └── main.tsx │ │ │ │ └── modules.json │ │ ├── jsx_type_react │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── modules.json │ │ │ │ └── local │ │ │ │ │ └── jsx │ │ │ │ │ └── main.tsx │ │ │ └── bundle.js │ │ └── jsx_type_reactjsx_with_custom_import_source │ │ │ ├── deno.json │ │ │ ├── modules.json │ │ │ └── local │ │ │ └── jsx │ │ │ └── main.tsx │ ├── import_map │ │ ├── embedded │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ │ ├── subdir │ │ │ │ │ │ └── foo.ts │ │ │ │ │ └── import_map │ │ │ │ │ │ └── main.ts │ │ │ │ └── modules.json │ │ │ └── bundle.js │ │ ├── empty_import_map │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ │ ├── subdir │ │ │ │ │ │ ├── print_hello.ts │ │ │ │ │ │ └── mod2.ts │ │ │ │ │ └── mod1.ts │ │ │ │ └── modules.json │ │ │ └── bundle.js │ │ ├── embedded_with_specific_base_url │ │ │ ├── bundle.js │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ ├── subdir │ │ │ │ │ └── foo.ts │ │ │ │ └── import_map │ │ │ │ │ └── main.ts │ │ │ │ └── modules.json │ │ ├── local_file_set_as_absolute_path │ │ │ ├── bundle.js │ │ │ └── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ ├── subdir │ │ │ │ │ └── foo.ts │ │ │ │ └── import_map │ │ │ │ │ └── main.ts │ │ │ │ └── modules.json │ │ ├── local_file_set_as_file_url_object │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ │ ├── subdir │ │ │ │ │ │ └── foo.ts │ │ │ │ │ └── import_map │ │ │ │ │ │ └── main.ts │ │ │ │ └── modules.json │ │ │ └── bundle.js │ │ ├── local_file_set_as_file_url_string │ │ │ ├── transpile │ │ │ │ ├── deno.json │ │ │ │ ├── local │ │ │ │ │ ├── subdir │ │ │ │ │ │ └── foo.ts │ │ │ │ │ └── import_map │ │ │ │ │ │ └── main.ts │ │ │ │ └── modules.json │ │ │ └── bundle.js │ │ └── local_file_set_as_relative_path │ │ │ ├── bundle.js │ │ │ └── transpile │ │ │ ├── deno.json │ │ │ ├── local │ │ │ ├── subdir │ │ │ │ └── foo.ts │ │ │ └── import_map │ │ │ │ └── main.ts │ │ │ └── modules.json │ └── bundle │ │ ├── circular.js │ │ ├── json_import_escape.js │ │ ├── minified_json_import.js │ │ └── json_import.js ├── jsx_test.ts ├── bundle_test.ts ├── import_map_test.ts ├── common_test.ts └── source_map_test.ts ├── rust-toolchain.toml ├── .gitattributes ├── .gitignore ├── .rustfmt.toml ├── js ├── deno.json ├── README.md ├── _utils.ts ├── emit.generated.d.ts └── mod.ts ├── deno.jsonc ├── Cargo.toml ├── rs-lib ├── Cargo.toml └── src │ ├── bundle_hook.rs │ ├── text.rs │ └── lib.rs ├── wasm ├── Cargo.toml └── src │ └── lib.rs ├── README.md ├── .github └── workflows │ ├── release.yml │ └── ci.yml └── LICENSE /testdata/external.ts: -------------------------------------------------------------------------------- 1 | import "node:fs"; 2 | -------------------------------------------------------------------------------- /testdata/error_with_bare_import.ts: -------------------------------------------------------------------------------- 1 | import "foo"; 2 | -------------------------------------------------------------------------------- /testdata/subdir/foo.js: -------------------------------------------------------------------------------- 1 | export const foo = "foo"; 2 | -------------------------------------------------------------------------------- /testdata/hello_world.ts: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /testdata/subdir/foo.ts: -------------------------------------------------------------------------------- 1 | export const foo: string = "foo"; 2 | -------------------------------------------------------------------------------- /testdata/subdir/foo2.ts: -------------------------------------------------------------------------------- 1 | export const foo: string = "foo2"; 2 | -------------------------------------------------------------------------------- /testdata/js_module.js: -------------------------------------------------------------------------------- 1 | export { foo } from "./subdir/foo.js"; 2 | -------------------------------------------------------------------------------- /testdata/jsx/main.tsx: -------------------------------------------------------------------------------- 1 | const helloWorld =
; -------------------------------------------------------------------------------- /tests/__snapshots__/common/external/bundle.js: -------------------------------------------------------------------------------- 1 | import "node:fs"; 2 | -------------------------------------------------------------------------------- /testdata/top_level_await.ts: -------------------------------------------------------------------------------- 1 | export const tla = await Promise.resolve("Hello"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/hello_world/bundle.js: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/js/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/load_override/bundle.js: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_preserve/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_reactjsx/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /testdata/import_map/main.ts: -------------------------------------------------------------------------------- 1 | import { foo } from "foo"; 2 | 3 | console.log(foo); 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/exports/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/external/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/external/transpile/local/external.ts: -------------------------------------------------------------------------------- 1 | import "node:fs"; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/file_url_as_object/bundle.js: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/file_url_as_string/bundle.js: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_default/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_precompile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_preserve/bundle.js: -------------------------------------------------------------------------------- 1 |
; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_reactnative/bundle.js: -------------------------------------------------------------------------------- 1 |
; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/es_decorators/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/hello_world/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/js/bundle.js: -------------------------------------------------------------------------------- 1 | const foo = "foo"; 2 | export { foo as foo }; 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/js/transpile/local/subdir/foo.js: -------------------------------------------------------------------------------- 1 | export const foo = "foo"; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/load_override/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/ts_decorators/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/embedded/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_preserve/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_react/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.80.0" 3 | components = [ "clippy", "rustfmt" ] -------------------------------------------------------------------------------- /testdata/jsx_import_from_ts.ts: -------------------------------------------------------------------------------- 1 | import app from "./subdir/app.jsx"; 2 | 3 | console.log(app); 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/file_url_as_object/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/file_url_as_string/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/hello_world_relative_path/bundle.js: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/jsx_import_from_ts/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/load_override/transpile/local/src.ts: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/top_level_await/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/embedded/bundle.js: -------------------------------------------------------------------------------- 1 | const foo = "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_precompile/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_reactnative/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | /tests/__snapshots__/** text eol=lf 3 | /testdata/** text eol=lf 4 | -------------------------------------------------------------------------------- /testdata/subdir/print_hello.ts: -------------------------------------------------------------------------------- 1 | export function printHello() { 2 | console.log("Hello"); 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/hello_world/transpile/local/hello_world.ts: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/js/transpile/local/js_module.js: -------------------------------------------------------------------------------- 1 | export { foo } from "./subdir/foo.js"; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/embedded/transpile/local/subdir/foo.ts: -------------------------------------------------------------------------------- 1 | export const foo = "foo"; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/empty_import_map/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /testdata/import_map/import_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "foo": "../subdir/foo.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/export_specifier_with_alias/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/hello_world_relative_path/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/file_url_as_object/transpile/local/hello_world.ts: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/file_url_as_string/transpile/local/hello_world.ts: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_default/bundle.js: -------------------------------------------------------------------------------- 1 | React.createElement("div", { 2 | id: "helloWorld" 3 | }); 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_preserve/local/jsx/main.tsx: -------------------------------------------------------------------------------- 1 | const helloWorld =
; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_reactjsx_with_custom_import_source/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/export_specifier_with_alias/transpile/local/subdir/foo.ts: -------------------------------------------------------------------------------- 1 | export const foo = "foo"; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/hello_world_relative_path/transpile/local/hello_world.ts: -------------------------------------------------------------------------------- 1 | console.log("Hello world!"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/load_override/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///src.ts": "local/src.ts" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/embedded_with_specific_base_url/bundle.js: -------------------------------------------------------------------------------- 1 | const foo = "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/embedded_with_specific_base_url/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_absolute_path/bundle.js: -------------------------------------------------------------------------------- 1 | const foo = "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_absolute_path/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_file_url_object/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_file_url_string/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_relative_path/bundle.js: -------------------------------------------------------------------------------- 1 | const foo = "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_relative_path/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": {} 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_preserve/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///jsx/main.tsx": "local/jsx/main.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_react/bundle.js: -------------------------------------------------------------------------------- 1 | React.createElement("div", { 2 | id: "helloWorld" 3 | }); 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_reactjsx/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///jsx/main.tsx": "local/jsx/main.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /testdata/json_import.ts: -------------------------------------------------------------------------------- 1 | import json from "./subdir/object.json" assert { type: "json" }; 2 | 3 | console.log(json); 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/external/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///external.ts": "local/external.ts" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/embedded_with_specific_base_url/transpile/local/subdir/foo.ts: -------------------------------------------------------------------------------- 1 | export const foo = "foo"; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_absolute_path/transpile/local/subdir/foo.ts: -------------------------------------------------------------------------------- 1 | export const foo = "foo"; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_file_url_object/bundle.js: -------------------------------------------------------------------------------- 1 | const foo = "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_file_url_string/bundle.js: -------------------------------------------------------------------------------- 1 | const foo = "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_relative_path/transpile/local/subdir/foo.ts: -------------------------------------------------------------------------------- 1 | export const foo = "foo"; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_default/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///jsx/main.tsx": "local/jsx/main.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_precompile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///jsx/main.tsx": "local/jsx/main.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_preserve/transpile/local/jsx/main.tsx: -------------------------------------------------------------------------------- 1 | const helloWorld =
; 2 | -------------------------------------------------------------------------------- /testdata/json_import_escape.ts: -------------------------------------------------------------------------------- 1 | import json from "./subdir/escape.json" assert { type: "json" }; 2 | 3 | console.log(json); 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/hello_world/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///hello_world.ts": "local/hello_world.ts" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/top_level_await/bundle.js: -------------------------------------------------------------------------------- 1 | const tla = await Promise.resolve("Hello"); 2 | export { tla as tla }; 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/embedded/transpile/local/import_map/main.ts: -------------------------------------------------------------------------------- 1 | import { foo } from "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_file_url_object/transpile/local/subdir/foo.ts: -------------------------------------------------------------------------------- 1 | export const foo = "foo"; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_file_url_string/transpile/local/subdir/foo.ts: -------------------------------------------------------------------------------- 1 | export const foo = "foo"; 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_preserve/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///jsx/main.tsx": "local/jsx/main.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_react/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///jsx/main.tsx": "local/jsx/main.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_reactnative/transpile/local/jsx/main.tsx: -------------------------------------------------------------------------------- 1 | const helloWorld =
; 2 | -------------------------------------------------------------------------------- /testdata/subdir/escape.json: -------------------------------------------------------------------------------- 1 | "a value with newline\n, \"double quotes\", 'single quotes', ${jsInterpolation} and `string literal`" 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/top_level_await/transpile/local/top_level_await.ts: -------------------------------------------------------------------------------- 1 | export const tla = await Promise.resolve("Hello"); 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_precompile/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///jsx/main.tsx": "local/jsx/main.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_reactnative/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///jsx/main.tsx": "local/jsx/main.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /rs-lib/target 3 | /wasm/target 4 | .vscode/ 5 | /js/LICENSE 6 | /js/emit_bg.wasm 7 | /js/emit.generated.js 8 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/file_url_as_object/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///hello_world.ts": "local/hello_world.ts" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/file_url_as_string/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///hello_world.ts": "local/hello_world.ts" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/exports/transpile/local/subdir/print_hello.ts: -------------------------------------------------------------------------------- 1 | export function printHello() { 2 | console.log("Hello"); 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/hello_world_relative_path/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///hello_world.ts": "local/hello_world.ts" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/top_level_await/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///top_level_await.ts": "local/top_level_await.ts" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_reactjsx_with_custom_import_source/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///jsx/main.tsx": "local/jsx/main.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/jsx_import_from_ts/transpile/local/jsx_import_from_ts.ts: -------------------------------------------------------------------------------- 1 | import app from "./subdir/app.jsx"; 2 | console.log(app); 3 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 the Deno authors. All rights reserved. MIT license. 2 | max_width = 80 3 | tab_spaces = 2 4 | edition = "2018" 5 | -------------------------------------------------------------------------------- /testdata/shebang.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S deno run --allow-read 2 | 3 | for (const item of Deno.readDirSync(".")) { 4 | console.log(item.name); 5 | } 6 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/embedded_with_specific_base_url/transpile/local/import_map/main.ts: -------------------------------------------------------------------------------- 1 | import { foo } from "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_absolute_path/transpile/local/import_map/main.ts: -------------------------------------------------------------------------------- 1 | import { foo } from "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_file_url_object/transpile/local/import_map/main.ts: -------------------------------------------------------------------------------- 1 | import { foo } from "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_file_url_string/transpile/local/import_map/main.ts: -------------------------------------------------------------------------------- 1 | import { foo } from "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_relative_path/transpile/local/import_map/main.ts: -------------------------------------------------------------------------------- 1 | import { foo } from "foo"; 2 | console.log(foo); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/empty_import_map/transpile/local/subdir/print_hello.ts: -------------------------------------------------------------------------------- 1 | export function printHello() { 2 | console.log("Hello"); 3 | } 4 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_default/transpile/local/jsx/main.tsx: -------------------------------------------------------------------------------- 1 | const helloWorld = /*#__PURE__*/ React.createElement("div", { 2 | id: "helloWorld" 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/circular1.ts: -------------------------------------------------------------------------------- 1 | import * as circular2 from "./subdir/circular2.ts"; 2 | 3 | export function f1() { 4 | console.log("f1"); 5 | } 6 | 7 | circular2.f2(); 8 | -------------------------------------------------------------------------------- /testdata/subdir/circular2.ts: -------------------------------------------------------------------------------- 1 | import * as circular1 from "../circular1.ts"; 2 | 3 | export function f2() { 4 | console.log("f2"); 5 | } 6 | 7 | circular1.f1(); 8 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/export_specifier_with_alias/bundle.js: -------------------------------------------------------------------------------- 1 | const foo = "foo"; 2 | export { foo as test1 }; 3 | export { foo as test2 }; 4 | console.log(foo); 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_react/transpile/local/jsx/main.tsx: -------------------------------------------------------------------------------- 1 | const helloWorld = /*#__PURE__*/ React.createElement("div", { 2 | id: "helloWorld" 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/subdir/object.json: -------------------------------------------------------------------------------- 1 | { 2 | "$var": { "a": 123, "b": [1, 2, 3], "c": null }, 3 | "with space": "invalid variable name", 4 | "function": "reserved word" 5 | } 6 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/js/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///js_module.js": "local/js_module.js", 3 | "file:///subdir/foo.js": "local/subdir/foo.js" 4 | } 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "https://deno.land": "./remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "https://deno.land": "./remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/embedded/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///import_map/main.ts": "local/import_map/main.ts", 3 | "file:///subdir/foo.ts": "local/subdir/foo.ts" 4 | } 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_reactjsx/local/jsx/main.tsx: -------------------------------------------------------------------------------- 1 | import { jsx as _jsx } from "/jsx-runtime"; 2 | const helloWorld = /*#__PURE__*/ _jsx("div", { 3 | id: "helloWorld" 4 | }); 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/io/types.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/io/types.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | -------------------------------------------------------------------------------- /tests/__snapshots__/bundle/circular.js: -------------------------------------------------------------------------------- 1 | function f1() { 2 | console.log("f1"); 3 | } 4 | function f2() { 5 | console.log("f2"); 6 | } 7 | f2(); 8 | f1(); 9 | export { f1 as f1 }; 10 | -------------------------------------------------------------------------------- /testdata/exports_with_alias.ts: -------------------------------------------------------------------------------- 1 | export { foo as test1 } from "./subdir/foo.ts"; 2 | export { foo as test2 } from "./subdir/foo.ts"; 3 | import { foo } from "./subdir/foo.ts"; 4 | 5 | console.log(foo); 6 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/jsx_import_from_ts/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///jsx_import_from_ts.ts": "local/jsx_import_from_ts.ts", 3 | "file:///subdir/app.jsx": "local/subdir/app.jsx" 4 | } 5 | -------------------------------------------------------------------------------- /testdata/subdir/app.jsx: -------------------------------------------------------------------------------- 1 | const React = { 2 | createElement() {}, 3 | }; 4 | 5 | export default function app() { 6 | return ( 7 |
8 |

asdf

9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/es_decorators/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///es_decorators.ts": "local/es_decorators.ts", 3 | "file:///subdir/more_decorators.ts": "local/subdir/more_decorators.ts" 4 | } 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/export_specifier_with_alias/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///exports_with_alias.ts": "local/exports_with_alias.ts", 3 | "file:///subdir/foo.ts": "local/subdir/foo.ts" 4 | } 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/ts_decorators/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///subdir/more_decorators.ts": "local/subdir/more_decorators.ts", 3 | "file:///ts_decorators.ts": "local/ts_decorators.ts" 4 | } 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/embedded_with_specific_base_url/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///import_map/main.ts": "local/import_map/main.ts", 3 | "file:///subdir/foo.ts": "local/subdir/foo.ts" 4 | } 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_absolute_path/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///import_map/main.ts": "local/import_map/main.ts", 3 | "file:///subdir/foo.ts": "local/subdir/foo.ts" 4 | } 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_file_url_object/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///import_map/main.ts": "local/import_map/main.ts", 3 | "file:///subdir/foo.ts": "local/subdir/foo.ts" 4 | } 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_file_url_string/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///import_map/main.ts": "local/import_map/main.ts", 3 | "file:///subdir/foo.ts": "local/subdir/foo.ts" 4 | } 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/local_file_set_as_relative_path/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///import_map/main.ts": "local/import_map/main.ts", 3 | "file:///subdir/foo.ts": "local/subdir/foo.ts" 4 | } 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/bundle/json_import_escape.js: -------------------------------------------------------------------------------- 1 | const __default = JSON.parse("\"a value with newline\\n, \\\"double quotes\\\", 'single quotes', ${jsInterpolation} and `string literal`\""); 2 | console.log(__default); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_reactjsx_with_custom_import_source/local/jsx/main.tsx: -------------------------------------------------------------------------------- 1 | import { jsx as _jsx } from "example/jsx-runtime"; 2 | const helloWorld = /*#__PURE__*/ _jsx("div", { 3 | id: "helloWorld" 4 | }); 5 | -------------------------------------------------------------------------------- /testdata/subdir/mod2.ts: -------------------------------------------------------------------------------- 1 | import { printHello } from "./print_hello.ts"; 2 | 3 | export function returnsFoo(): string { 4 | return "Foo"; 5 | } 6 | 7 | export function printHello2() { 8 | printHello(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/__snapshots__/bundle/minified_json_import.js: -------------------------------------------------------------------------------- 1 | const __default=JSON.parse('{\n "$var": { "a": 123, "b": [1, 2, 3], "c": null },\n "with space": "invalid variable name",\n "function": "reserved word"\n}');console.log(__default); -------------------------------------------------------------------------------- /tests/__snapshots__/common/exports/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///mod1.ts": "local/mod1.ts", 3 | "file:///subdir/mod2.ts": "local/subdir/mod2.ts", 4 | "file:///subdir/print_hello.ts": "local/subdir/print_hello.ts" 5 | } 6 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/exports/transpile/local/subdir/mod2.ts: -------------------------------------------------------------------------------- 1 | import { printHello } from "./print_hello.ts"; 2 | export function returnsFoo() { 3 | return "Foo"; 4 | } 5 | export function printHello2() { 6 | printHello(); 7 | } 8 | -------------------------------------------------------------------------------- /tests/__snapshots__/bundle/json_import.js: -------------------------------------------------------------------------------- 1 | const __default = JSON.parse("{\n \"$var\": { \"a\": 123, \"b\": [1, 2, 3], \"c\": null },\n \"with space\": \"invalid variable name\",\n \"function\": \"reserved word\"\n}"); 2 | console.log(__default); 3 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/jsx_import_from_ts/bundle.js: -------------------------------------------------------------------------------- 1 | const React = { 2 | createElement () {} 3 | }; 4 | function app() { 5 | return React.createElement("div", null, React.createElement("h2", null, "asdf")); 6 | } 7 | console.log(app); 8 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/empty_import_map/transpile/local/subdir/mod2.ts: -------------------------------------------------------------------------------- 1 | import { printHello } from "./print_hello.ts"; 2 | export function returnsFoo() { 3 | return "Foo"; 4 | } 5 | export function printHello2() { 6 | printHello(); 7 | } 8 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/empty_import_map/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "file:///mod1.ts": "local/mod1.ts", 3 | "file:///subdir/mod2.ts": "local/subdir/mod2.ts", 4 | "file:///subdir/print_hello.ts": "local/subdir/print_hello.ts" 5 | } 6 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_precompile/local/jsx/main.tsx: -------------------------------------------------------------------------------- 1 | import { jsxTemplate as _jsxTemplate } from "jsx-precompile/jsx-runtime"; 2 | const $$_tpl_1 = [ 3 | '
' 4 | ]; 5 | const helloWorld = _jsxTemplate($$_tpl_1); 6 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/export_specifier_with_alias/transpile/local/exports_with_alias.ts: -------------------------------------------------------------------------------- 1 | export { foo as test1 } from "./subdir/foo.ts"; 2 | export { foo as test2 } from "./subdir/foo.ts"; 3 | import { foo } from "./subdir/foo.ts"; 4 | console.log(foo); 5 | -------------------------------------------------------------------------------- /tests/__snapshots__/jsx/jsx_type_precompile/transpile/local/jsx/main.tsx: -------------------------------------------------------------------------------- 1 | import { jsxTemplate as _jsxTemplate } from "jsx-precompile/jsx-runtime"; 2 | const $$_tpl_1 = [ 3 | '
' 4 | ]; 5 | const helloWorld = _jsxTemplate($$_tpl_1); 6 | -------------------------------------------------------------------------------- /js/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@deno/emit", 3 | "version": "0.0.0", 4 | "exports": "./mod.ts", 5 | "publish": { 6 | "exclude": [ 7 | "!**" 8 | ] 9 | }, 10 | "imports": { 11 | "@std/path": "jsr:@std/path@^0.223.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/jsx_import_from_ts/transpile/local/subdir/app.jsx: -------------------------------------------------------------------------------- 1 | const React = { 2 | createElement () {} 3 | }; 4 | export default function app() { 5 | return /*#__PURE__*/ React.createElement("div", null, /*#__PURE__*/ React.createElement("h2", null, "asdf")); 6 | } 7 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_interface.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | /** 4 | * A parsed path object generated by path.parse() or consumed by path.format(). 5 | */ -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_interface.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | /** 4 | * A parsed path object generated by path.parse() or consumed by path.format(). 5 | */ -------------------------------------------------------------------------------- /testdata/subdir/more_decorators.ts: -------------------------------------------------------------------------------- 1 | function a() { 2 | console.log("a(): evaluated"); 3 | return ( 4 | _target: any, 5 | _propertyKey: string, 6 | _descriptor: PropertyDescriptor, 7 | ) => { 8 | console.log("a(): called"); 9 | }; 10 | } 11 | 12 | export class B { 13 | @a() 14 | method() { 15 | console.log("method"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/separator.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | import { isWindows } from "../_util/os.ts"; 4 | export const SEP = isWindows ? "\\" : "/"; 5 | export const SEP_PATTERN = isWindows ? /[\\/]+/ : /\/+/; 6 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/separator.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | import { isWindows } from "../_util/os.ts"; 4 | export const SEP = isWindows ? "\\" : "/"; 5 | export const SEP_PATTERN = isWindows ? /[\\/]+/ : /\/+/; 6 | -------------------------------------------------------------------------------- /testdata/mod1.ts: -------------------------------------------------------------------------------- 1 | import { printHello2, returnsFoo } from "./subdir/mod2.ts"; 2 | 3 | export function returnsHi(): string { 4 | return "Hi"; 5 | } 6 | 7 | export function returnsFoo2(): string { 8 | return returnsFoo(); 9 | } 10 | 11 | export function printHello3() { 12 | printHello2(); 13 | } 14 | 15 | export function throwsError() { 16 | throw Error("exception from mod1"); 17 | } 18 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/exports/transpile/local/mod1.ts: -------------------------------------------------------------------------------- 1 | import { printHello2, returnsFoo } from "./subdir/mod2.ts"; 2 | export function returnsHi() { 3 | return "Hi"; 4 | } 5 | export function returnsFoo2() { 6 | return returnsFoo(); 7 | } 8 | export function printHello3() { 9 | printHello2(); 10 | } 11 | export function throwsError() { 12 | throw Error("exception from mod1"); 13 | } 14 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/empty_import_map/transpile/local/mod1.ts: -------------------------------------------------------------------------------- 1 | import { printHello2, returnsFoo } from "./subdir/mod2.ts"; 2 | export function returnsHi() { 3 | return "Hi"; 4 | } 5 | export function returnsFoo2() { 6 | return returnsFoo(); 7 | } 8 | export function printHello3() { 9 | printHello2(); 10 | } 11 | export function throwsError() { 12 | throw Error("exception from mod1"); 13 | } 14 | -------------------------------------------------------------------------------- /deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "lock": false, 3 | "tasks": { 4 | "test": "deno test -A", 5 | "update-snapshots": "deno test -A -- --update", 6 | "build": "cp LICENSE js/LICENSE && deno run -A jsr:@deno/wasmbuild@0.17.1 --out js" 7 | }, 8 | "exclude": [ 9 | "lib", 10 | "static", 11 | "testdata", 12 | "target", 13 | "tests/__snapshots__" 14 | ], 15 | "imports": { 16 | "@std/path": "jsr:@std/path@^0.223.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "rs-lib", 5 | "wasm" 6 | ] 7 | 8 | [workspace.dependencies] 9 | anyhow = "1.0.44" 10 | base64 = "0.21.5" 11 | deno_graph = { version = "0.82.0", default-features = false } 12 | deno_ast = { version = "0.42.0", features = ["bundler", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "visit", "transpiling"] } 13 | url = { version = "2.3.1" } 14 | 15 | [profile.release] 16 | codegen-units = 1 17 | incremental = true 18 | lto = true 19 | opt-level = "z" 20 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/_util/assert.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | export class DenoStdInternalError extends Error { 4 | constructor(message){ 5 | super(message); 6 | this.name = "DenoStdInternalError"; 7 | } 8 | } 9 | /** Make an assertion, if not `true`, then throw. */ export function assert(expr, msg = "") { 10 | if (!expr) { 11 | throw new DenoStdInternalError(msg); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/_util/assert.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | export class DenoStdInternalError extends Error { 4 | constructor(message){ 5 | super(message); 6 | this.name = "DenoStdInternalError"; 7 | } 8 | } 9 | /** Make an assertion, if not `true`, then throw. */ export function assert(expr, msg = "") { 10 | if (!expr) { 11 | throw new DenoStdInternalError(msg); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /testdata/es_decorators.ts: -------------------------------------------------------------------------------- 1 | import { B } from "./subdir/more_decorators.ts"; 2 | 3 | function Decorator() { 4 | return function ( 5 | target: Record, 6 | propertyKey: string, 7 | descriptor: TypedPropertyDescriptor, 8 | ) { 9 | const originalFn: Function = descriptor.value as Function; 10 | descriptor.value = async function (...args: any[]) { 11 | return await originalFn.apply(this, args); 12 | }; 13 | return descriptor; 14 | }; 15 | } 16 | 17 | class SomeClass { 18 | @Decorator() 19 | async test() {} 20 | } 21 | 22 | new SomeClass().test(); 23 | new B().method(); 24 | -------------------------------------------------------------------------------- /testdata/ts_decorators.ts: -------------------------------------------------------------------------------- 1 | import { B } from "./subdir/more_decorators.ts"; 2 | 3 | function Decorator() { 4 | return function ( 5 | target: Record, 6 | propertyKey: string, 7 | descriptor: TypedPropertyDescriptor, 8 | ) { 9 | const originalFn: Function = descriptor.value as Function; 10 | descriptor.value = async function (...args: any[]) { 11 | return await originalFn.apply(this, args); 12 | }; 13 | return descriptor; 14 | }; 15 | } 16 | 17 | class SomeClass { 18 | @Decorator() 19 | async test() {} 20 | } 21 | 22 | new SomeClass().test(); 23 | new B().method(); 24 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/exports/bundle.js: -------------------------------------------------------------------------------- 1 | function printHello() { 2 | console.log("Hello"); 3 | } 4 | function returnsFoo() { 5 | return "Foo"; 6 | } 7 | function printHello2() { 8 | printHello(); 9 | } 10 | function returnsHi() { 11 | return "Hi"; 12 | } 13 | function returnsFoo2() { 14 | return returnsFoo(); 15 | } 16 | function printHello3() { 17 | printHello2(); 18 | } 19 | function throwsError() { 20 | throw Error("exception from mod1"); 21 | } 22 | export { returnsHi as returnsHi }; 23 | export { returnsFoo2 as returnsFoo2 }; 24 | export { printHello3 as printHello3 }; 25 | export { throwsError as throwsError }; 26 | -------------------------------------------------------------------------------- /tests/__snapshots__/import_map/empty_import_map/bundle.js: -------------------------------------------------------------------------------- 1 | function printHello() { 2 | console.log("Hello"); 3 | } 4 | function returnsFoo() { 5 | return "Foo"; 6 | } 7 | function printHello2() { 8 | printHello(); 9 | } 10 | function returnsHi() { 11 | return "Hi"; 12 | } 13 | function returnsFoo2() { 14 | return returnsFoo(); 15 | } 16 | function printHello3() { 17 | printHello2(); 18 | } 19 | function throwsError() { 20 | throw Error("exception from mod1"); 21 | } 22 | export { returnsHi as returnsHi }; 23 | export { returnsFoo2 as returnsFoo2 }; 24 | export { printHello3 as printHello3 }; 25 | export { throwsError as throwsError }; 26 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/_util/os.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | export const osType = (()=>{ 4 | // deno-lint-ignore no-explicit-any 5 | const { Deno } = globalThis; 6 | if (typeof Deno?.build?.os === "string") { 7 | return Deno.build.os; 8 | } 9 | // deno-lint-ignore no-explicit-any 10 | const { navigator } = globalThis; 11 | if (navigator?.appVersion?.includes?.("Win")) { 12 | return "windows"; 13 | } 14 | return "linux"; 15 | })(); 16 | export const isWindows = osType === "windows"; 17 | export const isLinux = osType === "linux"; 18 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/_util/os.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | export const osType = (()=>{ 4 | // deno-lint-ignore no-explicit-any 5 | const { Deno } = globalThis; 6 | if (typeof Deno?.build?.os === "string") { 7 | return Deno.build.os; 8 | } 9 | // deno-lint-ignore no-explicit-any 10 | const { navigator } = globalThis; 11 | if (navigator?.appVersion?.includes?.("Win")) { 12 | return "windows"; 13 | } 14 | return "linux"; 15 | })(); 16 | export const isWindows = osType === "windows"; 17 | export const isLinux = osType === "linux"; 18 | -------------------------------------------------------------------------------- /rs-lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deno_emit" 3 | version = "0.46.0" 4 | edition = "2021" 5 | description = "module transpiling and emitting for deno" 6 | homepage = "https://deno.land/" 7 | repository = "https://github.com/denoland/deno_emit" 8 | authors = ["the Deno authors"] 9 | license = "MIT" 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | base64 = { workspace = true } 14 | deno_ast = { workspace = true } 15 | deno_graph = { workspace = true } 16 | escape8259 = "0.5.2" 17 | futures = "0.3.17" 18 | import_map = "0.20.0" 19 | parking_lot = { version = "0.11.2" } 20 | url = { workspace = true } 21 | 22 | [dev-dependencies] 23 | pretty_assertions = "1.0.0" 24 | tokio = { version = "1.11.0", features = ["full"] } 25 | -------------------------------------------------------------------------------- /wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deno_emit_wasm" 3 | version = "0.0.0" 4 | edition = "2021" 5 | description = "module transpiling and emitting for deno" 6 | homepage = "https://deno.land/" 7 | repository = "https://github.com/denoland/deno_emit" 8 | authors = ["the Deno authors"] 9 | license = "MIT" 10 | 11 | [lib] 12 | crate-type = ["cdylib", "rlib"] 13 | name = "emit" 14 | 15 | [dependencies] 16 | anyhow = { workspace = true } 17 | base64 = { workspace = true } 18 | console_error_panic_hook = "0.1.7" 19 | deno_emit = { path = "../rs-lib" } 20 | deno_graph = { workspace = true } 21 | getrandom = { version = "*", features = ["js"] } 22 | js-sys = { version = "=0.3.69" } 23 | serde = { version = "1.0.130", features = ["derive", "rc"] } 24 | url = { workspace = true } 25 | wasm-bindgen = { version = "=0.2.92" } 26 | wasm-bindgen-futures = { version = "=0.4.42" } 27 | serde-wasm-bindgen = "0.5.0" 28 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/ts_decorators/transpile/local/subdir/more_decorators.ts: -------------------------------------------------------------------------------- 1 | function _ts_decorate(decorators, target, key, desc) { 2 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 3 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 4 | else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 5 | return c > 3 && r && Object.defineProperty(target, key, r), r; 6 | } 7 | function a() { 8 | console.log("a(): evaluated"); 9 | return (_target, _propertyKey, _descriptor)=>{ 10 | console.log("a(): called"); 11 | }; 12 | } 13 | export class B { 14 | method() { 15 | console.log("method"); 16 | } 17 | } 18 | _ts_decorate([ 19 | a() 20 | ], B.prototype, "method", null); 21 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/mod.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // Copyright the Browserify authors. MIT License. 3 | /** 4 | * Ported mostly from https://github.com/browserify/path-browserify/ 5 | * This module is browser compatible. 6 | * @module 7 | */ import { isWindows } from "../_util/os.ts"; 8 | import * as _win32 from "./win32.ts"; 9 | import * as _posix from "./posix.ts"; 10 | const path = isWindows ? _win32 : _posix; 11 | export const win32 = _win32; 12 | export const posix = _posix; 13 | export const { basename, delimiter, dirname, extname, format, fromFileUrl, isAbsolute, join, normalize, parse, relative, resolve, sep, toFileUrl, toNamespacedPath } = path; 14 | export * from "./common.ts"; 15 | export { SEP, SEP_PATTERN } from "./separator.ts"; 16 | export * from "./_interface.ts"; 17 | export * from "./glob.ts"; 18 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/mod.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // Copyright the Browserify authors. MIT License. 3 | /** 4 | * Ported mostly from https://github.com/browserify/path-browserify/ 5 | * This module is browser compatible. 6 | * @module 7 | */ import { isWindows } from "../_util/os.ts"; 8 | import * as _win32 from "./win32.ts"; 9 | import * as _posix from "./posix.ts"; 10 | const path = isWindows ? _win32 : _posix; 11 | export const win32 = _win32; 12 | export const posix = _posix; 13 | export const { basename, delimiter, dirname, extname, format, fromFileUrl, isAbsolute, join, normalize, parse, relative, resolve, sep, toFileUrl, toNamespacedPath } = path; 14 | export * from "./common.ts"; 15 | export { SEP, SEP_PATTERN } from "./separator.ts"; 16 | export * from "./_interface.ts"; 17 | export * from "./glob.ts"; 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # deno_emit 2 | 3 | [![deno emit](https://jsr.io/badges/@deno/emit)](https://jsr.io/@deno/emit) 4 | 5 | > [!WARNING] 6 | > `deno emit` is deprecated and not recommended anymore. See 7 | > [this issue](https://github.com/denoland/deno_emit/issues/200) for better 8 | > alternatives. 9 | 10 | Transpile and bundle JavaScript and TypeScript in Deno and Deno Deploy. 11 | 12 | > This is an unstable module, where the API is likely to change over time. 13 | 14 | ## JS API 15 | 16 | See [js/README.md](js/README.md). 17 | 18 | --- 19 | 20 | Copyright 2018-2024 the Deno authors. All rights reserved. MIT License. 21 | 22 | [Build Status - Cirrus]: https://github.com/denoland/deno_emit/workflows/ci/badge.svg?branch=main&event=push 23 | [Build status]: https://github.com/denoland/deno_emit/actions 24 | [Twitter badge]: https://twitter.com/intent/follow?screen_name=deno_land 25 | [Twitter handle]: https://img.shields.io/twitter/follow/deno_land.svg?style=social&label=Follow 26 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/ts_decorators/transpile/local/ts_decorators.ts: -------------------------------------------------------------------------------- 1 | function _ts_decorate(decorators, target, key, desc) { 2 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 3 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 4 | else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 5 | return c > 3 && r && Object.defineProperty(target, key, r), r; 6 | } 7 | import { B } from "./subdir/more_decorators.ts"; 8 | function Decorator() { 9 | return function(target, propertyKey, descriptor) { 10 | const originalFn = descriptor.value; 11 | descriptor.value = async function(...args) { 12 | return await originalFn.apply(this, args); 13 | }; 14 | return descriptor; 15 | }; 16 | } 17 | class SomeClass { 18 | async test() {} 19 | } 20 | _ts_decorate([ 21 | Decorator() 22 | ], SomeClass.prototype, "test", null); 23 | new SomeClass().test(); 24 | new B().method(); 25 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | releaseKind: 7 | description: "Kind of release" 8 | default: "minor" 9 | type: choice 10 | options: 11 | - patch 12 | - minor 13 | required: true 14 | 15 | jobs: 16 | rust: 17 | name: release 18 | runs-on: ubuntu-latest 19 | timeout-minutes: 30 20 | 21 | steps: 22 | - name: Clone repository 23 | uses: actions/checkout@v4 24 | with: 25 | token: ${{ secrets.DENOBOT_PAT }} 26 | 27 | - uses: denoland/setup-deno@v2 28 | - uses: dsherret/rust-toolchain-file@v1 29 | 30 | - name: Tag and release 31 | env: 32 | GITHUB_TOKEN: ${{ secrets.DENOBOT_PAT }} 33 | GH_WORKFLOW_ACTOR: ${{ github.actor }} 34 | run: | 35 | git config user.email "denobot@users.noreply.github.com" 36 | git config user.name "denobot" 37 | deno run -A https://raw.githubusercontent.com/denoland/automation/0.14.1/tasks/publish_release.ts --${{github.event.inputs.releaseKind}} deno_emit 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2024 the Deno authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /js/README.md: -------------------------------------------------------------------------------- 1 | # emit 2 | 3 | [![deno emit](https://jsr.io/badges/@deno/emit)](https://jsr.io/@deno/emit) 4 | 5 | Transpile and bundle JavaScript and TypeScript in Deno and Deno Deploy. 6 | 7 | > This is an unstable module, where the API is likely to change over time. 8 | 9 | ## Transpiling 10 | 11 | Take individual modules that are JavaScript or TypeScript and emit them in a 12 | transpiled fashion. An example of taking some TypeScript and transpiling to 13 | JavaScript: 14 | 15 | ```ts 16 | import { transpile } from "jsr:@deno/emit"; 17 | 18 | const url = new URL("./testdata/mod.ts", import.meta.url); 19 | const result = await transpile(url); 20 | 21 | const code = result.get(url.href); 22 | console.log(code?.includes("export default function hello()")); 23 | ``` 24 | 25 | ## Bundle 26 | 27 | Take a root module and all its dependencies and emit a single JavaScript bundle. 28 | This is similar to the functionality provided by `deno bundle` on the Deno 29 | command line. An example: 30 | 31 | ```ts 32 | import { bundle } from "jsr:@deno/emit"; 33 | const result = await bundle( 34 | new URL("https://deno.land/std@0.140.0/examples/chat/server.ts"), 35 | ); 36 | 37 | const { code } = result; 38 | console.log(code); 39 | ``` 40 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/common.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | import { SEP } from "./separator.ts"; 4 | /** Determines the common path from a set of paths, using an optional separator, 5 | * which defaults to the OS default separator. 6 | * 7 | * ```ts 8 | * import { common } from "https://deno.land/std@$STD_VERSION/path/mod.ts"; 9 | * const p = common([ 10 | * "./deno/std/path/mod.ts", 11 | * "./deno/std/fs/mod.ts", 12 | * ]); 13 | * console.log(p); // "./deno/std/" 14 | * ``` 15 | */ export function common(paths, sep = SEP) { 16 | const [first = "", ...remaining] = paths; 17 | if (first === "" || remaining.length === 0) { 18 | return first.substring(0, first.lastIndexOf(sep) + 1); 19 | } 20 | const parts = first.split(sep); 21 | let endOfPrefix = parts.length; 22 | for (const path of remaining){ 23 | const compare = path.split(sep); 24 | for(let i = 0; i < endOfPrefix; i++){ 25 | if (compare[i] !== parts[i]) { 26 | endOfPrefix = i; 27 | } 28 | } 29 | if (endOfPrefix === 0) { 30 | return ""; 31 | } 32 | } 33 | const prefix = parts.slice(0, endOfPrefix).join(sep); 34 | return prefix.endsWith(sep) ? prefix : `${prefix}${sep}`; 35 | } 36 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/common.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | import { SEP } from "./separator.ts"; 4 | /** Determines the common path from a set of paths, using an optional separator, 5 | * which defaults to the OS default separator. 6 | * 7 | * ```ts 8 | * import { common } from "https://deno.land/std@$STD_VERSION/path/mod.ts"; 9 | * const p = common([ 10 | * "./deno/std/path/mod.ts", 11 | * "./deno/std/fs/mod.ts", 12 | * ]); 13 | * console.log(p); // "./deno/std/" 14 | * ``` 15 | */ export function common(paths, sep = SEP) { 16 | const [first = "", ...remaining] = paths; 17 | if (first === "" || remaining.length === 0) { 18 | return first.substring(0, first.lastIndexOf(sep) + 1); 19 | } 20 | const parts = first.split(sep); 21 | let endOfPrefix = parts.length; 22 | for (const path of remaining){ 23 | const compare = path.split(sep); 24 | for(let i = 0; i < endOfPrefix; i++){ 25 | if (compare[i] !== parts[i]) { 26 | endOfPrefix = i; 27 | } 28 | } 29 | if (endOfPrefix === 0) { 30 | return ""; 31 | } 32 | } 33 | const prefix = parts.slice(0, endOfPrefix).join(sep); 34 | return prefix.endsWith(sep) ? prefix : `${prefix}${sep}`; 35 | } 36 | -------------------------------------------------------------------------------- /rs-lib/src/bundle_hook.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. 2 | 3 | use anyhow::Result; 4 | use deno_ast::swc::ast; 5 | use deno_ast::swc::bundler::Hook; 6 | use deno_ast::swc::bundler::ModuleRecord; 7 | use deno_ast::swc::common::Span; 8 | 9 | /// This contains the logic for Deno to rewrite the `import.meta` when bundling. 10 | pub struct BundleHook; 11 | 12 | impl Hook for BundleHook { 13 | fn get_import_meta_props( 14 | &self, 15 | span: Span, 16 | module_record: &ModuleRecord, 17 | ) -> Result> { 18 | Ok(vec![ 19 | ast::KeyValueProp { 20 | key: ast::PropName::Ident(ast::IdentName::new("url".into(), span)), 21 | value: Box::new(ast::Expr::Lit(ast::Lit::Str(ast::Str { 22 | span, 23 | value: module_record.file_name.to_string().into(), 24 | raw: None, 25 | }))), 26 | }, 27 | ast::KeyValueProp { 28 | key: ast::PropName::Ident(ast::IdentName::new("main".into(), span)), 29 | value: Box::new(if module_record.is_entry { 30 | ast::Expr::Member(ast::MemberExpr { 31 | span, 32 | obj: Box::new(ast::Expr::MetaProp(ast::MetaPropExpr { 33 | span, 34 | kind: ast::MetaPropKind::ImportMeta, 35 | })), 36 | prop: ast::MemberProp::Ident(ast::IdentName::new( 37 | "main".into(), 38 | span, 39 | )), 40 | }) 41 | } else { 42 | ast::Expr::Lit(ast::Lit::Bool(ast::Bool { span, value: false })) 43 | }), 44 | }, 45 | ]) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/equals.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | /** Check whether binary arrays are equal to each other using 8-bit comparisons. 4 | * @private 5 | * @param a first array to check equality 6 | * @param b second array to check equality 7 | */ export function equalsNaive(a, b) { 8 | if (a.length !== b.length) return false; 9 | for(let i = 0; i < b.length; i++){ 10 | if (a[i] !== b[i]) return false; 11 | } 12 | return true; 13 | } 14 | /** Check whether binary arrays are equal to each other using 32-bit comparisons. 15 | * @private 16 | * @param a first array to check equality 17 | * @param b second array to check equality 18 | */ export function equalsSimd(a, b) { 19 | if (a.length !== b.length) return false; 20 | const len = a.length; 21 | const compressable = Math.floor(len / 4); 22 | const compressedA = new Uint32Array(a.buffer, 0, compressable); 23 | const compressedB = new Uint32Array(b.buffer, 0, compressable); 24 | for(let i = compressable * 4; i < len; i++){ 25 | if (a[i] !== b[i]) return false; 26 | } 27 | for(let i = 0; i < compressedA.length; i++){ 28 | if (compressedA[i] !== compressedB[i]) return false; 29 | } 30 | return true; 31 | } 32 | /** Check whether binary arrays are equal to each other. 33 | * @param a first array to check equality 34 | * @param b second array to check equality 35 | */ export function equals(a, b) { 36 | if (a.length < 1000) return equalsNaive(a, b); 37 | return equalsSimd(a, b); 38 | } 39 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/equals.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | /** Check whether binary arrays are equal to each other using 8-bit comparisons. 4 | * @private 5 | * @param a first array to check equality 6 | * @param b second array to check equality 7 | */ export function equalsNaive(a, b) { 8 | if (a.length !== b.length) return false; 9 | for(let i = 0; i < b.length; i++){ 10 | if (a[i] !== b[i]) return false; 11 | } 12 | return true; 13 | } 14 | /** Check whether binary arrays are equal to each other using 32-bit comparisons. 15 | * @private 16 | * @param a first array to check equality 17 | * @param b second array to check equality 18 | */ export function equalsSimd(a, b) { 19 | if (a.length !== b.length) return false; 20 | const len = a.length; 21 | const compressable = Math.floor(len / 4); 22 | const compressedA = new Uint32Array(a.buffer, 0, compressable); 23 | const compressedB = new Uint32Array(b.buffer, 0, compressable); 24 | for(let i = compressable * 4; i < len; i++){ 25 | if (a[i] !== b[i]) return false; 26 | } 27 | for(let i = 0; i < compressedA.length; i++){ 28 | if (compressedA[i] !== compressedB[i]) return false; 29 | } 30 | return true; 31 | } 32 | /** Check whether binary arrays are equal to each other. 33 | * @param a first array to check equality 34 | * @param b second array to check equality 35 | */ export function equals(a, b) { 36 | if (a.length < 1000) return equalsNaive(a, b); 37 | return equalsSimd(a, b); 38 | } 39 | -------------------------------------------------------------------------------- /js/_utils.ts: -------------------------------------------------------------------------------- 1 | import { isAbsolute, resolve, toFileUrl } from "@std/path"; 2 | 3 | /** 4 | * Resolves a location to its canonical URL object. 5 | * @description 6 | * The JS API is pretty liberal in what it accepts as a file location. 7 | * It can be a URL or a path. The URL can be a URL object or a string, and can 8 | * locate a local file or a remote file. The path can be relative or absolute, 9 | * and can be represented as a POSIX path or a Win32 path, depending on the 10 | * system. 11 | * The Rust API, on the other hand, always expects well-formed URLs, and nothing 12 | * else. 13 | * @param location a URL object, a URL string, an absolute file path or a 14 | * relative file path 15 | * @returns a URL object that matches the location 16 | */ 17 | export function locationToUrl(location: URL | string): URL { 18 | if (location instanceof URL) { 19 | // We don't return it directly to ensure that the caller can then safely 20 | // mutate without affecting the original. 21 | return new URL(location); 22 | } 23 | // We attempt to build a URL from the location; if it succeeds, it's great! 24 | // If it does not, we assume that it was probably a file path instead. 25 | try { 26 | // Absolute file paths on Windows can be successfully parsed as URLs, so we 27 | // exclude that case first. 28 | if (!isAbsolute(location)) { 29 | return new URL(location); 30 | } 31 | } catch (error) { 32 | // Rethrowing errors that have nothing to do with failing to parse the URL. 33 | if ( 34 | !(error instanceof TypeError && 35 | error.message.startsWith("Invalid URL")) 36 | ) { 37 | throw error; 38 | } 39 | } 40 | return toFileUrl(resolve(location)); 41 | } 42 | -------------------------------------------------------------------------------- /tests/jsx_test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | resolveFixture, 3 | testTranspile, 4 | testTranspileAndBundle, 5 | } from "./utils.ts"; 6 | 7 | Deno.test({ 8 | name: "jsx default", 9 | fn: testTranspileAndBundle( 10 | resolveFixture("jsx/main.tsx"), 11 | ), 12 | }); 13 | 14 | Deno.test({ 15 | name: "jsx type react", 16 | fn: testTranspileAndBundle( 17 | resolveFixture("jsx/main.tsx"), 18 | { 19 | compilerOptions: { 20 | jsx: "react", 21 | }, 22 | }, 23 | ), 24 | }); 25 | 26 | Deno.test({ 27 | name: "jsx type react-native", 28 | fn: testTranspileAndBundle( 29 | resolveFixture("jsx/main.tsx"), 30 | { 31 | compilerOptions: { 32 | jsx: "react-native", 33 | }, 34 | }, 35 | ), 36 | }); 37 | 38 | Deno.test({ 39 | name: "jsx type precompile", 40 | fn: testTranspile( 41 | resolveFixture("jsx/main.tsx"), 42 | { 43 | compilerOptions: { 44 | jsx: "precompile", 45 | jsxImportSource: "jsx-precompile", 46 | }, 47 | }, 48 | ), 49 | }); 50 | 51 | Deno.test({ 52 | name: "jsx type preserve", 53 | fn: testTranspileAndBundle( 54 | resolveFixture("jsx/main.tsx"), 55 | { 56 | compilerOptions: { 57 | jsx: "preserve", 58 | }, 59 | }, 60 | ), 61 | }); 62 | 63 | Deno.test({ 64 | name: "jsx type react-jsx", 65 | fn: testTranspile( 66 | resolveFixture("jsx/main.tsx"), 67 | { 68 | compilerOptions: { 69 | jsx: "react-jsx", 70 | }, 71 | }, 72 | ), 73 | }); 74 | 75 | Deno.test({ 76 | name: "jsx type react-jsx with custom import source", 77 | fn: testTranspile( 78 | resolveFixture("jsx/main.tsx"), 79 | { 80 | compilerOptions: { 81 | jsx: "react-jsx", 82 | jsxImportSource: "example", 83 | }, 84 | }, 85 | ), 86 | }); 87 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/ts_decorators/bundle.js: -------------------------------------------------------------------------------- 1 | function _ts_decorate(decorators, target, key, desc) { 2 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 3 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 4 | else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 5 | return c > 3 && r && Object.defineProperty(target, key, r), r; 6 | } 7 | function a() { 8 | console.log("a(): evaluated"); 9 | return (_target, _propertyKey, _descriptor)=>{ 10 | console.log("a(): called"); 11 | }; 12 | } 13 | class B { 14 | method() { 15 | console.log("method"); 16 | } 17 | } 18 | _ts_decorate([ 19 | a() 20 | ], B.prototype, "method", null); 21 | function _ts_decorate1(decorators, target, key, desc) { 22 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 23 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 24 | else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 25 | return c > 3 && r && Object.defineProperty(target, key, r), r; 26 | } 27 | function Decorator() { 28 | return function(target, propertyKey, descriptor) { 29 | const originalFn = descriptor.value; 30 | descriptor.value = async function(...args) { 31 | return await originalFn.apply(this, args); 32 | }; 33 | return descriptor; 34 | }; 35 | } 36 | class SomeClass { 37 | async test() {} 38 | } 39 | _ts_decorate1([ 40 | Decorator() 41 | ], SomeClass.prototype, "test", null); 42 | new SomeClass().test(); 43 | new B().method(); 44 | -------------------------------------------------------------------------------- /js/emit.generated.d.ts: -------------------------------------------------------------------------------- 1 | // deno-lint-ignore-file 2 | // deno-fmt-ignore-file 3 | 4 | export interface InstantiateResult { 5 | instance: WebAssembly.Instance; 6 | exports: { 7 | bundle: typeof bundle; 8 | transpile: typeof transpile 9 | }; 10 | } 11 | 12 | /** Gets if the Wasm module has been instantiated. */ 13 | export function isInstantiated(): boolean; 14 | 15 | /** Options for instantiating a Wasm instance. */ 16 | export interface InstantiateOptions { 17 | /** Optional url to the Wasm file to instantiate. */ 18 | url?: URL; 19 | /** Callback to decompress the raw Wasm file bytes before instantiating. */ 20 | decompress?: (bytes: Uint8Array) => Uint8Array; 21 | } 22 | 23 | /** Instantiates an instance of the Wasm module returning its functions. 24 | * @remarks It is safe to call this multiple times and once successfully 25 | * loaded it will always return a reference to the same object. */ 26 | export function instantiate(opts?: InstantiateOptions): Promise; 27 | 28 | /** Instantiates an instance of the Wasm module along with its exports. 29 | * @remarks It is safe to call this multiple times and once successfully 30 | * loaded it will always return a reference to the same object. */ 31 | export function instantiateWithInstance(opts?: InstantiateOptions): Promise; 32 | 33 | /** 34 | * @param {string} root 35 | * @param {Function} load 36 | * @param {string | undefined} maybe_bundle_type 37 | * @param {any} maybe_import_map 38 | * @param {any} maybe_compiler_options 39 | * @param {boolean} minify 40 | * @returns {Promise} 41 | */ 42 | export function bundle(root: string, load: Function, maybe_bundle_type: string | undefined, maybe_import_map: any, maybe_compiler_options: any, minify: boolean): Promise; 43 | /** 44 | * @param {string} root 45 | * @param {Function} load 46 | * @param {any} maybe_import_map 47 | * @param {any} maybe_compiler_options 48 | * @returns {Promise} 49 | */ 50 | export function transpile(root: string, load: Function, maybe_import_map: any, maybe_compiler_options: any): Promise; 51 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "https://deno.land/std@0.140.0/_util/assert.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/_util/assert.ts", 3 | "https://deno.land/std@0.140.0/_util/os.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/_util/os.ts", 4 | "https://deno.land/std@0.140.0/bytes/bytes_list.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/bytes_list.ts", 5 | "https://deno.land/std@0.140.0/bytes/equals.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/equals.ts", 6 | "https://deno.land/std@0.140.0/bytes/mod.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/mod.ts", 7 | "https://deno.land/std@0.140.0/examples/chat/server.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/examples/chat/server.ts", 8 | "https://deno.land/std@0.140.0/io/buffer.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/io/buffer.ts", 9 | "https://deno.land/std@0.140.0/path/_constants.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_constants.ts", 10 | "https://deno.land/std@0.140.0/path/_interface.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_interface.ts", 11 | "https://deno.land/std@0.140.0/path/_util.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_util.ts", 12 | "https://deno.land/std@0.140.0/path/common.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/common.ts", 13 | "https://deno.land/std@0.140.0/path/glob.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/glob.ts", 14 | "https://deno.land/std@0.140.0/path/mod.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/mod.ts", 15 | "https://deno.land/std@0.140.0/path/posix.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/posix.ts", 16 | "https://deno.land/std@0.140.0/path/separator.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/separator.ts", 17 | "https://deno.land/std@0.140.0/path/win32.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/win32.ts", 18 | "https://deno.land/std@0.140.0/streams/conversion.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/streams/conversion.ts" 19 | } 20 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "https://deno.land/std@0.140.0/_util/assert.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/_util/assert.ts", 3 | "https://deno.land/std@0.140.0/_util/os.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/_util/os.ts", 4 | "https://deno.land/std@0.140.0/bytes/bytes_list.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/bytes_list.ts", 5 | "https://deno.land/std@0.140.0/bytes/equals.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/equals.ts", 6 | "https://deno.land/std@0.140.0/bytes/mod.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/mod.ts", 7 | "https://deno.land/std@0.140.0/examples/chat/server.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/examples/chat/server.ts", 8 | "https://deno.land/std@0.140.0/io/buffer.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/io/buffer.ts", 9 | "https://deno.land/std@0.140.0/path/_constants.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_constants.ts", 10 | "https://deno.land/std@0.140.0/path/_interface.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_interface.ts", 11 | "https://deno.land/std@0.140.0/path/_util.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_util.ts", 12 | "https://deno.land/std@0.140.0/path/common.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/common.ts", 13 | "https://deno.land/std@0.140.0/path/glob.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/glob.ts", 14 | "https://deno.land/std@0.140.0/path/mod.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/mod.ts", 15 | "https://deno.land/std@0.140.0/path/posix.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/posix.ts", 16 | "https://deno.land/std@0.140.0/path/separator.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/separator.ts", 17 | "https://deno.land/std@0.140.0/path/win32.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/win32.ts", 18 | "https://deno.land/std@0.140.0/streams/conversion.ts": "remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/streams/conversion.ts" 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | rust: 7 | name: deno_emit-${{ matrix.os }} 8 | if: | 9 | github.event_name == 'push' || 10 | !startsWith(github.event.pull_request.head.label, 'denoland:') 11 | runs-on: ${{ matrix.os }} 12 | timeout-minutes: 30 13 | strategy: 14 | matrix: 15 | os: [macOS-latest, ubuntu-latest, windows-latest] 16 | 17 | env: 18 | CARGO_INCREMENTAL: 0 19 | GH_ACTIONS: 1 20 | RUST_BACKTRACE: full 21 | RUSTFLAGS: -D warnings 22 | 23 | permissions: 24 | contents: read 25 | id-token: write 26 | 27 | steps: 28 | - name: Clone repository 29 | uses: actions/checkout@v4 30 | 31 | - name: Install rust 32 | uses: dsherret/rust-toolchain-file@v1 33 | 34 | - uses: Swatinem/rust-cache@v2 35 | with: 36 | save-if: ${{ github.ref == 'refs/heads/main' }} 37 | 38 | - name: Install up Deno 39 | uses: denoland/setup-deno@v2 40 | 41 | - name: Format 42 | if: contains(matrix.os, 'ubuntu') 43 | run: | 44 | cargo fmt -- --check 45 | deno fmt --check 46 | 47 | - name: Lint 48 | if: contains(matrix.os, 'ubuntu') 49 | run: | 50 | cargo clippy --locked --release --all-features --all-targets -- -D clippy::all 51 | deno lint 52 | 53 | - name: Build 54 | run: deno task build 55 | 56 | - name: Test 57 | run: | 58 | cargo test --locked --release --all-features --all-targets 59 | deno task test 60 | 61 | - name: Cargo publish 62 | if: | 63 | contains(matrix.os, 'ubuntu') && 64 | github.repository == 'denoland/deno_emit' && 65 | startsWith(github.ref, 'refs/tags/') 66 | env: 67 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 68 | run: | 69 | cargo publish -p deno_emit 70 | 71 | - name: Publish to JSR 72 | if: contains(matrix.os, 'ubuntu') 73 | run: cd js && deno run -A jsr:@david/publish-on-tag@0.1.3 74 | -------------------------------------------------------------------------------- /rs-lib/src/text.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. 2 | 3 | const BOM_CHAR: char = '\u{FEFF}'; 4 | 5 | /// Strips the byte order mark from the provided text if it exists. 6 | pub fn strip_bom(text: &str) -> &str { 7 | if text.starts_with(BOM_CHAR) { 8 | &text[BOM_CHAR.len_utf8()..] 9 | } else { 10 | text 11 | } 12 | } 13 | 14 | pub fn transform_json_source(source: &str) -> String { 15 | // Make sure to trim all redundant training newlines, 16 | // and escape all reserved characters per JSON RFC, 17 | // https://www.rfc-editor.org/rfc/rfc8259 18 | let escaped = escape8259::escape(source.trim_end()); 19 | format!(r#"export default JSON.parse("{escaped}");"#) 20 | } 21 | 22 | #[cfg(test)] 23 | mod test { 24 | use super::*; 25 | 26 | #[test] 27 | fn strip_bom_with_bom() { 28 | let text = format!("{BOM_CHAR}text"); 29 | assert_eq!(strip_bom(&text), "text"); 30 | } 31 | 32 | #[test] 33 | fn strip_bom_without_bom() { 34 | let text = "text"; 35 | assert_eq!(strip_bom(text), "text"); 36 | } 37 | 38 | #[test] 39 | fn transform_json_source_simple() { 40 | let text = r#"{"foo": "bar"}"#; 41 | assert_eq!( 42 | transform_json_source(text), 43 | r#"export default JSON.parse("{\"foo\": \"bar\"}");"# 44 | ); 45 | } 46 | 47 | #[test] 48 | fn transform_json_source_escape_newline() { 49 | let text = r#"{"foo": "bar\nbaz"}"#; 50 | assert_eq!( 51 | transform_json_source(text), 52 | r#"export default JSON.parse("{\"foo\": \"bar\\nbaz\"}");"# 53 | ); 54 | } 55 | 56 | #[test] 57 | fn transform_json_source_escape_quotes() { 58 | let text = r#"{"foo": "bar \"baz\" 'qux' `quaz`"}"#; 59 | assert_eq!( 60 | transform_json_source(text), 61 | r#"export default JSON.parse("{\"foo\": \"bar \\\"baz\\\" 'qux' `quaz`\"}");"# 62 | ); 63 | } 64 | 65 | #[test] 66 | fn transform_json_source_not_escape_string_interpolation() { 67 | let text = r#"{"foo": "bar ${baz}"}"#; 68 | assert_eq!( 69 | transform_json_source(text), 70 | r#"export default JSON.parse("{\"foo\": \"bar ${baz}\"}");"# 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/bundle_test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. 2 | import { 3 | assertEquals, 4 | assertStringIncludes, 5 | } from "https://deno.land/std@0.182.0/testing/asserts.ts"; 6 | import { resolveFixture, runModule, testBundle } from "./utils.ts"; 7 | 8 | Deno.test({ 9 | name: "json import", 10 | fn: testBundle( 11 | resolveFixture("json_import.ts"), 12 | undefined, 13 | async ({ outputFileUrl }) => { 14 | const output = await runModule(outputFileUrl); 15 | assertStringIncludes(output, "with space"); 16 | }, 17 | ), 18 | }); 19 | 20 | Deno.test({ 21 | name: "json import escape", 22 | fn: testBundle( 23 | resolveFixture("json_import_escape.ts"), 24 | undefined, 25 | async ({ outputFileUrl, result }) => { 26 | const output = await runModule(outputFileUrl); 27 | assertStringIncludes( 28 | output, 29 | "a value with newline\n, \"double quotes\", 'single quotes', ${jsInterpolation} and `string literal`", 30 | ); 31 | 32 | // This is done on purpose, as `String.raw` still performs a string interpolation, 33 | // and we want a literal value as is, without any modifications. 34 | // We should not need to escape $, { nor ` as they are JSON-safe characters. 35 | const jsInterpolation = "${jsInterpolation} and `string literal`"; 36 | assertStringIncludes( 37 | result.code, 38 | String 39 | .raw`const __default = JSON.parse("\"a value with newline\\n, \\\"double quotes\\\", 'single quotes', ${jsInterpolation}\"");`, 40 | ); 41 | }, 42 | ), 43 | }); 44 | 45 | Deno.test({ 46 | name: "minified json import", 47 | fn: testBundle( 48 | resolveFixture("json_import.ts"), 49 | { minify: true }, 50 | async ({ outputFileUrl }) => { 51 | const output = await runModule(outputFileUrl); 52 | assertStringIncludes(output, "with space"); 53 | }, 54 | ), 55 | }); 56 | 57 | Deno.test({ 58 | name: "circular", 59 | fn: testBundle( 60 | resolveFixture("circular1.ts"), 61 | undefined, 62 | async ({ outputFileUrl }) => { 63 | const output = await runModule(outputFileUrl); 64 | assertEquals(output, "f2\nf1\n"); 65 | }, 66 | ), 67 | }); 68 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_constants.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // Copyright the Browserify authors. MIT License. 3 | // Ported from https://github.com/browserify/path-browserify/ 4 | // This module is browser compatible. 5 | // Alphabet chars. 6 | export const CHAR_UPPERCASE_A = 65; /* A */ 7 | export const CHAR_LOWERCASE_A = 97; /* a */ 8 | export const CHAR_UPPERCASE_Z = 90; /* Z */ 9 | export const CHAR_LOWERCASE_Z = 122; /* z */ 10 | // Non-alphabetic chars. 11 | export const CHAR_DOT = 46; /* . */ 12 | export const CHAR_FORWARD_SLASH = 47; /* / */ 13 | export const CHAR_BACKWARD_SLASH = 92; /* \ */ 14 | export const CHAR_VERTICAL_LINE = 124; /* | */ 15 | export const CHAR_COLON = 58; /* : */ 16 | export const CHAR_QUESTION_MARK = 63; /* ? */ 17 | export const CHAR_UNDERSCORE = 95; /* _ */ 18 | export const CHAR_LINE_FEED = 10; /* \n */ 19 | export const CHAR_CARRIAGE_RETURN = 13; /* \r */ 20 | export const CHAR_TAB = 9; /* \t */ 21 | export const CHAR_FORM_FEED = 12; /* \f */ 22 | export const CHAR_EXCLAMATION_MARK = 33; /* ! */ 23 | export const CHAR_HASH = 35; /* # */ 24 | export const CHAR_SPACE = 32; /* */ 25 | export const CHAR_NO_BREAK_SPACE = 160; /* \u00A0 */ 26 | export const CHAR_ZERO_WIDTH_NOBREAK_SPACE = 65279; /* \uFEFF */ 27 | export const CHAR_LEFT_SQUARE_BRACKET = 91; /* [ */ 28 | export const CHAR_RIGHT_SQUARE_BRACKET = 93; /* ] */ 29 | export const CHAR_LEFT_ANGLE_BRACKET = 60; /* < */ 30 | export const CHAR_RIGHT_ANGLE_BRACKET = 62; /* > */ 31 | export const CHAR_LEFT_CURLY_BRACKET = 123; /* { */ 32 | export const CHAR_RIGHT_CURLY_BRACKET = 125; /* } */ 33 | export const CHAR_HYPHEN_MINUS = 45; /* - */ 34 | export const CHAR_PLUS = 43; /* + */ 35 | export const CHAR_DOUBLE_QUOTE = 34; /* " */ 36 | export const CHAR_SINGLE_QUOTE = 39; /* ' */ 37 | export const CHAR_PERCENT = 37; /* % */ 38 | export const CHAR_SEMICOLON = 59; /* ; */ 39 | export const CHAR_CIRCUMFLEX_ACCENT = 94; /* ^ */ 40 | export const CHAR_GRAVE_ACCENT = 96; /* ` */ 41 | export const CHAR_AT = 64; /* @ */ 42 | export const CHAR_AMPERSAND = 38; /* & */ 43 | export const CHAR_EQUAL = 61; /* = */ 44 | // Digits 45 | export const CHAR_0 = 48; /* 0 */ 46 | export const CHAR_9 = 57; /* 9 */ 47 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_constants.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // Copyright the Browserify authors. MIT License. 3 | // Ported from https://github.com/browserify/path-browserify/ 4 | // This module is browser compatible. 5 | // Alphabet chars. 6 | export const CHAR_UPPERCASE_A = 65; /* A */ 7 | export const CHAR_LOWERCASE_A = 97; /* a */ 8 | export const CHAR_UPPERCASE_Z = 90; /* Z */ 9 | export const CHAR_LOWERCASE_Z = 122; /* z */ 10 | // Non-alphabetic chars. 11 | export const CHAR_DOT = 46; /* . */ 12 | export const CHAR_FORWARD_SLASH = 47; /* / */ 13 | export const CHAR_BACKWARD_SLASH = 92; /* \ */ 14 | export const CHAR_VERTICAL_LINE = 124; /* | */ 15 | export const CHAR_COLON = 58; /* : */ 16 | export const CHAR_QUESTION_MARK = 63; /* ? */ 17 | export const CHAR_UNDERSCORE = 95; /* _ */ 18 | export const CHAR_LINE_FEED = 10; /* \n */ 19 | export const CHAR_CARRIAGE_RETURN = 13; /* \r */ 20 | export const CHAR_TAB = 9; /* \t */ 21 | export const CHAR_FORM_FEED = 12; /* \f */ 22 | export const CHAR_EXCLAMATION_MARK = 33; /* ! */ 23 | export const CHAR_HASH = 35; /* # */ 24 | export const CHAR_SPACE = 32; /* */ 25 | export const CHAR_NO_BREAK_SPACE = 160; /* \u00A0 */ 26 | export const CHAR_ZERO_WIDTH_NOBREAK_SPACE = 65279; /* \uFEFF */ 27 | export const CHAR_LEFT_SQUARE_BRACKET = 91; /* [ */ 28 | export const CHAR_RIGHT_SQUARE_BRACKET = 93; /* ] */ 29 | export const CHAR_LEFT_ANGLE_BRACKET = 60; /* < */ 30 | export const CHAR_RIGHT_ANGLE_BRACKET = 62; /* > */ 31 | export const CHAR_LEFT_CURLY_BRACKET = 123; /* { */ 32 | export const CHAR_RIGHT_CURLY_BRACKET = 125; /* } */ 33 | export const CHAR_HYPHEN_MINUS = 45; /* - */ 34 | export const CHAR_PLUS = 43; /* + */ 35 | export const CHAR_DOUBLE_QUOTE = 34; /* " */ 36 | export const CHAR_SINGLE_QUOTE = 39; /* ' */ 37 | export const CHAR_PERCENT = 37; /* % */ 38 | export const CHAR_SEMICOLON = 59; /* ; */ 39 | export const CHAR_CIRCUMFLEX_ACCENT = 94; /* ^ */ 40 | export const CHAR_GRAVE_ACCENT = 96; /* ` */ 41 | export const CHAR_AT = 64; /* @ */ 42 | export const CHAR_AMPERSAND = 38; /* & */ 43 | export const CHAR_EQUAL = 61; /* = */ 44 | // Digits 45 | export const CHAR_0 = 48; /* 0 */ 46 | export const CHAR_9 = 57; /* 9 */ 47 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/examples/chat/server.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | import { fromFileUrl } from "../../path/mod.ts"; 3 | import { readableStreamFromReader } from "../../streams/conversion.ts"; 4 | const clients = new Map(); 5 | let clientId = 0; 6 | function dispatch(msg) { 7 | for (const client of clients.values()){ 8 | client.send(msg); 9 | } 10 | } 11 | function wsHandler(ws) { 12 | const id = ++clientId; 13 | clients.set(id, ws); 14 | ws.onopen = ()=>{ 15 | dispatch(`Connected: [${id}]`); 16 | }; 17 | ws.onmessage = (e)=>{ 18 | console.log(`msg:${id}`, e.data); 19 | dispatch(`[${id}]: ${e.data}`); 20 | }; 21 | ws.onclose = ()=>{ 22 | clients.delete(id); 23 | dispatch(`Closed: [${id}]`); 24 | }; 25 | } 26 | async function requestHandler(req) { 27 | const pathname = new URL(req.request.url).pathname; 28 | if (req.request.method === "GET" && pathname === "/") { 29 | //Serve with hack 30 | const u = new URL("./index.html", import.meta.url); 31 | if (u.protocol.startsWith("http")) { 32 | // server launched by deno run http(s)://.../server.ts, 33 | fetch(u.href).then(async (resp)=>{ 34 | const body = new Uint8Array(await resp.arrayBuffer()); 35 | req.respondWith(new Response(body, { 36 | status: resp.status, 37 | headers: { 38 | "content-type": "text/html" 39 | } 40 | })); 41 | }); 42 | } else { 43 | // server launched by deno run ./server.ts 44 | const file = await Deno.open(fromFileUrl(u)); 45 | req.respondWith(new Response(readableStreamFromReader(file), { 46 | status: 200, 47 | headers: { 48 | "content-type": "text/html" 49 | } 50 | })); 51 | } 52 | } else if (req.request.method === "GET" && pathname === "/favicon.ico") { 53 | req.respondWith(Response.redirect("https://deno.land/favicon.ico", 302)); 54 | } else if (req.request.method === "GET" && pathname === "/ws") { 55 | const { socket, response } = Deno.upgradeWebSocket(req.request); 56 | wsHandler(socket); 57 | req.respondWith(response); 58 | } 59 | } 60 | const server = Deno.listen({ 61 | port: 8080 62 | }); 63 | console.log("chat server starting on :8080...."); 64 | for await (const conn of server){ 65 | (async ()=>{ 66 | const httpConn = Deno.serveHttp(conn); 67 | for await (const requestEvent of httpConn){ 68 | requestHandler(requestEvent); 69 | } 70 | })(); 71 | } 72 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/examples/chat/server.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | import { fromFileUrl } from "../../path/mod.ts"; 3 | import { readableStreamFromReader } from "../../streams/conversion.ts"; 4 | const clients = new Map(); 5 | let clientId = 0; 6 | function dispatch(msg) { 7 | for (const client of clients.values()){ 8 | client.send(msg); 9 | } 10 | } 11 | function wsHandler(ws) { 12 | const id = ++clientId; 13 | clients.set(id, ws); 14 | ws.onopen = ()=>{ 15 | dispatch(`Connected: [${id}]`); 16 | }; 17 | ws.onmessage = (e)=>{ 18 | console.log(`msg:${id}`, e.data); 19 | dispatch(`[${id}]: ${e.data}`); 20 | }; 21 | ws.onclose = ()=>{ 22 | clients.delete(id); 23 | dispatch(`Closed: [${id}]`); 24 | }; 25 | } 26 | async function requestHandler(req) { 27 | const pathname = new URL(req.request.url).pathname; 28 | if (req.request.method === "GET" && pathname === "/") { 29 | //Serve with hack 30 | const u = new URL("./index.html", import.meta.url); 31 | if (u.protocol.startsWith("http")) { 32 | // server launched by deno run http(s)://.../server.ts, 33 | fetch(u.href).then(async (resp)=>{ 34 | const body = new Uint8Array(await resp.arrayBuffer()); 35 | req.respondWith(new Response(body, { 36 | status: resp.status, 37 | headers: { 38 | "content-type": "text/html" 39 | } 40 | })); 41 | }); 42 | } else { 43 | // server launched by deno run ./server.ts 44 | const file = await Deno.open(fromFileUrl(u)); 45 | req.respondWith(new Response(readableStreamFromReader(file), { 46 | status: 200, 47 | headers: { 48 | "content-type": "text/html" 49 | } 50 | })); 51 | } 52 | } else if (req.request.method === "GET" && pathname === "/favicon.ico") { 53 | req.respondWith(Response.redirect("https://deno.land/favicon.ico", 302)); 54 | } else if (req.request.method === "GET" && pathname === "/ws") { 55 | const { socket, response } = Deno.upgradeWebSocket(req.request); 56 | wsHandler(socket); 57 | req.respondWith(response); 58 | } 59 | } 60 | const server = Deno.listen({ 61 | port: 8080 62 | }); 63 | console.log("chat server starting on :8080...."); 64 | for await (const conn of server){ 65 | (async ()=>{ 66 | const httpConn = Deno.serveHttp(conn); 67 | for await (const requestEvent of httpConn){ 68 | requestHandler(requestEvent); 69 | } 70 | })(); 71 | } 72 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_util.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // Copyright the Browserify authors. MIT License. 3 | // Ported from https://github.com/browserify/path-browserify/ 4 | // This module is browser compatible. 5 | import { CHAR_BACKWARD_SLASH, CHAR_DOT, CHAR_FORWARD_SLASH, CHAR_LOWERCASE_A, CHAR_LOWERCASE_Z, CHAR_UPPERCASE_A, CHAR_UPPERCASE_Z } from "./_constants.ts"; 6 | export function assertPath(path) { 7 | if (typeof path !== "string") { 8 | throw new TypeError(`Path must be a string. Received ${JSON.stringify(path)}`); 9 | } 10 | } 11 | export function isPosixPathSeparator(code) { 12 | return code === CHAR_FORWARD_SLASH; 13 | } 14 | export function isPathSeparator(code) { 15 | return isPosixPathSeparator(code) || code === CHAR_BACKWARD_SLASH; 16 | } 17 | export function isWindowsDeviceRoot(code) { 18 | return code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z || code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z; 19 | } 20 | // Resolves . and .. elements in a path with directory names 21 | export function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { 22 | let res = ""; 23 | let lastSegmentLength = 0; 24 | let lastSlash = -1; 25 | let dots = 0; 26 | let code; 27 | for(let i = 0, len = path.length; i <= len; ++i){ 28 | if (i < len) code = path.charCodeAt(i); 29 | else if (isPathSeparator(code)) break; 30 | else code = CHAR_FORWARD_SLASH; 31 | if (isPathSeparator(code)) { 32 | if (lastSlash === i - 1 || dots === 1) { 33 | // NOOP 34 | } else if (lastSlash !== i - 1 && dots === 2) { 35 | if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== CHAR_DOT || res.charCodeAt(res.length - 2) !== CHAR_DOT) { 36 | if (res.length > 2) { 37 | const lastSlashIndex = res.lastIndexOf(separator); 38 | if (lastSlashIndex === -1) { 39 | res = ""; 40 | lastSegmentLength = 0; 41 | } else { 42 | res = res.slice(0, lastSlashIndex); 43 | lastSegmentLength = res.length - 1 - res.lastIndexOf(separator); 44 | } 45 | lastSlash = i; 46 | dots = 0; 47 | continue; 48 | } else if (res.length === 2 || res.length === 1) { 49 | res = ""; 50 | lastSegmentLength = 0; 51 | lastSlash = i; 52 | dots = 0; 53 | continue; 54 | } 55 | } 56 | if (allowAboveRoot) { 57 | if (res.length > 0) res += `${separator}..`; 58 | else res = ".."; 59 | lastSegmentLength = 2; 60 | } 61 | } else { 62 | if (res.length > 0) res += separator + path.slice(lastSlash + 1, i); 63 | else res = path.slice(lastSlash + 1, i); 64 | lastSegmentLength = i - lastSlash - 1; 65 | } 66 | lastSlash = i; 67 | dots = 0; 68 | } else if (code === CHAR_DOT && dots !== -1) { 69 | ++dots; 70 | } else { 71 | dots = -1; 72 | } 73 | } 74 | return res; 75 | } 76 | export function _format(sep, pathObject) { 77 | const dir = pathObject.dir || pathObject.root; 78 | const base = pathObject.base || (pathObject.name || "") + (pathObject.ext || ""); 79 | if (!dir) return base; 80 | if (dir === pathObject.root) return dir + base; 81 | return dir + sep + base; 82 | } 83 | const WHITESPACE_ENCODINGS = { 84 | "\u0009": "%09", 85 | "\u000A": "%0A", 86 | "\u000B": "%0B", 87 | "\u000C": "%0C", 88 | "\u000D": "%0D", 89 | "\u0020": "%20" 90 | }; 91 | export function encodeWhitespace(string) { 92 | return string.replaceAll(/[\s]/g, (c)=>{ 93 | return WHITESPACE_ENCODINGS[c] ?? c; 94 | }); 95 | } 96 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/_util.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // Copyright the Browserify authors. MIT License. 3 | // Ported from https://github.com/browserify/path-browserify/ 4 | // This module is browser compatible. 5 | import { CHAR_BACKWARD_SLASH, CHAR_DOT, CHAR_FORWARD_SLASH, CHAR_LOWERCASE_A, CHAR_LOWERCASE_Z, CHAR_UPPERCASE_A, CHAR_UPPERCASE_Z } from "./_constants.ts"; 6 | export function assertPath(path) { 7 | if (typeof path !== "string") { 8 | throw new TypeError(`Path must be a string. Received ${JSON.stringify(path)}`); 9 | } 10 | } 11 | export function isPosixPathSeparator(code) { 12 | return code === CHAR_FORWARD_SLASH; 13 | } 14 | export function isPathSeparator(code) { 15 | return isPosixPathSeparator(code) || code === CHAR_BACKWARD_SLASH; 16 | } 17 | export function isWindowsDeviceRoot(code) { 18 | return code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z || code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z; 19 | } 20 | // Resolves . and .. elements in a path with directory names 21 | export function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { 22 | let res = ""; 23 | let lastSegmentLength = 0; 24 | let lastSlash = -1; 25 | let dots = 0; 26 | let code; 27 | for(let i = 0, len = path.length; i <= len; ++i){ 28 | if (i < len) code = path.charCodeAt(i); 29 | else if (isPathSeparator(code)) break; 30 | else code = CHAR_FORWARD_SLASH; 31 | if (isPathSeparator(code)) { 32 | if (lastSlash === i - 1 || dots === 1) { 33 | // NOOP 34 | } else if (lastSlash !== i - 1 && dots === 2) { 35 | if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== CHAR_DOT || res.charCodeAt(res.length - 2) !== CHAR_DOT) { 36 | if (res.length > 2) { 37 | const lastSlashIndex = res.lastIndexOf(separator); 38 | if (lastSlashIndex === -1) { 39 | res = ""; 40 | lastSegmentLength = 0; 41 | } else { 42 | res = res.slice(0, lastSlashIndex); 43 | lastSegmentLength = res.length - 1 - res.lastIndexOf(separator); 44 | } 45 | lastSlash = i; 46 | dots = 0; 47 | continue; 48 | } else if (res.length === 2 || res.length === 1) { 49 | res = ""; 50 | lastSegmentLength = 0; 51 | lastSlash = i; 52 | dots = 0; 53 | continue; 54 | } 55 | } 56 | if (allowAboveRoot) { 57 | if (res.length > 0) res += `${separator}..`; 58 | else res = ".."; 59 | lastSegmentLength = 2; 60 | } 61 | } else { 62 | if (res.length > 0) res += separator + path.slice(lastSlash + 1, i); 63 | else res = path.slice(lastSlash + 1, i); 64 | lastSegmentLength = i - lastSlash - 1; 65 | } 66 | lastSlash = i; 67 | dots = 0; 68 | } else if (code === CHAR_DOT && dots !== -1) { 69 | ++dots; 70 | } else { 71 | dots = -1; 72 | } 73 | } 74 | return res; 75 | } 76 | export function _format(sep, pathObject) { 77 | const dir = pathObject.dir || pathObject.root; 78 | const base = pathObject.base || (pathObject.name || "") + (pathObject.ext || ""); 79 | if (!dir) return base; 80 | if (dir === pathObject.root) return dir + base; 81 | return dir + sep + base; 82 | } 83 | const WHITESPACE_ENCODINGS = { 84 | "\u0009": "%09", 85 | "\u000A": "%0A", 86 | "\u000B": "%0B", 87 | "\u000C": "%0C", 88 | "\u000D": "%0D", 89 | "\u0020": "%20" 90 | }; 91 | export function encodeWhitespace(string) { 92 | return string.replaceAll(/[\s]/g, (c)=>{ 93 | return WHITESPACE_ENCODINGS[c] ?? c; 94 | }); 95 | } 96 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/bytes_list.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | /** 4 | * An abstraction of multiple Uint8Arrays 5 | */ export class BytesList { 6 | len = 0; 7 | chunks = []; 8 | constructor(){} 9 | /** 10 | * Total size of bytes 11 | */ size() { 12 | return this.len; 13 | } 14 | /** 15 | * Push bytes with given offset infos 16 | */ add(value, start = 0, end = value.byteLength) { 17 | if (value.byteLength === 0 || end - start === 0) { 18 | return; 19 | } 20 | checkRange(start, end, value.byteLength); 21 | this.chunks.push({ 22 | value, 23 | end, 24 | start, 25 | offset: this.len 26 | }); 27 | this.len += end - start; 28 | } 29 | /** 30 | * Drop head `n` bytes. 31 | */ shift(n) { 32 | if (n === 0) { 33 | return; 34 | } 35 | if (this.len <= n) { 36 | this.chunks = []; 37 | this.len = 0; 38 | return; 39 | } 40 | const idx = this.getChunkIndex(n); 41 | this.chunks.splice(0, idx); 42 | const [chunk] = this.chunks; 43 | if (chunk) { 44 | const diff = n - chunk.offset; 45 | chunk.start += diff; 46 | } 47 | let offset = 0; 48 | for (const chunk of this.chunks){ 49 | chunk.offset = offset; 50 | offset += chunk.end - chunk.start; 51 | } 52 | this.len = offset; 53 | } 54 | /** 55 | * Find chunk index in which `pos` locates by binary-search 56 | * returns -1 if out of range 57 | */ getChunkIndex(pos) { 58 | let max = this.chunks.length; 59 | let min = 0; 60 | while(true){ 61 | const i = min + Math.floor((max - min) / 2); 62 | if (i < 0 || this.chunks.length <= i) { 63 | return -1; 64 | } 65 | const { offset, start, end } = this.chunks[i]; 66 | const len = end - start; 67 | if (offset <= pos && pos < offset + len) { 68 | return i; 69 | } else if (offset + len <= pos) { 70 | min = i + 1; 71 | } else { 72 | max = i - 1; 73 | } 74 | } 75 | } 76 | /** 77 | * Get indexed byte from chunks 78 | */ get(i) { 79 | if (i < 0 || this.len <= i) { 80 | throw new Error("out of range"); 81 | } 82 | const idx = this.getChunkIndex(i); 83 | const { value, offset, start } = this.chunks[idx]; 84 | return value[start + i - offset]; 85 | } 86 | /** 87 | * Iterator of bytes from given position 88 | */ *iterator(start = 0) { 89 | const startIdx = this.getChunkIndex(start); 90 | if (startIdx < 0) return; 91 | const first = this.chunks[startIdx]; 92 | let firstOffset = start - first.offset; 93 | for(let i = startIdx; i < this.chunks.length; i++){ 94 | const chunk = this.chunks[i]; 95 | for(let j = chunk.start + firstOffset; j < chunk.end; j++){ 96 | yield chunk.value[j]; 97 | } 98 | firstOffset = 0; 99 | } 100 | } 101 | /** 102 | * Returns subset of bytes copied 103 | */ slice(start, end = this.len) { 104 | if (end === start) { 105 | return new Uint8Array(); 106 | } 107 | checkRange(start, end, this.len); 108 | const result = new Uint8Array(end - start); 109 | const startIdx = this.getChunkIndex(start); 110 | const endIdx = this.getChunkIndex(end - 1); 111 | let written = 0; 112 | for(let i = startIdx; i < endIdx; i++){ 113 | const chunk = this.chunks[i]; 114 | const len = chunk.end - chunk.start; 115 | result.set(chunk.value.subarray(chunk.start, chunk.end), written); 116 | written += len; 117 | } 118 | const last = this.chunks[endIdx]; 119 | const rest = end - start - written; 120 | result.set(last.value.subarray(last.start, last.start + rest), written); 121 | return result; 122 | } 123 | /** 124 | * Concatenate chunks into single Uint8Array copied. 125 | */ concat() { 126 | const result = new Uint8Array(this.len); 127 | let sum = 0; 128 | for (const { value, start, end } of this.chunks){ 129 | result.set(value.subarray(start, end), sum); 130 | sum += end - start; 131 | } 132 | return result; 133 | } 134 | } 135 | function checkRange(start, end, len) { 136 | if (start < 0 || len < start || end < 0 || len < end || end < start) { 137 | throw new Error("invalid range"); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/bytes_list.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | /** 4 | * An abstraction of multiple Uint8Arrays 5 | */ export class BytesList { 6 | len = 0; 7 | chunks = []; 8 | constructor(){} 9 | /** 10 | * Total size of bytes 11 | */ size() { 12 | return this.len; 13 | } 14 | /** 15 | * Push bytes with given offset infos 16 | */ add(value, start = 0, end = value.byteLength) { 17 | if (value.byteLength === 0 || end - start === 0) { 18 | return; 19 | } 20 | checkRange(start, end, value.byteLength); 21 | this.chunks.push({ 22 | value, 23 | end, 24 | start, 25 | offset: this.len 26 | }); 27 | this.len += end - start; 28 | } 29 | /** 30 | * Drop head `n` bytes. 31 | */ shift(n) { 32 | if (n === 0) { 33 | return; 34 | } 35 | if (this.len <= n) { 36 | this.chunks = []; 37 | this.len = 0; 38 | return; 39 | } 40 | const idx = this.getChunkIndex(n); 41 | this.chunks.splice(0, idx); 42 | const [chunk] = this.chunks; 43 | if (chunk) { 44 | const diff = n - chunk.offset; 45 | chunk.start += diff; 46 | } 47 | let offset = 0; 48 | for (const chunk of this.chunks){ 49 | chunk.offset = offset; 50 | offset += chunk.end - chunk.start; 51 | } 52 | this.len = offset; 53 | } 54 | /** 55 | * Find chunk index in which `pos` locates by binary-search 56 | * returns -1 if out of range 57 | */ getChunkIndex(pos) { 58 | let max = this.chunks.length; 59 | let min = 0; 60 | while(true){ 61 | const i = min + Math.floor((max - min) / 2); 62 | if (i < 0 || this.chunks.length <= i) { 63 | return -1; 64 | } 65 | const { offset, start, end } = this.chunks[i]; 66 | const len = end - start; 67 | if (offset <= pos && pos < offset + len) { 68 | return i; 69 | } else if (offset + len <= pos) { 70 | min = i + 1; 71 | } else { 72 | max = i - 1; 73 | } 74 | } 75 | } 76 | /** 77 | * Get indexed byte from chunks 78 | */ get(i) { 79 | if (i < 0 || this.len <= i) { 80 | throw new Error("out of range"); 81 | } 82 | const idx = this.getChunkIndex(i); 83 | const { value, offset, start } = this.chunks[idx]; 84 | return value[start + i - offset]; 85 | } 86 | /** 87 | * Iterator of bytes from given position 88 | */ *iterator(start = 0) { 89 | const startIdx = this.getChunkIndex(start); 90 | if (startIdx < 0) return; 91 | const first = this.chunks[startIdx]; 92 | let firstOffset = start - first.offset; 93 | for(let i = startIdx; i < this.chunks.length; i++){ 94 | const chunk = this.chunks[i]; 95 | for(let j = chunk.start + firstOffset; j < chunk.end; j++){ 96 | yield chunk.value[j]; 97 | } 98 | firstOffset = 0; 99 | } 100 | } 101 | /** 102 | * Returns subset of bytes copied 103 | */ slice(start, end = this.len) { 104 | if (end === start) { 105 | return new Uint8Array(); 106 | } 107 | checkRange(start, end, this.len); 108 | const result = new Uint8Array(end - start); 109 | const startIdx = this.getChunkIndex(start); 110 | const endIdx = this.getChunkIndex(end - 1); 111 | let written = 0; 112 | for(let i = startIdx; i < endIdx; i++){ 113 | const chunk = this.chunks[i]; 114 | const len = chunk.end - chunk.start; 115 | result.set(chunk.value.subarray(chunk.start, chunk.end), written); 116 | written += len; 117 | } 118 | const last = this.chunks[endIdx]; 119 | const rest = end - start - written; 120 | result.set(last.value.subarray(last.start, last.start + rest), written); 121 | return result; 122 | } 123 | /** 124 | * Concatenate chunks into single Uint8Array copied. 125 | */ concat() { 126 | const result = new Uint8Array(this.len); 127 | let sum = 0; 128 | for (const { value, start, end } of this.chunks){ 129 | result.set(value.subarray(start, end), sum); 130 | sum += end - start; 131 | } 132 | return result; 133 | } 134 | } 135 | function checkRange(start, end, len) { 136 | if (start < 0 || len < start || end < 0 || len < end || end < start) { 137 | throw new Error("invalid range"); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /tests/import_map_test.ts: -------------------------------------------------------------------------------- 1 | import { join, toFileUrl } from "https://deno.land/std@0.182.0/path/mod.ts"; 2 | import { assertEquals } from "https://deno.land/std@0.182.0/testing/asserts.ts"; 3 | import { resolveFixture, runModule, testTranspileAndBundle } from "./utils.ts"; 4 | 5 | Deno.test({ 6 | name: "embedded", 7 | fn: testTranspileAndBundle( 8 | resolveFixture("import_map/main.ts"), 9 | { 10 | importMap: { 11 | imports: { 12 | "foo": "./testdata/subdir/foo.ts", 13 | }, 14 | }, 15 | }, 16 | async ({ outputFileUrl, denoConfigPath, functionCalled }) => { 17 | if (functionCalled === "bundle") { 18 | const output = await runModule(outputFileUrl, denoConfigPath); 19 | assertEquals(output, "foo\n"); 20 | } 21 | }, 22 | ), 23 | }); 24 | 25 | Deno.test({ 26 | name: "embedded with specific base url", 27 | fn: testTranspileAndBundle( 28 | resolveFixture("import_map/main.ts"), 29 | { 30 | importMap: { 31 | baseUrl: toFileUrl(resolveFixture(".")), 32 | imports: { 33 | "foo": "./subdir/foo.ts", 34 | }, 35 | }, 36 | }, 37 | async ({ outputFileUrl, denoConfigPath, functionCalled }) => { 38 | if (functionCalled === "bundle") { 39 | const output = await runModule(outputFileUrl, denoConfigPath); 40 | assertEquals(output, "foo\n"); 41 | } 42 | }, 43 | ), 44 | }); 45 | 46 | Deno.test({ 47 | name: "local file set as relative path", 48 | fn: testTranspileAndBundle( 49 | resolveFixture("import_map/main.ts"), 50 | { 51 | importMap: join("testdata", "import_map", "import_map.json"), 52 | }, 53 | async ({ outputFileUrl, denoConfigPath, functionCalled }) => { 54 | if (functionCalled === "bundle") { 55 | const output = await runModule(outputFileUrl, denoConfigPath); 56 | assertEquals(output, "foo\n"); 57 | } 58 | }, 59 | ), 60 | }); 61 | 62 | Deno.test({ 63 | name: "local file set as absolute path", 64 | fn: testTranspileAndBundle( 65 | resolveFixture("import_map/main.ts"), 66 | { 67 | importMap: resolveFixture("import_map/import_map.json"), 68 | }, 69 | async ({ outputFileUrl, denoConfigPath, functionCalled }) => { 70 | if (functionCalled === "bundle") { 71 | const output = await runModule(outputFileUrl, denoConfigPath); 72 | assertEquals(output, "foo\n"); 73 | } 74 | }, 75 | ), 76 | }); 77 | 78 | Deno.test({ 79 | name: "local file set as file url string", 80 | fn: testTranspileAndBundle( 81 | resolveFixture("import_map/main.ts"), 82 | { 83 | importMap: toFileUrl(resolveFixture("import_map/import_map.json")) 84 | .toString(), 85 | }, 86 | async ({ outputFileUrl, denoConfigPath, functionCalled }) => { 87 | if (functionCalled === "bundle") { 88 | const output = await runModule(outputFileUrl, denoConfigPath); 89 | assertEquals(output, "foo\n"); 90 | } 91 | }, 92 | ), 93 | }); 94 | 95 | Deno.test({ 96 | name: "local file set as file url object", 97 | fn: testTranspileAndBundle( 98 | resolveFixture("import_map/main.ts"), 99 | { 100 | importMap: toFileUrl(resolveFixture("import_map/import_map.json")), 101 | }, 102 | async ({ outputFileUrl, denoConfigPath, functionCalled }) => { 103 | if (functionCalled === "bundle") { 104 | const output = await runModule(outputFileUrl, denoConfigPath); 105 | assertEquals(output, "foo\n"); 106 | } 107 | }, 108 | ), 109 | }); 110 | 111 | Deno.test({ 112 | name: "remote url string", 113 | fn: testTranspileAndBundle( 114 | resolveFixture("import_map/main.ts"), 115 | { 116 | importMap: "http://localhost:8000/import_map/import_map.json", 117 | }, 118 | async ({ outputFileUrl, denoConfigPath, functionCalled }) => { 119 | if (functionCalled === "bundle") { 120 | const output = await runModule(outputFileUrl, denoConfigPath); 121 | assertEquals(output, "foo\n"); 122 | } 123 | }, 124 | ), 125 | // TODO: Run a local server to be able to test this. 126 | ignore: true, 127 | }); 128 | 129 | Deno.test({ 130 | name: "remote url object", 131 | fn: testTranspileAndBundle( 132 | resolveFixture("import_map/main.ts"), 133 | { 134 | importMap: new URL("http://localhost:8000/import_map/import_map.json"), 135 | }, 136 | async ({ outputFileUrl, denoConfigPath, functionCalled }) => { 137 | if (functionCalled === "bundle") { 138 | const output = await runModule(outputFileUrl, denoConfigPath); 139 | assertEquals(output, "foo\n"); 140 | } 141 | }, 142 | ), 143 | // TODO: Run a local server to be able to test this. 144 | ignore: true, 145 | }); 146 | 147 | Deno.test({ 148 | name: "empty import map", 149 | fn: testTranspileAndBundle( 150 | resolveFixture("mod1.ts"), 151 | { importMap: {} }, 152 | ), 153 | }); 154 | -------------------------------------------------------------------------------- /rs-lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. 2 | 3 | #![deny(clippy::print_stderr)] 4 | #![deny(clippy::print_stdout)] 5 | 6 | mod bundle_hook; 7 | mod emit; 8 | mod text; 9 | 10 | use anyhow::Result; 11 | use deno_graph::source::ResolveError; 12 | use deno_graph::BuildOptions; 13 | use deno_graph::CapturingModuleAnalyzer; 14 | use deno_graph::GraphKind; 15 | use deno_graph::ModuleGraph; 16 | use deno_graph::ParsedSourceStore; 17 | use deno_graph::Range; 18 | use import_map::ImportMap; 19 | use import_map::ImportMapOptions; 20 | use std::collections::HashMap; 21 | use url::Url; 22 | 23 | pub use emit::bundle_graph; 24 | pub use emit::BundleEmit; 25 | pub use emit::BundleOptions; 26 | pub use emit::BundleType; 27 | 28 | pub use deno_ast::EmitOptions; 29 | pub use deno_ast::ImportsNotUsedAsValues; 30 | pub use deno_ast::ModuleSpecifier; 31 | pub use deno_ast::SourceMapOption; 32 | pub use deno_ast::TranspileOptions; 33 | pub use deno_graph::source::CacheSetting; 34 | pub use deno_graph::source::LoadFuture; 35 | pub use deno_graph::source::LoadOptions; 36 | pub use deno_graph::source::Loader; 37 | pub use deno_graph::source::LoaderChecksum; 38 | 39 | pub async fn bundle( 40 | root: ModuleSpecifier, 41 | loader: &mut dyn Loader, 42 | maybe_import_map: Option, 43 | options: BundleOptions, 44 | ) -> Result { 45 | let maybe_import_map = get_import_map_from_input(maybe_import_map)?; 46 | let import_map_resolver = ImportMapResolver(maybe_import_map); 47 | let mut graph = ModuleGraph::new(GraphKind::CodeOnly); 48 | graph 49 | .build( 50 | vec![root], 51 | loader, 52 | BuildOptions { 53 | resolver: Some(import_map_resolver.as_resolver()), 54 | ..Default::default() 55 | }, 56 | ) 57 | .await; 58 | 59 | bundle_graph(&graph, options) 60 | } 61 | 62 | pub async fn transpile( 63 | root: ModuleSpecifier, 64 | loader: &mut dyn Loader, 65 | maybe_import_map: Option, 66 | transpile_options: &TranspileOptions, 67 | emit_options: &EmitOptions, 68 | ) -> Result>> { 69 | let analyzer = CapturingModuleAnalyzer::default(); 70 | let maybe_import_map = get_import_map_from_input(maybe_import_map)?; 71 | let import_map_resolver = ImportMapResolver(maybe_import_map); 72 | let mut graph = ModuleGraph::new(GraphKind::CodeOnly); 73 | graph 74 | .build( 75 | vec![root], 76 | loader, 77 | BuildOptions { 78 | module_analyzer: &analyzer, 79 | resolver: Some(import_map_resolver.as_resolver()), 80 | ..Default::default() 81 | }, 82 | ) 83 | .await; 84 | 85 | graph.valid()?; 86 | 87 | let mut map = HashMap::new(); 88 | 89 | for module in graph.modules().filter_map(|m| m.js()) { 90 | if let Some(parsed_source) = 91 | analyzer.remove_parsed_source(&module.specifier) 92 | { 93 | let transpiled_source = parsed_source 94 | .transpile(transpile_options, emit_options)? 95 | .into_source(); 96 | 97 | map.insert(module.specifier.to_string(), transpiled_source.source); 98 | 99 | if let Some(source_map) = transpiled_source.source_map { 100 | map.insert(format!("{}.map", module.specifier.as_str()), source_map); 101 | } 102 | } 103 | } 104 | 105 | Ok(map) 106 | } 107 | 108 | #[derive(Debug)] 109 | pub struct ImportMapInput { 110 | pub base_url: Url, 111 | pub json_string: String, 112 | } 113 | 114 | fn get_import_map_from_input( 115 | maybe_input: Option, 116 | ) -> Result> { 117 | if let Some(input) = maybe_input { 118 | let import_map = import_map::parse_from_json_with_options( 119 | input.base_url, 120 | &input.json_string, 121 | ImportMapOptions { 122 | address_hook: None, 123 | // always do this for simplicity 124 | expand_imports: true, 125 | }, 126 | )? 127 | .import_map; 128 | Ok(Some(import_map)) 129 | } else { 130 | Ok(None) 131 | } 132 | } 133 | 134 | #[derive(Debug)] 135 | struct ImportMapResolver(Option); 136 | 137 | impl ImportMapResolver { 138 | pub fn as_resolver(&self) -> &dyn deno_graph::source::Resolver { 139 | self 140 | } 141 | } 142 | 143 | impl deno_graph::source::Resolver for ImportMapResolver { 144 | fn resolve( 145 | &self, 146 | specifier: &str, 147 | referrer_range: &Range, 148 | _mode: deno_graph::source::ResolutionMode, 149 | ) -> Result { 150 | let maybe_import_map = &self.0; 151 | 152 | let maybe_import_map_err = 153 | match maybe_import_map.as_ref().map(|import_map| { 154 | import_map.resolve(specifier, &referrer_range.specifier) 155 | }) { 156 | Some(Ok(value)) => return Ok(value), 157 | Some(Err(err)) => Some(err), 158 | None => None, 159 | }; 160 | 161 | if let Some(err) = maybe_import_map_err { 162 | Err(ResolveError::Other(err.into())) 163 | } else { 164 | deno_graph::resolve_import(specifier, &referrer_range.specifier) 165 | .map_err(|err| err.into()) 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /tests/common_test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. 2 | import { toFileUrl } from "https://deno.land/std@0.182.0/path/mod.ts"; 3 | import { 4 | assertEquals, 5 | assertRejects, 6 | assertStringIncludes, 7 | } from "https://deno.land/std@0.182.0/testing/asserts.ts"; 8 | import { bundle, transpile } from "../js/mod.ts"; 9 | import { 10 | resolveFixture, 11 | runCode, 12 | runModule, 13 | testTranspileAndBundle, 14 | } from "./utils.ts"; 15 | 16 | // Most of the tests below have been ported and adapted from deno bundle's test 17 | // suite. Some of them are ignored; see the comments for more details. 18 | 19 | Deno.test({ 20 | name: "hello world", 21 | fn: testTranspileAndBundle( 22 | resolveFixture("hello_world.ts"), 23 | undefined, 24 | async ({ outputFileUrl }) => { 25 | const output = await runModule(outputFileUrl); 26 | assertEquals(output, "Hello world!\n"); 27 | }, 28 | ), 29 | }); 30 | 31 | Deno.test({ 32 | name: "hello world relative path", 33 | fn: testTranspileAndBundle("./testdata/hello_world.ts"), 34 | }); 35 | 36 | Deno.test({ 37 | name: "file url as string", 38 | fn: testTranspileAndBundle( 39 | toFileUrl(resolveFixture("hello_world.ts")).toString(), 40 | ), 41 | }); 42 | 43 | Deno.test({ 44 | name: "remote url as string", 45 | fn: testTranspileAndBundle( 46 | "https://deno.land/std@0.140.0/examples/chat/server.ts", 47 | ), 48 | }); 49 | 50 | Deno.test({ 51 | name: "file url as object", 52 | fn: testTranspileAndBundle(toFileUrl(resolveFixture("hello_world.ts"))), 53 | }); 54 | 55 | Deno.test({ 56 | name: "remote url as object", 57 | fn: testTranspileAndBundle( 58 | new URL("https://deno.land/std@0.140.0/examples/chat/server.ts"), 59 | ), 60 | }); 61 | 62 | Deno.test({ 63 | name: "load override", 64 | fn: testTranspileAndBundle(new URL("file:///src.ts"), { 65 | async load(specifier) { 66 | if (specifier !== "file:///src.ts") return undefined; 67 | const content = await Deno.readTextFile(resolveFixture("hello_world.ts")); 68 | return { kind: "module", specifier, content }; 69 | }, 70 | }), 71 | }); 72 | 73 | Deno.test({ 74 | name: "exports", 75 | fn: testTranspileAndBundle( 76 | resolveFixture("mod1.ts"), 77 | undefined, 78 | async ({ outputFileUrl, denoConfigPath }) => { 79 | const output = await runCode( 80 | `import { printHello3 } from "${outputFileUrl}";\n printHello3();`, 81 | denoConfigPath, 82 | ); 83 | assertEquals(output, "Hello\n"); 84 | 85 | // TODO: See with https://github.com/denoland/deno_emit/issues/106 if we 86 | // should also test for the presence of ignore directives. 87 | }, 88 | ), 89 | }); 90 | 91 | Deno.test({ 92 | name: "top level await", 93 | fn: testTranspileAndBundle( 94 | resolveFixture("top_level_await.ts"), 95 | undefined, 96 | async ({ outputFileUrl, denoConfigPath }) => { 97 | const output = await runCode( 98 | `import { tla } from "${outputFileUrl}";\n console.log(tla);`, 99 | denoConfigPath, 100 | ); 101 | assertEquals(output, "Hello\n"); 102 | }, 103 | ), 104 | }); 105 | 106 | Deno.test({ 107 | name: "js", 108 | fn: testTranspileAndBundle( 109 | resolveFixture("js_module.js"), 110 | undefined, 111 | async ({ outputFileUrl, denoConfigPath }) => { 112 | await runModule(outputFileUrl, denoConfigPath); 113 | }, 114 | ), 115 | }); 116 | 117 | Deno.test({ 118 | name: "dynamic import", 119 | fn: testTranspileAndBundle( 120 | resolveFixture("dynamic_import.ts"), 121 | undefined, 122 | async ({ outputFileUrl, denoConfigPath }) => { 123 | const output = await runModule(outputFileUrl, denoConfigPath); 124 | assertEquals(output, "Hello\n"); 125 | }, 126 | ), 127 | // TODO: Determine whether we want to support dynamic imports. If so, we need 128 | // a way to run a local server. 129 | ignore: true, 130 | }); 131 | 132 | Deno.test({ 133 | name: "error with bare import", 134 | async fn(t) { 135 | // TODO: Better error message 136 | await t.step("bundle", async () => { 137 | await assertRejects(() => { 138 | return bundle(resolveFixture("error_with_bare_import.ts")); 139 | }); 140 | }); 141 | await t.step("transpile", async () => { 142 | await assertRejects(() => { 143 | return transpile(resolveFixture("error_with_bare_import.ts")); 144 | }); 145 | }); 146 | }, 147 | }); 148 | 149 | Deno.test({ 150 | name: "jsx import from ts", 151 | fn: testTranspileAndBundle(resolveFixture("jsx_import_from_ts.ts")), 152 | }); 153 | 154 | Deno.test({ 155 | name: "es decorators", 156 | fn: testTranspileAndBundle(resolveFixture("es_decorators.ts")), 157 | }); 158 | 159 | Deno.test({ 160 | name: "ts decorators", 161 | fn: testTranspileAndBundle(resolveFixture("ts_decorators.ts"), { 162 | compilerOptions: { 163 | experimentalDecorators: true, 164 | }, 165 | }), 166 | }); 167 | 168 | Deno.test({ 169 | name: "export specifier with alias", 170 | fn: testTranspileAndBundle(resolveFixture("exports_with_alias.ts")), 171 | }); 172 | 173 | Deno.test({ 174 | name: "preserve shebang", 175 | fn: testTranspileAndBundle( 176 | resolveFixture("shebang.ts"), 177 | undefined, 178 | ({ outputCode }) => { 179 | assertStringIncludes( 180 | outputCode, 181 | "#!/usr/bin/env -S deno run --allow-read\n", 182 | ); 183 | }, 184 | ), 185 | // TODO: Shebangs are not preserved, but they should be. 186 | ignore: true, 187 | }); 188 | 189 | Deno.test({ 190 | name: "external", 191 | fn: testTranspileAndBundle(resolveFixture("external.ts"), { 192 | async load(specifier) { 193 | if (specifier === toFileUrl(resolveFixture("external.ts")).toString()) { 194 | const content = await Deno.readTextFile(resolveFixture("external.ts")); 195 | console.log(content); 196 | return { kind: "module", specifier, content }; 197 | } 198 | return { kind: "external", specifier }; 199 | }, 200 | }), 201 | }); 202 | -------------------------------------------------------------------------------- /tests/source_map_test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | assert, 3 | assertEquals, 4 | assertExists, 5 | assertRejects, 6 | } from "https://deno.land/std@0.182.0/testing/asserts.ts"; 7 | import { toFileUrl } from "https://deno.land/std@0.182.0/path/mod.ts"; 8 | import { bundle, transpile } from "../js/mod.ts"; 9 | import { resolveFixture } from "./utils.ts"; 10 | 11 | type Outcome = 12 | | "inline source maps" 13 | | "external source maps" 14 | | "no source maps" 15 | | "error"; 16 | 17 | interface CompilerOptions { 18 | sourceMap?: boolean; 19 | inlineSourceMap?: boolean; 20 | inlineSources?: boolean; 21 | } 22 | 23 | interface TestCase { 24 | compilerOptions: CompilerOptions | undefined; 25 | outcome: Outcome; 26 | } 27 | 28 | const cases: TestCase[] = [ 29 | { 30 | compilerOptions: undefined, 31 | outcome: "no source maps", 32 | }, 33 | { 34 | compilerOptions: {}, 35 | outcome: "no source maps", 36 | }, 37 | { 38 | compilerOptions: { sourceMap: false }, 39 | outcome: "no source maps", 40 | }, 41 | { 42 | compilerOptions: { inlineSourceMap: false }, 43 | outcome: "no source maps", 44 | }, 45 | { 46 | compilerOptions: { sourceMap: false, inlineSourceMap: false }, 47 | outcome: "no source maps", 48 | }, 49 | { 50 | compilerOptions: { inlineSources: false }, 51 | outcome: "no source maps", 52 | }, 53 | { 54 | compilerOptions: { sourceMap: false, inlineSources: false }, 55 | outcome: "no source maps", 56 | }, 57 | { 58 | compilerOptions: { inlineSourceMap: false, inlineSources: false }, 59 | outcome: "no source maps", 60 | }, 61 | { 62 | compilerOptions: { 63 | sourceMap: false, 64 | inlineSourceMap: false, 65 | inlineSources: false, 66 | }, 67 | outcome: "no source maps", 68 | }, 69 | { 70 | compilerOptions: { inlineSourceMap: true }, 71 | outcome: "inline source maps", 72 | }, 73 | { 74 | compilerOptions: { sourceMap: false, inlineSourceMap: true }, 75 | outcome: "inline source maps", 76 | }, 77 | { 78 | compilerOptions: { inlineSourceMap: true, inlineSources: true }, 79 | outcome: "inline source maps", 80 | }, 81 | { 82 | compilerOptions: { inlineSourceMap: true, inlineSources: false }, 83 | outcome: "inline source maps", 84 | }, 85 | { 86 | compilerOptions: { 87 | sourceMap: false, 88 | inlineSourceMap: true, 89 | inlineSources: true, 90 | }, 91 | outcome: "inline source maps", 92 | }, 93 | { 94 | compilerOptions: { 95 | sourceMap: false, 96 | inlineSourceMap: true, 97 | inlineSources: false, 98 | }, 99 | outcome: "inline source maps", 100 | }, 101 | { 102 | compilerOptions: { sourceMap: true }, 103 | outcome: "external source maps", 104 | }, 105 | { 106 | compilerOptions: { sourceMap: true, inlineSourceMap: false }, 107 | outcome: "external source maps", 108 | }, 109 | { 110 | compilerOptions: { sourceMap: true, inlineSources: true }, 111 | outcome: "external source maps", 112 | }, 113 | { 114 | compilerOptions: { sourceMap: true, inlineSources: false }, 115 | outcome: "external source maps", 116 | }, 117 | { 118 | compilerOptions: { 119 | sourceMap: true, 120 | inlineSourceMap: false, 121 | inlineSources: true, 122 | }, 123 | outcome: "external source maps", 124 | }, 125 | { 126 | compilerOptions: { 127 | sourceMap: true, 128 | inlineSourceMap: false, 129 | inlineSources: false, 130 | }, 131 | outcome: "external source maps", 132 | }, 133 | { 134 | compilerOptions: { sourceMap: true, inlineSourceMap: true }, 135 | outcome: "error", 136 | }, 137 | { 138 | compilerOptions: { inlineSources: true }, 139 | outcome: "error", 140 | }, 141 | { 142 | compilerOptions: { sourceMap: false, inlineSources: true }, 143 | outcome: "error", 144 | }, 145 | { 146 | compilerOptions: { inlineSourceMap: false, inlineSources: true }, 147 | outcome: "error", 148 | }, 149 | { 150 | compilerOptions: { 151 | sourceMap: true, 152 | inlineSourceMap: true, 153 | inlineSources: true, 154 | }, 155 | outcome: "error", 156 | }, 157 | { 158 | compilerOptions: { 159 | sourceMap: true, 160 | inlineSourceMap: true, 161 | inlineSources: false, 162 | }, 163 | outcome: "error", 164 | }, 165 | { 166 | compilerOptions: { 167 | sourceMap: false, 168 | inlineSourceMap: false, 169 | inlineSources: true, 170 | }, 171 | outcome: "error", 172 | }, 173 | ]; 174 | 175 | interface Output { 176 | code: string; 177 | map?: string; 178 | } 179 | 180 | async function testSourceMapBehavior( 181 | t: Deno.TestContext, 182 | fn: (options?: CompilerOptions) => Promise, 183 | ): Promise { 184 | for (const { compilerOptions, outcome } of cases) { 185 | await t.step({ 186 | name: `${ 187 | outcome === "error" ? "errors" : `emits ${outcome}` 188 | } when compilerOptions is set to ${JSON.stringify(compilerOptions)}`, 189 | async fn() { 190 | const run = fn.bind(null, compilerOptions); 191 | 192 | if (outcome === "error") { 193 | await assertRejects(run, "bundle throws an error"); 194 | } else { 195 | const { code, map } = await run(); 196 | 197 | switch (outcome) { 198 | case "inline source maps": 199 | assert( 200 | code.trim().split("\n").at(-1)?.startsWith( 201 | "//# sourceMappingURL=data:application/json;base64,", 202 | ), 203 | "code contains an inline source map", 204 | ); 205 | assertEquals( 206 | map, 207 | undefined, 208 | "bundle does not return a source map", 209 | ); 210 | break; 211 | 212 | case "external source maps": 213 | assertExists(map, "bundle returns a source map"); 214 | break; 215 | 216 | case "no source maps": 217 | assert( 218 | !code.includes( 219 | "//# sourceMappingURL=", 220 | ), 221 | "code does not reference any source maps", 222 | ); 223 | assertEquals( 224 | map, 225 | undefined, 226 | "bundle does not return a source map", 227 | ); 228 | break; 229 | 230 | default: 231 | throw new Error(`Unexpected outcome: ${outcome}`); 232 | } 233 | } 234 | }, 235 | }); 236 | } 237 | } 238 | 239 | Deno.test({ 240 | name: "source maps generation consistent with tsc", 241 | async fn(t) { 242 | await t.step("transpile", async (t) => { 243 | await testSourceMapBehavior(t, async (compilerOptions) => { 244 | const filePath = resolveFixture("hello_world.ts"); 245 | const fileUrl = toFileUrl(filePath).toString(); 246 | const sourceMapUrl = `${fileUrl}.map`; 247 | 248 | const result = await transpile(filePath, { compilerOptions }); 249 | const code = result.get(fileUrl); 250 | assertExists(code); 251 | return { 252 | code, 253 | map: result.get(sourceMapUrl), 254 | }; 255 | }); 256 | }); 257 | 258 | await t.step("bundle", async (t) => { 259 | await testSourceMapBehavior(t, async (compilerOptions) => { 260 | const result = await bundle(resolveFixture("hello_world.ts"), { 261 | compilerOptions, 262 | }); 263 | return result; 264 | }); 265 | }); 266 | }, 267 | }); 268 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/mod.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | /** 4 | * Provides helper functions to manipulate `Uint8Array` byte slices that are not 5 | * included on the `Uint8Array` prototype. 6 | * 7 | * @module 8 | */ /** Returns the index of the first occurrence of the needle array in the source 9 | * array, or -1 if it is not present. 10 | * 11 | * A start index can be specified as the third argument that begins the search 12 | * at that given index. The start index defaults to the start of the array. 13 | * 14 | * The complexity of this function is O(source.lenth * needle.length). 15 | * 16 | * ```ts 17 | * import { indexOfNeedle } from "./mod.ts"; 18 | * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]); 19 | * const needle = new Uint8Array([1, 2]); 20 | * console.log(indexOfNeedle(source, needle)); // 1 21 | * console.log(indexOfNeedle(source, needle, 2)); // 3 22 | * ``` 23 | */ export function indexOfNeedle(source, needle, start = 0) { 24 | if (start >= source.length) { 25 | return -1; 26 | } 27 | if (start < 0) { 28 | start = Math.max(0, source.length + start); 29 | } 30 | const s = needle[0]; 31 | for(let i = start; i < source.length; i++){ 32 | if (source[i] !== s) continue; 33 | const pin = i; 34 | let matched = 1; 35 | let j = i; 36 | while(matched < needle.length){ 37 | j++; 38 | if (source[j] !== needle[j - pin]) { 39 | break; 40 | } 41 | matched++; 42 | } 43 | if (matched === needle.length) { 44 | return pin; 45 | } 46 | } 47 | return -1; 48 | } 49 | /** Returns the index of the last occurrence of the needle array in the source 50 | * array, or -1 if it is not present. 51 | * 52 | * A start index can be specified as the third argument that begins the search 53 | * at that given index. The start index defaults to the end of the array. 54 | * 55 | * The complexity of this function is O(source.lenth * needle.length). 56 | * 57 | * ```ts 58 | * import { lastIndexOfNeedle } from "./mod.ts"; 59 | * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]); 60 | * const needle = new Uint8Array([1, 2]); 61 | * console.log(lastIndexOfNeedle(source, needle)); // 5 62 | * console.log(lastIndexOfNeedle(source, needle, 4)); // 3 63 | * ``` 64 | */ export function lastIndexOfNeedle(source, needle, start = source.length - 1) { 65 | if (start < 0) { 66 | return -1; 67 | } 68 | if (start >= source.length) { 69 | start = source.length - 1; 70 | } 71 | const e = needle[needle.length - 1]; 72 | for(let i = start; i >= 0; i--){ 73 | if (source[i] !== e) continue; 74 | const pin = i; 75 | let matched = 1; 76 | let j = i; 77 | while(matched < needle.length){ 78 | j--; 79 | if (source[j] !== needle[needle.length - 1 - (pin - j)]) { 80 | break; 81 | } 82 | matched++; 83 | } 84 | if (matched === needle.length) { 85 | return pin - needle.length + 1; 86 | } 87 | } 88 | return -1; 89 | } 90 | /** Returns true if the prefix array appears at the start of the source array, 91 | * false otherwise. 92 | * 93 | * The complexity of this function is O(prefix.length). 94 | * 95 | * ```ts 96 | * import { startsWith } from "./mod.ts"; 97 | * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]); 98 | * const prefix = new Uint8Array([0, 1, 2]); 99 | * console.log(startsWith(source, prefix)); // true 100 | * ``` 101 | */ export function startsWith(source, prefix) { 102 | for(let i = 0, max = prefix.length; i < max; i++){ 103 | if (source[i] !== prefix[i]) return false; 104 | } 105 | return true; 106 | } 107 | /** Returns true if the suffix array appears at the end of the source array, 108 | * false otherwise. 109 | * 110 | * The complexity of this function is O(suffix.length). 111 | * 112 | * ```ts 113 | * import { endsWith } from "./mod.ts"; 114 | * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]); 115 | * const suffix = new Uint8Array([1, 2, 3]); 116 | * console.log(endsWith(source, suffix)); // true 117 | * ``` 118 | */ export function endsWith(source, suffix) { 119 | for(let srci = source.length - 1, sfxi = suffix.length - 1; sfxi >= 0; srci--, sfxi--){ 120 | if (source[srci] !== suffix[sfxi]) return false; 121 | } 122 | return true; 123 | } 124 | /** Returns a new Uint8Array composed of `count` repetitions of the `source` 125 | * array. 126 | * 127 | * If `count` is negative, a `RangeError` is thrown. 128 | * 129 | * ```ts 130 | * import { repeat } from "./mod.ts"; 131 | * const source = new Uint8Array([0, 1, 2]); 132 | * console.log(repeat(source, 3)); // [0, 1, 2, 0, 1, 2, 0, 1, 2] 133 | * console.log(repeat(source, 0)); // [] 134 | * console.log(repeat(source, -1)); // RangeError 135 | * ``` 136 | */ export function repeat(source, count) { 137 | if (count === 0) { 138 | return new Uint8Array(); 139 | } 140 | if (count < 0) { 141 | throw new RangeError("bytes: negative repeat count"); 142 | } else if (source.length * count / count !== source.length) { 143 | throw new Error("bytes: repeat count causes overflow"); 144 | } 145 | const int = Math.floor(count); 146 | if (int !== count) { 147 | throw new Error("bytes: repeat count must be an integer"); 148 | } 149 | const nb = new Uint8Array(source.length * count); 150 | let bp = copy(source, nb); 151 | for(; bp < nb.length; bp *= 2){ 152 | copy(nb.slice(0, bp), nb, bp); 153 | } 154 | return nb; 155 | } 156 | /** Concatenate the given arrays into a new Uint8Array. 157 | * 158 | * ```ts 159 | * import { concat } from "./mod.ts"; 160 | * const a = new Uint8Array([0, 1, 2]); 161 | * const b = new Uint8Array([3, 4, 5]); 162 | * console.log(concat(a, b)); // [0, 1, 2, 3, 4, 5] 163 | */ export function concat(...buf) { 164 | let length = 0; 165 | for (const b of buf){ 166 | length += b.length; 167 | } 168 | const output = new Uint8Array(length); 169 | let index = 0; 170 | for (const b of buf){ 171 | output.set(b, index); 172 | index += b.length; 173 | } 174 | return output; 175 | } 176 | /** Returns true if the source array contains the needle array, false otherwise. 177 | * 178 | * A start index can be specified as the third argument that begins the search 179 | * at that given index. The start index defaults to the beginning of the array. 180 | * 181 | * The complexity of this function is O(source.length * needle.length). 182 | * 183 | * ```ts 184 | * import { includesNeedle } from "./mod.ts"; 185 | * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]); 186 | * const needle = new Uint8Array([1, 2]); 187 | * console.log(includesNeedle(source, needle)); // true 188 | * console.log(includesNeedle(source, needle, 6)); // false 189 | * ``` 190 | */ export function includesNeedle(source, needle, start = 0) { 191 | return indexOfNeedle(source, needle, start) !== -1; 192 | } 193 | /** Copy bytes from the `src` array to the `dst` array. Returns the number of 194 | * bytes copied. 195 | * 196 | * If the `src` array is larger than what the `dst` array can hold, only the 197 | * amount of bytes that fit in the `dst` array are copied. 198 | * 199 | * An offset can be specified as the third argument that begins the copy at 200 | * that given index in the `dst` array. The offset defaults to the beginning of 201 | * the array. 202 | * 203 | * ```ts 204 | * import { copy } from "./mod.ts"; 205 | * const src = new Uint8Array([9, 8, 7]); 206 | * const dst = new Uint8Array([0, 1, 2, 3, 4, 5]); 207 | * console.log(copy(src, dst)); // 3 208 | * console.log(dst); // [9, 8, 7, 3, 4, 5] 209 | * ``` 210 | * 211 | * ```ts 212 | * import { copy } from "./mod.ts"; 213 | * const src = new Uint8Array([1, 1, 1, 1]); 214 | * const dst = new Uint8Array([0, 0, 0, 0]); 215 | * console.log(copy(src, dst, 1)); // 3 216 | * console.log(dst); // [0, 1, 1, 1] 217 | * ``` 218 | */ export function copy(src, dst, off = 0) { 219 | off = Math.max(0, Math.min(off, dst.byteLength)); 220 | const dstBytesAvailable = dst.byteLength - off; 221 | if (src.byteLength > dstBytesAvailable) { 222 | src = src.subarray(0, dstBytesAvailable); 223 | } 224 | dst.set(src, off); 225 | return src.byteLength; 226 | } 227 | export { equals } from "./equals.ts"; 228 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/bytes/mod.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | /** 4 | * Provides helper functions to manipulate `Uint8Array` byte slices that are not 5 | * included on the `Uint8Array` prototype. 6 | * 7 | * @module 8 | */ /** Returns the index of the first occurrence of the needle array in the source 9 | * array, or -1 if it is not present. 10 | * 11 | * A start index can be specified as the third argument that begins the search 12 | * at that given index. The start index defaults to the start of the array. 13 | * 14 | * The complexity of this function is O(source.lenth * needle.length). 15 | * 16 | * ```ts 17 | * import { indexOfNeedle } from "./mod.ts"; 18 | * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]); 19 | * const needle = new Uint8Array([1, 2]); 20 | * console.log(indexOfNeedle(source, needle)); // 1 21 | * console.log(indexOfNeedle(source, needle, 2)); // 3 22 | * ``` 23 | */ export function indexOfNeedle(source, needle, start = 0) { 24 | if (start >= source.length) { 25 | return -1; 26 | } 27 | if (start < 0) { 28 | start = Math.max(0, source.length + start); 29 | } 30 | const s = needle[0]; 31 | for(let i = start; i < source.length; i++){ 32 | if (source[i] !== s) continue; 33 | const pin = i; 34 | let matched = 1; 35 | let j = i; 36 | while(matched < needle.length){ 37 | j++; 38 | if (source[j] !== needle[j - pin]) { 39 | break; 40 | } 41 | matched++; 42 | } 43 | if (matched === needle.length) { 44 | return pin; 45 | } 46 | } 47 | return -1; 48 | } 49 | /** Returns the index of the last occurrence of the needle array in the source 50 | * array, or -1 if it is not present. 51 | * 52 | * A start index can be specified as the third argument that begins the search 53 | * at that given index. The start index defaults to the end of the array. 54 | * 55 | * The complexity of this function is O(source.lenth * needle.length). 56 | * 57 | * ```ts 58 | * import { lastIndexOfNeedle } from "./mod.ts"; 59 | * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]); 60 | * const needle = new Uint8Array([1, 2]); 61 | * console.log(lastIndexOfNeedle(source, needle)); // 5 62 | * console.log(lastIndexOfNeedle(source, needle, 4)); // 3 63 | * ``` 64 | */ export function lastIndexOfNeedle(source, needle, start = source.length - 1) { 65 | if (start < 0) { 66 | return -1; 67 | } 68 | if (start >= source.length) { 69 | start = source.length - 1; 70 | } 71 | const e = needle[needle.length - 1]; 72 | for(let i = start; i >= 0; i--){ 73 | if (source[i] !== e) continue; 74 | const pin = i; 75 | let matched = 1; 76 | let j = i; 77 | while(matched < needle.length){ 78 | j--; 79 | if (source[j] !== needle[needle.length - 1 - (pin - j)]) { 80 | break; 81 | } 82 | matched++; 83 | } 84 | if (matched === needle.length) { 85 | return pin - needle.length + 1; 86 | } 87 | } 88 | return -1; 89 | } 90 | /** Returns true if the prefix array appears at the start of the source array, 91 | * false otherwise. 92 | * 93 | * The complexity of this function is O(prefix.length). 94 | * 95 | * ```ts 96 | * import { startsWith } from "./mod.ts"; 97 | * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]); 98 | * const prefix = new Uint8Array([0, 1, 2]); 99 | * console.log(startsWith(source, prefix)); // true 100 | * ``` 101 | */ export function startsWith(source, prefix) { 102 | for(let i = 0, max = prefix.length; i < max; i++){ 103 | if (source[i] !== prefix[i]) return false; 104 | } 105 | return true; 106 | } 107 | /** Returns true if the suffix array appears at the end of the source array, 108 | * false otherwise. 109 | * 110 | * The complexity of this function is O(suffix.length). 111 | * 112 | * ```ts 113 | * import { endsWith } from "./mod.ts"; 114 | * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]); 115 | * const suffix = new Uint8Array([1, 2, 3]); 116 | * console.log(endsWith(source, suffix)); // true 117 | * ``` 118 | */ export function endsWith(source, suffix) { 119 | for(let srci = source.length - 1, sfxi = suffix.length - 1; sfxi >= 0; srci--, sfxi--){ 120 | if (source[srci] !== suffix[sfxi]) return false; 121 | } 122 | return true; 123 | } 124 | /** Returns a new Uint8Array composed of `count` repetitions of the `source` 125 | * array. 126 | * 127 | * If `count` is negative, a `RangeError` is thrown. 128 | * 129 | * ```ts 130 | * import { repeat } from "./mod.ts"; 131 | * const source = new Uint8Array([0, 1, 2]); 132 | * console.log(repeat(source, 3)); // [0, 1, 2, 0, 1, 2, 0, 1, 2] 133 | * console.log(repeat(source, 0)); // [] 134 | * console.log(repeat(source, -1)); // RangeError 135 | * ``` 136 | */ export function repeat(source, count) { 137 | if (count === 0) { 138 | return new Uint8Array(); 139 | } 140 | if (count < 0) { 141 | throw new RangeError("bytes: negative repeat count"); 142 | } else if (source.length * count / count !== source.length) { 143 | throw new Error("bytes: repeat count causes overflow"); 144 | } 145 | const int = Math.floor(count); 146 | if (int !== count) { 147 | throw new Error("bytes: repeat count must be an integer"); 148 | } 149 | const nb = new Uint8Array(source.length * count); 150 | let bp = copy(source, nb); 151 | for(; bp < nb.length; bp *= 2){ 152 | copy(nb.slice(0, bp), nb, bp); 153 | } 154 | return nb; 155 | } 156 | /** Concatenate the given arrays into a new Uint8Array. 157 | * 158 | * ```ts 159 | * import { concat } from "./mod.ts"; 160 | * const a = new Uint8Array([0, 1, 2]); 161 | * const b = new Uint8Array([3, 4, 5]); 162 | * console.log(concat(a, b)); // [0, 1, 2, 3, 4, 5] 163 | */ export function concat(...buf) { 164 | let length = 0; 165 | for (const b of buf){ 166 | length += b.length; 167 | } 168 | const output = new Uint8Array(length); 169 | let index = 0; 170 | for (const b of buf){ 171 | output.set(b, index); 172 | index += b.length; 173 | } 174 | return output; 175 | } 176 | /** Returns true if the source array contains the needle array, false otherwise. 177 | * 178 | * A start index can be specified as the third argument that begins the search 179 | * at that given index. The start index defaults to the beginning of the array. 180 | * 181 | * The complexity of this function is O(source.length * needle.length). 182 | * 183 | * ```ts 184 | * import { includesNeedle } from "./mod.ts"; 185 | * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]); 186 | * const needle = new Uint8Array([1, 2]); 187 | * console.log(includesNeedle(source, needle)); // true 188 | * console.log(includesNeedle(source, needle, 6)); // false 189 | * ``` 190 | */ export function includesNeedle(source, needle, start = 0) { 191 | return indexOfNeedle(source, needle, start) !== -1; 192 | } 193 | /** Copy bytes from the `src` array to the `dst` array. Returns the number of 194 | * bytes copied. 195 | * 196 | * If the `src` array is larger than what the `dst` array can hold, only the 197 | * amount of bytes that fit in the `dst` array are copied. 198 | * 199 | * An offset can be specified as the third argument that begins the copy at 200 | * that given index in the `dst` array. The offset defaults to the beginning of 201 | * the array. 202 | * 203 | * ```ts 204 | * import { copy } from "./mod.ts"; 205 | * const src = new Uint8Array([9, 8, 7]); 206 | * const dst = new Uint8Array([0, 1, 2, 3, 4, 5]); 207 | * console.log(copy(src, dst)); // 3 208 | * console.log(dst); // [9, 8, 7, 3, 4, 5] 209 | * ``` 210 | * 211 | * ```ts 212 | * import { copy } from "./mod.ts"; 213 | * const src = new Uint8Array([1, 1, 1, 1]); 214 | * const dst = new Uint8Array([0, 0, 0, 0]); 215 | * console.log(copy(src, dst, 1)); // 3 216 | * console.log(dst); // [0, 1, 1, 1] 217 | * ``` 218 | */ export function copy(src, dst, off = 0) { 219 | off = Math.max(0, Math.min(off, dst.byteLength)); 220 | const dstBytesAvailable = dst.byteLength - off; 221 | if (src.byteLength > dstBytesAvailable) { 222 | src = src.subarray(0, dstBytesAvailable); 223 | } 224 | dst.set(src, off); 225 | return src.byteLength; 226 | } 227 | export { equals } from "./equals.ts"; 228 | -------------------------------------------------------------------------------- /wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. 2 | 3 | use std::collections::HashMap; 4 | use std::string::FromUtf8Error; 5 | 6 | use anyhow::anyhow; 7 | use deno_emit::BundleOptions; 8 | use deno_emit::BundleType; 9 | use deno_emit::EmitOptions; 10 | use deno_emit::ImportMapInput; 11 | use deno_emit::ImportsNotUsedAsValues; 12 | use deno_emit::LoadFuture; 13 | use deno_emit::LoadOptions; 14 | use deno_emit::Loader; 15 | use deno_emit::ModuleSpecifier; 16 | use deno_emit::SourceMapOption; 17 | use deno_emit::TranspileOptions; 18 | use serde::Serialize; 19 | use url::Url; 20 | use wasm_bindgen::prelude::*; 21 | 22 | /// This is a deserializable structure of the `"compilerOptions"` section of a 23 | /// TypeScript or Deno configuration file which can effect how the emitting is 24 | /// handled, all other options don't impact the output. 25 | #[derive(serde::Deserialize)] 26 | #[serde(default, rename_all = "camelCase")] 27 | #[derive(Debug)] 28 | pub struct CompilerOptions { 29 | pub check_js: bool, 30 | pub experimental_decorators: bool, 31 | pub emit_decorator_metadata: bool, 32 | pub imports_not_used_as_values: String, 33 | pub inline_source_map: bool, 34 | pub inline_sources: bool, 35 | pub jsx: String, 36 | pub jsx_factory: String, 37 | pub jsx_fragment_factory: String, 38 | pub jsx_import_source: Option, 39 | pub source_map: bool, 40 | } 41 | 42 | impl CompilerOptions { 43 | pub fn into_options(self) -> (TranspileOptions, EmitOptions) { 44 | let imports_not_used_as_values = 45 | match self.imports_not_used_as_values.as_str() { 46 | "preserve" => ImportsNotUsedAsValues::Preserve, 47 | "error" => ImportsNotUsedAsValues::Error, 48 | _ => ImportsNotUsedAsValues::Remove, 49 | }; 50 | 51 | // copied from the CLI 52 | let (transform_jsx, jsx_automatic, jsx_development, precompile_jsx) = 53 | match self.jsx.as_str() { 54 | "react" => (true, false, false, false), 55 | "react-jsx" => (true, true, false, false), 56 | "react-jsxdev" => (true, true, true, false), 57 | "precompile" => (false, false, false, true), 58 | _ => (false, false, false, false), 59 | }; 60 | let source_map = if self.inline_source_map { 61 | SourceMapOption::Inline 62 | } else if self.source_map { 63 | SourceMapOption::Separate 64 | } else { 65 | SourceMapOption::None 66 | }; 67 | 68 | ( 69 | TranspileOptions { 70 | use_decorators_proposal: !self.experimental_decorators, 71 | use_ts_decorators: self.experimental_decorators, 72 | emit_metadata: self.emit_decorator_metadata, 73 | imports_not_used_as_values, 74 | jsx_factory: self.jsx_factory, 75 | jsx_fragment_factory: self.jsx_fragment_factory, 76 | transform_jsx, 77 | var_decl_imports: false, 78 | jsx_automatic, 79 | jsx_development, 80 | jsx_import_source: self.jsx_import_source, 81 | precompile_jsx, 82 | precompile_jsx_skip_elements: None, 83 | precompile_jsx_dynamic_props: None, 84 | }, 85 | EmitOptions { 86 | inline_sources: self.inline_sources, 87 | source_map_file: None, 88 | source_map_base: None, 89 | remove_comments: false, 90 | source_map, 91 | }, 92 | ) 93 | } 94 | } 95 | 96 | impl Default for CompilerOptions { 97 | fn default() -> Self { 98 | Self { 99 | experimental_decorators: false, 100 | check_js: false, 101 | emit_decorator_metadata: false, 102 | imports_not_used_as_values: "remove".to_string(), 103 | inline_source_map: false, 104 | inline_sources: false, 105 | jsx: "react".to_string(), 106 | jsx_factory: "React.createElement".to_string(), 107 | jsx_fragment_factory: "React.Fragment".to_string(), 108 | jsx_import_source: None, 109 | source_map: false, 110 | } 111 | } 112 | } 113 | 114 | #[derive(serde::Deserialize, Debug)] 115 | #[serde(rename_all = "camelCase")] 116 | struct ImportMapJsInput { 117 | base_url: String, 118 | json_string: String, 119 | } 120 | 121 | impl TryFrom for ImportMapInput { 122 | type Error = anyhow::Error; 123 | 124 | fn try_from(js_input: ImportMapJsInput) -> anyhow::Result { 125 | Ok(ImportMapInput { 126 | base_url: Url::parse(&js_input.base_url)?, 127 | json_string: js_input.json_string, 128 | }) 129 | } 130 | } 131 | 132 | #[derive(serde::Serialize, Debug)] 133 | pub struct SerializableBundleEmit { 134 | pub code: String, 135 | #[serde(skip_serializing_if = "Option::is_none")] 136 | pub map: Option, 137 | } 138 | 139 | struct JsLoader { 140 | load: js_sys::Function, 141 | } 142 | 143 | impl JsLoader { 144 | pub fn new(load: js_sys::Function) -> Self { 145 | Self { load } 146 | } 147 | } 148 | 149 | impl Loader for JsLoader { 150 | fn load( 151 | &self, 152 | specifier: &ModuleSpecifier, 153 | options: LoadOptions, 154 | ) -> LoadFuture { 155 | #[derive(Serialize)] 156 | #[serde(rename_all = "camelCase")] 157 | struct JsLoadOptions { 158 | pub is_dynamic: bool, 159 | pub cache_setting: &'static str, 160 | pub checksum: Option, 161 | } 162 | 163 | let specifier = specifier.clone(); 164 | let this = JsValue::null(); 165 | let arg0 = JsValue::from(specifier.to_string()); 166 | let arg1 = serde_wasm_bindgen::to_value(&JsLoadOptions { 167 | is_dynamic: options.is_dynamic, 168 | cache_setting: options.cache_setting.as_js_str(), 169 | checksum: options.maybe_checksum.map(|c| c.into_string()), 170 | }) 171 | .unwrap(); 172 | let result = self.load.call2(&this, &arg0, &arg1); 173 | let f = async move { 174 | let response = match result { 175 | Ok(result) => { 176 | wasm_bindgen_futures::JsFuture::from(js_sys::Promise::resolve( 177 | &result, 178 | )) 179 | .await 180 | } 181 | Err(err) => Err(err), 182 | }; 183 | 184 | response 185 | .map(|value| serde_wasm_bindgen::from_value(value).unwrap()) 186 | .map_err(|err| anyhow!("load rejected or errored: {:#?}", err)) 187 | }; 188 | Box::pin(f) 189 | } 190 | } 191 | 192 | #[wasm_bindgen] 193 | pub async fn bundle( 194 | root: String, 195 | load: js_sys::Function, 196 | maybe_bundle_type: Option, 197 | maybe_import_map: JsValue, 198 | maybe_compiler_options: JsValue, 199 | minify: bool, 200 | ) -> Result { 201 | console_error_panic_hook::set_once(); 202 | // todo(dsherret): eliminate all the duplicate `.map_err`s 203 | let compiler_options: CompilerOptions = serde_wasm_bindgen::from_value::< 204 | Option, 205 | >(maybe_compiler_options) 206 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))? 207 | .unwrap_or_default(); 208 | let root = ModuleSpecifier::parse(&root) 209 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))?; 210 | let mut loader = JsLoader::new(load); 211 | let (transpile_options, emit_options) = compiler_options.into_options(); 212 | let bundle_type = match maybe_bundle_type.as_deref() { 213 | Some("module") | None => BundleType::Module, 214 | Some("classic") => BundleType::Classic, 215 | Some(value) => { 216 | return Err(JsValue::from(js_sys::Error::new(&format!( 217 | "Unsupported bundle type \"{value}\"", 218 | )))) 219 | } 220 | }; 221 | let maybe_import_map = serde_wasm_bindgen::from_value::< 222 | Option, 223 | >(maybe_import_map) 224 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))? 225 | .map(|js_input| { 226 | let result: anyhow::Result = js_input.try_into(); 227 | result 228 | }) 229 | .transpose() 230 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))?; 231 | 232 | let result = deno_emit::bundle( 233 | root, 234 | &mut loader, 235 | maybe_import_map, 236 | BundleOptions { 237 | bundle_type, 238 | emit_options, 239 | emit_ignore_directives: false, 240 | transpile_options, 241 | minify, 242 | }, 243 | ) 244 | .await 245 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))?; 246 | 247 | serde_wasm_bindgen::to_value(&SerializableBundleEmit { 248 | code: result.code, 249 | map: result.maybe_map, 250 | }) 251 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err)))) 252 | } 253 | 254 | #[wasm_bindgen] 255 | pub async fn transpile( 256 | root: String, 257 | load: js_sys::Function, 258 | maybe_import_map: JsValue, 259 | maybe_compiler_options: JsValue, 260 | ) -> Result { 261 | console_error_panic_hook::set_once(); 262 | let compiler_options: CompilerOptions = serde_wasm_bindgen::from_value::< 263 | Option, 264 | >(maybe_compiler_options) 265 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))? 266 | .unwrap_or_default(); 267 | let root = ModuleSpecifier::parse(&root) 268 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))?; 269 | let mut loader = JsLoader::new(load); 270 | let (transpile_options, emit_options) = compiler_options.into_options(); 271 | 272 | let maybe_import_map = serde_wasm_bindgen::from_value::< 273 | Option, 274 | >(maybe_import_map) 275 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))? 276 | .map(|js_input| { 277 | let result: anyhow::Result = js_input.try_into(); 278 | result 279 | }) 280 | .transpose() 281 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))?; 282 | 283 | let map = deno_emit::transpile( 284 | root, 285 | &mut loader, 286 | maybe_import_map, 287 | &transpile_options, 288 | &emit_options, 289 | ) 290 | .await 291 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))?; 292 | let map = map 293 | .into_iter() 294 | .map(|(specifier, source)| { 295 | Ok((specifier.to_string(), String::from_utf8(source)?)) 296 | }) 297 | .collect::, FromUtf8Error>>() 298 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err))))?; 299 | 300 | serde_wasm_bindgen::to_value(&map) 301 | .map_err(|err| JsValue::from(js_sys::Error::new(&format!("{:#}", err)))) 302 | } 303 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/es_decorators/transpile/local/subdir/more_decorators.ts: -------------------------------------------------------------------------------- 1 | function applyDecs2203RFactory() { 2 | function createAddInitializerMethod(initializers, decoratorFinishedRef) { 3 | return function addInitializer(initializer) { 4 | assertNotFinished(decoratorFinishedRef, "addInitializer"); 5 | assertCallable(initializer, "An initializer"); 6 | initializers.push(initializer); 7 | }; 8 | } 9 | function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) { 10 | var kindStr; 11 | switch(kind){ 12 | case 1: 13 | kindStr = "accessor"; 14 | break; 15 | case 2: 16 | kindStr = "method"; 17 | break; 18 | case 3: 19 | kindStr = "getter"; 20 | break; 21 | case 4: 22 | kindStr = "setter"; 23 | break; 24 | default: 25 | kindStr = "field"; 26 | } 27 | var ctx = { 28 | kind: kindStr, 29 | name: isPrivate ? "#" + name : name, 30 | static: isStatic, 31 | private: isPrivate, 32 | metadata: metadata 33 | }; 34 | var decoratorFinishedRef = { 35 | v: false 36 | }; 37 | ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef); 38 | var get, set; 39 | if (kind === 0) { 40 | if (isPrivate) { 41 | get = desc.get; 42 | set = desc.set; 43 | } else { 44 | get = function() { 45 | return this[name]; 46 | }; 47 | set = function(v) { 48 | this[name] = v; 49 | }; 50 | } 51 | } else if (kind === 2) { 52 | get = function() { 53 | return desc.value; 54 | }; 55 | } else { 56 | if (kind === 1 || kind === 3) { 57 | get = function() { 58 | return desc.get.call(this); 59 | }; 60 | } 61 | if (kind === 1 || kind === 4) { 62 | set = function(v) { 63 | desc.set.call(this, v); 64 | }; 65 | } 66 | } 67 | ctx.access = get && set ? { 68 | get: get, 69 | set: set 70 | } : get ? { 71 | get: get 72 | } : { 73 | set: set 74 | }; 75 | try { 76 | return dec(value, ctx); 77 | } finally{ 78 | decoratorFinishedRef.v = true; 79 | } 80 | } 81 | function assertNotFinished(decoratorFinishedRef, fnName) { 82 | if (decoratorFinishedRef.v) { 83 | throw new Error("attempted to call " + fnName + " after decoration was finished"); 84 | } 85 | } 86 | function assertCallable(fn, hint) { 87 | if (typeof fn !== "function") { 88 | throw new TypeError(hint + " must be a function"); 89 | } 90 | } 91 | function assertValidReturnValue(kind, value) { 92 | var type = typeof value; 93 | if (kind === 1) { 94 | if (type !== "object" || value === null) { 95 | throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0"); 96 | } 97 | if (value.get !== undefined) { 98 | assertCallable(value.get, "accessor.get"); 99 | } 100 | if (value.set !== undefined) { 101 | assertCallable(value.set, "accessor.set"); 102 | } 103 | if (value.init !== undefined) { 104 | assertCallable(value.init, "accessor.init"); 105 | } 106 | } else if (type !== "function") { 107 | var hint; 108 | if (kind === 0) { 109 | hint = "field"; 110 | } else if (kind === 10) { 111 | hint = "class"; 112 | } else { 113 | hint = "method"; 114 | } 115 | throw new TypeError(hint + " decorators must return a function or void 0"); 116 | } 117 | } 118 | function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) { 119 | var decs = decInfo[0]; 120 | var desc, init, value; 121 | if (isPrivate) { 122 | if (kind === 0 || kind === 1) { 123 | desc = { 124 | get: decInfo[3], 125 | set: decInfo[4] 126 | }; 127 | } else if (kind === 3) { 128 | desc = { 129 | get: decInfo[3] 130 | }; 131 | } else if (kind === 4) { 132 | desc = { 133 | set: decInfo[3] 134 | }; 135 | } else { 136 | desc = { 137 | value: decInfo[3] 138 | }; 139 | } 140 | } else if (kind !== 0) { 141 | desc = Object.getOwnPropertyDescriptor(base, name); 142 | } 143 | if (kind === 1) { 144 | value = { 145 | get: desc.get, 146 | set: desc.set 147 | }; 148 | } else if (kind === 2) { 149 | value = desc.value; 150 | } else if (kind === 3) { 151 | value = desc.get; 152 | } else if (kind === 4) { 153 | value = desc.set; 154 | } 155 | var newValue, get, set; 156 | if (typeof decs === "function") { 157 | newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value); 158 | if (newValue !== void 0) { 159 | assertValidReturnValue(kind, newValue); 160 | if (kind === 0) { 161 | init = newValue; 162 | } else if (kind === 1) { 163 | init = newValue.init; 164 | get = newValue.get || value.get; 165 | set = newValue.set || value.set; 166 | value = { 167 | get: get, 168 | set: set 169 | }; 170 | } else { 171 | value = newValue; 172 | } 173 | } 174 | } else { 175 | for(var i = decs.length - 1; i >= 0; i--){ 176 | var dec = decs[i]; 177 | newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value); 178 | if (newValue !== void 0) { 179 | assertValidReturnValue(kind, newValue); 180 | var newInit; 181 | if (kind === 0) { 182 | newInit = newValue; 183 | } else if (kind === 1) { 184 | newInit = newValue.init; 185 | get = newValue.get || value.get; 186 | set = newValue.set || value.set; 187 | value = { 188 | get: get, 189 | set: set 190 | }; 191 | } else { 192 | value = newValue; 193 | } 194 | if (newInit !== void 0) { 195 | if (init === void 0) { 196 | init = newInit; 197 | } else if (typeof init === "function") { 198 | init = [ 199 | init, 200 | newInit 201 | ]; 202 | } else { 203 | init.push(newInit); 204 | } 205 | } 206 | } 207 | } 208 | } 209 | if (kind === 0 || kind === 1) { 210 | if (init === void 0) { 211 | init = function(instance, init) { 212 | return init; 213 | }; 214 | } else if (typeof init !== "function") { 215 | var ownInitializers = init; 216 | init = function(instance, init) { 217 | var value = init; 218 | for(var i = 0; i < ownInitializers.length; i++){ 219 | value = ownInitializers[i].call(instance, value); 220 | } 221 | return value; 222 | }; 223 | } else { 224 | var originalInitializer = init; 225 | init = function(instance, init) { 226 | return originalInitializer.call(instance, init); 227 | }; 228 | } 229 | ret.push(init); 230 | } 231 | if (kind !== 0) { 232 | if (kind === 1) { 233 | desc.get = value.get; 234 | desc.set = value.set; 235 | } else if (kind === 2) { 236 | desc.value = value; 237 | } else if (kind === 3) { 238 | desc.get = value; 239 | } else if (kind === 4) { 240 | desc.set = value; 241 | } 242 | if (isPrivate) { 243 | if (kind === 1) { 244 | ret.push(function(instance, args) { 245 | return value.get.call(instance, args); 246 | }); 247 | ret.push(function(instance, args) { 248 | return value.set.call(instance, args); 249 | }); 250 | } else if (kind === 2) { 251 | ret.push(value); 252 | } else { 253 | ret.push(function(instance, args) { 254 | return value.call(instance, args); 255 | }); 256 | } 257 | } else { 258 | Object.defineProperty(base, name, desc); 259 | } 260 | } 261 | } 262 | function applyMemberDecs(Class, decInfos, metadata) { 263 | var ret = []; 264 | var protoInitializers; 265 | var staticInitializers; 266 | var existingProtoNonFields = new Map(); 267 | var existingStaticNonFields = new Map(); 268 | for(var i = 0; i < decInfos.length; i++){ 269 | var decInfo = decInfos[i]; 270 | if (!Array.isArray(decInfo)) continue; 271 | var kind = decInfo[1]; 272 | var name = decInfo[2]; 273 | var isPrivate = decInfo.length > 3; 274 | var isStatic = kind >= 5; 275 | var base; 276 | var initializers; 277 | if (isStatic) { 278 | base = Class; 279 | kind = kind - 5; 280 | staticInitializers = staticInitializers || []; 281 | initializers = staticInitializers; 282 | } else { 283 | base = Class.prototype; 284 | protoInitializers = protoInitializers || []; 285 | initializers = protoInitializers; 286 | } 287 | if (kind !== 0 && !isPrivate) { 288 | var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields; 289 | var existingKind = existingNonFields.get(name) || 0; 290 | if (existingKind === true || existingKind === 3 && kind !== 4 || existingKind === 4 && kind !== 3) { 291 | throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name); 292 | } else if (!existingKind && kind > 2) { 293 | existingNonFields.set(name, kind); 294 | } else { 295 | existingNonFields.set(name, true); 296 | } 297 | } 298 | applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata); 299 | } 300 | pushInitializers(ret, protoInitializers); 301 | pushInitializers(ret, staticInitializers); 302 | return ret; 303 | } 304 | function pushInitializers(ret, initializers) { 305 | if (initializers) { 306 | ret.push(function(instance) { 307 | for(var i = 0; i < initializers.length; i++){ 308 | initializers[i].call(instance); 309 | } 310 | return instance; 311 | }); 312 | } 313 | } 314 | function applyClassDecs(targetClass, classDecs, metadata) { 315 | if (classDecs.length > 0) { 316 | var initializers = []; 317 | var newClass = targetClass; 318 | var name = targetClass.name; 319 | for(var i = classDecs.length - 1; i >= 0; i--){ 320 | var decoratorFinishedRef = { 321 | v: false 322 | }; 323 | try { 324 | var nextNewClass = classDecs[i](newClass, { 325 | kind: "class", 326 | name: name, 327 | addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef), 328 | metadata 329 | }); 330 | } finally{ 331 | decoratorFinishedRef.v = true; 332 | } 333 | if (nextNewClass !== undefined) { 334 | assertValidReturnValue(10, nextNewClass); 335 | newClass = nextNewClass; 336 | } 337 | } 338 | return [ 339 | defineMetadata(newClass, metadata), 340 | function() { 341 | for(var i = 0; i < initializers.length; i++){ 342 | initializers[i].call(newClass); 343 | } 344 | } 345 | ]; 346 | } 347 | } 348 | function defineMetadata(Class, metadata) { 349 | return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), { 350 | configurable: true, 351 | enumerable: true, 352 | value: metadata 353 | }); 354 | } 355 | return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) { 356 | if (parentClass !== void 0) { 357 | var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")]; 358 | } 359 | var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata); 360 | var e = applyMemberDecs(targetClass, memberDecs, metadata); 361 | if (!classDecs.length) defineMetadata(targetClass, metadata); 362 | return { 363 | e: e, 364 | get c () { 365 | return applyClassDecs(targetClass, classDecs, metadata); 366 | } 367 | }; 368 | }; 369 | } 370 | function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) { 371 | return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass); 372 | } 373 | var _dec, _initProto; 374 | function a() { 375 | console.log("a(): evaluated"); 376 | return (_target, _propertyKey, _descriptor)=>{ 377 | console.log("a(): called"); 378 | }; 379 | } 380 | _dec = a(); 381 | export class B { 382 | static{ 383 | ({ e: [_initProto] } = _apply_decs_2203_r(this, [ 384 | [ 385 | _dec, 386 | 2, 387 | "method" 388 | ] 389 | ], [])); 390 | } 391 | constructor(){ 392 | _initProto(this); 393 | } 394 | method() { 395 | console.log("method"); 396 | } 397 | } 398 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_object/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/glob.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | import { isWindows, osType } from "../_util/os.ts"; 4 | import { SEP, SEP_PATTERN } from "./separator.ts"; 5 | import * as _win32 from "./win32.ts"; 6 | import * as _posix from "./posix.ts"; 7 | const path = isWindows ? _win32 : _posix; 8 | const { join, normalize } = path; 9 | const regExpEscapeChars = [ 10 | "!", 11 | "$", 12 | "(", 13 | ")", 14 | "*", 15 | "+", 16 | ".", 17 | "=", 18 | "?", 19 | "[", 20 | "\\", 21 | "^", 22 | "{", 23 | "|" 24 | ]; 25 | const rangeEscapeChars = [ 26 | "-", 27 | "\\", 28 | "]" 29 | ]; 30 | /** Convert a glob string to a regular expression. 31 | * 32 | * Tries to match bash glob expansion as closely as possible. 33 | * 34 | * Basic glob syntax: 35 | * - `*` - Matches everything without leaving the path segment. 36 | * - `?` - Matches any single character. 37 | * - `{foo,bar}` - Matches `foo` or `bar`. 38 | * - `[abcd]` - Matches `a`, `b`, `c` or `d`. 39 | * - `[a-d]` - Matches `a`, `b`, `c` or `d`. 40 | * - `[!abcd]` - Matches any single character besides `a`, `b`, `c` or `d`. 41 | * - `[[::]]` - Matches any character belonging to ``. 42 | * - `[[:alnum:]]` - Matches any digit or letter. 43 | * - `[[:digit:]abc]` - Matches any digit, `a`, `b` or `c`. 44 | * - See https://facelessuser.github.io/wcmatch/glob/#posix-character-classes 45 | * for a complete list of supported character classes. 46 | * - `\` - Escapes the next character for an `os` other than `"windows"`. 47 | * - \` - Escapes the next character for `os` set to `"windows"`. 48 | * - `/` - Path separator. 49 | * - `\` - Additional path separator only for `os` set to `"windows"`. 50 | * 51 | * Extended syntax: 52 | * - Requires `{ extended: true }`. 53 | * - `?(foo|bar)` - Matches 0 or 1 instance of `{foo,bar}`. 54 | * - `@(foo|bar)` - Matches 1 instance of `{foo,bar}`. They behave the same. 55 | * - `*(foo|bar)` - Matches _n_ instances of `{foo,bar}`. 56 | * - `+(foo|bar)` - Matches _n > 0_ instances of `{foo,bar}`. 57 | * - `!(foo|bar)` - Matches anything other than `{foo,bar}`. 58 | * - See https://www.linuxjournal.com/content/bash-extended-globbing. 59 | * 60 | * Globstar syntax: 61 | * - Requires `{ globstar: true }`. 62 | * - `**` - Matches any number of any path segments. 63 | * - Must comprise its entire path segment in the provided glob. 64 | * - See https://www.linuxjournal.com/content/globstar-new-bash-globbing-option. 65 | * 66 | * Note the following properties: 67 | * - The generated `RegExp` is anchored at both start and end. 68 | * - Repeating and trailing separators are tolerated. Trailing separators in the 69 | * provided glob have no meaning and are discarded. 70 | * - Absolute globs will only match absolute paths, etc. 71 | * - Empty globs will match nothing. 72 | * - Any special glob syntax must be contained to one path segment. For example, 73 | * `?(foo|bar/baz)` is invalid. The separator will take precedence and the 74 | * first segment ends with an unclosed group. 75 | * - If a path segment ends with unclosed groups or a dangling escape prefix, a 76 | * parse error has occurred. Every character for that segment is taken 77 | * literally in this event. 78 | * 79 | * Limitations: 80 | * - A negative group like `!(foo|bar)` will wrongly be converted to a negative 81 | * look-ahead followed by a wildcard. This means that `!(foo).js` will wrongly 82 | * fail to match `foobar.js`, even though `foobar` is not `foo`. Effectively, 83 | * `!(foo|bar)` is treated like `!(@(foo|bar)*)`. This will work correctly if 84 | * the group occurs not nested at the end of the segment. */ export function globToRegExp(glob, { extended = true, globstar: globstarOption = true, os = osType, caseInsensitive = false } = {}) { 85 | if (glob == "") { 86 | return /(?!)/; 87 | } 88 | const sep = os == "windows" ? "(?:\\\\|/)+" : "/+"; 89 | const sepMaybe = os == "windows" ? "(?:\\\\|/)*" : "/*"; 90 | const seps = os == "windows" ? [ 91 | "\\", 92 | "/" 93 | ] : [ 94 | "/" 95 | ]; 96 | const globstar = os == "windows" ? "(?:[^\\\\/]*(?:\\\\|/|$)+)*" : "(?:[^/]*(?:/|$)+)*"; 97 | const wildcard = os == "windows" ? "[^\\\\/]*" : "[^/]*"; 98 | const escapePrefix = os == "windows" ? "`" : "\\"; 99 | // Remove trailing separators. 100 | let newLength = glob.length; 101 | for(; newLength > 1 && seps.includes(glob[newLength - 1]); newLength--); 102 | glob = glob.slice(0, newLength); 103 | let regExpString = ""; 104 | // Terminates correctly. Trust that `j` is incremented every iteration. 105 | for(let j = 0; j < glob.length;){ 106 | let segment = ""; 107 | const groupStack = []; 108 | let inRange = false; 109 | let inEscape = false; 110 | let endsWithSep = false; 111 | let i = j; 112 | // Terminates with `i` at the non-inclusive end of the current segment. 113 | for(; i < glob.length && !seps.includes(glob[i]); i++){ 114 | if (inEscape) { 115 | inEscape = false; 116 | const escapeChars = inRange ? rangeEscapeChars : regExpEscapeChars; 117 | segment += escapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i]; 118 | continue; 119 | } 120 | if (glob[i] == escapePrefix) { 121 | inEscape = true; 122 | continue; 123 | } 124 | if (glob[i] == "[") { 125 | if (!inRange) { 126 | inRange = true; 127 | segment += "["; 128 | if (glob[i + 1] == "!") { 129 | i++; 130 | segment += "^"; 131 | } else if (glob[i + 1] == "^") { 132 | i++; 133 | segment += "\\^"; 134 | } 135 | continue; 136 | } else if (glob[i + 1] == ":") { 137 | let k = i + 1; 138 | let value = ""; 139 | while(glob[k + 1] != null && glob[k + 1] != ":"){ 140 | value += glob[k + 1]; 141 | k++; 142 | } 143 | if (glob[k + 1] == ":" && glob[k + 2] == "]") { 144 | i = k + 2; 145 | if (value == "alnum") segment += "\\dA-Za-z"; 146 | else if (value == "alpha") segment += "A-Za-z"; 147 | else if (value == "ascii") segment += "\x00-\x7F"; 148 | else if (value == "blank") segment += "\t "; 149 | else if (value == "cntrl") segment += "\x00-\x1F\x7F"; 150 | else if (value == "digit") segment += "\\d"; 151 | else if (value == "graph") segment += "\x21-\x7E"; 152 | else if (value == "lower") segment += "a-z"; 153 | else if (value == "print") segment += "\x20-\x7E"; 154 | else if (value == "punct") { 155 | segment += "!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_‘{|}~"; 156 | } else if (value == "space") segment += "\\s\v"; 157 | else if (value == "upper") segment += "A-Z"; 158 | else if (value == "word") segment += "\\w"; 159 | else if (value == "xdigit") segment += "\\dA-Fa-f"; 160 | continue; 161 | } 162 | } 163 | } 164 | if (glob[i] == "]" && inRange) { 165 | inRange = false; 166 | segment += "]"; 167 | continue; 168 | } 169 | if (inRange) { 170 | if (glob[i] == "\\") { 171 | segment += `\\\\`; 172 | } else { 173 | segment += glob[i]; 174 | } 175 | continue; 176 | } 177 | if (glob[i] == ")" && groupStack.length > 0 && groupStack[groupStack.length - 1] != "BRACE") { 178 | segment += ")"; 179 | const type = groupStack.pop(); 180 | if (type == "!") { 181 | segment += wildcard; 182 | } else if (type != "@") { 183 | segment += type; 184 | } 185 | continue; 186 | } 187 | if (glob[i] == "|" && groupStack.length > 0 && groupStack[groupStack.length - 1] != "BRACE") { 188 | segment += "|"; 189 | continue; 190 | } 191 | if (glob[i] == "+" && extended && glob[i + 1] == "(") { 192 | i++; 193 | groupStack.push("+"); 194 | segment += "(?:"; 195 | continue; 196 | } 197 | if (glob[i] == "@" && extended && glob[i + 1] == "(") { 198 | i++; 199 | groupStack.push("@"); 200 | segment += "(?:"; 201 | continue; 202 | } 203 | if (glob[i] == "?") { 204 | if (extended && glob[i + 1] == "(") { 205 | i++; 206 | groupStack.push("?"); 207 | segment += "(?:"; 208 | } else { 209 | segment += "."; 210 | } 211 | continue; 212 | } 213 | if (glob[i] == "!" && extended && glob[i + 1] == "(") { 214 | i++; 215 | groupStack.push("!"); 216 | segment += "(?!"; 217 | continue; 218 | } 219 | if (glob[i] == "{") { 220 | groupStack.push("BRACE"); 221 | segment += "(?:"; 222 | continue; 223 | } 224 | if (glob[i] == "}" && groupStack[groupStack.length - 1] == "BRACE") { 225 | groupStack.pop(); 226 | segment += ")"; 227 | continue; 228 | } 229 | if (glob[i] == "," && groupStack[groupStack.length - 1] == "BRACE") { 230 | segment += "|"; 231 | continue; 232 | } 233 | if (glob[i] == "*") { 234 | if (extended && glob[i + 1] == "(") { 235 | i++; 236 | groupStack.push("*"); 237 | segment += "(?:"; 238 | } else { 239 | const prevChar = glob[i - 1]; 240 | let numStars = 1; 241 | while(glob[i + 1] == "*"){ 242 | i++; 243 | numStars++; 244 | } 245 | const nextChar = glob[i + 1]; 246 | if (globstarOption && numStars == 2 && [ 247 | ...seps, 248 | undefined 249 | ].includes(prevChar) && [ 250 | ...seps, 251 | undefined 252 | ].includes(nextChar)) { 253 | segment += globstar; 254 | endsWithSep = true; 255 | } else { 256 | segment += wildcard; 257 | } 258 | } 259 | continue; 260 | } 261 | segment += regExpEscapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i]; 262 | } 263 | // Check for unclosed groups or a dangling backslash. 264 | if (groupStack.length > 0 || inRange || inEscape) { 265 | // Parse failure. Take all characters from this segment literally. 266 | segment = ""; 267 | for (const c of glob.slice(j, i)){ 268 | segment += regExpEscapeChars.includes(c) ? `\\${c}` : c; 269 | endsWithSep = false; 270 | } 271 | } 272 | regExpString += segment; 273 | if (!endsWithSep) { 274 | regExpString += i < glob.length ? sep : sepMaybe; 275 | endsWithSep = true; 276 | } 277 | // Terminates with `i` at the start of the next segment. 278 | while(seps.includes(glob[i]))i++; 279 | // Check that the next value of `j` is indeed higher than the current value. 280 | if (!(i > j)) { 281 | throw new Error("Assertion failure: i > j (potential infinite loop)"); 282 | } 283 | j = i; 284 | } 285 | regExpString = `^${regExpString}$`; 286 | return new RegExp(regExpString, caseInsensitive ? "i" : ""); 287 | } 288 | /** Test whether the given string is a glob */ export function isGlob(str) { 289 | const chars = { 290 | "{": "}", 291 | "(": ")", 292 | "[": "]" 293 | }; 294 | const regex = /\\(.)|(^!|\*|\?|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; 295 | if (str === "") { 296 | return false; 297 | } 298 | let match; 299 | while(match = regex.exec(str)){ 300 | if (match[2]) return true; 301 | let idx = match.index + match[0].length; 302 | // if an open bracket/brace/paren is escaped, 303 | // set the index to the next closing character 304 | const open = match[1]; 305 | const close = open ? chars[open] : null; 306 | if (open && close) { 307 | const n = str.indexOf(close, idx); 308 | if (n !== -1) { 309 | idx = n + 1; 310 | } 311 | } 312 | str = str.slice(idx); 313 | } 314 | return false; 315 | } 316 | /** Like normalize(), but doesn't collapse "**\/.." when `globstar` is true. */ export function normalizeGlob(glob, { globstar = false } = {}) { 317 | if (glob.match(/\0/g)) { 318 | throw new Error(`Glob contains invalid characters: "${glob}"`); 319 | } 320 | if (!globstar) { 321 | return normalize(glob); 322 | } 323 | const s = SEP_PATTERN.source; 324 | const badParentPattern = new RegExp(`(?<=(${s}|^)\\*\\*${s})\\.\\.(?=${s}|$)`, "g"); 325 | return normalize(glob.replace(badParentPattern, "\0")).replace(/\0/g, ".."); 326 | } 327 | /** Like join(), but doesn't collapse "**\/.." when `globstar` is true. */ export function joinGlobs(globs, { extended = true, globstar = false } = {}) { 328 | if (!globstar || globs.length == 0) { 329 | return join(...globs); 330 | } 331 | if (globs.length === 0) return "."; 332 | let joined; 333 | for (const glob of globs){ 334 | const path = glob; 335 | if (path.length > 0) { 336 | if (!joined) joined = path; 337 | else joined += `${SEP}${path}`; 338 | } 339 | } 340 | if (!joined) return "."; 341 | return normalizeGlob(joined, { 342 | extended, 343 | globstar 344 | }); 345 | } 346 | -------------------------------------------------------------------------------- /tests/__snapshots__/common/remote_url_as_string/transpile/remote/NNRNTa3nQ9cRguYpg8Fa19sQDzU/std@0.140.0/path/glob.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. 2 | // This module is browser compatible. 3 | import { isWindows, osType } from "../_util/os.ts"; 4 | import { SEP, SEP_PATTERN } from "./separator.ts"; 5 | import * as _win32 from "./win32.ts"; 6 | import * as _posix from "./posix.ts"; 7 | const path = isWindows ? _win32 : _posix; 8 | const { join, normalize } = path; 9 | const regExpEscapeChars = [ 10 | "!", 11 | "$", 12 | "(", 13 | ")", 14 | "*", 15 | "+", 16 | ".", 17 | "=", 18 | "?", 19 | "[", 20 | "\\", 21 | "^", 22 | "{", 23 | "|" 24 | ]; 25 | const rangeEscapeChars = [ 26 | "-", 27 | "\\", 28 | "]" 29 | ]; 30 | /** Convert a glob string to a regular expression. 31 | * 32 | * Tries to match bash glob expansion as closely as possible. 33 | * 34 | * Basic glob syntax: 35 | * - `*` - Matches everything without leaving the path segment. 36 | * - `?` - Matches any single character. 37 | * - `{foo,bar}` - Matches `foo` or `bar`. 38 | * - `[abcd]` - Matches `a`, `b`, `c` or `d`. 39 | * - `[a-d]` - Matches `a`, `b`, `c` or `d`. 40 | * - `[!abcd]` - Matches any single character besides `a`, `b`, `c` or `d`. 41 | * - `[[::]]` - Matches any character belonging to ``. 42 | * - `[[:alnum:]]` - Matches any digit or letter. 43 | * - `[[:digit:]abc]` - Matches any digit, `a`, `b` or `c`. 44 | * - See https://facelessuser.github.io/wcmatch/glob/#posix-character-classes 45 | * for a complete list of supported character classes. 46 | * - `\` - Escapes the next character for an `os` other than `"windows"`. 47 | * - \` - Escapes the next character for `os` set to `"windows"`. 48 | * - `/` - Path separator. 49 | * - `\` - Additional path separator only for `os` set to `"windows"`. 50 | * 51 | * Extended syntax: 52 | * - Requires `{ extended: true }`. 53 | * - `?(foo|bar)` - Matches 0 or 1 instance of `{foo,bar}`. 54 | * - `@(foo|bar)` - Matches 1 instance of `{foo,bar}`. They behave the same. 55 | * - `*(foo|bar)` - Matches _n_ instances of `{foo,bar}`. 56 | * - `+(foo|bar)` - Matches _n > 0_ instances of `{foo,bar}`. 57 | * - `!(foo|bar)` - Matches anything other than `{foo,bar}`. 58 | * - See https://www.linuxjournal.com/content/bash-extended-globbing. 59 | * 60 | * Globstar syntax: 61 | * - Requires `{ globstar: true }`. 62 | * - `**` - Matches any number of any path segments. 63 | * - Must comprise its entire path segment in the provided glob. 64 | * - See https://www.linuxjournal.com/content/globstar-new-bash-globbing-option. 65 | * 66 | * Note the following properties: 67 | * - The generated `RegExp` is anchored at both start and end. 68 | * - Repeating and trailing separators are tolerated. Trailing separators in the 69 | * provided glob have no meaning and are discarded. 70 | * - Absolute globs will only match absolute paths, etc. 71 | * - Empty globs will match nothing. 72 | * - Any special glob syntax must be contained to one path segment. For example, 73 | * `?(foo|bar/baz)` is invalid. The separator will take precedence and the 74 | * first segment ends with an unclosed group. 75 | * - If a path segment ends with unclosed groups or a dangling escape prefix, a 76 | * parse error has occurred. Every character for that segment is taken 77 | * literally in this event. 78 | * 79 | * Limitations: 80 | * - A negative group like `!(foo|bar)` will wrongly be converted to a negative 81 | * look-ahead followed by a wildcard. This means that `!(foo).js` will wrongly 82 | * fail to match `foobar.js`, even though `foobar` is not `foo`. Effectively, 83 | * `!(foo|bar)` is treated like `!(@(foo|bar)*)`. This will work correctly if 84 | * the group occurs not nested at the end of the segment. */ export function globToRegExp(glob, { extended = true, globstar: globstarOption = true, os = osType, caseInsensitive = false } = {}) { 85 | if (glob == "") { 86 | return /(?!)/; 87 | } 88 | const sep = os == "windows" ? "(?:\\\\|/)+" : "/+"; 89 | const sepMaybe = os == "windows" ? "(?:\\\\|/)*" : "/*"; 90 | const seps = os == "windows" ? [ 91 | "\\", 92 | "/" 93 | ] : [ 94 | "/" 95 | ]; 96 | const globstar = os == "windows" ? "(?:[^\\\\/]*(?:\\\\|/|$)+)*" : "(?:[^/]*(?:/|$)+)*"; 97 | const wildcard = os == "windows" ? "[^\\\\/]*" : "[^/]*"; 98 | const escapePrefix = os == "windows" ? "`" : "\\"; 99 | // Remove trailing separators. 100 | let newLength = glob.length; 101 | for(; newLength > 1 && seps.includes(glob[newLength - 1]); newLength--); 102 | glob = glob.slice(0, newLength); 103 | let regExpString = ""; 104 | // Terminates correctly. Trust that `j` is incremented every iteration. 105 | for(let j = 0; j < glob.length;){ 106 | let segment = ""; 107 | const groupStack = []; 108 | let inRange = false; 109 | let inEscape = false; 110 | let endsWithSep = false; 111 | let i = j; 112 | // Terminates with `i` at the non-inclusive end of the current segment. 113 | for(; i < glob.length && !seps.includes(glob[i]); i++){ 114 | if (inEscape) { 115 | inEscape = false; 116 | const escapeChars = inRange ? rangeEscapeChars : regExpEscapeChars; 117 | segment += escapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i]; 118 | continue; 119 | } 120 | if (glob[i] == escapePrefix) { 121 | inEscape = true; 122 | continue; 123 | } 124 | if (glob[i] == "[") { 125 | if (!inRange) { 126 | inRange = true; 127 | segment += "["; 128 | if (glob[i + 1] == "!") { 129 | i++; 130 | segment += "^"; 131 | } else if (glob[i + 1] == "^") { 132 | i++; 133 | segment += "\\^"; 134 | } 135 | continue; 136 | } else if (glob[i + 1] == ":") { 137 | let k = i + 1; 138 | let value = ""; 139 | while(glob[k + 1] != null && glob[k + 1] != ":"){ 140 | value += glob[k + 1]; 141 | k++; 142 | } 143 | if (glob[k + 1] == ":" && glob[k + 2] == "]") { 144 | i = k + 2; 145 | if (value == "alnum") segment += "\\dA-Za-z"; 146 | else if (value == "alpha") segment += "A-Za-z"; 147 | else if (value == "ascii") segment += "\x00-\x7F"; 148 | else if (value == "blank") segment += "\t "; 149 | else if (value == "cntrl") segment += "\x00-\x1F\x7F"; 150 | else if (value == "digit") segment += "\\d"; 151 | else if (value == "graph") segment += "\x21-\x7E"; 152 | else if (value == "lower") segment += "a-z"; 153 | else if (value == "print") segment += "\x20-\x7E"; 154 | else if (value == "punct") { 155 | segment += "!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_‘{|}~"; 156 | } else if (value == "space") segment += "\\s\v"; 157 | else if (value == "upper") segment += "A-Z"; 158 | else if (value == "word") segment += "\\w"; 159 | else if (value == "xdigit") segment += "\\dA-Fa-f"; 160 | continue; 161 | } 162 | } 163 | } 164 | if (glob[i] == "]" && inRange) { 165 | inRange = false; 166 | segment += "]"; 167 | continue; 168 | } 169 | if (inRange) { 170 | if (glob[i] == "\\") { 171 | segment += `\\\\`; 172 | } else { 173 | segment += glob[i]; 174 | } 175 | continue; 176 | } 177 | if (glob[i] == ")" && groupStack.length > 0 && groupStack[groupStack.length - 1] != "BRACE") { 178 | segment += ")"; 179 | const type = groupStack.pop(); 180 | if (type == "!") { 181 | segment += wildcard; 182 | } else if (type != "@") { 183 | segment += type; 184 | } 185 | continue; 186 | } 187 | if (glob[i] == "|" && groupStack.length > 0 && groupStack[groupStack.length - 1] != "BRACE") { 188 | segment += "|"; 189 | continue; 190 | } 191 | if (glob[i] == "+" && extended && glob[i + 1] == "(") { 192 | i++; 193 | groupStack.push("+"); 194 | segment += "(?:"; 195 | continue; 196 | } 197 | if (glob[i] == "@" && extended && glob[i + 1] == "(") { 198 | i++; 199 | groupStack.push("@"); 200 | segment += "(?:"; 201 | continue; 202 | } 203 | if (glob[i] == "?") { 204 | if (extended && glob[i + 1] == "(") { 205 | i++; 206 | groupStack.push("?"); 207 | segment += "(?:"; 208 | } else { 209 | segment += "."; 210 | } 211 | continue; 212 | } 213 | if (glob[i] == "!" && extended && glob[i + 1] == "(") { 214 | i++; 215 | groupStack.push("!"); 216 | segment += "(?!"; 217 | continue; 218 | } 219 | if (glob[i] == "{") { 220 | groupStack.push("BRACE"); 221 | segment += "(?:"; 222 | continue; 223 | } 224 | if (glob[i] == "}" && groupStack[groupStack.length - 1] == "BRACE") { 225 | groupStack.pop(); 226 | segment += ")"; 227 | continue; 228 | } 229 | if (glob[i] == "," && groupStack[groupStack.length - 1] == "BRACE") { 230 | segment += "|"; 231 | continue; 232 | } 233 | if (glob[i] == "*") { 234 | if (extended && glob[i + 1] == "(") { 235 | i++; 236 | groupStack.push("*"); 237 | segment += "(?:"; 238 | } else { 239 | const prevChar = glob[i - 1]; 240 | let numStars = 1; 241 | while(glob[i + 1] == "*"){ 242 | i++; 243 | numStars++; 244 | } 245 | const nextChar = glob[i + 1]; 246 | if (globstarOption && numStars == 2 && [ 247 | ...seps, 248 | undefined 249 | ].includes(prevChar) && [ 250 | ...seps, 251 | undefined 252 | ].includes(nextChar)) { 253 | segment += globstar; 254 | endsWithSep = true; 255 | } else { 256 | segment += wildcard; 257 | } 258 | } 259 | continue; 260 | } 261 | segment += regExpEscapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i]; 262 | } 263 | // Check for unclosed groups or a dangling backslash. 264 | if (groupStack.length > 0 || inRange || inEscape) { 265 | // Parse failure. Take all characters from this segment literally. 266 | segment = ""; 267 | for (const c of glob.slice(j, i)){ 268 | segment += regExpEscapeChars.includes(c) ? `\\${c}` : c; 269 | endsWithSep = false; 270 | } 271 | } 272 | regExpString += segment; 273 | if (!endsWithSep) { 274 | regExpString += i < glob.length ? sep : sepMaybe; 275 | endsWithSep = true; 276 | } 277 | // Terminates with `i` at the start of the next segment. 278 | while(seps.includes(glob[i]))i++; 279 | // Check that the next value of `j` is indeed higher than the current value. 280 | if (!(i > j)) { 281 | throw new Error("Assertion failure: i > j (potential infinite loop)"); 282 | } 283 | j = i; 284 | } 285 | regExpString = `^${regExpString}$`; 286 | return new RegExp(regExpString, caseInsensitive ? "i" : ""); 287 | } 288 | /** Test whether the given string is a glob */ export function isGlob(str) { 289 | const chars = { 290 | "{": "}", 291 | "(": ")", 292 | "[": "]" 293 | }; 294 | const regex = /\\(.)|(^!|\*|\?|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; 295 | if (str === "") { 296 | return false; 297 | } 298 | let match; 299 | while(match = regex.exec(str)){ 300 | if (match[2]) return true; 301 | let idx = match.index + match[0].length; 302 | // if an open bracket/brace/paren is escaped, 303 | // set the index to the next closing character 304 | const open = match[1]; 305 | const close = open ? chars[open] : null; 306 | if (open && close) { 307 | const n = str.indexOf(close, idx); 308 | if (n !== -1) { 309 | idx = n + 1; 310 | } 311 | } 312 | str = str.slice(idx); 313 | } 314 | return false; 315 | } 316 | /** Like normalize(), but doesn't collapse "**\/.." when `globstar` is true. */ export function normalizeGlob(glob, { globstar = false } = {}) { 317 | if (glob.match(/\0/g)) { 318 | throw new Error(`Glob contains invalid characters: "${glob}"`); 319 | } 320 | if (!globstar) { 321 | return normalize(glob); 322 | } 323 | const s = SEP_PATTERN.source; 324 | const badParentPattern = new RegExp(`(?<=(${s}|^)\\*\\*${s})\\.\\.(?=${s}|$)`, "g"); 325 | return normalize(glob.replace(badParentPattern, "\0")).replace(/\0/g, ".."); 326 | } 327 | /** Like join(), but doesn't collapse "**\/.." when `globstar` is true. */ export function joinGlobs(globs, { extended = true, globstar = false } = {}) { 328 | if (!globstar || globs.length == 0) { 329 | return join(...globs); 330 | } 331 | if (globs.length === 0) return "."; 332 | let joined; 333 | for (const glob of globs){ 334 | const path = glob; 335 | if (path.length > 0) { 336 | if (!joined) joined = path; 337 | else joined += `${SEP}${path}`; 338 | } 339 | } 340 | if (!joined) return "."; 341 | return normalizeGlob(joined, { 342 | extended, 343 | globstar 344 | }); 345 | } 346 | -------------------------------------------------------------------------------- /js/mod.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. 2 | 3 | /** APIs to transpile and bundle JavaScript and TypeScript under Deno and Deno. 4 | * 5 | * It is a user loadable module which provides an alternative to the removed 6 | * unstable `Deno.emit()` API. 7 | * 8 | * ### Example - Transpiling 9 | * 10 | * ```ts 11 | * import { transpile } from "jsr:@deno/emit"; 12 | * 13 | * const url = new URL("./testdata/mod.ts", import.meta.url); 14 | * const result = await transpile(url); 15 | * 16 | * const code = result.get(url.href); 17 | * console.log(code?.includes("export default function hello()")); 18 | * ``` 19 | * 20 | * ### Example - Bundling 21 | * 22 | * ```ts 23 | * import { bundle } from "jsr:@deno/emit"; 24 | * const result = await bundle( 25 | * "https://deno.land/std@0.140.0/examples/chat/server.ts", 26 | * ); 27 | * 28 | * const { code } = result; 29 | * console.log(code); 30 | * ``` 31 | * 32 | * @module 33 | */ 34 | 35 | const encoder = new TextEncoder(); 36 | 37 | // run `deno task build` to build this 38 | import { instantiate } from "./emit.generated.js"; 39 | import { locationToUrl } from "./_utils.ts"; 40 | import { 41 | type CacheSetting, 42 | createCache, 43 | type FetchCacher, 44 | } from "jsr:@deno/cache-dir@0.13.2"; 45 | 46 | /** The output of the {@linkcode bundle} function. */ 47 | export interface BundleEmit { 48 | /** The bundles code as a single JavaScript module. */ 49 | code: string; 50 | /** An optional source map. */ 51 | map?: string; 52 | } 53 | 54 | /** An [import-map](https://docs.deno.com/runtime/manual/basics/import_maps) */ 55 | export interface ImportMap { 56 | /** Base URL to resolve import map specifiers. It Is always treated as a 57 | * directory. Defaults to the file URL of `Deno.cwd()`. */ 58 | baseUrl?: URL | string; 59 | /** Specifiers of the import map. */ 60 | imports?: Record; 61 | /** Overrides of the specifiers for the provided scopes. */ 62 | scopes?: Record>; 63 | } 64 | 65 | export interface BundleOptions { 66 | /** Allow remote modules to be loaded or read from the cache. */ 67 | allowRemote?: boolean; 68 | /** The cache root to use, overriding the default inferred `DENO_DIR`. */ 69 | cacheRoot?: string; 70 | /** The setting to use when loading sources from the Deno cache. */ 71 | cacheSetting?: CacheSetting; 72 | /** Compiler options which can be set when bundling. */ 73 | compilerOptions?: CompilerOptions; 74 | /** An [import-map](https://docs.deno.com/runtime/manual/basics/import_maps) 75 | * which will be applied to the imports, or the URL of an import map, or the 76 | * path to an import map */ 77 | importMap?: ImportMap | URL | string; 78 | /** Override the default loading mechanism with a custom loader. This can 79 | * provide a way to use "in-memory" resources instead of fetching them 80 | * remotely. */ 81 | load?: FetchCacher["load"]; 82 | /** Minify compiled code, default false. */ 83 | minify?: boolean; 84 | /** Should the emitted bundle be an ES module or an IIFE script. The default 85 | * is `"module"` to output a ESM module. */ 86 | type?: "module" | "classic"; 87 | } 88 | 89 | /** Options which can be set when using the {@linkcode transpile} function. */ 90 | export interface TranspileOptions { 91 | /** Allow remote modules to be loaded or read from the cache. */ 92 | allowRemote?: boolean; 93 | /** The cache root to use, overriding the default inferred `DENO_DIR`. */ 94 | cacheRoot?: string; 95 | /** The setting to use when loading sources from the Deno cache. */ 96 | cacheSetting?: CacheSetting; 97 | /** Compiler options which can be set when transpiling. */ 98 | compilerOptions?: CompilerOptions; 99 | /** An [import-map](https://docs.deno.com/runtime/manual/basics/import_maps) 100 | * which will be applied to the imports, or the URL of an import map, or the 101 | * path to an import map */ 102 | importMap?: ImportMap | URL | string; 103 | /** Override the default loading mechanism with a custom loader. This can 104 | * provide a way to use "in-memory" resources instead of fetching them 105 | * remotely. */ 106 | load?: FetchCacher["load"]; 107 | //type?: "module" | "classic"; 108 | } 109 | 110 | export interface CompilerOptions { 111 | checkJs?: boolean; 112 | /** Whether to use TypeScript's experimental decorators. */ 113 | experimentalDecorators?: boolean; 114 | /** Determines if reflection meta data is emitted for legacy decorators or 115 | * not. Defaults to `false`. */ 116 | emitDecoratorMetadata?: boolean; 117 | importsNotUsedAsValues?: string; 118 | /** When set, instead of writing out a `.js.map` file to provide source maps, 119 | * the source map will be embedded the source map content in the `.js` files. 120 | * 121 | * Although this results in larger JS files, it can be convenient in some 122 | * scenarios. For example, you might want to debug JS files on a webserver 123 | * that doesn’t allow `.map` files to be served. */ 124 | inlineSourceMap?: boolean; 125 | /** When set, the original content of the `.ts` file as an embedded string in 126 | * the source map (using the source map’s `sourcesContent` property). 127 | * 128 | * This is often useful in the same cases as `inlineSourceMap`. */ 129 | inlineSources?: boolean; 130 | /** Controls how JSX constructs are emitted in JavaScript files. This only 131 | * affects output of JS files that started in `.jsx` or `.tsx` files. */ 132 | jsx?: 133 | | "precompile" 134 | | "preserve" 135 | | "react-jsx" 136 | | "react-jsxdev" 137 | | "react-native" 138 | | "react"; 139 | /** Changes the function called in `.js` files when compiling JSX Elements 140 | * using the classic JSX runtime. The most common change is to use `"h"` or 141 | * `"preact.h"`. */ 142 | jsxFactory?: string; 143 | /** Specify the JSX fragment factory function to use when targeting react JSX 144 | * emit with jsxFactory compiler option is specified, e.g. `Fragment`. */ 145 | jsxFragmentFactory?: string; 146 | /** The string module specifier to implicitly import JSX factories from when 147 | * transpiling JSX. */ 148 | jsxImportSource?: string; 149 | /** Enables the generation of sourcemap files. */ 150 | sourceMap?: boolean; 151 | } 152 | 153 | /** Generate a single file JavaScript bundle of the root module and its 154 | * dependencies. 155 | * 156 | * ### Example 157 | * 158 | * ```ts 159 | * import { bundle } from "jsr:@deno/emit"; 160 | * const result = await bundle( 161 | * "https://deno.land/std@0.140.0/examples/chat/server.ts", 162 | * ); 163 | * 164 | * const { code } = result; 165 | * console.log(code); 166 | * ``` 167 | * 168 | * @param root The root module specifier to use for the bundle. 169 | * @param options Options to use when bundling. 170 | * @returns a promise which resolves with the emitted bundle (and optional 171 | * source map) 172 | */ 173 | export async function bundle( 174 | root: string | URL, 175 | options: BundleOptions = {}, 176 | ): Promise { 177 | const { 178 | allowRemote, 179 | cacheRoot, 180 | cacheSetting, 181 | compilerOptions, 182 | importMap, 183 | load, 184 | minify, 185 | type, 186 | } = options; 187 | 188 | checkCompilerOptions(compilerOptions); 189 | 190 | let bundleLoad = load; 191 | if (!bundleLoad) { 192 | const cache = createCache({ root: cacheRoot, cacheSetting, allowRemote }); 193 | bundleLoad = cache.load; 194 | } 195 | const { bundle: jsBundle } = await instantiate(); 196 | const result = await jsBundle( 197 | locationToUrl(root).toString(), 198 | (specifier: string, options: { 199 | isDynamic: boolean; 200 | cacheSetting: CacheSetting; 201 | checksum: string | undefined; 202 | }) => { 203 | return bundleLoad!( 204 | specifier, 205 | options.isDynamic, 206 | options.cacheSetting, 207 | options.checksum, 208 | ).then((result) => { 209 | if (result?.kind === "module") { 210 | if (typeof result.content === "string") { 211 | result.content = encoder.encode(result.content); 212 | } 213 | // need to convert to an array for serde_wasm_bindgen to work 214 | // deno-lint-ignore no-explicit-any 215 | (result as any).content = Array.from(result.content); 216 | } 217 | return result; 218 | }); 219 | }, 220 | type, 221 | await processImportMapInput(importMap, bundleLoad), 222 | compilerOptions, 223 | minify ?? false, 224 | ); 225 | return { 226 | code: result.code, 227 | map: result.map ?? undefined, 228 | }; 229 | } 230 | 231 | /** Transpile TypeScript (or JavaScript) into JavaScript, returning a promise 232 | * which resolves with a map of the emitted files. 233 | * 234 | * @param root The root module specifier to use for the bundle. 235 | * @param options Options to use when emitting. 236 | * @returns A promise which resolves with a map of the emitted files, 237 | * where the key is the emitted files name and the value is the 238 | * source for the file. 239 | */ 240 | export async function transpile( 241 | root: string | URL, 242 | options: TranspileOptions = {}, 243 | ): Promise> { 244 | const { 245 | allowRemote, 246 | cacheSetting, 247 | cacheRoot, 248 | compilerOptions, 249 | importMap, 250 | load, 251 | } = options; 252 | 253 | checkCompilerOptions(compilerOptions); 254 | 255 | let transpileLoad = load; 256 | if (!transpileLoad) { 257 | const cache = createCache({ root: cacheRoot, cacheSetting, allowRemote }); 258 | transpileLoad = cache.load; 259 | } 260 | const { transpile: jsTranspile } = await instantiate(); 261 | return jsTranspile( 262 | locationToUrl(root).toString(), 263 | (specifier: string, isDynamic: boolean, cacheSetting: CacheSetting) => { 264 | return transpileLoad!(specifier, isDynamic, cacheSetting).then( 265 | (result) => { 266 | if (result?.kind === "module") { 267 | if (typeof result.content === "string") { 268 | result.content = encoder.encode(result.content); 269 | } 270 | // need to convert to an array for serde_wasm_bindgen to work 271 | // deno-lint-ignore no-explicit-any 272 | (result as any).content = Array.from(result.content); 273 | } 274 | return result; 275 | }, 276 | ); 277 | }, 278 | await processImportMapInput(importMap, transpileLoad), 279 | compilerOptions, 280 | ); 281 | } 282 | 283 | function checkCompilerOptions( 284 | compilerOptions: CompilerOptions | undefined, 285 | ): void { 286 | if (compilerOptions === undefined) { 287 | return; 288 | } 289 | if (compilerOptions.inlineSourceMap && compilerOptions.sourceMap) { 290 | throw new Error( 291 | "Option 'sourceMap' cannot be specified with option 'inlineSourceMap'", 292 | ); 293 | } 294 | if ( 295 | compilerOptions.inlineSources && 296 | !(compilerOptions.inlineSourceMap || compilerOptions.sourceMap) 297 | ) { 298 | throw new Error( 299 | "Option 'inlineSources' can only be used when either option 'inlineSourceMap' or option 'sourceMap' is provided", 300 | ); 301 | } 302 | } 303 | 304 | /** 305 | * Transforms the import map input to the format that The Rust lib expects , 306 | * i.e. all locations are resolved to file URLs and the import map content is 307 | * serialized to JSON. 308 | * @param importMap The import map as provided to the JS API. 309 | * @returns The import map that must be provided to the Rust API. 310 | */ 311 | async function processImportMapInput( 312 | importMap: ImportMapJsLibInput, 313 | load: FetchCacher["load"], 314 | ): Promise { 315 | if (typeof importMap === "string" || importMap instanceof URL) { 316 | importMap = locationToUrl(importMap); 317 | const data = await load(importMap.toString(), false, "use"); 318 | if (data == null) { 319 | return undefined; 320 | } 321 | switch (data.kind) { 322 | case "module": { 323 | return { 324 | baseUrl: importMap.toString(), 325 | jsonString: data.content instanceof Uint8Array 326 | ? new TextDecoder().decode(data.content) 327 | : data.content, 328 | }; 329 | } 330 | case "external": 331 | throw new Error("External import maps are not supported."); 332 | case "redirect": 333 | throw new Error("Redirects are not supported for import maps."); 334 | default: { 335 | const _assertNever: never = data; 336 | throw new Error("Unexpected kind."); 337 | } 338 | } 339 | } else if (typeof importMap === "object") { 340 | const { baseUrl, imports, scopes } = importMap; 341 | const url = locationToUrl(baseUrl ?? Deno.cwd()); 342 | // Rust lib expects url to be the file URL to the import map file, but the 343 | // JS API expects it to be the file URL to the root directory, so we need to 344 | // append an extra slash. 345 | if (!url.pathname.endsWith("/")) { 346 | url.pathname += "/"; 347 | } 348 | return { 349 | baseUrl: url.toString(), 350 | jsonString: JSON.stringify({ imports, scopes }), 351 | }; 352 | } else { 353 | return undefined; 354 | } 355 | } 356 | 357 | type ImportMapJsLibInput = 358 | | BundleOptions["importMap"] 359 | | TranspileOptions["importMap"]; 360 | 361 | type ImportMapRustLibInput = 362 | | { 363 | baseUrl: string; 364 | jsonString: string; 365 | } 366 | | undefined; 367 | --------------------------------------------------------------------------------