diff --git a/fixtures/components/third-party-import-types/button/index.tsx b/fixtures/components/third-party-import-types/button/index.tsx
new file mode 100644
index 0000000..26010e1
--- /dev/null
+++ b/fixtures/components/third-party-import-types/button/index.tsx
@@ -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
{iconName}
;
+}
diff --git a/fixtures/components/third-party-import-types/button/interfaces.ts b/fixtures/components/third-party-import-types/button/interfaces.ts
new file mode 100644
index 0000000..23fac53
--- /dev/null
+++ b/fixtures/components/third-party-import-types/button/interfaces.ts
@@ -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/icon';
+
+export interface ButtonProps {
+ /**
+ * This is icon name
+ */
+ iconName: IconProps.Name;
+}
diff --git a/fixtures/components/third-party-import-types/tsconfig.json b/fixtures/components/third-party-import-types/tsconfig.json
new file mode 100644
index 0000000..0c95ade
--- /dev/null
+++ b/fixtures/components/third-party-import-types/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "button"
+ },
+ "include": ["button"]
+}
diff --git a/src/bootstrap/index.ts b/src/bootstrap/index.ts
index 7821398..871b73d 100644
--- a/src/bootstrap/index.ts
+++ b/src/bootstrap/index.ts
@@ -5,7 +5,11 @@ import { TypeDocAndTSOptions, Application, TSConfigReader, ProjectReflection } f
import { matcher } from 'micromatch';
import { resolve } from 'pathe';
-export function bootstrapProject(options: Partial, filteringGlob?: string): ProjectReflection {
+export function bootstrapProject(
+ options: Partial,
+ filteringGlob?: string,
+ nodeModulesInputFilePaths?: string[]
+): ProjectReflection {
const app = new Application();
app.options.addReader(new TSConfigReader());
@@ -14,6 +18,10 @@ export function bootstrapProject(options: Partial, filterin
throw new Error('Errors during parsing configuration');
}
+ if (nodeModulesInputFilePaths?.length) {
+ inputFiles.push(...nodeModulesInputFilePaths);
+ }
+
const filteredInputFiles = filterFiles(inputFiles, filteringGlob);
if (!filteredInputFiles.length) {
throw new Error('No input files to convert');
diff --git a/src/components/components-extractor.ts b/src/components/components-extractor.ts
index 089cf97..e6e5f2c 100644
--- a/src/components/components-extractor.ts
+++ b/src/components/components-extractor.ts
@@ -86,11 +86,7 @@ function findProps(allDefinitions: DeclarationReflection[], propsName: string, d
};
}
-export default function extractComponents(
- publicFilesGlob: string,
- project: ProjectReflection,
- hasCoreComponentTypeDependency?: boolean
-): ComponentDefinition[] {
+export default function extractComponents(publicFilesGlob: string, project: ProjectReflection): ComponentDefinition[] {
const definitions: ComponentDefinition[] = [];
const isMatch = matcher(resolve(publicFilesGlob));
@@ -100,10 +96,6 @@ export default function extractComponents(
const allDefinitions = project.children.flatMap(module => {
if (!module.children) {
- if (hasCoreComponentTypeDependency) {
- return [];
- }
-
throw new Error(`Module ${module.originalName} does not contain a definition.`);
}
diff --git a/src/components/index.ts b/src/components/index.ts
index 05435e7..718bfbc 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -8,11 +8,17 @@ import { bootstrapProject } from '../bootstrap';
export function documentComponents(
tsconfigPath: string,
publicFilesGlob: string,
- hasCoreComponentTypeDependency?: boolean
+ nodeModulesInputFilePaths?: string[]
): ComponentDefinition[] {
- const project = bootstrapProject({
- tsconfig: tsconfigPath,
- includeDeclarations: hasCoreComponentTypeDependency,
- });
- return extractComponents(publicFilesGlob, project, hasCoreComponentTypeDependency);
+ const includeNodeModulePaths = Boolean(nodeModulesInputFilePaths?.length);
+ const project = bootstrapProject(
+ {
+ tsconfig: tsconfigPath,
+ includeDeclarations: includeNodeModulePaths,
+ excludeExternals: includeNodeModulePaths,
+ },
+ undefined,
+ nodeModulesInputFilePaths
+ );
+ return extractComponents(publicFilesGlob, project);
}
diff --git a/test/components/test-helpers.ts b/test/components/test-helpers.ts
index cbb4d18..daf4909 100644
--- a/test/components/test-helpers.ts
+++ b/test/components/test-helpers.ts
@@ -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, nodeModulesInputFilePaths?: string[]): ComponentDefinition[] {
return documentComponents(
require.resolve(`../../fixtures/components/${name}/tsconfig.json`),
- `fixtures/components/${name}/*/index.tsx`
+ `fixtures/components/${name}/*/index.tsx`,
+ nodeModulesInputFilePaths
);
}
diff --git a/test/components/third-party-import-types.test.ts b/test/components/third-party-import-types.test.ts
new file mode 100644
index 0000000..e4b77a7
--- /dev/null
+++ b/test/components/third-party-import-types.test.ts
@@ -0,0 +1,46 @@
+// 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 process from 'node:process';
+const cwd = process.cwd();
+
+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', [
+ `${cwd}/fixtures/components/third-party-import-types/node_modules/icon/interfaces.d.ts`,
+ ]);
+ 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,
+ },
+ ]);
+});