Customizing generator options
Adding a TypeScript schema
To create a TypeScript schema to use in your generator function, define a TypeScript file next to your schema.json named schema.ts
. Inside the schema.ts
, define an interface to match the properties in your schema.json file, and whether they are required.
1export interface GeneratorOptions {
2 name: string;
3 type?: string;
4}
5
Import the TypeScript schema into your generator file and replace the any in your generator function with the interface.
1import { Tree, formatFiles, installPackagesTask } from '@nrwl/devkit';
2import { libraryGenerator } from '@nrwl/workspace/generators';
3
4export default async function (tree: Tree, schema: GeneratorOptions) {
5 await libraryGenerator(tree, { name: `${schema.name}-${schema.type || ''}` });
6 await formatFiles(tree);
7 return () => {
8 installPackagesTask(tree);
9 };
10}
11
Adding static options
Static options for a generator don't prompt the user for input. To add a static option, define a key in the schema.json file with the option name, and define an object with its type, description, and optional default value.
1{
2 "$schema": "http://json-schema.org/schema",
3 "id": "my-generator",
4 "type": "object",
5 "properties": {
6 "name": {
7 "type": "string",
8 "description": "Library name",
9 "$default": {
10 "$source": "argv",
11 "index": 0
12 }
13 },
14 "type": {
15 "type": "string",
16 "description": "Provide the library type, such as 'data-access' or 'state'"
17 }
18 },
19 "required": ["name"]
20}
21
If you run the generator without providing a value for the type, it is not included in the generated name of the library.
Adding dynamic prompts
Dynamic options can prompt the user to select from a list of options. To define a prompt, add a x-prompt
property to the option object, set the type to list, and define an items array for the choices.
1{
2 "$schema": "http://json-schema.org/schema",
3 "id": "my-generator",
4 "type": "object",
5 "properties": {
6 "name": {
7 "type": "string",
8 "description": "Library name",
9 "$default": {
10 "$source": "argv",
11 "index": 0
12 }
13 },
14 "type": {
15 "type": "string",
16 "description": "Provide the library type",
17 "x-prompt": {
18 "message": "Which type of library would you like to generate?",
19 "type": "list",
20 "items": [
21 {
22 "value": "data-access",
23 "label": "Data Access"
24 },
25 {
26 "value": "feature",
27 "label": "Feature"
28 },
29 {
30 "value": "state",
31 "label": "State Management"
32 }
33 ]
34 }
35 }
36 },
37 "required": ["name"]
38}
39
Running the generator without providing a value for the type will prompt the user to make a selection.
All configurable schema options
Properties tagged with ⚠️ are required. Others are optional.
Schema
1{
2 "properties": {
3 "name": {} // see Properties
4 },
5 "required": [],
6 "description": "",
7 "definitions": {}, // same as "properties"
8 "additionalProperties": false
9}
10
⚠️ properties
The properties of a generator. Properties are listed by name:
1{
2 "properties_name": {
3 // properties configuration
4 }
5}
6
The available options of the properties' configuration can be seen in the Properties section.
required
The property keys that are required. Example:
1{
2 "properties": {
3 "name": {
4 "type": "string"
5 },
6 "type": {
7 "type": "string"
8 }
9 },
10 "required": ["name"]
11}
12
In this example, the property name
is required, while the property type
is optional. You can define your TypeScript schema like this:
1interface Schema {
2 name: string; // required
3 type?: string; // optional
4}
5
description
The description of your schema for users to understand what they can do with the generator.
Example: A exception class generator.
definitions
Define an auxiliary schema in order to be reused and combined later on. Examples:
1{
2 "$id": "https://example.com/schemas/customer",
3 "$schema": "https://json-schema.org/draft/2020-12/schema",
4
5 "type": "object",
6 "properties": {
7 "first_name": { "type": "string" },
8 "last_name": { "type": "string" },
9 "shipping_address": { "$ref": "/schemas/address" },
10 "billing_address": { "$ref": "/schemas/address" }
11 },
12 "required": [
13 "first_name",
14 "last_name",
15 "shipping_address",
16 "billing_address"
17 ],
18
19 "$defs": {
20 "address": {
21 "$id": "/schemas/address",
22 "$schema": "http://json-schema.org/draft-07/schema#",
23
24 "type": "object",
25 "properties": {
26 "street_address": { "type": "string" },
27 "city": { "type": "string" },
28 "state": { "$ref": "#/definitions/state" }
29 },
30 "required": ["street_address", "city", "state"],
31
32 "definitions": {
33 "state": { "enum": ["CA", "NY", "... etc ..."] }
34 }
35 }
36 }
37}
38
In this example, we defined the state
in the definitions
and reference it later by $ref
.
Reference 1: JSON Schema > Definitions & References
Reference 2: Understanding JSON Schema > Extending Recursive Schemas
additionalProperties
Specify whether the additional properties in the input are allowed. Example:
1{
2 "type": "object",
3 "properties": {
4 "number": { "type": "number" },
5 "street_name": { "type": "string" },
6 "street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
7 },
8 "additionalProperties": false
9}
10
In this example, this schema only accepts the properties that are explicitly defined in the properties
object such like:
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue" }
Any additional properties will be considered invalid.
1{
2 "number": 1600,
3 "street_name": "Pennsylvania",
4 "street_type": "Avenue",
5 "direction": "NW"
6}
7
The above examples are from Understanding JSON schema > Additional Properties. There are more details in that tutorial.
Properties
1{
2 "type": "",
3 "required": [],
4 "enum": [],
5 "properties": {},
6 "oneOf": [],
7 "anyOf": [],
8 "allOf": [],
9 "items": [],
10 "alias": "",
11 "aliases": [],
12 "description": "",
13 "format": "",
14 "visible": false,
15 "default": "",
16 "$ref": "",
17 "$default": {
18 "$source": "argv",
19 "index": 0
20 },
21 "additionalProperties": false,
22 "x-prompt": {
23 "message": "",
24 "type": "",
25 "items": [],
26 "multiselect": false
27 },
28 "x-deprecated": false
29}
30
Options available in number
type:
1{
2 "multipleOf": 5,
3 "minimum": 5,
4 "exclusiveMinimum": 4,
5 "maximum": 200,
6 "exclusiveMaximum": 201
7}
8
Options available in string
type:
1{
2 "pattern": "\\d+",
3 "minLength": 10,
4 "maxLength": 100
5}
6
type
The type of the input. Can be one of string
, number
, bigint
, boolean
, object
or array
.
Example:
1{
2 "type": "string",
3 "minLength": "10"
4}
5
required
The property keys that are required. Example:
1{
2 "properties": {
3 "a": {
4 "type": "boolean"
5 },
6 "b": {
7 "type": "boolean"
8 }
9 },
10 "required": ["a"]
11}
12
In this example, the property a
is required, while the property b
is optional.
enum
Make sure that the value is in the enumeration. Example:
1{
2 "type": "string",
3 "enum": ["foo", "bar"]
4
5 // valid case: `foo`, `bar`
6 // invalid case: any other string like `hello`
7}
8
properties
The sub-properties of a property. Example:
1{
2 "index": {
3 "description": "Configures the generation of the application's HTML index.",
4 "type": "object",
5 "description": "",
6 "properties": {
7 "input": {
8 "type": "string",
9 "minLength": 1,
10 "description": "The path of a file to use for the application's generated HTML index."
11 },
12 "output": {
13 "type": "string",
14 "minLength": 1,
15 "default": "index.html",
16 "description": "The output path of the application's generated HTML index file. The full provided path will be used and will be considered relative to the application's configured output path."
17 }
18 },
19 "required": ["input"]
20 }
21}
22
In this example, the property index
is a object
, which accepts two properties: input
and output
.
oneOf
Only accepts a value that matches one of the condition properties. Example:
1{
2 "sourceMap": {
3 "description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.",
4 "default": true,
5 "oneOf": [
6 {
7 "type": "boolean"
8 },
9 {
10 "type": "string"
11 }
12 ]
13 }
14}
15
In this example, sourceMap
accepts a value whose type is either boolean
or string
. Another example:
1{
2 "optimization": {
3 "description": "Enables optimization of the build output.",
4 "oneOf": [
5 {
6 "type": "object",
7 "properties": {
8 "scripts": {
9 "type": "boolean",
10 "description": "Enables optimization of the scripts output.",
11 "default": true
12 },
13 "styles": {
14 "type": "boolean",
15 "description": "Enables optimization of the styles output.",
16 "default": true
17 }
18 },
19 "additionalProperties": false
20 },
21 {
22 "type": "boolean"
23 }
24 ]
25 }
26}
27
optimization
accepts either an object that includes scripts
and styles
properties, or a boolean that switches the optimization on or off.
anyOf
Only accepts a value that matches one of the condition properties. Example:
1{
2 "format": {
3 "type": "string",
4 "description": "ESLint Output formatter (https://eslint.org/docs/user-guide/formatters).",
5 "default": "stylish",
6 "anyOf": [
7 {
8 "enum": [
9 "stylish",
10 "compact",
11 "codeframe",
12 "unix",
13 "visualstudio",
14 "table",
15 "checkstyle",
16 "html",
17 "jslint-xml",
18 "json",
19 "json-with-metadata",
20 "junit",
21 "tap"
22 ]
23 },
24 { "minLength": 1 }
25 ]
26 }
27}
28
In this example, format
accepts a string listed in the enum
property, and/or a string whose minimum length is larger than 1.
allOf
Only accepts a value that matches all the condition properties. Example:
1{
2 "a": {
3 "type": "number",
4 "allOf": [{ "multipleOf": 5 }, { "multipleOf": 3 }]
5 }
6}
7
In this example, a
only accepts a value that can be divided by 5 and 3.
alias
The alias of this property. Example:
1{
2 "tags": {
3 "type": "string",
4 "description": "Add tags to the project (used for linting)",
5 "alias": "t"
6 },
7 "directory": {
8 "type": "string",
9 "description": "A directory where the project is placed",
10 "alias": "d"
11 }
12}
13
You can pass either --tags
or -t
to provide the value of the property tag
; either --directory
or -d
to provide the value of the property directory
.
aliases
Mostly same as alias
, but it can accept multiple aliases. Example:
1{
2 "directory": {
3 "description": "Directory where the generated files are placed.",
4 "type": "string",
5 "aliases": ["dir", "path"]
6 }
7}
8
You can pass either --dir
, --path
or even --directory
to provide the value of the property directory
.
description
The description for users of your property. Example:
1{
2 "flat": {
3 "description": "Flag to indicate if a directory is created.",
4 "type": "boolean",
5 "default": false
6 }
7}
8
format
The format of this property. Available options are: path
, html-selector
, etc. Example:
1{
2 "prefix": {
3 "type": "string",
4 "format": "html-selector",
5 "description": "The prefix to apply to generated selectors.",
6 "alias": "p"
7 }
8}
9
In this example, the value provided for prefix
should be formatted using the html-selector
schema.
visible
Indicate whether the property should be visible in the configuration UI. Example:
1{
2 "path": {
3 "format": "path",
4 "visible": false
5 }
6}
7
In this example, the path
won't be visible in the configuration UI, and will apply a default value.
default
The default value of this property. Example:
1{
2 "linter": {
3 "description": "The tool to use for running lint checks.",
4 "type": "string",
5 "enum": ["eslint", "tslint"],
6 "default": "eslint"
7 }
8}
9
In this example, linter
will pick eslint
when users do not provide the value explicitly.
$ref
Reference to a schema. Examples can be seen in the definitions
section.
$default
The default source of this property. The full declaration of $default
is:
1// with ? - optional
2// without ? - required
3// | - or
4$default?: { $source: 'argv'; index: number } | { $source: 'projectName' };
5
Example of $source: argv
:
1{
2 "name": {
3 "type": "string",
4 "description": "Library name",
5 "$default": {
6 "$source": "argv",
7 "index": 0
8 },
9 "x-prompt": "What name would you like to use for the library?",
10 "pattern": "^[a-zA-Z].*$"
11 }
12}
13
name
will pick the first argument of the command line as the default value.
Example of $source: projectName
:
1{
2 "project": {
3 "type": "string",
4 "description": "The name of the project.",
5 "alias": "p",
6 "$default": {
7 "$source": "projectName"
8 },
9 "x-prompt": "What is the name of the project for the migration?"
10 }
11}
12
project
will pick the default project name as the default value.
additionalProperties
See the above additionalProperties
section.
x-prompt
Prompt and help user to input the value of the property. It can be a string
or a object
. The full declaration is:
1// with ? - optional
2// without ? - required
3// | - or
4'x-prompt'?:
5 | string
6 | { message: string; type: string; items: any[]; multiselect?: boolean };
7
The string x-prompt
example:
1{
2 "name": {
3 "type": "string",
4 "description": "Library name",
5 "$default": {
6 "$source": "argv",
7 "index": 0
8 },
9 "x-prompt": "What is your desired library name?"
10 }
11}
12
The object example can be seen at Adding dynamic prompts.
⚠️ x-prompt
> message
The prompt message.
Example: Which type of library would you like to generate?
⚠️ x-prompt
> type
The type of the prompt.
⚠️ x-prompt
> items
The choice of the prompt. The x-prompt.type
must be list
. The declaration of items
is:
1// with ? - optional
2// without ? - required
3// | - or
4items?: (string | { name: string; message: string })[];
5
Example that contains value
and label
:
1{
2 "style": {
3 "description": "The file extension to be used for style files.",
4 "type": "string",
5 "default": "css",
6 "enum": ["css", "scss", "sass", "less"],
7 "x-prompt": {
8 "message": "Which stylesheet format would you like to use?",
9 "type": "list",
10 "items": [
11 {
12 "value": "css",
13 "label": "CSS"
14 },
15 {
16 "value": "scss",
17 "label": "SASS(.scss) [ http://sass-lang.com ]"
18 },
19 {
20 "value": "sass",
21 "label": "SASS(.sass) [ http://sass-lang.com ]"
22 },
23 {
24 "value": "less",
25 "label": "LESS [ http://lesscss.org ]"
26 }
27 ]
28 }
29 }
30}
31
x-prompt
> multiselect
Allow to multi-select in the prompt.
x-deprecated
Indicate whether the property is deprecated. Can be a boolean
or a string
. The boolean
example:
1{
2 "setupFile": {
3 "description": "The name of a setup file used by Jest. (use Jest config file https://jestjs.io/docs/en/configuration#setupfilesafterenv-array)",
4 "type": "string",
5 "x-deprecated": true
6 }
7}
8
This indicates that the property setupFile
is deprecated without a reason. The string
example:
1{
2 "tsSpecConfig": {
3 "type": "string",
4 "description": "The tsconfig file for specs.",
5 "x-deprecated": "Use the `tsconfig` property for `ts-jest` in the e2e project `jest.config.js` file. It will be removed in the next major release."
6 }
7}
8
This indicates that users should use the tsconfig
property rather than specify this property.
number
specific: multipleOf
Make sure that the number can be divided by the specified number. Example:
1{
2 "a": {
3 "type": "number",
4 "multipleOf": 5
5 }
6}
7
In this example, a
only accepts the value that can be divided by 5.
number
specific: minimum
Make sure that the number is greater than or equal to the specified number.
1{
2 "value": {
3 "type": "number",
4 "minimum": 5
5 }
6}
7
In this example, value
only accepts a value that is greater than or equal to 5 (value >= 5
).
You can read more at Understanding JSON schema.
number
specific: exclusiveMinimum
Make sure that the number is greater than the specified number.
1{
2 "value": {
3 "type": "number",
4 "exclusiveMinimum": 4
5 }
6}
7
In this example, value
only accepts a value that is greater than 4 (value > 4
).
You can read more at Understanding JSON schema.
number
specific: maximum
Make sure that the number is less than or equal to the specified number.
1{
2 "value": {
3 "type": "number",
4 "maximum": 200
5 }
6}
7
In this example, value
only accepts a value that is less than or equal to 200 (value <= 200
).
You can read more at Understanding JSON schema.
number
specific: exclusiveMaximum
Make sure that the number is less than the specified number.
1{
2 "value": {
3 "type": "number",
4 "maximum": 201
5 }
6}
7
In this example, value
only accepts a value that is less than 201 (value < 201
).
You can read more at Understanding JSON schema.
string
specific: pattern
Make sure that the string matches the Regexp pattern.
1{
2 "value": {
3 "type": "string",
4 "pattern": "^\\d+$"
5 }
6}
7
In this example, value
requires the value to match the ^\\d+$
pattern, which is a regular expression that matches a string that contains only digits.
string
specific: minLength
Make sure that the string length is greater than or equal to the specified value.
1{
2 "value": {
3 "type": "string",
4 "minLength": 10
5 }
6}
7
In this example, value
requires the value to be at least 10 characters long.
string
specific: maxLength
Make sure that the string length is less than or equal to the specified value.
1{
2 "value": {
3 "type": "string",
4 "maxLength": 10
5 }
6}
7
In this example, value
requires the value to be at most 10 characters long.
More information
The current configurable options (and its parse method) can be found here. You would need a basic knowledge of TypeScript to read this.
Most examples are referenced from the codebase of Nx. Thanks to everyone who have ever contributed to Nx!