ember-cli/ember-cli

View on GitHub
lib/commands/generate.js

Summary

Maintainability
B
4 hrs
Test Coverage
A
98%
'use strict';

const path = require('path');
const chalk = require('chalk');
const Command = require('../models/command');
const Blueprint = require('../models/blueprint');
const mergeBlueprintOptions = require('../utilities/merge-blueprint-options');
const { merge, reject } = require('ember-cli-lodash-subset');
const EOL = require('os').EOL;
const SilentError = require('silent-error');

const UNKNOWN_BLUEPRINT_ERROR =
  'The `ember generate` command requires a ' +
  'blueprint name to be specified. ' +
  'For more details, use `ember help`';

module.exports = Command.extend({
  name: 'generate',
  description: 'Generates new code from blueprints.',
  aliases: ['g'],
  works: 'insideProject',

  availableOptions: [
    { name: 'dry-run', type: Boolean, default: false, aliases: ['d'] },
    { name: 'verbose', type: Boolean, default: false, aliases: ['v'] },
    { name: 'pod', type: Boolean, default: false, aliases: ['p', 'pods'] },
    { name: 'classic', type: Boolean, default: false, aliases: ['c'] },
    { name: 'dummy', type: Boolean, default: false, aliases: ['dum', 'id'] },
    { name: 'in-repo-addon', type: String, default: null, aliases: ['in-repo', 'ir'] },
    { name: 'lint-fix', type: Boolean, default: true },
    {
      name: 'in',
      type: String,
      default: null,
      description:
        'Runs a blueprint against an in repo addon. ' + 'A path is expected, relative to the root of the project.',
    },
    {
      name: 'typescript',
      type: Boolean,
      aliases: ['ts'],
      description: 'Generates a version of the blueprint written in TypeScript (if available).',
    },
  ],

  anonymousOptions: ['<blueprint>'],

  beforeRun: mergeBlueprintOptions,

  run(commandOptions, rawArgs) {
    let blueprintName = rawArgs[0];

    if (!blueprintName) {
      return Promise.reject(new SilentError(UNKNOWN_BLUEPRINT_ERROR));
    }

    let taskArgs = {
      args: rawArgs,
    };

    if (this.settings && this.settings.usePods && !commandOptions.classic) {
      commandOptions.pod = true;
    }

    if (commandOptions.in) {
      let relativePath = path.relative(this.project.root, commandOptions.in);
      commandOptions.in = path.resolve(relativePath);
    }

    let taskOptions = merge(taskArgs, commandOptions || {});

    if (this.project.initializeAddons) {
      this.project.initializeAddons();
    }

    return this.runTask('GenerateFromBlueprint', taskOptions);
  },

  printDetailedHelp(options) {
    this.ui.writeLine(this.getAllBlueprints(options));
  },

  addAdditionalJsonForHelp(json, options) {
    json.availableBlueprints = this.getAllBlueprints(options);
  },

  getAllBlueprints(options) {
    let lookupPaths = this.project.blueprintLookupPaths();
    let blueprintList = Blueprint.list({ paths: lookupPaths });

    let output = '';

    let singleBlueprintName;
    if (options.rawArgs) {
      singleBlueprintName = options.rawArgs[0];
    }

    if (!singleBlueprintName && !options.json) {
      output += `${EOL}  Available blueprints:${EOL}`;
    }

    let collectionsJson = [];

    blueprintList.forEach(function (collection) {
      let result = this.getPackageBlueprints(collection, options, singleBlueprintName);
      if (options.json) {
        let collectionJson = {};
        collectionJson[collection.source] = result;
        collectionsJson.push(collectionJson);
      } else {
        output += result;
      }
    }, this);

    if (singleBlueprintName && !output && !options.json) {
      output = chalk.yellow(`The '${singleBlueprintName}' blueprint does not exist in this project.`) + EOL;
    }

    if (options.json) {
      return collectionsJson;
    } else {
      return output;
    }
  },

  getPackageBlueprints(collection, options, singleBlueprintName) {
    let verbose = options.verbose;
    let blueprints = collection.blueprints;

    if (!verbose) {
      blueprints = reject(blueprints, 'overridden');
    }

    let output = '';

    if (blueprints.length && !singleBlueprintName && !options.json) {
      output += `    ${collection.source}:${EOL}`;
    }

    let blueprintsJson = [];

    blueprints.forEach(function (blueprint) {
      let singleMatch = singleBlueprintName === blueprint.name;
      if (singleMatch) {
        verbose = true;
      }
      if (!singleBlueprintName || singleMatch) {
        // this may add default keys for printing
        blueprint.availableOptions.forEach(this.normalizeOption);

        if (options.json) {
          blueprintsJson.push(blueprint.getJson(verbose));
        } else {
          output += blueprint.printBasicHelp(verbose) + EOL;
        }
      }
    }, this);

    if (options.json) {
      return blueprintsJson;
    } else {
      return output;
    }
  },
});

module.exports.ERRORS = {
  UNKNOWN_BLUEPRINT_ERROR,
};