Skip to content

Commit

Permalink
feat(ng-schematics): add component generate schematic
Browse files Browse the repository at this point in the history
  • Loading branch information
damyanpetev committed May 28, 2019
1 parent 90a22f0 commit a0e86c2
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 42 deletions.
25 changes: 18 additions & 7 deletions packages/igx-templates/IgniteUIForAngularTemplate.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
AddTemplateArgs, ControlExtraConfiguration,
TemplateDependency, TypeScriptFileUpdate, Util
AddTemplateArgs, ControlExtraConfiguration, FsFileSystem, IFileSystem,
Template, TemplateDependency, TypeScriptFileUpdate, Util
} from "@igniteui-cli/core";
import * as path from "path";

export class IgniteUIForAngularTemplate {
export class IgniteUIForAngularTemplate implements Template {
public components: string[];
public controlGroup: string;
public listInComponentTemplates: boolean = true;
Expand All @@ -15,7 +15,7 @@ export class IgniteUIForAngularTemplate {
public framework: string = "angular";
public projectType: string = "igx-ts";
public hasExtraConfiguration: boolean = false;
public packages = [];
public packages: string[] = [];

public dependencies: TemplateDependency[] = [];

Expand All @@ -34,6 +34,17 @@ export class IgniteUIForAngularTemplate {
return [path.join(this.rootPath, "files")];
}

private _fs: IFileSystem;
public get virtFs(): IFileSystem {
if (!this._fs) {
this._fs = new FsFileSystem();
}
return this._fs;
}
public set virtFs(v: IFileSystem) {
this._fs = v;
}

constructor(private rootPath: string) {
}

Expand Down Expand Up @@ -78,11 +89,11 @@ export class IgniteUIForAngularTemplate {
const TsUpdate: typeof TypeScriptFileUpdate =
require("@igniteui-cli/core/typescript").TypeScriptFileUpdate;

if (!(options && options.skipRoute) && Util.fileExists("src/app/app-routing.module.ts")) {
if (!(options && options.skipRoute) && this.virtFs.fileExists("src/app/app-routing.module.ts")) {
//1) import the component class name,
//2) and populate the Routes array with the path and component
//for example: { path: 'combo', component: ComboComponent }
const routingModule = new TsUpdate(path.join(projectPath, "src/app/app-routing.module.ts"));
const routingModule = new TsUpdate(path.join(projectPath, "src/app/app-routing.module.ts"), this.virtFs);
routingModule.addRoute(
path.join(projectPath, `src/app/${this.folderName(name)}/${this.fileName(name)}.component.ts`),
this.fileName(name), //path
Expand All @@ -93,7 +104,7 @@ export class IgniteUIForAngularTemplate {
//3) add an import of the component class from its file location.
//4) populate the declarations portion of the @NgModule with the component class name.
const mainModulePath = path.join(projectPath, `src/app/${modulePath}`);
const mainModule = new TsUpdate(mainModulePath);
const mainModule = new TsUpdate(mainModulePath, this.virtFs);
mainModule.addDeclaration(
path.join(projectPath, `src/app/${this.folderName(name)}/${this.fileName(name)}.component.ts`),
modulePath !== "app.module.ts"
Expand Down
48 changes: 48 additions & 0 deletions packages/ng-schematics/src/component/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
apply, chain, MergeStrategy, mergeWith,
Rule, SchematicContext, SchematicsException, template, Tree, url } from "@angular-devkit/schematics";
import { NodePackageInstallTask } from "@angular-devkit/schematics/tasks";
import { IgniteUIForAngularTemplate } from "@igniteui-angular/templates";
import { NgTreeFileSystem, Util } from "@igniteui-cli/core";
import { SchematicsTemplateManager } from "../SchematicsTemplateManager";
import { ComponentOptions } from "./schema";

export function component(options: ComponentOptions): Rule {
return (_tree: Tree, context: SchematicContext) => {

// TODO: validate template name + nameFromPath, id, modulePath, skipRoute
// TODO: jump into prompt session w/o provided id?

if (!options.templateInst) {
if (!options.template) {
throw new SchematicsException("argument template id must be provided");
}
const templateManager = new SchematicsTemplateManager();
const projLib = templateManager.getProjectLibrary("angular", "igx-ts");
options.templateInst = projLib.getTemplateById(options.template) as IgniteUIForAngularTemplate;
}

const config = options.templateInst.generateConfig(options.name, {});

context.logger.info(`Generating ${options.templateInst.name} with name: ${options.name}`);
// TODO: reuse component schematic?
return chain([
...options.templateInst.templatePaths.map(templatePath =>
mergeWith(
apply(url(Util.relativePath(__filename, templatePath, true)), [
template(config)
]
), MergeStrategy.Overwrite)
),
(host: Tree, _context: SchematicContext) => {
if (options.templateInst) {
for (const packageName of options.templateInst.packages) {
context.addTask(new NodePackageInstallTask({ packageName, workingDirectory: options.projectName }));
}
options.templateInst.virtFs = new NgTreeFileSystem(host);
options.templateInst.registerInProject("", options.name, { skipRoute: options.skipRoute });
}
}
]);
};
}
14 changes: 14 additions & 0 deletions packages/ng-schematics/src/component/index_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Tree } from "@angular-devkit/schematics";
import { SchematicTestRunner } from "@angular-devkit/schematics/testing";
import * as path from "path";

const collectionPath = path.join(__dirname, "../collection.json");

describe("component", () => {
it("works", () => {
const runner = new SchematicTestRunner("schematics", collectionPath);
const tree = runner.runSchematic("component", {}, Tree.empty());

expect(tree.files).toEqual([]);
});
});
29 changes: 29 additions & 0 deletions packages/ng-schematics/src/component/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "http://json-schema.org/schema",
"id": "SchematicsAngularComponent",
"title": "Angular Component Options Schema",
"type": "object",
"description": "Creates a new Ignite UI for Angular component in the given or default project.",
"properties": {
"name": {
"type": "string",
"description": "The name of the component.",
"$default": {
"$source": "argv",
"index": 1
},
"x-prompt": "What name would you like to use for the component?"
},
"template": {
"type": "string",
"description": "Template ID, such as 'grid', 'combo', etc.",
"$default": {
"$source": "argv",
"index": 0
}
}
},
"required": [
"name"
]
}
9 changes: 9 additions & 0 deletions packages/ng-schematics/src/component/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IgniteUIForAngularTemplate } from "@igniteui-angular/templates";

export abstract class ComponentOptions {
public templateInst?: IgniteUIForAngularTemplate;
public template?: string;
public name: string;
public skipRoute?: boolean;
public projectName: string;
}
10 changes: 0 additions & 10 deletions packages/ng-schematics/src/igniteui-angular-schematics/index.ts

This file was deleted.

This file was deleted.

7 changes: 4 additions & 3 deletions packages/ng-schematics/src/ng-new/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { ProjectLibrary, Util } from "@igniteui-cli/core";
import { defer, Observable } from 'rxjs';
import { NewProjectOptions } from "../app-projects/schema";
import { ComponentOptions } from "../component/schema";
import { SchematicsPromptSession } from "../prompt/SchematicsPromptSession";
import { SchematicsTemplateManager } from "../SchematicsTemplateManager";
import { OptionsSchema } from "./schema";
Expand All @@ -22,9 +23,10 @@ export function newProject(options: OptionsSchema): Rule {
return (_host: Tree, context: IgxSchematicContext) => {
context.logger.info(`Generating ${options.name}`);

let projectName = options.name;
let projLibrary: ProjectLibrary;
let projectOptions: NewProjectOptions;
const addedComponents: any[] = [];
const addedComponents: ComponentOptions[] = [];
const templateManager = new SchematicsTemplateManager();
const prompt = new SchematicsPromptSession(templateManager, addedComponents);

Expand All @@ -34,7 +36,6 @@ export function newProject(options: OptionsSchema): Rule {
return chain([
(tree: Tree, context: IgxSchematicContext): Observable<Tree> => {
return defer<Tree>(async function() { // TODO rxjs types?
let projectName = options.name;

if (!prompt.nameIsValid(options.name)) {
projectName = await prompt.getUserInput({
Expand Down Expand Up @@ -89,7 +90,7 @@ export function newProject(options: OptionsSchema): Rule {
},
(_tree: Tree, _context: IgxSchematicContext) => {
if (addedComponents.length) {
return chain(addedComponents);
return chain(addedComponents.map(x => schematic("component", Object.assign(x, { projectName }))));
}
},
move(options.name)
Expand Down
17 changes: 11 additions & 6 deletions packages/ng-schematics/src/prompt/SchematicsPromptSession.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Rule, schematic, Tree } from "@angular-devkit/schematics";
import { Tree } from "@angular-devkit/schematics";
import { IgniteUIForAngularTemplate } from "@igniteui-angular/templates";
import {
BasePromptSession, BaseTemplateManager, Framework, IUserInputOptions,
ProjectLibrary, ProjectTemplate, PromptTaskContext, Task, ProjectConfig, NgTreeFileSystem } from "@igniteui-cli/core";
NgTreeFileSystem, ProjectConfig, ProjectLibrary, ProjectTemplate, PromptTaskContext, Task } from "@igniteui-cli/core";
import { ComponentOptions } from "../component/schema";

export class SchematicsPromptSession extends BasePromptSession {

constructor(templateManager: BaseTemplateManager, private rulesChain: Rule[]) {
constructor(templateManager: BaseTemplateManager, private rulesChain: ComponentOptions[]) {
super(templateManager);
this.config = ProjectConfig.getConfig();
}
Expand Down Expand Up @@ -47,10 +49,13 @@ export class SchematicsPromptSession extends BasePromptSession {
if (context.template.hasExtraConfiguration) {
await this.customizeTemplateTask(context.template);
}
this.rulesChain.push(schematic("component", {

const options: ComponentOptions = {
name,
template: context.template
}));
projectName: "",
templateInst: context.template as IgniteUIForAngularTemplate
};
this.rulesChain.push(options);
return true;
};
}
Expand Down

0 comments on commit a0e86c2

Please sign in to comment.