Edited at

Schematicsでちょっとだけgenerateされるファイルをカスタマイズ


発端

ng g s --name myでservice作る時に

import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root'
})
export class MyService {

constructor() { }
}

が作られますが

import { Injectable } from '@angular/core';

@Injectable({
providedIn: null
})
export class MyService {

constructor() { }
}

としたいなぁと。

少しだけ変更したいだけなので、もともとのパラメータの役割とかも引き継ぎたい。そんな時

ng g --helpをして出てくる schematicを利用して試してみる。

$ ng g --help

Generates and/or modifies files based on a schematic.
usage: ng generate <schematic> [options]

arguments:
schematic
The schematic or collection:schematic to generate.

options:
--defaults
When true, disables interactive input prompts for options with a default.
--dry-run (-d)
When true, runs through and reports activity without writing out results.
--force (-f)
When true, forces overwriting of existing files.
--help
Shows a help message for this command in the console.
--interactive
When false, disables interactive input prompts.


やってみた

npm i -g @angular-devkit/schematics-cliしたり

schematics blank my-schematicsしたり

等の説明は省略します。

構成としてはこんな感じで作ります。

my-schematics

├── README.md
├── package-lock.json
├── package.json
├── src
│   ├── collection.json
│   ├── component
│   │   ├── files
│   │   │   └── __name@dasherize@if-flat__
│   │   │   ├── __name@dasherize__.component.__styleExt__.template
│   │   │   ├── __name@dasherize__.component.html.template
│   │   │   ├── __name@dasherize__.component.spec.ts.template
│   │   │   └── __name@dasherize__.component.ts.template
│   │   ├── index.ts
│   ├── index_spec.ts
│   │   ├── schema.json
│   │   └── schema.ts
│   └── service
│   ├── files
│   │   └── __name@dasherize@if-flat__
│   │   ├── __name@dasherize__.service.spec.ts.template
│   │   └── __name@dasherize__.service.ts.template
│   ├── index.ts
│   ├── index_spec.ts
│   ├── schema.json
│   └── schema.ts
└── tsconfig.json

npm i @schematics/angular@schematics/angularを入れておきます。


my-schematics/src/collection.ts

{

"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"component": {
"aliases": [ "c" ],
"description": "create component",
"factory": "./component",
"schema": "./component/schema.json"
},
"service": {
"aliases": [ "s" ],
"description": "create service",
"factory": "./service",
"schema": "./service/schema.json"
}
}
}



my-schematics/src/service/index.ts

import { Rule, chain } from '@angular-devkit/schematics';

import buildService from '@schematics/angular/service';
import { Schema as ServiceOptions } from './schema';

export default function (options: ServiceOptions): Rule {

return chain([
buildService( {...options} ),
]);
}



my-schematics/src/service/schema.ts

import { Schema as ServiceSchema } from '@schematics/angular/service/schema';

export interface Schema extends ServiceSchema {
root?: boolean;
}



my-schematics/src/service/schema.json

{

"$schema": "http://json-schema.org/schema",
"id": "SchematicsAngularService",
"title": "Angular Service Options Schema",
"type": "object",
"description": "Creates a new, generic service definition in the given or default project.",
"properties": {
"name": {
"type": "string",
"description": "The name of the service.",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "What name would you like to use for the service?"
},
"path": {
"type": "string",
"format": "path",
"description": "The path at which to create the service, relative to the workspace root.",
"visible": false
},
"project": {
"type": "string",
"description": "The name of the project.",
"$default": {
"$source": "projectName"
}
},
"flat": {
"type": "boolean",
"default": true,
"description": "When true (the default), creates files at the top level of the project."
},
"spec": {
"type": "boolean",
"default": true,
"description": "When true (the default), generates a \"spec.ts\" test file for the new service.",
"x-deprecated": "Use \"skipTests\" instead."
},
"skipTests": {
"type": "boolean",
"description": "When true, does not create \"spec.ts\" test files for the new service.",
"default": false
},
"lintFix": {
"type": "boolean",
"default": false,
"description": "When true, applies lint fixes after generating the pipe."
},
"root": "--- 追加部分 ---",
"root": {
"type": "boolean",
"default": false,
"description": "When true, provided in will be 'root'. If not null"
}
},
"required": [
"name"
]
}



my-schematics/src/service/files/__name@dasherize@if-flat__/__name@dasherize__.service.ts.template

import { Injectable } from '@angular/core';

@Injectable({
providedIn: <% if(root) { %>'root'<% } else { %>null<% } %>
})
export class <%= classify(name) %>Service {

constructor() { }
}


これでnpm run buildし、あとはpublishするなり、privateや相対パスリポジトリとしてinstallするなりします。

installしたプロジェクト内で

ng g my-schematics:service --name my

import { Injectable } from '@angular/core';

@Injectable({
providedIn: null
})
export class MyService {

constructor() { }
}

ng g --helpすると使えるschematicsとして一覧に追加される

$ ng g --help

Generates and/or modifies files based on a schematic.
usage: ng generate <schematic> [options]

arguments:
schematic
The schematic or collection:schematic to generate.

options:
--defaults
When true, disables interactive input prompts for options with a default.
--dry-run (-d)
When true, runs through and reports activity without writing out results.
--force (-f)
When true, forces overwriting of existing files.
--help
Shows a help message for this command in the console.
--interactive
When false, disables interactive input prompts.

Available Schematics:
Collection "my-schematics" (default):
appShell
application
class
component
directive
enum
guard
interface
library
module
pipe
service
serviceWorker
universal

続く