Skip to content

Commit

Permalink
✨ Allow user to choose a non HTML README template (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
kefranabg authored Jun 27, 2019
1 parent 88c96ac commit 6d5c884
Show file tree
Hide file tree
Showing 11 changed files with 358 additions and 102 deletions.
69 changes: 68 additions & 1 deletion src/__snapshots__/readme.spec.js.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`readme buildReadmeContent should return readme template content 1`] = `
exports[`readme buildReadmeContent should return readme default template content 1`] = `
"<h1 align=\\"center\\">Welcome to readme-md-generator 👋</h1>
<p>
<img src=\\"https://img.shields.io/badge/version-0.1.3-blue.svg?cacheSeconds=2592000\\" />
Expand Down Expand Up @@ -74,3 +74,70 @@ This project is [MIT](https://github.com/kefranabg/readme-md-generator/blob/mast
***
_This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_"
`;

exports[`readme buildReadmeContent should return readme default template no html content 1`] = `
"# Welcome to readme-md-generator 👋
![Version](https://img.shields.io/badge/version-0.1.3-blue.svg?cacheSeconds=2592000)
![Prerequisite](https://img.shields.io/badge/npm-%3E%3D5.5.0-blue.svg)
![Prerequisite](https://img.shields.io/badge/node-%3E%3D%209.3.0-blue.svg)
[![Documentation](https://img.shields.io/badge/documentation-yes-brightgreen.svg)](https://github.com/kefranabg/readme-md-generator#readme)
[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/kefranabg/readme-md-generator/graphs/commit-activity)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE)
[![Twitter: FranckAbgrall](https://img.shields.io/twitter/follow/FranckAbgrall.svg?style=social)](https://twitter.com/FranckAbgrall)
> Generates beautiful README files from git config &amp; package.json infos
### 🏠 [Homepage](https://github.com/kefranabg/readme-md-generator#readme)
## Prerequisites
- npm &gt;=5.5.0
- node &gt;= 9.3.0
## Install
\`\`\`sh
npm install
\`\`\`
## Usage
\`\`\`sh
npm start
\`\`\`
## Run tests
\`\`\`sh
npm run test
\`\`\`
## Author
👤 **Franck Abgrall**
* Twitter: [@FranckAbgrall](https://twitter.com/FranckAbgrall)
* Github: [@kefranabg](https://github.com/kefranabg)
## 🤝 Contributing
Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/kefranabg/readme-md-generator/issues).
## Show your support
Give a ⭐️ if this project helped you!
[![support us](https://img.shields.io/badge/become-a patreon%20us-orange.svg?cacheSeconds=2592000)](https://www.patreon.com/FranckAbgrall)
## 📝 License
Copyright © 2019 [Franck Abgrall](https://github.com/kefranabg).
This project is [MIT](https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE) licensed.
***
_This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_"
`;
24 changes: 7 additions & 17 deletions src/ask-questions.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,21 @@
const inquirer = require('inquirer')
const { flatMap } = require('lodash')

const questionsBuilders = require('./questions')
const utils = require('./utils')

/**
* Get questions
*
* @param {Object} projectInfos
*/
const getQuestions = projectInfos =>
Object.values(questionsBuilders).reduce(
(questions, questionBuilder) => [
...questions,
questionBuilder(projectInfos)
],
[]
)

/**
* Ask user questions and return context to generate a README
*
* @param {Object} projectInfos
* @param {Boolean} useDefaultAnswers
*/
module.exports = async (projectInfos, skipQuestions) => {
const questions = getQuestions(projectInfos)
module.exports = async (projectInfos, useDefaultAnswers) => {
const questions = flatMap(Object.values(questionsBuilders), questionBuilder =>
questionBuilder(projectInfos)
)

const answersContext = skipQuestions
const answersContext = useDefaultAnswers
? utils.getDefaultAnswers(questions)
: await inquirer.prompt(questions)

Expand Down
4 changes: 2 additions & 2 deletions src/ask-questions.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('ask-questions', () => {
it('should call all builder functions exported by questions', async () => {
const projectInfos = { name: 'readme-md-generator' }

await askQuestions(projectInfos)
await askQuestions(projectInfos, false)

expect(questions.askProjectName).toHaveBeenCalledTimes(1)
expect(questions.askProjectVersion).toHaveBeenCalledTimes(1)
Expand All @@ -66,7 +66,7 @@ describe('ask-questions', () => {
it('should return merged contexts', async () => {
const projectInfos = { name: 'readme-md-generator' }

const context = await askQuestions(projectInfos)
const context = await askQuestions(projectInfos, false)

expect(context).toEqual({
projectName: 'value',
Expand Down
33 changes: 33 additions & 0 deletions src/choose-template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const inquirer = require('inquirer')
const path = require('path')

module.exports = async useDefaultAnswers => {
const defaultTemplate = path.resolve(__dirname, '../templates/default.md')
const defaultNoHtmlTemplate = path.resolve(
__dirname,
'../templates/default-no-html.md'
)

if (useDefaultAnswers) return defaultTemplate

const question = {
type: 'list',
message:
'🎨 Use HTML in your README.md for a nicer rendering? (not supported everywhere. ex: Bitbucket)',
name: 'templatePath',
choices: [
{
name: 'Yes ',
value: defaultTemplate
},
{
name: 'No',
value: defaultNoHtmlTemplate
}
]
}

const { templatePath } = await inquirer.prompt([question])

return templatePath
}
51 changes: 51 additions & 0 deletions src/choose-template.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const inquirer = require('inquirer')
const path = require('path')

const chooseTemplate = require('./choose-template')

const defaultTemplatePath = path.resolve(__dirname, '../templates/default.md')
const defaultNoHtmlTemplatePath = path.resolve(
__dirname,
'../templates/default-no-html.md'
)

inquirer.prompt = jest.fn(() =>
Promise.resolve({ templatePath: defaultTemplatePath })
)

describe('choose-template', () => {
it('should return user choice', async () => {
const result = await chooseTemplate(false)

expect(result).toEqual(defaultTemplatePath)
})

it('should return default template', async () => {
const result = await chooseTemplate(true)

expect(result).toEqual(defaultTemplatePath)
})

it('should call prompt with correct parameters', async () => {
await chooseTemplate(false)

expect(inquirer.prompt).toHaveBeenNthCalledWith(1, [
{
type: 'list',
message:
'🎨 Use HTML in your README.md for a nicer rendering? (not supported everywhere. ex: Bitbucket)',
name: 'templatePath',
choices: [
{
name: 'Yes ',
value: defaultTemplatePath
},
{
name: 'No',
value: defaultNoHtmlTemplatePath
}
]
}
])
})
})
21 changes: 14 additions & 7 deletions src/cli.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
const readme = require('./readme')
const infos = require('./project-infos')

const utils = require('./utils')
const askQuestions = require('./ask-questions')

/**
* Main process:
* 1) Gather project infos
* 2) Ask user questions
* 3) Build README content
* 4) Create README.md file
* 1) Get README template path
* 2) Gather project infos
* 3) Ask user questions
* 4) Build README content
* 5) Create README.md file
*
* @param {Object} args
*/
module.exports = async ({ templatePath, yes }) => {
module.exports = async ({ customTemplatePath, useDefaultAnswers }) => {
const templatePath = await readme.getReadmeTemplatePath(
customTemplatePath,
useDefaultAnswers
)
const projectInformations = await infos.getProjectInfos()
const answersContext = await askQuestions(projectInformations, yes)
const answersContext = await askQuestions(
projectInformations,
useDefaultAnswers
)
const readmeContent = await readme.buildReadmeContent(
answersContext,
templatePath
Expand Down
29 changes: 11 additions & 18 deletions src/cli.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,29 @@ describe('mainProcess', () => {
})

it('should call main functions with correct args', async () => {
const templatePath = 'default'
const customTemplatePath = undefined
const useDefaultAnswers = true
const projectInformations = { name: 'readme-md-generator' }
const readmeContent = 'content'
const templatePath = 'path/to/template'
infos.getProjectInfos = jest.fn(() => Promise.resolve(projectInformations))
readme.buildReadmeContent = jest.fn(() => Promise.resolve(readmeContent))
readme.getReadmeTemplatePath = jest.fn(() => Promise.resolve(templatePath))
readme.writeReadme = jest.fn()
utils.showEndMessage = jest.fn()

await mainProcess({ templatePath })
await mainProcess({ customTemplatePath, useDefaultAnswers })

expect(readme.getReadmeTemplatePath).toHaveBeenNthCalledWith(
1,
customTemplatePath,
useDefaultAnswers
)
expect(infos.getProjectInfos).toHaveBeenCalledTimes(1)
expect(askQuestions).toHaveBeenNthCalledWith(
1,
projectInformations,
undefined
useDefaultAnswers
)
expect(readme.buildReadmeContent).toHaveBeenNthCalledWith(
1,
Expand All @@ -68,19 +76,4 @@ describe('mainProcess', () => {
expect(readme.writeReadme).toHaveBeenNthCalledWith(1, readmeContent)
expect(utils.showEndMessage).toHaveBeenCalledTimes(1)
})

it('should forward --yes option to askQuestions', async () => {
const template = 'default'
const projectInformations = { name: 'readme-md-generator' }
const skipQuestions = true
utils.showEndMessage = jest.fn()

await mainProcess({ template, yes: skipQuestions })

expect(askQuestions).toHaveBeenNthCalledWith(
1,
projectInformations,
skipQuestions
)
})
})
19 changes: 5 additions & 14 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
#!/usr/bin/env node

const yargs = require('yargs')
const { noop } = require('lodash')

const mainProcess = require('./cli')
const { getReadmeTemplatePath } = require('./readme')

yargs
.usage('Usage: $0 <command> [options]')
.command(
'$0 [template]',
'Generate README.md from a template',
command =>
command.positional('template', {
desc: 'The name of template you want to use',
default: 'default'
}),
args => {
const templatePath = getReadmeTemplatePath(args)
mainProcess({ templatePath, yes: args.yes })
}
)
.command('$0', 'Generate README.md', noop, args => {
const { path: customTemplatePath, yes: useDefaultAnswers } = args
mainProcess({ customTemplatePath, useDefaultAnswers })
})
.string('p')
.alias('p', 'path')
.describe('path', 'Path to your own template')
Expand Down
30 changes: 19 additions & 11 deletions src/readme.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ const ora = require('ora')
const { promisify } = require('util')
const getYear = require('date-fns/get_year')
const fs = require('fs')
const path = require('path')
const { isNil } = require('lodash')

const chooseTemplate = require('./choose-template')

const README_PATH = 'README.md'

/**
Expand Down Expand Up @@ -61,20 +62,13 @@ const buildReadmeContent = async (context, templatePath) => {
}

/**
* Get path to the readme template
* Validate template path
*
* @param {string} availableTemplate
* @param {string} customTemplate
* @param {string} templatePath
*/
const getReadmeTemplatePath = args => {
const validateReadmeTemplatePath = templatePath => {
const spinner = ora('Resolving README template path').start()

const { template: availableTemplate, path: customTemplate } = args

const templatePath = isNil(customTemplate)
? path.resolve(__dirname, `../templates/${availableTemplate}.md`)
: customTemplate

try {
fs.lstatSync(templatePath).isFile()
} catch (err) {
Expand All @@ -83,6 +77,20 @@ const getReadmeTemplatePath = args => {
}

spinner.succeed('README template path resolved')
}

/**
* Get readme template path
* (either a custom template, or a template that user will choose from prompt)
*
* @param {String} customTemplate
*/
const getReadmeTemplatePath = async (customTemplate, useDefaultAnswers) => {
const templatePath = isNil(customTemplate)
? await chooseTemplate(useDefaultAnswers)
: customTemplate

validateReadmeTemplatePath(templatePath)

return templatePath
}
Expand Down
Loading

0 comments on commit 6d5c884

Please sign in to comment.