diff --git a/src/extract/ast-extractors/extract-typescript-deps.mjs b/src/extract/ast-extractors/extract-typescript-deps.mjs index f39add30e..f768bbc19 100644 --- a/src/extract/ast-extractors/extract-typescript-deps.mjs +++ b/src/extract/ast-extractors/extract-typescript-deps.mjs @@ -8,16 +8,31 @@ const typescript = await tryImport( meta.supportedTranspilers.typescript, ); -function isTypeOnly(pStatement) { +function isTypeOnlyImport(pStatement) { + return ( + pStatement.importClause && + (pStatement.importClause.isTypeOnly || + (pStatement.importClause.namedBindings && + pStatement.importClause.namedBindings.elements && + pStatement.importClause.namedBindings.elements.every( + (pElement) => pElement.isTypeOnly, + ))) + ); +} + +function isTypeOnlyExport(pStatement) { return ( - (pStatement.importClause && pStatement.importClause.isTypeOnly) || // for some reason the isTypeOnly indicator is on _statement_ level // and not in exportClause as it is in the importClause ¯\_ (ツ)_/¯. // Also in the case of the omission of an alias the exportClause // is not there entirely. So regardless whether there is a // pStatement.exportClause or not, we can directly test for the // isTypeOnly attribute. - pStatement.isTypeOnly + pStatement.isTypeOnly || + // named reexports are per-element though + (pStatement.exportClause && + pStatement.exportClause.elements && + pStatement.exportClause.elements.every((pElement) => pElement.isTypeOnly)) ); } @@ -47,7 +62,9 @@ function extractImportsAndExports(pAST) { module: pStatement.moduleSpecifier.text, moduleSystem: "es6", exoticallyRequired: false, - ...(isTypeOnly(pStatement) ? { dependencyTypes: ["type-only"] } : {}), + ...(isTypeOnlyImport(pStatement) || isTypeOnlyExport(pStatement) + ? { dependencyTypes: ["type-only"] } + : {}), })); } diff --git a/test/extract/ast-extractors/extract-typescript-type-imports-and-exports.spec.mjs b/test/extract/ast-extractors/extract-typescript-type-imports-and-exports.spec.mjs index 721252435..1c0399a03 100644 --- a/test/extract/ast-extractors/extract-typescript-type-imports-and-exports.spec.mjs +++ b/test/extract/ast-extractors/extract-typescript-type-imports-and-exports.spec.mjs @@ -117,6 +117,37 @@ describe("[U] ast-extractors/extract-typescript - type imports and exports", () ); }); + it("extracts imports with inline type imports - only type imports", () => { + deepEqual( + extractTypescript( + "import { type slork, type klaatu } from './ts-typical';", + ), + [ + { + module: "./ts-typical", + moduleSystem: "es6", + dynamic: false, + exoticallyRequired: false, + dependencyTypes: ["type-only"], + }, + ], + ); + }); + + it("extracts imports with inline type imports - mixing type and non-type", () => { + deepEqual( + extractTypescript("import { type slork, klaatu } from './ts-typical';"), + [ + { + module: "./ts-typical", + moduleSystem: "es6", + dynamic: false, + exoticallyRequired: false, + }, + ], + ); + }); + it("extracts re-exports that explicitly state they only re-export a type", () => { deepEqual( extractTypescript("export type * as vehicles from './vehicles';"), @@ -143,4 +174,33 @@ describe("[U] ast-extractors/extract-typescript - type imports and exports", () }, ]); }); + + it("extracts re-exports with inline type re-exports - only type re-exports", () => { + deepEqual( + extractTypescript("export { type foobar, type baz } from './vehicles';"), + [ + { + module: "./vehicles", + moduleSystem: "es6", + dynamic: false, + exoticallyRequired: false, + dependencyTypes: ["type-only"], + }, + ], + ); + }); + + it("extracts re-exports with inline type re-exports - mixing type and non-type", () => { + deepEqual( + extractTypescript("export { type foobar, baz } from './vehicles';"), + [ + { + module: "./vehicles", + moduleSystem: "es6", + dynamic: false, + exoticallyRequired: false, + }, + ], + ); + }); });