diff --git a/.babelrc b/.babelrc index c13c5f6..831f20a 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,4 @@ { - "presets": ["es2015"] + "presets": ["es2015"], + "plugins": ["transform-object-rest-spread"] } diff --git a/lib/cli.js b/lib/cli.js index 1a6851b..04c79b9 100755 --- a/lib/cli.js +++ b/lib/cli.js @@ -7,18 +7,21 @@ import {parse} from 'nomnom'; import glob from 'glob'; import parseProps from './parseProps'; import generate from './generate'; +import setPackageProps from './packageExtras'; +import {getPackage, getPackageProps, mergePackages} from './mergePack'; import fs from 'fs'; import mkdirp from 'mkdirp'; import path from 'path'; -import {properties, defaults} from './properties'; +import {packageProperties, properties, defaults} from './properties'; import { blackBright as grey, greenBright as green, yellowBright as yellow, redBright as red} from 'cli-color'; -const schema = {properties}; - +let schema = {properties}; +const existingPackage = getPackage(); +schema = getPackageProps(existingPackage, packageProperties, schema); Object.assign(prompt, { message: '>'.green, @@ -56,8 +59,10 @@ const scaffold = args => { prompt.override = args; getPrompt() + .then(setPackageProps(existingPackage)) .then(parseProps(defaults)) .then(generate(srcContent)) + .then(mergePackages(getPackage(), destinations)) .then(saveCompiled) .then(() => { console.log(green('OK'), 'Generation completed', '\n'); diff --git a/lib/mergePack.js b/lib/mergePack.js new file mode 100644 index 0000000..7b974cb --- /dev/null +++ b/lib/mergePack.js @@ -0,0 +1,51 @@ +import fs from 'fs'; +import path from 'path'; +import merge from 'lodash.merge'; +import parseAuthor from 'parse-author'; +import parseGithub from 'parse-github-url'; + +export const getPackage = () => { + let origPackage; + try { + origPackage = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8')); + } catch (e) { + origPackage = false; + } + return origPackage; +}; + +export const getPackageProps = (existingPackage, packageProperties, schema) => { + let gitHub, authorInfo; + if (existingPackage) { + console.log(`Existing package.json file has been used to get default variables.`); + schema.properties = {...schema.properties, ...packageProperties}; + schema.properties['package.name'].default = existingPackage.name; + schema.properties['package.description'].default = existingPackage.description; + // Try to get Name, Email & GitHub Username + if (existingPackage.repository && existingPackage.repository.url) { + gitHub = parseGithub(existingPackage.repository.url).owner; + schema.properties['user.github'].default = gitHub; + } + if (existingPackage.author) { + authorInfo = parseAuthor(existingPackage.author); + if (authorInfo.name) { + schema.properties['user.name'].default = authorInfo.name; + } + if (authorInfo.email) { + schema.properties['user.email'].default = authorInfo.email; + } + } + } + return schema; +}; + +export const mergePackages = (origPackage, destinations) => compiledFiles => { + if (origPackage) { + const newPackagePath = path.join(process.cwd(), 'package.json'); + const packageIndex = destinations.indexOf(newPackagePath); + const packageContents = JSON.parse(compiledFiles[packageIndex]); + const mergedPack = JSON.stringify(merge(packageContents, origPackage), null, 2); + compiledFiles[packageIndex] = mergedPack; + } + return compiledFiles; +}; diff --git a/lib/packageExtras.js b/lib/packageExtras.js new file mode 100644 index 0000000..5875109 --- /dev/null +++ b/lib/packageExtras.js @@ -0,0 +1,16 @@ +import templatePackage from '../template/package.json'; + +const packageFields = ['dependencies', 'devDependencies', 'scripts']; + +const setPackageProps = userPackage => props => { + packageFields.forEach((field) => { + if (props[`package.${field}`]) { + props[`package.${field}`] = {...templatePackage[field], ...userPackage[field]}; + } else { + props[`package.${field}`] = {...templatePackage[field]}; + } + }); + return props; +}; + +export default setPackageProps; diff --git a/lib/properties.js b/lib/properties.js index e407699..6f1ae18 100644 --- a/lib/properties.js +++ b/lib/properties.js @@ -12,7 +12,31 @@ export const defaults = { }, package: { name: '', - description: '' + description: '', + dependencies: {}, + devDependencies: {}, + scripts: {} + } +}; + +export const packageProperties = { + 'package.dependencies': { + description: 'Keep existing dependencies? (true|false): ', + message: 'Required', + type: 'boolean', + required: true + }, + 'package.devDependencies': { + description: 'Keep existing devDependencies? (true|false): ', + message: 'Required', + type: 'boolean', + required: true + }, + 'package.scripts': { + description: 'Keep existing scripts? (true|false): ', + message: 'Required', + type: 'boolean', + required: true } }; diff --git a/package.json b/package.json index 8b8320e..e1d219a 100644 --- a/package.json +++ b/package.json @@ -45,18 +45,22 @@ "cli-color": "^1.0.0", "glob": "^5.0.14", "handlebars": "^4.0.0", + "lodash.merge": "^3.3.2", "mkdirp": "^0.5.1", "nomnom": "^1.8.1", "prompt": "^0.2.14" }, "devDependencies": { "babel-eslint": "^4.1.1", + "babel-plugin-transform-object-rest-spread": "^6.5.0", "blue-tape": "^0.1.10", "eslint": "^1.3.1", "faucet": "0.0.1", "husky": "^0.10.1", "isparta": "^3.0.4", "nsp": "^2.0.2", + "parse-author": "^0.2.0", + "parse-github-url": "^0.3.0", "rimraf": "^2.4.3", "sinon": "^1.16.1", "tap-xunit": "^1.1.1" diff --git a/template/package.json b/template/package.json index ffa3489..68f313e 100644 --- a/template/package.json +++ b/template/package.json @@ -28,11 +28,11 @@ "precommit": "npm run lint", "prepush": "npm run validate" }, - "devDependencies": { + "devDependencies": { "babel-cli": "^6.2.0", "babel-core": "^6.0.0", "babel-preset-es2015": "^6.1.18", - "babel-preset-stage-1":"^6.0.0", + "babel-preset-stage-1": "^6.0.0", "babel-eslint": "^4.0.5", "babel-loader": "^6.0.0", "babel-plugin-transform-object-assign": "^6.1.18", diff --git a/test/lib/mergePack-test.js b/test/lib/mergePack-test.js new file mode 100644 index 0000000..9ad579d --- /dev/null +++ b/test/lib/mergePack-test.js @@ -0,0 +1,51 @@ +import {test} from 'blue-tape'; +import {mergePackages} from '../../lib/mergePack'; +import path from 'path'; + +test('Merge Packages', t => { + + const packPath = path.join(process.cwd(), 'package.json'); + const templatedFile = JSON.stringify({ + name: 'templatePackage', + description: 'This should not overwrite stuff', + main: 'src/index.js', + scripts: { + start: 'do a lotta new stuff', + test: 'mocha this package' + } + }); + const originalFile = { + name: 'originalPackage', + description: 'This should not be overwritten by a template', + scripts: { + start: 'do a lotta old stuff', + lint: 'lint this package' + } + }; + const mergedFile = { + name: 'originalPackage', + description: 'This should not be overwritten by a template', + main: 'src/index.js', + scripts: { + start: 'do a lotta old stuff', + lint: 'lint this package', + test: 'mocha this package' + } + }; + + t.ok(mergePackages instanceof Function, 'should be function'); + + t.ok(mergePackages() instanceof Function, 'should return function'); + + t.deepEqual(mergePackages(false, [packPath])([templatedFile]), [templatedFile], + 'should return the generated package when there is no pre-existing package.json'); + + const merger = mergePackages(originalFile, [packPath])([templatedFile])[0]; + + t.deepEqual(JSON.parse(merger), mergedFile, + 'should merge an existing package.json with template and return results'); + + t.ok(merger.match(/\s\s/), 'merged package should be formatted with spaces'); + + t.end(); +});