diff --git a/packages/@o3r/workspace/schematics/index.it.spec.ts b/packages/@o3r/workspace/schematics/index.it.spec.ts index bcc0750764..b37f360aa2 100644 --- a/packages/@o3r/workspace/schematics/index.it.spec.ts +++ b/packages/@o3r/workspace/schematics/index.it.spec.ts @@ -90,7 +90,7 @@ describe('new otter workspace', () => { expect(() => packageManagerRunOnProject('@my-sdk/sdk', isInWorkspace, { script: 'spec:upgrade' }, execAppOptions)).not.toThrow(); }); - test('should add a library to an existing workspace', () => { + test('should add a library to an existing workspace', async () => { const { workspacePath } = o3rEnvironment.testEnvironment; const execAppOptions = { ...getDefaultExecSyncOptions(), cwd: workspacePath }; const libName = 'test-library'; @@ -115,6 +115,10 @@ describe('new otter workspace', () => { expect(existsSync(path.join(workspacePath, 'project'))).toBe(false); generatedLibFiles.forEach((file) => expect(existsSync(path.join(inLibraryPath, file))).toBe(true)); expect(() => packageManagerRunOnProject(libName, true, { script: 'build' }, execAppOptions)).not.toThrow(); + + // check tsconfig.lib.prod.json override + const tsconfigLibProd = JSON.parse(await fs.readFile(path.join(inLibraryPath, 'tsconfig.lib.prod.json'), { encoding: 'utf8' })); + expect(!!tsconfigLibProd.extends && existsSync(path.resolve(inLibraryPath, tsconfigLibProd.extends))).toBe(true); }); test('should generate a monorepo setup', async () => { diff --git a/packages/@o3r/workspace/schematics/library/index.spec.ts b/packages/@o3r/workspace/schematics/library/index.spec.ts index e8ea8ad7e0..775607e251 100644 --- a/packages/@o3r/workspace/schematics/library/index.spec.ts +++ b/packages/@o3r/workspace/schematics/library/index.spec.ts @@ -20,24 +20,14 @@ const collectionPath = path.join(__dirname, '..', '..', 'collection.json'); describe('New module generator', () => { let initialTree: Tree; - beforeEach(() => { initialTree = Tree.empty(); - initialTree.create('/tsconfig.base.json', JSON.stringify({ - compilerOptions: { - paths: {} - } - })); - initialTree.create('/tsconfig.build.json', JSON.stringify({ - compilerOptions: { - paths: {} - } - })); + initialTree.create('angular.json', '{"version": 1, "projects": {} }'); + initialTree.create('package.json', '{ "version": "0.0.0-test" }'); }); it('should generate the minimum mandatory files', async () => { - initialTree.create('angular.json', '{"version": 1, "projects": {} }'); - initialTree.create('package.json', '{ "version": "0.0.0-test" }'); + initialTree.create('/tsconfig.base.json', JSON.stringify({})); initialTree.create('/packages-test/my-new-module/package.json', '{ "version": "0.0.0-test" }'); initialTree.create('/packages-test/my-new-module/ng-package.json', '{ }'); const runner = new SchematicTestRunner('schematics', collectionPath); @@ -55,12 +45,34 @@ describe('New module generator', () => { expect(spy).toHaveBeenNthCalledWith(1, '@schematics/angular', 'library', expect.anything()); expect(tree.exists('/packages-test/my-new-module/tsconfig.json')).toBe(true); + expect(tree.readJson('/packages-test/my-new-module/tsconfig.lib.prod.json')).toStrictEqual({ extends: '../../tsconfig.base.json' }); expect(tree.exists('/packages-test/my-new-module/project.json')).toBe(false); expect(JSON.parse(tree.readContent('/tsconfig.base.json')).compilerOptions.paths['@my/new-module']).toContain('packages-test/my-new-module/src/public-api'); - expect(JSON.parse(tree.readContent('/tsconfig.build.json')).compilerOptions.paths['@my/new-module'][0]).toBe('packages-test/my-new-module/dist'); + expect(JSON.parse(tree.readContent('/tsconfig.base.json')).compilerOptions.paths['@my/new-module']).not.toContain('packages-test/my-new-module/dist'); + expect(tree.exists('/tsconfig.build.json')).toBe(true); + expect(JSON.parse(tree.readContent('/tsconfig.build.json')).compilerOptions.paths['@my/new-module']).toContain('packages-test/my-new-module/dist'); expect(tree.files.length).toBeGreaterThanOrEqual(9); }); + it('should handle the missing tsconfig.base.json', async () => { + initialTree.create('/packages-test/my-new-module/package.json', '{ "version": "0.0.0-test" }'); + initialTree.create('/packages-test/my-new-module/ng-package.json', '{ }'); + const runner = new SchematicTestRunner('schematics', collectionPath); + const angularPackageJson = require.resolve('@schematics/angular/package.json'); + const o3rCorePackageJson = require.resolve('@o3r/core/package.json'); + runner.registerCollection('@o3r/core', path.resolve(path.dirname(o3rCorePackageJson), require(o3rCorePackageJson).schematics)); + runner.registerCollection('@schematics/angular', path.resolve(path.dirname(angularPackageJson), require(angularPackageJson).schematics)); + const spy = jest.spyOn(require('@angular-devkit/schematics'), 'externalSchematic'); + const tree = await runner.runSchematic('library', { + path: 'packages-test', + name: '@my/new-module', + skipLinter: true, + skipInstall: true + }, initialTree); + expect(spy).toHaveBeenNthCalledWith(1, '@schematics/angular', 'library', expect.anything()); + expect(tree.exists('/tsconfig.base.json')).toBe(false); + }); + // eslint-disable-next-line jest/no-disabled-tests -- TODO: Should be re-enable when the following issue #2066 is fixed describe.skip('in NX monorepo', () => { it('should generate Nx project.json with given name', async () => { diff --git a/packages/@o3r/workspace/schematics/library/rules/rules.ng.ts b/packages/@o3r/workspace/schematics/library/rules/rules.ng.ts index 6384dd4447..7bfc7d18cb 100644 --- a/packages/@o3r/workspace/schematics/library/rules/rules.ng.ts +++ b/packages/@o3r/workspace/schematics/library/rules/rules.ng.ts @@ -85,26 +85,46 @@ export function ngGenerateModule(options: NgGenerateModuleSchema & { targetPath: */ const updateTsConfigFiles: Rule = (tree, context) => { const tsconfigBase = findConfigFileRelativePath(tree, ['tsconfig.base.json', 'tsconfig.json'], '/'); - const tsconfigBuild = findConfigFileRelativePath(tree, ['tsconfig.build.json'], '/'); - [tsconfigBase, tsconfigBuild].forEach((tsconfigPath) => { - if (tsconfigPath) { - const configFile = tree.readJson(tsconfigPath) as TsConfigJson; - if (configFile?.compilerOptions?.paths) { - configFile.compilerOptions.baseUrl = '.'; - configFile.compilerOptions.paths = Object.fromEntries( - Object.entries(configFile.compilerOptions.paths).filter(([pathName, _]) => pathName !== options.name)); - configFile.compilerOptions.paths[options.packageJsonName] = [ - path.posix.join(relativeTargetPath, 'dist'), - path.posix.join(relativeTargetPath, 'src', 'public-api') - ]; - tree.overwrite(tsconfigPath, JSON.stringify(configFile, null, 2)); - } else { - context.logger.warn(`${tsconfigPath} does not contain path mapping, the edition will be skipped`); + let tsconfigBuild = findConfigFileRelativePath(tree, ['tsconfig.build.json'], '/'); + + if (!tsconfigBase) { + context.logger.error('No TSConfig found in the workspace to register the library.'); + return; + } + + // create tsconfig.build.json if it does not exist + if (!tsconfigBuild || !tree.exists(tsconfigBuild)) { + const content = { + extends: tsconfigBase.replace(/^\/?/, './'), + compilerOptions: { + declarationMap: false + }, + angularCompilerOptions: { + compilationMode: 'partial' } - } else { - context.logger.warn(`No TsConfig file found at ${tsconfigPath}`); - } + }; + tsconfigBuild ||= 'tsconfig.build.json'; + tree.create(tsconfigBuild, JSON.stringify(content, null, 2)); + } + + [tsconfigBase, tsconfigBuild].forEach((tsconfigPath) => { + const configFile = tree.readJson(tsconfigPath) as TsConfigJson; + configFile.compilerOptions ||= {}; + configFile.compilerOptions.paths ||= {}; + configFile.compilerOptions.baseUrl ||= '.'; + configFile.compilerOptions.paths = Object.fromEntries( + Object.entries(configFile.compilerOptions.paths).filter(([pathName, _]) => pathName !== options.name)); + configFile.compilerOptions.paths[options.packageJsonName] = [ + path.posix.join(relativeTargetPath, 'src', 'public-api') + ]; + tree.overwrite(tsconfigPath, JSON.stringify(configFile, null, 2)); }); + + if (tsconfigBuild && tree.exists(tsconfigBuild)) { + const configFile = tree.readJson(tsconfigBuild) as TsConfigJson; + configFile.compilerOptions!.paths![options.packageJsonName].unshift(path.posix.join(relativeTargetPath, 'dist')); + tree.overwrite(tsconfigBuild, JSON.stringify(configFile, null, 2)); + } }; const ngCliUpdate: Rule = (tree, context) => { diff --git a/packages/@o3r/workspace/schematics/library/templates/ng/tsconfig.lib.prod.json.template b/packages/@o3r/workspace/schematics/library/templates/ng/tsconfig.lib.prod.json.template new file mode 100644 index 0000000000..0b30524469 --- /dev/null +++ b/packages/@o3r/workspace/schematics/library/templates/ng/tsconfig.lib.prod.json.template @@ -0,0 +1,3 @@ +{ + "extends": "<%= tsconfigBuildPath %>" +}