Skip to content

Commit 9aaba3b

Browse files
committed
fix(@angular-devkit/core): track workspace targets with no original collection
Fixes angular#15403
1 parent ab8d197 commit 9aaba3b

File tree

3 files changed

+82
-14
lines changed

3 files changed

+82
-14
lines changed

packages/angular_devkit/core/src/workspace/definitions.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@ export interface TargetDefinition {
2929
builder: string;
3030
}
3131

32-
export type DefinitionCollectionListener<V> = (
32+
export type DefinitionCollectionListener<V extends object> = (
3333
name: string,
3434
action: 'add' | 'remove' | 'replace',
3535
newValue: V | undefined,
3636
oldValue: V | undefined,
37+
collection: DefinitionCollection<V>,
3738
) => void;
3839

3940
class DefinitionCollection<V extends object> implements ReadonlyMap<string, V> {
@@ -50,7 +51,7 @@ class DefinitionCollection<V extends object> implements ReadonlyMap<string, V> {
5051
const value = this._map.get(key);
5152
const result = this._map.delete(key);
5253
if (result && value !== undefined && this._listener) {
53-
this._listener(key, 'remove', undefined, value);
54+
this._listener(key, 'remove', undefined, value, this);
5455
}
5556

5657
return result;
@@ -61,7 +62,7 @@ class DefinitionCollection<V extends object> implements ReadonlyMap<string, V> {
6162
this._map.set(key, value);
6263

6364
if (this._listener) {
64-
this._listener(key, existing !== undefined ? 'replace' : 'add', value, existing);
65+
this._listener(key, existing !== undefined ? 'replace' : 'add', value, existing, this);
6566
}
6667

6768
return this;

packages/angular_devkit/core/src/workspace/json/reader.ts

+29-11
Original file line numberDiff line numberDiff line change
@@ -213,17 +213,35 @@ function parseProject(
213213
}
214214

215215
let collectionListener: DefinitionCollectionListener<TargetDefinition> | undefined;
216-
if (context.trackChanges && targetsNode) {
217-
const parentNode = targetsNode;
218-
collectionListener = (name, action, newValue) => {
219-
jsonMetadata.addChange(
220-
action,
221-
`/projects/${projectName}/targets/${escapeKey(name)}`,
222-
parentNode,
223-
newValue,
224-
'target',
225-
);
226-
};
216+
if (context.trackChanges) {
217+
if (targetsNode) {
218+
const parentNode = targetsNode;
219+
collectionListener = (name, action, newValue) => {
220+
jsonMetadata.addChange(
221+
action,
222+
`/projects/${projectName}/targets/${escapeKey(name)}`,
223+
parentNode,
224+
newValue,
225+
'target',
226+
);
227+
};
228+
} else {
229+
let added = false;
230+
collectionListener = (_name, action, _new, _old, collection) => {
231+
if (added || action !== 'add') {
232+
return;
233+
}
234+
235+
jsonMetadata.addChange(
236+
'add',
237+
`/projects/${projectName}/targets`,
238+
projectNode,
239+
collection,
240+
'targetcollection',
241+
);
242+
added = true;
243+
};
244+
}
227245
}
228246

229247
const base = {

packages/angular_devkit/core/src/workspace/json/reader_spec.ts

+49
Original file line numberDiff line numberDiff line change
@@ -710,4 +710,53 @@ describe('JSON ProjectDefinition Tracks Project Changes', () => {
710710
expect(change.value).toBe('valueA');
711711
}
712712
});
713+
714+
it('tracks target additions with no original target collection', async () => {
715+
const original = stripIndent`
716+
{
717+
"version": 1,
718+
// Comment
719+
"schematics": {
720+
"@angular/schematics:component": {
721+
"prefix": "abc"
722+
}
723+
},
724+
"projects": {
725+
"p1": {
726+
"root": "p1-root"
727+
}
728+
},
729+
"x-foo": {
730+
"is": ["good", "great", "awesome"]
731+
},
732+
"x-bar": 5,
733+
}
734+
`;
735+
const host = createTestHost(original);
736+
737+
const workspace = await readJsonWorkspace('', host);
738+
739+
const project = workspace.projects.get('p1');
740+
expect(project).not.toBeUndefined();
741+
if (!project) {
742+
return;
743+
}
744+
745+
project.targets.add({
746+
name: 't1',
747+
builder: 't1-builder',
748+
});
749+
750+
const metadata = getMetadata(workspace);
751+
752+
expect(metadata.hasChanges).toBeTruthy();
753+
expect(metadata.changeCount).toBe(1);
754+
755+
const change = metadata.findChangesForPath('/projects/p1/targets')[0];
756+
expect(change).not.toBeUndefined();
757+
if (change) {
758+
expect(change.op).toBe('add');
759+
expect(change.type).toBe('targetcollection');
760+
}
761+
});
713762
});

0 commit comments

Comments
 (0)