【问题标题】:Yeoman Generator: Copy template to root directory based on prompt choiceYeoman Generator:根据提示选择将模板复制到根目录
【发布时间】:2017-05-11 11:26:59
【问题描述】:

我正在尝试添加到Yeoman generator,它提供了将模板文件复制到root-foldernew-folder 的功能,具体取决于用户是否选择选项bowerinternal .

  • 选择internal 将创建一个名为elementName 变量的文件夹并复制模板文件
  • 选择bower 只会将模板文件复制到它们所在的当前目录

提示:我添加了以下type: confirm 提示:

var prompts = [{
  type: 'input',
  name: 'elementName',
  message: 'What is the name of the new element?',
  validate: (input) => (input.indexOf('-') === -1 ? 'Element name needs a \'-\'' : true),
  default :this.appname
},

{
  when: (props) => (props.elementImplementation === 'bower'),
  type: 'confirm',
  name: 'noDirectory',
  message: 'Should I create a directory for you?',
  default: false
},

{
  when: (props) => (props.elementImplementation === 'internal'),
  type: 'confirm',
  name: 'yesDirectory',
  message: 'Should I create a directory for you?',
  default: true
},

默认值:我已经设置了默认值:

this.props.noDirectory = this.props.noDirectory || false;
this.props.yesDirectory = this.props.yesDirectory || true;

写作:writing: 函数内部是我苦苦挣扎的地方。我已将elementName 添加到destinationPath(但它不起作用):

if (this.props.elementImplementation === 'internal') {
  // copy all general files.
  this.fs.copyTpl(
    `${this.templatePath()}/**/!(_)*`,
    this.destinationPath(`${elementName}`),
    this.props
  );

  this.fs.copyTpl(
   `${this.templatePath()}/.!(gitignore)*`,
    this.destinationRoot(),
    this.props
  );

  // get over npm publish quirk with file rename.
  this.fs.copyTpl(
    this.templatePath('.gitignorefile'),
    this.destinationPath('.gitignore'),
    this.props
  );

}

据我了解,我需要修改destinationPathdestinationRoot,但我不确定...

另外,我发现这个 SO answer 说您可以使用 npm 模块 mkdirp 创建一个文件夹,但我不确定这是否需要与 Yeoman 默认为我们提供的内容一起使用。


这是我正在使用的完整 index.js 文件:

'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');


module.exports = yeoman.Base.extend({

  constructor: function () {
    yeoman.Base.apply(this, arguments);
    this.appname = this._dashedCaseFromSpaces(this.appname);
  },

  // Have Yeoman greet the user.
  prompting: function () {

    this.log(yosay(
      'Welcome to the solid ' + chalk.red('generator-polymer-init-element-scaffold') + ' generator!'
    ));

    var prompts = [{
      type: 'input',
      name: 'elementName',
      message: 'What is the name of the new element?',
      validate: (input) => (input.indexOf('-') === -1 ? 'Element name needs a \'-\'' : true),
      default :this.appname
    },

    {
      type: 'list',
      name: 'elementVersion',
      message: 'What version of element are you building?',
      choices: ['1.x', '2.0','vanilla'],
      default: '1.x'
    },

    {
      type: 'list',
      name: 'elementType',
      message: 'What type of element are you building?',
      choices: this._elementOptions,
      default: 'component'
    },

    {
      when: (props) => (props.elementType === 'behavior' && props.elementVersion ===  '1.x'),
      type: 'input',
      name: 'behaviorNameSpace',
      message: 'What namespace would you like for your behavior?',
      default: 'fooBehavior',
      store   : true
    },

    {
      when: (props) => (props.elementType === 'behavior' && props.elementVersion ===  '1.x'),
      type: 'confirm',
      name: 'isBehaviorExtend',
      message: 'Is this a behavior extension?',
      default: false

    },

    {
      type: 'list',
      name: 'elementImplementation',
      message: 'Is this a bower element or internal element?',
      choices: ['bower', 'internal'],
      default: 'bower'
    },
    {
      when: (props) => (props.elementImplementation === 'bower'),
      type: 'confirm',
      name: 'noDirectory',
      message: 'Should I create a directory for you?',
      default: false
    },
    {
      when: (props) => (props.elementImplementation === 'internal'),
      type: 'confirm',
      name: 'yesDirectory',
      message: 'Should I create a directory for you?',
      default: true
    },
    {
      when: (props) => (props.elementImplementation === 'bower'),
      type: 'input',
      name: 'elementDescription',
      message: 'What does this element do?',
      default: 'nothing yet'
    },
    {
      when: (props) => (props.elementImplementation === 'bower'),
      type: 'input',
      name: 'authorName',
      message: 'What is your name?',
      default: 'author',
      store   : true
    },
    {
      when: (props) => (props.elementImplementation === 'bower'),
      type: 'input',
      name: 'gitDomain',
      message: 'Where does your repo reside?',
      default: 'github',
      store   : true
    },
    {
      when: (props) => (props.elementImplementation === 'bower'),
      type: 'input',
      name: 'orgName',
      message: 'What is your organiztion\'s repo?',
      default: 'org',
      store   : true
    },
    {
      when: (props) => (props.elementImplementation === 'bower'),
      type: 'input',
      name: 'elementGrouping',
      message: 'What group does your element belong to?',
      default: 'none',
      store   : true
    },
    // // TODO: implement regex for tests inclusion
    // {
    //   when: (props) => (props.elementImplementation === 'bower'),
    //   type: 'confirm',
    //   name: 'testable',
    //   message: 'Would you like to include tests ?',
    //   default: true
    // },
    {
      when: (props) => (props.elementImplementation === 'bower'/*&& props.testable*/),
      type: 'confirm',
      name: 'sauceLabs',
      message: 'Would you like to use sauce labs for cross browser testing ?',
      default: true
    }];


    return this.prompt(prompts).then(function (props) {
      this.props = props;
      this.props.className = this._cappedCaseFromDashed(props.elementName);

      // need to have values
      this._setDefaultValues();

    }.bind(this));
  },

  _cappedCaseFromDashed: function(element) {
    if( typeof element !== "undefined") {
      return element.split('-').map( (name) => {
        return name.charAt(0).toUpperCase() + name.slice(1);
      }).join('');
    }
    return element
  },

  _dashedCaseFromSpaces: function(name) {
    if( typeof name !== "undefined") {
      return name.replace(/\s/g,'-');
    }
  },

  _elementOptions:function(props) {
    if(props.elementVersion === '1.x') {
      return ['component','style', 'behavior']
    } else if(props.elementVersion === '2.0') {
      return ['component','behavior']
    } else {
      return ['component']
    }
  },

  _setDefaultValues: function() {

    this.props.authorName = this.props.authorName || 'internal';
    this.props.orgName = this.props.orgName || 'internal';
    this.props.noDirectory = this.props.noDirectory || false;
    this.props.yesDirectory = this.props.yesDirectory || true;
    this.props.elementDescription = this.props.elementDescription || 'internal';
    this.props.elementGrouping = this.props.elementGrouping || 'internal';
    this.props.testable = this.props.testable || false;
    this.props.sauceLabs = this.props.sauceLabs || false;
    this.props.gitDomain = this.props.gitDomain || 'github';

  },

  writing: function () {

    const elementVersion = this.props.elementVersion;
    const elementType = this.props.elementType;
    const elementName = this.props.elementName;

    this._sharedWrites();
    this._versionWrite(elementVersion, elementType, elementName);
  },

  _sharedWrites: function() {

    // copy all general files.
    this.fs.copyTpl(
      `${this.templatePath()}/**/!(_)*`,
      this.destinationPath(),
      this.props
    );

    // copy over dot files for bower.
    if (this.props.elementImplementation === 'internal') {
      this.fs.copyTpl(
      `${this.templatePath()}/.!(gitignore)*`,
        this.destinationRoot(`${elementName}`),
        this.props
      );

      // get over npm publish quirk with file rename.
      this.fs.copyTpl(
        this.templatePath('.gitignorefile'),
        this.destinationPath('.gitignore'),
        this.props
      );

    }

    // copy over dot files for bower.
    if (this.props.elementImplementation === 'bower') {
      this.fs.copyTpl(
      `${this.templatePath()}/.!(gitignore)*`,
        this.destinationRoot(),
        this.props
      );

      // get over npm publish quirk with file rename.
      this.fs.copyTpl(
        this.templatePath('.gitignorefile'),
        this.destinationPath('.gitignore'),
        this.props
      );

    }
  },


  _versionWrite:function(version, elementType, elementName) {

    // Copy the main html file.
    this.fs.copyTpl(
      this.templatePath(`src/${version}/${elementType}/_${elementType}.html`),
      this.destinationPath(`${elementName}.html`),
      this.props
    );


    //If it is a style type you need to copy over the file
    if(elementType === 'style') {
      this.fs.copyTpl(
        this.templatePath(`src/${version}/${elementType}/_${elementType}-classes.html`),
      this.destinationPath(`${elementName}-classes.html`),
      this.props
      );
    } 

    // Each Version 
    if(version === '1.x') {
      this._PolymerOneWrite(version,elementType, elementName);
    }

    else if(version === '2.0') {
      this._PolymerTwoWrite(version,elementType, elementName);
    }

    else if(version === 'vanilla') {
      this._VanillaWrite(version, elementType, elementName);
    }


    // else if(elementType === 'behavior') {
    //     this.fs.copyTpl(
    //       this.templatePath(`demo/_${elementType}-demo.html`),
    //       this.destinationPath(`demo/${elementName}-demo.html`),
    //       this.props
    //     );
    //   } else {
    //     // copy over the script
    //     this.fs.copyTpl(
    //       this.templatePath(`src/${version}/${elementType}/_${elementType}.js`),
    //       this.destinationPath(`${elementName}.js`),
    //       this.props
    //     );

    //     // copy the component styles. css for vanilla and html for polymer
    //     const fileExt = elementType == 'vanilla' ? 'css': 'html';
    //     this.fs.copyTpl(
    //       this.templatePath(`src/${version}/${elementType}/_${elementType}-styles.${fileExt}`),
    //       this.destinationPath(`${elementName}-styles.${fileExt}`),
    //       this.props
    //     );
    //  }


  },

  _PolymerOneWrite: function(version,elementType, elementName) {

    if(elementType === 'component') {
      this.fs.copyTpl(
          this.templatePath(`src/${version}/${elementType}/_${elementType}.js`),
          this.destinationPath(`${elementName}.js`),
          this.props
      );

      this.fs.copyTpl(
        this.templatePath(`src/${version}/${elementType}/_${elementType}-styles.html`),
        this.destinationPath(`${elementName}-styles.html`),
        this.props
      );
    }

    if(elementType === 'style') {
      this.fs.copyTpl(
        this.templatePath(`src/${version}/${elementType}/_${elementType}-classes.html`),
        this.destinationPath(`${elementName}-classes.html`),
        this.props
      );
    } 

    if(elementType === 'behavior') {
        this.fs.copyTpl(
          this.templatePath(`demo/_${elementType}-demo.html`),
          this.destinationPath(`demo/${elementName}-demo.html`),
          this.props
        );
    }

  },
  _PolymerTwoWrite: function(elementType, elementName) {

    if(elementType === 'component' || elementType === 'behavior') {

      this.fs.copyTpl(
        this.templatePath(`src/${version}/${elementType}/_${elementType}.js`),
        this.destinationPath(`${elementName}.js`),
        this.props
      );

      this.fs.copyTpl(
        this.templatePath(`src/${version}/${elementType}/_${elementType}-styles.html`),
        this.destinationPath(`${elementName}-styles.html`),
        this.props
      );
    }

  },
  _VanillaOneWrite: function(version, elementType, elementName) {

    if(elementType === 'component') {
      this.fs.copyTpl(
        this.templatePath(`src/${version}/${elementType}/_${elementType}.js`),
        this.destinationPath(`${elementName}.js`),
        this.props
      );

      this.fs.copyTpl(
        this.templatePath(`src/${version}/${elementType}/_${elementType}-styles.css`),
        this.destinationPath(`${elementName}-styles.css`),
        this.props
      );

    }
  },

  install: function () {

    this.installDependencies({
      bower:this.props.elementImplementation === 'bower',
      npm: true
    });
  }

});

【问题讨论】:

    标签: node.js generator yeoman yeoman-generator yo


    【解决方案1】:

    不需要任何花哨的魔法。只需将要创建的文件夹名称连接到目的地即可:

    this.destinationPath(this.elementName)
    

    然后文件将被复制到一个名为元素的新文件夹中。

    【讨论】:

    • 感谢您在此问题上提供帮助。每当我这样做时,都会收到以下错误消息:Uncaught exception: TypeError: Path must be a string. Received undefined
    • 我尝试了this.destinationPath('${this.elementName}'),它不再产生错误,但是它创建了一个undefined 文件夹而不是elementName 以及一个空白的node_modules 文件夹。不过仍在努力。
    • @Oneezy 听起来像 this.elementNameundefined
    • 终于搞定了。出于某种原因,我不得不遵循以下语法:this.destinationPath(`${elementName}/${elementName}/*`) ...不太清楚为什么?我还必须将`${elementName}/${elementName}/*` 放在destinationPath 的每个实例中。可能有更聪明的方法来做到这一点
    • @Oneezy 你可以用this.destinationRoot('new/destination/')改变目标根目录
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-21
    • 2016-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多