Skip to content

Commit e73acd2

Browse files
authored
Feature/project readme generator (#144)
* first preparation for multiple templates and the new command * first draft * update readme * check if plugin fn was created from fastify-plugin * omit error prefix, print executed command because of levensthein, rename commands * rename commands, update readme * check min fastify version * [skip ci] improve readme
1 parent 8b4f82f commit e73acd2

22 files changed

+257
-43
lines changed

README.md

+22-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ Will print an help:
2424
```
2525
Fastify command line interface, available commands are:
2626
27-
* start start a server
28-
* generate generate a new project
29-
* version the current fastify-cli version
30-
* help help about commands
27+
* start start a server
28+
* generate generate a new project
29+
* readme generate a README.md for the plugin
30+
* version the current fastify-cli version
31+
* help help about commands
3132
3233
Launch 'fastify help [command]' to know more about the commands.
3334
@@ -179,6 +180,23 @@ You will find three different folders:
179180
Finally there will be an `app.js` file, which is your entry point.
180181
It is a standard Fastify plugin and you will not need to add the `listen` method to run the server, just run it with one of the scripts above.
181182

183+
### readme
184+
185+
`fastify-cli` can also help with generating a concise and informative readme for your plugin. If no `package.json` was provided a new one is generated automatically.
186+
To use it:
187+
188+
1. `cd yourplugin`
189+
2. `fastify readme <path-to-your-plugin-file>`
190+
191+
Finally there will be a new `README.md` file, which provides internal informations about your plugin e.g:
192+
193+
* Install instructions
194+
* Example usage
195+
* Plugin dependencies
196+
* Exposed decorators
197+
* Encapsulation semantic
198+
* Compatible Fastify version
199+
182200
### linting
183201

184202
`fastify-cli` is unopinionated on the choice of linter. We recommend you to add a linter, like so:

cli.js

+2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ const help = require('help-me')({
1010
})
1111
const start = require('./start')
1212
const generate = require('./generate')
13+
const generateReadme = require('./generate-readme')
1314

1415
commist.register('start', start.cli)
1516
commist.register('generate', generate.cli)
17+
commist.register('readme', generateReadme.cli)
1618
commist.register('help', help.toStdout)
1719
commist.register('version', function () {
1820
console.log(require('./package.json').version)

generate-readme.js

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
'use strict'
2+
3+
const { readFileSync, existsSync } = require('fs')
4+
const path = require('path')
5+
const generify = require('generify')
6+
const argv = require('yargs-parser')
7+
const { execSync } = require('child_process')
8+
const log = require('./log')
9+
10+
function toMarkdownList (a) {
11+
return a.map(d => `- ${d}`).join('\n')
12+
}
13+
function generate (dir, { pluginMeta, encapsulated, pluginFileName }, cb) {
14+
process.chdir(dir)
15+
16+
if (!existsSync(path.join(dir, 'package.json'))) {
17+
execSync('npm init -y')
18+
log('info', `generated package.json in ${dir}`)
19+
}
20+
21+
log('info', `reading package.json in ${dir}`)
22+
let pkg = readFileSync('package.json')
23+
try {
24+
pkg = JSON.parse(pkg)
25+
} catch (err) {
26+
return cb(err)
27+
}
28+
29+
pluginMeta.decorators = pluginMeta.decorators ? pluginMeta.decorators : { fastify: [], reply: [] }
30+
pluginMeta.dependencies = pluginMeta.dependencies ? pluginMeta.dependencies : []
31+
32+
const peerDepFastify = pkg.peerDependencies ? pkg.peerDependencies.fastify : ''
33+
const depFastify = pkg.dependencies ? pkg.dependencies.fastify : ''
34+
const minFastify = pluginMeta.fastify || peerDepFastify || depFastify
35+
36+
let accessibilityTemplate = ''
37+
if (!encapsulated) {
38+
accessibilityTemplate = `- [X] Accessible in the same context where you require them\n- [ ] Accessible only in a child context\n`
39+
} else {
40+
accessibilityTemplate = `- [ ] Accessible in the same context where you require them\n- [X] Accessible only in a child context\n`
41+
}
42+
43+
let fastifyDecorators = toMarkdownList(pluginMeta.decorators.fastify)
44+
let replyDecorators = toMarkdownList(pluginMeta.decorators.reply)
45+
let pluginDeps = toMarkdownList(pluginMeta.dependencies)
46+
47+
generify(
48+
path.join(__dirname, 'templates', 'readme'),
49+
dir,
50+
{
51+
accessibilityTemplate,
52+
fastifyDecorators,
53+
replyDecorators,
54+
pluginDeps,
55+
packageName: pkg.name,
56+
pluginFileName,
57+
minFastify
58+
},
59+
function (file) {
60+
log('debug', `generated ${file}`)
61+
},
62+
function (err) {
63+
if (err) {
64+
return cb(err)
65+
}
66+
67+
log('info', `README for plugin ${pkg.name} generated successfully`)
68+
}
69+
)
70+
}
71+
72+
function stop (error) {
73+
if (error) {
74+
console.log(error)
75+
process.exit(1)
76+
}
77+
process.exit()
78+
}
79+
80+
function showHelp () {
81+
console.log(
82+
readFileSync(path.join(__dirname, 'help', 'readme.txt'), 'utf8')
83+
)
84+
return stop()
85+
}
86+
87+
function cli (args) {
88+
const opts = argv(args)
89+
90+
const dir = process.cwd()
91+
92+
if (opts._.length !== 1) {
93+
log('error', 'Missing the required file parameter\n')
94+
return showHelp()
95+
}
96+
97+
if (existsSync(path.join(dir, 'README.md'))) {
98+
log('error', 'a README.md file already exists in target directory')
99+
process.exit(1)
100+
}
101+
102+
const pluginPath = path.join(dir, path.basename(opts._[0], '.js'))
103+
104+
let plugin
105+
try {
106+
plugin = require(pluginPath)
107+
} catch (err) {
108+
log('error', 'plugin could not be loaded', err)
109+
process.exit(1)
110+
}
111+
112+
const pluginMeta = plugin[Symbol.for('plugin-meta')]
113+
114+
if (!pluginMeta) {
115+
log('error', 'no plugin metadata could be found. Are you sure that you use https://github.com/fastify/fastify-plugin ?')
116+
process.exit(1)
117+
}
118+
119+
let encapsulated = !plugin[Symbol.for('skip-override')]
120+
const pluginFileName = path.basename(opts._[0])
121+
122+
generate(dir, { pluginMeta, encapsulated, pluginFileName }, function (
123+
err
124+
) {
125+
if (err) {
126+
log('error', err.message)
127+
process.exit(1)
128+
}
129+
})
130+
}
131+
132+
module.exports = {
133+
generate,
134+
cli
135+
}
136+
137+
if (require.main === module) {
138+
cli(process.argv.slice(2))
139+
}

generate.js

+5-29
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,16 @@ const {
55
writeFile,
66
existsSync
77
} = require('fs')
8-
const chalk = require('chalk')
98
const path = require('path')
9+
const chalk = require('chalk')
1010
const generify = require('generify')
1111
const argv = require('yargs-parser')
1212
const cliPkg = require('./package')
1313
const { execSync } = require('child_process')
14+
const log = require('./log')
1415

15-
function generate (dir, log, cb) {
16-
if (!cb) {
17-
cb = log
18-
log = () => {}
19-
}
20-
21-
generify(path.join(__dirname, 'app_template'), dir, {}, function (file) {
16+
function generate (dir, cb) {
17+
generify(path.join(__dirname, 'templates', 'app'), dir, {}, function (file) {
2218
log('debug', `generated ${file}`)
2319
}, function (err) {
2420
if (err) {
@@ -78,18 +74,6 @@ function generate (dir, log, cb) {
7874
})
7975
}
8076

81-
const levels = {
82-
'debug': 0,
83-
'info': 1,
84-
'error': 2
85-
}
86-
87-
const colors = [
88-
(l) => l,
89-
chalk.green,
90-
chalk.red
91-
]
92-
9377
function cli (args) {
9478
const opts = argv(args)
9579

@@ -105,20 +89,12 @@ function cli (args) {
10589
process.exit(1)
10690
}
10791

108-
generate(dir, log, function (err) {
92+
generate(dir, function (err) {
10993
if (err) {
11094
log('error', err.message)
11195
process.exit(1)
11296
}
11397
})
114-
115-
function log (severity, line) {
116-
const level = levels[severity] || 0
117-
if (level === 1) {
118-
line = '--> ' + line
119-
}
120-
console.log(colors[level](line))
121-
}
12298
}
12399

124100
module.exports = {

help/help.txt

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
Fastify command line interface available commands are:
22

3-
* start start a server
4-
* generate generate a new project
5-
* version the current fastify-cli version
6-
* help help about commands
3+
* start start a server
4+
* generate generate a new project
5+
* readme generate a README.md for the plugin
6+
* version the current fastify-cli version
7+
* help help about commands
78

89
Launch 'fastify help [command]' to learn more about each command.

help/readme.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Usage: fastify readme <path-to-plugin-file>
2+
3+
Sets up project with `npm init -y` and
4+
generates a sample README.md file
5+
from the <path-to-plugin-file>.

log.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict'
2+
3+
const chalk = require('chalk')
4+
5+
const levels = {
6+
debug: 0,
7+
info: 1,
8+
error: 2
9+
}
10+
11+
const colors = [l => l, chalk.green, chalk.red]
12+
13+
function log (severity, line) {
14+
const level = levels[severity] || 0
15+
if (level === 1) {
16+
line = '--> ' + line
17+
}
18+
console.log(colors[level](line))
19+
}
20+
21+
module.exports = log

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
},
99
"scripts": {
1010
"lint": "standard",
11-
"test": "tap test/*.test.js app_template/test/*/*.test.js",
12-
"pretest": "standard"
11+
"unit": "tap test/*.test.js templates/app/test/*/*.test.js",
12+
"test": "npm run lint && npm run unit"
1313
},
1414
"keywords": [
1515
"fastify",

start.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function start (args, cb) {
4141
}
4242

4343
if (opts._.length !== 1) {
44-
console.error('Error: Missing the required file parameter\n')
44+
console.error('Missing the required file parameter\n')
4545
return showHelp()
4646
}
4747

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

templates/readme/README.md

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# __packageName__
2+
3+
Short description of the purpose of your plugin.
4+
5+
## Install
6+
7+
```
8+
npm install __packageName__ --save
9+
yarn add __packageName__
10+
```
11+
12+
## Example
13+
14+
```js
15+
const fastify = require('fastify')()
16+
fastify.register(require('__packageName__'))
17+
fastify.listen(3000)
18+
```
19+
20+
You can also start any Fastify plugin with the [Fastify-cli](https://github.com/fastify/fastify-cli):
21+
22+
```
23+
fastify start __pluginFileName__
24+
```
25+
26+
## Plugin
27+
28+
### Accessibility
29+
<!-- Is your plugin fully encapsulated? If you use fastify-plugin or the hidden property 'skip-override' it's not -->
30+
31+
__accessibilityTemplate__
32+
33+
### Decorators
34+
<!-- A list of all exposed decorators in your plugin -->
35+
36+
#### Fastify
37+
<!-- Please define the method signature in typescript because it's well known and easy to write -->
38+
39+
__fastifyDecorators__
40+
41+
#### Reply
42+
<!-- Please define the method signature in typescript because it's well known and easy to write -->
43+
44+
__replyDecorators__
45+
46+
## Dependencies
47+
48+
__pluginDeps__
49+
50+
## Compatible Fastify version
51+
52+
__minFastify__

0 commit comments

Comments
 (0)