summaryrefslogtreecommitdiff
path: root/cli/tools/vendor/build.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools/vendor/build.rs')
-rw-r--r--cli/tools/vendor/build.rs1330
1 files changed, 0 insertions, 1330 deletions
diff --git a/cli/tools/vendor/build.rs b/cli/tools/vendor/build.rs
deleted file mode 100644
index a4424e3f3..000000000
--- a/cli/tools/vendor/build.rs
+++ /dev/null
@@ -1,1330 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-use std::fmt::Write as _;
-use std::path::Path;
-use std::sync::Arc;
-
-use deno_ast::ModuleSpecifier;
-use deno_core::anyhow::bail;
-use deno_core::anyhow::Context;
-use deno_core::error::AnyError;
-use deno_core::futures::future::LocalBoxFuture;
-use deno_graph::source::ResolutionMode;
-use deno_graph::JsModule;
-use deno_graph::Module;
-use deno_graph::ModuleGraph;
-use deno_runtime::deno_fs;
-use import_map::ImportMap;
-use import_map::SpecifierMap;
-
-use crate::args::JsxImportSourceConfig;
-use crate::cache::ParsedSourceCache;
-use crate::graph_util;
-use crate::tools::vendor::import_map::BuildImportMapInput;
-
-use super::analyze::has_default_export;
-use super::import_map::build_import_map;
-use super::mappings::Mappings;
-use super::mappings::ProxiedModule;
-use super::specifiers::is_remote_specifier;
-
-/// Allows substituting the environment for testing purposes.
-pub trait VendorEnvironment {
- fn create_dir_all(&self, dir_path: &Path) -> Result<(), AnyError>;
- fn write_file(&self, file_path: &Path, bytes: &[u8]) -> Result<(), AnyError>;
-}
-
-pub struct RealVendorEnvironment;
-
-impl VendorEnvironment for RealVendorEnvironment {
- fn create_dir_all(&self, dir_path: &Path) -> Result<(), AnyError> {
- Ok(std::fs::create_dir_all(dir_path)?)
- }
-
- fn write_file(&self, file_path: &Path, bytes: &[u8]) -> Result<(), AnyError> {
- std::fs::write(file_path, bytes)
- .with_context(|| format!("Failed writing {}", file_path.display()))
- }
-}
-
-type BuildGraphFuture = LocalBoxFuture<'static, Result<ModuleGraph, AnyError>>;
-
-pub struct BuildInput<
- 'a,
- TBuildGraphFn: FnOnce(Vec<ModuleSpecifier>) -> BuildGraphFuture,
- TEnvironment: VendorEnvironment,
-> {
- pub entry_points: Vec<ModuleSpecifier>,
- pub build_graph: TBuildGraphFn,
- pub parsed_source_cache: &'a ParsedSourceCache,
- pub output_dir: &'a Path,
- pub maybe_original_import_map: Option<&'a ImportMap>,
- pub maybe_jsx_import_source: Option<&'a JsxImportSourceConfig>,
- pub resolver: &'a dyn deno_graph::source::Resolver,
- pub environment: &'a TEnvironment,
-}
-
-pub struct BuildOutput {
- pub vendored_count: usize,
- pub graph: ModuleGraph,
-}
-
-/// Vendors remote modules and returns how many were vendored.
-pub async fn build<
- TBuildGraphFn: FnOnce(Vec<ModuleSpecifier>) -> BuildGraphFuture,
- TEnvironment: VendorEnvironment,
->(
- input: BuildInput<'_, TBuildGraphFn, TEnvironment>,
-) -> Result<BuildOutput, AnyError> {
- let BuildInput {
- mut entry_points,
- build_graph,
- parsed_source_cache,
- output_dir,
- maybe_original_import_map,
- maybe_jsx_import_source,
- resolver,
- environment,
- } = input;
- assert!(output_dir.is_absolute());
- let output_dir_specifier =
- ModuleSpecifier::from_directory_path(output_dir).unwrap();
-
- if let Some(original_im) = &maybe_original_import_map {
- validate_original_import_map(original_im, &output_dir_specifier)?;
- }
-
- // add the jsx import source to the entry points to ensure it is always vendored
- if let Some(jsx_import_source) = maybe_jsx_import_source {
- if let Some(specifier_text) = jsx_import_source.maybe_specifier_text() {
- if let Ok(specifier) = resolver.resolve(
- &specifier_text,
- &deno_graph::Range {
- specifier: jsx_import_source.base_url.clone(),
- start: deno_graph::Position::zeroed(),
- end: deno_graph::Position::zeroed(),
- },
- ResolutionMode::Execution,
- ) {
- entry_points.push(specifier);
- }
- }
- }
-
- let graph = build_graph(entry_points).await?;
-
- // surface any errors
- let real_fs = Arc::new(deno_fs::RealFs) as Arc<dyn deno_fs::FileSystem>;
- graph_util::graph_valid(
- &graph,
- &real_fs,
- &graph.roots.iter().cloned().collect::<Vec<_>>(),
- graph_util::GraphValidOptions {
- is_vendoring: true,
- check_js: true,
- follow_type_only: true,
- exit_lockfile_errors: true,
- },
- )?;
-
- // figure out how to map remote modules to local
- let all_modules = graph.modules().collect::<Vec<_>>();
- let remote_modules = all_modules
- .iter()
- .filter(|m| is_remote_specifier(m.specifier()))
- .copied()
- .collect::<Vec<_>>();
- let mappings =
- Mappings::from_remote_modules(&graph, &remote_modules, output_dir)?;
-
- // write out all the files
- for module in &remote_modules {
- let source = match module {
- Module::Js(module) => &module.source,
- Module::Json(module) => &module.source,
- Module::Node(_) | Module::Npm(_) | Module::External(_) => continue,
- };
- let specifier = module.specifier();
- let local_path = mappings
- .proxied_path(specifier)
- .unwrap_or_else(|| mappings.local_path(specifier));
-
- environment.create_dir_all(local_path.parent().unwrap())?;
- environment.write_file(&local_path, source.as_bytes())?;
- }
-
- // write out the proxies
- for (specifier, proxied_module) in mappings.proxied_modules() {
- let proxy_path = mappings.local_path(specifier);
- let module = graph.get(specifier).unwrap().js().unwrap();
- let text =
- build_proxy_module_source(module, proxied_module, parsed_source_cache)?;
-
- environment.write_file(&proxy_path, text.as_bytes())?;
- }
-
- // create the import map if necessary
- if !remote_modules.is_empty() {
- let import_map_path = output_dir.join("import_map.json");
- let import_map_text = build_import_map(BuildImportMapInput {
- base_dir: &output_dir_specifier,
- graph: &graph,
- modules: &all_modules,
- mappings: &mappings,
- maybe_original_import_map,
- maybe_jsx_import_source,
- resolver,
- parsed_source_cache,
- })?;
- environment.write_file(&import_map_path, import_map_text.as_bytes())?;
- }
-
- Ok(BuildOutput {
- vendored_count: remote_modules.len(),
- graph,
- })
-}
-
-fn validate_original_import_map(
- import_map: &ImportMap,
- output_dir: &ModuleSpecifier,
-) -> Result<(), AnyError> {
- fn validate_imports(
- imports: &SpecifierMap,
- output_dir: &ModuleSpecifier,
- ) -> Result<(), AnyError> {
- for entry in imports.entries() {
- if let Some(value) = entry.value {
- if value.as_str().starts_with(output_dir.as_str()) {
- bail!(
- "Providing an existing import map with entries for the output directory is not supported (\"{}\": \"{}\").",
- entry.raw_key,
- entry.raw_value.unwrap_or("<INVALID>"),
- );
- }
- }
- }
- Ok(())
- }
-
- validate_imports(import_map.imports(), output_dir)?;
-
- for scope in import_map.scopes() {
- if scope.key.starts_with(output_dir.as_str()) {
- bail!(
- "Providing an existing import map with a scope for the output directory is not supported (\"{}\").",
- scope.raw_key,
- );
- }
- validate_imports(scope.imports, output_dir)?;
- }
-
- Ok(())
-}
-
-fn build_proxy_module_source(
- module: &JsModule,
- proxied_module: &ProxiedModule,
- parsed_source_cache: &ParsedSourceCache,
-) -> Result<String, AnyError> {
- let mut text = String::new();
- writeln!(
- text,
- "// @deno-types=\"{}\"",
- proxied_module.declaration_specifier
- )
- .unwrap();
-
- let relative_specifier = format!(
- "./{}",
- proxied_module
- .output_path
- .file_name()
- .unwrap()
- .to_string_lossy()
- );
-
- // for simplicity, always include the `export *` statement as it won't error
- // even when the module does not contain a named export
- writeln!(text, "export * from \"{relative_specifier}\";").unwrap();
-
- // add a default export if one exists in the module
- let parsed_source =
- parsed_source_cache.get_parsed_source_from_js_module(module)?;
- if has_default_export(&parsed_source) {
- writeln!(text, "export {{ default }} from \"{relative_specifier}\";")
- .unwrap();
- }
-
- Ok(text)
-}
-
-#[cfg(test)]
-mod test {
- use crate::args::JsxImportSourceConfig;
- use crate::tools::vendor::test::VendorTestBuilder;
- use deno_core::serde_json::json;
- use pretty_assertions::assert_eq;
-
- #[tokio::test]
- async fn no_remote_modules() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "");
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(output.import_map, None,);
- assert_eq!(output.files, vec![],);
- }
-
- #[tokio::test]
- async fn local_specifiers_to_remote() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader
- .add(
- "/mod.ts",
- concat!(
- r#"import "https://localhost/mod.ts";"#,
- r#"import "https://localhost/other.ts?test";"#,
- r#"import "https://localhost/redirect.ts";"#,
- ),
- )
- .add("https://localhost/mod.ts", "export class Mod {}")
- .add("https://localhost/other.ts?test", "export class Other {}")
- .add_redirect(
- "https://localhost/redirect.ts",
- "https://localhost/mod.ts",
- );
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/other.ts?test": "./localhost/other.ts",
- "https://localhost/redirect.ts": "./localhost/mod.ts",
- "https://localhost/": "./localhost/",
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- ("/vendor/localhost/mod.ts", "export class Mod {}"),
- ("/vendor/localhost/other.ts", "export class Other {}"),
- ]),
- );
- }
-
- #[tokio::test]
- async fn remote_specifiers() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader
- .add(
- "/mod.ts",
- concat!(
- r#"import "https://localhost/mod.ts";"#,
- r#"import "https://other/mod.ts";"#,
- ),
- )
- .add(
- "https://localhost/mod.ts",
- concat!(
- "export * from './other.ts';",
- "export * from './redirect.ts';",
- "export * from '/absolute.ts';",
- ),
- )
- .add("https://localhost/other.ts", "export class Other {}")
- .add_redirect(
- "https://localhost/redirect.ts",
- "https://localhost/other.ts",
- )
- .add("https://localhost/absolute.ts", "export class Absolute {}")
- .add("https://other/mod.ts", "export * from './sub/mod.ts';")
- .add(
- "https://other/sub/mod.ts",
- concat!(
- "export * from '../sub2/mod.ts';",
- "export * from '../sub2/other?asdf';",
- // reference a path on a different origin
- "export * from 'https://localhost/other.ts';",
- "export * from 'https://localhost/redirect.ts';",
- ),
- )
- .add("https://other/sub2/mod.ts", "export class Mod {}")
- .add_with_headers(
- "https://other/sub2/other?asdf",
- "export class Other {}",
- &[("content-type", "application/javascript")],
- );
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/": "./localhost/",
- "https://localhost/redirect.ts": "./localhost/other.ts",
- "https://other/": "./other/",
- },
- "scopes": {
- "./localhost/": {
- "./localhost/redirect.ts": "./localhost/other.ts",
- "/absolute.ts": "./localhost/absolute.ts",
- },
- "./other/": {
- "./other/sub2/other?asdf": "./other/sub2/other.js"
- }
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- ("/vendor/localhost/absolute.ts", "export class Absolute {}"),
- (
- "/vendor/localhost/mod.ts",
- concat!(
- "export * from './other.ts';",
- "export * from './redirect.ts';",
- "export * from '/absolute.ts';",
- )
- ),
- ("/vendor/localhost/other.ts", "export class Other {}"),
- ("/vendor/other/mod.ts", "export * from './sub/mod.ts';"),
- (
- "/vendor/other/sub/mod.ts",
- concat!(
- "export * from '../sub2/mod.ts';",
- "export * from '../sub2/other?asdf';",
- "export * from 'https://localhost/other.ts';",
- "export * from 'https://localhost/redirect.ts';",
- )
- ),
- ("/vendor/other/sub2/mod.ts", "export class Mod {}"),
- ("/vendor/other/sub2/other.js", "export class Other {}"),
- ]),
- );
- }
-
- #[tokio::test]
- async fn remote_redirect_entrypoint() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader
- .add(
- "/mod.ts",
- concat!(
- "import * as test from 'https://x.nest.land/Yenv@1.0.0/mod.ts';\n",
- "console.log(test)",
- ),
- )
- .add_redirect("https://x.nest.land/Yenv@1.0.0/mod.ts", "https://arweave.net/VFtWNW3QZ-7__v7c7kck22eFI24OuK1DFzyQHKoZ9AE/mod.ts")
- .add(
- "https://arweave.net/VFtWNW3QZ-7__v7c7kck22eFI24OuK1DFzyQHKoZ9AE/mod.ts",
- "export * from './src/mod.ts'",
- )
- .add(
- "https://arweave.net/VFtWNW3QZ-7__v7c7kck22eFI24OuK1DFzyQHKoZ9AE/src/mod.ts",
- "export class Test {}",
- );
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://x.nest.land/Yenv@1.0.0/mod.ts": "./arweave.net/VFtWNW3QZ-7__v7c7kck22eFI24OuK1DFzyQHKoZ9AE/mod.ts",
- "https://arweave.net/": "./arweave.net/"
- },
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- ("/vendor/arweave.net/VFtWNW3QZ-7__v7c7kck22eFI24OuK1DFzyQHKoZ9AE/mod.ts", "export * from './src/mod.ts'"),
- (
- "/vendor/arweave.net/VFtWNW3QZ-7__v7c7kck22eFI24OuK1DFzyQHKoZ9AE/src/mod.ts",
- "export class Test {}",
- ),
- ]),
- );
- }
-
- #[tokio::test]
- async fn same_target_filename_specifiers() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader
- .add(
- "/mod.ts",
- concat!(
- r#"import "https://localhost/MOD.TS";"#,
- r#"import "https://localhost/mod.TS";"#,
- r#"import "https://localhost/mod.ts";"#,
- r#"import "https://localhost/mod.ts?test";"#,
- r#"import "https://localhost/CAPS.TS";"#,
- ),
- )
- .add("https://localhost/MOD.TS", "export class Mod {}")
- .add("https://localhost/mod.TS", "export class Mod2 {}")
- .add("https://localhost/mod.ts", "export class Mod3 {}")
- .add("https://localhost/mod.ts?test", "export class Mod4 {}")
- .add("https://localhost/CAPS.TS", "export class Caps {}");
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/mod.TS": "./localhost/mod_2.TS",
- "https://localhost/mod.ts": "./localhost/mod_3.ts",
- "https://localhost/mod.ts?test": "./localhost/mod_4.ts",
- "https://localhost/": "./localhost/",
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- ("/vendor/localhost/CAPS.TS", "export class Caps {}"),
- ("/vendor/localhost/MOD.TS", "export class Mod {}"),
- ("/vendor/localhost/mod_2.TS", "export class Mod2 {}"),
- ("/vendor/localhost/mod_3.ts", "export class Mod3 {}"),
- ("/vendor/localhost/mod_4.ts", "export class Mod4 {}"),
- ]),
- );
- }
-
- #[tokio::test]
- async fn multiple_entrypoints() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .add_entry_point("/test.deps.ts")
- .with_loader(|loader| {
- loader
- .add("/mod.ts", r#"import "https://localhost/mod.ts";"#)
- .add(
- "/test.deps.ts",
- r#"export * from "https://localhost/test.ts";"#,
- )
- .add("https://localhost/mod.ts", "export class Mod {}")
- .add("https://localhost/test.ts", "export class Test {}");
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/": "./localhost/",
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- ("/vendor/localhost/mod.ts", "export class Mod {}"),
- ("/vendor/localhost/test.ts", "export class Test {}"),
- ]),
- );
- }
-
- #[tokio::test]
- async fn json_module() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader
- .add(
- "/mod.ts",
- r#"import data from "https://localhost/data.json" assert { type: "json" };"#,
- )
- .add("https://localhost/data.json", "{ \"a\": \"b\" }");
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/": "./localhost/"
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[("/vendor/localhost/data.json", "{ \"a\": \"b\" }"),]),
- );
- }
-
- #[tokio::test]
- async fn data_urls() {
- let mut builder = VendorTestBuilder::with_default_setup();
-
- let mod_file_text = r#"import * as b from "data:application/typescript,export%20*%20from%20%22https://localhost/mod.ts%22;";"#;
-
- let output = builder
- .with_loader(|loader| {
- loader
- .add("/mod.ts", mod_file_text)
- .add("https://localhost/mod.ts", "export class Example {}");
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/": "./localhost/"
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[("/vendor/localhost/mod.ts", "export class Example {}"),]),
- );
- }
-
- #[tokio::test]
- async fn x_typescript_types_no_default() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader
- .add("/mod.ts", r#"import "https://localhost/mod.js";"#)
- .add_with_headers(
- "https://localhost/mod.js",
- "export class Mod {}",
- &[("x-typescript-types", "https://localhost/mod.d.ts")],
- )
- .add("https://localhost/mod.d.ts", "export class Mod {}");
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/": "./localhost/"
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- ("/vendor/localhost/mod.d.ts", "export class Mod {}"),
- (
- "/vendor/localhost/mod.js",
- concat!(
- "// @deno-types=\"https://localhost/mod.d.ts\"\n",
- "export * from \"./mod.proxied.js\";\n"
- )
- ),
- ("/vendor/localhost/mod.proxied.js", "export class Mod {}"),
- ]),
- );
- }
-
- #[tokio::test]
- async fn x_typescript_types_default_export() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader
- .add("/mod.ts", r#"import "https://localhost/mod.js";"#)
- .add_with_headers(
- "https://localhost/mod.js",
- "export default class Mod {}",
- &[("x-typescript-types", "https://localhost/mod.d.ts")],
- )
- .add("https://localhost/mod.d.ts", "export default class Mod {}");
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/": "./localhost/"
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- ("/vendor/localhost/mod.d.ts", "export default class Mod {}"),
- (
- "/vendor/localhost/mod.js",
- concat!(
- "// @deno-types=\"https://localhost/mod.d.ts\"\n",
- "export * from \"./mod.proxied.js\";\n",
- "export { default } from \"./mod.proxied.js\";\n",
- )
- ),
- (
- "/vendor/localhost/mod.proxied.js",
- "export default class Mod {}"
- ),
- ]),
- );
- }
-
- #[tokio::test]
- async fn subdir() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader
- .add(
- "/mod.ts",
- r#"import "http://localhost:4545/sub/logger/mod.ts?testing";"#,
- )
- .add(
- "http://localhost:4545/sub/logger/mod.ts?testing",
- "export * from './logger.ts?test';",
- )
- .add(
- "http://localhost:4545/sub/logger/logger.ts?test",
- "export class Logger {}",
- );
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "http://localhost:4545/sub/logger/mod.ts?testing": "./localhost_4545/sub/logger/mod.ts",
- "http://localhost:4545/": "./localhost_4545/",
- },
- "scopes": {
- "./localhost_4545/": {
- "./localhost_4545/sub/logger/logger.ts?test": "./localhost_4545/sub/logger/logger.ts"
- }
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- (
- "/vendor/localhost_4545/sub/logger/logger.ts",
- "export class Logger {}",
- ),
- (
- "/vendor/localhost_4545/sub/logger/mod.ts",
- "export * from './logger.ts?test';"
- ),
- ]),
- );
- }
-
- #[tokio::test]
- async fn same_origin_absolute_with_redirect() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader
- .add(
- "/mod.ts",
- r#"import "https://localhost/subdir/sub/mod.ts";"#,
- )
- .add(
- "https://localhost/subdir/sub/mod.ts",
- "import 'https://localhost/std/hash/mod.ts'",
- )
- .add_redirect(
- "https://localhost/std/hash/mod.ts",
- "https://localhost/std@0.1.0/hash/mod.ts",
- )
- .add(
- "https://localhost/std@0.1.0/hash/mod.ts",
- "export class Test {}",
- );
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/std/hash/mod.ts": "./localhost/std@0.1.0/hash/mod.ts",
- "https://localhost/": "./localhost/",
- },
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- (
- "/vendor/localhost/std@0.1.0/hash/mod.ts",
- "export class Test {}"
- ),
- (
- "/vendor/localhost/subdir/sub/mod.ts",
- "import 'https://localhost/std/hash/mod.ts'"
- ),
- ]),
- );
- }
-
- #[tokio::test]
- async fn remote_relative_specifier_with_scheme_like_folder_name() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let output = builder
- .with_loader(|loader| {
- loader
- .add("/mod.ts", "import 'https://localhost/mod.ts';")
- .add(
- "https://localhost/mod.ts",
- "import './npm:test@1.0.0/test/test!cjs?test';import './npm:test@1.0.0/mod.ts';",
- )
- .add(
- "https://localhost/npm:test@1.0.0/mod.ts",
- "console.log(4);",
- )
- .add_with_headers(
- "https://localhost/npm:test@1.0.0/test/test!cjs?test",
- "console.log(5);",
- &[("content-type", "application/javascript")],
- );
- })
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/": "./localhost/"
- },
- "scopes": {
- "./localhost/": {
- "./localhost/npm:test@1.0.0/mod.ts": "./localhost/npm_test@1.0.0/mod.ts",
- "./localhost/npm:test@1.0.0/test/test!cjs?test": "./localhost/npm_test@1.0.0/test/test!cjs.js",
- "./localhost/npm_test@1.0.0/test/test!cjs?test": "./localhost/npm_test@1.0.0/test/test!cjs.js"
- }
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- (
- "/vendor/localhost/mod.ts",
- "import './npm:test@1.0.0/test/test!cjs?test';import './npm:test@1.0.0/mod.ts';"
- ),
- ("/vendor/localhost/npm_test@1.0.0/mod.ts", "console.log(4);"),
- (
- "/vendor/localhost/npm_test@1.0.0/test/test!cjs.js",
- "console.log(5);"
- ),
- ]),
- );
- }
-
- #[tokio::test]
- async fn existing_import_map_basic() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let mut original_import_map = builder.new_import_map("/import_map2.json");
- original_import_map
- .imports_mut()
- .append(
- "https://localhost/mod.ts".to_string(),
- "./local_vendor/mod.ts".to_string(),
- )
- .unwrap();
- let local_vendor_scope = original_import_map
- .get_or_append_scope_mut("./local_vendor/")
- .unwrap();
- local_vendor_scope
- .append(
- "https://localhost/logger.ts".to_string(),
- "./local_vendor/logger.ts".to_string(),
- )
- .unwrap();
- local_vendor_scope
- .append(
- "/console_logger.ts".to_string(),
- "./local_vendor/console_logger.ts".to_string(),
- )
- .unwrap();
-
- let output = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "import 'https://localhost/mod.ts'; import 'https://localhost/other.ts';");
- loader.add("/local_vendor/mod.ts", "import 'https://localhost/logger.ts'; import '/console_logger.ts'; console.log(5);");
- loader.add("/local_vendor/logger.ts", "export class Logger {}");
- loader.add("/local_vendor/console_logger.ts", "export class ConsoleLogger {}");
- loader.add("https://localhost/mod.ts", "console.log(6);");
- loader.add("https://localhost/other.ts", "import './mod.ts';");
- })
- .set_original_import_map(original_import_map)
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/mod.ts": "../local_vendor/mod.ts",
- "https://localhost/": "./localhost/"
- },
- "scopes": {
- "../local_vendor/": {
- "https://localhost/logger.ts": "../local_vendor/logger.ts",
- "/console_logger.ts": "../local_vendor/console_logger.ts",
- },
- "./localhost/": {
- "./localhost/mod.ts": "../local_vendor/mod.ts",
- },
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[("/vendor/localhost/other.ts", "import './mod.ts';")]),
- );
- }
-
- #[tokio::test]
- async fn existing_import_map_remote_dep_bare_specifier() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let mut original_import_map = builder.new_import_map("/import_map2.json");
- original_import_map
- .imports_mut()
- .append(
- "twind".to_string(),
- "https://localhost/twind.ts".to_string(),
- )
- .unwrap();
-
- let output = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "import 'https://remote/mod.ts';");
- loader.add("https://remote/mod.ts", "import 'twind';");
- loader.add("https://localhost/twind.ts", "export class Test {}");
- })
- .set_original_import_map(original_import_map)
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/": "./localhost/",
- "https://remote/": "./remote/"
- },
- "scopes": {
- "./remote/": {
- "twind": "./localhost/twind.ts"
- },
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- ("/vendor/localhost/twind.ts", "export class Test {}"),
- ("/vendor/remote/mod.ts", "import 'twind';"),
- ]),
- );
- }
-
- #[tokio::test]
- async fn existing_import_map_mapped_bare_specifier() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let mut original_import_map = builder.new_import_map("/import_map.json");
- let imports = original_import_map.imports_mut();
- imports
- .append("$fresh".to_string(), "https://localhost/fresh".to_string())
- .unwrap();
- imports
- .append("std/".to_string(), "https://deno.land/std/".to_string())
- .unwrap();
- let output = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "import 'std/mod.ts'; import '$fresh';");
- loader.add("https://deno.land/std/mod.ts", "export function test() {}");
- loader.add_with_headers(
- "https://localhost/fresh",
- "export function fresh() {}",
- &[("content-type", "application/typescript")],
- );
- })
- .set_original_import_map(original_import_map)
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://deno.land/": "./deno.land/",
- "https://localhost/": "./localhost/",
- "$fresh": "./localhost/fresh.ts",
- "std/mod.ts": "./deno.land/std/mod.ts",
- },
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- ("/vendor/deno.land/std/mod.ts", "export function test() {}"),
- ("/vendor/localhost/fresh.ts", "export function fresh() {}")
- ]),
- );
- }
-
- #[tokio::test]
- async fn existing_import_map_remote_absolute_specifier_local() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let mut original_import_map = builder.new_import_map("/import_map.json");
- original_import_map
- .imports_mut()
- .append(
- "https://localhost/logger.ts?test".to_string(),
- "./local/logger.ts".to_string(),
- )
- .unwrap();
-
- let output = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "import 'https://localhost/mod.ts'; import 'https://localhost/logger.ts?test';");
- loader.add("/local/logger.ts", "export class Logger {}");
- // absolute specifier in a remote module that will point at ./local/logger.ts
- loader.add("https://localhost/mod.ts", "import '/logger.ts?test';");
- loader.add("https://localhost/logger.ts?test", "export class Logger {}");
- })
- .set_original_import_map(original_import_map)
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/logger.ts?test": "../local/logger.ts",
- "https://localhost/": "./localhost/",
- },
- "scopes": {
- "./localhost/": {
- "/logger.ts?test": "../local/logger.ts",
- },
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[("/vendor/localhost/mod.ts", "import '/logger.ts?test';")]),
- );
- }
-
- #[tokio::test]
- async fn existing_import_map_imports_output_dir() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let mut original_import_map = builder.new_import_map("/import_map.json");
- original_import_map
- .imports_mut()
- .append(
- "std/mod.ts".to_string(),
- "./vendor/deno.land/std/mod.ts".to_string(),
- )
- .unwrap();
- let err = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "import 'std/mod.ts';");
- loader.add("/vendor/deno.land/std/mod.ts", "export function f() {}");
- loader.add("https://deno.land/std/mod.ts", "export function f() {}");
- })
- .set_original_import_map(original_import_map)
- .build()
- .await
- .err()
- .unwrap();
-
- assert_eq!(
- err.to_string(),
- concat!(
- "Providing an existing import map with entries for the output ",
- "directory is not supported ",
- "(\"std/mod.ts\": \"./vendor/deno.land/std/mod.ts\").",
- )
- );
- }
-
- #[tokio::test]
- async fn existing_import_map_scopes_entry_output_dir() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let mut original_import_map = builder.new_import_map("/import_map.json");
- let scopes = original_import_map
- .get_or_append_scope_mut("./other/")
- .unwrap();
- scopes
- .append("/mod.ts".to_string(), "./vendor/mod.ts".to_string())
- .unwrap();
- let err = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "console.log(5);");
- })
- .set_original_import_map(original_import_map)
- .build()
- .await
- .err()
- .unwrap();
-
- assert_eq!(
- err.to_string(),
- concat!(
- "Providing an existing import map with entries for the output ",
- "directory is not supported ",
- "(\"/mod.ts\": \"./vendor/mod.ts\").",
- )
- );
- }
-
- #[tokio::test]
- async fn existing_import_map_scopes_key_output_dir() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let mut original_import_map = builder.new_import_map("/import_map.json");
- let scopes = original_import_map
- .get_or_append_scope_mut("./vendor/")
- .unwrap();
- scopes
- .append("/mod.ts".to_string(), "./vendor/mod.ts".to_string())
- .unwrap();
- let err = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "console.log(5);");
- })
- .set_original_import_map(original_import_map)
- .build()
- .await
- .err()
- .unwrap();
-
- assert_eq!(
- err.to_string(),
- concat!(
- "Providing an existing import map with a scope for the output ",
- "directory is not supported (\"./vendor/\").",
- )
- );
- }
-
- #[tokio::test]
- async fn existing_import_map_http_key() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let mut original_import_map = builder.new_import_map("/import_map.json");
- original_import_map
- .imports_mut()
- .append(
- "http/".to_string(),
- "https://deno.land/std/http/".to_string(),
- )
- .unwrap();
- let output = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "import 'http/mod.ts';");
- loader.add("https://deno.land/std/http/mod.ts", "console.log(5);");
- })
- .set_original_import_map(original_import_map)
- .build()
- .await
- .unwrap();
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "http/mod.ts": "./deno.land/std/http/mod.ts",
- "https://deno.land/": "./deno.land/",
- }
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[("/vendor/deno.land/std/http/mod.ts", "console.log(5);")]),
- );
- }
-
- #[tokio::test]
- async fn existing_import_map_jsx_import_source_jsx_files() {
- let mut builder = VendorTestBuilder::default();
- builder.add_entry_point("/mod.tsx");
- builder.set_jsx_import_source_config(JsxImportSourceConfig {
- default_specifier: Some("preact".to_string()),
- default_types_specifier: None,
- module: "jsx-runtime".to_string(),
- base_url: builder.resolve_to_url("/deno.json"),
- });
- let mut original_import_map = builder.new_import_map("/import_map.json");
- let imports = original_import_map.imports_mut();
- imports
- .append(
- "preact/".to_string(),
- "https://localhost/preact/".to_string(),
- )
- .unwrap();
- let output = builder
- .with_loader(|loader| {
- loader.add("/mod.tsx", "const myComponent = <div></div>;");
- loader.add_with_headers(
- "https://localhost/preact/jsx-runtime",
- "export function stuff() {}",
- &[("content-type", "application/typescript")],
- );
- })
- .set_original_import_map(original_import_map)
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/": "./localhost/",
- "preact/jsx-runtime": "./localhost/preact/jsx-runtime.ts",
- },
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[(
- "/vendor/localhost/preact/jsx-runtime.ts",
- "export function stuff() {}"
- ),]),
- );
- }
-
- #[tokio::test]
- async fn existing_import_map_jsx_import_source_no_jsx_files() {
- let mut builder = VendorTestBuilder::default();
- builder.add_entry_point("/mod.ts");
- builder.set_jsx_import_source_config(JsxImportSourceConfig {
- default_specifier: Some("preact".to_string()),
- default_types_specifier: None,
- module: "jsx-runtime".to_string(),
- base_url: builder.resolve_to_url("/deno.json"),
- });
- let mut original_import_map = builder.new_import_map("/import_map.json");
- let imports = original_import_map.imports_mut();
- imports
- .append(
- "preact/".to_string(),
- "https://localhost/preact/".to_string(),
- )
- .unwrap();
- let output = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "import 'https://localhost/mod.ts';");
- loader.add("https://localhost/mod.ts", "console.log(1)");
- loader.add_with_headers(
- "https://localhost/preact/jsx-runtime",
- "export function stuff() {}",
- &[("content-type", "application/typescript")],
- );
- })
- .set_original_import_map(original_import_map)
- .build()
- .await
- .unwrap();
-
- assert_eq!(
- output.import_map,
- Some(json!({
- "imports": {
- "https://localhost/": "./localhost/",
- "preact/jsx-runtime": "./localhost/preact/jsx-runtime.ts"
- },
- }))
- );
- assert_eq!(
- output.files,
- to_file_vec(&[
- ("/vendor/localhost/mod.ts", "console.log(1)"),
- (
- "/vendor/localhost/preact/jsx-runtime.ts",
- "export function stuff() {}"
- ),
- ]),
- );
- }
-
- #[tokio::test]
- async fn vendor_file_fails_loading_dynamic_import() {
- let mut builder = VendorTestBuilder::with_default_setup();
- let err = builder
- .with_loader(|loader| {
- loader.add("/mod.ts", "import 'https://localhost/mod.ts';");
- loader.add("https://localhost/mod.ts", "await import('./test.ts');");
- loader.add_failure(
- "https://localhost/test.ts",
- "500 Internal Server Error",
- );
- })
- .build()
- .await
- .err()
- .unwrap();
-
- assert_eq!(
- test_util::strip_ansi_codes(&err.to_string()),
- concat!(
- "500 Internal Server Error\n",
- " at https://localhost/mod.ts:1:14"
- )
- );
- }
-
- fn to_file_vec(items: &[(&str, &str)]) -> Vec<(String, String)> {
- items
- .iter()
- .map(|(f, t)| (f.to_string(), t.to_string()))
- .collect()
- }
-}