Skip to content

Commit 4dfdc0b

Browse files
authored
feat: use plop for scaffolding (#10)
1 parent 32dda3e commit 4dfdc0b

File tree

15 files changed

+645
-187
lines changed

15 files changed

+645
-187
lines changed

packages/cli-core/GitUtilities.js

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,14 @@ exports.assertMatchesRemote = async () => {
6060
throw new Error('The remote differs from the local working tree');
6161
};
6262

63-
exports.addRemote = (dest, name, org) => {
64-
try {
65-
execa('git', ['remote', 'add', 'origin', exports.remoteUrl(name, org)], {
66-
cwd: dest,
67-
stdio: 'inherit',
68-
});
69-
} catch (err) {
63+
exports.addRemote = (dest, name, org) =>
64+
execa('git', ['remote', 'add', 'origin', exports.remoteUrl(name, org)], {
65+
cwd: dest,
66+
stdio: 'inherit',
67+
}).catch(err => {
7068
if ((err.stderr || '').match(/remote origin already exists/)) return;
7169
throw err;
72-
}
73-
};
70+
});
7471

7572
exports.addTag = async tag => {
7673
if (await hasTag(tag)) return;

packages/init/addHelpers.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = plop => {
2+
plop.setHelper('eq', (a, b) => a === b);
3+
plop.setHelper('neq', (a, b) => a !== b);
4+
5+
plop.setHelper('iff', (a, b, c) => (a ? b : c));
6+
7+
plop.setHelper('year', () => new Date().getFullYear());
8+
};

packages/init/command.js

Lines changed: 8 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
1-
const path = require('path');
2-
const fs = require('fs-extra');
3-
const execa = require('execa');
4-
const inquirer = require('inquirer');
5-
const GitUtilities = require('@4c/cli-core/GitUtilities');
1+
const nodePlop = require('node-plop');
62

7-
const writePkgJson = require('./writePkgJson');
8-
const { getPackageNameFromPath, copyTemplate } = require('./utils');
3+
// load an instance of plop from a plopfile
94

105
exports.command = '$0 [location]';
116

@@ -19,110 +14,11 @@ exports.builder = _ =>
1914
normalize: true,
2015
});
2116

22-
exports.handler = async ({ location, cwd = process.cwd() }) => {
23-
const dest = path.isAbsolute(location)
24-
? location
25-
: path.resolve(cwd, location);
17+
exports.handler = async ({ location }) => {
18+
const plop = nodePlop('./plopfile.js');
19+
const newPkg = plop.getGenerator('new-package');
2620

27-
const answers = await inquirer.prompt([
28-
{
29-
name: 'scopePackage',
30-
type: 'confirm',
31-
message: 'Create a scoped package?',
32-
default: true,
33-
},
34-
{
35-
name: 'scope',
36-
type: 'input',
37-
message: 'package scope',
38-
default: '@4c',
39-
when: _ => !!_.scopePackage,
40-
},
41-
{
42-
name: 'isPrivate',
43-
type: 'confirm',
44-
default: false,
45-
message: 'Is this a private package?',
46-
when: _ => !!_.scope,
47-
},
48-
{
49-
name: 'name',
50-
type: 'input',
51-
message: 'name',
52-
default: _ => getPackageNameFromPath(_.scope, dest),
53-
},
54-
{
55-
name: 'type',
56-
type: 'list',
57-
default: 'node',
58-
choices: ['node', 'web'],
59-
message: 'What type of library is this?',
60-
},
61-
{
62-
name: 'babel',
63-
type: 'confirm',
64-
default: false,
65-
message: 'Do you need babel (maybe not?)',
66-
when: _ => _.type === 'node',
67-
},
68-
{
69-
name: 'semanticRelease',
70-
type: 'confirm',
71-
default: true,
72-
message: 'Do you want to use semantic-release to handle releases?',
73-
},
74-
]);
75-
76-
if (answers.type === 'web') {
77-
answers.babel = true;
78-
}
79-
80-
await fs.ensureDir(dest);
81-
82-
await copyTemplate('gitignore', '.gitignore');
83-
await copyTemplate('.travis.yml');
84-
await copyTemplate(`${answers.type}.eslintrc`, '.eslintrc');
85-
await copyTemplate('.eslintignore');
86-
await copyTemplate('LICENSE');
87-
88-
await GitUtilities.init(dest);
89-
await GitUtilities.addRemote(dest, answers.name);
90-
91-
await writePkgJson(dest, answers);
92-
93-
if (answers.babel) {
94-
await fs.ensureFile(path.join(dest, 'src/index.js'));
95-
await fs.writeFile(
96-
path.join(dest, '.babelrc.js'),
97-
`
98-
module.exports = api => ({
99-
presets: [
100-
[
101-
'@4c/4catalyzer',
102-
{
103-
target: '${answers.type}',
104-
modules: api.env() === 'esm' ? false : 'commonjs'
105-
},
106-
],
107-
]
108-
});
109-
`,
110-
);
111-
} else {
112-
await fs.ensureFile(path.join(dest, 'index.js'));
113-
}
114-
115-
await execa('yarn', ['install'], { cwd: dest, stdio: 'inherit' });
116-
await execa('yarn', ['upgrade-interactive', '--latest'], {
117-
cwd: dest,
118-
stdio: 'inherit',
119-
});
120-
121-
if (answers.semanticRelease) {
122-
console.log(
123-
'\nRun `npx semantic-release-cli setup` after pushing to github for the first time to setup semantic release\n',
124-
);
125-
} else {
126-
console.log('Done!');
127-
}
21+
const answers = await newPkg.runPrompts([location]);
22+
const f = await newPkg.runActions(answers);
23+
console.log('here', f);
12824
};

packages/init/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
"execa": "^1.0.0",
1616
"fs-extra": "^7.0.0",
1717
"inquirer": "^6.2.0",
18+
"node-plop": "^0.16.0",
19+
"prettier": "^1.14.2",
1820
"yargs": "^12.0.1"
21+
},
22+
"devDependencies": {
23+
"eslint": "^5.5.0"
1924
}
2025
}

packages/init/plopfile.js

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
const path = require('path');
2+
const execa = require('execa');
3+
const GitUtilities = require('@4c/cli-core/GitUtilities');
4+
5+
const addHelpers = require('./addHelpers');
6+
const { getPackageNameFromPath, templatePath } = require('./utils');
7+
8+
const ignore = () => {};
9+
10+
const prompts = [
11+
{
12+
name: 'location',
13+
type: 'input',
14+
message: 'package location',
15+
filter: location =>
16+
path.isAbsolute(location) ? location : path.resolve(location),
17+
},
18+
{
19+
name: 'scopePackage',
20+
type: 'confirm',
21+
message: 'Create a scoped package?',
22+
default: true,
23+
},
24+
{
25+
name: 'scope',
26+
type: 'input',
27+
message: 'package scope',
28+
default: '@4c',
29+
when: _ => !!_.scopePackage,
30+
},
31+
{
32+
name: 'isPrivate',
33+
type: 'confirm',
34+
default: false,
35+
message: 'Is this a private package?',
36+
when: _ => !!_.scope,
37+
},
38+
{
39+
name: 'name',
40+
type: 'input',
41+
message: 'name',
42+
default: _ => getPackageNameFromPath(_.scope, _.location),
43+
},
44+
{
45+
name: 'type',
46+
type: 'list',
47+
default: 'node',
48+
choices: ['node', 'web'],
49+
message: 'What type of library is this?',
50+
},
51+
{
52+
name: 'babel',
53+
type: 'confirm',
54+
default: false,
55+
message: 'Do you need babel (maybe not?)',
56+
when: _ => _.type === 'node',
57+
},
58+
{
59+
name: 'semanticRelease',
60+
type: 'confirm',
61+
default: true,
62+
message: 'Do you want to use semantic-release to handle releases?',
63+
},
64+
];
65+
66+
module.exports = plop => {
67+
addHelpers(plop);
68+
69+
plop.setHelper('gitUrl', name => GitUtilities.remoteUrl(name));
70+
71+
// controller generator
72+
plop.setGenerator('new-package', {
73+
description: 'create a new package',
74+
prompts,
75+
actions({ type, babel, location }) {
76+
if (type === 'web') babel = true; // eslint-disable-line no-param-reassign
77+
78+
return [
79+
{
80+
type: 'add',
81+
path: '{{location}}/package.json',
82+
templateFile: `${templatePath}/package.json.hbs`,
83+
},
84+
{
85+
type: 'add',
86+
path: '{{location}}/.gitignore',
87+
templateFile: `${templatePath}/gitignore`,
88+
skipIfExists: true,
89+
},
90+
{
91+
type: 'add',
92+
path: `{{location}}/.travis.yml`,
93+
templateFile: `${templatePath}/.travis.yml.hbs`,
94+
skipIfExists: true,
95+
},
96+
{
97+
type: 'add',
98+
path: `{{location}}/.eslintrc`,
99+
templateFile: `${templatePath}/.eslintrc.hbs`,
100+
skipIfExists: true,
101+
},
102+
{
103+
type: 'add',
104+
path: `{{location}}/.eslintignore`,
105+
templateFile: `${templatePath}/.eslintignore`,
106+
skipIfExists: true,
107+
},
108+
{
109+
type: 'add',
110+
path: `{{location}}/LICENSE`,
111+
templateFile: `${templatePath}/LICENSE.hbs`,
112+
skipIfExists: true,
113+
},
114+
() => GitUtilities.init(location).catch(ignore),
115+
_ => GitUtilities.addRemote(location, _.name).catch(ignore),
116+
babel
117+
? {
118+
type: 'add',
119+
path: `{{location}}/.babelrc.js`,
120+
templateFile: `${templatePath}/babelrc.js.hbs`,
121+
skipIfExists: true,
122+
}
123+
: {
124+
type: 'add',
125+
path: `{{location}}/index.js`,
126+
skipIfExists: true,
127+
},
128+
() =>
129+
execa(
130+
'prettier',
131+
[
132+
`${location}/**/*.{js,json,md}`,
133+
`${location}/.eslintrc`,
134+
'--write',
135+
],
136+
{ cwd: location },
137+
).catch(ignore),
138+
() => execa('yarn', ['install'], { cwd: location, stdio: 'inherit' }),
139+
() =>
140+
execa('yarn', ['upgrade-interactive', '--latest'], {
141+
cwd: location,
142+
stdio: 'inherit',
143+
}),
144+
145+
({ semanticRelease }) => {
146+
if (semanticRelease) {
147+
console.log(
148+
'\nRun `npx semantic-release-cli setup` after pushing to github for the first time to setup semantic release\n',
149+
);
150+
} else {
151+
console.log('Done!');
152+
}
153+
},
154+
];
155+
},
156+
});
157+
};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
**/coverage/**
22
**/es/**
3+
**/lib/**
34
**/fixtures/**
45
**/flow-typed/**
5-
**/lib/**
66
**/node_modules/**
77
**/CHANGELOG.md
88
**/package.json
Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,33 @@
11
{
2-
"extends": ["4catalyzer", "prettier"],
32
"plugins": ["prettier"],
3+
{{#if (eq type "node")}}
4+
"extends": ["4catalyzer", "prettier"],
45
"env": {
5-
"node": true
6+
"node": true
67
},
78
"rules": {
89
"prettier/prettier": "error",
910
"global-require": "off",
1011
"import/no-dynamic-require": "off"
1112
},
13+
{{else}}
14+
"extends": ["4catalyzer-react", "prettier", "prettier-react"],
15+
"env": {
16+
"web": true
17+
},
18+
"rules": {
19+
"prettier/prettier": "error"
20+
},
21+
{{/if}}
1222
"overrides": [
1323
{
1424
"files": ["test/**"],
1525
"plugins": ["jest"],
16-
"env": {
17-
"jest/globals": true
18-
},
1926
"rules": {
20-
"no-console": "off",
27+
"global-require": "off",
2128
"no-await-in-loop": "off",
29+
"no-console": "off",
30+
"import/no-dynamic-require": "off",
2231
"jest/no-disabled-tests": "warn",
2332
"jest/no-focused-tests": "error",
2433
"jest/no-identical-title": "error",

packages/init/templates/.travis.yml

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)