feat(doc): support multiple file entry (#21018)

This commit adds support for multiple entry points to `deno doc`.

Unfortunately to achieve that, I had to change the semantics of the
command to explicitly require `--filter` parameter for filtering
symbols, instead of treating second free argument as the filter argument.

`deno doc --builtin` is still supported, but cannot be mixed with
actual entrypoints.
This commit is contained in:
Bartek Iwańczuk 2023-10-30 23:58:57 +01:00 committed by GitHub
parent b75f3b5ca0
commit 48c5c3a3fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 33 deletions

View file

@ -96,7 +96,7 @@ pub struct CoverageFlags {
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DocSourceFileFlag {
Builtin,
Path(String),
Paths(Vec<String>),
}
impl Default for DocSourceFileFlag {
@ -109,7 +109,7 @@ impl Default for DocSourceFileFlag {
pub struct DocFlags {
pub private: bool,
pub json: bool,
pub source_file: DocSourceFileFlag,
pub source_files: DocSourceFileFlag,
pub filter: Option<String>,
}
@ -1356,17 +1356,23 @@ Show documentation for runtime built-ins:
.help("Output private documentation")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("filter")
.long("filter")
.help("Dot separated path to symbol")
.required(false)
.conflicts_with("json"),
)
// TODO(nayeemrmn): Make `--builtin` a proper option. Blocked by
// https://github.com/clap-rs/clap/issues/1794. Currently `--builtin` is
// just a possible value of `source_file` so leading hyphens must be
// enabled.
.allow_hyphen_values(true)
.arg(Arg::new("source_file").value_hint(ValueHint::FilePath))
.arg(
Arg::new("filter")
.help("Dot separated path to symbol")
.required(false)
.conflicts_with("json"),
Arg::new("source_file")
.num_args(1..)
.action(ArgAction::Append)
.value_hint(ValueHint::FilePath),
)
})
}
@ -3090,21 +3096,29 @@ fn doc_parse(flags: &mut Flags, matches: &mut ArgMatches) {
no_npm_arg_parse(flags, matches);
no_remote_arg_parse(flags, matches);
let source_file = matches
.remove_one::<String>("source_file")
.map(|value| {
if value == "--builtin" {
let source_files_val = matches.remove_many::<String>("source_file");
let source_files = if let Some(val) = source_files_val {
let vals: Vec<String> = val.collect();
if vals.len() == 1 {
if vals[0] == "--builtin" {
DocSourceFileFlag::Builtin
} else {
DocSourceFileFlag::Path(value)
DocSourceFileFlag::Paths(vec![vals[0].to_string()])
}
})
.unwrap_or_default();
} else {
DocSourceFileFlag::Paths(
vals.into_iter().filter(|v| v != "--builtin").collect(),
)
}
} else {
DocSourceFileFlag::Builtin
};
let private = matches.get_flag("private");
let json = matches.get_flag("json");
let filter = matches.remove_one::<String>("filter");
flags.subcommand = DenoSubcommand::Doc(DocFlags {
source_file,
source_files,
json,
filter,
private,
@ -5918,7 +5932,7 @@ mod tests {
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Doc(DocFlags {
source_file: DocSourceFileFlag::Path("script.ts".to_owned()),
source_files: DocSourceFileFlag::Paths(vec!["script.ts".to_owned()]),
private: false,
json: false,
filter: None,
@ -7178,7 +7192,9 @@ mod tests {
subcommand: DenoSubcommand::Doc(DocFlags {
private: false,
json: true,
source_file: DocSourceFileFlag::Path("path/to/module.ts".to_string()),
source_files: DocSourceFileFlag::Paths(vec![
"path/to/module.ts".to_string()
]),
filter: None,
}),
..Flags::default()
@ -7188,8 +7204,9 @@ mod tests {
let r = flags_from_vec(svec![
"deno",
"doc",
"--filter",
"SomeClass.someField",
"path/to/module.ts",
"SomeClass.someField"
]);
assert_eq!(
r.unwrap(),
@ -7197,7 +7214,9 @@ mod tests {
subcommand: DenoSubcommand::Doc(DocFlags {
private: false,
json: false,
source_file: DocSourceFileFlag::Path("path/to/module.ts".to_string()),
source_files: DocSourceFileFlag::Paths(vec![
"path/to/module.ts".to_string()
]),
filter: Some("SomeClass.someField".to_string()),
}),
..Flags::default()
@ -7211,21 +7230,27 @@ mod tests {
subcommand: DenoSubcommand::Doc(DocFlags {
private: false,
json: false,
source_file: Default::default(),
source_files: Default::default(),
filter: None,
}),
..Flags::default()
}
);
let r = flags_from_vec(svec!["deno", "doc", "--builtin", "Deno.Listener"]);
let r = flags_from_vec(svec![
"deno",
"doc",
"--filter",
"Deno.Listener",
"--builtin"
]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Doc(DocFlags {
private: false,
json: false,
source_file: DocSourceFileFlag::Builtin,
source_files: DocSourceFileFlag::Builtin,
filter: Some("Deno.Listener".to_string()),
}),
..Flags::default()
@ -7246,7 +7271,9 @@ mod tests {
subcommand: DenoSubcommand::Doc(DocFlags {
private: true,
json: false,
source_file: DocSourceFileFlag::Path("path/to/module.js".to_string()),
source_files: DocSourceFileFlag::Paths(vec![
"path/to/module.js".to_string()
]),
filter: None,
}),
no_npm: true,
@ -7254,6 +7281,51 @@ mod tests {
..Flags::default()
}
);
let r = flags_from_vec(svec![
"deno",
"doc",
"path/to/module.js",
"path/to/module2.js"
]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Doc(DocFlags {
private: false,
json: false,
source_files: DocSourceFileFlag::Paths(vec![
"path/to/module.js".to_string(),
"path/to/module2.js".to_string()
]),
filter: None,
}),
..Flags::default()
}
);
let r = flags_from_vec(svec![
"deno",
"doc",
"path/to/module.js",
"--builtin",
"path/to/module2.js"
]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Doc(DocFlags {
private: false,
json: false,
source_files: DocSourceFileFlag::Paths(vec![
"path/to/module.js".to_string(),
"path/to/module2.js".to_string()
]),
filter: None,
}),
..Flags::default()
}
);
}
#[test]

View file

@ -17,12 +17,13 @@ fn deno_doc() {
let output = context
.new_command()
.env("NO_COLOR", "1")
.args("doc doc/deno_doc.ts")
.args("doc doc/deno_doc.ts doc/deno_doc2.ts")
.split_output()
.run();
output.assert_exit_code(0);
assert_contains!(output.stdout(), "function foo");
assert_contains!(output.stdout(), "function bar");
}
}
@ -54,7 +55,7 @@ itest!(deno_doc_referenced_private_types {
itest!(_060_deno_doc_displays_all_overloads_in_details_view {
args:
"doc doc/060_deno_doc_displays_all_overloads_in_details_view.ts NS.test",
"doc --filter NS.test doc/060_deno_doc_displays_all_overloads_in_details_view.ts",
output: "doc/060_deno_doc_displays_all_overloads_in_details_view.ts.out",
});

3
cli/tests/testdata/doc/deno_doc2.ts vendored Normal file
View file

@ -0,0 +1,3 @@
/** Some JSDoc */
export function bar() {
}

View file

@ -33,7 +33,7 @@ pub async fn print_docs(
let capturing_parser =
CapturingModuleParser::new(Some(&source_parser), &store);
let mut doc_nodes = match doc_flags.source_file {
let mut doc_nodes = match doc_flags.source_files {
DocSourceFileFlag::Builtin => {
let source_file_specifier =
ModuleSpecifier::parse("internal://lib.deno.d.ts").unwrap();
@ -64,18 +64,23 @@ pub async fn print_docs(
doc::DocParser::new(&graph, doc_flags.private, capturing_parser)?;
doc_parser.parse_module(&source_file_specifier)?.definitions
}
DocSourceFileFlag::Path(source_file) => {
DocSourceFileFlag::Paths(source_files) => {
let module_graph_builder = factory.module_graph_builder().await?;
let maybe_lockfile = factory.maybe_lockfile();
let module_specifier =
resolve_url_or_path(&source_file, cli_options.initial_cwd())?;
let module_specifiers: Result<Vec<ModuleSpecifier>, AnyError> =
source_files
.iter()
.map(|source_file| {
Ok(resolve_url_or_path(source_file, cli_options.initial_cwd())?)
})
.collect();
let module_specifiers = module_specifiers?;
let mut loader = module_graph_builder.create_graph_loader();
let graph = module_graph_builder
.create_graph_with_options(CreateGraphOptions {
graph_kind: GraphKind::TypesOnly,
roots: vec![module_specifier.clone()],
roots: module_specifiers.clone(),
loader: &mut loader,
analyzer: &analyzer,
})
@ -85,8 +90,17 @@ pub async fn print_docs(
graph_lock_or_exit(&graph, &mut lockfile.lock());
}
doc::DocParser::new(&graph, doc_flags.private, capturing_parser)?
.parse_with_reexports(&module_specifier)?
let doc_parser =
doc::DocParser::new(&graph, doc_flags.private, capturing_parser)?;
let mut doc_nodes = vec![];
for module_specifier in module_specifiers {
let nodes = doc_parser.parse_with_reexports(&module_specifier)?;
doc_nodes.extend_from_slice(&nodes);
}
doc_nodes
}
};