diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a2389381423bfc..225dd3a402d521 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -133,6 +133,7 @@ apps/recipes-react-components @microsoft/cxe-red @microsoft/cxe-coastal @microso #### Packages packages/azure-themes @Jacqueline-ms @robtaft-ms packages/bundle-size @microsoft/teams-prg +packages/react-conformance @microsoft/fluentui-react-build packages/date-time-utilities @microsoft/cxe-red packages/eslint-plugin @microsoft/fluentui-react-build packages/foundation-legacy @microsoft/cxe-red @khmakoto diff --git a/change/@fluentui-react-conformance-9b875b33-ced4-434a-9690-448766658f08.json b/change/@fluentui-react-conformance-9b875b33-ced4-434a-9690-448766658f08.json new file mode 100644 index 00000000000000..26d48b6da4a784 --- /dev/null +++ b/change/@fluentui-react-conformance-9b875b33-ced4-434a-9690-448766658f08.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: add new TS config api to be able to specify configName and configDir", + "packageName": "@fluentui/react-conformance", + "email": "martinhochel@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-conformance/src/isConformant.ts b/packages/react-conformance/src/isConformant.ts index 734e1cb0090828..2711019ebf321a 100644 --- a/packages/react-conformance/src/isConformant.ts +++ b/packages/react-conformance/src/isConformant.ts @@ -8,14 +8,28 @@ import { getComponentDoc } from './utils/getComponentDoc'; export function isConformant(...testInfo: Partial>[]) { const mergedOptions = merge(...testInfo); - const { componentPath, displayName, disabledTests = [], extraTests, tsconfigDir } = mergedOptions; + + const { + componentPath, + displayName, + disabledTests = [], + extraTests, + tsConfig, + // eslint-disable-next-line deprecation/deprecation + tsconfigDir, + } = mergedOptions; + + const mergedTsConfig = { + configDir: tsConfig?.configDir ?? tsconfigDir, + configName: tsConfig?.configName, + }; describe('isConformant', () => { if (!fs.existsSync(componentPath)) { throw new Error(`Path ${componentPath} does not exist`); } - const tsProgram = createTsProgram(componentPath, tsconfigDir); + const tsProgram = createTsProgram(componentPath, mergedTsConfig); const components = getComponentDoc(componentPath, tsProgram); const mainComponents = components.filter(comp => comp.displayName === displayName); diff --git a/packages/react-conformance/src/types.ts b/packages/react-conformance/src/types.ts index 0abb94ea054c5c..5e950e4e3af70e 100644 --- a/packages/react-conformance/src/types.ts +++ b/packages/react-conformance/src/types.ts @@ -92,10 +92,16 @@ export interface IsConformantOptions { primarySlot?: keyof TProps | 'root'; /** + * @deprecated - use `tsConfig` property + * * Test will load the first tsconfig.json file working upwards from `tsconfigDir`. * @defaultvalue the directory of the component being tested */ tsconfigDir?: string; + /** + * replaces tsconfigDir + */ + tsConfig?: Partial<{ configName: string; configDir: string }>; } export type ConformanceTest = ( diff --git a/packages/react-conformance/src/utils/createTsProgram.ts b/packages/react-conformance/src/utils/createTsProgram.ts index c2fb35a59d1d4a..9c35cf10473929 100644 --- a/packages/react-conformance/src/utils/createTsProgram.ts +++ b/packages/react-conformance/src/utils/createTsProgram.ts @@ -5,18 +5,23 @@ import * as ts from 'typescript'; let program: ts.Program; /** - * Creates a cached TS Program. + * Creates a ~cached~ TS Program. + * @remarks this will be never cached with current use/setup as jest creates this for every it/describe() block 🐌 */ -export function createTsProgram(componentPath: string, tsconfigDir?: string): ts.Program { +export function createTsProgram( + sourcePath: string, + options: Partial<{ configDir: string; configName: string }> = {}, +): ts.Program { + const { configName, configDir } = options; if (!program) { // Calling parse() from react-docgen-typescript would create a new ts.Program for every component, // which can take multiple seconds in a large project. For better performance, we create a single // ts.Program per package and pass it to parseWithProgramProvider(). - const tsconfigPath = ts.findConfigFile(tsconfigDir ?? componentPath, fs.existsSync); + const tsconfigPath = ts.findConfigFile(configDir ?? sourcePath, fs.existsSync, configName); if (!tsconfigPath) { - throw new Error('Cannot find tsconfig.json'); + throw new Error(`Cannot find ${configName}`); } const compilerOptions = getCompilerOptions(tsconfigPath); @@ -33,9 +38,9 @@ export function createTsProgram(componentPath: string, tsconfigDir?: string): ts program = ts.createProgram([rootFile], compilerOptions); } - if (!program.getSourceFile(componentPath)) { + if (!program.getSourceFile(sourcePath)) { // See earlier comment for why it's handled this way (can reconsider if it becomes a problem) - throw new Error(`Component file "${componentPath}" does not appear to be referenced from the project index file`); + throw new Error(`Component file "${sourcePath}" does not appear to be referenced from the project index file`); } return program;