Skip to content

Commit

Permalink
fix(scripts-tasks): make generate-api work in deterministic way (#28215)
Browse files Browse the repository at this point in the history
* fix(scripts-tasks): disable api-extractor custom path aliases usage which causes invalid api.md and .d.ts rollup generation
* chore: add generate-api task definition to lage config
* feat(react-conformance): migrate package to v9 setup in order to be able to run generate-api task without build
  • Loading branch information
Hotell authored Jun 16, 2023
1 parent 676dc58 commit 402599e
Show file tree
Hide file tree
Showing 16 changed files with 243 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "BREAKING CHANGE: migrate package to v9 setup in order to be able to run generate-api task without build",
"packageName": "@fluentui/react-conformance",
"email": "martinhochel@microsoft.com",
"dependentChangeType": "patch"
}
1 change: 1 addition & 0 deletions lage.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
lint: ['build'],
clean: [],
test: ['build'],
'generate-api': ['^generate-api'],
'test-ssr': [],
'type-check': ['build'],
'code-style': [],
Expand Down
61 changes: 32 additions & 29 deletions packages/react-conformance/.npmignore
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
.storybook/
.vscode/
bundle-size/
config/
coverage/
docs/
etc/
node_modules/
src/
stories/
dist/types/
temp/
__fixtures__
__mocks__
__tests__

*.api.json
*.config.js
*.log
*.nuspec
*.spec.*
*.cy.*
*.test.*
*.yml

# config files
*config.*
*rc.*
.editorconfig
.eslintrc*
.eslintcache
.gitattributes
.gitignore
.vscode
coverage
dist/storybook
dist/*.stats.html
dist/*.stats.json
dist/demo
fabric-test*
gulpfile.js
images
index.html
jsconfig.json
node_modules
results
src/**/*
!src/**/examples/*.tsx
!src/**/docs/**/*.md
!src/**/*.types.ts
temp
tsconfig.json
tsd.json
tslint.json
typings
visualtests
.eslint*
.git*
.prettierignore
.swcrc

# exclude gitignore patterns explicitly
!lib
!lib-commonjs
!lib-amd
!dist/*.d.ts
30 changes: 30 additions & 0 deletions packages/react-conformance/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "https://json.schemastore.org/swcrc",
"exclude": [
"/testing",
"/**/*.cy.ts",
"/**/*.cy.tsx",
"/**/*.spec.ts",
"/**/*.spec.tsx",
"/**/*.test.ts",
"/**/*.test.tsx"
],
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": false,
"dynamicImport": false
},
"externalHelpers": true,
"transform": {
"react": {
"runtime": "classic",
"useSpread": true
}
},
"target": "es2019"
},
"minify": false,
"sourceMaps": true
}
5 changes: 5 additions & 0 deletions packages/react-conformance/config/api-extractor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "@fluentui/scripts-api-extractor/api-extractor.common.v-next.json",
"mainEntryPointFilePath": "<projectFolder>/../../dist/out-tsc/types/packages/<unscopedPackageName>/src/index.d.ts"
}
1 change: 1 addition & 0 deletions packages/react-conformance/config/tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** Jest test setup file. */
75 changes: 75 additions & 0 deletions packages/react-conformance/etc/react-conformance.api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
## API Report File for "@fluentui/react-conformance"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts

import { ComponentDoc } from 'react-docgen-typescript';
import * as React_2 from 'react';
import { render } from '@testing-library/react';
import * as ts from 'typescript';

// @public (undocumented)
export type ConformanceTest<TProps = {}> = (componentInfo: ComponentDoc, testInfo: IsConformantOptions<TProps>, tsProgram: ts.Program) => void;

// @public (undocumented)
export function isConformant<TProps = {}>(...testInfo: Partial<IsConformantOptions<TProps>>[]): void;

// @public (undocumented)
export interface IsConformantOptions<TProps = {}> {
Component: React_2.ComponentType<TProps>;
componentPath: string;
disabledTests?: string[];
displayName: string;
elementRefName?: string;
extraTests?: TestObject<TProps>;
getTargetElement?: (renderResult: ReturnType<typeof render>, attr: keyof React_2.AllHTMLAttributes<HTMLElement> | 'ref' | `data-${string}`) => HTMLElement;
isInternal?: boolean;
primarySlot?: keyof TProps | 'root';
renderOptions?: Parameters<typeof render>[1];
requiredProps?: Partial<TProps>;
testOptions?: TestOptions;
tsConfig?: Partial<{
configName: string;
configDir: string;
}>;
// @deprecated (undocumented)
tsconfigDir?: string;
useDefaultExport?: boolean;
}

// @public (undocumented)
export interface TestObject<TProps = {}> {
// (undocumented)
[key: string]: ConformanceTest<TProps>;
}

// @public
export interface TestOptions {
// (undocumented)
'component-has-static-classname'?: {
prefix?: string;
};
// (undocumented)
'consistent-callback-args'?: {
ignoreProps?: string[];
};
// (undocumented)
'consistent-callback-names'?: {
ignoreProps?: string[];
};
// (undocumented)
'has-static-classnames'?: {
props: {
[key: string]: string | {};
};
expectedClassNames?: {
[key: string]: string;
};
getPortalElement?: (renderResult: ReturnType<typeof render>) => HTMLElement;
}[];
}

// (No @packageDocumentation comment for this package)

```
23 changes: 19 additions & 4 deletions packages/react-conformance/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
const { createV8Config: createConfig } = require('@fluentui/scripts-jest');
// @ts-check

const config = createConfig({});

module.exports = config;
/**
* @type {import('@jest/types').Config.InitialOptions}
*/
module.exports = {
displayName: 'react-conformance',
preset: '../../jest.preset.js',
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
isolatedModules: true,
},
},
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
coverageDirectory: './coverage',
setupFilesAfterEnv: ['./config/tests.js'],
};
2 changes: 1 addition & 1 deletion packages/react-conformance/just.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import { preset, task } from '@fluentui/scripts-tasks';

preset();

task('build', 'build:node-lib').cached!();
task('build', 'build:react-components').cached?.();
14 changes: 12 additions & 2 deletions packages/react-conformance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.16.3",
"description": "Customizable conformance testing utility for Fluent UI React components.",
"main": "lib-commonjs/index.js",
"typings": "lib-commonjs/index.d.ts",
"typings": "dist/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/microsoft/fluentui"
Expand All @@ -15,7 +15,9 @@
"code-style": "just-scripts code-style",
"just": "just-scripts",
"test": "just-scripts test",
"lint": "just-scripts lint"
"lint": "just-scripts lint",
"generate-api": "just-scripts generate-api",
"type-check": "just-scripts type-check"
},
"devDependencies": {
"@fluentui/eslint-plugin": "*",
Expand All @@ -37,5 +39,13 @@
"react": ">=16.8.0 <19.0.0",
"react-dom": ">=16.8.0 <19.0.0",
"typescript": "^4.3.0"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"node": "./lib-commonjs/index.js",
"require": "./lib-commonjs/index.js"
},
"./package.json": "./package.json"
}
}
30 changes: 15 additions & 15 deletions packages/react-conformance/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": ".",
"outDir": "lib",
"target": "es6",
"module": "commonjs",
"target": "ES2019",
"noEmit": true,
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"isolatedModules": true,
"importHelpers": true,
"noUnusedLocals": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"moduleResolution": "node",
"preserveConstEnums": true,
"isolatedModules": true,
"lib": ["es2017", "dom"],
"types": ["jest", "node"]
"noUnusedLocals": true
},
"include": ["src"]
"include": [],
"files": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
15 changes: 15 additions & 0 deletions packages/react-conformance/tsconfig.lib.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"lib": ["DOM", "ES2019"],
"declaration": true,
"declarationDir": "../../dist/out-tsc/types",
"outDir": "../../dist/out-tsc",
"inlineSources": true,
"types": ["static-assets", "environment", "jest", "node"],
"module": "CommonJS"
},
"exclude": ["**/*.spec.ts", "**/*.spec.tsx", "**/*.test.ts", "**/*.test.tsx"],
"include": ["./src/**/*.ts", "./src/**/*.tsx"]
}
9 changes: 9 additions & 0 deletions packages/react-conformance/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "CommonJS",
"outDir": "dist",
"types": ["jest", "node"]
},
"include": ["**/*.spec.ts", "**/*.spec.tsx", "**/*.test.ts", "**/*.test.tsx", "**/*.d.ts"]
}
7 changes: 5 additions & 2 deletions scripts/tasks/src/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@ describe(`utils`, () => {
definitionsRootPath: 'dist/for/types',
});

expect(actual.overrideTsconfig.compilerOptions).toEqual(expect.objectContaining({ paths: undefined }));
expect(actual.overrideTsconfig.compilerOptions).toEqual(
expect.objectContaining({ paths: undefined, baseUrl: '.' }),
);
});

it(`should override path aliases to emitted declaration files instead of source files`, () => {
// This is not used unless api-extractor resolves resolving workspace d.ts packages - see https://github.com/microsoft/rushstack/pull/3321, https://github.com/microsoft/rushstack/pull/3339
it.skip(`should override path aliases to emitted declaration files instead of source files`, () => {
const actual = setup({
definitionsRootPath: 'dist/for/types',
pathAliasesTsConfigPath: path.join(workspaceRoot, 'tsconfig.base.json'),
Expand Down
21 changes: 14 additions & 7 deletions scripts/tasks/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ function enableAllowSyntheticDefaultImports(options: { pkgJson: PackageJson }) {
return shouldEnable ? { allowSyntheticDefaultImports: true } : null;
}

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - 💡 NOTE: this is not used unless api-extractor resolves resolving workspace d.ts packages - see https://github.com/microsoft/rushstack/pull/3321, https://github.com/microsoft/rushstack/pull/3339
function createNormalizedTsPaths(options: { definitionsRootPath: string; pathAliasesTsConfigPath: string }) {
type PathAliases = Record<string, string[]>;
const { definitionsRootPath, pathAliasesTsConfigPath } = options;
Expand All @@ -132,14 +134,16 @@ export function getTsPathAliasesApiExtractorConfig(options: {
definitionsRootPath: string;
pathAliasesTsConfigPath?: string;
}) {
const { packageJson, tsConfig, pathAliasesTsConfigPath, definitionsRootPath } = options;
const { packageJson, tsConfig /* , pathAliasesTsConfigPath, definitionsRootPath */ } = options;
/**
* Because api-extractor ran into race conditions when executing via lage (https://github.com/microsoft/fluentui/issues/25766),
* we won't use path aliases on CI, rather serving api-extractor rolluped dts files cross package, that will be referenced via yarn workspace sym-links
*
* 💡 NOTE: this is not used unless api-extractor resolves resolving workspace d.ts packages - see https://github.com/microsoft/rushstack/pull/3321, https://github.com/microsoft/rushstack/pull/3339
*/
const normalizedPaths = pathAliasesTsConfigPath
? createNormalizedTsPaths({ definitionsRootPath, pathAliasesTsConfigPath })
: undefined;
// const normalizedPaths = pathAliasesTsConfigPath
// ? createNormalizedTsPaths({ definitionsRootPath, pathAliasesTsConfigPath })
// : undefined;

/**
* Customized TSConfig that uses `tsconfig.lib.json` as base with some required overrides:
Expand All @@ -166,10 +170,13 @@ export function getTsPathAliasesApiExtractorConfig(options: {
*/
skipLibCheck: false,
/**
* just-scripts provides invalid types for tsconfig, thus `paths` cannot be set to dictionary,nor null or `{}`
* api-extractor introduced a "feature" which is actually a bug and makes using path aliases impossible
* - with this api extractor change user is forced to rely on yarn/npm "workspace" symlinks in order to determine that inner workspace package should not be bundled in type definition rollup/api.md
* - see https://github.com/microsoft/rushstack/pull/3321, https://github.com/microsoft/rushstack/pull/3339
*
*/
// @ts-expect-error - just-scripts provides invalid types
paths: normalizedPaths,
paths: undefined,
baseUrl: '.',
},
};

Expand Down
Loading

0 comments on commit 402599e

Please sign in to comment.