Skip to content

Commit b98afb5

Browse files
authored
feat: deno vendor (denoland#13670)
1 parent 02c95d3 commit b98afb5

File tree

21 files changed

+2531
-12
lines changed

21 files changed

+2531
-12
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ env_logger = "=0.8.4"
6969
eszip = "=0.16.0"
7070
fancy-regex = "=0.7.1"
7171
http = "=0.2.4"
72-
import_map = "=0.8.0"
72+
import_map = "=0.9.0"
7373
jsonc-parser = { version = "=0.19.0", features = ["serde"] }
7474
libc = "=0.2.106"
7575
log = { version = "=0.4.14", features = ["serde"] }

cli/flags.rs

Lines changed: 133 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,13 @@ pub struct UpgradeFlags {
162162
pub ca_file: Option<String>,
163163
}
164164

165+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
166+
pub struct VendorFlags {
167+
pub specifiers: Vec<String>,
168+
pub output_path: Option<PathBuf>,
169+
pub force: bool,
170+
}
171+
165172
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
166173
pub enum DenoSubcommand {
167174
Bundle(BundleFlags),
@@ -182,6 +189,7 @@ pub enum DenoSubcommand {
182189
Test(TestFlags),
183190
Types,
184191
Upgrade(UpgradeFlags),
192+
Vendor(VendorFlags),
185193
}
186194

187195
impl Default for DenoSubcommand {
@@ -481,6 +489,7 @@ pub fn flags_from_vec(args: Vec<String>) -> clap::Result<Flags> {
481489
Some(("lint", m)) => lint_parse(&mut flags, m),
482490
Some(("compile", m)) => compile_parse(&mut flags, m),
483491
Some(("lsp", m)) => lsp_parse(&mut flags, m),
492+
Some(("vendor", m)) => vendor_parse(&mut flags, m),
484493
_ => handle_repl_flags(&mut flags, ReplFlags { eval: None }),
485494
}
486495

@@ -552,6 +561,7 @@ If the flag is set, restrict these messages to errors.",
552561
.subcommand(test_subcommand())
553562
.subcommand(types_subcommand())
554563
.subcommand(upgrade_subcommand())
564+
.subcommand(vendor_subcommand())
555565
.long_about(DENO_HELP)
556566
.after_help(ENV_VARIABLES_HELP)
557567
}
@@ -1413,6 +1423,52 @@ update to a different location, use the --output flag
14131423
.arg(ca_file_arg())
14141424
}
14151425

1426+
fn vendor_subcommand<'a>() -> App<'a> {
1427+
App::new("vendor")
1428+
.about("Vendor remote modules into a local directory")
1429+
.long_about(
1430+
"Vendor remote modules into a local directory.
1431+
1432+
Analyzes the provided modules along with their dependencies, downloads
1433+
remote modules to the output directory, and produces an import map that
1434+
maps remote specifiers to the downloaded files.
1435+
1436+
deno vendor main.ts
1437+
deno run --import-map vendor/import_map.json main.ts
1438+
1439+
Remote modules and multiple modules may also be specified:
1440+
1441+
deno vendor main.ts test.deps.ts https://deno.land/std/path/mod.ts",
1442+
)
1443+
.arg(
1444+
Arg::new("specifiers")
1445+
.takes_value(true)
1446+
.multiple_values(true)
1447+
.multiple_occurrences(true)
1448+
.required(true),
1449+
)
1450+
.arg(
1451+
Arg::new("output")
1452+
.long("output")
1453+
.help("The directory to output the vendored modules to")
1454+
.takes_value(true),
1455+
)
1456+
.arg(
1457+
Arg::new("force")
1458+
.long("force")
1459+
.short('f')
1460+
.help(
1461+
"Forcefully overwrite conflicting files in existing output directory",
1462+
)
1463+
.takes_value(false),
1464+
)
1465+
.arg(config_arg())
1466+
.arg(import_map_arg())
1467+
.arg(lock_arg())
1468+
.arg(reload_arg())
1469+
.arg(ca_file_arg())
1470+
}
1471+
14161472
fn compile_args(app: App) -> App {
14171473
app
14181474
.arg(import_map_arg())
@@ -2237,6 +2293,23 @@ fn upgrade_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
22372293
});
22382294
}
22392295

2296+
fn vendor_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
2297+
ca_file_arg_parse(flags, matches);
2298+
config_arg_parse(flags, matches);
2299+
import_map_arg_parse(flags, matches);
2300+
lock_arg_parse(flags, matches);
2301+
reload_arg_parse(flags, matches);
2302+
2303+
flags.subcommand = DenoSubcommand::Vendor(VendorFlags {
2304+
specifiers: matches
2305+
.values_of("specifiers")
2306+
.map(|p| p.map(ToString::to_string).collect())
2307+
.unwrap_or_default(),
2308+
output_path: matches.value_of("output").map(PathBuf::from),
2309+
force: matches.is_present("force"),
2310+
});
2311+
}
2312+
22402313
fn compile_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
22412314
import_map_arg_parse(flags, matches);
22422315
no_remote_arg_parse(flags, matches);
@@ -2443,13 +2516,17 @@ fn no_check_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
24432516
}
24442517

24452518
fn lock_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
2519+
lock_arg_parse(flags, matches);
2520+
if matches.is_present("lock-write") {
2521+
flags.lock_write = true;
2522+
}
2523+
}
2524+
2525+
fn lock_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
24462526
if matches.is_present("lock") {
24472527
let lockfile = matches.value_of("lock").unwrap();
24482528
flags.lock = Some(PathBuf::from(lockfile));
24492529
}
2450-
if matches.is_present("lock-write") {
2451-
flags.lock_write = true;
2452-
}
24532530
}
24542531

24552532
fn config_arg_parse(flags: &mut Flags, matches: &ArgMatches) {
@@ -2512,8 +2589,8 @@ mod tests {
25122589

25132590
/// Creates vector of strings, Vec<String>
25142591
macro_rules! svec {
2515-
($($x:expr),*) => (vec![$($x.to_string()),*]);
2516-
}
2592+
($($x:expr),* $(,)?) => (vec![$($x.to_string()),*]);
2593+
}
25172594

25182595
#[test]
25192596
fn global_flags() {
@@ -4895,4 +4972,55 @@ mod tests {
48954972
.contains("error: The following required arguments were not provided:"));
48964973
assert!(&error_message.contains("--watch=<FILES>..."));
48974974
}
4975+
4976+
#[test]
4977+
fn vendor_minimal() {
4978+
let r = flags_from_vec(svec!["deno", "vendor", "mod.ts",]);
4979+
assert_eq!(
4980+
r.unwrap(),
4981+
Flags {
4982+
subcommand: DenoSubcommand::Vendor(VendorFlags {
4983+
specifiers: svec!["mod.ts"],
4984+
force: false,
4985+
output_path: None,
4986+
}),
4987+
..Flags::default()
4988+
}
4989+
);
4990+
}
4991+
4992+
#[test]
4993+
fn vendor_all() {
4994+
let r = flags_from_vec(svec![
4995+
"deno",
4996+
"vendor",
4997+
"--config",
4998+
"deno.json",
4999+
"--import-map",
5000+
"import_map.json",
5001+
"--lock",
5002+
"lock.json",
5003+
"--force",
5004+
"--output",
5005+
"out_dir",
5006+
"--reload",
5007+
"mod.ts",
5008+
"deps.test.ts",
5009+
]);
5010+
assert_eq!(
5011+
r.unwrap(),
5012+
Flags {
5013+
subcommand: DenoSubcommand::Vendor(VendorFlags {
5014+
specifiers: svec!["mod.ts", "deps.test.ts"],
5015+
force: true,
5016+
output_path: Some(PathBuf::from("out_dir")),
5017+
}),
5018+
config_path: Some("deno.json".to_string()),
5019+
import_map_path: Some("import_map.json".to_string()),
5020+
lock: Some(PathBuf::from("lock.json")),
5021+
reload: true,
5022+
..Flags::default()
5023+
}
5024+
);
5025+
}
48985026
}

cli/fs_util.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,34 @@ pub fn path_has_trailing_slash(path: &Path) -> bool {
362362
}
363363
}
364364

365+
/// Gets a path with the specified file stem suffix.
366+
///
367+
/// Ex. `file.ts` with suffix `_2` returns `file_2.ts`
368+
pub fn path_with_stem_suffix(path: &Path, suffix: &str) -> PathBuf {
369+
if let Some(file_name) = path.file_name().map(|f| f.to_string_lossy()) {
370+
if let Some(file_stem) = path.file_stem().map(|f| f.to_string_lossy()) {
371+
if let Some(ext) = path.extension().map(|f| f.to_string_lossy()) {
372+
return if file_stem.to_lowercase().ends_with(".d") {
373+
path.with_file_name(format!(
374+
"{}{}.{}.{}",
375+
&file_stem[..file_stem.len() - ".d".len()],
376+
suffix,
377+
// maintain casing
378+
&file_stem[file_stem.len() - "d".len()..],
379+
ext
380+
))
381+
} else {
382+
path.with_file_name(format!("{}{}.{}", file_stem, suffix, ext))
383+
};
384+
}
385+
}
386+
387+
path.with_file_name(format!("{}{}", file_name, suffix))
388+
} else {
389+
path.with_file_name(suffix)
390+
}
391+
}
392+
365393
#[cfg(test)]
366394
mod tests {
367395
use super::*;
@@ -730,4 +758,44 @@ mod tests {
730758
assert_eq!(result, expected);
731759
}
732760
}
761+
762+
#[test]
763+
fn test_path_with_stem_suffix() {
764+
assert_eq!(
765+
path_with_stem_suffix(&PathBuf::from("/"), "_2"),
766+
PathBuf::from("/_2")
767+
);
768+
assert_eq!(
769+
path_with_stem_suffix(&PathBuf::from("/test"), "_2"),
770+
PathBuf::from("/test_2")
771+
);
772+
assert_eq!(
773+
path_with_stem_suffix(&PathBuf::from("/test.txt"), "_2"),
774+
PathBuf::from("/test_2.txt")
775+
);
776+
assert_eq!(
777+
path_with_stem_suffix(&PathBuf::from("/test/subdir"), "_2"),
778+
PathBuf::from("/test/subdir_2")
779+
);
780+
assert_eq!(
781+
path_with_stem_suffix(&PathBuf::from("/test/subdir.other.txt"), "_2"),
782+
PathBuf::from("/test/subdir.other_2.txt")
783+
);
784+
assert_eq!(
785+
path_with_stem_suffix(&PathBuf::from("/test.d.ts"), "_2"),
786+
PathBuf::from("/test_2.d.ts")
787+
);
788+
assert_eq!(
789+
path_with_stem_suffix(&PathBuf::from("/test.D.TS"), "_2"),
790+
PathBuf::from("/test_2.D.TS")
791+
);
792+
assert_eq!(
793+
path_with_stem_suffix(&PathBuf::from("/test.d.mts"), "_2"),
794+
PathBuf::from("/test_2.d.mts")
795+
);
796+
assert_eq!(
797+
path_with_stem_suffix(&PathBuf::from("/test.d.cts"), "_2"),
798+
PathBuf::from("/test_2.d.cts")
799+
);
800+
}
733801
}

cli/main.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ use crate::flags::RunFlags;
5858
use crate::flags::TestFlags;
5959
use crate::flags::UninstallFlags;
6060
use crate::flags::UpgradeFlags;
61+
use crate::flags::VendorFlags;
6162
use crate::fmt_errors::PrettyJsError;
6263
use crate::graph_util::graph_lock_or_exit;
6364
use crate::graph_util::graph_valid;
@@ -1290,6 +1291,15 @@ async fn upgrade_command(
12901291
Ok(0)
12911292
}
12921293

1294+
async fn vendor_command(
1295+
flags: Flags,
1296+
vendor_flags: VendorFlags,
1297+
) -> Result<i32, AnyError> {
1298+
let ps = ProcState::build(Arc::new(flags)).await?;
1299+
tools::vendor::vendor(ps, vendor_flags).await?;
1300+
Ok(0)
1301+
}
1302+
12931303
fn init_v8_flags(v8_flags: &[String]) {
12941304
let v8_flags_includes_help = v8_flags
12951305
.iter()
@@ -1368,6 +1378,9 @@ fn get_subcommand(
13681378
DenoSubcommand::Upgrade(upgrade_flags) => {
13691379
upgrade_command(flags, upgrade_flags).boxed_local()
13701380
}
1381+
DenoSubcommand::Vendor(vendor_flags) => {
1382+
vendor_command(flags, vendor_flags).boxed_local()
1383+
}
13711384
}
13721385
}
13731386

cli/tests/integration/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ mod run;
8484
mod test;
8585
#[path = "upgrade_tests.rs"]
8686
mod upgrade;
87+
#[path = "vendor_tests.rs"]
88+
mod vendor;
8789
#[path = "watcher_tests.rs"]
8890
mod watcher;
8991
#[path = "worker_tests.rs"]

0 commit comments

Comments
 (0)