From b7b01c0d21c0ac301cd5b8d4cb595f3bbfeebe6b Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Wed, 8 Feb 2023 17:15:38 -0800 Subject: [PATCH] [labs/analyzer] Don't extract JSDoc types in TS. Port type tests to JS. (#3658) * TS already takes into account JSDoc comments when determining types, if applicable. (...) When TypeScript is checking `.ts` files, JSDoc comments that indicate types have no effect despite being parsed and reachable through the AST. When checking `.js` files, JSDoc comments are automatically considered by `tsc` and don't need to be separately taken into account. * Remove incorrect JSDoc type tests. (...) These tests were checking if types defined by JSDoc comments in `.ts` files were being output by the analyzer. However, TS does not consider JSDoc comments to have any effect in `.ts` files, even though they're parsed and reachable in the AST. * Copy TS type tests and port to JS. * Remove a comment that no longer applies. * Add a changeset. --- .changeset/dry-ravens-drop.md | 5 + packages/labs/analyzer/src/lib/types.ts | 7 +- packages/labs/analyzer/src/test/types_test.ts | 584 ++++++++---------- .../analyzer/test-files/js/types/external.js | 19 + .../analyzer/test-files/js/types/module.js | 77 +++ .../analyzer/test-files/js/types/package.json | 6 + .../test-files/ts/types/src/module.ts | 11 - 7 files changed, 380 insertions(+), 329 deletions(-) create mode 100644 .changeset/dry-ravens-drop.md create mode 100644 packages/labs/analyzer/test-files/js/types/external.js create mode 100644 packages/labs/analyzer/test-files/js/types/module.js create mode 100644 packages/labs/analyzer/test-files/js/types/package.json diff --git a/.changeset/dry-ravens-drop.md b/.changeset/dry-ravens-drop.md new file mode 100644 index 0000000000..72e3af151c --- /dev/null +++ b/.changeset/dry-ravens-drop.md @@ -0,0 +1,5 @@ +--- +'@lit-labs/analyzer': minor +--- + +JSDoc types in TS files now have no effect on the analyzer's output, matching TS itself. diff --git a/packages/labs/analyzer/src/lib/types.ts b/packages/labs/analyzer/src/lib/types.ts index 67fd1c347a..07febfa83f 100644 --- a/packages/labs/analyzer/src/lib/types.ts +++ b/packages/labs/analyzer/src/lib/types.ts @@ -60,13 +60,8 @@ export const getTypeForNode = ( node: ts.Node, analyzer: AnalyzerInterface ): Type => { - // Since getTypeAtLocation will return `any` for an untyped node, to support - // jsdoc @type for JS (TBD), we look at the jsdoc type first. - const jsdocType = ts.getJSDocType(node); return getTypeForType( - jsdocType - ? analyzer.program.getTypeChecker().getTypeFromTypeNode(jsdocType) - : analyzer.program.getTypeChecker().getTypeAtLocation(node), + analyzer.program.getTypeChecker().getTypeAtLocation(node), node, analyzer ); diff --git a/packages/labs/analyzer/src/test/types_test.ts b/packages/labs/analyzer/src/test/types_test.ts index 53d3e5388d..4803f910bb 100644 --- a/packages/labs/analyzer/src/test/types_test.ts +++ b/packages/labs/analyzer/src/test/types_test.ts @@ -17,322 +17,282 @@ import { } from '../index.js'; import {Reference} from '../lib/model.js'; +import {languages} from './utils.js'; -const test = suite<{module: Module; packagePath: AbsolutePath}>('Types tests'); - -test.before((ctx) => { - try { - const packagePath = (ctx.packagePath = fileURLToPath( - new URL('../test-files/ts/types', import.meta.url).href - ) as AbsolutePath); - const analyzer = createPackageAnalyzer(packagePath); - const pkg = analyzer.getPackage(); - ctx.module = pkg.modules.filter((m) => m.jsPath === 'module.js')[0]; - } catch (e) { - // Uvu has a bug where it silently ignores failures in before and after, - // see https://github.com/lukeed/uvu/issues/191. - console.error(e); - process.exit(1); - } -}); - -const typeForVariable = (module: Module, name: string) => { - const dec = module.getDeclaration(name); - assert.ok(dec.isVariableDeclaration()); - assert.ok(dec, `Could not find symbol named ${name}`); - const type = dec.type; - assert.ok(type); - return type; -}; - -test('testString', ({module}) => { - const type = typeForVariable(module, 'testString'); - assert.equal(type.text, 'string'); - assert.equal(type.references.length, 0); -}); - -test('inferredString', ({module}) => { - const type = typeForVariable(module, 'inferredString'); - assert.equal(type.text, 'string'); - assert.equal(type.references.length, 0); -}); - -test('localClass', ({module}) => { - const type = typeForVariable(module, 'localClass'); - assert.equal(type.text, 'LocalClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LocalClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'module.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('importedClass', ({module}) => { - const type = typeForVariable(module, 'importedClass'); - assert.equal(type.text, 'ImportedClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'ImportedClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'external.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('localInterface', ({module}) => { - const type = typeForVariable(module, 'localInterface'); - assert.equal(type.text, 'LocalInterface'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LocalInterface'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'module.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('importedInterface', ({module}) => { - const type = typeForVariable(module, 'importedInterface'); - assert.equal(type.text, 'ImportedInterface'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'ImportedInterface'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'external.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('testStringNumberUnion', ({module}) => { - const type = typeForVariable(module, 'testStringNumberUnion'); - assert.equal(type.text, 'string | number'); - assert.equal(type.references.length, 0); -}); - -test('testStringClassUnion', ({module}) => { - const type = typeForVariable(module, 'testStringClassUnion'); - assert.equal(type.text, 'string | LocalClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LocalClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'module.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('testStringImportedClassUnion', ({module}) => { - const type = typeForVariable(module, 'testStringImportedClassUnion'); - assert.equal(type.text, 'string | ImportedClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'ImportedClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'external.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('testStringImportedGlobalClassUnion', ({module}) => { - const type = typeForVariable(module, 'testStringImportedGlobalClassUnion'); - assert.equal(type.text, 'string | ImportedClass | HTMLElement'); - assert.equal(type.references.length, 2); - assert.equal(type.references[0].name, 'ImportedClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'external.js'); - assert.equal(type.references[0].isGlobal, false); - assert.equal(type.references[1].name, 'HTMLElement'); - assert.equal(type.references[1].isGlobal, true); -}); - -test('inferredLocalClass', ({module}) => { - const type = typeForVariable(module, 'inferredLocalClass'); - assert.equal(type.text, 'LocalClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LocalClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'module.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('inferredImportedClass', ({module}) => { - const type = typeForVariable(module, 'inferredImportedClass'); - assert.equal(type.text, 'ImportedClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'ImportedClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'external.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('jsdocString', ({module}) => { - const type = typeForVariable(module, 'jsdocString'); - assert.equal(type.text, 'string'); - assert.equal(type.references.length, 0); -}); - -test('jsdocLocalClass', ({module}) => { - const type = typeForVariable(module, 'jsdocLocalClass'); - assert.equal(type.text, 'LocalClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LocalClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'module.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('jsdocImportedClass', ({module}) => { - const type = typeForVariable(module, 'jsdocImportedClass'); - assert.equal(type.text, 'ImportedClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'ImportedClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'external.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('jsdocStringExternalClassUnion', ({module}) => { - const type = typeForVariable(module, 'jsdocStringExternalClassUnion'); - assert.equal(type.text, 'string | ImportedClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'ImportedClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'external.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('jsdocStringExternalGlobalClassUnion', ({module}) => { - const type = typeForVariable(module, 'jsdocStringExternalGlobalClassUnion'); - assert.equal(type.text, 'string | ImportedClass | HTMLElement'); - assert.equal(type.references.length, 2); - assert.equal(type.references[0].name, 'ImportedClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'external.js'); - assert.equal(type.references[0].isGlobal, false); - assert.equal(type.references[1].name, 'HTMLElement'); - assert.equal(type.references[1].isGlobal, true); -}); - -test('complexType', ({module}) => { - const type = typeForVariable(module, 'complexType'); - assert.equal(type.text, 'Promise>[]'); - assert.equal(type.references.length, 4); - assert.equal(type.references[0].name, 'Promise'); - assert.equal(type.references[0].isGlobal, true); - assert.equal(type.references[1].name, 'Map'); - assert.equal(type.references[1].isGlobal, true); - assert.equal(type.references[2].name, 'LitElement'); - assert.equal(type.references[2].package, 'lit'); - assert.equal(type.references[2].module, undefined); - assert.equal(type.references[2].isGlobal, false); - assert.equal(type.references[3].name, 'ImportedClass'); - assert.equal(type.references[3].package, '@lit-internal/test-types'); - assert.equal(type.references[3].module, 'external.js'); - assert.equal(type.references[3].isGlobal, false); -}); - -test('destructObj', ({module}) => { - const type = typeForVariable(module, 'destructObj'); - assert.equal(type.text, 'LocalClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LocalClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'module.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('destructObjNested', ({module}) => { - const type = typeForVariable(module, 'destructObjNested'); - assert.equal(type.text, 'LitElement'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LitElement'); - assert.equal(type.references[0].package, 'lit'); - assert.equal(type.references[0].module, undefined); - assert.equal(type.references[0].isGlobal, false); -}); - -test('separatelyExportedClass', ({module}) => { - const type = typeForVariable(module, 'separatelyExportedClass'); - assert.equal(type.text, 'LocalClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LocalClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'module.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('separatelyExportedDestructObj', ({module}) => { - const type = typeForVariable(module, 'separatelyExportedDestructObj'); - assert.equal(type.text, 'LocalClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LocalClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'module.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('separatelyExportedDestructObjNested', ({module}) => { - const type = typeForVariable(module, 'separatelyExportedDestructObjNested'); - assert.equal(type.text, 'LitElement'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LitElement'); - assert.equal(type.references[0].package, 'lit'); - assert.equal(type.references[0].module, undefined); - assert.equal(type.references[0].isGlobal, false); -}); - -test('separatelyExportedDestructArr', ({module}) => { - const type = typeForVariable(module, 'separatelyExportedDestructArr'); - assert.equal(type.text, 'LocalClass'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LocalClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'module.js'); - assert.equal(type.references[0].isGlobal, false); -}); - -test('separatelyExportedDestructArrNested', ({module}) => { - const type = typeForVariable(module, 'separatelyExportedDestructArrNested'); - assert.equal(type.text, 'LitElement'); - assert.equal(type.references.length, 1); - assert.equal(type.references[0].name, 'LitElement'); - assert.equal(type.references[0].package, 'lit'); - assert.equal(type.references[0].module, undefined); - assert.equal(type.references[0].isGlobal, false); -}); - -test('importedType', ({module}) => { - const type = typeForVariable(module, 'importedType'); - //assert.equal(type.text, 'TemplateResult<1>'); - assert.equal(type.references.length, 2); - assert.equal(type.references[0].name, 'ImportedClass'); - assert.equal(type.references[0].package, '@lit-internal/test-types'); - assert.equal(type.references[0].module, 'external.js'); - assert.equal(type.references[0].isGlobal, false); - assert.equal(type.references[1].name, 'TemplateResult'); - assert.equal(type.references[1].package, 'lit-html'); - assert.equal(type.references[1].module, undefined); - assert.equal(type.references[1].isGlobal, false); -}); +for (const lang of languages) { + const test = suite<{module: Module; packagePath: AbsolutePath}>( + `Types tests (${lang})` + ); -test('getImportsStringForReferences', ({module}) => { - const type = typeForVariable(module, 'complexType'); - assert.equal( - getImportsStringForReferences(type.references), - ` + test.before((ctx) => { + try { + const packagePath = (ctx.packagePath = fileURLToPath( + new URL(`../test-files/${lang}/types`, import.meta.url).href + ) as AbsolutePath); + const analyzer = createPackageAnalyzer(packagePath); + const pkg = analyzer.getPackage(); + ctx.module = pkg.modules.filter((m) => m.jsPath === 'module.js')[0]; + } catch (e) { + // Uvu has a bug where it silently ignores failures in before and after, + // see https://github.com/lukeed/uvu/issues/191. + console.error(e); + process.exit(1); + } + }); + + const typeForVariable = (module: Module, name: string) => { + const dec = module.getDeclaration(name); + assert.ok(dec.isVariableDeclaration()); + assert.ok(dec, `Could not find symbol named ${name}`); + const type = dec.type; + assert.ok(type); + return type; + }; + + test('testString', ({module}) => { + const type = typeForVariable(module, 'testString'); + assert.equal(type.text, 'string'); + assert.equal(type.references.length, 0); + }); + + test('inferredString', ({module}) => { + const type = typeForVariable(module, 'inferredString'); + assert.equal(type.text, 'string'); + assert.equal(type.references.length, 0); + }); + + test('localClass', ({module}) => { + const type = typeForVariable(module, 'localClass'); + assert.equal(type.text, 'LocalClass'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LocalClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'module.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('importedClass', ({module}) => { + const type = typeForVariable(module, 'importedClass'); + assert.equal(type.text, 'ImportedClass'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'ImportedClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'external.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('localInterface', ({module}) => { + const type = typeForVariable(module, 'localInterface'); + assert.equal(type.text, 'LocalInterface'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LocalInterface'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'module.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('importedInterface', ({module}) => { + const type = typeForVariable(module, 'importedInterface'); + assert.equal(type.text, 'ImportedInterface'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'ImportedInterface'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'external.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('testStringNumberUnion', ({module}) => { + const type = typeForVariable(module, 'testStringNumberUnion'); + assert.equal(type.text, 'string | number'); + assert.equal(type.references.length, 0); + }); + + test('testStringClassUnion', ({module}) => { + const type = typeForVariable(module, 'testStringClassUnion'); + assert.equal(type.text, 'string | LocalClass'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LocalClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'module.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('testStringImportedClassUnion', ({module}) => { + const type = typeForVariable(module, 'testStringImportedClassUnion'); + assert.equal(type.text, 'string | ImportedClass'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'ImportedClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'external.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('testStringImportedGlobalClassUnion', ({module}) => { + const type = typeForVariable(module, 'testStringImportedGlobalClassUnion'); + assert.equal(type.text, 'string | ImportedClass | HTMLElement'); + assert.equal(type.references.length, 2); + assert.equal(type.references[0].name, 'ImportedClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'external.js'); + assert.equal(type.references[0].isGlobal, false); + assert.equal(type.references[1].name, 'HTMLElement'); + assert.equal(type.references[1].isGlobal, true); + }); + + test('inferredLocalClass', ({module}) => { + const type = typeForVariable(module, 'inferredLocalClass'); + assert.equal(type.text, 'LocalClass'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LocalClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'module.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('inferredImportedClass', ({module}) => { + const type = typeForVariable(module, 'inferredImportedClass'); + assert.equal(type.text, 'ImportedClass'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'ImportedClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'external.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('complexType', ({module}) => { + const type = typeForVariable(module, 'complexType'); + assert.equal( + type.text, + 'Promise>[]' + ); + assert.equal(type.references.length, 4); + assert.equal(type.references[0].name, 'Promise'); + assert.equal(type.references[0].isGlobal, true); + assert.equal(type.references[1].name, 'Map'); + assert.equal(type.references[1].isGlobal, true); + assert.equal(type.references[2].name, 'LitElement'); + assert.equal(type.references[2].package, 'lit'); + assert.equal(type.references[2].module, undefined); + assert.equal(type.references[2].isGlobal, false); + assert.equal(type.references[3].name, 'ImportedClass'); + assert.equal(type.references[3].package, '@lit-internal/test-types'); + assert.equal(type.references[3].module, 'external.js'); + assert.equal(type.references[3].isGlobal, false); + }); + + test('destructObj', ({module}) => { + const type = typeForVariable(module, 'destructObj'); + assert.equal(type.text, 'LocalClass'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LocalClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'module.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('destructObjNested', ({module}) => { + const type = typeForVariable(module, 'destructObjNested'); + assert.equal(type.text, 'LitElement'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LitElement'); + assert.equal(type.references[0].package, 'lit'); + assert.equal(type.references[0].module, undefined); + assert.equal(type.references[0].isGlobal, false); + }); + + test('separatelyExportedClass', ({module}) => { + const type = typeForVariable(module, 'separatelyExportedClass'); + assert.equal(type.text, 'LocalClass'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LocalClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'module.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('separatelyExportedDestructObj', ({module}) => { + const type = typeForVariable(module, 'separatelyExportedDestructObj'); + assert.equal(type.text, 'LocalClass'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LocalClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'module.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('separatelyExportedDestructObjNested', ({module}) => { + const type = typeForVariable(module, 'separatelyExportedDestructObjNested'); + assert.equal(type.text, 'LitElement'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LitElement'); + assert.equal(type.references[0].package, 'lit'); + assert.equal(type.references[0].module, undefined); + assert.equal(type.references[0].isGlobal, false); + }); + + test('separatelyExportedDestructArr', ({module}) => { + const type = typeForVariable(module, 'separatelyExportedDestructArr'); + assert.equal(type.text, 'LocalClass'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LocalClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'module.js'); + assert.equal(type.references[0].isGlobal, false); + }); + + test('separatelyExportedDestructArrNested', ({module}) => { + const type = typeForVariable(module, 'separatelyExportedDestructArrNested'); + assert.equal(type.text, 'LitElement'); + assert.equal(type.references.length, 1); + assert.equal(type.references[0].name, 'LitElement'); + assert.equal(type.references[0].package, 'lit'); + assert.equal(type.references[0].module, undefined); + assert.equal(type.references[0].isGlobal, false); + }); + + test('importedType', ({module}) => { + const type = typeForVariable(module, 'importedType'); + //assert.equal(type.text, 'TemplateResult<1>'); + assert.equal(type.references.length, 2); + assert.equal(type.references[0].name, 'ImportedClass'); + assert.equal(type.references[0].package, '@lit-internal/test-types'); + assert.equal(type.references[0].module, 'external.js'); + assert.equal(type.references[0].isGlobal, false); + assert.equal(type.references[1].name, 'TemplateResult'); + assert.equal(type.references[1].package, 'lit-html'); + assert.equal(type.references[1].module, undefined); + assert.equal(type.references[1].isGlobal, false); + }); + + test('getImportsStringForReferences', ({module}) => { + const type = typeForVariable(module, 'complexType'); + assert.equal( + getImportsStringForReferences(type.references), + ` import {LitElement} from 'lit'; import {ImportedClass} from '@lit-internal/test-types/external.js'; -`.trim() - ); -}); - -test('getImportsStringForReferences coalesced', () => { - const reference = [ - new Reference({package: 'foo', name: 'foo1'}), - new Reference({package: 'bar', name: 'bar1'}), - new Reference({package: 'foo', name: 'foo1'}), - new Reference({package: 'foo', name: 'foo2'}), - new Reference({package: 'bar', name: 'bar2'}), - new Reference({package: 'bar', name: 'bar2'}), - new Reference({package: 'foo', name: 'foo3'}), - ]; - assert.equal( - getImportsStringForReferences(reference), - ` + `.trim() + ); + }); + + test('getImportsStringForReferences coalesced', () => { + const reference = [ + new Reference({package: 'foo', name: 'foo1'}), + new Reference({package: 'bar', name: 'bar1'}), + new Reference({package: 'foo', name: 'foo1'}), + new Reference({package: 'foo', name: 'foo2'}), + new Reference({package: 'bar', name: 'bar2'}), + new Reference({package: 'bar', name: 'bar2'}), + new Reference({package: 'foo', name: 'foo3'}), + ]; + assert.equal( + getImportsStringForReferences(reference), + ` import {foo1, foo2, foo3} from 'foo'; import {bar1, bar2} from 'bar'; -`.trim() - ); -}); + `.trim() + ); + }); -test.run(); + test.run(); +} diff --git a/packages/labs/analyzer/test-files/js/types/external.js b/packages/labs/analyzer/test-files/js/types/external.js new file mode 100644 index 0000000000..8085488497 --- /dev/null +++ b/packages/labs/analyzer/test-files/js/types/external.js @@ -0,0 +1,19 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ + +export class ImportedClass { + /** @type {number} */ + someData; +} + +/** + * @typedef ImportedInterface + * @prop {number} someData + */ + +export const returnsClass = () => { + return new ImportedClass(); +}; diff --git a/packages/labs/analyzer/test-files/js/types/module.js b/packages/labs/analyzer/test-files/js/types/module.js new file mode 100644 index 0000000000..c623d896bf --- /dev/null +++ b/packages/labs/analyzer/test-files/js/types/module.js @@ -0,0 +1,77 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** @typedef {import("./external.js").ImportedInterface} ImportedInterface */ +import {ImportedClass, returnsClass} from './external.js'; +import {LitElement, html} from 'lit'; + +/** @type {string} */ +export const testString = 'hi'; +export const inferredString = 'hi'; + +export class LocalClass {} + +/** + * @typedef LocalInterface + * @prop {number} someData + */ + +/** @type {LocalClass} */ +export let localClass; +/** @type {ImportedClass} */ +export let importedClass; +/** @type {LitElement} */ +export let externalClass; + +/** @type {LocalInterface} */ +export let localInterface; +/** @type {ImportedInterface} */ +export let importedInterface; + +/** @type {string | number} */ +export const testStringNumberUnion = 'hi'; +/** @type {string | LocalClass} */ +export const testStringClassUnion = 'hi'; +/** @type {string | ImportedClass} */ +export const testStringImportedClassUnion = 'hi'; +/** @type {string | ImportedClass | HTMLElement} */ +export const testStringImportedGlobalClassUnion = 'hi'; + +export const inferredLocalClass = new LocalClass(); +export const inferredImportedClass = new ImportedClass(); +export const inferredExternalClass = new LitElement(); + +/** @type {Promise>[]} */ +export let complexType; + +export const { + destructObj, + foo: {destructObjNested}, +} = { + destructObj: new LocalClass(), + foo: {destructObjNested: new LitElement()}, +}; + +/** @type {LocalClass} */ +const separatelyExportedClass = new LocalClass(); +export {separatelyExportedClass}; + +const { + separatelyExportedDestructObj, + foo: {separatelyExportedDestructObjNested}, +} = { + separatelyExportedDestructObj: new LocalClass(), + foo: {separatelyExportedDestructObjNested: new LitElement()}, +}; +export {separatelyExportedDestructObj, separatelyExportedDestructObjNested}; + +const [separatelyExportedDestructArr, [separatelyExportedDestructArrNested]] = [ + new LocalClass(), + [new LitElement()], +]; +export {separatelyExportedDestructArr, separatelyExportedDestructArrNested}; + +export const importedType = Math.random() ? returnsClass() : html``; diff --git a/packages/labs/analyzer/test-files/js/types/package.json b/packages/labs/analyzer/test-files/js/types/package.json new file mode 100644 index 0000000000..c5e684c208 --- /dev/null +++ b/packages/labs/analyzer/test-files/js/types/package.json @@ -0,0 +1,6 @@ +{ + "name": "@lit-internal/test-types", + "dependencies": { + "lit": "^2.0.0" + } +} diff --git a/packages/labs/analyzer/test-files/ts/types/src/module.ts b/packages/labs/analyzer/test-files/ts/types/src/module.ts index 79f3921049..6e939baadc 100644 --- a/packages/labs/analyzer/test-files/ts/types/src/module.ts +++ b/packages/labs/analyzer/test-files/ts/types/src/module.ts @@ -35,17 +35,6 @@ export const inferredLocalClass = new LocalClass(); export const inferredImportedClass = new ImportedClass(); export const inferredExternalClass = new LitElement(); -/** @type {string} */ -export let jsdocString; -/** @type {LocalClass} */ -export let jsdocLocalClass; -/** @type {ImportedClass} */ -export let jsdocImportedClass; -/** @type {string | ImportedClass} */ -export let jsdocStringExternalClassUnion; -/** @type {string | ImportedClass | HTMLElement} */ -export let jsdocStringExternalGlobalClassUnion; - export let complexType: Promise>[]; export const {