Skip to content

Commit 32281c2

Browse files
alan-agius4dgp1130
authored andcommitted
fix(@schematics/angular): add migration to remove package.json in libraries secondary entrypoints
`package.json` files have been remove from secondary entrypoints in version 14 of Angular package format (APF). With this change we delete the now redundant files and in case these contained the deprecated way of how to configure secondary entrypoints in ng-packagr we migrate these as well.
1 parent f633b6b commit 32281c2

File tree

3 files changed

+192
-0
lines changed

3 files changed

+192
-0
lines changed

packages/schematics/angular/migrations/migration-collection.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
"version": "14.0.0",
2525
"factory": "./update-14/replace-default-collection-option",
2626
"description": "Replace 'defaultCollection' option in workspace configuration with 'schematicCollections'."
27+
},
28+
"update-libraries-secondary-entrypoints": {
29+
"version": "14.0.0",
30+
"factory": "./update-14/update-libraries-secondary-entrypoints",
31+
"description": "Remove 'package.json' files from library projects secondary entrypoints."
2732
}
2833
}
2934
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { dirname, isJsonObject, join, normalize } from '@angular-devkit/core';
10+
import { DirEntry, Rule } from '@angular-devkit/schematics';
11+
import { getWorkspace } from '../../utility/workspace';
12+
13+
function* visitPackageJsonFiles(
14+
directory: DirEntry,
15+
includedInLookup = false,
16+
): IterableIterator<string> {
17+
if (includedInLookup) {
18+
for (const path of directory.subfiles) {
19+
if (path !== 'package.json') {
20+
continue;
21+
}
22+
23+
yield join(directory.path, path);
24+
}
25+
}
26+
27+
for (const path of directory.subdirs) {
28+
if (path === 'node_modules' || path.startsWith('.')) {
29+
continue;
30+
}
31+
32+
yield* visitPackageJsonFiles(directory.dir(path), true);
33+
}
34+
}
35+
36+
/** Migration to remove secondary entrypoints 'package.json' files and migrate ng-packagr configurations. */
37+
export default function (): Rule {
38+
return async (tree) => {
39+
const workspace = await getWorkspace(tree);
40+
41+
for (const project of workspace.projects.values()) {
42+
if (
43+
project.extensions['projectType'] !== 'library' ||
44+
![...project.targets.values()].some(
45+
({ builder }) => builder === '@angular-devkit/build-angular:ng-packagr',
46+
)
47+
) {
48+
// Project is not a library or doesn't use ng-packagr, skip.
49+
continue;
50+
}
51+
52+
for (const path of visitPackageJsonFiles(tree.getDir(project.root))) {
53+
const json = tree.readJson(path);
54+
if (isJsonObject(json) && json['ngPackage']) {
55+
// Migrate ng-packagr config to an ng-packagr config file.
56+
const configFilePath = join(dirname(normalize(path)), 'ng-package.json');
57+
tree.create(configFilePath, JSON.stringify(json['ngPackage'], undefined, 2));
58+
}
59+
60+
// Delete package.json as it is no longer needed in APF 14.
61+
tree.delete(path);
62+
}
63+
}
64+
};
65+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { EmptyTree } from '@angular-devkit/schematics';
10+
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
11+
import { Builders, ProjectType, WorkspaceSchema } from '../../utility/workspace-models';
12+
13+
function createFileStructure(tree: UnitTestTree) {
14+
const angularConfig: WorkspaceSchema = {
15+
version: 1,
16+
projects: {
17+
foo: {
18+
root: 'projects/foo',
19+
sourceRoot: 'projects/foo/src',
20+
projectType: ProjectType.Library,
21+
prefix: 'lib',
22+
architect: {
23+
build: {
24+
builder: Builders.NgPackagr,
25+
options: {
26+
project: '',
27+
tsConfig: '',
28+
},
29+
},
30+
},
31+
},
32+
bar: {
33+
root: 'projects/bar',
34+
sourceRoot: 'projects/bar/src',
35+
projectType: ProjectType.Library,
36+
prefix: 'lib',
37+
architect: {
38+
test: {
39+
builder: Builders.Karma,
40+
options: {
41+
karmaConfig: '',
42+
tsConfig: '',
43+
},
44+
},
45+
},
46+
},
47+
},
48+
};
49+
50+
tree.create('/angular.json', JSON.stringify(angularConfig, undefined, 2));
51+
52+
// Library foo
53+
tree.create('/projects/foo/package.json', JSON.stringify({ version: '0.0.0' }, undefined, 2));
54+
// Library foo/secondary
55+
tree.create(
56+
'/projects/foo/secondary/package.json',
57+
JSON.stringify(
58+
{ version: '0.0.0', ngPackage: { lib: { entryFile: 'src/public-api.ts' } } },
59+
undefined,
60+
2,
61+
),
62+
);
63+
64+
// Library bar
65+
tree.create('/projects/bar/package.json', JSON.stringify({ version: '0.0.0' }, undefined, 2));
66+
// Library bar/secondary
67+
tree.create(
68+
'/projects/bar/secondary/package.json',
69+
JSON.stringify({ version: '0.0.0' }, undefined, 2),
70+
);
71+
}
72+
73+
describe(`Migration to update Angular libraries secondary entrypoints.`, () => {
74+
const schematicName = 'update-libraries-secondary-entrypoints';
75+
const schematicRunner = new SchematicTestRunner(
76+
'migrations',
77+
require.resolve('../migration-collection.json'),
78+
);
79+
80+
let tree: UnitTestTree;
81+
beforeEach(() => {
82+
tree = new UnitTestTree(new EmptyTree());
83+
createFileStructure(tree);
84+
});
85+
86+
describe(`when library has '@angular-devkit/build-angular:ng-packagr' as a builder`, () => {
87+
it(`should not delete 'package.json' of primary entry-point`, async () => {
88+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
89+
90+
expect(newTree.exists('/projects/foo/package.json')).toBeTrue();
91+
});
92+
93+
it(`should delete 'package.json' of secondary entry-point`, async () => {
94+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
95+
expect(newTree.exists('/projects/foo/secondary/package.json')).toBeFalse();
96+
});
97+
98+
it(`should move ng-packagr configuration from 'package.json' to 'ng-package.json'`, async () => {
99+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
100+
expect(newTree.readJson('projects/foo/secondary/ng-package.json')).toEqual({
101+
lib: { entryFile: 'src/public-api.ts' },
102+
});
103+
});
104+
});
105+
106+
describe(`when library doesn't have '@angular-devkit/build-angular:ng-packagr' as a builder`, () => {
107+
it(`should not delete 'package.json' of primary entry-point`, async () => {
108+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
109+
expect(newTree.exists('/projects/bar/package.json')).toBeTrue();
110+
});
111+
112+
it(`should not delete 'package.json' of secondary entry-point`, async () => {
113+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
114+
expect(newTree.exists('/projects/bar/package.json')).toBeTrue();
115+
});
116+
117+
it(`should not create ng-packagr configuration`, async () => {
118+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
119+
expect(newTree.exists('projects/bar/secondary/ng-package.json')).toBeFalse();
120+
});
121+
});
122+
});

0 commit comments

Comments
 (0)