Skip to content

Commit 12cd4a0

Browse files
clydinfilipesilva
authored andcommitted
refactor(@schematics/angular): use new workspace helpers in update-workspace-config migration
1 parent 38ea7dc commit 12cd4a0

File tree

2 files changed

+106
-101
lines changed

2 files changed

+106
-101
lines changed

packages/schematics/angular/migrations/update-9/update-workspace-config.ts

Lines changed: 76 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -5,159 +5,135 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import { JsonAstObject } from '@angular-devkit/core';
9-
import { Rule, Tree, UpdateRecorder } from '@angular-devkit/schematics';
10-
import { getWorkspacePath } from '../../utility/config';
11-
import {
12-
appendValueInAstArray,
13-
findPropertyInAstObject,
14-
insertPropertyInAstObjectInOrder,
15-
removePropertyInAstObject,
16-
} from '../../utility/json-utils';
8+
import { workspaces } from '@angular-devkit/core';
9+
import { Rule, Tree } from '@angular-devkit/schematics';
10+
import { allTargetOptions, allWorkspaceTargets, updateWorkspace } from '../../utility/workspace';
1711
import { Builders } from '../../utility/workspace-models';
18-
import { getAllOptions, getTargets, getWorkspace, isIvyEnabled } from './utils';
12+
import { isIvyEnabled } from './utils';
1913

2014
export const ANY_COMPONENT_STYLE_BUDGET = {
2115
type: 'anyComponentStyle',
2216
maximumWarning: '6kb',
2317
};
2418

2519
export function updateWorkspaceConfig(): Rule {
26-
return (tree, context) => {
27-
const workspacePath = getWorkspacePath(tree);
28-
const workspace = getWorkspace(tree);
29-
const recorder = tree.beginUpdate(workspacePath);
30-
31-
for (const { target } of getTargets(workspace, 'build', Builders.Browser)) {
32-
updateStyleOrScriptOption('styles', recorder, target);
33-
updateStyleOrScriptOption('scripts', recorder, target);
34-
addAnyComponentStyleBudget(recorder, target);
35-
updateAotOption(tree, recorder, target);
36-
}
37-
38-
for (const { target } of getTargets(workspace, 'test', Builders.Karma)) {
39-
updateStyleOrScriptOption('styles', recorder, target);
40-
updateStyleOrScriptOption('scripts', recorder, target);
41-
}
42-
43-
for (const { target } of getTargets(workspace, 'server', Builders.Server)) {
44-
updateOptimizationOption(recorder, target);
45-
}
46-
47-
tree.commitUpdate(recorder);
48-
49-
return tree;
50-
};
20+
return (tree) =>
21+
updateWorkspace((workspace) => {
22+
for (const [targetName, target] of allWorkspaceTargets(workspace)) {
23+
switch (targetName) {
24+
case 'build':
25+
if (target.builder !== Builders.Browser) {
26+
break;
27+
}
28+
updateStyleOrScriptOption('styles', target);
29+
updateStyleOrScriptOption('scripts', target);
30+
addAnyComponentStyleBudget(target);
31+
updateAotOption(tree, target);
32+
break;
33+
case 'test':
34+
if (target.builder !== Builders.Karma) {
35+
break;
36+
}
37+
updateStyleOrScriptOption('styles', target);
38+
updateStyleOrScriptOption('scripts', target);
39+
break;
40+
case 'server':
41+
if (target.builder !== Builders.Server) {
42+
break;
43+
}
44+
updateOptimizationOption(target);
45+
break;
46+
}
47+
}
48+
});
5149
}
5250

53-
function updateAotOption(tree: Tree, recorder: UpdateRecorder, builderConfig: JsonAstObject) {
54-
const options = findPropertyInAstObject(builderConfig, 'options');
55-
if (!options || options.kind !== 'object') {
51+
function updateAotOption(tree: Tree, builderConfig: workspaces.TargetDefinition) {
52+
if (!builderConfig.options) {
5653
return;
5754
}
5855

59-
const tsConfig = findPropertyInAstObject(options, 'tsConfig');
60-
// Do not add aot option if the users already opted out from Ivy.
61-
if (tsConfig && tsConfig.kind === 'string' && !isIvyEnabled(tree, tsConfig.value)) {
56+
const tsConfig = builderConfig.options.tsConfig;
57+
// Do not add aot option if the users already opted out from Ivy
58+
if (tsConfig && typeof tsConfig === 'string' && !isIvyEnabled(tree, tsConfig)) {
6259
return;
6360
}
6461

65-
// Add aot to options.
66-
const aotOption = findPropertyInAstObject(options, 'aot');
67-
68-
if (!aotOption) {
69-
insertPropertyInAstObjectInOrder(recorder, options, 'aot', true, 12);
70-
71-
return;
62+
// Add aot to options
63+
const aotOption = builderConfig.options.aot;
64+
if (aotOption === undefined || aotOption === false) {
65+
builderConfig.options.aot = true;
7266
}
7367

74-
if (aotOption.kind !== 'true') {
75-
const { start, end } = aotOption;
76-
recorder.remove(start.offset, end.offset - start.offset);
77-
recorder.insertLeft(start.offset, 'true');
68+
if (!builderConfig.configurations) {
69+
return;
7870
}
7971

80-
// Remove aot properties from other configurations as they are no redundant
81-
const configOptions = getAllOptions(builderConfig, true);
82-
for (const options of configOptions) {
83-
removePropertyInAstObject(recorder, options, 'aot');
72+
for (const configurationOptions of Object.values(builderConfig.configurations)) {
73+
delete configurationOptions?.aot;
8474
}
8575
}
8676

87-
function updateStyleOrScriptOption(property: 'scripts' | 'styles', recorder: UpdateRecorder, builderConfig: JsonAstObject) {
88-
const options = getAllOptions(builderConfig);
89-
90-
for (const option of options) {
91-
const propertyOption = findPropertyInAstObject(option, property);
92-
if (!propertyOption || propertyOption.kind !== 'array') {
77+
function updateStyleOrScriptOption(
78+
property: 'scripts' | 'styles',
79+
builderConfig: workspaces.TargetDefinition,
80+
) {
81+
for (const [, options] of allTargetOptions(builderConfig)) {
82+
const propertyOption = options[property];
83+
if (!propertyOption || !Array.isArray(propertyOption)) {
9384
continue;
9485
}
9586

96-
for (const node of propertyOption.elements) {
97-
if (!node || node.kind !== 'object') {
87+
for (const node of propertyOption) {
88+
if (!node || typeof node !== 'object' || Array.isArray(node)) {
9889
// skip non complex objects
9990
continue;
10091
}
10192

102-
const lazy = findPropertyInAstObject(node, 'lazy');
103-
removePropertyInAstObject(recorder, node, 'lazy');
93+
const lazy = node.lazy;
94+
if (lazy !== undefined) {
95+
delete node.lazy;
10496

105-
// if lazy was not true, it is redundant hence, don't add it
106-
if (lazy && lazy.kind === 'true') {
107-
insertPropertyInAstObjectInOrder(recorder, node, 'inject', false, 0);
97+
// if lazy was not true, it is redundant hence, don't add it
98+
if (lazy) {
99+
node.inject = false;
100+
}
108101
}
109102
}
110103
}
111104
}
112105

113-
function addAnyComponentStyleBudget(recorder: UpdateRecorder, builderConfig: JsonAstObject) {
114-
const options = getAllOptions(builderConfig, true);
115-
116-
for (const option of options) {
117-
const budgetOption = findPropertyInAstObject(option, 'budgets');
118-
if (!budgetOption) {
119-
// add
120-
insertPropertyInAstObjectInOrder(recorder, option, 'budgets', [ANY_COMPONENT_STYLE_BUDGET], 14);
106+
function addAnyComponentStyleBudget(builderConfig: workspaces.TargetDefinition) {
107+
for (const [, options] of allTargetOptions(builderConfig, /* skipBaseOptions */ true)) {
108+
if (options.budgets === undefined) {
109+
options.budgets = [ANY_COMPONENT_STYLE_BUDGET];
121110
continue;
122111
}
123112

124-
if (budgetOption.kind !== 'array') {
113+
if (!Array.isArray(options.budgets)) {
125114
continue;
126115
}
127116

128-
// if 'anyComponentStyle' budget already exists don't add.
129-
const hasAnyComponentStyle = budgetOption.elements.some(node => {
130-
if (!node || node.kind !== 'object') {
117+
// If 'anyComponentStyle' budget already exists, don't add
118+
const hasAnyComponentStyle = options.budgets.some((node) => {
119+
if (!node || typeof node !== 'object' || Array.isArray(node)) {
131120
// skip non complex objects
132121
return false;
133122
}
134123

135-
const budget = findPropertyInAstObject(node, 'type');
136-
137-
return !!budget && budget.kind === 'string' && budget.value === 'anyComponentStyle';
124+
return node.type === 'anyComponentStyle';
138125
});
139126

140127
if (!hasAnyComponentStyle) {
141-
appendValueInAstArray(recorder, budgetOption, ANY_COMPONENT_STYLE_BUDGET, 16);
128+
options.budgets.push(ANY_COMPONENT_STYLE_BUDGET);
142129
}
143130
}
144131
}
145132

146-
function updateOptimizationOption(recorder: UpdateRecorder, builderConfig: JsonAstObject) {
147-
const options = getAllOptions(builderConfig, true);
148-
149-
for (const option of options) {
150-
const optimizationOption = findPropertyInAstObject(option, 'optimization');
151-
if (!optimizationOption) {
152-
// add
153-
insertPropertyInAstObjectInOrder(recorder, option, 'optimization', true, 14);
154-
continue;
155-
}
156-
157-
if (optimizationOption.kind !== 'true') {
158-
const { start, end } = optimizationOption;
159-
recorder.remove(start.offset, end.offset - start.offset);
160-
recorder.insertLeft(start.offset, 'true');
133+
function updateOptimizationOption(builderConfig: workspaces.TargetDefinition) {
134+
for (const [, options] of allTargetOptions(builderConfig, /* skipBaseOptions */ true)) {
135+
if (options.optimization !== true) {
136+
options.optimization = true;
161137
}
162138
}
163139
}

packages/schematics/angular/utility/workspace.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import { virtualFs, workspaces } from '@angular-devkit/core';
8+
import { json, virtualFs, workspaces } from '@angular-devkit/core';
99
import { Rule, Tree, noop } from '@angular-devkit/schematics';
1010
import { ProjectType } from './workspace-models';
1111

@@ -90,3 +90,32 @@ export async function createDefaultPath(tree: Tree, projectName: string): Promis
9090

9191
return buildDefaultPath(project);
9292
}
93+
94+
export function* allWorkspaceTargets(
95+
workspace: workspaces.WorkspaceDefinition,
96+
): Iterable<[string, workspaces.TargetDefinition]> {
97+
for (const [, project] of workspace.projects) {
98+
for (const targetEntry of project.targets) {
99+
yield targetEntry;
100+
}
101+
}
102+
}
103+
104+
export function* allTargetOptions(
105+
target: workspaces.TargetDefinition,
106+
skipBaseOptions = false,
107+
): Iterable<[string | undefined, Record<string, json.JsonValue | undefined>]> {
108+
if (!skipBaseOptions && target.options) {
109+
yield [undefined, target.options];
110+
}
111+
112+
if (!target.configurations) {
113+
return;
114+
}
115+
116+
for (const [name, options] of Object.entries(target.configurations)) {
117+
if (options !== undefined) {
118+
yield [name, options];
119+
}
120+
}
121+
}

0 commit comments

Comments
 (0)