diff --git a/src/index.js b/src/index.js index 0761c04..513d0c2 100644 --- a/src/index.js +++ b/src/index.js @@ -98,7 +98,7 @@ export class JSDocParser { /** * Returns all the valid ESM Scripts within a file * @param {string} fileName - The file name in the program to check - * @returns {import('typescript').Node[]} - An array of any exported ESM Script nodes within the file + * @returns {Map} - A map of valid ESM Script within the file */ getAllEsmScripts(fileName) { @@ -123,9 +123,15 @@ export class JSDocParser { const esmScriptClass = pcTypes.statements.find(node => node.kind === ts.SyntaxKind.ClassDeclaration && node.name.text === 'Script')?.symbol; + const esmScripts = new Map(); // Check if the file exports a class that inherits from `Script` - return Array.from(nodes).filter(node => isAliasedClassDeclaration(node, typeChecker) && inheritsFrom(node, typeChecker, esmScriptClass)); + nodes.forEach((node, name) => { + if (isAliasedClassDeclaration(node, typeChecker) && inheritsFrom(node, typeChecker, esmScriptClass)) { + esmScripts.set(name, node); + } + }); + return esmScripts; } /** @@ -146,9 +152,8 @@ export class JSDocParser { const nodes = this.getAllEsmScripts(fileName); // Extract attributes from each script - nodes.forEach((node) => { - const name = toLowerCamelCase(node.name.text); - const opts = results[name] = { attributes: {}, errors: [] }; + nodes.forEach((node, name) => { + const opts = results[toLowerCamelCase(name)] = { attributes: {}, errors: [] }; this.parser.extractAttributes(node, opts); }); diff --git a/src/utils/ts-utils.js b/src/utils/ts-utils.js index 833ebd2..cbe7a81 100644 --- a/src/utils/ts-utils.js +++ b/src/utils/ts-utils.js @@ -45,7 +45,7 @@ function resolveAliasedSymbol(typeChecker, symbol) { * Returns an array of exported nodes from a TypeScript source file. * @param {import('typescript').Program} program - The TypeScript program * @param {import('typescript').SourceFile} sourceFile - The TypeScript source file - * @returns {Set} - A Set of exported nodes + * @returns {let map: Map>} - A Map of exported nodes */ export function getExportedNodes(program, sourceFile) { if (!program || !sourceFile) { @@ -62,16 +62,18 @@ export function getExportedNodes(program, sourceFile) { const exportedSymbols = typeChecker.getExportsOfModule(moduleSymbol); // Find the actual declaration nodes for each exported symbol - const exportedNodes = []; + const exportedNodes = new Map(); exportedSymbols.forEach((symbol) => { const resolvedSymbol = resolveAliasedSymbol(typeChecker, symbol); if (resolvedSymbol.declarations) { - exportedNodes.push(...resolvedSymbol.declarations); + const node = resolvedSymbol.declarations[0]; + const name = symbol.name === 'default' ? node.name.getText() : symbol.name; + exportedNodes.set(name, node); } }); - return new Set(exportedNodes); + return exportedNodes; } /** diff --git a/test/fixtures/export.import.js b/test/fixtures/export.import.js index 3d3f4a1..479f8da 100644 --- a/test/fixtures/export.import.js +++ b/test/fixtures/export.import.js @@ -1,3 +1,8 @@ import { Script } from 'playcanvas'; -export class ExampleImport extends Script {} +export class ExampleImport extends Script { + /** + * @attribute + */ + prop = 10; +} diff --git a/test/fixtures/export.valid.js b/test/fixtures/export.valid.js index 52112fd..79d9f3b 100644 --- a/test/fixtures/export.valid.js +++ b/test/fixtures/export.valid.js @@ -4,9 +4,12 @@ import { ExampleImport } from './export.import.js'; class ExampleImportExtend extends ExampleImport {} -export { ExampleImport as ExampleImportExportAs } from './export.import.js'; +export { ExampleImport as ExampleImportAsExport } from './export.import.js'; -class Example extends Script {} +class Example extends Script { + /** @attribute */ + num = 10; +} export default class ExampleDefault extends Script {} diff --git a/test/tests/valid/export.test.js b/test/tests/valid/export.test.js index ea98652..e5234ad 100644 --- a/test/tests/valid/export.test.js +++ b/test/tests/valid/export.test.js @@ -17,7 +17,7 @@ describe('VALID: Export Script', function () { it('Example: should exist without attributes or errors', function () { expect(data[0]?.example).to.exist; - expect(data[0].example.attributes).to.be.empty; + expect(data[0].example.attributes).to.not.be.empty; expect(data[0].example.errors).to.be.empty; }); @@ -33,13 +33,21 @@ describe('VALID: Export Script', function () { expect(data[0].exampleDefault.errors).to.be.empty; }); + it('ExampleImportAsExport: should not exist', function () { + expect(data[0]?.exampleImportAsExport).to.exist; + expect(data[0].exampleImportAsExport.attributes).to.not.be.empty; + expect(data[0].exampleImportAsExport.errors).to.be.empty; + }); + it('ExampleExportAs: should not exist', function () { - expect(data[0]?.exampleExportAs).to.not.exist; + expect(data[0]?.exampleExportAs).to.exist; + expect(data[0].exampleExportAs.attributes).to.not.be.empty; + expect(data[0].exampleExportAs.errors).to.be.empty; }); it('ExampleImport: should exist without attributes or errors', function () { expect(data[0]?.exampleImport).to.exist; - expect(data[0].exampleImport.attributes).to.be.empty; + expect(data[0].exampleImport.attributes).to.not.be.empty; expect(data[0].exampleImport.errors).to.be.empty; });