feat(nx): remove @nrwl/bazel package

This commit is contained in:
mrmeku 2019-04-10 10:29:05 -04:00 committed by Victor Savkin
parent a5bc37c60d
commit b8ee3ba478
66 changed files with 4 additions and 3972 deletions

View File

@ -45,7 +45,6 @@
- [Affected support for uncommitted changes](https://github.com/nrwl/nx/commit/113b51bd330c2af058675386e482d38f170a6688)
- [Extend circular dependency check](https://github.com/nrwl/nx/commit/fff9659c3a108b613c6db89bcca4072494fbe85f)
- [Add lint checks ensuring the integrity of the workspace](https://github.com/nrwl/nx/commit/ce553b732e8ca004e1ecf53cf54bcadb6ba1f7f3)
- [Add ability to create bazel workspace](https://github.com/nrwl/nx/commit/5a26f241b1e8b8b87e2ab4da941d3d3c4c480046)
## Fixes

View File

@ -14,7 +14,7 @@ If you find a bug in the source code or a mistake in the documentation, you can
After cloning the project run: `yarn`.
After that run `yarn build` to build the `bazel`, `nx`, and `schematics` packages.
After that run `yarn build` to build the `nx`, and `schematics` packages.
After that run `yarn linknpm`.

View File

@ -15,10 +15,10 @@
<hr>
<p align="center">
<a href="https://hubs.ly/H0g97pW0" target="_blank">
<img
<a href="https://hubs.ly/H0g97pW0" target="_blank">
<img
width="728"
src="https://images.ctfassets.net/8eyogtwep6d2/40ASb6l6MR7V0w5ntqZ2yi/b4d439fcf56e50085d1f76df1bee41af/monorepo-banner-angularconsole.png"
src="https://images.ctfassets.net/8eyogtwep6d2/40ASb6l6MR7V0w5ntqZ2yi/b4d439fcf56e50085d1f76df1bee41af/monorepo-banner-angularconsole.png"
alt="Our Newest Enterprise Angular Book">
</a>
</p>

View File

@ -1,41 +0,0 @@
Bazel Commands
## Add new app
node_modules/.bin/ng generate app [name]
Example: node_modules/.bin/ng generate app test
## Add new component
node_modules/.bin/ng generate component [name] --directory=[dir]
Example: node_modules/.bin/ng generate component friends --directory=myDir
- must manually import the component's Bazel rule in the consuming Bazel rule
## Add new lib
node_modules/.bin/ng generate lib [name]
Example: node_modules/.bin/ng generate lib mylib
- must manually import the lib's Bazel rule in the consuming Bazel rule
## Run dev server
ibazel run apps/[app specific path]]/src:devserver (anything between apps/\*\*/src points to a specific app)
Example: ibazel run apps/my-dir/my-app/src:devserver
## Run prod server
bazel run apps/[app specific path]]/src:prodserver (anything between apps/\*\*/src points to a specific app)
Example: bazel run apps/my-dir/my-app/src:prodserver
## Run unit tests
ibazel test //libs/mylib/src:test
- currently works for libs

View File

@ -1,21 +0,0 @@
{
"name": "@nrwl/bazel",
"version": "0.0.1",
"description": "Nrwl Extensions for Angular: Bazel Schematics",
"main": "index.js",
"types": "index.d.js",
"author": "Victor Savkin",
"license": "MIT",
"schematics": "./src/collection.json",
"dependencies": {
"@ngrx/schematics": "6.0.1",
"app-root-path": "^2.0.1",
"npm-run-all": "4.1.2",
"semver": "5.4.1",
"tmp": "0.0.33",
"yargs-parser": "10.0.0"
},
"peerDependencies": {
"@schematics/angular": "0.7.1"
}
}

View File

@ -1,28 +0,0 @@
{
"name": "nx-bazel",
"version": "0.1",
"extends": "@schematics/angular",
"schematics": {
"application": {
"factory": "./collection/application",
"schema": "./collection/application/schema.json",
"description": "Create a Bazel workspace."
},
"app": {
"factory": "./collection/app",
"schema": "./collection/app/schema.json",
"description": "Create an application."
},
"lib": {
"factory": "./collection/lib",
"schema": "./collection/lib/schema.json",
"description": "Create a library"
},
"module": {
"aliases": ["m"],
"factory": "./collection/module",
"schema": "./collection/module/schema.json",
"description": "Create a Module"
}
}
}

View File

@ -1,57 +0,0 @@
load("@angular//:index.bzl", "ng_module")
load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver")
package(default_visibility = ["//visibility:public"])
ng_module(
name = "<%= sourceDir %>",
srcs = glob(["main.ts"]),
deps = [
"//apps/<%= fullName %>/src/app",
"@rxjs",
],
)
# Needed because the devserver only loads static files that appear under this
# package.
genrule(
name = "zone.js",
srcs = ["//:node_modules/zone.js/dist/zone.min.js"],
outs = ["zone.min.js"],
cmd = "cp $< $@",
)
STATIC_FILES = [
"favicon.ico",
"index.html",
"styles.css",
":zone.js",
]
ts_devserver(
name = "devserver",
data = ["//apps/<%= fullName %>/src/assets"],
entry_module = "<%= workspaceName %>/apps/<%= fullName %>/src/main",
scripts = ["//:angular_bundles"],
serving_path = "/bundle.min.js",
static_files = STATIC_FILES,
deps = [":<%= sourceDir %>"],
)
load("@build_bazel_rules_nodejs//:defs.bzl", "rollup_bundle", "nodejs_binary")
rollup_bundle(
name = "bundle",
entry_point = "<%= workspaceName %>/apps/<%= fullName %>/src/main",
deps = [":<%= sourceDir %>"],
)
nodejs_binary(
name = "prodserver",
args = ["./apps/<%= fullName %>/src"],
data = STATIC_FILES + [
":bundle",
"//apps/<%= fullName %>/src/assets",
],
entry_point = "http-server/bin/http-server",
)

View File

@ -1,6 +0,0 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "assets",
srcs = glob(["*"]),
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -1,17 +0,0 @@
<!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>
<<%= prefix %>-root></<%= prefix %>-root>
<script src="/zone.min.js"></script>
<script src="/bundle.min.js"></script>
</body>
</html>

View File

@ -1,7 +0,0 @@
import { enableProdMode } from '@angular/core';
import { platformBrowser } from '@angular/platform-browser';
import {AppModuleNgFactory} from './app/app.module.ngfactory';
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory)
.catch(err => console.log(err));

View File

@ -1,76 +0,0 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';
/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import 'core-js/es7/reflect';
/**
* Required to support Web Animations `@angular/platform-browser/animations`.
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/***************************************************************************************************
* Zone JS is required by Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
/**
* Date, currency, decimal and percent pipes.
* Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
*/
// import 'intl'; // Run `npm install --save intl`.
/**
* Need to import at least one locale-data with intl.
*/
// import 'intl/locale-data/jsonp/en';

View File

@ -1 +0,0 @@
/* You can add global styles to this file, and also import other style files */

View File

@ -1,14 +0,0 @@
{
"extends": "<%= offsetFromRoot %>tsconfig.json",
"compilerOptions": {
"outDir": "<%= offsetFromRoot %>dist/out-tsc/apps/<%= fullName %>",
"module": "es2015"
},
"include": [
"**/*.ts"
/* add all lazy-loaded libraries here: "<%= offsetFromRoot %>libs/my-lib/index.ts" */
],
"exclude": [
"**/*.spec.ts"
]
}

View File

@ -1,14 +0,0 @@
import { AppPage } from './app.po';
describe('<%= utils.dasherize(name) %> App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.text()).toContain('Welcome');
});
});

View File

@ -1,11 +0,0 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get('/');
}
text() {
return browser.findElement(by.css('body')).getText();
}
}

View File

@ -1,20 +0,0 @@
{
"extends": "<%= offsetFromRoot %>tsconfig.json",
"compilerOptions": {
"outDir": "<%= offsetFromRoot %>dist/out-tsc/e2e/<%= fullName %>",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
},
"include": [
"../**/*.ts"
/* add all lazy-loaded libraries here: "<%= offsetFromRoot %>libs/my-lib/index.ts" */
],
"exclude": [
"**/*.spec.ts"
]
}

View File

@ -1,307 +0,0 @@
import {
apply,
branchAndMerge,
chain,
externalSchematic,
mergeWith,
noop,
Rule,
template,
Tree,
url
} from '@angular-devkit/schematics';
import { Schema } from './schema';
import { strings } from '@angular-devkit/core';
import {
addImportToModule,
insert,
addImportToTestBed,
updateJsonInTree
} from '../../utils/ast-utils';
import { toFileName } from '../../utils/name-utils';
import * as ts from 'typescript';
import {
addBootstrapToModule,
insertImport
} from '@schematics/angular/utility/ast-utils';
import { addApp, readCliConfigFile } from '../../utils/fileutils';
import { offsetFromRoot } from '../../utils/common';
import { formatFiles } from '../../utils/rules/format-files';
interface NormalizedSchema extends Schema {
fullName: string;
fullPath: string;
workspaceName: string;
}
function addBootstrap(path: string): Rule {
return (host: Tree) => {
const modulePath = `${path}/app/app.module.ts`;
const moduleSource = host.read(modulePath)!.toString('utf-8');
const sourceFile = ts.createSourceFile(
modulePath,
moduleSource,
ts.ScriptTarget.Latest,
true
);
insert(host, modulePath, [
insertImport(
sourceFile,
modulePath,
'BrowserModule',
'@angular/platform-browser'
),
...addImportToModule(sourceFile, modulePath, 'BrowserModule'),
...addBootstrapToModule(
sourceFile,
modulePath,
'AppComponent',
'./app.component'
)
]);
return host;
};
}
function addNxModule(path: string): Rule {
return (host: Tree) => {
const modulePath = `${path}/app/app.module.ts`;
const moduleSource = host.read(modulePath)!.toString('utf-8');
const sourceFile = ts.createSourceFile(
modulePath,
moduleSource,
ts.ScriptTarget.Latest,
true
);
insert(host, modulePath, [
insertImport(sourceFile, modulePath, 'NxModule', '@nrwl/nx'),
...addImportToModule(sourceFile, modulePath, 'NxModule.forRoot()')
]);
return host;
};
}
function addAppToAngularCliJson(options: NormalizedSchema): Rule {
return updateJsonInTree('.angular-cli.json', angularCliJson => {
angularCliJson.apps = addApp(angularCliJson.apps, {
name: options.fullName,
root: options.fullPath,
outDir: `dist/apps/${options.fullName}`,
assets: ['assets', 'favicon.ico'],
index: 'index.html',
main: 'main.ts',
polyfills: 'polyfills.ts',
test: `${offsetFromRoot(options.fullPath)}test.js`,
tsconfig: `tsconfig.app.json`,
testTsconfig: `${offsetFromRoot(options.fullPath)}tsconfig.spec.json`,
prefix: options.prefix,
styles: [`styles.${options.style}`],
scripts: [],
environmentSource: 'environments/environment.ts',
environments: {
dev: 'environments/environment.ts',
prod: 'environments/environment.prod.ts'
}
});
angularCliJson.lint = [
...(angularCliJson.lint || []),
{
project: `${options.fullPath}/tsconfig.app.json`,
exclude: '**/node_modules/**'
},
{
project: `apps/${options.fullName}/e2e/tsconfig.e2e.json`,
exclude: '**/node_modules/**'
}
];
return angularCliJson;
});
}
function addRouterRootConfiguration(path: string): Rule {
return (host: Tree) => {
const modulePath = `${path}/app/app.module.ts`;
const moduleSource = host.read(modulePath)!.toString('utf-8');
const sourceFile = ts.createSourceFile(
modulePath,
moduleSource,
ts.ScriptTarget.Latest,
true
);
insert(host, modulePath, [
insertImport(sourceFile, modulePath, 'RouterModule', '@angular/router'),
...addImportToModule(
sourceFile,
modulePath,
`RouterModule.forRoot([], {initialNavigation: 'enabled'})`
)
]);
const componentSpecPath = `${path}/app/app.component.spec.ts`;
const componentSpecSource = host.read(componentSpecPath)!.toString('utf-8');
const componentSpecSourceFile = ts.createSourceFile(
componentSpecPath,
componentSpecSource,
ts.ScriptTarget.Latest,
true
);
insert(host, componentSpecPath, [
insertImport(
componentSpecSourceFile,
componentSpecPath,
'RouterTestingModule',
'@angular/router/testing'
),
...addImportToTestBed(
componentSpecSourceFile,
componentSpecPath,
`RouterTestingModule`
)
]);
return host;
};
}
const staticComponentContent = `
<div style="text-align:center">
<h1>
Welcome to an Angular CLI app built with Nrwl Nx!
</h1>
<img width="450" src="assets/nx-logo.png">
</div>
<h2>Nx</h2>
An open source toolkit for enterprise Angular applications.
Nx is designed to help you create and build enterprise grade Angular applications. It provides an opinionated approach to application project structure and patterns.
<h2>Quick Start & Documentation</h2>
<a href="https://nrwl.io/nx">Watch a 5-minute video on how to get started with Nx.</a>`;
function updateComponentTemplate(options: NormalizedSchema): Rule {
return (host: Tree) => {
const content = options.routing
? `${staticComponentContent}\n<router-outlet></router-outlet>`
: staticComponentContent;
host.overwrite(`${options.fullPath}/app/app.component.html`, content);
};
}
function addBazelBuildFile(path: string): Rule {
return (host: Tree) => {
const ngModule = `package(default_visibility = ["//visibility:public"])
load("@angular//:index.bzl", "ng_module")
load("@build_bazel_rules_typescript//:defs.bzl", "ts_library", "ts_web_test")
ng_module(
name = "app",
srcs = glob(
["*.ts"],
exclude = ["*.spec.ts"],
),
assets = [
"app.component.css",
"app.component.html",
],
deps = [
"@rxjs",
],
)
ts_library(
name = "test_lib",
testonly = 1,
srcs = glob(["*.spec.ts"]),
deps = [
":app",
],
)
ts_web_test(
name = "test",
bootstrap = ["//:angular_bootstrap_scripts"],
deps = [
":test_lib",
"//:angular_bundles",
"//:angular_test_bundles",
],
)
`;
host.create(`${path}/app/BUILD.bazel`, ngModule);
};
}
export default function(schema: Schema): Rule {
let npmScope = schema.npmScope;
if (!npmScope) {
npmScope = readCliConfigFile().project.npmScope;
}
const options = normalizeOptions(schema);
const templateSource = apply(url('./files'), [
template({
utils: strings,
dot: '.',
tmpl: '',
offsetFromRoot: offsetFromRoot(options.fullPath),
...(options as object),
npmScope
})
]);
const selector = `${options.prefix}-root`;
return chain([
branchAndMerge(chain([mergeWith(templateSource)])),
externalSchematic('@schematics/angular', 'module', {
name: 'app',
commonModule: false,
flat: true,
routing: false,
sourceDir: options.fullPath,
spec: false
}),
externalSchematic('@schematics/angular', 'component', {
name: 'app',
selector: selector,
sourceDir: options.fullPath,
flat: true,
inlineStyle: options.inlineStyle,
inlineTemplate: options.inlineTemplate,
spec: !options.skipTests,
styleext: options.style,
viewEncapsulation: options.viewEncapsulation,
changeDetection: options.changeDetection
}),
updateComponentTemplate(options),
addBootstrap(options.fullPath),
addNxModule(options.fullPath),
addAppToAngularCliJson(options),
addBazelBuildFile(options.fullPath),
addAppToAngularCliJson(options),
options.routing ? addRouterRootConfiguration(options.fullPath) : noop(),
formatFiles(options)
]);
}
function normalizeOptions(options: Schema): NormalizedSchema {
const name = toFileName(options.name);
const fullName = options.directory
? `${toFileName(options.directory)}/${name}`
: name;
const fullPath = `apps/${fullName}/src`;
const workspaceName = readCliConfigFile().project.name;
return {
...options,
sourceDir: 'src',
name,
fullName,
fullPath,
workspaceName
};
}

View File

@ -1,15 +0,0 @@
export interface Schema {
name: string;
skipFormat: boolean;
npmScope?: string;
directory?: string;
sourceDir?: string;
inlineStyle?: boolean;
inlineTemplate?: boolean;
viewEncapsulation?: 'Emulated' | 'Native' | 'None';
changeDetection?: 'Default' | 'OnPush';
routing?: boolean;
skipTests?: boolean;
prefix?: string;
style?: string;
}

View File

@ -1,70 +0,0 @@
{
"$schema": "http://json-schema.org/schema",
"id": "application",
"title": "Create an application",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Application name"
},
"npmScope": {
"type": "string",
"description": "Calculated stuff"
},
"directory": {
"type": "string",
"description": "A directory where the app is placed"
},
"inlineStyle": {
"description": "Specifies if the style will be in the ts file.",
"type": "boolean",
"default": false,
"alias": "is"
},
"inlineTemplate": {
"description": "Specifies if the template will be in the ts file.",
"type": "boolean",
"default": false,
"alias": "it"
},
"viewEncapsulation": {
"description": "Specifies the view encapsulation strategy.",
"enum": ["Emulated", "Native", "None"],
"type": "string"
},
"changeDetection": {
"description": "Specifies the change detection strategy.",
"enum": ["Default", "OnPush"],
"type": "string",
"default": "Default"
},
"routing": {
"type": "boolean",
"default": false
},
"skipFormat": {
"description": "Skip formatting files",
"type": "boolean",
"default": false
},
"skipTests": {
"description": "Skip creating spec files.",
"type": "boolean",
"default": false,
"alias": "st"
},
"prefix": {
"type": "string",
"description": "The prefix to apply to generated selectors.",
"default": "app",
"alias": "p"
},
"style": {
"description": "The file extension to be used for style files.",
"type": "string",
"default": "css"
}
},
"required": ["name"]
}

View File

@ -1,61 +0,0 @@
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import * as path from 'path';
import { Tree, VirtualTree } from '@angular-devkit/schematics';
import { readJsonInTree } from '../../utils/ast-utils';
describe('application', () => {
const schematicRunner = new SchematicTestRunner(
'@nrwl/bazel',
path.join(__dirname, '../../collection.json')
);
let appTree: Tree;
beforeEach(() => {
appTree = new VirtualTree();
});
it('should generate files', () => {
const tree = schematicRunner.runSchematic(
'application',
{ name: 'myApp', directory: 'my-app' },
appTree
);
expect(tree.files).toEqual([
'/my-app/BUILD.bazel',
'/my-app/README.md',
'/my-app/WORKSPACE',
'/my-app/.angular-cli.json',
'/my-app/.editorconfig',
'/my-app/.gitignore',
'/my-app/apps/.gitkeep',
'/my-app/karma.conf.js',
'/my-app/libs/.gitkeep',
'/my-app/ngc.tsconfig.json',
'/my-app/package.json',
'/my-app/protractor.conf.js',
'/my-app/test.js',
'/my-app/tools/bazel.rc',
'/my-app/tsconfig.json',
'/my-app/tsconfig.spec.json',
'/my-app/tslint.json'
]);
});
it('should update package.json', () => {
const tree = schematicRunner.runSchematic(
'application',
{ name: 'myApp', directory: 'my-app' },
appTree
);
const packageJson = readJsonInTree(tree, '/my-app/package.json');
expect(packageJson.devDependencies['@nrwl/schematics']).toBeDefined();
expect(packageJson.dependencies['@nrwl/nx']).toBeDefined();
expect(packageJson.dependencies['@ngrx/store']).toBeDefined();
expect(packageJson.dependencies['@ngrx/effects']).toBeDefined();
expect(packageJson.dependencies['@ngrx/router-store']).toBeDefined();
expect(packageJson.dependencies['@ngrx/store-devtools']).toBeDefined();
});
});

View File

@ -1,81 +0,0 @@
package(default_visibility = ["//visibility:public"])
exports_files(["tsconfig.json"])
# NOTE: this will move to node_modules/BUILD in a later release
filegroup(
name = "node_modules",
# NB: rxjs is not in this list, because we build it from sources using the
# label @rxjs//:rxjs
srcs = glob(["/".join([
"node_modules",
pkg,
"**",
ext,
]) for pkg in [
"@angular",
"@nrwl",
"@ngrx",
"tsickle",
"tsutils",
"typescript",
"@types",
] for ext in [
"*.js",
"*.json",
"*.d.ts",
]] + [
"node_modules/http-server/**",
]),
)
ANGULAR_TESTING = [
"node_modules/@angular/*/bundles/*-testing.umd.js",
# We use AOT, so the compiler and the dynamic platform-browser should be
# visible only in tests
"node_modules/@angular/compiler/bundles/*.umd.js",
"node_modules/@angular/platform-browser-dynamic/bundles/*.umd.js",
]
# TODO: it's messy for users to need to specify the following
# Angular dependency lists. It should live somewhere else.
# See https://github.com/angular/angular/issues/21048
filegroup(
name = "angular_bundles",
srcs = glob(
[
"node_modules/@angular/*/bundles/*.umd.js",
"node_modules/@ngrx/store/bundles/store.umd.js",
"node_modules/@ngrx/router-store/bundles/router-store.umd.js",
"node_modules/@ngrx/effects/bundles/effects.umd.js",
"node_modules/@nrwl/nx/bundles/nrwl-nx.umd.js",
],
exclude = ANGULAR_TESTING + [
"node_modules/@angular/bazel/**/*",
"node_modules/@angular/cli/**/*",
"node_modules/@angular/compiler-cli/**/*",
"node_modules/@angular/language-service/**/*",
],
),
)
filegroup(
name = "angular_test_bundles",
testonly = 1,
srcs = glob(ANGULAR_TESTING),
)
filegroup(
name = "angular_bootstrap_scripts",
# do not sort
srcs = [
"//:node_modules/zone.js/dist/zone.min.js",
"//:node_modules/zone.js/dist/async-test.js",
"//:node_modules/zone.js/dist/sync-test.js",
"//:node_modules/zone.js/dist/proxy.min.js",
"//:node_modules/zone.js/dist/jasmine-patch.js",
],
)

View File

@ -1,44 +0,0 @@
# <%= utils.classify(name) %>
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) using [Nrwl Nx](https://nrwl.io/nx).
## Nrwl Extensions for Angular (Nx)
<a href="https://nrwl.io/nx"><img src="https://preview.ibb.co/mW6sdw/nx_logo.png"></a>
Nx is an open source toolkit for enterprise Angular applications.
Nx is designed to help you create and build enterprise grade Angular applications. It provides an opinionated approach to application project structure and patterns.
## Quick Start & Documentation
[Watch a 5-minute video on how to get started with Nx.](http://nrwl.io/nx)
## Generate your first application
Run `ng generate app myapp` to generate an application. When using Nx, you can create multiple applications and libraries in the same CLI workspace. Read more [here](http://nrwl.io/nx).
## Development server
Run `ng serve --app=myapp` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name --app=myapp` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build --app=myapp` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
Before running the tests make sure you are serving the app via `ng serve`.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@ -1,74 +0,0 @@
workspace(name = "<%= name %>")
####################################
# The Bazel buildtools repo contains tools like the BUILD file formatter, buildifier
http_archive(
name = "com_github_bazelbuild_buildtools",
sha256 = "4d8d6244320dd751590f9100cf39fd7a4b75cd901e1f3ffdfd6f048328883695",
# Note, this commit matches the version of buildifier in angular/ngcontainer
url = "https://github.com/bazelbuild/buildtools/archive/b3b620e8bcff18ed3378cd3f35ebeb7016d71f71.zip",
)
####################################
# Fetch and install the NodeJS rules
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "e9bc013417272b17f302dc169ad597f05561bb277451f010043f4da493417607",
strip_prefix = "rules_nodejs-0.4.1",
url = "https://github.com/bazelbuild/rules_nodejs/archive/0.4.1.zip",
)
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
node_repositories(package_json = ["//:package.json"])
####################################
# Fetch and install the Sass rules
git_repository(
name = "io_bazel_rules_sass",
remote = "https://github.com/bazelbuild/rules_sass.git",
tag = "0.0.3",
)
load("@io_bazel_rules_sass//sass:sass.bzl", "sass_repositories")
sass_repositories()
####################################
# Fetch and install the TypeScript rules
http_archive(
name = "build_bazel_rules_typescript",
sha256 = "a2c81776a4a492ff9f878f9705639f5647bef345f7f3e1da09c9eeb8dec80485",
strip_prefix = "rules_typescript-0.10.1",
url = "https://github.com/bazelbuild/rules_typescript/archive/0.10.1.zip",
)
load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")
ts_setup_workspace()
# Some of the TypeScript is written in Go.
# Bazel doesn't support transitive WORKSPACE deps, so we must repeat them here.
http_archive(
name = "io_bazel_rules_go",
sha256 = "4b14d8dd31c6dbaf3ff871adcd03f28c3274e42abc855cb8fb4d01233c0154dc",
url = "https://github.com/bazelbuild/rules_go/releases/download/0.10.1/rules_go-0.10.1.tar.gz",
)
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
go_rules_dependencies()
go_register_toolchains()
####################################
# Tell Bazel about some workspaces that were installed from npm.
local_repository(
name = "angular",
path = "node_modules/@angular/bazel",
)
local_repository(
name = "rxjs",
path = "node_modules/rxjs/src",
)

View File

@ -1,64 +0,0 @@
{
"$schema": "<%= angularCliSchema %>",
"project": {
"name": "<%= utils.dasherize(name) %>",
"npmScope": "<%= npmScope %>",
"latestMigration": "<%= latestMigration %>"
},
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "./tsconfig.spec.json",
"exclude": "**/node_modules/**"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"apps": [
{
"name": "$workspaceRoot",
"root": ".",
"appRoot": ""
}
],
"defaults": {
"schematics": {
"collection": "@nrwl/bazel"
},
"styleExt": "<%= style %>",<% if (!minimal) { %>
"component": {}<% } else { %>
"component": {
"spec": false,
"inlineStyle": true,
"inlineTemplate": true
},
"directive": {
"spec": false
},
"class": {
"spec": false
},
"guard": {
"spec": false
},
"module": {
"spec": false
},
"pipe": {
"spec": false
},
"service": {
"spec": false
} <% } %>
},
"warnings": {
"typescriptMismatch": false
}
}

View File

@ -1,13 +0,0 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View File

@ -1,42 +0,0 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
testem.log
/typings
# e2e
/e2e/*.js
/e2e/*.map
# System Files
.DS_Store
Thumbs.db

View File

@ -1,37 +0,0 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
const { makeSureNoAppIsSelected } = require('@nrwl/schematics/src/utils/cli-config-utils');
// Nx only supports running unit tests for all apps and libs.
makeSureNoAppIsSelected();
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

View File

@ -1,27 +0,0 @@
// WORKAROUND https://github.com/angular/angular/issues/18810
// This file is required to run ngc on angular libraries, to write files like
// node_modules/@angular/core/core.ngsummary.json
{
"compilerOptions": {
"lib": [
"dom",
"es2015"
],
"experimentalDecorators": true,
"types": []
},
"include": [
"node_modules/@angular/**/*",
"node_modules/@nrwl/**/*",
"node_modules/@ngrx/**/*",
],
"exclude": [
"node_modules/@angular/bazel/**",
"node_modules/@angular/router/**",
"node_modules/@angular/cli/**",
"node_modules/@angular/compiler-cli/**",
"node_modules/@angular/tsc-wrapped/**",
"node_modules/@nrwl/bazel/**",
"node_modules/@nrwl/schematics/**",
]
}

View File

@ -1,72 +0,0 @@
{
"name": "<%= utils.dasherize(name) %>",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"affected:apps": "./node_modules/.bin/nx affected:apps",
"affected:build": "./node_modules/.bin/nx affected:build",
"affected:e2e": "./node_modules/.bin/nx affected:e2e",
"affected:dep-graph": "./node_modules/.bin/nx affected:dep-graph",
"format": "./node_modules/.bin/nx format:write",
"format:write": "./node_modules/.bin/nx format:write",
"format:check": "./node_modules/.bin/nx format:check",
"update": "./node_modules/.bin/nx update",
"update:check": "./node_modules/.bin/nx update:check",
"update:skip": "./node_modules/.bin/nx update:skip",
"dep-graph": "./node_modules/.bin/nx dep-graph",
"postinstall": "ngc -p ngc.tsconfig.json"
},
"private": true,
"dependencies": {
"@angular/animations": "<%= angularVersion %>",
"@angular/bazel": "angular/bazel-builds#d09df98b39658463fdfe3567b25a20cdd7130661",
"@angular/common": "<%= angularVersion %>",
"@angular/compiler": "<%= angularVersion %>",
"@angular/core": "<%= angularVersion %>",
"@angular/forms": "<%= angularVersion %>",
"@angular/platform-browser": "<%= angularVersion %>",
"@angular/platform-browser-dynamic": "<%= angularVersion %>",
"@angular/router": "<%= angularVersion %>",
"concurrently": "3.5.1",
"core-js": "^2.4.1",
"rxjs": "<%= rxjsVersion %>",
"zone.js": "^0.8.19",
"@nrwl/nx": "<%= nxVersion %>",
"@ngrx/effects": "<%= ngrxVersion %>",
"@ngrx/router-store": "<%= ngrxVersion %>",
"@ngrx/store": "<%= ngrxVersion %>",
"@ngrx/store-devtools": "<%= ngrxVersion %>"
},
"devDependencies": {
"@angular/cli": "<%= angularCliVersion %>",
"@angular/compiler-cli": "<%= angularVersion %>",
"@nrwl/schematics": "<%= schematicsVersion %>",
"@nrwl/bazel": "<%= schematicsVersion %>",
"@angular/language-service": "<%= angularVersion %>",
"@bazel/ibazel": "^0.3.1",<% if (!minimal) { %>
"@types/jasmine": "~2.8.3",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
"codelyzer": "^4.0.1",
"jasmine-core": "~2.8.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~2.0.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "~4.1.0",
"tslint": "~5.9.1",<%
} %>
"typescript": "<%= typescriptVersion %>",
"prettier": "<%= prettierVersion %>",
"http-server": "0.11.1"
}
}

View File

@ -1,30 +0,0 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
const { getAppDirectoryUsingCliConfig } = require('@nrwl/schematics/src/utils/cli-config-utils');
const appDir = getAppDirectoryUsingCliConfig();
exports.config = {
allScriptsTimeout: 11000,
specs: [
appDir + '/e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:8080/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: appDir + '/e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

View File

@ -1,25 +0,0 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
require('zone.js/dist/zone-testing');
const getTestBed = require('@angular/core/testing').getTestBed;
const BrowserDynamicTestingModule = require('@angular/platform-browser-dynamic/testing').BrowserDynamicTestingModule;
const platformBrowserDynamicTesting = require('@angular/platform-browser-dynamic/testing').platformBrowserDynamicTesting;
// Prevent Karma from running prematurely.
__karma__.loaded = function () {};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const contextApps = require.context('./apps', true, /\.spec\.ts$/);
// And load the modules.
contextApps.keys().map(contextApps);
const contextLibs = require.context('./libs', true, /\.spec\.ts$/);
// And load the modules.
contextLibs.keys().map(contextLibs);
// Finally, start Karma to run the tests.
__karma__.start();

View File

@ -1,19 +0,0 @@
# Make TypeScript compilation fast, by keeping a few copies of the compiler
# running as daemons, and cache SourceFile AST's to reduce parse time.
build --strategy=TypeScriptCompile=worker
# Don't create bazel-* symlinks in the WORKSPACE directory.
# These require .gitignore and may scare users.
# Also, it's a workaround for https://github.com/bazelbuild/rules_typescript/issues/12
# which affects the common case of having `tsconfig.json` in the WORKSPACE directory.
#
# Instead, you should run `bazel info bazel-bin` to find out where the outputs went.
build --symlink_prefix=dist/
test --test_output=errors
# Workaround https://github.com/bazelbuild/bazel/issues/3645
# Limit Bazel to consuming 3072K of RAM
build:ci --local_resources=3072,2.0,1.0
build:ci --noshow_progress

View File

@ -1,15 +0,0 @@
{
"compileOnSave": false,
"compilerOptions": {
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"lib": [
"es2017",
"dom"
],
}
}

View File

@ -1,22 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./dist/out-tsc/spec",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"node"
]
},
"include": [
"**/*.ts"
],
"exclude": [
"**/e2e/*.ts",
"**/*.e2e-spec.ts",
"**/*.po.ts",
"node_modules",
"tmp"
]
}

View File

@ -1,102 +0,0 @@
{
"rulesDirectory": [
"node_modules/codelyzer",
"node_modules/@nrwl/schematics/src/tslint"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"forin": true,
"deprecation": {
"severity": "warn"
},
"import-blacklist": [
true,
"rxjs",
"rxjs/Rx"
],
"interface-over-type-literal": true,
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"prefer-const": true,
"radix": true,
"triple-equals": [
true,
"allow-null-check"
],
"unified-signatures": true,
"variable-name": false,
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"no-output-on-prefix": true,
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true,
"nx-enforce-module-boundaries": [
true,
{
"lazyLoad": [],
"allow": []
}
]
}
}

View File

@ -1,60 +0,0 @@
import {
apply,
branchAndMerge,
chain,
mergeWith,
Rule,
SchematicContext,
template,
Tree,
url
} from '@angular-devkit/schematics';
import { Schema } from './schema';
import { strings } from '@angular-devkit/core';
import {
NodePackageInstallTask,
RepositoryInitializerTask
} from '@angular-devkit/schematics/tasks';
import { libVersions } from '../../lib-versions';
export default function(options: Schema): Rule {
if (!/^\w+$/.test(options.name)) {
throw new Error(
`${options.name} is invalid for a bazel workspace.\n` +
'Your workspace name must contain only alphanumeric characters and underscores.'
);
}
return (host: Tree, context: SchematicContext) => {
addTasks(options, context);
const npmScope = options.npmScope ? options.npmScope : options.name;
const templateSource = apply(url('./files'), [
template({
utils: strings,
dot: '.',
...libVersions,
...(options as object),
npmScope
})
]);
return chain([branchAndMerge(chain([mergeWith(templateSource)]))])(
host,
context
);
};
}
function addTasks(options: Schema, context: SchematicContext) {
let packageTask;
if (!options.skipInstall) {
packageTask = context.addTask(
new NodePackageInstallTask(options.directory)
);
}
if (!options.skipGit) {
context.addTask(
new RepositoryInitializerTask(options.directory, options.commit),
packageTask ? [packageTask] : []
);
}
}

View File

@ -1,11 +0,0 @@
export interface Schema {
name: string;
directory: string;
npmScope?: string;
prefix?: string;
style?: string;
minimal?: boolean;
skipInstall?: boolean;
commit?: { name: string; email: string; message?: string };
skipGit?: boolean;
}

View File

@ -1,72 +0,0 @@
{
"$schema": "http://json-schema.org/schema",
"id": "workspace",
"title": "Create an empty workspace",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Workspace name"
},
"directory": {
"type": "string",
"description": "The directory name to create the app in.",
"alias": "dir"
},
"npmScope": {
"type": "string",
"description": "Npm scope for importing libs."
},
"skipInstall": {
"description": "Skip installing dependency packages.",
"type": "boolean",
"default": false
},
"skipGit": {
"description": "Skip initializing a git repository.",
"type": "boolean",
"default": false,
"alias": "sg"
},
"commit": {
"description": "Initial repository commit information.",
"default": null,
"oneOf": [
{ "type": "null" },
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"message": {
"type": "string"
}
},
"required": ["name", "email"]
}
]
},
"prefix": {
"type": "string",
"description": "The prefix to apply to generated selectors.",
"default": "app",
"alias": "p"
},
"style": {
"description": "The file extension to be used for style files.",
"type": "string",
"default": "css"
},
"minimal": {
"description": "Should create a minimal app.",
"type": "boolean",
"default": false
}
},
"required": ["name", "directory"]
}

View File

@ -1,35 +0,0 @@
# TODO: Make this private when we can import from the root index.ts
package(default_visibility = ["//visibility:public"])
load("@angular//:index.bzl", "ng_module")
load("@build_bazel_rules_typescript//:defs.bzl", "ts_library", "ts_web_test")
ng_module(
name = "<%= sourceDir %>",
srcs = glob(
["*.ts"],
exclude = ["*.spec.ts"],
),
deps = [
"@rxjs",
],
)
ts_library(
name = "test_lib",
testonly = 1,
srcs = glob(["*.spec.ts"]),
deps = [
":<%= sourceDir %>",
],
)
ts_web_test(
name = "test",
bootstrap = ["//:angular_bootstrap_scripts"],
deps = [
":test_lib",
"//:angular_bundles",
"//:angular_test_bundles",
],
)

View File

@ -1,7 +0,0 @@
import { <%= className %> } from './<%=fileName%>';
describe('<%= className %>', () => {
it('should work', () => {
expect(new <%= className %>()).toBeDefined();
});
});

View File

@ -1,2 +0,0 @@
export class <%= className %> {
}

View File

@ -1,289 +0,0 @@
import {
apply,
branchAndMerge,
chain,
mergeWith,
noop,
Rule,
template,
Tree,
url
} from '@angular-devkit/schematics';
import { insertImport } from '@schematics/angular/utility/ast-utils';
import * as path from 'path';
import * as ts from 'typescript';
import {
addGlobal,
addImportToModule,
addIncludeToTsConfig,
addReexport,
addRoute,
getAngularCliConfig,
insert
} from '../../utils/ast-utils';
import { offsetFromRoot } from '../../utils/common';
import {
names,
toClassName,
toFileName,
toPropertyName
} from '../../utils/name-utils';
import { Schema } from './schema';
import { formatFiles } from '../../utils/rules/format-files';
interface NormalizedSchema extends Schema {
name: string;
fullName: string;
fullPath: string;
tags?: string;
}
function normalizeOptions(options: Schema): NormalizedSchema {
const name = toFileName(options.name);
const fullName = options.directory
? `${toFileName(options.directory)}/${name}`
: name;
const fullPath = `libs/${fullName}/src`;
return { ...options, sourceDir: 'src', name, fullName, fullPath };
}
function addLazyLoadedRouterConfiguration(modulePath: string): Rule {
return (host: Tree) => {
const moduleSource = host.read(modulePath)!.toString('utf-8');
const sourceFile = ts.createSourceFile(
modulePath,
moduleSource,
ts.ScriptTarget.Latest,
true
);
insert(host, modulePath, [
insertImport(sourceFile, modulePath, 'RouterModule', '@angular/router'),
...addImportToModule(
sourceFile,
modulePath,
`
RouterModule.forChild([
/* {path: '', pathMatch: 'full', component: InsertYourComponentHere} */
]) `
)
]);
return host;
};
}
function addRouterConfiguration(
schema: NormalizedSchema,
indexFilePath: string,
moduleFileName: string,
modulePath: string
): Rule {
return (host: Tree) => {
const indexSource = host.read(indexFilePath)!.toString('utf-8');
const indexSourceFile = ts.createSourceFile(
indexFilePath,
indexSource,
ts.ScriptTarget.Latest,
true
);
const moduleSource = host.read(modulePath)!.toString('utf-8');
const moduleSourceFile = ts.createSourceFile(
modulePath,
moduleSource,
ts.ScriptTarget.Latest,
true
);
const constName = `${toPropertyName(schema.name)}Routes`;
insert(host, modulePath, [
insertImport(
moduleSourceFile,
modulePath,
'RouterModule, Route',
'@angular/router'
),
...addImportToModule(moduleSourceFile, modulePath, `RouterModule`),
...addGlobal(
moduleSourceFile,
modulePath,
`export const ${constName}: Route[] = [];`
)
]);
insert(host, indexFilePath, [
...addReexport(indexSourceFile, indexFilePath, moduleFileName, constName)
]);
return host;
};
}
function addLoadChildren(schema: NormalizedSchema): Rule {
return (host: Tree) => {
const json = getAngularCliConfig(host);
const moduleSource = host.read(schema.parentModule)!.toString('utf-8');
const sourceFile = ts.createSourceFile(
schema.parentModule,
moduleSource,
ts.ScriptTarget.Latest,
true
);
const loadChildren = `@${json.project.npmScope}/${toFileName(
schema.fullName
)}#${toClassName(schema.name)}Module`;
insert(host, schema.parentModule, [
...addRoute(
schema.parentModule,
sourceFile,
`{path: '${toFileName(schema.name)}', loadChildren: '${loadChildren}'}`
)
]);
const tsConfig = findClosestTsConfigApp(host, schema.parentModule);
if (tsConfig) {
const tsConfigAppSource = host.read(tsConfig)!.toString('utf-8');
const tsConfigAppFile = ts.createSourceFile(
tsConfig,
tsConfigAppSource,
ts.ScriptTarget.Latest,
true
);
const offset = offsetFromRoot(path.dirname(tsConfig));
insert(host, tsConfig, [
...addIncludeToTsConfig(
tsConfig,
tsConfigAppFile,
`\n , "${offset}libs/${schema.fullName}/index.ts"\n`
)
]);
const e2e = `${path.dirname(
path.dirname(tsConfig)
)}/e2e/tsconfig.e2e.json`;
if (host.exists(e2e)) {
const tsConfigE2ESource = host.read(e2e)!.toString('utf-8');
const tsConfigE2EFile = ts.createSourceFile(
e2e,
tsConfigE2ESource,
ts.ScriptTarget.Latest,
true
);
insert(host, e2e, [
...addIncludeToTsConfig(
e2e,
tsConfigE2EFile,
`\n , "${offset}libs/${schema.fullName}/index.ts"\n`
)
]);
}
} else {
// we should warn the user about not finding the config
}
return host;
};
}
function findClosestTsConfigApp(
host: Tree,
parentModule: string
): string | null {
const dir = path.parse(parentModule).dir;
if (host.exists(`${dir}/tsconfig.app.json`)) {
return `${dir}/tsconfig.app.json`;
} else if (dir != '') {
return findClosestTsConfigApp(host, dir);
} else {
return null;
}
}
function addChildren(schema: NormalizedSchema): Rule {
return (host: Tree) => {
const json = getAngularCliConfig(host);
const moduleSource = host.read(schema.parentModule)!.toString('utf-8');
const sourceFile = ts.createSourceFile(
schema.parentModule,
moduleSource,
ts.ScriptTarget.Latest,
true
);
const constName = `${toPropertyName(schema.name)}Routes`;
const importPath = `@${json.project.npmScope}/${toFileName(
schema.fullName
)}`;
insert(host, schema.parentModule, [
insertImport(sourceFile, schema.parentModule, constName, importPath),
...addRoute(
schema.parentModule,
sourceFile,
`{path: '${toFileName(schema.name)}', children: ${constName}}`
)
]);
return host;
};
}
function validateLibSchema(schema) {
const options = normalizeOptions(schema);
const moduleFileName = `${toFileName(options.name)}.module`;
const modulePath = `${options.fullPath}/${moduleFileName}.ts`;
const indexFile = `libs/${toFileName(options.fullName)}/index.ts`;
if (options.routing && options.nomodule) {
throw new Error(`nomodule and routing cannot be used together`);
}
if (!options.routing && options.lazy) {
throw new Error(`routing must be set`);
}
const routingRules: Array<Rule> = [
options.routing && options.lazy
? addLazyLoadedRouterConfiguration(modulePath)
: noop(),
options.routing && options.lazy && options.parentModule
? addLoadChildren(options)
: noop(),
options.routing && !options.lazy
? addRouterConfiguration(options, indexFile, moduleFileName, modulePath)
: noop(),
options.routing && !options.lazy && options.parentModule
? addChildren(options)
: noop()
];
const templateSource = apply(
url(options.nomodule ? './files' : './ngfiles'),
[
template({
...names(options.name),
dot: '.',
tmpl: '',
...(options as object)
})
]
);
return {
options,
moduleFileName,
modulePath,
indexFile,
templateSource,
routingRules
};
}
export default function(schema: Schema): Rule {
const { templateSource, routingRules } = validateLibSchema(schema);
return chain([
branchAndMerge(chain([mergeWith(templateSource)])),
...routingRules,
formatFiles(schema)
]);
}

View File

@ -1,35 +0,0 @@
# TODO: Make this private when we can import from the root index.ts
package(default_visibility = ["//visibility:public"])
load("@angular//:index.bzl", "ng_module")
load("@build_bazel_rules_typescript//:defs.bzl", "ts_library", "ts_web_test")
ng_module(
name = "<%= sourceDir %>",
srcs = glob(
["*.ts"],
exclude = ["*.spec.ts"],
),
deps = [
"@rxjs",
],
)
ts_library(
name = "test_lib",
testonly = 1,
srcs = glob(["*.spec.ts"]),
deps = [
":<%= sourceDir %>",
],
)
ts_web_test(
name = "test",
bootstrap = ["//:angular_bootstrap_scripts"],
deps = [
":test_lib",
"//:angular_bundles",
"//:angular_test_bundles",
],
)

View File

@ -1,7 +0,0 @@
import { <%= className %>Module } from './<%=fileName%>.module';
describe('<%= className %>Module', () => {
it('should work', () => {
expect(new <%= className %>Module()).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
imports: [CommonModule]
})
export class <%= className %>Module {
}

View File

@ -1,15 +0,0 @@
export interface Schema {
name: string;
skipFormat: boolean;
directory?: string;
sourceDir?: string;
nomodule: boolean;
spec?: boolean;
flat?: boolean;
commonModule?: boolean;
routing?: boolean;
lazy?: boolean;
parentModule?: string;
}

View File

@ -1,41 +0,0 @@
{
"$schema": "http://json-schema.org/schema",
"id": "library",
"title": "Create a library",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Library name"
},
"directory": {
"type": "string",
"description": "A directory where the app is placed"
},
"nomodule": {
"type": "boolean",
"default": false,
"description": "Generate a simple TS library when set to true."
},
"routing": {
"type": "boolean",
"default": false,
"description": "Add router configuration. See lazy for more information."
},
"skipFormat": {
"description": "Skip formatting files",
"type": "boolean",
"default": false
},
"lazy": {
"type": "boolean",
"default": false,
"description": "Add RouterModule.forChild when set to true, and a simple array of routes when set to false."
},
"parentModule": {
"type": "string",
"description": "Update the router configuration of the parent module using loadChildren or children, depending on what `lazy` is set to."
}
},
"required": ["name"]
}

View File

@ -1,24 +0,0 @@
package(default_visibility = ["//visibility:public"])
load("@angular//:index.bzl", "ng_module")
load("@build_bazel_rules_typescript//:defs.bzl", "ts_library")
ng_module(
name = "<%= dasherize(name) %>",
srcs = glob(
["*.ts"],
exclude = ["*.spec.ts"],
),
deps = [
"@rxjs",
],
)
ts_library(
name = "test_lib",
testonly = 1,
srcs = glob(["*.spec.ts"]),
deps = [
":<%= dasherize(name) %>",
],
)

View File

@ -1,43 +0,0 @@
import { normalize, strings } from '@angular-devkit/core';
import {
apply,
branchAndMerge,
chain,
externalSchematic,
mergeWith,
move,
Rule,
SchematicContext,
SchematicsException,
template,
Tree,
url,
TaskConfigurationGenerator,
TaskConfiguration
} from '@angular-devkit/schematics';
import { Schema } from './schema';
import { formatFiles } from '../../utils/rules/format-files';
export default function(schema: Schema): Rule {
schema.path = schema.path ? normalize(schema.path) : schema.path;
const sourceDir = schema.sourceDir;
if (!sourceDir) {
throw new SchematicsException(`sourceDir option is required.`);
}
const templateSource = apply(url('./files'), [
template({
...strings,
'if-flat': (s: string) => (schema.flat ? '' : s),
...schema
}),
move(sourceDir)
]);
return chain([
branchAndMerge(chain([mergeWith(templateSource)])),
externalSchematic('@schematics/angular', 'module', schema),
formatFiles(schema)
]);
}

View File

@ -1,55 +0,0 @@
/**
* @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
*/
export interface Schema {
/**
* The name of the module.
*/
name: string;
/**
* Skip formatting of files
*/
skipFormat: boolean;
/**
* The path to create the module.
*/
path?: string;
/**
* The path of the source directory.
*/
sourceDir?: string;
/**
* The root of the application.
*/
appRoot?: string;
/**
* Generates a routing module.
*/
routing?: boolean;
/**
* The scope for the generated routing.
*/
routingScope?: 'Child' | 'Root';
/**
* Specifies if a spec file is generated.
*/
spec?: boolean;
/**
* Flag to indicate if a dir is created.
*/
flat?: boolean;
/**
* Flag to control whether the CommonModule is imported.
*/
commonModule?: boolean;
/**
* Allows specification of the declaring module.
*/
module?: string;
}

View File

@ -1,70 +0,0 @@
{
"$schema": "http://json-schema.org/schema",
"id": "module",
"title": "NX Module Options Schema",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the module."
},
"path": {
"type": "string",
"format": "path",
"description": "The path to create the module.",
"default": "app",
"visible": false
},
"sourceDir": {
"type": "string",
"format": "path",
"description": "The path of the source directory.",
"default": "src",
"visible": false
},
"appRoot": {
"type": "string",
"format": "path",
"description": "The root of the application.",
"visible": false
},
"routing": {
"type": "boolean",
"description": "Generates a routing module.",
"default": false
},
"routingScope": {
"enum": ["Child", "Root"],
"type": "string",
"description": "The scope for the generated routing.",
"default": "Child"
},
"spec": {
"type": "boolean",
"description": "Specifies if a spec file is generated.",
"default": true
},
"flat": {
"type": "boolean",
"description": "Flag to indicate if a dir is created.",
"default": false
},
"commonModule": {
"type": "boolean",
"description": "Flag to control whether the CommonModule is imported.",
"default": true,
"visible": false
},
"skipFormat": {
"description": "Skip formatting files",
"type": "boolean",
"default": false
},
"module": {
"type": "string",
"description": "Allows specification of the declaring module.",
"alias": "m"
}
},
"required": ["name"]
}

View File

@ -1,36 +0,0 @@
export const angularCliVersion = '1.7.1';
export const angularVersion = '5.2.7';
export const angularJsVersion = '1.6.6';
export const ngrxVersion = '5.1.0';
export const ngrxStoreFreezeVersion = '^0.2.1';
export const routerStoreVersion = '5.0.1';
export const nxVersion = '*';
export const schematicsVersion = '*';
export const angularCliSchema =
'./node_modules/@nrwl/schematics/src/schema.json';
export const latestMigration = '20180313-add-tags';
export const prettierVersion = '1.10.2';
export const typescriptVersion = '2.6.2';
export const rxjsVersion = '^5.5.6';
export const devKitCoreVersion = '^0.0.29';
export const devKitSchematicsVersion = '0.0.52';
export const schematicsAngularVersion = '0.1.17';
export const libVersions = {
angularVersion,
angularCliVersion,
angularJsVersion,
ngrxVersion,
ngrxStoreFreezeVersion,
nxVersion,
schematicsVersion,
prettierVersion,
angularCliSchema,
latestMigration,
typescriptVersion,
rxjsVersion,
devKitCoreVersion,
devKitSchematicsVersion,
schematicsAngularVersion,
routerStoreVersion
};

View File

@ -1,686 +0,0 @@
{
"$schema": "http://json-schema.org/schema",
"id": "https://github.com/nrwl/nx/blob/master/packages/bazel/src/schema.json",
"title": "Nrwl Nx Config Schema",
"type": "object",
"properties": {
"$schema": {
"type": "string"
},
"project": {
"description": "The global configuration of the project.",
"type": "object",
"properties": {
"name": {
"description": "The name of the project.",
"type": "string"
},
"latestMigration": {
"description": "Npm scope for importing libs.",
"type": "string"
},
"ejected": {
"description": "Whether or not this project was ejected.",
"type": "boolean",
"default": false
}
},
"additionalProperties": false
},
"apps": {
"description": "Properties of the different applications in this project.",
"type": "array",
"items": {
"type": "object",
"properties": {
"tags": {
"type": "array",
"description": "Project tags",
"items": {
"type": "string"
},
"default": []
},
"name": {
"type": "string",
"description": "Name of the app."
},
"appRoot": {
"type": "string",
"description": "Directory where app files are placed.",
"default": "app"
},
"appShell": {
"type": "object",
"description": "AppShell configuration.",
"properties": {
"app": {
"type": "string",
"description": "Index or name of the related AppShell app."
},
"route": {
"type": "string",
"description": "Default AppShell route to render."
}
}
},
"root": {
"type": "string",
"description": "The root directory of the app."
},
"outDir": {
"type": "string",
"default": "dist/",
"description": "The output directory for build results."
},
"assets": {
"type": "array",
"description": "List of application assets.",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"glob": {
"type": "string",
"default": "",
"description": "The pattern to match."
},
"input": {
"type": "string",
"default": "",
"description": "The dir to search within."
},
"output": {
"type": "string",
"default": "",
"description": "The output path (relative to the outDir)."
},
"allowOutsideOutDir": {
"type": "boolean",
"description": "Allow assets to be copied outside the outDir.",
"default": false
}
},
"additionalProperties": false
}
]
},
"default": []
},
"budgets": {
"type": "array",
"description": "Threshold definitions for bundle sizes.",
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"bundle",
"initial",
"allScript",
"all",
"anyScript",
"any"
],
"description": "The type of budget"
},
"name": {
"type": "string",
"description": "The name of the bundle"
},
"baseline": {
"type": "string",
"description": "The baseline size for comparison."
},
"maximumWarning": {
"type": "string",
"description": "The maximum threshold for warning relative to the baseline."
},
"maximumError": {
"type": "string",
"description": "The maximum threshold for error relative to the baseline."
},
"minimumWarning": {
"type": "string",
"description": "The minimum threshold for warning relative to the baseline."
},
"minimumError": {
"type": "string",
"description": "The minimum threshold for error relative to the baseline."
},
"warning": {
"type": "string",
"description": "The threshold for warning relative to the baseline (min & max)."
},
"error": {
"type": "string",
"description": "The threshold for error relative to the baseline (min & max)."
}
}
},
"default": []
},
"deployUrl": {
"type": "string",
"description": "URL where files will be deployed."
},
"baseHref": {
"type": "string",
"description": "Base url for the application being built."
},
"platform": {
"type": "string",
"enum": ["browser", "server"],
"default": "browser",
"description": "The runtime platform of the app."
},
"index": {
"type": "string",
"default": "index.html",
"description": "The name of the start HTML file."
},
"main": {
"type": "string",
"description": "The name of the main entry-point file."
},
"polyfills": {
"type": "string",
"description": "The name of the polyfills file."
},
"test": {
"type": "string",
"description": "The name of the test entry-point file."
},
"tsconfig": {
"type": "string",
"default": "tsconfig.app.json",
"description": "The name of the TypeScript configuration file."
},
"testTsconfig": {
"type": "string",
"description": "The name of the TypeScript configuration file for unit tests."
},
"prefix": {
"type": "string",
"description": "The prefix to apply to generated selectors."
},
"serviceWorker": {
"description": "Experimental support for a service worker from @angular/service-worker.",
"type": "boolean",
"default": false
},
"styles": {
"description": "Global styles to be included in the build.",
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"input": {
"type": "string"
}
},
"additionalProperties": true
}
]
},
"additionalProperties": false
},
"stylePreprocessorOptions": {
"description": "Options to pass to style preprocessors",
"type": "object",
"properties": {
"includePaths": {
"description": "Paths to include. Paths will be resolved to project root.",
"type": "array",
"items": {
"type": "string"
},
"default": []
}
},
"additionalProperties": false
},
"scripts": {
"description": "Global scripts to be included in the build.",
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"input": {
"type": "string"
}
},
"additionalProperties": true,
"required": ["input"]
}
]
},
"additionalProperties": false
},
"environmentSource": {
"description": "Source file for environment config.",
"type": "string"
},
"environments": {
"description": "Name and corresponding file for environment config.",
"type": "object",
"additionalProperties": true
}
},
"additionalProperties": false
},
"additionalProperties": false
},
"e2e": {
"type": "object",
"description": "Configuration for end-to-end tests.",
"properties": {
"protractor": {
"type": "object",
"properties": {
"config": {
"description": "Path to the config file.",
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"lint": {
"description": "Properties to be passed to TSLint.",
"type": "array",
"items": {
"type": "object",
"properties": {
"files": {
"description": "File glob(s) to lint.",
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"default": []
},
"project": {
"description": "Location of the tsconfig.json project file. Will also use as files to lint if 'files' property not present.",
"type": "string"
},
"tslintConfig": {
"description": "Location of the tslint.json configuration.",
"type": "string"
},
"exclude": {
"description": "File glob(s) to ignore.",
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"default": []
}
},
"required": ["project"],
"additionalProperties": false
}
},
"test": {
"description": "Configuration for unit tests.",
"type": "object",
"properties": {
"karma": {
"type": "object",
"properties": {
"config": {
"description": "Path to the karma config file.",
"type": "string"
}
},
"additionalProperties": false
},
"codeCoverage": {
"type": "object",
"properties": {
"exclude": {
"description": "Globs to exclude from code coverage.",
"type": "array",
"items": {
"type": "string"
},
"default": []
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"defaults": {
"description": "Specify the default values for generating.",
"type": "object",
"properties": {
"styleExt": {
"description": "The file extension to be used for style files.",
"type": "string"
},
"poll": {
"description": "How often to check for file updates.",
"type": "number"
},
"lintFix": {
"description": "Use lint to fix files after generation",
"type": "boolean",
"default": false
},
"class": {
"description": "Options for generating a class.",
"type": "object",
"properties": {
"spec": {
"description": "Specifies if a spec file is generated.",
"type": "boolean",
"default": false
}
}
},
"component": {
"description": "Options for generating a component.",
"type": "object",
"properties": {
"flat": {
"description": "Flag to indicate if a dir is created.",
"type": "boolean",
"default": true
},
"spec": {
"description": "Specifies if a spec file is generated.",
"type": "boolean",
"default": true
},
"inlineStyle": {
"description": "Specifies if the style will be in the ts file.",
"type": "boolean",
"default": false
},
"inlineTemplate": {
"description": "Specifies if the template will be in the ts file.",
"type": "boolean",
"default": false
},
"viewEncapsulation": {
"description": "Specifies the view encapsulation strategy.",
"enum": ["Emulated", "Native", "None"],
"type": "string"
},
"changeDetection": {
"description": "Specifies the change detection strategy.",
"enum": ["Default", "OnPush"],
"type": "string"
}
}
},
"directive": {
"description": "Options for generating a directive.",
"type": "object",
"properties": {
"flat": {
"description": "Flag to indicate if a dir is created.",
"type": "boolean",
"default": true
},
"spec": {
"description": "Specifies if a spec file is generated.",
"type": "boolean",
"default": true
}
}
},
"guard": {
"description": "Options for generating a guard.",
"type": "object",
"properties": {
"flat": {
"description": "Flag to indicate if a dir is created.",
"type": "boolean",
"default": true
},
"spec": {
"description": "Specifies if a spec file is generated.",
"type": "boolean",
"default": true
}
}
},
"interface": {
"description": "Options for generating an interface.",
"type": "object",
"properties": {
"prefix": {
"description": "Prefix to apply to interface names. (i.e. I)",
"type": "string",
"default": ""
}
}
},
"module": {
"description": "Options for generating a module.",
"type": "object",
"properties": {
"flat": {
"description": "Flag to indicate if a dir is created.",
"type": "boolean",
"default": false
},
"spec": {
"description": "Specifies if a spec file is generated.",
"type": "boolean",
"default": false
}
}
},
"pipe": {
"description": "Options for generating a pipe.",
"type": "object",
"properties": {
"flat": {
"description": "Flag to indicate if a dir is created.",
"type": "boolean",
"default": true
},
"spec": {
"description": "Specifies if a spec file is generated.",
"type": "boolean",
"default": true
}
}
},
"service": {
"description": "Options for generating a service.",
"type": "object",
"properties": {
"flat": {
"description": "Flag to indicate if a dir is created.",
"type": "boolean",
"default": true
},
"spec": {
"description": "Specifies if a spec file is generated.",
"type": "boolean",
"default": true
}
}
},
"build": {
"description": "Properties to be passed to the build command.",
"type": "object",
"properties": {
"sourcemaps": {
"description": "Output sourcemaps.",
"type": "boolean"
},
"baseHref": {
"description": "Base url for the application being built.",
"type": "string"
},
"progress": {
"description": "The ssl key used by the server.",
"type": "boolean"
},
"poll": {
"description": "Enable and define the file watching poll time period (milliseconds).",
"type": "number"
},
"deleteOutputPath": {
"description": "Delete output path before build.",
"type": "boolean",
"default": true
},
"preserveSymlinks": {
"description": "Do not use the real path when resolving modules.",
"type": "boolean",
"default": false
},
"showCircularDependencies": {
"description": "Show circular dependency warnings on builds.",
"type": "boolean",
"default": true
},
"commonChunk": {
"description": "Use a separate bundle containing code used across multiple bundles.",
"type": "boolean",
"default": true
},
"namedChunks": {
"description": "Use file name for lazy loaded chunks.",
"type": "boolean"
}
}
},
"serve": {
"description": "Properties to be passed to the serve command.",
"type": "object",
"properties": {
"port": {
"description": "The port the application will be served on.",
"type": "number",
"default": 4200
},
"host": {
"description": "The host the application will be served on.",
"type": "string",
"default": "localhost"
},
"ssl": {
"description": "Enables ssl for the application.",
"type": "boolean",
"default": false
},
"sslKey": {
"description": "The ssl key used by the server.",
"type": "string",
"default": "ssl/server.key"
},
"sslCert": {
"description": "The ssl certificate used by the server.",
"type": "string",
"default": "ssl/server.crt"
},
"proxyConfig": {
"description": "Proxy configuration file.",
"type": "string"
}
}
},
"schematics": {
"description": "Properties about schematics.",
"type": "object",
"properties": {
"collection": {
"description": "The schematics collection to use.",
"type": "string",
"default": "@schematics/angular"
},
"newApp": {
"description": "The new app schematic.",
"type": "string",
"default": "application"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"packageManager": {
"description": "Specify which package manager tool to use.",
"enum": ["npm", "cnpm", "yarn", "default"],
"default": "default",
"type": "string"
},
"warnings": {
"description": "Allow people to disable console warnings.",
"type": "object",
"properties": {
"hmrWarning": {
"description": "Show a warning when the user enabled the --hmr option.",
"type": "boolean",
"default": true
},
"nodeDeprecation": {
"description": "Show a warning when the node version is incompatible.",
"type": "boolean",
"default": true
},
"packageDeprecation": {
"description": "Show a warning when the user installed angular-cli.",
"type": "boolean",
"default": true
},
"versionMismatch": {
"description": "Show a warning when the global version is newer than the local one.",
"type": "boolean",
"default": true
},
"typescriptMismatch": {
"description": "Show a warning when the TypeScript version is incompatible",
"type": "boolean",
"default": true
},
"servePathDefault": {
"description": "Show a warning when deploy-url/base-href use unsupported serve path values.",
"type": "boolean",
"default": true
}
}
}
},
"additionalProperties": false
}

View File

@ -1,671 +0,0 @@
/**
* @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 { Tree, Rule } from '@angular-devkit/schematics';
import {
findNodes,
getDecoratorMetadata,
getSourceNodes
} from '@schematics/angular/utility/ast-utils';
import {
Change,
InsertChange,
NoopChange,
RemoveChange
} from '@schematics/angular/utility/change';
import * as ts from 'typescript';
import { toFileName } from './name-utils';
import * as path from 'path';
import { serializeJson } from '../utils/fileutils';
// This should be moved to @schematics/angular once it allows to pass custom expressions as providers
function _addSymbolToNgModuleMetadata(
source: ts.SourceFile,
ngModulePath: string,
metadataField: string,
expression: string
): Change[] {
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
let node: any = nodes[0]; // tslint:disable-line:no-any
// Find the decorator declaration.
if (!node) {
return [];
}
// Get all the children property assignment of object literals.
const matchingProperties: ts.ObjectLiteralElement[] = (node as ts.ObjectLiteralExpression).properties
.filter(prop => prop.kind == ts.SyntaxKind.PropertyAssignment)
// Filter out every fields that's not "metadataField". Also handles string literals
// (but not expressions).
.filter((prop: ts.PropertyAssignment) => {
const name = prop.name;
switch (name.kind) {
case ts.SyntaxKind.Identifier:
return (name as ts.Identifier).getText(source) == metadataField;
case ts.SyntaxKind.StringLiteral:
return (name as ts.StringLiteral).text == metadataField;
}
return false;
});
// Get the last node of the array literal.
if (!matchingProperties) {
return [];
}
if (matchingProperties.length == 0) {
// We haven't found the field in the metadata declaration. Insert a new field.
const expr = node as ts.ObjectLiteralExpression;
let position: number;
let toInsert: string;
if (expr.properties.length == 0) {
position = expr.getEnd() - 1;
toInsert = ` ${metadataField}: [${expression}]\n`;
} else {
node = expr.properties[expr.properties.length - 1];
position = node.getEnd();
// Get the indentation of the last element, if any.
const text = node.getFullText(source);
if (text.match('^\r?\r?\n')) {
toInsert = `,${
text.match(/^\r?\n\s+/)[0]
}${metadataField}: [${expression}]`;
} else {
toInsert = `, ${metadataField}: [${expression}]`;
}
}
const newMetadataProperty = new InsertChange(
ngModulePath,
position,
toInsert
);
return [newMetadataProperty];
}
const assignment = matchingProperties[0] as ts.PropertyAssignment;
// If it's not an array, nothing we can do really.
if (assignment.initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression) {
return [];
}
const arrLiteral = assignment.initializer as ts.ArrayLiteralExpression;
if (arrLiteral.elements.length == 0) {
// Forward the property.
node = arrLiteral;
} else {
node = arrLiteral.elements;
}
if (!node) {
console.log(
'No app module found. Please add your new class to your component.'
);
return [];
}
if (Array.isArray(node)) {
const nodeArray = (node as {}) as Array<ts.Node>;
const symbolsArray = nodeArray.map(node => node.getText());
if (symbolsArray.includes(expression)) {
return [];
}
node = node[node.length - 1];
}
let toInsert: string;
let position = node.getEnd();
if (node.kind == ts.SyntaxKind.ObjectLiteralExpression) {
// We haven't found the field in the metadata declaration. Insert a new
// field.
const expr = node as ts.ObjectLiteralExpression;
if (expr.properties.length == 0) {
position = expr.getEnd() - 1;
toInsert = ` ${metadataField}: [${expression}]\n`;
} else {
node = expr.properties[expr.properties.length - 1];
position = node.getEnd();
// Get the indentation of the last element, if any.
const text = node.getFullText(source);
if (text.match('^\r?\r?\n')) {
toInsert = `,${
text.match(/^\r?\n\s+/)[0]
}${metadataField}: [${expression}]`;
} else {
toInsert = `, ${metadataField}: [${expression}]`;
}
}
} else if (node.kind == ts.SyntaxKind.ArrayLiteralExpression) {
// We found the field but it's empty. Insert it just before the `]`.
position--;
toInsert = `${expression}`;
} else {
// Get the indentation of the last element, if any.
const text = node.getFullText(source);
if (text.match(/^\r?\n/)) {
toInsert = `,${text.match(/^\r?\n(\r?)\s+/)[0]}${expression}`;
} else {
toInsert = `, ${expression}`;
}
}
const insert = new InsertChange(ngModulePath, position, toInsert);
return [insert];
}
export function addParameterToConstructor(
source: ts.SourceFile,
modulePath: string,
opts: { className: string; param: string }
): Change[] {
const clazz = findClass(source, opts.className);
const constructor = clazz.members.filter(
m => m.kind === ts.SyntaxKind.Constructor
)[0];
if (constructor) {
throw new Error('Should be tested');
} else {
const methodHeader = `constructor(${opts.param})`;
return addMethod(source, modulePath, {
className: opts.className,
methodHeader,
body: null
});
}
}
export function addMethod(
source: ts.SourceFile,
modulePath: string,
opts: { className: string; methodHeader: string; body: string }
): Change[] {
const clazz = findClass(source, opts.className);
const body = opts.body
? `
${opts.methodHeader} {
${offset(opts.body, 1, false)}
}
`
: `
${opts.methodHeader} {}
`;
return [new InsertChange(modulePath, clazz.end - 1, offset(body, 1, true))];
}
export function removeFromNgModule(
source: ts.SourceFile,
modulePath: string,
property: string
): Change[] {
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
let node: any = nodes[0]; // tslint:disable-line:no-any
// Find the decorator declaration.
if (!node) {
return [];
}
// Get all the children property assignment of object literals.
const matchingProperty = getMatchingProperty(source, property);
if (matchingProperty) {
return [
new RemoveChange(
modulePath,
matchingProperty.pos,
matchingProperty.getFullText(source)
)
];
} else {
return [];
}
}
function findClass(
source: ts.SourceFile,
className: string
): ts.ClassDeclaration {
const nodes = getSourceNodes(source);
const clazz = <any>(
nodes.filter(
n =>
n.kind === ts.SyntaxKind.ClassDeclaration &&
(<any>n).name.text === className
)[0]
);
if (!clazz) {
throw new Error(`Cannot find class '${className}'`);
}
return clazz;
}
export function offset(
text: string,
numberOfTabs: number,
wrap: boolean
): string {
const lines = text
.trim()
.split('\n')
.map(line => {
let tabs = '';
for (let c = 0; c < numberOfTabs; ++c) {
tabs += ' ';
}
return `${tabs}${line}`;
})
.join('\n');
return wrap ? `\n${lines}\n` : lines;
}
export function addImportToModule(
source: ts.SourceFile,
modulePath: string,
symbolName: string
): Change[] {
return _addSymbolToNgModuleMetadata(
source,
modulePath,
'imports',
symbolName
);
}
export function addImportToTestBed(
source: ts.SourceFile,
specPath: string,
symbolName: string
): Change[] {
const allCalls: ts.CallExpression[] = <any>(
findNodes(source, ts.SyntaxKind.CallExpression)
);
const configureTestingModuleObjectLiterals = allCalls
.filter(c => c.expression.kind === ts.SyntaxKind.PropertyAccessExpression)
.filter(
(c: any) => c.expression.name.getText(source) === 'configureTestingModule'
)
.map(c =>
c.arguments[0].kind === ts.SyntaxKind.ObjectLiteralExpression
? c.arguments[0]
: null
);
if (configureTestingModuleObjectLiterals.length > 0) {
const startPosition = configureTestingModuleObjectLiterals[0]
.getFirstToken(source)
.getEnd();
return [
new InsertChange(specPath, startPosition, `imports: [${symbolName}], `)
];
} else {
return [];
}
}
export function addReexport(
source: ts.SourceFile,
modulePath: string,
reexportedFileName: string,
token: string
): Change[] {
const allExports = findNodes(source, ts.SyntaxKind.ExportDeclaration);
if (allExports.length > 0) {
const m = allExports.filter(
(e: ts.ExportDeclaration) =>
e.moduleSpecifier.getText(source).indexOf(reexportedFileName) > -1
);
if (m.length > 0) {
const mm: ts.ExportDeclaration = <any>m[0];
return [
new InsertChange(modulePath, mm.exportClause.end - 1, `, ${token} `)
];
}
}
return [];
}
export function getBootstrapComponent(
source: ts.SourceFile,
moduleClassName: string
): string {
const bootstrap = getMatchingProperty(source, 'bootstrap');
if (!bootstrap) {
throw new Error(`Cannot find bootstrap components in '${moduleClassName}'`);
}
const c = bootstrap.getChildren();
const nodes = c[c.length - 1].getChildren();
const bootstrapComponent = nodes.slice(1, nodes.length - 1)[0];
if (!bootstrapComponent) {
throw new Error(`Cannot find bootstrap components in '${moduleClassName}'`);
}
return bootstrapComponent.getText();
}
function getMatchingObjectLiteralElement(
node: any,
source: ts.SourceFile,
property: string
) {
return (
(node as ts.ObjectLiteralExpression).properties
.filter(prop => prop.kind == ts.SyntaxKind.PropertyAssignment)
// Filter out every fields that's not "metadataField". Also handles string literals
// (but not expressions).
.filter((prop: ts.PropertyAssignment) => {
const name = prop.name;
switch (name.kind) {
case ts.SyntaxKind.Identifier:
return (name as ts.Identifier).getText(source) === property;
case ts.SyntaxKind.StringLiteral:
return (name as ts.StringLiteral).text === property;
}
return false;
})[0]
);
}
function getMatchingProperty(
source: ts.SourceFile,
property: string
): ts.ObjectLiteralElement {
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
let node: any = nodes[0]; // tslint:disable-line:no-any
if (!node) return null;
// Get all the children property assignment of object literals.
return getMatchingObjectLiteralElement(node, source, property);
}
export function addRoute(
ngModulePath: string,
source: ts.SourceFile,
route: string
): Change[] {
const routes = getListOfRoutes(source);
if (!routes) return [];
if (routes.hasTrailingComma || routes.length === 0) {
return [new InsertChange(ngModulePath, routes.end, route)];
} else {
return [new InsertChange(ngModulePath, routes.end, `, ${route}`)];
}
}
export function addIncludeToTsConfig(
tsConfigPath: string,
source: ts.SourceFile,
include: string
): Change[] {
const includeKeywordPos = source.text.indexOf('"include":');
if (includeKeywordPos > -1) {
const includeArrayEndPos = source.text.indexOf(']', includeKeywordPos);
return [new InsertChange(tsConfigPath, includeArrayEndPos, include)];
} else {
return [];
}
}
function getListOfRoutes(source: ts.SourceFile): ts.NodeArray<ts.Expression> {
const imports: any = getMatchingProperty(source, 'imports');
if (imports.initializer.kind === ts.SyntaxKind.ArrayLiteralExpression) {
const a = imports.initializer as ts.ArrayLiteralExpression;
for (let e of a.elements) {
if (e.kind === 181) {
const ee = e as ts.CallExpression;
const text = ee.expression.getText(source);
if (
(text === 'RouterModule.forRoot' ||
text === 'RouterModule.forChild') &&
ee.arguments.length > 0
) {
const routes = ee.arguments[0];
if (routes.kind === ts.SyntaxKind.ArrayLiteralExpression) {
return (routes as ts.ArrayLiteralExpression).elements;
}
}
}
}
}
return null;
}
export function getImport(
source: ts.SourceFile,
predicate: (a: any) => boolean
): { moduleSpec: string; bindings: string[] }[] {
const allImports = findNodes(source, ts.SyntaxKind.ImportDeclaration);
const matching = allImports.filter((i: ts.ImportDeclaration) =>
predicate(i.moduleSpecifier.getText())
);
return matching.map((i: ts.ImportDeclaration) => {
const moduleSpec = i.moduleSpecifier
.getText()
.substring(1, i.moduleSpecifier.getText().length - 1);
const t = i.importClause.namedBindings.getText();
const bindings = t
.replace('{', '')
.replace('}', '')
.split(',')
.map(q => q.trim());
return { moduleSpec, bindings };
});
}
export function addProviderToModule(
source: ts.SourceFile,
modulePath: string,
symbolName: string
): Change[] {
return _addSymbolToNgModuleMetadata(
source,
modulePath,
'providers',
symbolName
);
}
export function addDeclarationToModule(
source: ts.SourceFile,
modulePath: string,
symbolName: string
): Change[] {
return _addSymbolToNgModuleMetadata(
source,
modulePath,
'declarations',
symbolName
);
}
export function addEntryComponents(
source: ts.SourceFile,
modulePath: string,
symbolName: string
): Change[] {
return _addSymbolToNgModuleMetadata(
source,
modulePath,
'entryComponents',
symbolName
);
}
export function addGlobal(
source: ts.SourceFile,
modulePath: string,
statement: string
): Change[] {
const allImports = findNodes(source, ts.SyntaxKind.ImportDeclaration);
if (allImports.length > 0) {
const lastImport = allImports[allImports.length - 1];
return [
new InsertChange(modulePath, lastImport.end + 1, `\n${statement}\n`)
];
} else {
return [new InsertChange(modulePath, 0, `${statement}\n`)];
}
}
export function insert(host: Tree, modulePath: string, changes: Change[]) {
const recorder = host.beginUpdate(modulePath);
for (const change of changes) {
if (change instanceof InsertChange) {
recorder.insertLeft(change.pos, change.toAdd);
} else if (change instanceof RemoveChange) {
recorder.remove((<any>change).pos - 1, (<any>change).toRemove.length + 1);
} else if (change instanceof NoopChange) {
// do nothing
} else {
throw new Error(`Unexpected Change '${change}'`);
}
}
host.commitUpdate(recorder);
}
/**
* This method is specifically for reading JSON files in a Tree
* @param host The host tree
* @param path The path to the JSON file
* @returns The JSON data in the file.
*/
export function readJsonInTree<T = any>(host: Tree, path: string): T {
if (!host.exists(path)) {
throw new Error(`Cannot find ${path}`);
}
return JSON.parse(host.read(path)!.toString('utf-8'));
}
/**
* This method is specifically for updating JSON in a Tree
* @param path Path of JSON file in the Tree
* @param callback Manipulation of the JSON data
* @returns A rule which updates a JSON file file in a Tree
*/
export function updateJsonInTree<T = any, O = T>(
path: string,
callback: (json: T) => O
): Rule {
return (host: Tree): Tree => {
host.overwrite(path, serializeJson(callback(readJsonInTree(host, path))));
return host;
};
}
/**
* This method is specifically for getting the .angular-cli.json data from a Tree
* @param host The host tree
*/
export function getAngularCliConfig(host: Tree) {
return readJsonInTree(host, '.angular-cli.json');
}
export function getAppConfig(host: Tree, name: string): any {
const angularCliJson = getAngularCliConfig(host);
const apps = angularCliJson.apps;
if (!apps || apps.length === 0) {
throw new Error(`Cannot find app '${name}'`);
}
if (name) {
const appConfig = apps.filter(a => a.name === name)[0];
if (!appConfig) {
throw new Error(`Cannot find app '${name}'`);
} else {
return appConfig;
}
}
return apps[0];
}
export function readBootstrapInfo(
host: Tree,
app: string
): {
moduleSpec: string;
modulePath: string;
mainPath: string;
moduleClassName: string;
moduleSource: ts.SourceFile;
bootstrapComponentClassName: string;
bootstrapComponentFileName: string;
} {
const config = getAppConfig(host, app);
const mainPath = path.join(config.root, config.main);
if (!host.exists(mainPath)) {
throw new Error('Main file cannot be located');
}
const mainSource = host.read(mainPath)!.toString('utf-8');
const main = ts.createSourceFile(
mainPath,
mainSource,
ts.ScriptTarget.Latest,
true
);
const moduleImports = getImport(
main,
(s: string) => s.indexOf('.module') > -1
);
if (moduleImports.length !== 1) {
throw new Error(`main.ts can only import a single module`);
}
const moduleImport = moduleImports[0];
const moduleClassName = moduleImport.bindings.filter(b =>
b.endsWith('Module')
)[0];
const modulePath = `${path.join(
path.dirname(mainPath),
moduleImport.moduleSpec
)}.ts`;
if (!host.exists(modulePath)) {
throw new Error(`Cannot find '${modulePath}'`);
}
const moduleSourceText = host.read(modulePath)!.toString('utf-8');
const moduleSource = ts.createSourceFile(
modulePath,
moduleSourceText,
ts.ScriptTarget.Latest,
true
);
const bootstrapComponentClassName = getBootstrapComponent(
moduleSource,
moduleClassName
);
const bootstrapComponentFileName = `./${path.join(
path.dirname(moduleImport.moduleSpec),
`${toFileName(
bootstrapComponentClassName.substring(
0,
bootstrapComponentClassName.length - 9
)
)}.component`
)}`;
return {
moduleSpec: moduleImport.moduleSpec,
mainPath,
modulePath,
moduleSource,
moduleClassName,
bootstrapComponentClassName,
bootstrapComponentFileName
};
}

View File

@ -1,43 +0,0 @@
import * as yargsParser from 'yargs-parser';
import { readJsonFile } from './fileutils';
export function getAppDirectoryUsingCliConfig() {
const cli = readJsonFile(process.cwd() + '/.angular-cli.json');
const appName = getAppName();
if (appName) {
const app = cli.apps.find(a => a.name === appName);
if (!app) {
console.error(`Cannot find app '${appName}'.`);
process.exit(1);
} else if (app.root.startsWith('libs')) {
console.error(`Cannot run e2e tests for a library.`);
process.exit(1);
} else {
return `apps/${appName}`;
}
} else {
console.error(`Please provide the app name using --app or -a.`);
process.exit(1);
}
}
export function makeSureNoAppIsSelected() {
if (getAppName()) {
console.error('Nx only supports running unit tests for all apps and libs.');
console.error('You cannot use -a or --app.');
console.error('Use fdescribe or fit to select a subset of tests to run.');
process.exit(1);
}
}
function getAppName() {
return yargsParser(process.argv, {
alias: {
app: ['a']
},
string: ['app']
}).app;
}

View File

@ -1,44 +0,0 @@
import { Options } from 'prettier';
import * as cosmiconfig from 'cosmiconfig';
export function offsetFromRoot(fullPathToSourceDir: string): string {
const parts = fullPathToSourceDir.split('/');
let offset = '';
for (let i = 0; i < parts.length; ++i) {
offset += '../';
}
return offset;
}
export const DEFAULT_NRWL_PRETTIER_CONFIG = {
singleQuote: true
};
export interface ExistingPrettierConfig {
sourceFilepath: string;
config: Options;
}
export function resolveUserExistingPrettierConfig(): Promise<ExistingPrettierConfig | null> {
const explorer = cosmiconfig('prettier', {
sync: true,
cache: false,
rcExtensions: true,
stopDir: process.cwd(),
transform: result => {
if (result && result.config) {
delete result.config.$schema;
}
return result;
}
});
return Promise.resolve(explorer.load(process.cwd())).then(result => {
if (!result) {
return null;
}
return {
sourceFilepath: result.filepath,
config: result.config
};
});
}

View File

@ -1,41 +0,0 @@
import { addApp } from './fileutils';
describe('fileutils', () => {
describe('sortApps', () => {
it('should handle undefined', () => {
expect(addApp(undefined, { name: 'a' })).toEqual([{ name: 'a' }]);
});
it('should handle an empty array', () => {
expect(addApp([], { name: 'a' })).toEqual([{ name: 'a' }]);
});
it('should sort apps by name', () => {
expect(addApp([{ name: 'a' }, { name: 'b' }], { name: 'c' })).toEqual([
{ name: 'a' },
{ name: 'b' },
{ name: 'c' }
]);
});
it('should put workspaceRoot last', () => {
expect(
addApp([{ name: 'a' }, { name: 'z' }], { name: '$workspaceRoot' })
).toEqual([{ name: 'a' }, { name: 'z' }, { name: '$workspaceRoot' }]);
});
it('should prioritize apps with "main" defined', () => {
expect(
addApp([{ name: 'c' }, { name: 'a' }, { name: 'a', main: 'a' }], {
name: 'b',
main: 'b'
})
).toEqual([
{ name: 'a', main: 'a' },
{ name: 'b', main: 'b' },
{ name: 'a' },
{ name: 'c' }
]);
});
});
});

View File

@ -1,79 +0,0 @@
import * as fs from 'fs';
import * as path from 'path';
export function writeToFile(path: string, str: string) {
fs.writeFileSync(path, str);
}
/**
* This method is specifically for updating a JSON file using the filesystem
*
* @remarks
* If you are looking to update a JSON file in a tree, look for ./ast-utils#updateJsonInTree
* @param path Path of the JSON file on the filesystem
* @param callback Manipulation of the JSON data
*/
export function updateJsonFile(path: string, callback: (a: any) => any) {
const json = readJsonFile(path);
callback(json);
writeToFile(path, JSON.stringify(json, null, 2));
}
export function addApp(apps: any[] | undefined, newApp: any): any[] {
if (!apps) {
apps = [];
}
apps.push(newApp);
apps.sort((a: any, b: any) => {
if (a.name === '$workspaceRoot') return 1;
if (b.name === '$workspaceRoot') return -1;
if (a.main && !b.main) return -1;
if (!a.main && b.main) return 1;
if (a.name > b.name) return 1;
return -1;
});
return apps;
}
export function serializeJson(json: any): string {
return `${JSON.stringify(json, null, 2)}\n`;
}
/**
* This method is specifically for reading a JSON file from the filesystem
*
* @remarks
* If you are looking to read a JSON file in a Tree, use ./ast-utils#readJsonInTree
* @param path Path of the JSON file on the filesystem
*/
export function readJsonFile(path: string): any {
return JSON.parse(fs.readFileSync(path, 'utf-8'));
}
export function readCliConfigFile(): any {
return readJsonFile('.angular-cli.json');
}
export function copyFile(file: string, target: string) {
const f = path.basename(file);
const source = fs.createReadStream(file);
const dest = fs.createWriteStream(path.resolve(target, f));
source.pipe(dest);
source.on('error', e => console.error(e));
}
function directoryExists(name) {
try {
return fs.statSync(name).isDirectory();
} catch (e) {
return false;
}
}
export function createDirectory(name: string) {
if (!directoryExists(name)) {
fs.mkdirSync(name);
}
}

View File

@ -1,31 +0,0 @@
export function names(name: string): any {
return {
name,
className: toClassName(name),
propertyName: toPropertyName(name),
fileName: toFileName(name)
};
}
export function toClassName(str: string): string {
return toCapitalCase(toPropertyName(str));
}
export function toPropertyName(s: string): string {
return s
.replace(/(-|_|\.|\s)+(.)?/g, (_, __, chr) =>
chr ? chr.toUpperCase() : ''
)
.replace(/^([A-Z])/, m => m.toLowerCase());
}
export function toFileName(s: string): string {
return s
.replace(/([a-z\d])([A-Z])/g, '$1_$2')
.toLowerCase()
.replace(/[ _]/g, '-');
}
function toCapitalCase(s: string): string {
return s.charAt(0).toUpperCase() + s.substr(1);
}

View File

@ -1,40 +0,0 @@
import { readJsonInTree } from '../ast-utils';
import {
TaskConfigurationGenerator,
TaskConfiguration,
Tree,
SchematicContext,
Rule,
noop
} from '@angular-devkit/schematics';
class FormatFiles implements TaskConfigurationGenerator<any> {
toConfiguration(): TaskConfiguration<any> {
return {
name: 'node-package',
options: {
packageName: 'run format -- --untracked', // workaround. we should define a custom task executor.
quiet: true
}
};
}
}
export function formatFiles(options: { skipFormat: boolean }): Rule {
if (options.skipFormat) {
return noop();
}
return (host: Tree, context: SchematicContext) => {
const packageJson = readJsonInTree(host, 'package.json');
if (packageJson.scripts && packageJson.scripts.format) {
context.addTask(new FormatFiles());
} else {
context.logger.warn(
'The "format" npm script is missing in your package.json'
);
context.logger.warn(
'Your files were not formated during this code generation'
);
}
};
}

View File

@ -1,88 +0,0 @@
import { Tree } from '@angular-devkit/schematics';
export function createEmptyWorkspace(tree: Tree): Tree {
tree.create('/.angular-cli.json', JSON.stringify({}));
tree.create('/package.json', JSON.stringify({}));
tree.create(
'/tslint.json',
JSON.stringify({
rules: {
'nx-enforce-module-boundaries': [
true,
{
npmScope: '<%= npmScope %>',
lazyLoad: [],
allow: []
}
]
}
})
);
return tree;
}
export function createApp(tree: Tree, appName: string): Tree {
tree.create(
`/apps/${appName}/src/app/app.module.ts`,
`
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, RouterModule.forRoot([])],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule {}
`
);
tree.create(
`/apps/${appName}/src/main.ts`,
`
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.log(err));
`
);
tree.create(
`/apps/${appName}/src/tsconfig.app.json`,
JSON.stringify({
include: ['**/*.ts']
})
);
tree.create(
`/apps/${appName}/e2e/tsconfig.e2e.json`,
JSON.stringify({
include: ['../**/*.ts']
})
);
tree.overwrite(
'/.angular-cli.json',
JSON.stringify({
project: {
name: 'proj',
npmScope: 'proj'
},
apps: [
{
name: appName,
root: `apps/${appName}/src`,
main: 'main.ts',
index: 'index.html'
}
]
})
);
return tree;
}