Skip to content

Commit

Permalink
Project scaffolding with package.json (#114)
Browse files Browse the repository at this point in the history
* initial work for project scaffolding

* Added tests for cli, make tests pass, improve questions to match npm init

* Use npm init directly instead of asking questions, rely on generify mkdir instead

* Update README for new instructions
  • Loading branch information
cemremengu authored Nov 3, 2018
1 parent edcfead commit 6958ecc
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 84 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,9 @@ in case of a `'unhandledRejection'`.
`fastify-cli` can also help with generating some project scaffolding to
kickstart the development of your next Fastify application. To use it:

1. `mkdir yourapp`
1. `fastify generate <yourapp>`
2. `cd yourapp`
3. `npm init`
4. `fastify generate`
5. `npm install`
3. `npm install`

The sample code offers you four npm tasks:

Expand Down
66 changes: 66 additions & 0 deletions app_template/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Logs
logs
*.log
npm-debug.log*

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules
jspm_packages

# Optional npm cache directory
.npm

# Optional REPL history
.node_repl_history

# 0x
profile-*

# mac files
.DS_Store

# vim swap files
*.swp

# webstorm
.idea

# vscode
.vscode
*code-workspace

# clinic
profile*
*clinic*
*flamegraph*

# lock files
yarn.lock
package-lock.json

# generated code
examples/typescript-server.js
test/types/index.js
89 changes: 53 additions & 36 deletions generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,75 @@

const {
readFile,
writeFile
writeFile,
existsSync
} = require('fs')
const chalk = require('chalk')
const path = require('path')
const generify = require('generify')
const argv = require('yargs-parser')
const templatedir = path.join(__dirname, 'app_template')
const cliPkg = require('./package')
const { execSync } = require('child_process')

function generate (dir, log, cb) {
if (!cb) {
cb = log
log = () => {}
}
const pkgFile = path.join(dir, 'package.json')
log('info', `reading package.json in ${dir}`)
readFile(pkgFile, (err, data) => {

generify(path.join(__dirname, 'app_template'), dir, {}, function (file) {
log('debug', `generated ${file}`)
}, function (err) {
if (err) {
return cb(err)
}

var pkg
try {
pkg = JSON.parse(data)
} catch (err) {
return cb(err)
}
process.chdir(dir)
execSync('npm init -y')

pkg.scripts = Object.assign(pkg.scripts || {}, {
'test': 'tap test/*.test.js test/*/*.test.js test/*/*/*.test.js',
'start': 'fastify start -l info app.js',
'dev': 'fastify start -l info -P app.js'
})
log('info', `reading package.json in ${dir}`)
readFile('package.json', (err, data) => {
if (err) {
return cb(err)
}

pkg.dependencies = Object.assign(pkg.dependencies || {}, {
'fastify': cliPkg.dependencies.fastify,
'fastify-plugin': cliPkg.devDependencies['fastify-plugin'] || cliPkg.dependencies['fastify-plugin'],
'fastify-autoload': cliPkg.devDependencies['fastify-autoload'],
'fastify-cli': '^' + cliPkg.version
})
var pkg
try {
pkg = JSON.parse(data)
} catch (err) {
return cb(err)
}

pkg.devDependencies = Object.assign(pkg.devDependencies || {}, {
'tap': cliPkg.devDependencies['tap']
})
pkg.main = 'app.js'

log('debug', `edited package.json, saving`)
pkg.scripts = Object.assign(pkg.scripts || {}, {
'test': 'tap test/*.test.js test/*/*.test.js test/*/*/*.test.js',
'start': 'fastify start -l info app.js',
'dev': 'fastify start -l info -P app.js'
})

writeFile(pkgFile, JSON.stringify(pkg, null, 2), (err) => {
if (err) {
return cb(err)
}
pkg.dependencies = Object.assign(pkg.dependencies || {}, {
'fastify': cliPkg.dependencies.fastify,
'fastify-plugin': cliPkg.devDependencies['fastify-plugin'] || cliPkg.dependencies['fastify-plugin'],
'fastify-autoload': cliPkg.devDependencies['fastify-autoload'],
'fastify-cli': '^' + cliPkg.version
})

log('debug', `saved package.json`)
log('info', `copying sample project`)
pkg.devDependencies = Object.assign(pkg.devDependencies || {}, {
'tap': cliPkg.devDependencies['tap']
})

generify(templatedir, dir, {}, function (file) {
log('debug', `generated ${file}`)
}, function (err) {
log('debug', `edited package.json, saving`)
writeFile('package.json', JSON.stringify(pkg, null, 2), (err) => {
if (err) {
return cb(err)
}

log('debug', `saved package.json`)
log('info', `project ${pkg.name} generated successfully`)
log('debug', `run '${chalk.bold('npm install')}' to install the dependencies`)
log('debug', `run '${chalk.bold('npm start')}' to start the application`)
log('debug', `run '${chalk.bold('npm run dev')}' to start the application with pino-colada pretty logging (not suitable for production)`)
log('debug', `run '${chalk.bold('npm test')}' to execute the unit tests`)
cb()
})
Expand All @@ -88,7 +92,20 @@ const colors = [

function cli (args) {
const opts = argv(args)
generate(opts._[0] || process.cwd(), log, function (err) {

if (opts._[0] && existsSync(opts._[0])) {
log('error', 'directory ' + opts._[0] + ' already exists')
process.exit(1)
}

const dir = opts._[0] || process.cwd()

if (existsSync(path.join(dir, 'package.json'))) {
log('error', 'a package.json file already exists in target directory')
process.exit(1)
}

generate(dir, log, function (err) {
if (err) {
log('error', err.message)
process.exit(1)
Expand Down
72 changes: 28 additions & 44 deletions test/generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ process.env.TAP_BAIL = true

const t = require('tap')
const {
writeFile,
readFile
} = require('fs')
const path = require('path')
Expand All @@ -17,6 +16,7 @@ const { generate } = require('../generate')
const workdir = path.join(__dirname, 'workdir')
const templatedir = path.join(__dirname, '..', 'app_template')
const cliPkg = require('../package')
const { exec } = require('child_process')
const expected = {}

;(function (cb) {
Expand Down Expand Up @@ -59,63 +59,45 @@ function define (t) {
})
})

test('errors if package.json is not there', (t) => {
test('errors if directory exists', (t) => {
t.plan(2)

generate(workdir, function (err) {
t.ok(err)
t.equal(err.code, 'ENOENT')
exec('node generate.js ./test/workdir', (err, stdout) => {
t.is('directory ./test/workdir already exists', stdout.toString().trim())
t.is(1, err.code)
})
})

test('finish succesfully if package.json is there - npm', (t) => {
t.plan(12 + Object.keys(expected).length * 2)

const pkgFile = path.join(workdir, 'package.json')
const pkgContent = JSON.stringify({
name: 'an-npm-app',
version: '0.0.1',
description: 'whaat',
main: 'index.js',
scripts: {}
}, null, 2)

writeFile(pkgFile, pkgContent, function (err) {
t.error(err)
generate(workdir, function (err) {
t.error(err)
verifyPkg(t, pkgFile, pkgContent)
verifyCopy(t, pkgFile)
})
test('errors if pkgfile exists', (t) => {
t.plan(2)
exec('node generate.js', (err, stdout) => {
t.is('a package.json file already exists in target directory', stdout.toString().trim())
t.is(1, err.code)
})
})

test('finish succesfully if package.json is there - yarn', (t) => {
t.plan(12 + Object.keys(expected).length * 2)
test('should finish succesfully', (t) => {
t.plan(15 + Object.keys(expected).length * 2)

const pkgFile = path.join(workdir, 'package.json')
const pkgContent = JSON.stringify({
name: 'an-yarn-app',
version: '0.0.1',
description: 'whaat',
main: 'index.js'
}, null, 2)
writeFile(pkgFile, pkgContent, function (err) {
generate(workdir, function (err) {
t.error(err)

generate(workdir, function (err) {
t.error(err)
verifyPkg(t, pkgFile, pkgContent)
verifyCopy(t, pkgFile)
})
verifyPkg(t)
verifyCopy(t)
})
})

function verifyPkg (t, pkgFile, pkgContent) {
function verifyPkg (t) {
const pkgFile = path.join(workdir, 'package.json')

readFile(pkgFile, function (err, data) {
t.error(err)
t.equal(data.toString().split('"main"')[0], pkgContent.split('"main"')[0])
const pkg = JSON.parse(data)
t.equal(pkg.name, 'workdir')
t.equal(pkg.version, '1.0.0')
t.equal(pkg.description, '')
t.equal(pkg.author, '')
// by default this will be ISC but since we have a MIT licensed pkg file in upper dir, npm will set the license to MIT in this case
// so for local tests we need to accept MIT as well
t.ok(pkg.license === 'ISC' || pkg.license === 'MIT')
t.equal(pkg.scripts.test, 'tap test/*.test.js test/*/*.test.js test/*/*/*.test.js')
t.equal(pkg.scripts.start, 'fastify start -l info app.js')
t.equal(pkg.scripts.dev, 'fastify start -l info -P app.js')
Expand All @@ -127,7 +109,9 @@ function define (t) {
})
}

function verifyCopy (t, pkgFile) {
function verifyCopy (t) {
const pkgFile = path.join(workdir, 'package.json')

walker(workdir)
.on('file', function (file) {
if (file === pkgFile) {
Expand Down

0 comments on commit 6958ecc

Please sign in to comment.