feat(bazel): ng-new schematics with Bazel (#27277)
This commit creates a schematics for ng new command that builds the project with Bazel. PR Close #27277
This commit is contained in:
parent
7ec05b4d8c
commit
06d4a0c46e
|
@ -7,6 +7,7 @@ npm_package(
|
||||||
"package.json",
|
"package.json",
|
||||||
"protractor-utils.js",
|
"protractor-utils.js",
|
||||||
"//packages/bazel/src:package_assets",
|
"//packages/bazel/src:package_assets",
|
||||||
|
"//packages/bazel/src/builders:package_assets",
|
||||||
"//packages/bazel/src/schematics:package_assets",
|
"//packages/bazel/src/schematics:package_assets",
|
||||||
],
|
],
|
||||||
packages = [
|
packages = [
|
||||||
|
@ -19,5 +20,6 @@ npm_package(
|
||||||
"//packages/bazel/src/ngc-wrapped:ngc_lib",
|
"//packages/bazel/src/ngc-wrapped:ngc_lib",
|
||||||
"//packages/bazel/src/protractor/utils",
|
"//packages/bazel/src/protractor/utils",
|
||||||
"//packages/bazel/src/schematics/bazel-workspace",
|
"//packages/bazel/src/schematics/bazel-workspace",
|
||||||
|
"//packages/bazel/src/schematics/ng-new",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"builders": {
|
"builders": {
|
||||||
"build": {
|
"build": {
|
||||||
"class": "./index#Builder",
|
"class": "./index",
|
||||||
"schema": "./schema.json",
|
"schema": "./schema.json",
|
||||||
"description": "Executes Bazel on a target."
|
"description": "Executes Bazel on a target."
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*
|
*
|
||||||
* @fileoverview Bazel bundle builder
|
* @fileoverview Bazel builder
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {BuildEvent, Builder as BuilderInterface, BuilderConfiguration, BuilderContext} from '@angular-devkit/architect';
|
import {BuildEvent, Builder, BuilderConfiguration, BuilderContext} from '@angular-devkit/architect';
|
||||||
import {getSystemPath, resolve} from '@angular-devkit/core';
|
import {getSystemPath, resolve} from '@angular-devkit/core';
|
||||||
import {Observable, of } from 'rxjs';
|
import {Observable, of } from 'rxjs';
|
||||||
import {catchError, map, tap} from 'rxjs/operators';
|
import {catchError, map, tap} from 'rxjs/operators';
|
||||||
|
@ -16,7 +16,7 @@ import {catchError, map, tap} from 'rxjs/operators';
|
||||||
import {checkInstallation, runBazel} from './bazel';
|
import {checkInstallation, runBazel} from './bazel';
|
||||||
import {Schema} from './schema';
|
import {Schema} from './schema';
|
||||||
|
|
||||||
export class Builder implements BuilderInterface<Schema> {
|
class BazelBuilder implements Builder<Schema> {
|
||||||
constructor(private context: BuilderContext) {}
|
constructor(private context: BuilderContext) {}
|
||||||
|
|
||||||
run(builderConfig: BuilderConfiguration<Partial<Schema>>): Observable<BuildEvent> {
|
run(builderConfig: BuilderConfiguration<Partial<Schema>>): Observable<BuildEvent> {
|
||||||
|
@ -38,3 +38,5 @@ export class Builder implements BuilderInterface<Schema> {
|
||||||
.pipe(map(() => ({success: true})), catchError(() => of ({success: false})), );
|
.pipe(map(() => ({success: true})), catchError(() => of ({success: false})), );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default BazelBuilder;
|
||||||
|
|
|
@ -15,6 +15,7 @@ jasmine_node_test(
|
||||||
bootstrap = ["angular/tools/testing/init_node_spec.js"],
|
bootstrap = ["angular/tools/testing/init_node_spec.js"],
|
||||||
deps = [
|
deps = [
|
||||||
"//packages/bazel/src/schematics/bazel-workspace:test",
|
"//packages/bazel/src/schematics/bazel-workspace:test",
|
||||||
|
"//packages/bazel/src/schematics/ng-new:test",
|
||||||
"//tools/testing:node",
|
"//tools/testing:node",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,7 +7,15 @@ load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver")
|
||||||
|
|
||||||
ng_module(
|
ng_module(
|
||||||
name = "src",
|
name = "src",
|
||||||
srcs = glob(["**/*.ts"], exclude = ["**/*.spec.ts", "test.ts"]),
|
srcs = glob(
|
||||||
|
include = ["**/*.ts"],
|
||||||
|
exclude = [
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"main.ts",
|
||||||
|
"test.ts",
|
||||||
|
"initialize_testbed.ts",
|
||||||
|
],
|
||||||
|
),
|
||||||
assets = glob([
|
assets = glob([
|
||||||
"**/*.css",
|
"**/*.css",
|
||||||
"**/*.html",
|
"**/*.html",
|
||||||
|
@ -21,7 +29,7 @@ ng_module(
|
||||||
|
|
||||||
rollup_bundle(
|
rollup_bundle(
|
||||||
name = "bundle",
|
name = "bundle",
|
||||||
entry_point = "src/main",
|
entry_point = "src/main.prod",
|
||||||
deps = ["//src"],
|
deps = ["//src"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,7 +58,7 @@ ts_devserver(
|
||||||
"npm/node_modules/zone.js/dist",
|
"npm/node_modules/zone.js/dist",
|
||||||
"npm/node_modules/tslib",
|
"npm/node_modules/tslib",
|
||||||
],
|
],
|
||||||
entry_module = "<%= name %>/src/main",
|
entry_module = "<%= name %>/src/main.dev",
|
||||||
serving_path = "/bundle.min.js",
|
serving_path = "/bundle.min.js",
|
||||||
static_files = [
|
static_files = [
|
||||||
"@npm//node_modules/zone.js:dist/zone.min.js",
|
"@npm//node_modules/zone.js:dist/zone.min.js",
|
||||||
|
@ -67,14 +75,28 @@ ts_library(
|
||||||
deps = [
|
deps = [
|
||||||
":src",
|
":src",
|
||||||
"@angular//packages/core/testing",
|
"@angular//packages/core/testing",
|
||||||
"@angular//packages/platform-browser-dynamic/testing",
|
|
||||||
"@npm//@types",
|
"@npm//@types",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ts_library(
|
||||||
|
name = "initialize_testbed",
|
||||||
|
testonly = 1,
|
||||||
|
srcs = [
|
||||||
|
"initialize_testbed.ts",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"@angular//packages/core/testing",
|
||||||
|
"@angular//packages/platform-browser-dynamic/testing",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
ts_web_test_suite(
|
ts_web_test_suite(
|
||||||
name = "test",
|
name = "test",
|
||||||
srcs = ["@npm//node_modules/tslib:tslib.js"],
|
srcs = ["@npm//node_modules/tslib:tslib.js"],
|
||||||
|
runtime_deps = [
|
||||||
|
":initialize_testbed",
|
||||||
|
],
|
||||||
# do not sort
|
# do not sort
|
||||||
bootstrap = [
|
bootstrap = [
|
||||||
"@npm//node_modules/zone.js:dist/zone-testing-bundle.js",
|
"@npm//node_modules/zone.js:dist/zone-testing-bundle.js",
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* @fileoverview Provides a script to initialize TestBed before tests are run.
|
||||||
|
* This file should be included in the "runtime_deps" of a "ts_web_test_suite"
|
||||||
|
* rule.
|
||||||
|
*/
|
||||||
|
import {TestBed} from '@angular/core/testing';
|
||||||
|
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
|
TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
|
@ -30,7 +30,7 @@ export default function(options: BazelWorkspaceOptions): Rule {
|
||||||
const appDir = `${newProjectRoot}/${options.name}`;
|
const appDir = `${newProjectRoot}/${options.name}`;
|
||||||
|
|
||||||
const workspaceVersions = {
|
const workspaceVersions = {
|
||||||
'ANGULAR_VERSION': '7.0.2',
|
'ANGULAR_VERSION': '7.1.0',
|
||||||
'RULES_SASS_VERSION': '1.14.1',
|
'RULES_SASS_VERSION': '1.14.1',
|
||||||
'RXJS_VERSION': '6.3.3',
|
'RXJS_VERSION': '6.3.3',
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
"name": "@angular/bazel",
|
"name": "@angular/bazel",
|
||||||
"version": "0.1",
|
"version": "0.1",
|
||||||
"schematics": {
|
"schematics": {
|
||||||
|
"ng-new": {
|
||||||
|
"factory": "./ng-new",
|
||||||
|
"schema": "./ng-new/schema.json",
|
||||||
|
"description": "Create an Angular project that builds with Bazel."
|
||||||
|
},
|
||||||
"bazel-workspace": {
|
"bazel-workspace": {
|
||||||
"factory": "./bazel-workspace",
|
"factory": "./bazel-workspace",
|
||||||
"schema": "./bazel-workspace/schema.json",
|
"schema": "./bazel-workspace/schema.json",
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
|
load("//tools:defaults.bzl", "ts_library")
|
||||||
|
|
||||||
|
ts_library(
|
||||||
|
name = "ng-new",
|
||||||
|
srcs = [
|
||||||
|
"index.ts",
|
||||||
|
"schema.d.ts",
|
||||||
|
],
|
||||||
|
data = glob(["files/**/*"]) + [
|
||||||
|
"schema.json",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//packages/bazel/src/schematics/bazel-workspace",
|
||||||
|
"@ngdeps//@angular-devkit/core",
|
||||||
|
"@ngdeps//@angular-devkit/schematics",
|
||||||
|
"@ngdeps//@schematics/angular",
|
||||||
|
"@ngdeps//typescript",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
ts_library(
|
||||||
|
name = "test",
|
||||||
|
testonly = True,
|
||||||
|
srcs = [
|
||||||
|
"index_spec.ts",
|
||||||
|
],
|
||||||
|
data = [
|
||||||
|
"//packages/bazel/src/schematics:package_assets",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
":ng-new",
|
||||||
|
"@ngdeps//@angular-devkit/schematics",
|
||||||
|
],
|
||||||
|
)
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title><%= utils.classify(name) %></title>
|
||||||
|
<base href="/">
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
<script src="/zone.min.js"></script>
|
||||||
|
<script src="/bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,4 @@
|
||||||
|
import {platformBrowser} from '@angular/platform-browser';
|
||||||
|
import {AppModuleNgFactory} from './app/app.module.ngfactory';
|
||||||
|
|
||||||
|
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
|
@ -0,0 +1,6 @@
|
||||||
|
import {enableProdMode} from '@angular/core';
|
||||||
|
import {platformBrowser} from '@angular/platform-browser';
|
||||||
|
import {AppModuleNgFactory} from './app/app.module.ngfactory';
|
||||||
|
|
||||||
|
enableProdMode();
|
||||||
|
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
|
@ -0,0 +1,180 @@
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*
|
||||||
|
* @fileoverview Schematics for ng-new project that builds with Bazel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {apply, applyTemplates, chain, externalSchematic, MergeStrategy, mergeWith, move, Rule, schematic, Tree, url, SchematicsException, UpdateRecorder,} from '@angular-devkit/schematics';
|
||||||
|
import {parseJsonAst, JsonAstObject, strings, JsonValue} from '@angular-devkit/core';
|
||||||
|
import {findPropertyInAstObject, insertPropertyInAstObjectInOrder} from '@schematics/angular/utility/json-utils';
|
||||||
|
import {validateProjectName} from '@schematics/angular/utility/validation';
|
||||||
|
import {getWorkspace} from '@schematics/angular/utility/config';
|
||||||
|
import {Schema} from './schema';
|
||||||
|
|
||||||
|
function addDevDependenciesToPackageJson(options: Schema) {
|
||||||
|
return (host: Tree) => {
|
||||||
|
const packageJson = `${options.name}/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');
|
||||||
|
const angularCoreVersion = angularCoreNode !.value as string;
|
||||||
|
|
||||||
|
const devDependencies: {[k: string]: string} = {
|
||||||
|
'@angular/bazel': angularCoreVersion,
|
||||||
|
'@bazel/karma': '0.21.0',
|
||||||
|
'@bazel/typescript': '0.21.0',
|
||||||
|
};
|
||||||
|
|
||||||
|
const recorder = host.beginUpdate(packageJson);
|
||||||
|
for (const packageName of Object.keys(devDependencies)) {
|
||||||
|
const version = devDependencies[packageName];
|
||||||
|
const indent = 4;
|
||||||
|
insertPropertyInAstObjectInOrder(recorder, devDeps, packageName, version, indent);
|
||||||
|
}
|
||||||
|
host.commitUpdate(recorder);
|
||||||
|
return host;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function overwriteMainAndIndex(options: Schema) {
|
||||||
|
return (host: Tree) => {
|
||||||
|
let newProjectRoot = '';
|
||||||
|
try {
|
||||||
|
const workspace = getWorkspace(host);
|
||||||
|
newProjectRoot = workspace.newProjectRoot || '';
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
const srcDir = `${newProjectRoot}/${options.name}/src`;
|
||||||
|
|
||||||
|
return mergeWith(
|
||||||
|
apply(
|
||||||
|
url('./files'),
|
||||||
|
[
|
||||||
|
applyTemplates({
|
||||||
|
utils: strings,
|
||||||
|
...options,
|
||||||
|
'dot': '.',
|
||||||
|
}),
|
||||||
|
move(srcDir),
|
||||||
|
]),
|
||||||
|
MergeStrategy.Overwrite);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function replacePropertyInAstObject(
|
||||||
|
recorder: UpdateRecorder, node: JsonAstObject, propertyName: string, value: JsonValue,
|
||||||
|
indent: number) {
|
||||||
|
const property = findPropertyInAstObject(node, propertyName);
|
||||||
|
if (property === null) {
|
||||||
|
throw new Error(`Property ${propertyName} does not exist in JSON object`);
|
||||||
|
}
|
||||||
|
const {start, text} = property;
|
||||||
|
recorder.remove(start.offset, text.length);
|
||||||
|
const indentStr = '\n' +
|
||||||
|
' '.repeat(indent);
|
||||||
|
const content = JSON.stringify(value, null, ' ').replace(/\n/g, indentStr);
|
||||||
|
recorder.insertLeft(start.offset, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateWorkspaceFileToUseBazelBuilder(options: Schema): Rule {
|
||||||
|
return (host: Tree, context: SchematicContext) => {
|
||||||
|
const {name} = options;
|
||||||
|
const workspacePath = `${name}/angular.json`;
|
||||||
|
if (!host.exists(workspacePath)) {
|
||||||
|
throw new SchematicsException(`Workspace file ${workspacePath} not found.`);
|
||||||
|
}
|
||||||
|
const workspaceBuffer = host.read(workspacePath) !;
|
||||||
|
const workspaceJsonAst = parseJsonAst(workspaceBuffer.toString()) as JsonAstObject;
|
||||||
|
const projects = findPropertyInAstObject(workspaceJsonAst, 'projects');
|
||||||
|
if (!projects) {
|
||||||
|
throw new SchematicsException('Expect projects in angular.json to be an Object');
|
||||||
|
}
|
||||||
|
const project = findPropertyInAstObject(projects as JsonAstObject, name);
|
||||||
|
if (!project) {
|
||||||
|
throw new SchematicsException(`Expected projects to contain ${name}`);
|
||||||
|
}
|
||||||
|
const recorder = host.beginUpdate(workspacePath);
|
||||||
|
const indent = 6;
|
||||||
|
replacePropertyInAstObject(
|
||||||
|
recorder, project as JsonAstObject, 'architect', {
|
||||||
|
'build': {
|
||||||
|
'builder': '@angular/bazel:build',
|
||||||
|
'options': {'targetLabel': '//src:bundle.js', 'bazelCommand': 'build'},
|
||||||
|
'configurations': {'production': {'targetLabel': '//src:bundle'}}
|
||||||
|
},
|
||||||
|
'serve': {
|
||||||
|
'builder': '@angular/bazel:build',
|
||||||
|
'options': {'targetLabel': '//src:devserver', 'bazelCommand': 'run'},
|
||||||
|
'configurations': {'production': {'targetLabel': '//src:prodserver'}}
|
||||||
|
},
|
||||||
|
'extract-i18n': {
|
||||||
|
'builder': '@angular-devkit/build-angular:extract-i18n',
|
||||||
|
'options': {'browserTarget': `${name}:build`}
|
||||||
|
},
|
||||||
|
'test': {
|
||||||
|
'builder': '@angular/bazel:build',
|
||||||
|
'options': {'bazelCommand': 'test', 'targetLabel': '//src/...'}
|
||||||
|
},
|
||||||
|
'lint': {
|
||||||
|
'builder': '@angular-devkit/build-angular:tslint',
|
||||||
|
'options': {
|
||||||
|
'tsConfig': ['src/tsconfig.app.json', 'src/tsconfig.spec.json'],
|
||||||
|
'exclude': ['**/node_modules/**']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
indent);
|
||||||
|
|
||||||
|
const e2e = `${options.name}-e2e`;
|
||||||
|
const e2eNode = findPropertyInAstObject(projects as JsonAstObject, e2e);
|
||||||
|
if (e2eNode) {
|
||||||
|
replacePropertyInAstObject(
|
||||||
|
recorder, e2eNode as JsonAstObject, 'architect', {
|
||||||
|
'e2e': {
|
||||||
|
'builder': '@angular/bazel:build',
|
||||||
|
'options': {'bazelCommand': 'test', 'targetLabel': '//e2e:devserver_test'},
|
||||||
|
'configurations': {'production': {'targetLabel': '//e2e:prodserver_test'}}
|
||||||
|
},
|
||||||
|
'lint': {
|
||||||
|
'builder': '@angular-devkit/build-angular:tslint',
|
||||||
|
'options': {'tsConfig': 'e2e/tsconfig.e2e.json', 'exclude': ['**/node_modules/**']}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
host.commitUpdate(recorder);
|
||||||
|
return host;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function(options: Schema): Rule {
|
||||||
|
return (host: Tree) => {
|
||||||
|
validateProjectName(options.name);
|
||||||
|
|
||||||
|
return chain([
|
||||||
|
externalSchematic('@schematics/angular', 'ng-new', {
|
||||||
|
...options,
|
||||||
|
skipInstall: true,
|
||||||
|
}),
|
||||||
|
addDevDependenciesToPackageJson(options),
|
||||||
|
schematic('bazel-workspace', options),
|
||||||
|
overwriteMainAndIndex(options),
|
||||||
|
updateWorkspaceFileToUseBazelBuilder(options),
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
* @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 {SchematicTestRunner} from '@angular-devkit/schematics/testing';
|
||||||
|
|
||||||
|
describe('Ng-new Schematic', () => {
|
||||||
|
const schematicRunner =
|
||||||
|
new SchematicTestRunner('@angular/bazel', require.resolve('../collection.json'), );
|
||||||
|
const defaultOptions = {
|
||||||
|
name: 'demo',
|
||||||
|
version: '7.0.0',
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should call external @schematics/angular', () => {
|
||||||
|
const options = {...defaultOptions};
|
||||||
|
const host = schematicRunner.runSchematic('ng-new', options);
|
||||||
|
const {files} = host;
|
||||||
|
// External schematic should produce workspace file angular.json
|
||||||
|
expect(files).toContain('/demo/angular.json');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add @angular/bazel to package.json dependencies', () => {
|
||||||
|
const options = {...defaultOptions};
|
||||||
|
const host = schematicRunner.runSchematic('ng-new', options);
|
||||||
|
const {files} = host;
|
||||||
|
expect(files).toContain('/demo/package.json');
|
||||||
|
const content = host.readContent('/demo/package.json');
|
||||||
|
expect(() => JSON.parse(content)).not.toThrow();
|
||||||
|
const json = JSON.parse(content);
|
||||||
|
const core = '@angular/core';
|
||||||
|
const bazel = '@angular/bazel';
|
||||||
|
expect(Object.keys(json)).toContain('dependencies');
|
||||||
|
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 create Bazel workspace file', () => {
|
||||||
|
const options = {...defaultOptions};
|
||||||
|
const host = schematicRunner.runSchematic('ng-new', options);
|
||||||
|
const {files} = host;
|
||||||
|
expect(files).toContain('/demo/WORKSPACE');
|
||||||
|
expect(files).toContain('/demo/BUILD.bazel');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should produce main.prod.ts for AOT', () => {
|
||||||
|
const options = {...defaultOptions};
|
||||||
|
const host = schematicRunner.runSchematic('ng-new', options);
|
||||||
|
const {files} = host;
|
||||||
|
// main.prod.ts is used by Bazel for AOT
|
||||||
|
expect(files).toContain('/demo/src/main.prod.ts');
|
||||||
|
// main.ts is produced by original ng-new schematics
|
||||||
|
// This file should be present for backwards compatibility.
|
||||||
|
expect(files).toContain('/demo/src/main.ts');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should overwrite index.html with script tags', () => {
|
||||||
|
const options = {...defaultOptions};
|
||||||
|
const host = schematicRunner.runSchematic('ng-new', options);
|
||||||
|
const {files} = host;
|
||||||
|
expect(files).toContain('/demo/src/index.html');
|
||||||
|
const content = host.readContent('/demo/src/index.html');
|
||||||
|
expect(content).toMatch('<script src="/zone.min.js"></script>');
|
||||||
|
expect(content).toMatch('<script src="/bundle.min.js"></script>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update angular.json to use Bazel builder', () => {
|
||||||
|
const options = {...defaultOptions};
|
||||||
|
const host = schematicRunner.runSchematic('ng-new', options);
|
||||||
|
const {files} = host;
|
||||||
|
expect(files).toContain('/demo/angular.json');
|
||||||
|
const content = host.readContent('/demo/angular.json');
|
||||||
|
expect(() => JSON.parse(content)).not.toThrow();
|
||||||
|
const json = JSON.parse(content);
|
||||||
|
let {architect} = json.projects.demo;
|
||||||
|
expect(architect.build.builder).toBe('@angular/bazel:build');
|
||||||
|
expect(architect.serve.builder).toBe('@angular/bazel:build');
|
||||||
|
expect(architect.test.builder).toBe('@angular/bazel:build');
|
||||||
|
architect = json.projects['demo-e2e'].architect;
|
||||||
|
expect(architect.e2e.builder).toBe('@angular/bazel:build');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,103 @@
|
||||||
|
|
||||||
|
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
|
||||||
|
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
|
||||||
|
|
||||||
|
// tslint:disable:no-global-tslint-disable
|
||||||
|
// tslint:disable
|
||||||
|
|
||||||
|
export interface Schema {
|
||||||
|
/**
|
||||||
|
* Initial repository commit information.
|
||||||
|
*/
|
||||||
|
commit?: CommitUnion;
|
||||||
|
/**
|
||||||
|
* Flag to toggle creation of an application in the new workspace.
|
||||||
|
*/
|
||||||
|
createApplication?: boolean;
|
||||||
|
/**
|
||||||
|
* The directory name to create the workspace in.
|
||||||
|
*/
|
||||||
|
directory?: string;
|
||||||
|
/**
|
||||||
|
* EXPERIMENTAL: Specifies whether to create a new application which uses the Ivy rendering
|
||||||
|
* engine.
|
||||||
|
*/
|
||||||
|
experimentalIvy?: boolean;
|
||||||
|
/**
|
||||||
|
* Specifies if the style will be in the ts file.
|
||||||
|
*/
|
||||||
|
inlineStyle?: boolean;
|
||||||
|
/**
|
||||||
|
* Specifies if the template will be in the ts file.
|
||||||
|
*/
|
||||||
|
inlineTemplate?: boolean;
|
||||||
|
/**
|
||||||
|
* Link CLI to global version (internal development only).
|
||||||
|
*/
|
||||||
|
linkCli?: boolean;
|
||||||
|
/**
|
||||||
|
* Create a barebones project without any testing frameworks
|
||||||
|
*/
|
||||||
|
minimal?: boolean;
|
||||||
|
/**
|
||||||
|
* The name of the workspace.
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* The path where new projects will be created.
|
||||||
|
*/
|
||||||
|
newProjectRoot?: string;
|
||||||
|
/**
|
||||||
|
* The prefix to apply to generated selectors.
|
||||||
|
*/
|
||||||
|
prefix?: string;
|
||||||
|
/**
|
||||||
|
* Generates a routing module.
|
||||||
|
*/
|
||||||
|
routing?: boolean;
|
||||||
|
/**
|
||||||
|
* Skip initializing a git repository.
|
||||||
|
*/
|
||||||
|
skipGit?: boolean;
|
||||||
|
/**
|
||||||
|
* Skip installing dependency packages.
|
||||||
|
*/
|
||||||
|
skipInstall?: boolean;
|
||||||
|
/**
|
||||||
|
* Skip creating spec files.
|
||||||
|
*/
|
||||||
|
skipTests?: boolean;
|
||||||
|
/**
|
||||||
|
* The file extension to be used for style files.
|
||||||
|
*/
|
||||||
|
style?: string;
|
||||||
|
/**
|
||||||
|
* The version of the Angular CLI to use.
|
||||||
|
*/
|
||||||
|
version: string;
|
||||||
|
/**
|
||||||
|
* Specifies the view encapsulation strategy.
|
||||||
|
*/
|
||||||
|
viewEncapsulation?: ViewEncapsulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial repository commit information.
|
||||||
|
*/
|
||||||
|
export type CommitUnion = boolean | CommitObject;
|
||||||
|
|
||||||
|
export interface CommitObject {
|
||||||
|
email: string;
|
||||||
|
message?: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the view encapsulation strategy.
|
||||||
|
*/
|
||||||
|
export enum ViewEncapsulation {
|
||||||
|
Emulated = 'Emulated',
|
||||||
|
Native = 'Native',
|
||||||
|
None = 'None',
|
||||||
|
ShadowDOM = 'ShadowDom',
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/schema",
|
||||||
|
"id": "SchematicsAngularNgNew",
|
||||||
|
"title": "Angular Ng New Options Schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"directory": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The directory name to create the workspace in."
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"description": "The name of the workspace.",
|
||||||
|
"type": "string",
|
||||||
|
"format": "html-selector",
|
||||||
|
"$default": {
|
||||||
|
"$source": "argv",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
"x-prompt": "What name would you like to use for the project?"
|
||||||
|
},
|
||||||
|
"experimentalIvy": {
|
||||||
|
"description": "EXPERIMENTAL: Specifies whether to create a new application which uses the Ivy rendering engine.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"skipInstall": {
|
||||||
|
"description": "Skip installing dependency packages.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"linkCli": {
|
||||||
|
"description": "Link CLI to global version (internal development only).",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"visible": false
|
||||||
|
},
|
||||||
|
"skipGit": {
|
||||||
|
"description": "Skip initializing a git repository.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"alias": "g"
|
||||||
|
},
|
||||||
|
"commit": {
|
||||||
|
"description": "Initial repository commit information.",
|
||||||
|
"oneOf": [
|
||||||
|
{ "type": "boolean" },
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "email"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"email"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"newProjectRoot": {
|
||||||
|
"description": "The path where new projects will be created.",
|
||||||
|
"type": "string",
|
||||||
|
"default": "projects"
|
||||||
|
},
|
||||||
|
"inlineStyle": {
|
||||||
|
"description": "Specifies if the style will be in the ts file.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"alias": "s"
|
||||||
|
},
|
||||||
|
"inlineTemplate": {
|
||||||
|
"description": "Specifies if the template will be in the ts file.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"alias": "t"
|
||||||
|
},
|
||||||
|
"viewEncapsulation": {
|
||||||
|
"description": "Specifies the view encapsulation strategy.",
|
||||||
|
"enum": ["Emulated", "Native", "None", "ShadowDom"],
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The version of the Angular CLI to use.",
|
||||||
|
"visible": false,
|
||||||
|
"$default": {
|
||||||
|
"$source": "ng-cli-version"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"routing": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Generates a routing module.",
|
||||||
|
"default": false,
|
||||||
|
"x-prompt": "Would you like to add Angular routing?"
|
||||||
|
},
|
||||||
|
"prefix": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "html-selector",
|
||||||
|
"description": "The prefix to apply to generated selectors.",
|
||||||
|
"minLength": 1,
|
||||||
|
"default": "app",
|
||||||
|
"alias": "p"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"description": "The file extension to be used for style files.",
|
||||||
|
"type": "string",
|
||||||
|
"default": "css",
|
||||||
|
"x-prompt": {
|
||||||
|
"message": "Which stylesheet format would you like to use?",
|
||||||
|
"type": "list",
|
||||||
|
"items": [
|
||||||
|
{ "value": "css", "label": "CSS" },
|
||||||
|
{ "value": "scss", "label": "SCSS [ http://sass-lang.com ]" },
|
||||||
|
{ "value": "sass", "label": "SASS [ http://sass-lang.com ]" },
|
||||||
|
{ "value": "less", "label": "LESS [ http://lesscss.org ]" },
|
||||||
|
{ "value": "styl", "label": "Stylus [ http://stylus-lang.com ]" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"skipTests": {
|
||||||
|
"description": "Skip creating spec files.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"alias": "S"
|
||||||
|
},
|
||||||
|
"createApplication": {
|
||||||
|
"description": "Flag to toggle creation of an application in the new workspace.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"minimal": {
|
||||||
|
"description": "Create a barebones project without any testing frameworks",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"version"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue