Skip to content

Commit

Permalink
feat(@schematics/angular): add migration from lazy option to inject
Browse files Browse the repository at this point in the history
  • Loading branch information
alan-agius4 authored and vikerman committed Jul 2, 2019
1 parent 2b367be commit 040e3ea
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
"version": "8.0.0-beta.14",
"factory": "./update-8/#updateLazyModulePaths",
"description": "Update an Angular CLI project to version 8."
},
"migration-09": {
"version": "9.0.0-beta.0",
"factory": "./update-9",
"description": "Update an Angular CLI project to version 9."
}
}
}
18 changes: 18 additions & 0 deletions packages/schematics/angular/migrations/update-9/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @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 { Rule, chain } from '@angular-devkit/schematics';
import { UpdateWorkspaceConfig } from './update-workspace-config';

export default function(): Rule {
return () => {
return chain([
UpdateWorkspaceConfig(),
]);
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* @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 {
JsonAstObject,
JsonParseMode,
parseJsonAst,
} from '@angular-devkit/core';
import { Rule, Tree, UpdateRecorder } from '@angular-devkit/schematics';
import {
findPropertyInAstObject,
insertPropertyInAstObjectInOrder,
removePropertyInAstObject,
} from '../../utility/json-utils';

export function UpdateWorkspaceConfig(): Rule {
return (tree: Tree) => {
let workspaceConfigPath = 'angular.json';
let angularConfigContent = tree.read(workspaceConfigPath);

if (!angularConfigContent) {
workspaceConfigPath = '.angular.json';
angularConfigContent = tree.read(workspaceConfigPath);

if (!angularConfigContent) {
return;
}
}

const angularJson = parseJsonAst(angularConfigContent.toString(), JsonParseMode.Loose);
if (angularJson.kind !== 'object') {
return;
}

const projects = findPropertyInAstObject(angularJson, 'projects');
if (!projects || projects.kind !== 'object') {
return;
}

// For all projects
const recorder = tree.beginUpdate(workspaceConfigPath);
for (const project of projects.properties) {
const projectConfig = project.value;
if (projectConfig.kind !== 'object') {
break;
}

const architect = findPropertyInAstObject(projectConfig, 'architect');
if (!architect || architect.kind !== 'object') {
break;
}

const buildTarget = findPropertyInAstObject(architect, 'build');
if (buildTarget && buildTarget.kind === 'object') {
const builder = findPropertyInAstObject(buildTarget, 'builder');
// Projects who's build builder is not build-angular:browser
if (builder && builder.kind === 'string' && builder.value === '@angular-devkit/build-angular:browser') {
updateOption('styles', recorder, buildTarget);
updateOption('scripts', recorder, buildTarget);
}
}

const testTarget = findPropertyInAstObject(architect, 'test');
if (testTarget && testTarget.kind === 'object') {
const builder = findPropertyInAstObject(testTarget, 'builder');
// Projects who's build builder is not build-angular:browser
if (builder && builder.kind === 'string' && builder.value === '@angular-devkit/build-angular:karma') {
updateOption('styles', recorder, testTarget);
updateOption('scripts', recorder, testTarget);
}
}
}

tree.commitUpdate(recorder);

return tree;
};
}

/**
* Helper to retreive all the options in various configurations
*/
function getAllOptions(builderConfig: JsonAstObject): JsonAstObject[] {
const options = [];
const configurations = findPropertyInAstObject(builderConfig, 'configurations');
if (configurations && configurations.kind === 'object') {
options.push(...configurations.properties.map(x => x.value));
}

options.push(findPropertyInAstObject(builderConfig, 'options'));

return options.filter(o => o && o.kind === 'object') as JsonAstObject[];
}

function updateOption(property: 'scripts' | 'styles', recorder: UpdateRecorder, builderConfig: JsonAstObject) {
const options = getAllOptions(builderConfig);

for (const option of options) {
const propertyOption = findPropertyInAstObject(option, property);
if (!propertyOption || propertyOption.kind !== 'array') {
continue;
}

for (const node of propertyOption.elements) {
if (!node || node.kind !== 'object') {
// skip non complex objects
continue;
}

const lazy = findPropertyInAstObject(node, 'lazy');
removePropertyInAstObject(recorder, node, 'lazy');

// if lazy was not true, it is redundant hence, don't add it
if (lazy && lazy.kind === 'true') {
insertPropertyInAstObjectInOrder(recorder, node, 'inject', false, 0);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* @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 { EmptyTree } from '@angular-devkit/schematics';
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';

function readWorkspaceConfig(tree: UnitTestTree) {
return JSON.parse(tree.readContent('/angular.json'));
}

const scriptsWithLazy = [
{ bundleName: 'one', input: 'one.js', lazy: false },
{ bundleName: 'two', input: 'two.js', lazy: true },
{ bundleName: 'tree', input: 'tree.js' },
'four.js',
]

const scriptsExpectWithLazy = [
{ bundleName: 'one', input: 'one.js' },
{ bundleName: 'two', inject: false, input: 'two.js' },
{ bundleName: 'tree', input: 'tree.js' },
'four.js',
]

const stylesWithLazy = [
{ bundleName: 'one', input: 'one.css', lazy: false },
{ bundleName: 'two', input: 'two.css', lazy: true },
{ bundleName: 'tree', input: 'tree.css' },
'four.css',
]

const stylesExpectWithLazy = [
{ bundleName: 'one', input: 'one.css' },
{ bundleName: 'two', inject: false, input: 'two.css' },
{ bundleName: 'tree', input: 'tree.css' },
'four.css',
]

const workspacePath = '/angular.json';

// tslint:disable:no-big-function
describe('Migration to version 9', () => {
describe('Migrate workspace config', () => {
const schematicRunner = new SchematicTestRunner(
'migrations',
require.resolve('../migration-collection.json'),
);

let tree: UnitTestTree;

beforeEach(async () => {
tree = new UnitTestTree(new EmptyTree());
tree = await schematicRunner
.runExternalSchematicAsync(
require.resolve('../../collection.json'),
'ng-new',
{
name: 'migration-test',
version: '1.2.3',
directory: '.',
},
tree,
)
.toPromise();
});

it('should update scripts in build target', () => {
let config = readWorkspaceConfig(tree);
let build = config.projects['migration-test'].architect.build;
build.options.scripts = scriptsWithLazy;
build.configurations.production.scripts = scriptsWithLazy;

tree.overwrite(workspacePath, JSON.stringify(config));
const tree2 = schematicRunner.runSchematic('migration-09', {}, tree.branch());
config = readWorkspaceConfig(tree2);
build = config.projects['migration-test'].architect.build;
expect(build.options.scripts).toEqual(scriptsExpectWithLazy);
expect(build.configurations.production.scripts).toEqual(scriptsExpectWithLazy);
});

it('should update styles in build target', () => {
let config = readWorkspaceConfig(tree);
let build = config.projects['migration-test'].architect.build;
build.options.styles = stylesWithLazy;
build.configurations.production.styles = stylesWithLazy;

tree.overwrite(workspacePath, JSON.stringify(config));
const tree2 = schematicRunner.runSchematic('migration-09', {}, tree.branch());
config = readWorkspaceConfig(tree2);
build = config.projects['migration-test'].architect.build;
expect(build.options.styles).toEqual(stylesExpectWithLazy);
expect(build.configurations.production.styles).toEqual(stylesExpectWithLazy);
});

it('should update scripts in test target', () => {
let config = readWorkspaceConfig(tree);
let test = config.projects['migration-test'].architect.test;
test.options.scripts = scriptsWithLazy;
test.configurations = { production: { scripts: scriptsWithLazy } };

tree.overwrite(workspacePath, JSON.stringify(config));
const tree2 = schematicRunner.runSchematic('migration-09', {}, tree.branch());
config = readWorkspaceConfig(tree2);
test = config.projects['migration-test'].architect.test;
expect(test.options.scripts).toEqual(scriptsExpectWithLazy);
expect(test.configurations.production.scripts).toEqual(scriptsExpectWithLazy);
});

it('should update styles in test target', () => {
let config = readWorkspaceConfig(tree);
let test = config.projects['migration-test'].architect.test;
test.options.styles = stylesWithLazy;
test.configurations = { production: { styles: stylesWithLazy } };

tree.overwrite(workspacePath, JSON.stringify(config));
const tree2 = schematicRunner.runSchematic('migration-09', {}, tree.branch());
config = readWorkspaceConfig(tree2);
test = config.projects['migration-test'].architect.test;
expect(test.options.styles).toEqual(stylesExpectWithLazy);
expect(test.configurations.production.styles).toEqual(stylesExpectWithLazy);
});
});
});

0 comments on commit 040e3ea

Please sign in to comment.