Skip to content
Permalink
Browse files

fix(bazel): don't rely on @angular/core being as a depedency to insta…

…ll @angular/bazel (#34181)

With this change we fix the logic to detect if a package is installed, removing a package and add a package by using the CLI schematic helpers.

Also we save `@angular/bazel` package directly as a `devDependency` when doing `ng-add`.

Closes #34164

PR Close #34181
  • Loading branch information
alan-agius4 authored and mhevery committed Dec 2, 2019
1 parent ce79cac commit 716fc845f53f15191de4fb7397712ce0cd2be89f
@@ -51,6 +51,9 @@
},
"builders": "./src/builders/builders.json",
"schematics": "./src/schematics/collection.json",
"ng-add": {
"save": "devDependencies"
},
"ng-update": {
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
},
@@ -12,73 +12,59 @@ import {JsonAstObject, parseJsonAst} from '@angular-devkit/core';
import {Rule, SchematicContext, SchematicsException, Tree, apply, applyTemplates, chain, mergeWith, url} from '@angular-devkit/schematics';
import {NodePackageInstallTask} from '@angular-devkit/schematics/tasks';
import {getWorkspace, getWorkspacePath} from '@schematics/angular/utility/config';
import {NodeDependencyType, addPackageJsonDependency, getPackageJsonDependency, removePackageJsonDependency} from '@schematics/angular/utility/dependencies';
import {findPropertyInAstObject, insertPropertyInAstObjectInOrder} from '@schematics/angular/utility/json-utils';
import {validateProjectName} from '@schematics/angular/utility/validation';

import {isJsonAstObject, removeKeyValueInAstObject, replacePropertyInAstObject} from '../utility/json-utils';
import {isJsonAstObject, replacePropertyInAstObject} from '../utility/json-utils';
import {findE2eArchitect} from '../utility/workspace-utils';

import {Schema} from './schema';



/**
* Packages that build under Bazel require additional dev dependencies. This
* function adds those dependencies to "devDependencies" section in
* package.json.
*/
function addDevDependenciesToPackageJson(options: Schema) {
return (host: Tree) => {
const packageJson = 'package.json';
if (!host.exists(packageJson)) {
throw new Error(`Could not find ${packageJson}`);
}
const packageJsonContent = host.read(packageJson);
if (!packageJsonContent) {
throw new Error('Failed to read package.json content');
}
const jsonAst = parseJsonAst(packageJsonContent.toString()) as JsonAstObject;
const deps = findPropertyInAstObject(jsonAst, 'dependencies') as JsonAstObject;
const devDeps = findPropertyInAstObject(jsonAst, 'devDependencies') as JsonAstObject;

const angularCoreNode = findPropertyInAstObject(deps, '@angular/core');
if (!angularCoreNode) {
const angularCore = getPackageJsonDependency(host, '@angular/core');
if (!angularCore) {
throw new Error('@angular/core dependency not found in package.json');
}
const angularCoreVersion = angularCoreNode.value as string;

const devDependencies: {[k: string]: string} = {
'@angular/bazel': angularCoreVersion,
'@bazel/bazel': '1.1.0',
'@bazel/ibazel': '^0.10.2',
'@bazel/karma': '0.40.0',
'@bazel/protractor': '0.40.0',
'@bazel/rollup': '0.40.0',
'@bazel/terser': '0.40.0',
'@bazel/typescript': '0.40.0',
'history-server': '^1.3.1',
'rollup': '^1.25.2',
'rollup-plugin-commonjs': '^10.1.0',
'rollup-plugin-node-resolve': '^5.2.0',
'terser': '^4.3.9',
};
// TODO: use a Record<string, string> when the tsc lib setting allows us
const devDependencies: [string, string][] = [
['@angular/bazel', angularCore.version],
['@bazel/bazel', '1.1.0'],
['@bazel/ibazel', '^0.10.2'],
['@bazel/karma', '0.40.0'],
['@bazel/protractor', '0.40.0'],
['@bazel/rollup', '0.40.0'],
['@bazel/terser', '0.40.0'],
['@bazel/typescript', '0.40.0'],
['history-server', '^1.3.1'],
['rollup', '^1.25.2'],
['rollup-plugin-commonjs', '^10.1.0'],
['rollup-plugin-node-resolve', '^5.2.0'],
['terser', '^4.3.9'],
];

const recorder = host.beginUpdate(packageJson);
for (const packageName of Object.keys(devDependencies)) {
const existingDep = findPropertyInAstObject(deps, packageName);
if (existingDep) {
const content = packageJsonContent.toString();
removeKeyValueInAstObject(recorder, content, deps, packageName);
}
const version = devDependencies[packageName];
const indent = 4;
if (findPropertyInAstObject(devDeps, packageName)) {
replacePropertyInAstObject(recorder, devDeps, packageName, version, indent);
} else {
insertPropertyInAstObjectInOrder(recorder, devDeps, packageName, version, indent);
for (const [name, version] of devDependencies) {
const dep = getPackageJsonDependency(host, name);
if (dep && dep.type !== NodeDependencyType.Dev) {
removePackageJsonDependency(host, name);
}

addPackageJsonDependency(host, {
name,
version,
type: NodeDependencyType.Dev,
overwrite: true,
});
}
host.commitUpdate(recorder);
return host;
};
}

@@ -88,38 +74,13 @@ function addDevDependenciesToPackageJson(options: Schema) {
*/
function removeObsoleteDependenciesFromPackageJson(options: Schema) {
return (host: Tree) => {
const packageJson = 'package.json';
if (!host.exists(packageJson)) {
throw new Error(`Could not find ${packageJson}`);
}
const buffer = host.read(packageJson);
if (!buffer) {
throw new Error('Failed to read package.json content');
}
const content = buffer.toString();
const jsonAst = parseJsonAst(content) as JsonAstObject;
const deps = findPropertyInAstObject(jsonAst, 'dependencies') as JsonAstObject;
const devDeps = findPropertyInAstObject(jsonAst, 'devDependencies') as JsonAstObject;

const depsToRemove = [
'@angular-devkit/build-angular',
];

const recorder = host.beginUpdate(packageJson);

for (const packageName of depsToRemove) {
const depNode = findPropertyInAstObject(deps, packageName);
if (depNode) {
removeKeyValueInAstObject(recorder, content, deps, packageName);
}
const devDepNode = findPropertyInAstObject(devDeps, packageName);
if (devDepNode) {
removeKeyValueInAstObject(recorder, content, devDeps, packageName);
}
removePackageJsonDependency(host, packageName);
}

host.commitUpdate(recorder);
return host;
};
}

@@ -166,7 +127,7 @@ function updateGitignore() {
* Change the architect in angular.json to use Bazel builder.
*/
function updateAngularJsonToUseBazelBuilder(options: Schema): Rule {
return (host: Tree, context: SchematicContext) => {
return (host: Tree) => {
const name = options.name !;
const workspacePath = getWorkspacePath(host);
if (!workspacePath) {
@@ -277,39 +238,25 @@ function backupAngularJson(): Rule {
*/
function upgradeRxjs() {
return (host: Tree, context: SchematicContext) => {
const packageJson = 'package.json';
if (!host.exists(packageJson)) {
throw new Error(`Could not find ${packageJson}`);
const rxjsNode = getPackageJsonDependency(host, 'rxjs');
if (!rxjsNode) {
throw new Error(`Failed to find rxjs dependency.`);
}
const content = host.read(packageJson);
if (!content) {
throw new Error('Failed to read package.json content');
}
const jsonAst = parseJsonAst(content.toString());
if (!isJsonAstObject(jsonAst)) {
throw new Error(`Failed to parse JSON for ${packageJson}`);
}
const deps = findPropertyInAstObject(jsonAst, 'dependencies');
if (!isJsonAstObject(deps)) {
throw new Error(`Failed to find dependencies in ${packageJson}`);
}
const rxjs = findPropertyInAstObject(deps, 'rxjs');
if (!rxjs) {
throw new Error(`Failed to find rxjs in dependencies of ${packageJson}`);
}
const value = rxjs.value as string; // value can be version or range
const match = value.match(/(\d)+\.(\d)+.(\d)+$/);

const match = rxjsNode.version.match(/(\d)+\.(\d)+.(\d)+$/);
if (match) {
const [_, major, minor] = match;
if (major < '6' || (major === '6' && minor < '4')) {
const recorder = host.beginUpdate(packageJson);
replacePropertyInAstObject(recorder, deps, 'rxjs', '~6.4.0');
host.commitUpdate(recorder);
if (major < '6' || (major === '6' && minor < '5')) {
addPackageJsonDependency(host, {
...rxjsNode,
version: '~6.5.3',
overwrite: true,
});
}
} else {
context.logger.info(
'Could not determine version of rxjs. \n' +
'Please make sure that version is at least 6.4.0.');
'Please make sure that version is at least 6.5.3.');
}
return host;
};
@@ -73,7 +73,7 @@ describe('ng-add schematic', () => {
message = e.message;
}

expect(message).toBe('Could not find package.json');
expect(message).toBe('Could not read package.json.');
});

it('throws if angular.json is not found', async() => {
@@ -104,7 +104,6 @@ describe('ng-add schematic', () => {
expect(Object.keys(json)).toContain('devDependencies');
expect(Object.keys(json.dependencies)).toContain(core);
expect(Object.keys(json.devDependencies)).toContain(bazel);
expect(json.dependencies[core]).toBe(json.devDependencies[bazel]);
});

it('should add @bazel/* dev dependencies', async() => {
@@ -273,9 +272,9 @@ describe('ng-add schematic', () => {
['~6.3.3', true],
['^6.3.3', true],
['~6.3.11', true],
['6.4.0', false],
['~6.4.0', false],
['~6.4.1', false],
['6.4.0', true],
['~6.4.0', true],
['~6.4.1', true],
['6.5.0', false],
['~6.5.0', false],
['^6.5.0', false],
@@ -298,7 +297,7 @@ describe('ng-add schematic', () => {
const content = host.readContent('/package.json');
const json = JSON.parse(content);
if (upgrade) {
expect(json.dependencies.rxjs).toBe('~6.4.0');
expect(json.dependencies.rxjs).toBe('~6.5.3');
} else {
expect(json.dependencies.rxjs).toBe(version);
}

0 comments on commit 716fc84

Please sign in to comment.
You can’t perform that action at this time.