From 770937944458634028fa451f883698c3ff434646 Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Thu, 20 Oct 2022 12:52:09 +0200 Subject: [PATCH] feat(tools): add unstable API setup updates --- .../migrate-converged-pkg/index.spec.ts | 218 +++++++++++++----- .../generators/migrate-converged-pkg/index.ts | 160 ++++++++----- tools/types.ts | 2 + 3 files changed, 272 insertions(+), 108 deletions(-) diff --git a/tools/generators/migrate-converged-pkg/index.spec.ts b/tools/generators/migrate-converged-pkg/index.spec.ts index 4e0502b28ef19..5e0124bf699dd 100644 --- a/tools/generators/migrate-converged-pkg/index.spec.ts +++ b/tools/generators/migrate-converged-pkg/index.spec.ts @@ -19,6 +19,7 @@ import { writeJson, WorkspaceConfiguration, joinPathFragments, + ProjectConfiguration, } from '@nrwl/devkit'; import { PackageJson, TsConfig } from '../../types'; @@ -941,73 +942,55 @@ describe('migrate-converged-pkg generator', () => { }); }); - it(`should update exports map`, async () => { - const projectConfig = readProjectConfiguration(tree, options.name); - const pkgJsonPath = `${projectConfig.root}/package.json`; + describe(`export-maps`, () => { + function setup(config: { name: string; addModuleField?: boolean }) { + const addModuleField = config.addModuleField ?? true; + const projectConfig = readProjectConfiguration(tree, config.name); + const pkgJsonPath = `${projectConfig.root}/package.json`; - let pkgJson = readJson(tree, pkgJsonPath); + if (addModuleField) { + updateJson(tree, pkgJsonPath, json => { + json.module = './lib/index.js'; + return json; + }); + } - expect(pkgJson.exports).toBe(undefined); + const getPackageJson = () => readJson(tree, pkgJsonPath); - await generator(tree, options); + return { getPackageJson }; + } - pkgJson = readJson(tree, pkgJsonPath); + it(`should update exports map`, async () => { + const { getPackageJson } = setup({ name: options.name }); - expect(pkgJson.exports).toMatchInlineSnapshot(` - Object { - ".": Object { - "import": "./lib/index.js", - "require": "./lib-commonjs/index.js", - "types": "./dist/index.d.ts", - }, - "./package.json": "./package.json", - } - `); - }); + let pkgJson = getPackageJson(); - it(`should update exports map if unstable API is present`, async () => { - const projectConfig = readProjectConfiguration(tree, options.name); - const pkgJsonPath = `${projectConfig.root}/package.json`; - const pkgJsonUnstablePath = `${projectConfig.root}/src/unstable/package.json__tmpl__`; - writeJson(tree, pkgJsonUnstablePath, { - typings: './../dist/unstable.d.ts', - }); + expect(pkgJson.exports).toBe(undefined); - let pkgJson = readJson(tree, pkgJsonPath); - let pkgUnstableJson = readJson(tree, pkgJsonUnstablePath); + await generator(tree, options); - expect(pkgJson.exports).toBe(undefined); - expect(pkgUnstableJson.exports).toBe(undefined); + pkgJson = getPackageJson(); + + expect(pkgJson.exports).toMatchInlineSnapshot(` + Object { + ".": Object { + "import": "./lib/index.js", + "require": "./lib-commonjs/index.js", + "types": "./dist/index.d.ts", + }, + "./package.json": "./package.json", + } + `); + }); - await generator(tree, options); + it(`should update exports map based on main,module fields`, async () => { + const { getPackageJson } = setup({ name: options.name, addModuleField: false }); - pkgJson = readJson(tree, pkgJsonPath); - pkgUnstableJson = readJson(tree, pkgJsonUnstablePath); + await generator(tree, options); - expect(pkgJson.exports).toMatchInlineSnapshot(` - Object { - ".": Object { - "import": "./lib/index.js", - "require": "./lib-commonjs/index.js", - "types": "./dist/index.d.ts", - }, - "./package.json": "./package.json", - "./unstable": Object { - "import": "./lib/unstable/index.js", - "require": "./lib-commonjs/unstable/index.js", - "types": "./dist/unstable.d.ts", - }, - } - `); - expect(pkgUnstableJson.exports).toMatchInlineSnapshot(` - Object { - ".": Object { - "import": "./../lib/unstable/index.js", - "require": "./../lib-commonjs/unstable/index.js", - "types": "./../dist/unstable.d.ts", - }, - } - `); + const pkgJson = getPackageJson(); + expect(pkgJson.exports['.'].module).toBe(undefined); + }); }); it(`should not add start scripts to node packages`, async () => { @@ -1401,6 +1384,128 @@ describe('migrate-converged-pkg generator', () => { `); }); }); + + describe(`unstable API`, () => { + const getPkgJsonUnstablePath = (projectConfig: ProjectConfiguration) => { + return `${projectConfig.root}/src/unstable/package.json__tmpl__`; + }; + + describe(`export-maps`, () => { + function setup(config: { name: string; addModuleField?: boolean }) { + const addModuleField = config.addModuleField ?? true; + const projectConfig = readProjectConfiguration(tree, config.name); + const pkgJsonPath = `${projectConfig.root}/package.json`; + const pkgJsonUnstablePath = getPkgJsonUnstablePath(projectConfig); + + if (addModuleField) { + updateJson(tree, pkgJsonPath, json => { + json.module = './lib/index.js'; + return json; + }); + } + + writeJson(tree, pkgJsonUnstablePath, { + typings: './../dist/unstable.d.ts', + ...(addModuleField ? { module: './../lib/index.js' } : null), + }); + const getUnstablePackageJson = () => readJson(tree, pkgJsonUnstablePath); + + const getPackageJson = () => readJson(tree, pkgJsonPath); + + return { getPackageJson, getUnstablePackageJson }; + } + + it(`should update exports map in stable package.json`, async () => { + const { getPackageJson } = setup({ name: options.name }); + + await generator(tree, options); + + const pkgJson = getPackageJson(); + + expect(pkgJson.exports['./unstable']).toMatchInlineSnapshot(` + Object { + "import": "./lib/unstable/index.js", + "require": "./lib-commonjs/unstable/index.js", + "types": "./dist/unstable.d.ts", + } + `); + }); + + it(`should update exports map`, async () => { + const { getUnstablePackageJson } = setup({ name: options.name }); + + let pkgJson = getUnstablePackageJson(); + + expect(pkgJson.exports).toBe(undefined); + + await generator(tree, options); + + pkgJson = getUnstablePackageJson(); + + expect(pkgJson.exports).toMatchInlineSnapshot(` + Object { + ".": Object { + "import": "./../lib/unstable/index.js", + "require": "./../lib-commonjs/unstable/index.js", + "types": "./../dist/unstable.d.ts", + }, + } + `); + }); + + it(`should update exports map based on main,module fields`, async () => { + const { getPackageJson, getUnstablePackageJson } = setup({ + name: options.name, + addModuleField: false, + }); + + await generator(tree, options); + + const pkgJson = getPackageJson(); + const unstablePkgJson = getUnstablePackageJson(); + + expect(pkgJson.exports['./unstable'].module).toBe(undefined); + expect(unstablePkgJson.exports['.'].module).toBe(undefined); + }); + }); + + describe(`api-extractor`, () => { + it(`should create api-extractor.json`, async () => { + const projectConfig = readProjectConfiguration(tree, options.name); + const pkgJsonUnstablePath = getPkgJsonUnstablePath(projectConfig); + writeJson(tree, pkgJsonUnstablePath, { + description: 'unstable api', + sideEffects: false, + main: '../lib-commonjs/unstable/index.js', + }); + const apiExtractorConfigPath = `${projectConfig.root}/config/api-extractor.unstable.json`; + + expect(tree.exists(apiExtractorConfigPath)).toBeFalsy(); + + await generator(tree, options); + + expect(tree.exists(apiExtractorConfigPath)).toBeTruthy(); + /* eslint-disable @fluentui/max-len */ + expect(readJson(tree, apiExtractorConfigPath)).toMatchInlineSnapshot(` + Object { + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "apiReport": Object { + "enabled": true, + "reportFileName": ".unstable.api.md", + }, + "dtsRollup": Object { + "enabled": true, + "publicTrimmedFilePath": "/dist/unstable.d.ts", + "untrimmedFilePath": "/dist/unstable-untrimmed.d.ts", + }, + "extends": "@fluentui/scripts/api-extractor/api-extractor.common.v-next.json", + "mainEntryPointFilePath": "/../../../dist/out-tsc/types/packages/react-components//src/unstable/index.d.ts", + } + `); + /* eslint-enable @fluentui/max-len */ + }); + }); + }); }); // ==== helpers ==== @@ -1457,6 +1562,7 @@ function setupDummyPackage( name: pkgName, version: normalizedOptions.version, typings: 'lib/index.d.ts', + main: 'lib-commonjs/index.js', scripts: { build: 'just-scripts build', clean: 'just-scripts clean', diff --git a/tools/generators/migrate-converged-pkg/index.ts b/tools/generators/migrate-converged-pkg/index.ts index 9cb649c547745..91ffb014520a6 100644 --- a/tools/generators/migrate-converged-pkg/index.ts +++ b/tools/generators/migrate-converged-pkg/index.ts @@ -143,6 +143,8 @@ function runMigrationOnProject(tree: Tree, schema: AssertedSchema, _userLog: Use updateNxWorkspace(tree, options); moveDocsToSubfolder(tree, options); + + setupUnstableApi(tree, optionsWithTsConfigs); } // ==== helpers ==== @@ -160,6 +162,22 @@ const templates = { publicTrimmedFilePath: '/dist/index.d.ts', }, }, + unstable: { + $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: + // eslint-disable-next-line @fluentui/max-len + '/../../../dist/out-tsc/types/packages/react-components//src/unstable/index.d.ts', + apiReport: { + enabled: true, + reportFileName: '.unstable.api.md', + }, + dtsRollup: { + enabled: true, + untrimmedFilePath: '/dist/unstable-untrimmed.d.ts', + publicTrimmedFilePath: '/dist/unstable.d.ts', + }, + }, }; }, @@ -553,32 +571,88 @@ interface NormalizedSchemaWithTsConfigs extends NormalizedSchema { tsconfigs: ReturnType['configs']; } -function updatePackageJson(tree: Tree, options: NormalizedSchemaWithTsConfigs) { - const scripts = { - 'generate-api': 'tsc -p ./tsconfig.lib.json --emitDeclarationOnly && just-scripts api-extractor', - test: 'jest --passWithNoTests', - 'type-check': 'tsc -b tsconfig.json', - }; +function setupUnstableApi(tree: Tree, options: NormalizedSchemaWithTsConfigs) { + const unstablePackageJsonPath = options.paths.unstable.rootPackageJson; + const hasUnstableApi = tree.exists(unstablePackageJsonPath); - const unstableApiDefinitions = processUnstableApiDefinitions(); + if (!hasUnstableApi) { + return; + } - if (unstableApiDefinitions) { - updateJson(tree, unstableApiDefinitions.unstablePackageJsonPath, (json: PackageJson) => { - json.exports = unstableApiDefinitions.unstableExportMap; - return json; + updateUnstablePackageJson(); + updateUnstableApiExtractorForLocalBuilds(); + + return tree; + + function updateUnstableApiExtractorForLocalBuilds() { + const apiExtractor = templates.apiExtractor(); + + writeJson(tree, joinPathFragments(options.paths.configRoot, 'api-extractor.unstable.json'), apiExtractor.unstable); + + return; + } + + function updateUnstablePackageJson() { + const packageJsonPath = options.paths.packageJson; + + let unstablePackageJson = readJson(tree, unstablePackageJsonPath); + let packageJson = readJson(tree, packageJsonPath); + + Object.assign(unstablePackageJson, { + main: '../lib-commonjs/unstable/index.js', + ...(packageJson.module ? { module: '../lib/unstable/index.js' } : null), + typings: './../dist/unstable.d.ts', }); + + const updates = setupExportMaps(unstablePackageJson, packageJson); + + unstablePackageJson = updates.json; + packageJson = updates.rootJson; + + writeJson(tree, unstablePackageJsonPath, unstablePackageJson); + writeJson(tree, packageJsonPath, packageJson); + + return; + + function setupExportMaps(unstableJson: PackageJson, stableJson: PackageJson) { + unstableJson.exports = { + '.': { + types: unstableJson.typings, + ...(packageJson.module ? { import: './../lib/unstable/index.js' } : null), + require: './../lib-commonjs/unstable/index.js', + }, + }; + + Object.assign(stableJson.exports, { + './unstable': { + types: unstableJson.typings?.replace(/\.\.\//g, ''), + ...(packageJson.module ? { import: './lib/unstable/index.js' } : null), + require: './lib-commonjs/unstable/index.js', + }, + }); + + return { json: unstableJson, rootJson: stableJson }; + } } +} - updateJson(tree, options.paths.packageJson, (json: PackageJson) => { - json.typings = './dist/index.d.ts'; - json.exports = { - '.': { - types: json.typings, - import: './lib/index.js', - require: './lib-commonjs/index.js', - }, - ...(unstableApiDefinitions ? unstableApiDefinitions.rootExportMap : null), - './package.json': './package.json', +function updatePackageJson(tree: Tree, options: NormalizedSchemaWithTsConfigs) { + let packageJson = readJson(tree, options.paths.packageJson); + + packageJson.typings = './dist/index.d.ts'; + + packageJson = setupScripts(packageJson); + packageJson = setupExportMaps(packageJson); + + writeJson(tree, options.paths.packageJson, packageJson); + + return tree; + + function setupScripts(json: PackageJson) { + const scripts = { + 'generate-api': 'tsc -p ./tsconfig.lib.json --emitDeclarationOnly && just-scripts api-extractor', + test: 'jest --passWithNoTests', + 'type-check': 'tsc -b tsconfig.json', }; json.scripts = json.scripts || {}; @@ -596,41 +670,23 @@ function updatePackageJson(tree: Tree, options: NormalizedSchemaWithTsConfigs) { } return json; - }); + } - return tree; + function setupExportMaps(json: PackageJson) { + json.exports = { + '.': { + types: json.typings, + ...(json.module ? { import: normalizePackageEntryPointPaths(json.module) } : null), + ...(json.main ? { require: normalizePackageEntryPointPaths(json.main) } : null), + }, + './package.json': './package.json', + }; - function processUnstableApiDefinitions() { - const unstablePackageJsonPath = joinPathFragments(options.paths.unstable.rootPackageJson); - const hasUnstableApi = tree.exists(unstablePackageJsonPath); + return json; - if (!hasUnstableApi) { - return; + function normalizePackageEntryPointPaths(entryPath: string) { + return './' + path.normalize(entryPath); } - - const unstablePackageJson = readJson(tree, unstablePackageJsonPath); - const typePaths = { - rootExports: unstablePackageJson.typings?.replace(/\.\.\//g, ''), - unstableExports: unstablePackageJson.typings, - }; - - return { - unstablePackageJsonPath, - rootExportMap: { - './unstable': { - types: typePaths.rootExports, - import: './lib/unstable/index.js', - require: './lib-commonjs/unstable/index.js', - }, - }, - unstableExportMap: { - '.': { - types: typePaths.unstableExports, - import: './../lib/unstable/index.js', - require: './../lib-commonjs/unstable/index.js', - }, - }, - }; } } diff --git a/tools/types.ts b/tools/types.ts index 895f33de71f22..300e6b04a9e8b 100644 --- a/tools/types.ts +++ b/tools/types.ts @@ -25,6 +25,8 @@ export interface PackageJson { typings?: string; private?: boolean; name: string; + main: string; + module?: string; version: string; scripts?: Record; dependencies?: Record;