mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-17 02:54:21 +08:00
feat: ngmodules and insert components based on the AST (#1616)
This commit is contained in:
parent
4fd8e9c511
commit
5bcb7be917
@ -120,28 +120,23 @@ module.exports = {
|
||||
return;
|
||||
}
|
||||
|
||||
var returns = [];
|
||||
var modulePath = path.resolve(process.env.PWD, this.dynamicPath.appRoot, 'app.module.ts');
|
||||
var classifiedName =
|
||||
stringUtils.classify(`${options.entity.name}-${options.originBlueprintName}`);
|
||||
var importPath = `'./${options.entity.name}/` +
|
||||
stringUtils.dasherize(`${options.entity.name}.component';`);
|
||||
const returns = [];
|
||||
const modulePath = path.join(this.project.root, this.dynamicPath.appRoot, 'app.module.ts');
|
||||
const className = stringUtils.classify(`${options.entity.name}Component`);
|
||||
const fileName = stringUtils.dasherize(`${options.entity.name}.component`);
|
||||
const componentDir = path.relative(this.dynamicPath.appRoot, this.generatePath);
|
||||
const importPath = componentDir ? `./${componentDir}/${fileName}` : `./${fileName}`;
|
||||
|
||||
if (!options.flat) {
|
||||
returns.push(function() {
|
||||
return addBarrelRegistration(this, this.generatePath)
|
||||
});
|
||||
returns.push(addBarrelRegistration(this, componentDir));
|
||||
} else {
|
||||
returns.push(function() {
|
||||
return addBarrelRegistration(
|
||||
this,
|
||||
this.generatePath,
|
||||
options.entity.name + '.component')
|
||||
});
|
||||
returns.push(addBarrelRegistration(this, componentDir, fileName));
|
||||
}
|
||||
|
||||
if (!options['skip-import']) {
|
||||
returns.push(astUtils.importComponent(modulePath, classifiedName, importPath));
|
||||
returns.push(
|
||||
astUtils.addComponentToModule(modulePath, className, importPath)
|
||||
.then(change => change.apply()));
|
||||
}
|
||||
|
||||
return Promise.all(returns);
|
||||
|
@ -54,27 +54,27 @@ module.exports = {
|
||||
},
|
||||
|
||||
afterInstall: function(options) {
|
||||
var returns = [];
|
||||
var modulePath = path.resolve(process.env.PWD, this.dynamicPath.appRoot, 'app.module.ts');
|
||||
var classifiedName =
|
||||
stringUtils.classify(options.entity.name);
|
||||
var importPath = '\'./' + stringUtils.dasherize(`${options.entity.name}.directive';`);
|
||||
if (options.dryRun) {
|
||||
return;
|
||||
}
|
||||
|
||||
const returns = [];
|
||||
const modulePath = path.join(this.project.root, this.dynamicPath.appRoot, 'app.module.ts');
|
||||
const className = stringUtils.classify(`${options.entity.name}`);
|
||||
const fileName = stringUtils.dasherize(`${options.entity.name}.directive`);
|
||||
const componentDir = path.relative(this.dynamicPath.appRoot, this.generatePath);
|
||||
const importPath = componentDir ? `./${componentDir}/${fileName}` : `./${fileName}`;
|
||||
|
||||
if (!options.flat) {
|
||||
returns.push(function() {
|
||||
return addBarrelRegistration(this, this.generatePath)
|
||||
});
|
||||
returns.push(addBarrelRegistration(this, componentDir));
|
||||
} else {
|
||||
returns.push(function() {
|
||||
return addBarrelRegistration(
|
||||
this,
|
||||
this.generatePath,
|
||||
options.entity.name + '.directive')
|
||||
});
|
||||
returns.push(addBarrelRegistration(this, componentDir, fileName));
|
||||
}
|
||||
|
||||
if (!options['skip-import']) {
|
||||
returns.push(astUtils.importComponent(modulePath, classifiedName, importPath));
|
||||
returns.push(
|
||||
astUtils.addComponentToModule(modulePath, className, importPath)
|
||||
.then(change => change.apply()));
|
||||
}
|
||||
|
||||
return Promise.all(returns);
|
||||
|
@ -2,8 +2,7 @@ import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule, ApplicationRef } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { AppComponent } from './app.component';<% if (isMobile) { %>
|
||||
import { AppShellModule } from '../app-shell-module';<% } %>
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -12,12 +11,12 @@ import { AppShellModule } from '../app-shell-module';<% } %>
|
||||
imports: [
|
||||
BrowserModule,
|
||||
CommonModule,
|
||||
FormsModule<% if (isMobile) { %>,
|
||||
AppShellModule<% } %>
|
||||
FormsModule
|
||||
],
|
||||
providers: [],
|
||||
entryComponents: [AppComponent],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -12,14 +12,14 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "github:angular/common-builds",
|
||||
"@angular/compiler": "github:angular/compiler-builds",
|
||||
"@angular/core": "github:angular/core-builds",
|
||||
"@angular/forms": "github:angular/forms-builds",
|
||||
"@angular/http": "github:angular/http-builds",
|
||||
"@angular/platform-browser": "github:angular/platform-browser-builds",
|
||||
"@angular/platform-browser-dynamic": "github:angular/platform-browser-dynamic-builds",
|
||||
"@angular/router": "github:angular/router-builds",
|
||||
"@angular/common": "2.0.0-rc.5",
|
||||
"@angular/compiler": "2.0.0-rc.5",
|
||||
"@angular/core": "2.0.0-rc.5",
|
||||
"@angular/forms": "0.3.0",
|
||||
"@angular/http": "2.0.0-rc.5",
|
||||
"@angular/platform-browser": "2.0.0-rc.5",
|
||||
"@angular/platform-browser-dynamic": "2.0.0-rc.5",
|
||||
"@angular/router": "3.0.0-rc.1",
|
||||
"core-js": "^2.4.0",
|
||||
"reflect-metadata": "0.1.3",
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
|
@ -52,27 +52,27 @@ module.exports = {
|
||||
},
|
||||
|
||||
afterInstall: function(options) {
|
||||
var returns = [];
|
||||
var modulePath = path.resolve(process.env.PWD, this.dynamicPath.appRoot, 'app.module.ts');
|
||||
var classifiedName =
|
||||
stringUtils.classify(`${options.entity.name}-${options.originBlueprintName}`);
|
||||
var importPath = '\'./' + stringUtils.dasherize(`${options.entity.name}.pipe';`);
|
||||
if (options.dryRun) {
|
||||
return;
|
||||
}
|
||||
|
||||
const returns = [];
|
||||
const modulePath = path.join(this.project.root, this.dynamicPath.appRoot, 'app.module.ts');
|
||||
const className = stringUtils.classify(`${options.entity.name}Pipe`);
|
||||
const fileName = stringUtils.dasherize(`${options.entity.name}.pipe`);
|
||||
const componentDir = path.relative(this.dynamicPath.appRoot, this.generatePath);
|
||||
const importPath = componentDir ? `./${componentDir}/${fileName}` : `./${fileName}`;
|
||||
|
||||
if (!options.flat) {
|
||||
returns.push(function() {
|
||||
return addBarrelRegistration(this, this.generatePath)
|
||||
});
|
||||
returns.push(addBarrelRegistration(this, componentDir));
|
||||
} else {
|
||||
returns.push(function() {
|
||||
return addBarrelRegistration(
|
||||
this,
|
||||
this.generatePath,
|
||||
options.entity.name + '.pipe')
|
||||
});
|
||||
returns.push(addBarrelRegistration(this, componentDir, fileName));
|
||||
}
|
||||
|
||||
if (!options['skip-import']) {
|
||||
returns.push(astUtils.importComponent(modulePath, classifiedName, importPath));
|
||||
returns.push(
|
||||
astUtils.addComponentToModule(modulePath, className, importPath)
|
||||
.then(change => change.apply()));
|
||||
}
|
||||
|
||||
return Promise.all(returns);
|
||||
|
@ -3,10 +3,11 @@ var Blueprint = require('ember-cli/lib/models/blueprint');
|
||||
var dynamicPathParser = require('../../utilities/dynamic-path-parser');
|
||||
var addBarrelRegistration = require('../../utilities/barrel-management');
|
||||
var getFiles = Blueprint.prototype.files;
|
||||
const stringUtils = require('ember-cli-string-utils');
|
||||
|
||||
module.exports = {
|
||||
description: '',
|
||||
|
||||
|
||||
availableOptions: [
|
||||
{ name: 'flat', type: Boolean, default: true }
|
||||
],
|
||||
@ -24,10 +25,10 @@ module.exports = {
|
||||
flat: options.flat
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
files: function() {
|
||||
var fileList = getFiles.call(this);
|
||||
|
||||
|
||||
if (this.options && this.options.flat) {
|
||||
fileList = fileList.filter(p => p.indexOf('index.ts') <= 0);
|
||||
}
|
||||
@ -48,17 +49,17 @@ module.exports = {
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
afterInstall: function(options) {
|
||||
const returns = [];
|
||||
const fileName = stringUtils.dasherize(`${options.entity.name}.service`);
|
||||
|
||||
if (!options.flat) {
|
||||
return addBarrelRegistration(
|
||||
this,
|
||||
this.generatePath);
|
||||
returns.push(addBarrelRegistration(this, this.generatePath));
|
||||
} else {
|
||||
return addBarrelRegistration(
|
||||
this,
|
||||
this.generatePath,
|
||||
options.entity.name + '.service');
|
||||
returns.push(addBarrelRegistration(this, this.generatePath, fileName));
|
||||
}
|
||||
|
||||
return Promise.all(returns);
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,24 @@
|
||||
import * as ts from 'typescript';
|
||||
import * as fs from 'fs';
|
||||
import { InsertChange } from './change';
|
||||
import {Symbols} from '@angular/tsc-wrapped/src/symbols';
|
||||
import {
|
||||
isMetadataImportedSymbolReferenceExpression,
|
||||
isMetadataModuleReferenceExpression
|
||||
} from '@angular/tsc-wrapped';
|
||||
import {Change, InsertChange, NoopChange, MultiChange} from './change';
|
||||
import {insertImport} from './route-utils';
|
||||
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
import {ReplaySubject} from 'rxjs/ReplaySubject';
|
||||
import 'rxjs/add/observable/of';
|
||||
import 'rxjs/add/operator/do';
|
||||
import 'rxjs/add/operator/filter';
|
||||
import 'rxjs/add/operator/last';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/mergeMap';
|
||||
import 'rxjs/add/operator/toArray';
|
||||
import 'rxjs/add/operator/toPromise';
|
||||
|
||||
|
||||
/**
|
||||
* Get TS source file based on path.
|
||||
@ -12,6 +30,32 @@ export function getSource(filePath: string): ts.SourceFile {
|
||||
ts.ScriptTarget.ES6, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all the nodes from a source, as an observable.
|
||||
* @param sourceFile The source file object.
|
||||
* @returns {Observable<ts.Node>} An observable of all the nodes in the source.
|
||||
*/
|
||||
export function getSourceNodes(sourceFile: ts.SourceFile): Observable<ts.Node> {
|
||||
const subject = new ReplaySubject<ts.Node>();
|
||||
let nodes: ts.Node[] = [sourceFile];
|
||||
|
||||
while(nodes.length > 0) {
|
||||
const node = nodes.shift();
|
||||
|
||||
if (node) {
|
||||
subject.next(node);
|
||||
if (node.getChildCount(sourceFile) >= 0) {
|
||||
nodes.unshift(...node.getChildren());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subject.complete();
|
||||
return subject.asObservable();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find all nodes from the AST in the subtree of node of SyntaxKind kind.
|
||||
* @param node
|
||||
@ -30,25 +74,6 @@ export function findNodes(node: ts.Node, kind: ts.SyntaxKind): ts.Node[] {
|
||||
foundNodes.concat(findNodes(child, kind)), arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all nodes from the AST in the subtree based on text.
|
||||
* @param node
|
||||
* @param text
|
||||
* @return all nodes of text, or [] if none is found
|
||||
*/
|
||||
export function findNodesByText(node: ts.Node, text: string): ts.Node[] {
|
||||
if (!node) {
|
||||
return [];
|
||||
}
|
||||
let arr: ts.Node[] = [];
|
||||
if (node.getText() === text) {
|
||||
arr.push(node);
|
||||
}
|
||||
|
||||
return node.getChildren().reduce((foundNodes, child) => {
|
||||
return foundNodes.concat(findNodesByText(child, text));
|
||||
}, arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for sorting nodes.
|
||||
@ -58,6 +83,7 @@ function nodesByPosition(first: ts.Node, second: ts.Node): number {
|
||||
return first.pos - second.pos;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert `toInsert` after the last occurence of `ts.SyntaxKind[nodes[i].kind]`
|
||||
* or after the last of occurence of `syntaxKind` if the last occurence is a sub child
|
||||
@ -84,39 +110,163 @@ export function insertAfterLastOccurrence(nodes: ts.Node[], toInsert: string,
|
||||
return new InsertChange(file, lastItemPosition, toInsert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom function to insert component (component, pipe, directive)
|
||||
* into NgModule declarations. It also imports the component.
|
||||
* @param modulePath
|
||||
* @param classifiedName
|
||||
* @param importPath
|
||||
* @return Promise
|
||||
*/
|
||||
export function importComponent(modulePath: string, classifiedName: string,
|
||||
importPath: string): Promise<void> {
|
||||
let source: ts.SourceFile = this.getSource(modulePath);
|
||||
|
||||
let importNode: ts.Node =
|
||||
this.findNodesByText(source, 'import').pop();
|
||||
let iPos: ts.LineAndCharacter =
|
||||
source.getLineAndCharacterOfPosition(importNode.getEnd());
|
||||
let iLine: number = iPos.line + 1;
|
||||
let iStart: number = source.getPositionOfLineAndCharacter(iLine, 0);
|
||||
let iStr: string = `import { ${classifiedName} } from ${importPath}\n`;
|
||||
let changeImport: InsertChange = new InsertChange(modulePath, iStart, iStr);
|
||||
export function getDecoratorMetadata(source: ts.SourceFile, identifier: string,
|
||||
module: string): Observable<ts.Node> {
|
||||
const symbols = new Symbols(source);
|
||||
return getSourceNodes(source)
|
||||
.filter(node => {
|
||||
return node.kind == ts.SyntaxKind.Decorator
|
||||
&& (<ts.Decorator>node).expression.kind == ts.SyntaxKind.CallExpression;
|
||||
})
|
||||
.map(node => <ts.CallExpression>(<ts.Decorator>node).expression)
|
||||
.filter(expr => {
|
||||
if (expr.expression.kind == ts.SyntaxKind.Identifier) {
|
||||
const id = <ts.Identifier>expr.expression;
|
||||
const metaData = symbols.resolve(id.getFullText(source));
|
||||
if (isMetadataImportedSymbolReferenceExpression(metaData)) {
|
||||
return metaData.name == identifier && metaData.module == module;
|
||||
}
|
||||
} else if (expr.expression.kind == ts.SyntaxKind.PropertyAccessExpression) {
|
||||
// This covers foo.NgModule when importing * as foo.
|
||||
const paExpr = <ts.PropertyAccessExpression>expr.expression;
|
||||
// If the left expression is not an identifier, just give up at that point.
|
||||
if (paExpr.expression.kind !== ts.SyntaxKind.Identifier) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return changeImport.apply().then(() => {
|
||||
source = this.getSource(modulePath);
|
||||
let declarationsNode: ts.Node =
|
||||
this.findNodesByText(source, 'declarations').shift();
|
||||
let dPos: ts.LineAndCharacter =
|
||||
source.getLineAndCharacterOfPosition(declarationsNode.getEnd());
|
||||
let dStart: number =
|
||||
source.getPositionOfLineAndCharacter(dPos.line + 1, -1);
|
||||
let dStr: string = `\n ${classifiedName},`;
|
||||
let changeDeclarations: InsertChange = new InsertChange(modulePath, dStart, dStr);
|
||||
|
||||
return changeDeclarations.apply();
|
||||
});
|
||||
const id = paExpr.name;
|
||||
const moduleId = <ts.Identifier>paExpr.expression;
|
||||
const moduleMetaData = symbols.resolve(moduleId.getFullText(source));
|
||||
if (isMetadataModuleReferenceExpression(moduleMetaData)) {
|
||||
return moduleMetaData.module == module && id.getFullText(source) == identifier;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.filter(expr => expr.arguments[0]
|
||||
&& expr.arguments[0].kind == ts.SyntaxKind.ObjectLiteralExpression)
|
||||
.map(expr => <ts.ObjectLiteralExpression>expr.arguments[0]);
|
||||
}
|
||||
|
||||
|
||||
function _addSymbolToNgModuleMetadata(ngModulePath: string, metadataField: string,
|
||||
symbolName: string, importPath: string) {
|
||||
const source: ts.SourceFile = getSource(ngModulePath);
|
||||
let metadata = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
||||
|
||||
// Find the decorator declaration.
|
||||
return metadata
|
||||
.toPromise()
|
||||
.then((node: ts.ObjectLiteralExpression) => {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get all the children property assignment of object literals.
|
||||
return node.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 => {
|
||||
switch (prop.name.kind) {
|
||||
case ts.SyntaxKind.Identifier:
|
||||
return prop.name.getText(source) == metadataField;
|
||||
case ts.SyntaxKind.StringLiteral:
|
||||
return prop.name.text == metadataField;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
})
|
||||
// Get the last node of the array literal.
|
||||
.then(matchingProperties => {
|
||||
if (!matchingProperties) {
|
||||
return;
|
||||
}
|
||||
if (matchingProperties.length == 0) {
|
||||
return metadata
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
const assignment = <ts.PropertyAssignment>matchingProperties[0];
|
||||
|
||||
// If it's not an array, nothing we can do really.
|
||||
if (assignment.initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression) {
|
||||
return Observable.empty();
|
||||
}
|
||||
|
||||
const arrLiteral = <ts.ArrayLiteralExpression>assignment.initializer;
|
||||
if (arrLiteral.elements.length == 0) {
|
||||
// Forward the property.
|
||||
return arrLiteral;
|
||||
}
|
||||
return arrLiteral.elements;
|
||||
})
|
||||
.then((node: ts.Node) => {
|
||||
if (!node) {
|
||||
console.log('No app module found. Please add your new class to your component.');
|
||||
return new NoopChange();
|
||||
}
|
||||
if (Array.isArray(node)) {
|
||||
node = node[node.length - 1];
|
||||
}
|
||||
|
||||
let toInsert;
|
||||
let position = node.getEnd();
|
||||
if (node.kind == ts.SyntaxKind.ObjectLiteralExpression) {
|
||||
// We haven't found the field in the metadata declaration. Insert a new
|
||||
// field.
|
||||
let expr = <ts.ObjectLiteralExpression>node;
|
||||
if (expr.properties.length == 0) {
|
||||
position = expr.getEnd() - 1;
|
||||
toInsert = ` ${metadataField}: [${symbolName}]\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.startsWith('\n')) {
|
||||
toInsert = `,${text.match(/^\n(\r?)\s+/)[0]}${metadataField}: [${symbolName}]`;
|
||||
} else {
|
||||
toInsert = `, ${metadataField}: [${symbolName}]`;
|
||||
}
|
||||
}
|
||||
} else if (node.kind == ts.SyntaxKind.ArrayLiteralExpression) {
|
||||
// We found the field but it's empty. Insert it just before the `]`.
|
||||
position--;
|
||||
toInsert = `${symbolName}`;
|
||||
} else {
|
||||
// Get the indentation of the last element, if any.
|
||||
const text = node.getFullText(source);
|
||||
if (text.startsWith('\n')) {
|
||||
toInsert = `,${text.match(/^\n(\r?)\s+/)[0]}${symbolName}`;
|
||||
} else {
|
||||
toInsert = `, ${symbolName}`;
|
||||
}
|
||||
}
|
||||
|
||||
const insert = new InsertChange(ngModulePath, position, toInsert);
|
||||
const importInsert: Change = insertImport(ngModulePath, symbolName, importPath);
|
||||
return new MultiChange([insert, importInsert]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom function to insert a declaration (component, pipe, directive)
|
||||
* into NgModule declarations. It also imports the component.
|
||||
*/
|
||||
export function addComponentToModule(modulePath: string, classifiedName: string,
|
||||
importPath: string): Promise<Change> {
|
||||
|
||||
return _addSymbolToNgModuleMetadata(modulePath, 'declarations', classifiedName, importPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom function to insert a provider into NgModule. It also imports it.
|
||||
*/
|
||||
export function addProviderToModule(modulePath: string, classifiedName: string,
|
||||
importPath: string): Promise<Change> {
|
||||
return _addSymbolToNgModuleMetadata(modulePath, 'providers', classifiedName, importPath);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,58 @@ export interface Change {
|
||||
description: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An operation that does nothing.
|
||||
*/
|
||||
export class NoopChange implements Change {
|
||||
get description() { return 'No operation.'; }
|
||||
get order() { return Infinity; }
|
||||
get path() { return null; }
|
||||
apply() { return Promise.resolve(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* An operation that mixes two or more changes, and merge them (in order).
|
||||
* Can only apply to a single file. Use a ChangeManager to apply changes to multiple
|
||||
* files.
|
||||
*/
|
||||
export class MultiChange implements Change {
|
||||
private _path: string;
|
||||
private _changes: Change[];
|
||||
|
||||
constructor(...changes: Array<Change[], Change>) {
|
||||
this._changes = [];
|
||||
[].concat(...changes).forEach(change => this.appendChange(change));
|
||||
}
|
||||
|
||||
appendChange(change: Change) {
|
||||
// Validate that the path is the same for everyone of those.
|
||||
if (this._path === undefined) {
|
||||
this._path = change.path;
|
||||
} else if (change.path !== this._path) {
|
||||
throw new Error('Cannot apply a change to a different path.');
|
||||
}
|
||||
this._changes.push(change);
|
||||
}
|
||||
|
||||
get description() {
|
||||
return `Changes:\n ${this._changes.map(x => x.description).join('\n ')}`;
|
||||
}
|
||||
// Always apply as early as the highest change.
|
||||
get order() { return Math.max(...this._changes); }
|
||||
get path() { return this._path; }
|
||||
|
||||
apply() {
|
||||
return this._changes
|
||||
.sort((a: Change, b: Change) => b.order - a.order)
|
||||
.reduce((promise, change) => {
|
||||
return promise.then(() => change.apply())
|
||||
}, Promise.resolve());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Will add text to the source code.
|
||||
*/
|
||||
|
@ -4,7 +4,8 @@ var fs = require('fs');
|
||||
|
||||
module.exports = function dynamicPathParser(project, entityName) {
|
||||
var projectRoot = project.root;
|
||||
var appRoot = path.join(project.ngConfig.defaults.sourceDir, 'app');
|
||||
var sourceDir = project.ngConfig.defaults.sourceDir;
|
||||
var appRoot = path.join(sourceDir, 'app');
|
||||
var cwd = process.env.PWD;
|
||||
|
||||
var rootPath = path.join(projectRoot, appRoot);
|
||||
@ -52,7 +53,8 @@ module.exports = function dynamicPathParser(project, entityName) {
|
||||
}
|
||||
|
||||
parsedPath.dir = parsedPath.dir === path.sep ? '' : parsedPath.dir;
|
||||
parsedPath.appRoot = appRoot
|
||||
parsedPath.appRoot = appRoot;
|
||||
parsedPath.sourceDir = sourceDir;
|
||||
|
||||
return parsedPath;
|
||||
};
|
||||
|
@ -32,6 +32,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/angular/angular-cli",
|
||||
"dependencies": {
|
||||
"@angular/tsc-wrapped": "^0.2.2",
|
||||
"@types/lodash": "^4.0.25-alpha",
|
||||
"@types/rimraf": "0.0.25-alpha",
|
||||
"@types/webpack": "^1.12.22-alpha",
|
||||
@ -74,6 +75,7 @@
|
||||
"remap-istanbul": "^0.6.4",
|
||||
"resolve": "^1.1.7",
|
||||
"rimraf": "^2.5.3",
|
||||
"rxjs": "^5.0.0-beta.11",
|
||||
"sass-loader": "^3.2.0",
|
||||
"shelljs": "^0.7.0",
|
||||
"silent-error": "^1.0.0",
|
||||
|
@ -6,7 +6,8 @@ import { InsertChange, RemoveChange } from '../../addon/ng2/utilities/change';
|
||||
import * as Promise from 'ember-cli/lib/ext/promise';
|
||||
import {
|
||||
findNodes,
|
||||
insertAfterLastOccurrence
|
||||
insertAfterLastOccurrence,
|
||||
addComponentToModule
|
||||
} from '../../addon/ng2/utilities/ast-utils';
|
||||
|
||||
const readFile = Promise.denodeify(fs.readFile);
|
||||
@ -164,6 +165,122 @@ describe('ast-utils: insertAfterLastOccurrence', () => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('addComponentToModule', () => {
|
||||
beforeEach(() => {
|
||||
mockFs( {
|
||||
'1.ts': `
|
||||
import {NgModule} from '@angular/core';
|
||||
|
||||
@NgModule({
|
||||
declarations: []
|
||||
})
|
||||
class Module {}`,
|
||||
'2.ts': `
|
||||
import {NgModule} from '@angular/core';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
Other
|
||||
]
|
||||
})
|
||||
class Module {}`,
|
||||
'3.ts': `
|
||||
import {NgModule} from '@angular/core';
|
||||
|
||||
@NgModule({
|
||||
})
|
||||
class Module {}`,
|
||||
'4.ts': `
|
||||
import {NgModule} from '@angular/core';
|
||||
|
||||
@NgModule({
|
||||
field1: [],
|
||||
field2: {}
|
||||
})
|
||||
class Module {}`
|
||||
});
|
||||
});
|
||||
afterEach(() => mockFs.restore());
|
||||
|
||||
it('works with empty array', () => {
|
||||
return addComponentToModule('1.ts', 'MyClass', 'MyImportPath')
|
||||
.then(change => change.apply())
|
||||
.then(() => readFile('1.ts', 'utf-8'))
|
||||
.then(content => {
|
||||
expect(content).to.equal(
|
||||
'\n' +
|
||||
'import {NgModule} from \'@angular/core\';\n' +
|
||||
'import { MyClass } from \'MyImportPath\';\n' +
|
||||
'\n' +
|
||||
'@NgModule({\n' +
|
||||
' declarations: [MyClass]\n' +
|
||||
'})\n' +
|
||||
'class Module {}'
|
||||
);
|
||||
})
|
||||
});
|
||||
|
||||
it('works with array with declarations', () => {
|
||||
return addComponentToModule('2.ts', 'MyClass', 'MyImportPath')
|
||||
.then(change => change.apply())
|
||||
.then(() => readFile('2.ts', 'utf-8'))
|
||||
.then(content => {
|
||||
expect(content).to.equal(
|
||||
'\n' +
|
||||
'import {NgModule} from \'@angular/core\';\n' +
|
||||
'import { MyClass } from \'MyImportPath\';\n' +
|
||||
'\n' +
|
||||
'@NgModule({\n' +
|
||||
' declarations: [\n' +
|
||||
' Other,\n' +
|
||||
' MyClass\n' +
|
||||
' ]\n' +
|
||||
'})\n' +
|
||||
'class Module {}'
|
||||
);
|
||||
})
|
||||
});
|
||||
|
||||
it('works without any declarations', () => {
|
||||
return addComponentToModule('3.ts', 'MyClass', 'MyImportPath')
|
||||
.then(change => change.apply())
|
||||
.then(() => readFile('3.ts', 'utf-8'))
|
||||
.then(content => {
|
||||
expect(content).to.equal(
|
||||
'\n' +
|
||||
'import {NgModule} from \'@angular/core\';\n' +
|
||||
'import { MyClass } from \'MyImportPath\';\n' +
|
||||
'\n' +
|
||||
'@NgModule({\n' +
|
||||
' declarations: [MyClass]\n' +
|
||||
'})\n' +
|
||||
'class Module {}'
|
||||
);
|
||||
})
|
||||
});
|
||||
|
||||
it('works without a declaration field', () => {
|
||||
return addComponentToModule('4.ts', 'MyClass', 'MyImportPath')
|
||||
.then(change => change.apply())
|
||||
.then(() => readFile('4.ts', 'utf-8'))
|
||||
.then(content => {
|
||||
expect(content).to.equal(
|
||||
'\n' +
|
||||
'import {NgModule} from \'@angular/core\';\n' +
|
||||
'import { MyClass } from \'MyImportPath\';\n' +
|
||||
'\n' +
|
||||
'@NgModule({\n' +
|
||||
' field1: [],\n' +
|
||||
' field2: {},\n' +
|
||||
' declarations: [MyClass]\n' +
|
||||
'})\n' +
|
||||
'class Module {}'
|
||||
);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets node of kind kind from sourceFile
|
||||
*/
|
||||
|
@ -1,4 +1,3 @@
|
||||
/*eslint-disable no-console */
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs-extra');
|
||||
@ -11,6 +10,10 @@ var root = process.cwd();
|
||||
var conf = require('ember-cli/tests/helpers/conf');
|
||||
var Promise = require('ember-cli/lib/ext/promise');
|
||||
var SilentError = require('silent-error');
|
||||
const denodeify = require('denodeify');
|
||||
|
||||
const readFile = denodeify(fs.readFile);
|
||||
|
||||
|
||||
describe('Acceptance: ng generate component', function () {
|
||||
before(conf.setup);
|
||||
@ -27,18 +30,23 @@ describe('Acceptance: ng generate component', function () {
|
||||
|
||||
afterEach(function () {
|
||||
this.timeout(10000);
|
||||
|
||||
return tmp.teardown('./tmp');
|
||||
});
|
||||
|
||||
it('ng generate component my-comp', function () {
|
||||
return ng(['generate', 'component', 'my-comp']).then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.component.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
});
|
||||
it('my-comp', function () {
|
||||
const testPath = path.join(root, 'tmp/foo/src/app/my-comp/my-comp.component.ts');
|
||||
const appModule = path.join(root, 'tmp/foo/src/app/app.module.ts');
|
||||
return ng(['generate', 'component', 'my-comp'])
|
||||
.then(() => expect(existsSync(testPath)).to.equal(true))
|
||||
.then(() => readFile(appModule, 'utf-8'))
|
||||
.then(content => {
|
||||
// Expect that the app.module contains a reference to my-comp and its import.
|
||||
expect(content).matches(/import.*MyCompComponent.*from '.\/my-comp\/my-comp.component';/);
|
||||
expect(content).matches(/declarations:\s*\[[^\]]+?,\n\s+MyCompComponent\n/m);
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component test' + path.sep + 'my-comp', function () {
|
||||
it('test' + path.sep + 'my-comp', function () {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', 'test'));
|
||||
return ng(['generate', 'component', 'test' + path.sep + 'my-comp']).then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'test', 'my-comp', 'my-comp.component.ts');
|
||||
@ -46,7 +54,7 @@ describe('Acceptance: ng generate component', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component test' + path.sep + '..' + path.sep + 'my-comp', function () {
|
||||
it('test' + path.sep + '..' + path.sep + 'my-comp', function () {
|
||||
return ng(['generate', 'component', 'test' + path.sep + '..' + path.sep + 'my-comp'])
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.component.ts');
|
||||
@ -54,7 +62,7 @@ describe('Acceptance: ng generate component', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component my-comp from a child dir', () => {
|
||||
it('my-comp from a child dir', () => {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', '1'));
|
||||
return new Promise(function (resolve) {
|
||||
process.chdir('./src');
|
||||
@ -68,10 +76,10 @@ describe('Acceptance: ng generate component', function () {
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'my-comp', 'my-comp.component.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component child-dir' + path.sep + 'my-comp from a child dir', () => {
|
||||
it('child-dir' + path.sep + 'my-comp from a child dir', () => {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'child-dir'));
|
||||
return new Promise(function (resolve) {
|
||||
process.chdir('./src');
|
||||
@ -86,50 +94,39 @@ describe('Acceptance: ng generate component', function () {
|
||||
var testPath = path.join(
|
||||
root, 'tmp', 'foo', 'src', 'app', '1', 'child-dir', 'my-comp', 'my-comp.component.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component child-dir' + path.sep + '..' + path.sep + 'my-comp from a child dir',
|
||||
() => {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', '1'));
|
||||
return new Promise(function (resolve) {
|
||||
process.chdir('./src');
|
||||
resolve();
|
||||
it('child-dir' + path.sep + '..' + path.sep + 'my-comp from a child dir', () => {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', '1'));
|
||||
return Promise.resolve()
|
||||
.then(() => process.chdir(path.normalize('./src/app/1')))
|
||||
.then(() => {
|
||||
return ng([
|
||||
'generate', 'component', 'child-dir' + path.sep + '..' + path.sep + 'my-comp'
|
||||
])
|
||||
})
|
||||
.then(() => process.chdir('./app'))
|
||||
.then(() => process.chdir('./1'))
|
||||
.then(() => {
|
||||
return ng([
|
||||
'generate', 'component', 'child-dir' + path.sep + '..' + path.sep + 'my-comp'
|
||||
])
|
||||
})
|
||||
.then(() => {
|
||||
var testPath =
|
||||
path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'my-comp', 'my-comp.component.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
.then(() => {
|
||||
var testPath =
|
||||
path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'my-comp', 'my-comp.component.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component ' + path.sep + 'my-comp from a child dir, gens under ' +
|
||||
path.join('src', 'app'),
|
||||
() => {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', '1'));
|
||||
return new Promise(function (resolve) {
|
||||
process.chdir('./src');
|
||||
resolve();
|
||||
it(path.sep + 'my-comp from a child dir, gens under ' + path.join('src', 'app'), () => {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', '1'));
|
||||
return Promise.resolve()
|
||||
.then(() => process.chdir(path.normalize('./src/app/1')))
|
||||
.then(() => {
|
||||
return ng(['generate', 'component', path.sep + 'my-comp'])
|
||||
})
|
||||
.then(() => process.chdir('./app'))
|
||||
.then(() => process.chdir('./1'))
|
||||
.then(() => {
|
||||
return ng(['generate', 'component', path.sep + 'my-comp'])
|
||||
})
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.component.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.component.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component ..' + path.sep + 'my-comp from root dir will fail', () => {
|
||||
it('..' + path.sep + 'my-comp from root dir will fail', () => {
|
||||
return ng(['generate', 'component', '..' + path.sep + 'my-comp']).then(() => {
|
||||
throw new SilentError(`ng generate component ..${path.sep}my-comp from root dir should fail.`);
|
||||
}, (err) => {
|
||||
@ -137,7 +134,7 @@ describe('Acceptance: ng generate component', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component mycomp will prefix selector', () => {
|
||||
it('mycomp will prefix selector', () => {
|
||||
return ng(['generate', 'component', 'mycomp'])
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'mycomp', 'mycomp.component.ts');
|
||||
@ -147,7 +144,7 @@ describe('Acceptance: ng generate component', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component mycomp --no-prefix will not prefix selector', () => {
|
||||
it('mycomp --no-prefix will not prefix selector', () => {
|
||||
return ng(['generate', 'component', 'mycomp', '--no-prefix'])
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'mycomp', 'mycomp.component.ts');
|
||||
@ -157,7 +154,7 @@ describe('Acceptance: ng generate component', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component myComp will succeed', () => {
|
||||
it('myComp will succeed', () => {
|
||||
return ng(['generate', 'component', 'myComp'])
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.component.ts');
|
||||
@ -165,24 +162,24 @@ describe('Acceptance: ng generate component', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component my-comp --inline-template', function () {
|
||||
it('my-comp --inline-template', function () {
|
||||
return ng(['generate', 'component', 'my-comp', '--inline-template']).then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.component.html');
|
||||
expect(existsSync(testPath)).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component my-comp --inline-style', function () {
|
||||
it('my-comp --inline-style', function () {
|
||||
return ng(['generate', 'component', 'my-comp', '--inline-style']).then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.component.css');
|
||||
expect(existsSync(testPath)).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate component my-comp --nospec', function() {
|
||||
it('my-comp --nospec', function() {
|
||||
return ng(['generate', 'component', 'my-comp', '--nospec']).then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.component.spec.ts');
|
||||
expect(existsSync(testPath)).to.equal(false);
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
/*eslint-disable no-console */
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs-extra');
|
||||
@ -11,6 +10,10 @@ var root = process.cwd();
|
||||
var conf = require('ember-cli/tests/helpers/conf');
|
||||
var Promise = require('ember-cli/lib/ext/promise');
|
||||
var SilentError = require('silent-error');
|
||||
const denodeify = require('denodeify');
|
||||
|
||||
const readFile = denodeify(fs.readFile);
|
||||
|
||||
|
||||
describe('Acceptance: ng generate directive', function () {
|
||||
before(conf.setup);
|
||||
@ -31,21 +34,28 @@ describe('Acceptance: ng generate directive', function () {
|
||||
return tmp.teardown('./tmp');
|
||||
});
|
||||
|
||||
it('ng generate flat directive', function () {
|
||||
it('flat', function () {
|
||||
return ng(['generate', 'directive', 'flat']).then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'flat.directive.ts');
|
||||
var testPath = path.join(root, 'tmp/foo/src/app/flat.directive.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate directive my-dir', function () {
|
||||
return ng(['generate', 'directive', 'my-dir', '--flat', 'false']).then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-dir', 'my-dir.directive.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
});
|
||||
it('my-dir --flat false', function () {
|
||||
const appRoot = path.join(root, 'tmp/foo');
|
||||
const testPath = path.join(appRoot, 'src/app/my-dir/my-dir.directive.ts');
|
||||
const appModulePath = path.join(appRoot, 'src/app/app.module.ts');
|
||||
|
||||
return ng(['generate', 'directive', 'my-dir', '--flat', 'false'])
|
||||
.then(() => expect(existsSync(testPath)).to.equal(true))
|
||||
.then(() => readFile(appModulePath, 'utf-8'))
|
||||
.then(content => {
|
||||
expect(content).matches(/import.*\bMyDir\b.*from '.\/my-dir\/my-dir.directive';/);
|
||||
expect(content).matches(/declarations:\s*\[[^\]]+?,\n\s+MyDir\n/m);
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate directive test' + path.sep + 'my-dir', function () {
|
||||
it('test' + path.sep + 'my-dir', function () {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', 'test'));
|
||||
return ng(['generate', 'directive', 'test' + path.sep + 'my-dir', '--flat', 'false']).then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'test', 'my-dir', 'my-dir.directive.ts');
|
||||
@ -53,7 +63,7 @@ describe('Acceptance: ng generate directive', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate directive test' + path.sep + '..' + path.sep + 'my-dir', function () {
|
||||
it('test' + path.sep + '..' + path.sep + 'my-dir', function () {
|
||||
return ng(['generate', 'directive', 'test' + path.sep + '..' + path.sep + 'my-dir', '--flat', 'false'])
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-dir', 'my-dir.directive.ts');
|
||||
@ -61,7 +71,7 @@ describe('Acceptance: ng generate directive', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate directive my-dir from a child dir', () => {
|
||||
it('my-dir from a child dir', () => {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', '1'));
|
||||
return new Promise(function (resolve) {
|
||||
process.chdir('./src');
|
||||
@ -76,10 +86,10 @@ describe('Acceptance: ng generate directive', function () {
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'my-dir', 'my-dir.directive.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate directive child-dir' + path.sep + 'my-dir from a child dir', () => {
|
||||
it('child-dir' + path.sep + 'my-dir from a child dir', () => {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'child-dir'));
|
||||
return new Promise(function (resolve) {
|
||||
process.chdir('./src');
|
||||
@ -95,10 +105,10 @@ describe('Acceptance: ng generate directive', function () {
|
||||
var testPath = path.join(
|
||||
root, 'tmp', 'foo', 'src', 'app', '1', 'child-dir', 'my-dir', 'my-dir.directive.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate directive child-dir' + path.sep + '..' + path.sep + 'my-dir from a child dir',
|
||||
it('child-dir' + path.sep + '..' + path.sep + 'my-dir from a child dir',
|
||||
() => {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', '1'));
|
||||
return new Promise(function (resolve) {
|
||||
@ -116,10 +126,10 @@ describe('Acceptance: ng generate directive', function () {
|
||||
var testPath =
|
||||
path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'my-dir', 'my-dir.directive.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate directive ' + path.sep + 'my-dir from a child dir, gens under ' +
|
||||
it(path.sep + 'my-dir from a child dir, gens under ' +
|
||||
path.join('src', 'app'),
|
||||
() => {
|
||||
fs.mkdirsSync(path.join(root, 'tmp', 'foo', 'src', 'app', '1'));
|
||||
@ -136,10 +146,10 @@ describe('Acceptance: ng generate directive', function () {
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-dir', 'my-dir.directive.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate directive ..' + path.sep + 'my-dir from root dir will fail', () => {
|
||||
it('..' + path.sep + 'my-dir from root dir will fail', () => {
|
||||
return ng(['generate', 'directive', '..' + path.sep + 'my-dir']).then(() => {
|
||||
throw new SilentError(`ng generate directive ..${path.sep}my-dir from root dir should fail.`);
|
||||
}, (err) => {
|
||||
|
@ -11,6 +11,10 @@ var root = process.cwd();
|
||||
var conf = require('ember-cli/tests/helpers/conf');
|
||||
var Promise = require('ember-cli/lib/ext/promise');
|
||||
var SilentError = require('silent-error');
|
||||
const denodeify = require('denodeify');
|
||||
|
||||
const readFile = denodeify(fs.readFile);
|
||||
|
||||
|
||||
describe('Acceptance: ng generate pipe', function () {
|
||||
before(conf.setup);
|
||||
@ -32,10 +36,16 @@ describe('Acceptance: ng generate pipe', function () {
|
||||
});
|
||||
|
||||
it('ng generate pipe my-pipe', function () {
|
||||
return ng(['generate', 'pipe', 'my-pipe']).then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-pipe.pipe.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
});
|
||||
const appRoot = path.join(root, 'tmp/foo');
|
||||
const testPath = path.join(appRoot, 'src/app/my-pipe.pipe.ts');
|
||||
const appModulePath = path.join(appRoot, 'src/app/app.module.ts');
|
||||
return ng(['generate', 'pipe', 'my-pipe'])
|
||||
.then(() => expect(existsSync(testPath)).to.equal(true))
|
||||
.then(() => readFile(appModulePath, 'utf-8'))
|
||||
.then(content => {
|
||||
expect(content).matches(/import.*\bMyPipePipe\b.*from '.\/my-pipe.pipe';/);
|
||||
expect(content).matches(/declarations:\s*\[[^\]]+?,\n\s+MyPipePipe\n/m);
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate pipe test' + path.sep + 'my-pipe', function () {
|
||||
|
@ -1,4 +1,3 @@
|
||||
/*eslint-disable no-console */
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs-extra');
|
||||
@ -11,6 +10,10 @@ var root = process.cwd();
|
||||
var conf = require('ember-cli/tests/helpers/conf');
|
||||
var Promise = require('ember-cli/lib/ext/promise');
|
||||
var SilentError = require('silent-error');
|
||||
const denodeify = require('denodeify');
|
||||
|
||||
const readFile = denodeify(fs.readFile);
|
||||
|
||||
|
||||
describe('Acceptance: ng generate service', function () {
|
||||
before(conf.setup);
|
||||
@ -32,10 +35,17 @@ describe('Acceptance: ng generate service', function () {
|
||||
});
|
||||
|
||||
it('ng generate service my-svc', function () {
|
||||
return ng(['generate', 'service', 'my-svc']).then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-svc.service.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
});
|
||||
const appRoot = path.join(root, 'tmp/foo');
|
||||
const testPath = path.join(appRoot, 'src/app/my-svc.service.ts');
|
||||
const appModulePath = path.join(appRoot, 'src/app/app.module.ts');
|
||||
|
||||
return ng(['generate', 'service', 'my-svc'])
|
||||
.then(() => expect(existsSync(testPath)).to.equal(true))
|
||||
.then(() => readFile(appModulePath, 'utf-8'))
|
||||
.then(content => {
|
||||
expect(content).not.to.matches(/import.*\MySvcService\b.*from '.\/my-svc.service';/);
|
||||
expect(content).not.to.matches(/providers:\s*\[MySvcService\]/m);
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate service test' + path.sep + 'my-svc', function () {
|
||||
@ -68,7 +78,7 @@ describe('Acceptance: ng generate service', function () {
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'my-svc.service.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate service child-dir' + path.sep + 'my-svc from a child dir', () => {
|
||||
@ -87,7 +97,7 @@ describe('Acceptance: ng generate service', function () {
|
||||
var testPath = path.join(
|
||||
root, 'tmp', 'foo', 'src', 'app', '1', 'child-dir', 'my-svc.service.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate service child-dir' + path.sep + '..' + path.sep + 'my-svc from a child dir',
|
||||
@ -108,7 +118,7 @@ describe('Acceptance: ng generate service', function () {
|
||||
var testPath =
|
||||
path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'my-svc.service.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate service ' + path.sep + 'my-svc from a child dir, gens under ' +
|
||||
@ -128,7 +138,7 @@ describe('Acceptance: ng generate service', function () {
|
||||
.then(() => {
|
||||
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-svc.service.ts');
|
||||
expect(existsSync(testPath)).to.equal(true);
|
||||
}, err => console.log('ERR: ', err));
|
||||
});
|
||||
});
|
||||
|
||||
it('ng generate service ..' + path.sep + 'my-svc from root dir will fail', () => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user