From e61f2e6ceb77adf6d0256e62c93b10f56b5db79d Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Thu, 27 Aug 2020 13:04:00 +0200 Subject: [PATCH] feat(@schematics/angular): add migration to replace deprecated options --- .../migrations/migration-collection.json | 5 + .../update-11/update-angular-config.ts | 85 +++++++++++++ .../update-11/update-angular-config_spec.ts | 115 ++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 packages/schematics/angular/migrations/update-11/update-angular-config.ts create mode 100644 packages/schematics/angular/migrations/update-11/update-angular-config_spec.ts diff --git a/packages/schematics/angular/migrations/migration-collection.json b/packages/schematics/angular/migrations/migration-collection.json index 40f074b94b..87ff8b1e40 100644 --- a/packages/schematics/angular/migrations/migration-collection.json +++ b/packages/schematics/angular/migrations/migration-collection.json @@ -109,6 +109,11 @@ "version": "11.0.0-next.0", "factory": "./update-11/replace-ng-packagr-builder", "description": "Replace deprecated library builder '@angular-devkit/build-ng-packagr'." + }, + "update-angular-config-v11": { + "version": "11.0.0-next.0", + "factory": "./update-11/update-angular-config", + "description": "Remove deprecated options from 'angular.json' that are no longer present in v11." } } } diff --git a/packages/schematics/angular/migrations/update-11/update-angular-config.ts b/packages/schematics/angular/migrations/update-11/update-angular-config.ts new file mode 100644 index 0000000000..f03153efa2 --- /dev/null +++ b/packages/schematics/angular/migrations/update-11/update-angular-config.ts @@ -0,0 +1,85 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import { JsonArray, isJsonArray, isJsonObject, workspaces } from '@angular-devkit/core'; +import { Rule } from '@angular-devkit/schematics'; +import { updateWorkspace } from '../../utility/workspace'; + +export default function (): Rule { + return updateWorkspace(workspace => { + + const optionsToRemove: Record = { + extractCss: undefined, + tsconfigFileName: undefined, + }; + + for (const [, project] of workspace.projects) { + for (const [, target] of project.targets) { + // Only interested in Angular Devkit builders + if (!target?.builder.startsWith('@angular-devkit/build-angular')) { + continue; + } + + // Check options + if (target.options) { + target.options = { + ...updateLazyScriptsStyleOption(target.options), + ...optionsToRemove, + }; + } + + // Go through each configuration entry + if (!target.configurations) { + continue; + } + + for (const configurationName of Object.keys(target.configurations)) { + target.configurations[configurationName] = { + ...updateLazyScriptsStyleOption(target.configurations[configurationName]), + ...optionsToRemove, + }; + } + } + } + }); +} + +type TargetOptions = workspaces.TargetDefinition['options']; + +function updateLazyScriptsStyleOption(options: TargetOptions): TargetOptions { + function visitor(options: NonNullable, type: 'scripts' | 'styles'): JsonArray | undefined { + // tslint:disable-next-line: no-non-null-assertion + if (!options[type] || !isJsonArray(options[type]!)) { + return undefined; + } + const entries = []; + for (const entry of options[type] as JsonArray) { + if (isJsonObject(entry) && 'lazy' in entry) { + entries.push({ + ...entry, + inject: !entry.lazy, + lazy: undefined, + }); + } else { + entries.push(entry); + } + } + + return entries as JsonArray; + } + + if (!options) { + return undefined; + } + + return { + ...options, + styles: visitor(options, 'styles'), + scripts: visitor(options, 'scripts'), + }; +} diff --git a/packages/schematics/angular/migrations/update-11/update-angular-config_spec.ts b/packages/schematics/angular/migrations/update-11/update-angular-config_spec.ts new file mode 100644 index 0000000000..8d25c2f901 --- /dev/null +++ b/packages/schematics/angular/migrations/update-11/update-angular-config_spec.ts @@ -0,0 +1,115 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { JsonObject } from '@angular-devkit/core'; +import { EmptyTree } from '@angular-devkit/schematics'; +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import { BuilderTarget, Builders, ProjectType, WorkspaceSchema } from '../../utility/workspace-models'; + +function getBuildTarget(tree: UnitTestTree): BuilderTarget { + return JSON.parse(tree.readContent('/angular.json')).projects.app.architect.build; +} + +function createWorkSpaceConfig(tree: UnitTestTree) { + const angularConfig: WorkspaceSchema = { + version: 1, + projects: { + app: { + root: '', + sourceRoot: 'src', + projectType: ProjectType.Application, + prefix: 'app', + architect: { + build: { + builder: Builders.Browser, + options: { + scripts: [ + { lazy: true, name: 'bundle-1.js' }, + ], + extractCss: false, + sourceMaps: true, + buildOptimizer: false, + // tslint:disable-next-line:no-any + } as any, + configurations: { + one: { + aot: true, + scripts: [ + { lazy: true, name: 'bundle-1.js' }, + { lazy: false, name: 'bundle-2.js' }, + { inject: true, name: 'bundle-3.js' }, + 'bundle-4.js', + ], + styles: [ + { lazy: true, name: 'bundle-1.css' }, + { lazy: false, name: 'bundle-2.css' }, + { inject: true, name: 'bundle-3.css' }, + 'bundle-3.css', + ], + }, + two: { + extractCss: true, + aot: true, + }, + // tslint:disable-next-line:no-any + } as any, + }, + }, + }, + }, + }; + + tree.create('/angular.json', JSON.stringify(angularConfig, undefined, 2)); +} + +const schematicName = 'update-angular-config-v11'; + +describe(`Migration to update 'angular.json'. ${schematicName}`, () => { + const schematicRunner = new SchematicTestRunner( + 'migrations', + require.resolve('../migration-collection.json'), + ); + + let tree: UnitTestTree; + beforeEach(() => { + tree = new UnitTestTree(new EmptyTree()); + createWorkSpaceConfig(tree); + }); + + it(`should remove 'extractCss'`, async () => { + const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); + const { options, configurations } = getBuildTarget(newTree); + + expect(options.extractCss).toBeUndefined(); + expect(configurations).toBeDefined(); + expect(configurations?.one.extractCss).toBeUndefined(); + expect(configurations?.two.extractCss).toBeUndefined(); + }); + + it(`should replace 'lazy' with 'inject'`, async () => { + const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise(); + const { options, configurations } = getBuildTarget(newTree); + + expect(configurations?.one.scripts).toEqual([ + { inject: false, name: 'bundle-1.js' }, + { inject: true, name: 'bundle-2.js' }, + { inject: true, name: 'bundle-3.js' }, + 'bundle-4.js', + ]); + + expect(configurations?.one.styles).toEqual([ + { inject: false, name: 'bundle-1.css' }, + { inject: true, name: 'bundle-2.css' }, + { inject: true, name: 'bundle-3.css' }, + 'bundle-3.css', + ]); + + expect(options.scripts).toEqual([ + { inject: false, name: 'bundle-1.js' }, + ]); + }); +});