Skip to content

Commit

Permalink
feat(@angular/cli): Implement schematic workflow and workspace
Browse files Browse the repository at this point in the history
  • Loading branch information
Brocco authored and hansl committed Mar 23, 2018
1 parent 494b9f4 commit b056924
Show file tree
Hide file tree
Showing 160 changed files with 2,776 additions and 2,597 deletions.
2,587 changes: 1,453 additions & 1,134 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@
},
"homepage": "https://github.com/angular/angular-cli",
"dependencies": {
"@angular-devkit/architect": "angular/angular-devkit-architect-builds#9fa382c",
"@angular-devkit/build-webpack": "angular/angular-devkit-build-webpack-builds#9fa382c",
"@angular-devkit/core": "angular/angular-devkit-core-builds#9fa382c",
"@angular-devkit/schematics": "angular/angular-devkit-schematics-builds#9fa382c",
"@schematics/angular": "angular/schematics-angular-builds#9fa382c",
"@schematics/package-update": "angular/schematics-package-update-builds#9fa382c",
"@angular-devkit/architect": "angular/angular-devkit-architect-builds#caf9a5e",
"@angular-devkit/build-webpack": "angular/angular-devkit-build-webpack-builds#caf9a5e",
"@angular-devkit/core": "angular/angular-devkit-core-builds#caf9a5e",
"@angular-devkit/schematics": "angular/angular-devkit-schematics-builds#caf9a5e",
"@schematics/angular": "angular/schematics-angular-builds#caf9a5e",
"@schematics/package-update": "angular/schematics-package-update-builds#caf9a5e",
"ajv": "^6.1.1",
"chalk": "~2.2.0",
"common-tags": "^1.3.1",
Expand Down
53 changes: 20 additions & 33 deletions packages/@angular/cli/commands/add.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,33 @@
import chalk from 'chalk';
import { Command, CommandScope, Option } from '../models/command';
import { CommandScope, Option } from '../models/command';
import { parseOptions } from '../models/command-runner';
import { CliConfig } from '../models/config';
import { SchematicAvailableOptions } from '../tasks/schematic-get-options';
import { SchematicCommand } from '../models/schematic-command';
import { NpmInstall } from '../tasks/npm-install';

const SilentError = require('silent-error');


export default class AddCommand extends Command {
export default class AddCommand extends SchematicCommand {
readonly name = 'add';
readonly description = 'Add support for a library to your project.';
scope = CommandScope.inProject;
arguments = ['collection'];
options: Option[] = [];

private async _parseSchematicOptions(collectionName: string): Promise<any> {
const SchematicGetOptionsTask = require('../tasks/schematic-get-options').default;

const getOptionsTask = new SchematicGetOptionsTask({
ui: this.ui,
project: this.project
});

const availableOptions: SchematicAvailableOptions[] = await getOptionsTask.run({
const availableOptions: Option[] = await this.getOptions({
schematicName: 'ng-add',
collectionName,
});

const options = this.options.concat(availableOptions || []);

return parseOptions(this._rawArgs, options, []);
return parseOptions(this._rawArgs, options, [], this.argStrategy);
}

validate(options: any) {
const collectionName = options.collection;
const collectionName = options.argv[0];

if (!collectionName) {
throw new SilentError(
Expand All @@ -45,8 +39,8 @@ export default class AddCommand extends Command {
return true;
}

async run(commandOptions: any) {
const collectionName = commandOptions.collection;
async run(options: any) {
const collectionName = options.collection;

if (!collectionName) {
throw new SilentError(
Expand All @@ -57,41 +51,34 @@ export default class AddCommand extends Command {

const packageManager = CliConfig.fromGlobal().get('packageManager');

const NpmInstall = require('../tasks/npm-install').default;
const SchematicRunTask = require('../tasks/schematic-run').default;
const npmInstall: NpmInstall = require('../tasks/npm-install').default;

const packageName = collectionName.startsWith('@')
? collectionName.split('/', 2).join('/')
: collectionName.split('/', 1)[0];

// We don't actually add the package to package.json, that would be the work of the package
// itself.
let npmInstall = new NpmInstall({
ui: this.ui,
project: this.project,
packageManager,
await npmInstall(
packageName,
save: false,
});

const schematicRunTask = new SchematicRunTask({
ui: this.ui,
project: this.project
});

await npmInstall.run();
this.logger,
packageManager,
this.project.root,
false);

// Reparse the options with the new schematic accessible.
commandOptions = await this._parseSchematicOptions(collectionName);
options = await this._parseSchematicOptions(collectionName);

const runOptions = {
taskOptions: commandOptions,
schematicOptions: options,
workingDir: this.project.root,
collectionName,
schematicName: 'ng-add',
allowPrivate: true,
dryRun: false,
force: false,
};

await schematicRunTask.run(runOptions);
await this.runSchematic(runOptions);
}
}
110 changes: 18 additions & 92 deletions packages/@angular/cli/commands/generate.ts
Original file line number Diff line number Diff line change
@@ -1,142 +1,76 @@
import { Command, CommandScope, Option } from '../models/command';
import { CommandScope, Option } from '../models/command';
import chalk from 'chalk';
import { CliConfig } from '../models/config';
import {
getCollection,
getEngineHost
} from '../utilities/schematics';
import { SchematicAvailableOptions } from '../tasks/schematic-get-options';
import { oneLine } from 'common-tags';
import { getConfigValues } from '../tasks/schematic-get-config-values';
import { SchematicCommand } from '../models/schematic-command';

const { cyan } = chalk;

export default class GenerateCommand extends Command {
export default class GenerateCommand extends SchematicCommand {
public readonly name = 'generate';
public readonly description = 'Generates and/or modifies files based on a schematic.';
public static aliases = ['g'];
public readonly scope = CommandScope.inProject;
public arguments = ['schematic'];
public options: Option[] = [
{
name: 'dry-run',
type: Boolean,
default: false,
aliases: ['d'],
description: 'Run through without making any changes.'
},
{
name: 'force',
type: Boolean,
default: false,
aliases: ['f'],
description: 'Forces overwriting of files.'
},
{
name: 'app',
type: String,
description: 'Specifies app name to use.'
}
...this.coreOptions
];

private initialized = false;
public async initialize(options: any): Promise<void> {
public async initialize(options: any) {
if (this.initialized) {
return Promise.resolve();
return;
}
this.initialized = true;

const [collectionName, schematicName] = this.parseSchematicInfo(options);

if (!!schematicName) {
const SchematicGetOptionsTask = require('../tasks/schematic-get-options').default;

const getOptionsTask = new SchematicGetOptionsTask({
ui: this.ui,
project: this.project
});

const availableOptions: SchematicAvailableOptions[] = await getOptionsTask.run({
const availableOptions: Option[] = await this.getOptions({
schematicName,
collectionName,
});
let anonymousOptions: string[] = [];

if (availableOptions) {
const nameOption = availableOptions.filter(opt => opt.name === 'name')[0];
if (nameOption) {
anonymousOptions = [...anonymousOptions, 'name'];
}
} else {
anonymousOptions = [...anonymousOptions, 'name'];
}

if (collectionName === '@schematics/angular' && schematicName === 'interface') {
anonymousOptions = [...anonymousOptions, 'type'];
}

this.arguments = this.arguments.concat(anonymousOptions);
this.options = this.options.concat( availableOptions || []);
}
}

validate(options: any): boolean | Promise<boolean> {
if (!options.schematic) {
if (!options._[0]) {
this.logger.error(oneLine`
The "ng generate" command requires a
schematic name to be specified.
For more details, use "ng help".`);

return false;
}
if (options.name && /^\d/.test(options.name)) {
this.logger.error(oneLine`The \`ng generate ${options.schematic} ${options.name}\`
file name cannot begin with a digit.`);

return false;
}
return true;
}

public run(options: any) {
const cwd = process.env.PWD;
const [collectionName, schematicName] = this.parseSchematicInfo(options);

const workingDir = cwd.replace(this.project.root, '');
const pathOptions = this.getPathOptions(options, workingDir);
options = { ...options, ...pathOptions };

options = getConfigValues(this.name, options.schematic, this.options, options);
// remove the schematic name from the options
options._ = options._.slice(1);

const SchematicRunTask = require('../tasks/schematic-run').default;
const schematicRunTask = new SchematicRunTask({
ui: this.ui,
project: this.project
return this.runSchematic({
collectionName,
schematicName,
schematicOptions: options,
debug: options.debug,
dryRun: options.dryRun,
force: options.force,
});

const schematicOptions = this.stripLocalOptions(options);
return schematicRunTask.run({
taskOptions: schematicOptions,
dryRun: options.dryRun,
force: options.force,
workingDir: this.project.root,
collectionName,
schematicName
});
}

protected getPathOptions(options: any, workingDir: string): any {
return this.options
.filter(o => o.format === 'path')
.map(o => o.name)
.filter(name => options[name] === undefined)
.reduce((acc: any, curr) => acc[curr] = workingDir, {});
}

private parseSchematicInfo(options: any) {
let collectionName: string = CliConfig.getValue('defaults.schematics.collection');

let schematicName = options.schematic;
let schematicName = options._[0];

if (schematicName) {
if (schematicName.match(/:/)) {
Expand Down Expand Up @@ -165,12 +99,4 @@ export default class GenerateCommand extends Command {
this.logger.info(cyan(` ng generate <schematic> --help`));
}
}

private stripLocalOptions(options: any): any {
const opts = Object.assign({}, options);
delete opts.dryRun;
delete opts.force;
delete opts.app;
return opts;
}
}

0 comments on commit b056924

Please sign in to comment.