Skip to content

Commit

Permalink
fix(workspace): the tsconfig links to generate libraries (#2648)
Browse files Browse the repository at this point in the history
## Proposed change

fix(workspace): the tsconfig links to generate libraries

It fixes the following points:
- generate the tsconfig.build.json (mandatory for lib standalone
publishing)
- remove the `dist/` path from the `tsconfig.base.json` which is leading
to wrong path mapping when the library was locally built
- register properly the lib in both tsconfig files
- update the tsconfig.lib.prod.json to extend the correct tsconfig

<!--
Please include a summary of the changes and the related issue.
Please also include relevant motivation and context.
-->

## Related issues

<!--
Please make sure to follow the [contribution
guidelines](https://github.com/amadeus-digital/Otter/blob/main/CONTRIBUTING.md)
-->

<!-- * 🐛 Fix #issue -->
* 🐛 Fix resolves #2665
<!-- * 🚀 Feature #issue -->
<!-- * 🚀 Feature resolves #issue -->
<!-- * :octocat: Pull Request #issue -->
  • Loading branch information
kpanot authored Jan 25, 2025
2 parents d39f20e + c4bfafb commit e77dc8f
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 33 deletions.
6 changes: 5 additions & 1 deletion packages/@o3r/workspace/schematics/index.it.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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 () => {
Expand Down
40 changes: 26 additions & 14 deletions packages/@o3r/workspace/schematics/library/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 () => {
Expand Down
56 changes: 38 additions & 18 deletions packages/@o3r/workspace/schematics/library/rules/rules.ng.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "<%= tsconfigBuildPath %>"
}

0 comments on commit e77dc8f

Please sign in to comment.