SAO File
TIP
Make sure you have read the guide for creating generators first!
SAO file, i.e. saofile.js lies in the root directory of a generator, it's used to create a generator instance which defines how to generate a new project.
Prompts
Type: Prompt[] | (this: Generator) => Prompt[] | Promise<Prompt[]>
prompts is a list of questions you want the user to answer.
All prompt types in Inquirer.js are supported here. There are a few differences in the prompt options though:
 when
 The when property in each prompt can also be a string which will be evaluated in the context of answers.
For example:
prompts: [
  {
    name: 'useBundler',
    message: 'Do you want a bundler'
  },
  {
    name: 'bundler',
    type: 'list',
    choices: ['webpack', 'parcel', 'poi'],
    when: 'useBundler'
  }
]
Basically it's equivalent to when: answers => answers.useBundler.
 store
 - Type: 
boolean - Default: 
false 
This is a property only for SAO, it is used to store user inputs so that SAO can use stored value as default value the next time. Note that different version of a generator stores the inputs in different places.
 default
 When default is a string, you can use {propName} to access properties on Generator Instance. e.g. Use default: '{gitUser.name}' to set the default value to the name of the git user. If you want to disable interpolations here, use double back-slash: \\{gitUser.name}.
Actions
Type: Action[] | (this: Generator) => Action[] | Promise<Action[]>
actions is used to manipulate files. There're 4 kinds of actions which share following options:
- type: Action type
 - when: Similar to 
prompts'swhen. 
 type: 'add'
 Add files from template directory to target directory.
actions: [
  {
    type: 'add',
    files: '**',
    filters: {
      'foo.js': '!someAnswer'
    }
  }
]
- files: One or more glob patterns, files are resolved relative to 
templateDir. - transform: Enable/Disable transformer.
- Default: 
true 
 - Default: 
 - transformInclude: One or more glob patterns, transform specific files with the transformer.
 - transformExclude: One or more glob patterns, DON'T transform specific files with the transformer.
 - filters: Exclude some files from being added. It's an object whose key is a glob pattern and the value should be either a boolean or a string which will be evaluated in the context of 
answers. - templateData: See templateData but for this action only.
 - templateDir: See templateDir but for this action only.
 
 type: 'modify'
 Modify files in target directory.
actions: [
  {
    type: 'modify',
    files: 'package.json',
    handler(data, filepath) {
      data.main = './foo.js'
      return data
    }
  }
]
- files: One or more glob patterns.
 - handler: The function we use to get new file contents. For 
.jsonwe automatically parse and stringify it. Otherwise you will receive raw string. 
 type: 'move'
 Move files in target directory.
actions: [
  {
    type: 'move',
    patterns: {
      'index-*.js': 'index.js'
    }
  }
]
- patterns: Each entry can be a glob pattern which is supposed to matches zero or one file in target directory.
 
If you need a dynamic file path based on user answers, you can achieve it by passing a function to actions
actions: function() {
  return [
    {
      type: 'move',
      patterns: {
        'module.ts': `${this.answers.name}.module.ts`
      }
    }
  ]
}
 type: 'remove'
 Remove files in target directory.
actions: [
  {
    type: 'remove',
    files: '**/*.ts',
    when: '!useTypescript'
  }
]
- files: One or more glob patterns to match the files that should be removed.
 
templateDir
- Type: 
string - Default: 
template 
The working directory for file action: add.
templateData
The files added via file action add will be interpolated using EJS syntax. By default the data you can access is:
answers: Directly access answers, e.g.<%= description %>to access the answer of project description.context: The generator instance. e.g.<%= context.npmClient %>
You can provide more data with the templateData option:
module.exports = {
  templateData: {
    date: new Date()
  }
}
Then you can access it via <%= date %> in your files.
templateData can also be a function which can access generator context via this:
module.exports = {
  templateData() {
    return {
      link: `https://github.com/${this.gitUser.name}`
    }
  }
}
Sub-Generators
You can use the subGenerators option to register a list of sub generators:
module.exports = {
  subGenerators: [
    {
      name: 'foo',
      // A path to the generator, relative to the saofile
      generator: './generators/foo'
    },
    {
      name: 'bar',
      // Or use a package, like `sao-bar` here
      // It's also resolved relative to the saofile
      generator: 'sao-bar'
    }
  ]
}
Then you can call these sub-generators like this:
sao sample:foo
sao sample:bar
Hooks
 prepare
 Type: (this: Generator) => Prompt
Executed before prompts and actions, you can throw an error here to exit the process:
module.exports = {
  // A generator that requires package.json in output directory
  async prepare() {
    const hasPkg = await this.fs.pathExists(this.resolve('package.json'))
    if (!hasPkg) {
      throw this.createError('Missing package.json')
      // You can also throw new Error('...') directly
      // While `this.createError` will only display error message without stack trace.
    }
  }
}
 completed
 Type: (this: Generator) => Prompt
Executed when all actions are completed.
module.exports = {
  async completed() {
    this.gitInit()
    await this.npmInstall()
    this.showCompleteTips()
  }
}