Skip to content

Commit

Permalink
chore: Support third party type imports (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
cansuaa authored Aug 8, 2024
1 parent d348473 commit 7ca8cbe
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 5 deletions.
14 changes: 14 additions & 0 deletions fixtures/components/third-party-import-types/button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';

import { ButtonProps } from './interfaces';

export { ButtonProps };

/**
* Component-level description
*/
export default function Button({ iconName }: ButtonProps) {
return <div className={iconName}>{iconName}</div>;
}
10 changes: 10 additions & 0 deletions fixtures/components/third-party-import-types/button/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { IconProps } from '../node_modules_mock/icon';

export interface ButtonProps {
/**
* This is icon name
*/
iconName: IconProps.Name;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { IconProps } from './interfaces';
export { IconProps };
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
export interface IconProps {
/**
* Specifies the icon to be displayed.
*/
name?: IconProps.Name;
}
export declare namespace IconProps {
type Name = 'icon1' | 'icon2' | 'icon3';
}
7 changes: 7 additions & 0 deletions fixtures/components/third-party-import-types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "button"
},
"include": ["button"]
}
10 changes: 9 additions & 1 deletion src/bootstrap/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { TypeDocAndTSOptions, Application, TSConfigReader, ProjectReflection } f
import { matcher } from 'micromatch';
import { resolve } from 'pathe';

export function bootstrapProject(options: Partial<TypeDocAndTSOptions>, filteringGlob?: string): ProjectReflection {
export function bootstrapProject(
options: Partial<TypeDocAndTSOptions>,
filteringGlob?: string,
additionalInputFilePaths?: string[]
): ProjectReflection {
const app = new Application();
app.options.addReader(new TSConfigReader());

Expand All @@ -14,6 +18,10 @@ export function bootstrapProject(options: Partial<TypeDocAndTSOptions>, filterin
throw new Error('Errors during parsing configuration');
}

if (additionalInputFilePaths?.length) {
inputFiles.push(...additionalInputFilePaths);
}

const filteredInputFiles = filterFiles(inputFiles, filteringGlob);
if (!filteredInputFiles.length) {
throw new Error('No input files to convert');
Expand Down
23 changes: 21 additions & 2 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,26 @@ import { ComponentDefinition } from './interfaces';
import extractComponents from './components-extractor';
import { bootstrapProject } from '../bootstrap';

export function documentComponents(tsconfigPath: string, publicFilesGlob: string): ComponentDefinition[] {
const project = bootstrapProject({ tsconfig: tsconfigPath });
/**
* @param tsconfigPath Path to tsconfig file
* @param publicFilesGlob Filter to obtain public files
* @param nodeModulesDependencyFilePaths node_modules paths of libraries to include in documentation e.g.["dir/node_modules/@cloudscape-design/components/icon/interfaces.d.ts"]
* @returns Component definitions
*/
export function documentComponents(
tsconfigPath: string,
publicFilesGlob: string,
nodeModulesDependencyFilePaths?: string[]
): ComponentDefinition[] {
const includeNodeModulePaths = Boolean(nodeModulesDependencyFilePaths?.length);
const project = bootstrapProject(
{
tsconfig: tsconfigPath,
includeDeclarations: includeNodeModulePaths,
excludeExternals: includeNodeModulePaths,
},
undefined,
nodeModulesDependencyFilePaths
);
return extractComponents(publicFilesGlob, project);
}
5 changes: 3 additions & 2 deletions test/components/test-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import { TestUtilsDoc } from '../../src/test-utils/interfaces';

// TODO: Move this file into common location, improve naming

export function buildProject(name: string): ComponentDefinition[] {
export function buildProject(name: string, nodeModulesDependencyFilePaths?: string[]): ComponentDefinition[] {
return documentComponents(
require.resolve(`../../fixtures/components/${name}/tsconfig.json`),
`fixtures/components/${name}/*/index.tsx`
`fixtures/components/${name}/*/index.tsx`,
nodeModulesDependencyFilePaths
);
}

Expand Down
56 changes: 56 additions & 0 deletions test/components/third-party-import-types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { buildProject } from './test-helpers';
import { ComponentDefinition } from '../../src';
import * as bootstrap from '../../src/bootstrap';
import process from 'node:process';
const cwd = process.cwd();
const nodeModulesPath = `${cwd}/fixtures/components/third-party-import-types/node_modules_mock/icon/interfaces.d.ts`;

test('should resolve object type to string', () => {
const resultBefore = buildProject('third-party-import-types');
const buttonBefore: ComponentDefinition | undefined = resultBefore.find(component => component.name === 'Button');

expect(buttonBefore?.properties).toEqual([
{
name: 'iconName',
type: 'IconProps.Name',
inlineType: undefined,
optional: false,
description: 'This is icon name',
defaultValue: undefined,
visualRefreshTag: undefined,
deprecatedTag: undefined,
i18nTag: undefined,
analyticsTag: undefined,
},
]);

const resultAfter = buildProject('third-party-import-types', [nodeModulesPath]);
const buttonAfter: ComponentDefinition | undefined = resultAfter.find(component => component.name === 'Button');

expect(buttonAfter?.properties).toEqual([
{
name: 'iconName',
type: 'string',
inlineType: { name: 'IconProps.Name', type: 'union', values: ['icon1', 'icon2', 'icon3'] },
optional: false,
description: 'This is icon name',
defaultValue: undefined,
visualRefreshTag: undefined,
deprecatedTag: undefined,
i18nTag: undefined,
analyticsTag: undefined,
},
]);
});

test('passing nodeModulesDependencyFilePaths should enable includeDeclarations and excludeExternals', () => {
const bootstrapProjectSpy = jest.spyOn(bootstrap, 'bootstrapProject');
buildProject('third-party-import-types', [nodeModulesPath]);

expect(bootstrapProjectSpy.mock.calls[0][0].includeDeclarations).toBe(true);
expect(bootstrapProjectSpy.mock.calls[0][0].excludeExternals).toBe(true);

jest.restoreAllMocks();
});

0 comments on commit 7ca8cbe

Please sign in to comment.