diff --git a/.yo-rc.json b/.yo-rc.json new file mode 100644 index 00000000000..96c2176c546 --- /dev/null +++ b/.yo-rc.json @@ -0,0 +1,29 @@ +{ + "webpack-addons-ylvis": { + "inquirer": [ + { + "type": "input", + "name": "entry", + "message": "What is the name of the entry point in your application?" + }, + { + "type": "input", + "name": "output", + "message": "What is the name of the output directory in your application?" + }, + { + "type": "input", + "name": "resolve", + "message": "This is resolve peeps" + } + ], + "config": { + "entry": " ", + "output": " ", + "resolve": " " + }, + "childDependencies": [ + "webpack-addons-preact" + ] + } +} \ No newline at end of file diff --git a/__mocks__/parser/validate-options.mock.js b/__mocks__/creator/validate-options.mock.js similarity index 100% rename from __mocks__/parser/validate-options.mock.js rename to __mocks__/creator/validate-options.mock.js diff --git a/__mocks__/inquirer/initialize.mock.js b/__mocks__/inquirer/initialize.mock.js deleted file mode 100644 index e90feccfab6..00000000000 --- a/__mocks__/inquirer/initialize.mock.js +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint node/no-unsupported-features: 0 */ -'use strict'; -const Rx = require('rx'); -const questions = require('../../lib/utils/initial-questions'); -const exists = require('../../lib/utils/npm-exists'); -const initialConfig = require('../../lib/utils/initial-config'); - -//eslint-disable-next-line -const prompt = require('./prompt.mock'); - -async function npmPackagesExists(addon) { - let arr = []; - for(let k of addon) { - arr.push(await exists(k)); - } - return arr; -} - -function init(pkg, answer) { - // In the regular module, this is automatically an empty array, becomes `pkg.length == 0` - // We're adding manually the answers here as an argument for testing - if(!pkg) { - return prompt(Rx.Observable.from(questions), initialConfig, answer); - } - else { /* noop for now, manually testing addons */ } -} - - -module.exports = { - npmPackagesExists, - init -}; diff --git a/__mocks__/inquirer/prompt.mock.js b/__mocks__/inquirer/prompt.mock.js deleted file mode 100644 index cfe33f62789..00000000000 --- a/__mocks__/inquirer/prompt.mock.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -function prompt(questions, config, testAnswer) { - return questions.reduce( function(newOpts) { - return attachAnswers(newOpts, testAnswer); - }, Object.assign(config, require('../../lib/utils/initial-config'))) - .map(newOpts => checkEmptyAnswers(newOpts)); -} - -function attachAnswers(config, answer) { - let newConfig; - Object.keys(config).forEach( (configName) => { - if(answer[configName]) { - newConfig = Object.assign(config, { - [configName]: answer[configName] - }); - } - }); - return newConfig; -} - -function checkEmptyAnswers(config) { - for(let key in config) { - if(!config[key]) { - throw new Error('\nFound no answer given to property ' + - key + '\n'); - } - } - return config; -} - -module.exports = prompt; diff --git a/bin/webpack.js b/bin/webpack.js index 2d3b4dde3d0..1a5a67aac00 100755 --- a/bin/webpack.js +++ b/bin/webpack.js @@ -7,6 +7,9 @@ var path = require('path'); // var fs = require('fs'); // Local version replace global one + +process.title = 'webpack'; + try { var localWebpack = require.resolve(path.join(process.cwd(), 'node_modules', 'webpack-cli', 'bin', 'webpack.js')); if(localWebpack && path.relative(localWebpack, __filename) !== '') { diff --git a/lib/creator/generators/index.js b/lib/creator/generators/index.js new file mode 100644 index 00000000000..8433e0a06ee --- /dev/null +++ b/lib/creator/generators/index.js @@ -0,0 +1,30 @@ +const Generator = require('yeoman-generator'); +const Input = require('webpack-addons').Input; + + +module.exports = class WebpackGenerator extends Generator { + constructor(args, opts) { + super(args, opts); + this.myConfig = { + inquirer: [], + config: {}, + childDependencies: [] + }; + } + Inquirer() { + this.myConfig.inquirer = [ + Input('entry','What is the name of the entry point in your application?'), + Input('output','What is the name of the output directory in your application?') + ]; + } + Config() { + this.myConfig.config = { + entry: ' ', + output: ' ' + }; + } + childDependencies() { + this.myConfig.childDependencies = ['webpack-addons-preact']; + } + inject() {} +}; diff --git a/lib/creator/index.js b/lib/creator/index.js new file mode 100644 index 00000000000..4741ce342b7 --- /dev/null +++ b/lib/creator/index.js @@ -0,0 +1,41 @@ +const validateSchema = require('./utils/validateSchema.js'); +const webpackOptionsSchema = require('./utils/webpackOptionsSchema.json'); +const WebpackOptionsValidationError = require('./utils/WebpackOptionsValidationError'); +const initTransform = require('./init-transform'); +const chalk = require('chalk'); +/* +* @function creator +* +* Main function to build up a webpack configuration. +* Either throws an error if it doesn't match the webpack schema, +* or validates the filepaths of the options given. +* If a package is supplied, it finds the path of the package and runs inquirer +* +* @param { Array } pkgPaths - An Array of packages to run +* @param { } opts - An object containing webpackOptions or nothing +* @returns { } initTransform - Initializes the scaffold in yeoman +*/ + +module.exports = function creator(pkgPaths, opts) { + // null, config -> without package + // addon, null -> with package + // we're dealing with init, we need to change this later, as it may have been emptied by yeoman + if(!pkgPaths && !opts) { + initTransform(); + } + else if(pkgPaths) { + // this example app actually needs a refactor in order for it to work + initTransform(pkgPaths); + } + else if(!pkgPaths && opts) { + // scaffold is done + /* + const webpackOptionsValidationErrors = validateSchema(webpackOptionsSchema, initialWebpackConfig); + if (webpackOptionsValidationErrors.length) { + throw new WebpackOptionsValidationError(webpackOptionsValidationErrors); + } else { + process.stdout.write('\n' + chalk.green('Congratulations! Your new webpack config file is created!') + '\n'); + } + */ + } +}; diff --git a/lib/creator/init-transform.js b/lib/creator/init-transform.js new file mode 100644 index 00000000000..8e6d601081f --- /dev/null +++ b/lib/creator/init-transform.js @@ -0,0 +1,34 @@ +const fs = require('fs'); +const path = require('path'); +const yeoman = require('yeoman-environment'); +const Generator = require('yeoman-generator'); +const initGenerator = require('./generators/index'); + +/* +* @function initTransform +* +* Runs yeoman and in the future lets us grab the answers from the generators +* +* @param { Array } options - An Array of paths to match generators for +* @returns { } +*/ + +module.exports = function initTransform(options) { + const env = yeoman.createEnv(); + if(options) { + env.register(require.resolve(options), 'npm:app'); + env.run('npm:app'); + try { + let name = path.basename(options); + console.log('Done!'); + //eslint-disable-next-line + } catch (e) {} + } else { + env.registerStub(initGenerator, 'npm:app'); + env.run('npm:app'); + try { + console.log('Done!'); + // eslint-disable-next-line + } catch (e) {} + } +}; diff --git a/lib/parser/utils/WebpackOptionsValidationError.js b/lib/creator/utils/WebpackOptionsValidationError.js similarity index 100% rename from lib/parser/utils/WebpackOptionsValidationError.js rename to lib/creator/utils/WebpackOptionsValidationError.js diff --git a/lib/parser/utils/validateSchema.js b/lib/creator/utils/validateSchema.js similarity index 100% rename from lib/parser/utils/validateSchema.js rename to lib/creator/utils/validateSchema.js diff --git a/lib/parser/utils/webpackOptionsSchema.json b/lib/creator/utils/webpackOptionsSchema.json similarity index 100% rename from lib/parser/utils/webpackOptionsSchema.json rename to lib/creator/utils/webpackOptionsSchema.json diff --git a/lib/parser/validate-options.js b/lib/creator/validate-options.js similarity index 100% rename from lib/parser/validate-options.js rename to lib/creator/validate-options.js diff --git a/lib/parser/validate-options.spec.js b/lib/creator/validate-options.spec.js similarity index 77% rename from lib/parser/validate-options.spec.js rename to lib/creator/validate-options.spec.js index 06ea826334b..5ffa642da2a 100644 --- a/lib/parser/validate-options.spec.js +++ b/lib/creator/validate-options.spec.js @@ -1,8 +1,8 @@ 'use strict'; +const validateOptions = require('../../__mocks__/creator/validate-options.mock').validateOptions; + describe('validate-options', () => { - //eslint-disable-next-line - const {validateOptions} = require('../../__mocks__/parser/validate-options.mock'); it('should throw on fake paths', () => { expect(() => { diff --git a/lib/initialize.js b/lib/initialize.js index 60276d2b00f..81a107ff32b 100644 --- a/lib/initialize.js +++ b/lib/initialize.js @@ -1,8 +1,5 @@ -const questions = require('./utils/initial-questions'); const npmPackagesExists = require('./utils/npm-packages-exists'); -const prompt = require('./inquirer-prompt'); -const initialConfig = require('./utils/initial-config'); -const Rx = require('rx'); +const creator = require('./creator/index'); /* * @function initializeInquirer @@ -17,9 +14,7 @@ const Rx = require('rx'); module.exports = function initializeInquirer(pkg) { if(pkg.length == 0) { - return prompt(Rx.Observable.from(questions), initialConfig); - } - else { - return npmPackagesExists(pkg); + return creator(); } + return npmPackagesExists(pkg); }; diff --git a/lib/inquirer-prompt.js b/lib/inquirer-prompt.js deleted file mode 100644 index 6f4380cf08c..00000000000 --- a/lib/inquirer-prompt.js +++ /dev/null @@ -1,77 +0,0 @@ -const inquirer = require('inquirer'); -const chalk = require('chalk'); - -/* -* @function prompt -* -* Initializes an inquirer instance with questions provided from the --init feature -* -* @param { Object } questions - questions to be prompted in RxJS format -* @param { Object } config - Configuration passed from an addon to be included in -* answers, later sent down to the parser -* @returns { Function } Parser function that validates the answers, later transforming -* the answers to an webpack configuration -*/ - -module.exports = function prompt(questions, config) { - inquirer.prompt(questions).ui.process - .reduce(function (newOpts, ans) { - return attachAnswers(newOpts, ans); - }, Object.assign(config, require('./utils/initial-config'))) - .flatMap(newOpts => { - const parser = require('./parser/index'); - return parser(null, checkEmptyAnswers(newOpts)); - }) - .subscribeOnError( (err) => process.stdout.write(err.toString())); -}; - -/* -* @function attachAnswers -* -* Adds the answers from the inquirer instance if the type of the question is -* equal to the configuration property -* -* @param { Object } config - initial questions provided from --init -* @param { Object } answers - The answers passed from the inquirer instance -* @returns { Object } newConfig - An new object with the answers added to it -*/ - -function attachAnswers(config, answers) { - let newConfig; - Object.keys(config).forEach( (configName) => { - if(configName == answers.name) { - newConfig = Object.assign(config, { - [configName]: answers.answer - }); - } - }); - return newConfig; -} - -/* -* @function checkEmptyAnswers -* -* Checks for empty answers that didn't get attached from the prompt because it didn't match -* the given configuration property. If it finds an empty answer, it throws an error after logging -* each error to the console -* -* @param { Object } config - initial questions provided from --init -* @returns { Object } config - returns the configuration, -* as RxJS needs to have a return value to keep track of its context -*/ - -function checkEmptyAnswers(config) { - let errors = []; - for(let key in config) { - if(!config[key]) { - errors[key] = chalk.gray.bold('\nFound no answer given to property ') + - chalk.red.bold(key) + '\n'; - } - } - Object.keys(errors).map( (err) => { - console.error(errors[err]); - }).filter( () => { - process.exit(1); - }); - return config; -} diff --git a/lib/inquirer-prompt.spec.js b/lib/inquirer-prompt.spec.js deleted file mode 100644 index ed61002e696..00000000000 --- a/lib/inquirer-prompt.spec.js +++ /dev/null @@ -1,20 +0,0 @@ -/* eslint node/no-unsupported-features: 0 */ -'use strict'; - -describe('inquirer-prompt', () => { - //eslint-disable-next-line - const {init} = require('../__mocks__/inquirer/initialize.mock'); - - it('should provide with basic options if no argument is supplied to init', async () => { - let itInits = await init(null, { - entry: '1', output: '2' - }); - let matchObj = { - entry: '1', - output: '2' - }; - itInits.subscribe(function(answers) { - expect(answers).toMatchObject(matchObj); - }); - }); -}); diff --git a/lib/parser/index.js b/lib/parser/index.js deleted file mode 100644 index 0cc5ddcfa28..00000000000 --- a/lib/parser/index.js +++ /dev/null @@ -1,37 +0,0 @@ -const resolveTransform = require('./resolve-transform'); -const validateOptions = require('./validate-options'); -const validateSchema = require('./utils/validateSchema.js'); -const webpackOptionsSchema = require('./utils/webpackOptionsSchema.json'); -const WebpackOptionsValidationError = require('./utils/WebpackOptionsValidationError'); - -/* -* @function parser -* -* Main function to build up a webpack configuration. -* Either throws an error if it doesn't match the webpack schema, -* or validates the filepaths of the options given. -* If a package is supplied, it finds the package and runs inquirer -* -* TODO: This is going to be changed, as we need to build up transformation rules, -* and then check with validation. We should also make sure @validateOptions -* aren't being run for every object, as some objects in webpackOptions aren't filepaths. -* -* @param { Array } pkg - A package to be checked -* @param { } opts - An object containing webpackOptions or nothing -* @returns { } validateOptions|resolveTransform - -* Reruns inquirer or validates the given option paths if it matches the schema -*/ - -module.exports = function parser(pkg,opts) { - // null, config -> without package - // addon, null -> with package - if(opts) { - const webpackOptionsValidationErrors = validateSchema(webpackOptionsSchema, opts); - if(webpackOptionsValidationErrors.length) { - throw new WebpackOptionsValidationError(webpackOptionsValidationErrors); - } - validateOptions(opts); - } else { - resolveTransform(pkg); - } -}; diff --git a/lib/parser/resolve-transform.js b/lib/parser/resolve-transform.js deleted file mode 100644 index c02443ad8f8..00000000000 --- a/lib/parser/resolve-transform.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; -//TODO: Get the inq prompt and return the parser once again until there's no packages left to validate. -const Rx = require('rx'); -const prompt = require('../inquirer-prompt'); -const questions = require('../utils/initial-questions'); - -module.exports = function resolveTransform(pkg) { - const pkgQuestions = questions.concat(pkg.inquirer); - const pkgAddon = Rx.Observable.from(pkgQuestions); - - return prompt(pkgAddon, pkg.config); -}; diff --git a/lib/parser/transform.js b/lib/parser/transform.js deleted file mode 100644 index 2483ae3e4f8..00000000000 --- a/lib/parser/transform.js +++ /dev/null @@ -1,3 +0,0 @@ -// Hook up transformations with our options -module.exports = function transform(n) { //eslint-disable-line -}; diff --git a/lib/utils/initial-config.js b/lib/utils/initial-config.js deleted file mode 100644 index bd8e85a9d71..00000000000 --- a/lib/utils/initial-config.js +++ /dev/null @@ -1,12 +0,0 @@ -/* -* @object module.exports -* -* The initial objects later containing the information -* about entry and output paths in webpack -* -*/ - -module.exports = { - entry: {}, - output: {} -}; diff --git a/lib/utils/initial-questions.js b/lib/utils/initial-questions.js deleted file mode 100644 index 69dc1e51b95..00000000000 --- a/lib/utils/initial-questions.js +++ /dev/null @@ -1,31 +0,0 @@ -/* -* @function inquirerInput -* -* Utility function for inquirer to add an question to a inquirer -* instance -* -* @param { String } name - The name of the question -* @param { String } message - The question to be asked -* @returns { } - returns an inquirer question -*/ - -function inquirerInput(name, message) { - return ({ - type: 'input', - name: name, - message: message - }); -} -/* -* @array questions -* -* Adds the initial questions from the utility function above as an array. -* -*/ - -const questions = [ - inquirerInput('entry','What is the name of the entry point in your application?'), - inquirerInput('output','What is the name of the output directory in your application?') -]; - -module.exports = questions; diff --git a/lib/utils/initial-types.spec.js b/lib/utils/initial-types.spec.js deleted file mode 100644 index 4cad6e14cf3..00000000000 --- a/lib/utils/initial-types.spec.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -describe('initial-types', () => { - - const questions = require('./initial-questions'); - const config = require('./initial-config'); - - it('should return the initial questions', () => { - expect(questions).toMatchObject([ - { - 'message': 'What is the name of the entry point in your application?', - 'name': 'entry', - 'type': 'input' - }, - { - 'message': - 'What is the name of the output directory in your application?', - 'name': 'output', - 'type': 'input' - } - ]); - }); - it('should return the initial configuration objects', () => { - expect(config).toMatchObject({ - entry: {}, - output: {} - }); - }); - -}); diff --git a/lib/utils/npm-packages-exists.spec.js b/lib/utils/npm-packages-exists.spec.js deleted file mode 100644 index dd839b0fb61..00000000000 --- a/lib/utils/npm-packages-exists.spec.js +++ /dev/null @@ -1,13 +0,0 @@ -/* eslint node/no-unsupported-features: 0 */ -'use strict'; - -describe('npm-packages-exists', () => { - //eslint-disable-next-line - const {npmPackagesExists} = require('../../__mocks__/inquirer/initialize.mock'); - - it('should validate multiple packages if supplied', async () => { - let itValidatesAddon = await npmPackagesExists(['webpack-addons-ylvis', 'webpack-addons-noop']); - // BUG: We are making the values strings, so the tests pass - expect(itValidatesAddon.toString()).toBe([true, false].toString()); - }); -}); diff --git a/lib/utils/resolve-packages.js b/lib/utils/resolve-packages.js index b8168b16663..8f8f5587272 100644 --- a/lib/utils/resolve-packages.js +++ b/lib/utils/resolve-packages.js @@ -1,5 +1,5 @@ const spawn = require('cross-spawn'); -const parser = require('../parser/index'); +const creator = require('../creator/index'); const path = require('path'); const chalk = require('chalk'); @@ -29,29 +29,27 @@ function processPromise(child) { */ function spawnChild(pkg) { - //return spawn('npm', ['install', '--save', pkg], { stdio: 'inherit', customFds: [0, 1, 2] }); - return spawn('npm', ['install', '--save', pkg]); + return spawn('npm', ['install', '--save', pkg], { stdio: 'inherit', customFds: [0, 1, 2] }); + //return spawn('npm', ['install', '--save', pkg]); } /* * @function resolvePackages * -* Resolves the package after it is validated, later sending it to the parser +* Resolves the package after it is validated, later sending it to the creator * to be validated * * @param { String } pkg - The dependency to be installed -* @returns { } parser - Validates the dependency and builds +* @returns { } creator - Validates the dependency and builds * the webpack configuration */ module.exports = function resolvePackages(pkg) { Error.stackTraceLimit = 30; return processPromise(spawnChild(pkg)).then( () => { - let packageModule; try { let loc = path.join('..', '..', 'node_modules', pkg); - packageModule = require(loc); - parser(packageModule, null); + creator(loc, null); } catch(err) { console.log('Package wasn\'t validated correctly..'); console.log('Submit an issue for', pkg, 'if this persists'); diff --git a/lib/utils/resolve-packages.spec.js b/lib/utils/resolve-packages.spec.js index f1a870a32fa..8ee4d39bd50 100644 --- a/lib/utils/resolve-packages.spec.js +++ b/lib/utils/resolve-packages.spec.js @@ -1,8 +1,8 @@ 'use strict'; +const getLoc = require('../../__mocks__/inquirer/resolve.mock'); + describe('resolve-packages', () => { - // eslint-disable-next-line - const getLoc = require('../../__mocks__/inquirer/resolve.mock'); let moduleLoc; afterEach(() => { diff --git a/package.json b/package.json index 915b52b4632..99727a35865 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,11 @@ "rx": "^4.1.0", "supports-color": "^3.1.2", "webpack": "^2.2.0-rc.0", - "webpack-addons-ylvis": "0.0.27", - "yargs": "^6.5.0" + "webpack-addons": "0.0.20", + "webpack-addons-ylvis": "0.0.32", + "yargs": "^6.5.0", + "yeoman-environment": "^1.6.6", + "yeoman-generator": "^1.1.1" }, "devDependencies": { "ajv": "^4.11.3",