diff --git a/tools/generators/migrate-converged-pkg/index.spec.ts b/tools/generators/migrate-converged-pkg/index.spec.ts new file mode 100644 index 0000000000000..549d6dcf27bc9 --- /dev/null +++ b/tools/generators/migrate-converged-pkg/index.spec.ts @@ -0,0 +1,167 @@ +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; +import { + Tree, + readProjectConfiguration, + readJson, + stripIndents, + addProjectConfiguration, + readWorkspaceConfiguration, +} from '@nrwl/devkit'; + +import generator from './index'; +import { MigrateConvergedPkgGeneratorSchema } from './schema'; + +describe('migrate-converged-pkg generator', () => { + let tree: Tree; + const options: MigrateConvergedPkgGeneratorSchema = { name: '@proj/react-dummy' }; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + tree = setupDummyPackage(tree, options); + }); + + it('should update local tsconfig.json', async () => { + const projectConfig = readProjectConfiguration(tree, options.name); + function getTsConfig() { + return readJson(tree, `${projectConfig.root}/tsconfig.json`); + } + let tsConfig = getTsConfig(); + + expect(tsConfig).toMatchInlineSnapshot(` + Object { + "compilerOptions": Object { + "baseUrl": ".", + "typeRoots": Array [ + "../../node_modules/@types", + "../../typings", + ], + }, + } + `); + + await generator(tree, options); + + tsConfig = getTsConfig(); + + expect(tsConfig).toMatchInlineSnapshot(` + Object { + "compilerOptions": Object { + "declaration": true, + "experimentalDecorators": true, + "importHelpers": true, + "jsx": "react", + "lib": Array [ + "es5", + "dom", + ], + "module": "commonjs", + "noUnusedLocals": true, + "outDir": "dist", + "preserveConstEnums": true, + "target": "es5", + "types": Array [ + "jest", + "custom-global", + "inline-style-expand-shorthand", + ], + }, + "extends": "../../tsconfig.base.json", + "include": Array [ + "src", + ], + } + `); + }); + + it('should update root tsconfig.base.json', async () => { + function getBaseTsConfig() { + return readJson(tree, `/tsconfig.base.json`); + } + + let rootTsConfig = getBaseTsConfig(); + + expect(rootTsConfig).toMatchInlineSnapshot(` + Object { + "compilerOptions": Object { + "paths": Object {}, + }, + } + `); + + await generator(tree, options); + + rootTsConfig = getBaseTsConfig(); + + expect(rootTsConfig).toMatchInlineSnapshot(` + Object { + "compilerOptions": Object { + "paths": Object { + "@proj/react-dummy": Array [ + "packages/react-dummy/src/index.ts", + ], + }, + }, + } + `); + }); +}); + +// ==== helpers ==== + +function serializeJson(value: unknown) { + return JSON.stringify(value, null, 2); +} + +function setupDummyPackage(tree: Tree, options: MigrateConvergedPkgGeneratorSchema) { + const workspaceConfig = readWorkspaceConfiguration(tree); + const pkgName = options.name; + const paths = { + root: `packages/${options.name.replace(`@${workspaceConfig.npmScope}/`, '')}`, + }; + + const dummyPackageJson = { + name: pkgName, + scripts: { + build: 'just-scripts build', + clean: 'just-scripts clean', + 'code-style': 'just-scripts code-style', + just: 'just-scripts', + lint: 'just-scripts lint', + start: 'just-scripts dev:storybook', + 'start-test': 'just-scripts jest-watch', + test: 'just-scripts test', + 'update-snapshots': 'just-scripts jest -u', + }, + }; + + const dummyTsConfig = { + compilerOptions: { + baseUrl: '.', + typeRoots: ['../../node_modules/@types', '../../typings'], + }, + }; + + const dummyJestConfig = stripIndents` + const { createConfig } = require('@fluentui/scripts/jest/jest-resources'); + const path = require('path'); + + const config = createConfig({ + setupFiles: [path.resolve(path.join(__dirname, 'config', 'tests.js'))], + snapshotSerializers: ['@fluentui/jest-serializer-make-styles'], + }); + + module.exports = config; +`; + + tree.write(`${paths.root}/package.json`, serializeJson(dummyPackageJson)); + tree.write(`${paths.root}/tsconfig.json`, serializeJson(dummyTsConfig)); + tree.write(`${paths.root}/jest.config.js`, dummyJestConfig); + + addProjectConfiguration(tree, pkgName, { + root: paths.root, + projectType: 'library', + targets: {}, + }); + + return tree; +} diff --git a/tools/generators/migrate-converged-pkg/index.ts b/tools/generators/migrate-converged-pkg/index.ts new file mode 100644 index 0000000000000..c580f4e9f5221 --- /dev/null +++ b/tools/generators/migrate-converged-pkg/index.ts @@ -0,0 +1,94 @@ +import { + Tree, + formatFiles, + updateJson, + readProjectConfiguration, + readWorkspaceConfiguration, + joinPathFragments, +} from '@nrwl/devkit'; + +import { MigrateConvergedPkgGeneratorSchema } from './schema'; + +/** + * TASK: + * 1. migrate to typescript path aliases - #18343 ✅ (partially done) + * 2. migrate to use standard jest powered by TS path aliases + * 3. setup docs task to run api-extractor for local changes verification + * 4. bootstrap new storybook config + * 5. collocate all package stories from `react-examples` + */ + +interface NormalizedSchema extends ReturnType {} + +export default async function (tree: Tree, schema: MigrateConvergedPkgGeneratorSchema) { + const options = normalizeOptions(tree, schema); + + // 1. update TsConfigs + updatedLocalTsConfig(tree, options); + updatedBaseTsConfig(tree, options); + + formatFiles(tree); +} + +// ==== helpers ==== + +const templates = { + tsconfig: { + extends: '../../tsconfig.base.json', + compilerOptions: { + target: 'es5', + lib: ['es5', 'dom'], + outDir: 'dist', + jsx: 'react', + declaration: true, + module: 'commonjs', + experimentalDecorators: true, + importHelpers: true, + noUnusedLocals: true, + preserveConstEnums: true, + types: ['jest', 'custom-global', 'inline-style-expand-shorthand'], + }, + include: ['src'], + }, + jest: {}, +}; + +function normalizeOptions(host: Tree, options: MigrateConvergedPkgGeneratorSchema) { + const defaults = {}; + const workspaceConfig = readWorkspaceConfiguration(host); + const projectConfig = readProjectConfiguration(host, options.name); + + return { + ...defaults, + ...options, + projectConfig, + workspaceConfig: workspaceConfig, + paths: { + packageJson: joinPathFragments(projectConfig.root, 'package.json'), + tsconfig: joinPathFragments(projectConfig.root, 'tsconfig.json'), + jestConfig: joinPathFragments(projectConfig.root, 'jest.config.js'), + rootTsconfig: '/tsconfig.base.json', + rootJestPreset: '/jest.preset.js', + rootJestConfig: '/jest.config.js', + }, + }; +} + +function serializeJson(value: unknown) { + return JSON.stringify(value, null, 2); +} + +function updatedLocalTsConfig(tree: Tree, options: NormalizedSchema) { + tree.write(options.paths.tsconfig, serializeJson(templates.tsconfig)); + + return tree; +} + +function updatedBaseTsConfig(tree: Tree, options: NormalizedSchema) { + // @TODO: add missing dependencies from migrated package to path aliases + updateJson(tree, options.paths.rootTsconfig, json => { + json.compilerOptions.paths[options.name] = [`${options.projectConfig.root}/src/index.ts`]; + + return json; + }); +} diff --git a/tools/generators/migrate-converged-pkg/schema.json b/tools/generators/migrate-converged-pkg/schema.json new file mode 100644 index 0000000000000..27a4c13f30f0c --- /dev/null +++ b/tools/generators/migrate-converged-pkg/schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/schema", + "cli": "nx", + "id": "migrate-converged-pkg", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Library name", + "$default": { + "$source": "argv", + "index": 0 + } + } + }, + "required": ["name"] +} diff --git a/tools/generators/migrate-converged-pkg/schema.ts b/tools/generators/migrate-converged-pkg/schema.ts new file mode 100644 index 0000000000000..a75b4d900af46 --- /dev/null +++ b/tools/generators/migrate-converged-pkg/schema.ts @@ -0,0 +1,6 @@ +export interface MigrateConvergedPkgGeneratorSchema { + /** + * Library name + */ + name: string; +}