From cddfff0fa5a137b1ecc860b60d453b9eeb334930 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Mon, 13 May 2024 19:03:31 -0400 Subject: [PATCH] feat: support expando properties (#575) --- Cargo.lock | 13 +- Cargo.toml | 4 +- src/parser.rs | 123 +++++++++++++-- src/ts_type.rs | 8 +- src/ts_type_param.rs | 1 + src/variable.rs | 10 +- tests/html_test.rs | 2 + tests/specs/expando_props/basic.txt | 173 +++++++++++++++++++++ tests/specs/infer_variable.txt | 230 ++++++++++++++++------------ tests/specs_test.rs | 16 +- 10 files changed, 440 insertions(+), 140 deletions(-) create mode 100644 tests/specs/expando_props/basic.txt diff --git a/Cargo.lock b/Cargo.lock index cce2845a..1911c54b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -502,9 +502,9 @@ dependencies = [ [[package]] name = "deno_ast" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffefe28ebd657419ab0f7fbf4ab9cd4ae38d55c2a0e4fe1661c76d7fa2b81ba" +checksum = "7e2417aad5382d10d035e46d35f2f5fbbb93a922816408245ee585e7ca775194" dependencies = [ "anyhow", "base64", @@ -594,9 +594,9 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.74.0" +version = "0.75.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f5fa7d6a74edd749de34216fa52aad7af6b4e47b321cc7e91e38b9a7a2bb48" +checksum = "09ca91da7bab6d6be790d408b7c9d6b420aa4514f7ff76ad76e523fce8a2fa9e" dependencies = [ "anyhow", "async-trait", @@ -756,10 +756,11 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "file_test_runner" -version = "0.2.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13bacb20a988be248a13adc6011bce718648f78d4684d4dd0444d05256f4a7b" +checksum = "b8797fcdc5c6b8c06839900c30f5c59b3541ef2bec218579470ce7b1afc17ee9" dependencies = [ + "anyhow", "crossbeam-channel", "deno_terminal", "parking_lot", diff --git a/Cargo.toml b/Cargo.toml index 20dd614a..b45519aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/denoland/deno_doc" members = ["lib"] [workspace.dependencies] -deno_graph = { version = "0.74.0", default-features = false, features = ["symbols"] } +deno_graph = { version = "0.75.1", default-features = false, features = ["symbols"] } import_map = "0.19.0" serde = { version = "1.0.140", features = ["derive"] } @@ -67,7 +67,7 @@ anyhow = { version = "1.0.58" } clap = "2.33.3" console_static_text = "0.8.2" criterion = { version = "0.4.0", features = ["async_futures", "html_reports"] } -file_test_runner = "0.2.0" +file_test_runner = "0.7.0" tokio = { version = "1.25.0", features = ["full"] } pretty_assertions = "1.0.0" insta = "1.38.0" diff --git a/src/parser.rs b/src/parser.rs index b10956e6..d82b9c0e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -8,6 +8,7 @@ use crate::node::DeclarationKind; use crate::node::DocNode; use crate::node::ModuleDoc; use crate::node::NamespaceDef; +use crate::ts_type::infer_simple_ts_type_from_init; use crate::ts_type::PropertyDef; use crate::ts_type::TsTypeDef; use crate::ts_type::TsTypeDefKind; @@ -48,8 +49,10 @@ use deno_ast::swc::ast::VarDeclKind; use deno_ast::swc::ast::VarDeclarator; use deno_ast::ParsedSource; use deno_ast::SourceRange; +use deno_ast::SourceRanged; use deno_ast::SourceRangedForSpanned; use deno_graph::symbols::EsModuleInfo; +use deno_graph::symbols::ExpandoPropertyRef; use deno_graph::symbols::ExportDeclRef; use deno_graph::symbols::ModuleInfoRef; use deno_graph::symbols::Symbol; @@ -281,12 +284,12 @@ impl<'a> DocParser<'a> { if first_def.module.specifier() != module_info.specifier() { for definition in definitions { let decl = definition.symbol_decl; - let maybe_doc = self.doc_for_maybe_node( + let maybe_docs = self.docs_for_maybe_node( definition.module, definition.symbol, decl.maybe_node(), ); - if let Some(mut doc_node) = maybe_doc { + for mut doc_node in maybe_docs { doc_node.name = export_name.clone(); doc_node.declaration_kind = DeclarationKind::Export; @@ -370,6 +373,32 @@ impl<'a> DocParser<'a> { Ok(imports) } + fn get_doc_for_expando_property( + &self, + source: &ParsedSource, + expando_property: ExpandoPropertyRef, + ) -> Option { + let location = + get_location(source, expando_property.prop_name_range().start()); + let ts_type = infer_simple_ts_type_from_init( + source, + Some(expando_property.assignment()), + /* is const */ true, + ); + let js_doc = js_doc_for_range(source, &expando_property.inner().range())?; + + Some(DocNode::variable( + expando_property.prop_name().to_string(), + location, + DeclarationKind::Declare, + js_doc, + VariableDef { + ts_type, + kind: VarDeclKind::Const, + }, + )) + } + fn get_doc_for_var_declarator_ident( &self, module_info: &EsModuleInfo, @@ -565,12 +594,12 @@ impl<'a> DocParser<'a> { continue; } - let maybe_doc = self.doc_for_maybe_node( + let maybe_docs = self.docs_for_maybe_node( definition.module, definition.symbol, definition.symbol_decl.maybe_node(), ); - if let Some(mut doc_node) = maybe_doc { + for mut doc_node in maybe_docs { doc_node.name = export_name.to_string(); doc_node.declaration_kind = DeclarationKind::Export; @@ -624,9 +653,9 @@ impl<'a> DocParser<'a> { .is_none()); let mut doc_nodes = Vec::with_capacity(child_symbol.decls().len()); for decl in child_symbol.decls() { - if let Some(mut doc_node) = - self.doc_for_maybe_node(module_info, child_symbol, decl.maybe_node()) - { + let maybe_docs = + self.docs_for_maybe_node(module_info, child_symbol, decl.maybe_node()); + for mut doc_node in maybe_docs { let is_declared = decl .maybe_node() .map(|node| self.get_declare_for_symbol_node(node)) @@ -966,12 +995,12 @@ impl<'a> DocParser<'a> { continue; } handled_symbols.insert(definition.symbol.unique_id()); - let maybe_doc = self.doc_for_maybe_node( + let maybe_docs = self.docs_for_maybe_node( definition.module, definition.symbol, definition.symbol_decl.maybe_node(), ); - if let Some(mut doc_node) = maybe_doc { + for mut doc_node in maybe_docs { doc_node.name = export_name.clone(); doc_node.declaration_kind = DeclarationKind::Export; @@ -1002,12 +1031,13 @@ impl<'a> DocParser<'a> { doc_nodes } - fn doc_for_maybe_node( + fn docs_for_maybe_node( &self, module_info: ModuleInfoRef, symbol: &Symbol, maybe_node: Option>, - ) -> Option { + ) -> Vec { + let mut docs = Vec::with_capacity(2); let maybe_doc = match module_info { ModuleInfoRef::Json(module_info) => parse_json_module_doc_node( module_info.specifier(), @@ -1022,11 +1052,74 @@ impl<'a> DocParser<'a> { } }; - if maybe_doc.is_some() { + if let Some(doc) = maybe_doc { + docs.push(doc); + self.check_private_type_in_public_diagnostic(module_info, symbol); + + if let Some(node) = maybe_node { + if node.is_function() { + // find any expando properties for this function symbol + if let Some(expando_namespace) = self + .maybe_expando_property_namespace_doc(&docs[0], module_info, symbol) + { + docs.push(expando_namespace); + } + } + } } - maybe_doc + docs + } + + fn maybe_expando_property_namespace_doc( + &self, + func_doc: &DocNode, + module_info: ModuleInfoRef, + symbol: &Symbol, + ) -> Option { + let expando_properties = symbol.exports().iter().flat_map(|(name, id)| { + let symbol = module_info.symbol(*id).unwrap(); + symbol + .decls() + .iter() + .filter_map(move |n| match n.maybe_node() { + Some(SymbolNodeRef::ExpandoProperty(n)) => Some((name, n)), + _ => None, + }) + }); + let elements = expando_properties + .flat_map(|(name, n)| { + let mut docs = self.docs_for_maybe_node( + module_info, + symbol, + Some(SymbolNodeRef::ExpandoProperty(n)), + ); + for doc in &mut docs { + doc.name = name.clone(); + doc.declaration_kind = DeclarationKind::Declare; + } + docs + }) + .map(Arc::new) + .collect::>(); + if elements.is_empty() { + return None; + } + Some(DocNode::namespace( + func_doc.name.clone(), + elements[0].location.clone(), + DeclarationKind::Declare, + // give this a JS doc to prevent a missing JS doc diagnostic + JsDoc { + doc: Some(format!( + "Additional properties on the `{}` function.", + func_doc.name + )), + tags: vec![], + }, + NamespaceDef { elements }, + )) } fn check_private_type_in_public_diagnostic( @@ -1092,6 +1185,9 @@ impl<'a> DocParser<'a> { SymbolNodeRef::ClassDecl(n) => { self.get_doc_for_class_decl(parsed_source, n, &n.class.range()) } + SymbolNodeRef::ExpandoProperty(n) => { + self.get_doc_for_expando_property(parsed_source, n) + } SymbolNodeRef::ExportDefaultDecl(n) => { self.get_doc_for_export_default_decl(parsed_source, n) } @@ -1195,6 +1291,7 @@ impl<'a> DocParser<'a> { | SymbolNodeRef::ClassMethod(_) | SymbolNodeRef::ClassProp(_) | SymbolNodeRef::ClassParamProp(_) + | SymbolNodeRef::ExpandoProperty(_) | SymbolNodeRef::Constructor(_) | SymbolNodeRef::TsIndexSignature(_) | SymbolNodeRef::TsCallSignatureDecl(_) diff --git a/src/ts_type.rs b/src/ts_type.rs index a304b246..b7572b47 100644 --- a/src/ts_type.rs +++ b/src/ts_type.rs @@ -1597,13 +1597,13 @@ pub fn infer_ts_type_from_expr( } } -pub fn infer_simple_ts_type_from_var_decl( +pub fn infer_simple_ts_type_from_init( parsed_source: &ParsedSource, - decl: &VarDeclarator, + init: Option<&Expr>, is_const: bool, ) -> Option { - if let Some(init_expr) = &decl.init { - infer_ts_type_from_expr(parsed_source, init_expr.as_ref(), is_const) + if let Some(init_expr) = init { + infer_ts_type_from_expr(parsed_source, init_expr, is_const) } else { None } diff --git a/src/ts_type_param.rs b/src/ts_type_param.rs index 5b45d932..576a471d 100644 --- a/src/ts_type_param.rs +++ b/src/ts_type_param.rs @@ -1,4 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + use crate::ts_type::TsTypeDef; use deno_ast::swc::ast::TsTypeParam; use deno_ast::swc::ast::TsTypeParamDecl; diff --git a/src/variable.rs b/src/variable.rs index bf2b95cf..fa25f482 100644 --- a/src/variable.rs +++ b/src/variable.rs @@ -8,7 +8,7 @@ use deno_graph::symbols::SymbolNodeRef; use serde::Deserialize; use serde::Serialize; -use crate::ts_type::infer_simple_ts_type_from_var_decl; +use crate::ts_type::infer_simple_ts_type_from_init; use crate::ts_type::TsTypeDef; use crate::ts_type::TsTypeDefKind; @@ -60,9 +60,9 @@ pub fn get_docs_for_var_declarator( } } } - let maybe_type_ann = infer_simple_ts_type_from_var_decl( + let maybe_type_ann = infer_simple_ts_type_from_init( module_info.source(), - var_declarator, + var_declarator.init.as_deref(), var_decl.kind == VarDeclKind::Const, ); if let Some(type_ann) = maybe_type_ann { @@ -76,9 +76,9 @@ pub fn get_docs_for_var_declarator( } }) .or_else(|| { - infer_simple_ts_type_from_var_decl( + infer_simple_ts_type_from_init( module_info.source(), - var_declarator, + var_declarator.init.as_deref(), var_decl.kind == VarDeclKind::Const, ) }); diff --git a/tests/html_test.rs b/tests/html_test.rs index 7f407395..be92a2f1 100644 --- a/tests/html_test.rs +++ b/tests/html_test.rs @@ -1,3 +1,5 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + use deno_ast::ModuleSpecifier; use deno_doc::html::pages::SymbolPage; use deno_doc::html::*; diff --git a/tests/specs/expando_props/basic.txt b/tests/specs/expando_props/basic.txt new file mode 100644 index 00000000..3237ddb6 --- /dev/null +++ b/tests/specs/expando_props/basic.txt @@ -0,0 +1,173 @@ +# mod.ts +/** Testing */ +export function test() { +} + +/** doc1 */ +test.skip = (param: string): void => { +}; + +/** doc2 */ +test.textProp = "asdf"; + +/** doc3 */ +test.booleanProp = true; + +# output.txt +Defined in file:///mod.ts:2:1 + +function test(): void + Testing + +Defined in file:///mod.ts:6:6 + +namespace test + Additional properties on the `test` function. + + const skip: (param: string) => void + doc1 + const textProp: "asdf" + doc2 + const booleanProp: true + doc3 + + +# output.json +[ + { + "kind": "function", + "name": "test", + "location": { + "filename": "file:///mod.ts", + "line": 2, + "col": 0, + "byteIndex": 15 + }, + "declarationKind": "export", + "jsDoc": { + "doc": "Testing" + }, + "functionDef": { + "params": [], + "returnType": { + "repr": "void", + "kind": "keyword", + "keyword": "void" + }, + "hasBody": true, + "isAsync": false, + "isGenerator": false, + "typeParams": [] + } + }, + { + "kind": "namespace", + "name": "test", + "location": { + "filename": "file:///mod.ts", + "line": 6, + "col": 5, + "byteIndex": 60 + }, + "declarationKind": "export", + "jsDoc": { + "doc": "Additional properties on the `test` function." + }, + "namespaceDef": { + "elements": [ + { + "kind": "variable", + "name": "skip", + "location": { + "filename": "file:///mod.ts", + "line": 6, + "col": 5, + "byteIndex": 60 + }, + "declarationKind": "declare", + "jsDoc": { + "doc": "doc1" + }, + "variableDef": { + "tsType": { + "repr": "", + "kind": "fnOrConstructor", + "fnOrConstructor": { + "constructor": false, + "tsType": { + "repr": "void", + "kind": "keyword", + "keyword": "void" + }, + "params": [ + { + "kind": "identifier", + "name": "param", + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" + } + } + ], + "typeParams": [] + } + }, + "kind": "const" + } + }, + { + "kind": "variable", + "name": "textProp", + "location": { + "filename": "file:///mod.ts", + "line": 10, + "col": 5, + "byteIndex": 115 + }, + "declarationKind": "declare", + "jsDoc": { + "doc": "doc2" + }, + "variableDef": { + "tsType": { + "repr": "asdf", + "kind": "literal", + "literal": { + "kind": "string", + "string": "asdf" + } + }, + "kind": "const" + } + }, + { + "kind": "variable", + "name": "booleanProp", + "location": { + "filename": "file:///mod.ts", + "line": 13, + "col": 5, + "byteIndex": 152 + }, + "declarationKind": "declare", + "jsDoc": { + "doc": "doc3" + }, + "variableDef": { + "tsType": { + "repr": "true", + "kind": "literal", + "literal": { + "kind": "boolean", + "boolean": true + } + }, + "kind": "const" + } + } + ] + } + } +] diff --git a/tests/specs/infer_variable.txt b/tests/specs/infer_variable.txt index 81dc2853..d787db05 100644 --- a/tests/specs/infer_variable.txt +++ b/tests/specs/infer_variable.txt @@ -1,126 +1,82 @@ # mod.ts +/** doc1 */ export let a = (0); +/** doc2 */ export const b = a++; +/** doc3 */ export const c = 1; +/** doc4 */ export const d = 1 as string; +/** doc5 */ export const e = await 1; +/** doc6 */ export const f = true ? "a" : 1; +/** doc7 */ export const g = (true ? "a" : null)!; +/** doc8 */ export const h = null!; +/** doc9 */ export const i = 1 == "bar"; +/** doc10 */ export const j = 1 >> 1; - -# diagnostics -error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:1:12 - | -1 | export let a = (0); - | ^ - - -error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:2:14 - | -2 | export const b = a++; - | ^ - - -error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:3:14 - | -3 | export const c = 1; - | ^ - - -error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:4:14 - | -4 | export const d = 1 as string; - | ^ - - -error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:5:14 - | -5 | export const e = await 1; - | ^ - - -error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:6:14 - | -6 | export const f = true ? "a" : 1; - | ^ - - -error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:7:14 - | -7 | export const g = (true ? "a" : null)!; - | ^ - - -error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:8:14 - | -8 | export const h = null!; - | ^ - - -error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:9:14 - | -9 | export const i = 1 == "bar"; - | ^ - - -error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:10:14 - | -10 | export const j = 1 >> 1; - | ^ - +/** doc11 */ +export const k = (value: string) => 1; # output.txt -Defined in file:///mod.ts:1:12 +Defined in file:///mod.ts:2:12 let a: number + doc1 -Defined in file:///mod.ts:2:14 +Defined in file:///mod.ts:4:14 const b: number + doc2 -Defined in file:///mod.ts:3:14 +Defined in file:///mod.ts:6:14 const c: string + doc3 -Defined in file:///mod.ts:4:14 +Defined in file:///mod.ts:8:14 const d: string + doc4 -Defined in file:///mod.ts:5:14 +Defined in file:///mod.ts:10:14 const e: 1 + doc5 -Defined in file:///mod.ts:6:14 +Defined in file:///mod.ts:12:14 const f: "a" | 1 + doc6 -Defined in file:///mod.ts:7:14 +Defined in file:///mod.ts:14:14 const g: "a" + doc7 -Defined in file:///mod.ts:8:14 +Defined in file:///mod.ts:16:14 const h: never + doc8 -Defined in file:///mod.ts:9:14 +Defined in file:///mod.ts:18:14 const i: boolean + doc9 -Defined in file:///mod.ts:10:14 +Defined in file:///mod.ts:20:14 const j: number + doc10 + +Defined in file:///mod.ts:22:14 + +const k: (value: string) => unknown + doc11 # output.json @@ -130,11 +86,14 @@ const j: number "name": "a", "location": { "filename": "file:///mod.ts", - "line": 1, + "line": 2, "col": 11, - "byteIndex": 11 + "byteIndex": 23 }, "declarationKind": "export", + "jsDoc": { + "doc": "doc1" + }, "variableDef": { "tsType": { "repr": "number", @@ -149,11 +108,14 @@ const j: number "name": "b", "location": { "filename": "file:///mod.ts", - "line": 2, + "line": 4, "col": 13, - "byteIndex": 33 + "byteIndex": 57 }, "declarationKind": "export", + "jsDoc": { + "doc": "doc2" + }, "variableDef": { "tsType": { "repr": "number", @@ -168,11 +130,14 @@ const j: number "name": "c", "location": { "filename": "file:///mod.ts", - "line": 3, + "line": 6, "col": 13, - "byteIndex": 55 + "byteIndex": 91 }, "declarationKind": "export", + "jsDoc": { + "doc": "doc3" + }, "variableDef": { "tsType": { "repr": "string", @@ -187,11 +152,14 @@ const j: number "name": "d", "location": { "filename": "file:///mod.ts", - "line": 4, + "line": 8, "col": 13, - "byteIndex": 84 + "byteIndex": 132 }, "declarationKind": "export", + "jsDoc": { + "doc": "doc4" + }, "variableDef": { "tsType": { "repr": "string", @@ -206,11 +174,14 @@ const j: number "name": "e", "location": { "filename": "file:///mod.ts", - "line": 5, + "line": 10, "col": 13, - "byteIndex": 114 + "byteIndex": 174 }, "declarationKind": "export", + "jsDoc": { + "doc": "doc5" + }, "variableDef": { "tsType": { "repr": "1", @@ -228,11 +199,14 @@ const j: number "name": "f", "location": { "filename": "file:///mod.ts", - "line": 6, + "line": 12, "col": 13, - "byteIndex": 140 + "byteIndex": 212 }, "declarationKind": "export", + "jsDoc": { + "doc": "doc6" + }, "variableDef": { "tsType": { "repr": "", @@ -264,11 +238,14 @@ const j: number "name": "g", "location": { "filename": "file:///mod.ts", - "line": 7, + "line": 14, "col": 13, - "byteIndex": 173 + "byteIndex": 257 }, "declarationKind": "export", + "jsDoc": { + "doc": "doc7" + }, "variableDef": { "tsType": { "repr": "a", @@ -286,11 +263,14 @@ const j: number "name": "h", "location": { "filename": "file:///mod.ts", - "line": 8, + "line": 16, "col": 13, - "byteIndex": 212 + "byteIndex": 308 }, "declarationKind": "export", + "jsDoc": { + "doc": "doc8" + }, "variableDef": { "tsType": { "repr": "never", @@ -305,11 +285,14 @@ const j: number "name": "i", "location": { "filename": "file:///mod.ts", - "line": 9, + "line": 18, "col": 13, - "byteIndex": 236 + "byteIndex": 344 }, "declarationKind": "export", + "jsDoc": { + "doc": "doc9" + }, "variableDef": { "tsType": { "repr": "boolean", @@ -324,11 +307,14 @@ const j: number "name": "j", "location": { "filename": "file:///mod.ts", - "line": 10, + "line": 20, "col": 13, - "byteIndex": 265 + "byteIndex": 386 }, "declarationKind": "export", + "jsDoc": { + "doc": "doc10" + }, "variableDef": { "tsType": { "repr": "number", @@ -337,5 +323,47 @@ const j: number }, "kind": "const" } + }, + { + "kind": "variable", + "name": "k", + "location": { + "filename": "file:///mod.ts", + "line": 22, + "col": 13, + "byteIndex": 424 + }, + "declarationKind": "export", + "jsDoc": { + "doc": "doc11" + }, + "variableDef": { + "tsType": { + "repr": "", + "kind": "fnOrConstructor", + "fnOrConstructor": { + "constructor": false, + "tsType": { + "repr": "unknown", + "kind": "keyword", + "keyword": "unknown" + }, + "params": [ + { + "kind": "identifier", + "name": "value", + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" + } + } + ], + "typeParams": [] + } + }, + "kind": "const" + } } ] diff --git a/tests/specs_test.rs b/tests/specs_test.rs index d6df2a18..8ce8aa6d 100644 --- a/tests/specs_test.rs +++ b/tests/specs_test.rs @@ -1,16 +1,15 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use std::panic::AssertUnwindSafe; -use std::sync::Arc; use deno_ast::diagnostics::Diagnostic; use deno_doc::DocNode; use deno_graph::source::Source; use deno_graph::ModuleSpecifier; use file_test_runner::collect_and_run_tests; -use file_test_runner::CollectOptions; -use file_test_runner::CollectedTest; -use file_test_runner::FileCollectionStrategy; +use file_test_runner::collection::strategies::TestPerFileCollectionStrategy; +use file_test_runner::collection::CollectOptions; +use file_test_runner::collection::CollectedTest; use file_test_runner::RunOptions; use file_test_runner::TestResult; use indexmap::IndexMap; @@ -27,16 +26,15 @@ fn main() { collect_and_run_tests( CollectOptions { base: "tests/specs".into(), - strategy: FileCollectionStrategy::TestPerFile { file_pattern: None }, - root_category_name: "specs".to_string(), + strategy: Box::new(TestPerFileCollectionStrategy { file_pattern: None }), filter_override: None, }, RunOptions { parallel: true }, - Arc::new(|test| { + |test| { TestResult::from_maybe_panic(AssertUnwindSafe(|| { run_test(test); })) - }), + }, ) }