diff --git a/src/test-utils/extractor.ts b/src/test-utils/extractor.ts index c342654..1fbb304 100644 --- a/src/test-utils/extractor.ts +++ b/src/test-utils/extractor.ts @@ -19,7 +19,7 @@ function getInheritedFrom(declaration: ts.Declaration, currentClassName: string) if (parentName === currentClassName) { return undefined; } - return { name: parentName + '.' + declaration.name.getText() }; + return { className: parentName, methodName: declaration.name.getText() }; } function getDefaultValue(declaration: ts.Declaration) { @@ -35,7 +35,8 @@ function getDefaultValue(declaration: ts.Declaration) { export default function extractDocumentation( sourceFile: ts.SourceFile, checker: ts.TypeChecker, - extraExports: Array + extraExports: Array, + includeCoreMethods: boolean ): Array { const moduleSymbol = checker.getSymbolAtLocation(sourceFile); if (!moduleSymbol) { @@ -51,7 +52,7 @@ export default function extractDocumentation( continue; } const classType = checker.getDeclaredTypeOfSymbol(symbol); - documentClass(definitions, symbol, classType, checker); + documentClass(definitions, symbol, classType, checker, includeCoreMethods); } return Array.from(definitions.values()); @@ -61,7 +62,8 @@ function documentClass( definitions: Map, symbol: ts.Symbol, classType: ts.Type, - checker: ts.TypeChecker + checker: ts.TypeChecker, + includeCoreMethods: boolean ) { if (!classType.isClass()) { throw new Error(`Exported symbol is not a class, got ${checker.symbolToString(symbol)}`); @@ -92,11 +94,20 @@ function documentClass( maybeReturnType.flags & ts.TypeFlags.Void ? maybeReturnType : maybeReturnType.getNonNullableType(); const dependency = findDependencyType(returnType, checker); if (dependency && !definitions.has(dependency.typeName)) { - documentClass(definitions, dependency.symbol, dependency.type, checker); + documentClass(definitions, dependency.symbol, dependency.type, checker, includeCoreMethods); } const { typeName, typeParameters } = extractTypeArguments(returnType, checker); + const inheritedFrom = getInheritedFrom(declaration, className); + if ( + inheritedFrom && + !includeCoreMethods && + ['AbstractWrapper', 'ElementWrapper'].includes(inheritedFrom?.className) + ) { + continue; + } + definition.methods.push({ name: property.getName(), description: getDescription(property.getDocumentationComment(checker), declaration).text, @@ -117,7 +128,7 @@ function documentClass( defaultValue: getDefaultValue(extractDeclaration(parameter)), }; }), - inheritedFrom: getInheritedFrom(declaration, className), + inheritedFrom: inheritedFrom ? { name: `${inheritedFrom.className}.${inheritedFrom.methodName}` } : undefined, }); } } diff --git a/src/test-utils/index.ts b/src/test-utils/index.ts index b4083f9..a848a1d 100644 --- a/src/test-utils/index.ts +++ b/src/test-utils/index.ts @@ -13,6 +13,7 @@ export interface TestUtilsVariantOptions { export interface TestUtilsDocumenterOptions { tsconfigPath: string; + includeCoreMethods?: boolean; domUtils: TestUtilsVariantOptions; selectorsUtils: TestUtilsVariantOptions; } @@ -22,7 +23,7 @@ interface TestUtilsDefinitions { selectorsDefinitions: Array; } -export function documentTestUtilsNew(options: TestUtilsDocumenterOptions): TestUtilsDefinitions { +export function documentTestUtils(options: TestUtilsDocumenterOptions): TestUtilsDefinitions { const domUtilsRoot = pathe.resolve(options.domUtils.root); const selectorsUtilsRoot = pathe.resolve(options.selectorsUtils.root); const program = bootstrapTypescriptProject(options.tsconfigPath); @@ -37,9 +38,21 @@ export function documentTestUtilsNew(options: TestUtilsDocumenterOptions): TestU if (!selectorsUtilsFile) { throw new Error(`File '${selectorsUtilsFile}' not found`); } + // TODO: switch to false after all consumers updated + const includeCoreMethods = options.includeCoreMethods ?? true; return { - domDefinitions: extractDocumentation(domUtilsFile, checker, options.domUtils.extraExports ?? []), - selectorsDefinitions: extractDocumentation(selectorsUtilsFile, checker, options.selectorsUtils.extraExports ?? []), + domDefinitions: extractDocumentation( + domUtilsFile, + checker, + options.domUtils.extraExports ?? [], + includeCoreMethods + ), + selectorsDefinitions: extractDocumentation( + selectorsUtilsFile, + checker, + options.selectorsUtils.extraExports ?? [], + includeCoreMethods + ), }; } @@ -47,7 +60,7 @@ export function writeTestUtilsDocumentation({ outDir, ...rest }: TestUtilsDocumenterOptions & { outDir: string }): void { - const { domDefinitions, selectorsDefinitions } = documentTestUtilsNew(rest); + const { domDefinitions, selectorsDefinitions } = documentTestUtils(rest); fs.mkdirSync(outDir, { recursive: true }); fs.writeFileSync( pathe.join(outDir, 'dom.js'), diff --git a/src/test-utils/interfaces.ts b/src/test-utils/interfaces.ts index 410d920..74f8d2b 100644 --- a/src/test-utils/interfaces.ts +++ b/src/test-utils/interfaces.ts @@ -21,6 +21,7 @@ export interface TestUtilMethod { typeArguments?: Array; }; parameters: Array; + /* @deprecated All inherited methods should be filtered automatically */ inheritedFrom?: { name: string; }; diff --git a/test/test-utils/__snapshots__/doc-generation.test.ts.snap b/test/test-utils/__snapshots__/doc-generation.test.ts.snap index 9606860..b528edd 100644 --- a/test/test-utils/__snapshots__/doc-generation.test.ts.snap +++ b/test/test-utils/__snapshots__/doc-generation.test.ts.snap @@ -14,6 +14,27 @@ exports[`Generate documentation > For simple cases 1`] = ` ] `; +exports[`Generate documentation > allows to skip methods from core wrappers 1`] = ` +[ + { + "methods": [ + { + "description": undefined, + "inheritedFrom": undefined, + "name": "childClassMethod", + "parameters": [], + "returnType": { + "isNullable": false, + "name": "void", + "typeArguments": undefined, + }, + }, + ], + "name": "TestUtilWrapper", + }, +] +`; + exports[`Generate documentation > deal with more complex types 1`] = ` [ { @@ -285,3 +306,37 @@ exports[`Generate documentation > deal with re-exports 1`] = ` }, ] `; + +exports[`Generate documentation > includes inherited methods from core wrappers 1`] = ` +[ + { + "methods": [ + { + "description": undefined, + "inheritedFrom": undefined, + "name": "childClassMethod", + "parameters": [], + "returnType": { + "isNullable": false, + "name": "void", + "typeArguments": undefined, + }, + }, + { + "description": undefined, + "inheritedFrom": { + "name": "AbstractWrapper.inheritedMethod", + }, + "name": "inheritedMethod", + "parameters": [], + "returnType": { + "isNullable": false, + "name": "void", + "typeArguments": undefined, + }, + }, + ], + "name": "TestUtilWrapper", + }, +] +`; diff --git a/test/test-utils/doc-generation.test.ts b/test/test-utils/doc-generation.test.ts index 25b7e71..49d73c5 100644 --- a/test/test-utils/doc-generation.test.ts +++ b/test/test-utils/doc-generation.test.ts @@ -49,7 +49,7 @@ describe('Generate documentation', () => { }); test('deal with more complex types', () => { - const results = buildTestUtilsProject('advanced-types', { extraExports: ['default'] }); + const results = buildTestUtilsProject('advanced-types', undefined, { extraExports: ['default'] }); expect(results.length).toBe(1); const classDoc = results[0]; @@ -61,26 +61,16 @@ describe('Generate documentation', () => { expect(methods).toMatchSnapshot(); }); - test('and deal with inheritance', () => { - const results = buildTestUtilsProject('inheritance'); - - expect(results.length).toBe(1); - const classDoc = results.find(classDoc => classDoc.name === 'TestUtilWrapper'); - - expect(classDoc).toBeDefined(); - - const methods = classDoc?.methods || []; - expect(methods.length).toBe(2); - - const inheritedMethod = methods.find(method => method.name === 'inheritedMethod'); - expect(inheritedMethod).toBeDefined(); - expect(inheritedMethod?.inheritedFrom).toEqual({ - name: 'AbstractWrapper.inheritedMethod', - }); + test('includes inherited methods from core wrappers', () => { + const results = buildTestUtilsProject('inheritance', { includeCoreMethods: true }); + expect(results[0].methods.find(method => method.name === 'inheritedMethod')).toBeTruthy(); + expect(results).toMatchSnapshot(); + }); - const childClassMethod = methods.find(method => method.name === 'childClassMethod'); - expect(childClassMethod).toBeDefined(); - expect(childClassMethod?.inheritedFrom).toBeUndefined(); + test('allows to skip methods from core wrappers', () => { + const results = buildTestUtilsProject('inheritance', { includeCoreMethods: false }); + expect(results[0].methods.find(method => method.name === 'inheritedMethod')).toBeFalsy(); + expect(results).toMatchSnapshot(); }); test('deal with re-exports', () => { diff --git a/test/test-utils/test-helpers.ts b/test/test-utils/test-helpers.ts index 0b84c6a..ac96307 100644 --- a/test/test-utils/test-helpers.ts +++ b/test/test-utils/test-helpers.ts @@ -1,15 +1,17 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { documentTestUtilsNew, TestUtilsVariantOptions } from '../../src/test-utils'; +import { documentTestUtils, TestUtilsDocumenterOptions, TestUtilsVariantOptions } from '../../src/test-utils'; import { TestUtilsDoc } from '../../src/test-utils/interfaces'; export function buildTestUtilsProject( name: string, - configOverrides?: Partial + configOverrides?: Partial, + wrapperConfigOverrides?: Partial ): TestUtilsDoc[] { - return documentTestUtilsNew({ + return documentTestUtils({ tsconfigPath: require.resolve(`../../fixtures/test-utils/${name}/tsconfig.json`), - domUtils: { root: `fixtures/test-utils/${name}/index.ts`, ...configOverrides }, - selectorsUtils: { root: `fixtures/test-utils/${name}/index.ts`, ...configOverrides }, + domUtils: { root: `fixtures/test-utils/${name}/index.ts`, ...wrapperConfigOverrides }, + selectorsUtils: { root: `fixtures/test-utils/${name}/index.ts`, ...wrapperConfigOverrides }, + ...configOverrides, }).domDefinitions; } diff --git a/test/test-utils/usage.test.ts b/test/test-utils/usage.test.ts index 97fee69..2f1c94d 100644 --- a/test/test-utils/usage.test.ts +++ b/test/test-utils/usage.test.ts @@ -24,9 +24,13 @@ describe('documentTestUtils throws error for ', () => { test('having no input files because of a non-matching glob', () => { expect(() => - buildTestUtilsProject('simple', { - root: 'fixtures/does-not-exist/index.ts', - }) + buildTestUtilsProject( + 'simple', + {}, + { + root: 'fixtures/does-not-exist/index.ts', + } + ) ).toThrow(/File '.*fixtures\/does-not-exist\/index.ts' not found/); }); });