forked from plopjs/plop
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request plopjs#35 from amwmedia/nicoespeon-add-many-action
Nicoespeon add many action
- Loading branch information
Showing
37 changed files
with
589 additions
and
254 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import path from 'path'; | ||
import * as fspp from '../fs-promise-proxy'; | ||
|
||
export default function* addFile(data, cfg, plop) { | ||
// if not already an absolute path, make an absolute path from the basePath (plopfile location) | ||
const makeTmplPath = p => path.resolve(plop.getPlopfilePath(), p); | ||
const makeDestPath = p => path.resolve(plop.getDestBasePath(), p); | ||
|
||
var {template} = cfg; | ||
const fileDestPath = makeDestPath(plop.renderString(cfg.path || '', data)); | ||
|
||
try { | ||
if (cfg.templateFile) { | ||
template = yield fspp.readFile(makeTmplPath(cfg.templateFile)); | ||
} | ||
if (template == null) { template = ''; } | ||
|
||
// check path | ||
const pathExists = yield fspp.fileExists(fileDestPath); | ||
|
||
if (pathExists) { | ||
throw `File already exists\n -> ${fileDestPath}`; | ||
} else { | ||
yield fspp.makeDir(path.dirname(fileDestPath)); | ||
yield fspp.writeFile(fileDestPath, plop.renderString(template, data)); | ||
} | ||
|
||
// return the added file path (relative to the destination path) | ||
return fileDestPath.replace(path.resolve(plop.getDestBasePath()), ''); | ||
|
||
} catch(err) { | ||
if (typeof err === 'string') { | ||
throw err; | ||
} else { | ||
throw err.message || JSON.stringify(err); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export default function(action) { | ||
|
||
// it's not even an object, you fail! | ||
if (typeof action !== 'object') { | ||
return `Invalid action object: ${JSON.stringify(action)}`; | ||
} | ||
|
||
const {path} = action; | ||
|
||
if (typeof path !== 'string' || path.length === 0) { | ||
return `Invalid path "${path}"`; | ||
} | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import co from 'co'; | ||
import actionInterfaceTest from './_common-action-interface-check'; | ||
import addFile from './_common-action-add-file'; | ||
|
||
export default co.wrap(function* (data, cfg, plop) { | ||
const interfaceTestResult = actionInterfaceTest(cfg); | ||
if (interfaceTestResult !== true) { throw interfaceTestResult; } | ||
|
||
return yield addFile(data, cfg, plop); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import co from 'co'; | ||
import path from 'path'; | ||
import globby from 'globby'; | ||
import actionInterfaceTest from './_common-action-interface-check'; | ||
import addFile from './_common-action-add-file'; | ||
|
||
export default co.wrap(function* (data, cfg, plop) { | ||
const cfgWithCommonInterface = Object.assign({}, cfg, { | ||
path: cfg.destination | ||
}); | ||
const interfaceTestResult = actionInterfaceTest(cfgWithCommonInterface); | ||
if (interfaceTestResult !== true) { throw interfaceTestResult; } | ||
|
||
const templateFiles = resolveTemplateFiles(cfg.templateFiles, cfg.base, plop); | ||
const filesAdded = []; | ||
for (let templateFile of templateFiles) { | ||
const fileCfg = Object.assign({}, cfg, { | ||
path: resolvePath(cfg.destination, templateFile, cfg.base), | ||
templateFile: templateFile | ||
}); | ||
|
||
const addedPath = yield addFile(data, fileCfg, plop); | ||
filesAdded.push(addedPath); | ||
} | ||
|
||
return `${filesAdded.length} files added\n -> ${filesAdded.join('\n -> ')}`; | ||
}); | ||
|
||
function resolveTemplateFiles(templateFilesGlob, basePath, plop) { | ||
return globby.sync([templateFilesGlob], { cwd: plop.getPlopfilePath() }) | ||
.filter(isUnder(basePath)) | ||
.filter(isFile); | ||
} | ||
|
||
function isFile(file) { | ||
const fileParts = file.split(path.sep); | ||
const lastFilePart = fileParts[fileParts.length - 1]; | ||
const hasExtension = !!(lastFilePart.split('.')[1]); | ||
|
||
return hasExtension; | ||
} | ||
|
||
function isUnder(basePath = '') { | ||
return (path) => path.startsWith(basePath); | ||
} | ||
|
||
function resolvePath(destination, file, rootPath) { | ||
return path.join(destination, dropFileRootPath(file, rootPath)); | ||
} | ||
|
||
function dropFileRootPath(file, rootPath) { | ||
return (rootPath) ? file.replace(rootPath, '') : dropFileRootFolder(file); | ||
} | ||
|
||
function dropFileRootFolder(file) { | ||
const fileParts = file.split(path.sep); | ||
fileParts.shift(); | ||
|
||
return fileParts.join(path.sep); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import co from 'co'; | ||
import path from 'path'; | ||
import * as fspp from '../fs-promise-proxy'; | ||
import actionInterfaceTest from './_common-action-interface-check'; | ||
|
||
export default co.wrap(function* (data, cfg, plop) { | ||
const interfaceTestResult = actionInterfaceTest(cfg); | ||
if (interfaceTestResult !== true) { throw interfaceTestResult; } | ||
|
||
// if not already an absolute path, make an absolute path from the basePath (plopfile location) | ||
const makeTmplPath = p => path.resolve(plop.getPlopfilePath(), p); | ||
const makeDestPath = p => path.resolve(plop.getDestBasePath(), p); | ||
|
||
var {template} = cfg; | ||
const fileDestPath = makeDestPath(plop.renderString(cfg.path || '', data)); | ||
|
||
try { | ||
if (cfg.templateFile) { | ||
template = yield fspp.readFile(makeTmplPath(cfg.templateFile)); | ||
} | ||
if (template == null) { template = ''; } | ||
|
||
// check path | ||
const pathExists = yield fspp.fileExists(fileDestPath); | ||
|
||
if (!pathExists) { | ||
throw 'File does not exists'; | ||
} else { | ||
var fileData = yield fspp.readFile(fileDestPath); | ||
fileData = fileData.replace(cfg.pattern, plop.renderString(template, data)); | ||
yield fspp.writeFile(fileDestPath, fileData); | ||
} | ||
|
||
// return the modified file path (relative to the destination path) | ||
return fileDestPath.replace(path.resolve(plop.getDestBasePath()), ''); | ||
} catch(err) { | ||
if (typeof err === 'string') { | ||
throw err; | ||
} else { | ||
throw err.message || JSON.stringify(err); | ||
} | ||
} | ||
}); |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
'use strict'; | ||
|
||
import co from 'co'; | ||
import colors from 'colors'; | ||
import add from './actions/add'; | ||
import addMany from './actions/addMany'; | ||
import modify from './actions/modify'; | ||
|
||
export default function (plopfileApi) { | ||
var abort; | ||
|
||
// triggers inquirer with the correct prompts for this generator | ||
// returns a promise that resolves with the user's answers | ||
const runGeneratorPrompts = co.wrap(function* (genObject) { | ||
if (genObject.prompts == null) { | ||
throw Error(`${genObject.name} has no prompts`); | ||
} | ||
return yield plopfileApi.inquirer.prompt(genObject.prompts); | ||
}); | ||
|
||
// Run the actions for this generator | ||
const runGeneratorActions = co.wrap(function* (genObject, data) { | ||
var changes = []; // array of changed made by the actions | ||
var failures = []; // array of actions that failed | ||
var {actions} = genObject; // the list of actions to execute | ||
const customActionTypes = getCustomActionTypes(); | ||
const buildInActions = { add, addMany, modify }; | ||
const actionTypes = Object.assign({}, customActionTypes, buildInActions); | ||
|
||
abort = false; | ||
|
||
// if action is a function, run it to get our array of actions | ||
if (typeof actions === 'function') { actions = actions(data); } | ||
|
||
// if actions are not defined... we cannot proceed. | ||
if (actions == null) { | ||
throw Error(`${genObject.name} has no actions`); | ||
} | ||
|
||
// if actions are not an array, invalid! | ||
if (!(actions instanceof Array)) { | ||
throw Error(`${genObject.name} has invalid actions`); | ||
} | ||
|
||
for (let [actionIdx, action] of actions.entries()) { | ||
// bail out if a previous action aborted | ||
if (abort) { | ||
failures.push({ | ||
type: action.type || '', | ||
path: action.path || '', | ||
error: 'Aborted due to previous action failure' | ||
}); | ||
continue; | ||
} | ||
|
||
const actionIsFunction = typeof action === 'function'; | ||
const actionCfg = (actionIsFunction ? {} : action); | ||
const actionLogic = (actionIsFunction ? action : actionTypes[actionCfg.type]); | ||
|
||
if (typeof actionLogic !== 'function') { | ||
if (actionCfg.abortOnFail !== false) { abort = true; } | ||
failures.push({ | ||
type: action.type || '', | ||
path: action.path || '', | ||
error: `Invalid action (#${actionIdx + 1})` | ||
}); | ||
continue; | ||
} | ||
|
||
try { | ||
const actionResult = yield executeActionLogic(actionLogic, actionCfg, data); | ||
changes.push(actionResult); | ||
} catch(failure) { | ||
failures.push(failure); | ||
} | ||
} | ||
|
||
return { changes, failures }; | ||
}); | ||
|
||
// handle action logic | ||
const executeActionLogic = co.wrap(function* (action, cfg, data) { | ||
const failure = makeErrorLogger(cfg.type || 'function', '', cfg.abortOnFail); | ||
|
||
// convert any returned data into a promise to | ||
// return and wait on | ||
return yield Promise.resolve(action(data, cfg, plopfileApi)).then( | ||
// show the resolved value in the console | ||
result => ({ | ||
type: cfg.type || 'function', | ||
path: colors.blue(result.toString()) | ||
}), | ||
// a rejected promise is treated as a failure | ||
function (err) { | ||
throw failure(err.message || err.toString()); | ||
} | ||
); | ||
}); | ||
|
||
// request the list of custom actions from the plopfile | ||
function getCustomActionTypes() { | ||
return plopfileApi.getActionTypeList() | ||
.reduce(function (types, name) { | ||
types[name] = plopfileApi.getActionType(name); | ||
return types; | ||
}, {}); | ||
} | ||
|
||
// provide a function to handle action errors in a uniform way | ||
function makeErrorLogger(type, path, abortOnFail) { | ||
return function (error) { | ||
if (abortOnFail !== false) { abort = true; } | ||
return { type, path, error }; | ||
}; | ||
} | ||
|
||
return { | ||
runGeneratorActions, | ||
runGeneratorPrompts | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,11 @@ | ||
import 'core-js'; // es2015 polyfill | ||
import nodePlop from './modules/node-plop'; | ||
import nodePlop from './node-plop'; | ||
|
||
/** | ||
* Main node-plop module | ||
* | ||
* @param {string} plopfilePath - The absolute path to the plopfile we are interested in working with | ||
* @param {object} plopCfg - A config object to be passed into the plopfile when it's executed | ||
* @returns {object} the node-plop API for the plopfile requested | ||
*/ | ||
module.exports = nodePlop; |
Oops, something went wrong.