Repository: kefranabg/readme-md-generator
Branch: master
Commit: f0370c8efe60
Files: 81
Total size: 136.7 KB
Directory structure:
gitextract_6qg20dua/
├── .eslintrc.js
├── .github/
│ ├── CODE_OF_CONDUCT.md
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ └── nodejs.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode/
│ └── settings.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── jest.config.js
├── package.json
├── src/
│ ├── __snapshots__/
│ │ └── readme.spec.js.snap
│ ├── ask-overwrite.js
│ ├── ask-overwrite.spec.js
│ ├── ask-questions.js
│ ├── ask-questions.spec.js
│ ├── choose-template.js
│ ├── choose-template.spec.js
│ ├── clean-context.js
│ ├── clean-context.spec.js
│ ├── cli.js
│ ├── cli.spec.js
│ ├── index.js
│ ├── project-infos.js
│ ├── project-infos.spec.js
│ ├── questions/
│ │ ├── author-github.js
│ │ ├── author-github.spec.js
│ │ ├── author-linkedin.js
│ │ ├── author-linkedin.spec.js
│ │ ├── author-name.js
│ │ ├── author-name.spec.js
│ │ ├── author-patreon.js
│ │ ├── author-patreon.spec.js
│ │ ├── author-twitter.js
│ │ ├── author-twitter.spec.js
│ │ ├── author-website.js
│ │ ├── author-website.spec.js
│ │ ├── contributing-url.js
│ │ ├── contributing-url.spec.js
│ │ ├── index.js
│ │ ├── index.spec.js
│ │ ├── install-command.js
│ │ ├── install-command.spec.js
│ │ ├── issues-url.js
│ │ ├── issues-url.spec.js
│ │ ├── license-name.js
│ │ ├── license-name.spec.js
│ │ ├── license-url.js
│ │ ├── license-url.spec.js
│ │ ├── package-manager.js
│ │ ├── package-manager.spec.js
│ │ ├── project-demo-url.js
│ │ ├── project-demo-url.spec.js
│ │ ├── project-description.js
│ │ ├── project-description.spec.js
│ │ ├── project-documentation-url.js
│ │ ├── project-documentation-url.spec.js
│ │ ├── project-homepage.js
│ │ ├── project-homepage.spec.js
│ │ ├── project-name.js
│ │ ├── project-name.spec.js
│ │ ├── project-prerequisites.js
│ │ ├── project-prerequisites.spec.js
│ │ ├── project-version.js
│ │ ├── project-version.spec.js
│ │ ├── test-command.js
│ │ ├── test-command.spec.js
│ │ ├── usage.js
│ │ └── usage.spec.js
│ ├── readme.js
│ ├── readme.spec.js
│ ├── utils.js
│ └── utils.spec.js
└── templates/
├── default-no-html.md
├── default.md
└── footer.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.js
================================================
module.exports = {
root: true,
env: {
node: true,
jest: true
},
extends: ['airbnb-base', 'eslint:recommended'],
rules: {
semi: ['error', 'never'],
'no-use-before-define': ['error', { functions: false }],
'comma-dangle': 0,
'no-var': 2,
'prefer-const': 2,
'operator-linebreak': 0,
'no-confusing-arrow': 0,
'implicit-arrow-linebreak': 0,
indent: 0,
'no-param-reassign': 0,
'function-paren-newline': 0,
'arrow-parens': 0
},
parserOptions: {
parser: 'babel-eslint'
}
}
================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contribute to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at abgrallkefran@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: [kefranabg]
patreon: FranckAbgrall
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with a single custom sponsorship URL
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/workflows/nodejs.yml
================================================
name: Node CI
on:
pull_request:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [8.x, 10.x, 12.x]
steps:
- uses: actions/checkout@v1
- uses: actions/cache@v1
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: Run prettier check on project files
run: npm run prettier:check
- name: Run linter
run: npm run lint
- name: Run unit tests
run: npm run test:ci
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
================================================
FILE: .gitignore
================================================
.DS_Store
node_modules
/report
/coverage
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
# Fix an error from npm 6.9.0
.git
================================================
FILE: .prettierignore
================================================
templates/*
================================================
FILE: .prettierrc
================================================
{
"singleQuote": true,
"semi": false
}
================================================
FILE: .vscode/settings.json
================================================
{
"editor.formatOnSave": true
}
================================================
FILE: CHANGELOG.md
================================================
# Changelog
<a name="1.0.0"></a>
## 1.0.0 (2019-12-03)
### Added
- ✨ Ask for package manager when is JS project [[29986ce](https://github.com/kefranabg/readme-md-generator/commit/29986cea9acde108b9e167db5d0def67beaf7384)]
- ✨ Ask user for a link to contributing guide (fixes [#168](https://github.com/kefranabg/readme-md-generator/issues/168)) ([#179](https://github.com/kefranabg/readme-md-generator/issues/179)) [[310a8b1](https://github.com/kefranabg/readme-md-generator/commit/310a8b1f78154d9226c1267ccf18d0db9d9ea09f)]
- ✨ Ask author's linkedin username (fixes [#170](https://github.com/kefranabg/readme-md-generator/issues/170)) ([#177](https://github.com/kefranabg/readme-md-generator/issues/177)) [[10954d1](https://github.com/kefranabg/readme-md-generator/commit/10954d10739b995c431b751d63d5624c17397235)]
### Changed
- ⬆️ Update yargs to the latest version ([#186](https://github.com/kefranabg/readme-md-generator/issues/186)) [[16d7ceb](https://github.com/kefranabg/readme-md-generator/commit/16d7ceb8ec3040d63841397ded83dbdddc28da52)]
- ⬆️ Update ejs to the latest version ([#187](https://github.com/kefranabg/readme-md-generator/issues/187)) [[139e906](https://github.com/kefranabg/readme-md-generator/commit/139e906b1ed1b875ca96869fe8570ca03d9806c2)]
- 🔧 Update CI tiggers ([#184](https://github.com/kefranabg/readme-md-generator/issues/184)) [[6ef2be8](https://github.com/kefranabg/readme-md-generator/commit/6ef2be8ba8e00af16087f42eabd7e4b4ed2243b3)]
- ⬆️ Update ora to the latest version ([#181](https://github.com/kefranabg/readme-md-generator/issues/181)) [[c563d9d](https://github.com/kefranabg/readme-md-generator/commit/c563d9d473e5c17be6a45936b2f58f83b734c4e9)]
- 🔧 Move CI from CircleCI to GitHub actions [[a132525](https://github.com/kefranabg/readme-md-generator/commit/a132525ffe343629db2589378647665747e5cd4f)]
- 🔧 Update FUNDING.yml [[83be6c0](https://github.com/kefranabg/readme-md-generator/commit/83be6c00842eb4321b5c37a7f5617e28f1548cdb)]
### Fixed
- 🐛 Fix version badge label when contains \_ or - ([#190](https://github.com/kefranabg/readme-md-generator/issues/190)) [[6c345b5](https://github.com/kefranabg/readme-md-generator/commit/6c345b50caec810ef48f00dcbac0255f1db1f4a3)]
- 🐛 Execute default function to get default answer when -y flag is passed ([#185](https://github.com/kefranabg/readme-md-generator/issues/185)) [[89cd82d](https://github.com/kefranabg/readme-md-generator/commit/89cd82db18655bbb085eb72c339402f412dd3996)]
- 🐛 Escape markdown characters in social network questions answers ([#183](https://github.com/kefranabg/readme-md-generator/issues/183)) [[d96e310](https://github.com/kefranabg/readme-md-generator/commit/d96e310c5b54c573a139d01f4ad348f9456f7c3c)]
- ✏️ Use gender neutral in comment ([#174](https://github.com/kefranabg/readme-md-generator/issues/174)) [[9f78778](https://github.com/kefranabg/readme-md-generator/commit/9f78778002410c0b82f36015b86443fb366425a7)]
- 🐛 Fix InstallCommand test name [[279711f](https://github.com/kefranabg/readme-md-generator/commit/279711f1cdd18b2d53478c52f577041ea2186675)]
### Miscellaneous
- 📝 Add open collective to readme ([#192](https://github.com/kefranabg/readme-md-generator/issues/192)) [[81e3873](https://github.com/kefranabg/readme-md-generator/commit/81e387357c5c088714291b0a7f18b66cab8cd5c6)]
- 📝 Add anku255 as a contributor for test and bug ([#182](https://github.com/kefranabg/readme-md-generator/issues/182)) [[7624889](https://github.com/kefranabg/readme-md-generator/commit/76248890cf46ec7a27b6986add3d156095deb782)]
<a name="0.7.0"></a>
## 0.7.0 (2019-11-01)
### Added
- ✨ Add Author Github website url if exists (fixes [#124](https://github.com/kefranabg/readme-md-generator/issues/124)) ([#145](https://github.com/kefranabg/readme-md-generator/issues/145)) [[541d6e5](https://github.com/kefranabg/readme-md-generator/commit/541d6e53fdc2df42a3a416b5c2f2b5c1422e45db)]
### Changed
- ♻️ re-use prettier regexp across scripts ([#159](https://github.com/kefranabg/readme-md-generator/issues/159)) [[576e367](https://github.com/kefranabg/readme-md-generator/commit/576e367c67f7fbe0013fe2e32e20d17b6d4b8c8f)]
- 🔧 Add prettier fix command ([#158](https://github.com/kefranabg/readme-md-generator/issues/158)) [[da2c700](https://github.com/kefranabg/readme-md-generator/commit/da2c70034165b42d8e25abf1c799f275d7c349b0)]
### Fixed
- 🐛 Don't suggest install default value when project is not a js project ([#169](https://github.com/kefranabg/readme-md-generator/issues/169)) [[672d591](https://github.com/kefranabg/readme-md-generator/commit/672d591ae845e95ef2b8f41b00997e09dfff1a3c)]
- 🐛 Fix static badge generation when license name contains special characters ([#141](https://github.com/kefranabg/readme-md-generator/issues/141)) [[5b8bc08](https://github.com/kefranabg/readme-md-generator/commit/5b8bc08925e54f1c542d84a26283832040232053)]
### Miscellaneous
- 📝 Update README with CONTRIBUTING link [[5ec2ce4](https://github.com/kefranabg/readme-md-generator/commit/5ec2ce4e1404349eb94037dae16a8c569977e90a)]
- 📝 Add CONTRIBUTING.md (fixes [#155](https://github.com/kefranabg/readme-md-generator/issues/155)) ([#160](https://github.com/kefranabg/readme-md-generator/issues/160)) [[f2d6020](https://github.com/kefranabg/readme-md-generator/commit/f2d6020e5fdef4c880ed6830302ca20f0817d192)]
- 📝 Add code of conduct markdown ([#157](https://github.com/kefranabg/readme-md-generator/issues/157)) [[be3ec22](https://github.com/kefranabg/readme-md-generator/commit/be3ec22a7d44c88b59c3c67910ad266b65ff9746)]
<a name="0.6.4"></a>
## 0.6.4 (2019-10-09)
### Added
- ✨ Add check for overwrite readme ([#143](https://github.com/kefranabg/readme-md-generator/issues/143)) [[2e12553](https://github.com/kefranabg/readme-md-generator/commit/2e12553df31c65f31c88f556eb8811d5b5672739)]
- ✨ Display license badge even when there is no license url ([#139](https://github.com/kefranabg/readme-md-generator/issues/139)) [[a60627c](https://github.com/kefranabg/readme-md-generator/commit/a60627c93af35a2f87bc2f7ed44ce702871a6f7d)]
- ✨ Ask for demo link during README creation process ([#102](https://github.com/kefranabg/readme-md-generator/issues/102)) ([#130](https://github.com/kefranabg/readme-md-generator/issues/130)) [[f4d6ad4](https://github.com/kefranabg/readme-md-generator/commit/f4d6ad45c3884b24bf60536dd02d3ae17034f1b1)]
- ✨ Add dynamic license badge ([#131](https://github.com/kefranabg/readme-md-generator/issues/131)) [[86bdac5](https://github.com/kefranabg/readme-md-generator/commit/86bdac57c35734ca0bdd252d3e0ae12f9a5e80c8)]
### Changed
- ⬆️ Fix vulnerabilities ([#136](https://github.com/kefranabg/readme-md-generator/issues/136)) [[fb96985](https://github.com/kefranabg/readme-md-generator/commit/fb96985ff9665319f3669deae3e14e31a4fe9df9)]
<a name="0.6.3"></a>
## 0.6.3 (2019-09-24)
### Added
- ✨ Update issue templates [[3d5c28b](https://github.com/kefranabg/readme-md-generator/commit/3d5c28b3eb57c18245ef22f47fa8083117f1a08f)]
- ✨ Add link to npm on version badge ([#99](https://github.com/kefranabg/readme-md-generator/issues/99)) [[fdfe6e3](https://github.com/kefranabg/readme-md-generator/commit/fdfe6e374953a255eb72945405e8d8eadb62d3a9)]
- ✨ Add dynamic version badge if package exists on NPM ([#94](https://github.com/kefranabg/readme-md-generator/issues/94)) [[0a11d2a](https://github.com/kefranabg/readme-md-generator/commit/0a11d2ae3a7ea767e4f0138f7b1d21e114fb991a)]
### Changed
- ⬆️ Update ora to the latest version ([#122](https://github.com/kefranabg/readme-md-generator/issues/122)) [[ffb4d11](https://github.com/kefranabg/readme-md-generator/commit/ffb4d111547c23cedf03168c2facbd285c3c7d9d)]
- 🔧 Add gh package registry config ([#115](https://github.com/kefranabg/readme-md-generator/issues/115)) [[af1fb5a](https://github.com/kefranabg/readme-md-generator/commit/af1fb5ac10cfdabc57fc579e3c0a8f9a3d417f64)]
- ⬆️ Upgrade date-fns version ([#113](https://github.com/kefranabg/readme-md-generator/issues/113)) [[eacad62](https://github.com/kefranabg/readme-md-generator/commit/eacad62792e0f95f41b7ed267611265e08b14c2b)]
- ⬆️ Upgrade inquirer to the latest version 🚀 ([#110](https://github.com/kefranabg/readme-md-generator/issues/110)) [[f6fc84e](https://github.com/kefranabg/readme-md-generator/commit/f6fc84ec71a5b11de581745c8d75b7e6c1dd2143)]
- ⬆️ Bump mixin-deep from 1.3.1 to 1.3.2 ([#112](https://github.com/kefranabg/readme-md-generator/issues/112)) [[4e0abc4](https://github.com/kefranabg/readme-md-generator/commit/4e0abc4b574ced8433c0cc48f965d959a100ff04)]
- ⬆️ Bump eslint-utils from 1.3.1 to 1.4.2 ([#111](https://github.com/kefranabg/readme-md-generator/issues/111)) [[f0e09ac](https://github.com/kefranabg/readme-md-generator/commit/f0e09ac3f6b20882bda39c67e552eedd6fe18dce)]
- 🎨 Format Github issue templates [[95f44d2](https://github.com/kefranabg/readme-md-generator/commit/95f44d26062b06439c1ff97a13f61642279d32c5)]
- ⬆️ Update yargs to the latest version ([#104](https://github.com/kefranabg/readme-md-generator/issues/104)) [[d66db07](https://github.com/kefranabg/readme-md-generator/commit/d66db07cd2e0393b5ecb456ee982953a1448eff4)]
- ⬆️ Update inquirer to 6.5.1 ([#101](https://github.com/kefranabg/readme-md-generator/issues/101)) [[af8fbe6](https://github.com/kefranabg/readme-md-generator/commit/af8fbe6acf5f08090d6958e12e09c3a1f3e345ff)]
- ⬆️ Update eslint-config-airbnb-base to 14.0.0 ([#100](https://github.com/kefranabg/readme-md-generator/issues/100)) [[85ffea5](https://github.com/kefranabg/readme-md-generator/commit/85ffea57f3b4ed925ffe827f4194ac066298eb83)]
- ⬆️ Bump lodash from 4.17.11 to 4.17.13 ([#98](https://github.com/kefranabg/readme-md-generator/issues/98)) [[99dc774](https://github.com/kefranabg/readme-md-generator/commit/99dc774fac253a0786b935deb258a8cb3a777176)]
- 🔧 Ignore .git file in order to fix an npm bug [[f940f13](https://github.com/kefranabg/readme-md-generator/commit/f940f130efef5ffdeb3f278e7435570c95363acb)]
### Fixed
- 🐛 Process get stuck because of ora new version ([#152](https://github.com/kefranabg/readme-md-generator/issues/152)) [[4a741b9](https://github.com/kefranabg/readme-md-generator/commit/4a741b9b266ae33c8c04267e6958c26e598655b7)]
- 🐛 Fix badge target link ([#126](https://github.com/kefranabg/readme-md-generator/issues/126)) [[45df9a4](https://github.com/kefranabg/readme-md-generator/commit/45df9a4ab55ffa2ff6e8ac5a33e49bbba0b41efa)]
- ✏️ Capitalize the H in GitHub ([#116](https://github.com/kefranabg/readme-md-generator/issues/116)) [[3d08a76](https://github.com/kefranabg/readme-md-generator/commit/3d08a7610723a0034607bd4d136926220f431a03)]
### Miscellaneous
- 📝 Add anku255 as a contributor ([#144](https://github.com/kefranabg/readme-md-generator/issues/144)) [[32af6a2](https://github.com/kefranabg/readme-md-generator/commit/32af6a23fd22efbc93861c47f13c190c0800b9ed)]
- 📝 Add LucasProcopio as a contributor ([#138](https://github.com/kefranabg/readme-md-generator/issues/138)) [[d67b012](https://github.com/kefranabg/readme-md-generator/commit/d67b012fef502e296963c54f5cf3140a723c477d)]
- 📝 Add tbetous as a contributor ([#137](https://github.com/kefranabg/readme-md-generator/issues/137)) [[a93cd56](https://github.com/kefranabg/readme-md-generator/commit/a93cd56c43ed420245824542e808e3b27654c3ec)]
- 📝 Add david-dasilva as a contributor ([#133](https://github.com/kefranabg/readme-md-generator/issues/133)) [[f6f24e0](https://github.com/kefranabg/readme-md-generator/commit/f6f24e0be239214c5ff03d439aeb18007a513217)]
- 📝 All contributor profile url fixed ([#129](https://github.com/kefranabg/readme-md-generator/issues/129)) [[06bd6f3](https://github.com/kefranabg/readme-md-generator/commit/06bd6f3bf9b8af68c2548bf57524e52939cd192f)]
- 📝 Add Kushagra as a contributor ([#127](https://github.com/kefranabg/readme-md-generator/issues/127)) [[1624878](https://github.com/kefranabg/readme-md-generator/commit/1624878c90dc2f62cf5f692aa4fdedfc1d338f9c)]
- :spakles: Add start script ([#121](https://github.com/kefranabg/readme-md-generator/issues/121)) [[bc3d383](https://github.com/kefranabg/readme-md-generator/commit/bc3d38301c5b09f301a75094d5aed6c85e130da6)]
- 📝 Add bdougie as a contributor ([#117](https://github.com/kefranabg/readme-md-generator/issues/117)) [[2f327f7](https://github.com/kefranabg/readme-md-generator/commit/2f327f7547472093a030ded760508c90c1f21910)]
<a name="0.5.2"></a>
## 0.5.2 (2019-07-08)
### Added
- ✨ Filter social network inputs to remove potential @ ([#93](https://github.com/kefranabg/readme-md-generator/issues/93)) [[ccae357](https://github.com/kefranabg/readme-md-generator/commit/ccae357ad2c8a3788a248075644cf27d312f226b)]
### Miscellaneous
- Update readme and contributors to reflect username change ([#91](https://github.com/kefranabg/readme-md-generator/issues/91)) [[b2be60e](https://github.com/kefranabg/readme-md-generator/commit/b2be60e8bb429c9c440c6602f4f4ebec51b6d889)]
<a name="0.5.1"></a>
## 0.5.1 (2019-07-05)
### Fixed
- 🐛 Prevent encoding utf-8 chars in README ([#88](https://github.com/kefranabg/readme-md-generator/issues/88)) [[8059756](https://github.com/kefranabg/readme-md-generator/commit/80597564e0fd9e0b8c69c333929d02e9ec9ae0b0)]
<a name="0.5.0"></a>
## 0.5.0 (2019-06-27)
### Added
- ✨ Allow user to choose a non HTML README template ([#80](https://github.com/kefranabg/readme-md-generator/issues/80)) [[6d5c884](https://github.com/kefranabg/readme-md-generator/commit/6d5c8848c476fc2770204f215ddd6f48d539b4e0)]
- ✨ Allow user to specify path to custom README template ([#68](https://github.com/kefranabg/readme-md-generator/issues/68)) [[e0d66c0](https://github.com/kefranabg/readme-md-generator/commit/e0d66c002c8108ff3ae142979a5c8003a28a8107)]
- ✨ Get author name from package.json even if author prop is an object ([#75](https://github.com/kefranabg/readme-md-generator/issues/75)) [[688c338](https://github.com/kefranabg/readme-md-generator/commit/688c33833188a5487ff6df024d4993404ee0406c)]
### Changed
- ⬆️ Update eslint to the latest version ([#70](https://github.com/kefranabg/readme-md-generator/issues/70)) [[88c96ac](https://github.com/kefranabg/readme-md-generator/commit/88c96ac31acfa12381a33d39a2953f3405053870)]
- ⬆️ Update inquirer to the latest version ([#67](https://github.com/kefranabg/readme-md-generator/issues/67)) [[59f69e5](https://github.com/kefranabg/readme-md-generator/commit/59f69e51ec1caae17230d9331a2c14b04bd2825e)]
- ♻️ Refactoring inquirer code ([#69](https://github.com/kefranabg/readme-md-generator/issues/69)) [[802d57d](https://github.com/kefranabg/readme-md-generator/commit/802d57d8af2e2cdcdbddea86c2fa2225db6d4516)]
<a name="0.4.0"></a>
## 0.4.0 (2019-06-20)
### Added
- ✨ Ask for Patreon username ([#58](https://github.com/kefranabg/readme-md-generator/issues/58)) [[59b57af](https://github.com/kefranabg/readme-md-generator/commit/59b57af7aa5ce91ff0ce1998bff835d781b5df79)]
- ✨ Enable funding [[af10690](https://github.com/kefranabg/readme-md-generator/commit/af10690857df92d29807a37abce055d5351f99f4)]
- ✨ Add -v alias for --version option ([#50](https://github.com/kefranabg/readme-md-generator/issues/50)) [[a30cf02](https://github.com/kefranabg/readme-md-generator/commit/a30cf02531a4d26e85ed5e9db9ada6262d478711)]
### Fixed
- 🐛 Prevent from using inquirer 6.4 [[688c754](https://github.com/kefranabg/readme-md-generator/commit/688c754584bfb7d9191eb30e18563e16f2a7b3ff)]
### Miscellaneous
- 👥 Add contributors [[2533cd8](https://github.com/kefranabg/readme-md-generator/commit/2533cd8f2c8c78a043e67ca2bead9b4606606121)]
- docs: add kefranabg as a contributor ([#57](https://github.com/kefranabg/readme-md-generator/issues/57)) [[e5d9d53](https://github.com/kefranabg/readme-md-generator/commit/e5d9d5376b8341e06005e497728935c2874631b6)]
- 📝 Update README [[0dff1e5](https://github.com/kefranabg/readme-md-generator/commit/0dff1e5562404559b2ad64ccf0c8fc3d1df73f92)]
- 📝 Replace static version badge by a dynamic one [[99a507d](https://github.com/kefranabg/readme-md-generator/commit/99a507d6ebf54b58aaf941e1752e7e4d16565a53)]
- 📝 Update doc to use npx ([#55](https://github.com/kefranabg/readme-md-generator/issues/55)) [[77d6fdc](https://github.com/kefranabg/readme-md-generator/commit/77d6fdc4f0a2d9b86d3169f35ed8eab355ebcd68)]
- 📝 Update badge list on README [[e87ed1a](https://github.com/kefranabg/readme-md-generator/commit/e87ed1ae92f04cc94e06a3e6339090588b3eaa17)]
- 📝 Add available options in README ([#49](https://github.com/kefranabg/readme-md-generator/issues/49)) [[93da519](https://github.com/kefranabg/readme-md-generator/commit/93da51958d04335674201490cb90b9f04f5551bb)]
<a name="0.3.0"></a>
## 0.3.0 (2019-06-15)
### Added
- ✨ Add --yes flag ([#45](https://github.com/kefranabg/readme-md-generator/issues/45)) [[f0e2bd6](https://github.com/kefranabg/readme-md-generator/commit/f0e2bd6aaa0ed7b47843482046d4c443db5643c7)]
- ✨ Add prerequisites badges ([#38](https://github.com/kefranabg/readme-md-generator/issues/38)) [[e7e3590](https://github.com/kefranabg/readme-md-generator/commit/e7e3590023027f80acde722aa91824d9bc3d0b26)]
- ✅ Add missing test to readme generation [[d5027e4](https://github.com/kefranabg/readme-md-generator/commit/d5027e4d0e0d31e9059729e208e20908b299f040)]
- ✨ Add Twitter follow badge ([#35](https://github.com/kefranabg/readme-md-generator/issues/35)) [[58034a0](https://github.com/kefranabg/readme-md-generator/commit/58034a00bfdf6ea50e4ffabdd39657dfce317fee)]
- ✨ Improve README template [[7a12c8a](https://github.com/kefranabg/readme-md-generator/commit/7a12c8a687f50da7fee1c2b2352363f3abf1e71f)]
- ✨ Improve README content [[ffd6e1f](https://github.com/kefranabg/readme-md-generator/commit/ffd6e1f9653c31168bf025e797e05951bc9ab15a)]
- ✨ Adding some commands [[6850244](https://github.com/kefranabg/readme-md-generator/commit/685024493f8670559df643b551f383b9cbf434b0)]
- 🔊 Add logs in writeReadme [[772d536](https://github.com/kefranabg/readme-md-generator/commit/772d536a99fea4d0a8024fedb02664ae3a968351)]
- ✨ Add homepage link if exist [[1c1bf08](https://github.com/kefranabg/readme-md-generator/commit/1c1bf08b29ef16a677114d74eb145d3a83f3c35a)]
### Changed
- 💄 change prerequisite badges color ([#43](https://github.com/kefranabg/readme-md-generator/issues/43)) [[e888726](https://github.com/kefranabg/readme-md-generator/commit/e888726b471a28265ed689786f85c8618b9af957)]
- 🔧 Move some dependencies in devDependencies [[0038201](https://github.com/kefranabg/readme-md-generator/commit/0038201ec94f1d31b3473948cdfd9f950466d4ad)]
- 💬 Update badge version in README [[e5d418c](https://github.com/kefranabg/readme-md-generator/commit/e5d418c2b3b7e6fcbb2e5631adb70b51c2b82843)]
### Fixed
- 🐛 Fix current working directory error ([#46](https://github.com/kefranabg/readme-md-generator/issues/46)) [[6c184ba](https://github.com/kefranabg/readme-md-generator/commit/6c184ba009cfafb25adb1ff7ba6e1c4570de7503)]
- 🐛 Fix error when package.json does not exist ([#42](https://github.com/kefranabg/readme-md-generator/issues/42)) [[fe0fc61](https://github.com/kefranabg/readme-md-generator/commit/fe0fc61e4664baf457e1d6f4a35e50e8cd325c10)]
- ✏️ Remove whitespace before punctuation marks ([#36](https://github.com/kefranabg/readme-md-generator/issues/36)) [[094f9fb](https://github.com/kefranabg/readme-md-generator/commit/094f9fb5e7ebe6cc9001d1fe54cd9be0362730bd)]
- 🐛 Get doc url from only if github repos [[62109c4](https://github.com/kefranabg/readme-md-generator/commit/62109c4b315613100b7adf9b9714b5a7e6c00b31)]
<a name="0.1.4"></a>
## 0.1.4 (2019-06-11)
### Added
- ✨ Add instruction in README [[8f32674](https://github.com/kefranabg/readme-md-generator/commit/8f3267442fbd1673e9c13969858c2075864d8be6)]
- ✅ Add missing test for cli [[cdd7df6](https://github.com/kefranabg/readme-md-generator/commit/cdd7df640401fbce044c0e042bc02a8ede09b818)]
- ✨ Improve README content [[9bb7e90](https://github.com/kefranabg/readme-md-generator/commit/9bb7e909d838bc6ae364f8ca40115adda590a9c4)]
- ✅ Add cli tests [[2c5ed1e](https://github.com/kefranabg/readme-md-generator/commit/2c5ed1e1fb249f4f10e6ec7b304b1df1fbb38ec7)]
- ✅ Add tests for project infos module [[aae1bc6](https://github.com/kefranabg/readme-md-generator/commit/aae1bc6872a60feb2cfd6e50057be857f6a87db8)]
- ✨ Improve README content [[34d475c](https://github.com/kefranabg/readme-md-generator/commit/34d475cf4d446317430587d5b50644cf18049975)]
- ✅ Add tests for questions [[576a290](https://github.com/kefranabg/readme-md-generator/commit/576a290f77cab6376c50d9edf3d6c51e572988af)]
- ✅ Add tests for readme file [[0e18c2e](https://github.com/kefranabg/readme-md-generator/commit/0e18c2e73a16fb0edc039e3d28de52691c9409df)]
- ✨ Enable code cov ([#23](https://github.com/kefranabg/readme-md-generator/issues/23)) [[46d21b5](https://github.com/kefranabg/readme-md-generator/commit/46d21b5df0f26cba8f9d3eb42492a129d3dc4dd1)]
- ✨ Add log infos during process [[912c602](https://github.com/kefranabg/readme-md-generator/commit/912c602c9022ebcfd84f66ffce96ab814f424cd7)]
- ✨ Improve README [[a8ff226](https://github.com/kefranabg/readme-md-generator/commit/a8ff22685daac89d22ac1756b480a2f6777d0f50)]
- ✨ Improve README [[83796b2](https://github.com/kefranabg/readme-md-generator/commit/83796b29d055a52b9c7a67f9e9405141972b236c)]
- ✨ Add some badges [[3174ab9](https://github.com/kefranabg/readme-md-generator/commit/3174ab9830b47919559a2c4cdc73b4a598b9e9d9)]
- ✨ Add documentation badge [[dd435ca](https://github.com/kefranabg/readme-md-generator/commit/dd435ca85d2d5fa00b8cd28d956b6ff8ce08ea1f)]
- ✨ Add license url and name auto detection [[d2ee432](https://github.com/kefranabg/readme-md-generator/commit/d2ee432d5cd09b163efcfccf7e37354754eb589b)]
- ✨ Add prerequisites section in README [[9924f72](https://github.com/kefranabg/readme-md-generator/commit/9924f723afacee5c03fddd6b0436edf207cd618f)]
- ✨ Add npm version infos [[9ce8bb6](https://github.com/kefranabg/readme-md-generator/commit/9ce8bb64924404f01f2e5a0105b3241b15be1d65)]
- ✨ Add default value for github username if repos is github [[a59520f](https://github.com/kefranabg/readme-md-generator/commit/a59520ffd877cc0a091343d764733d058f6862c1)]
- ✨ Add contributing section [[d0f61f9](https://github.com/kefranabg/readme-md-generator/commit/d0f61f93f25998c2020f14e77165f0990cf43fb4)]
- ✨ Improve README content [[01134d2](https://github.com/kefranabg/readme-md-generator/commit/01134d2b9d8f347335dc132b1c9ea1edddc1aac4)]
- ✨ Improve README content [[5c4c2e8](https://github.com/kefranabg/readme-md-generator/commit/5c4c2e804429e75f912cd45c0192a990d1287a3e)]
- ✨ Improve README content [[0b4fe40](https://github.com/kefranabg/readme-md-generator/commit/0b4fe40281f447132011a3326847e6b6829d08ac)]
- ✨ Improve support section in README [[91a6f9e](https://github.com/kefranabg/readme-md-generator/commit/91a6f9e785a51cfdbc945b759216ef5e1708d682)]
- ✨ Add license to README [[096d44f](https://github.com/kefranabg/readme-md-generator/commit/096d44fc89108fb91ec51b2d10a6a71fdb274ae5)]
- ✨ Renaming questions function names [[8907db0](https://github.com/kefranabg/readme-md-generator/commit/8907db008882dd5b7a76864e59452ee5e7b9e5d7)]
- ✨ Add Greenkeeper 🌴 [[f69b4ad](https://github.com/kefranabg/readme-md-generator/commit/f69b4adc5307be9492dc4ea370696cd84ebf8d53)]
- ✨ Add support section in README [[b16af00](https://github.com/kefranabg/readme-md-generator/commit/b16af00df801992cdd56df54cbb8a913279ab544)]
- ✨ Add footer in README [[3d2cd7d](https://github.com/kefranabg/readme-md-generator/commit/3d2cd7d2d0d6c737d18b3e68b8e19ef40d316e4f)]
- ✨ Update README.md [[699f250](https://github.com/kefranabg/readme-md-generator/commit/699f250223ddd8d11872e3e3023056b15740d3ea)]
- ✨ Add author information in README [[2337d6b](https://github.com/kefranabg/readme-md-generator/commit/2337d6b6a8a933bbb55d4ab6489999dc2fb74363)]
- ✨ Improve author infos logic [[5d4cf6f](https://github.com/kefranabg/readme-md-generator/commit/5d4cf6fe9f790d4d2ee6bcc151e8283c7ac06655)]
- ✨ Add author information in README [[665303a](https://github.com/kefranabg/readme-md-generator/commit/665303a623f359d819872faae4e432cb95e82a8c)]
- 🎉 Initial commit [[500b2e8](https://github.com/kefranabg/readme-md-generator/commit/500b2e81875aeb61f94b6202bcb5d0b264cf7413)]
### Changed
- 🎨 Improve README structure [[1ced8d6](https://github.com/kefranabg/readme-md-generator/commit/1ced8d6ff426f5806d110f2c92b653547187c6c5)]
- 💬 Fix README format [[20005b6](https://github.com/kefranabg/readme-md-generator/commit/20005b6d243d26a8ab8d049e722776218796bb82)]
- 🔧 Update jest config [[3a9d847](https://github.com/kefranabg/readme-md-generator/commit/3a9d84742423d9da5b1c3c19dc96a1846010a44d)]
- 🔧 Add jest config [[5f629ed](https://github.com/kefranabg/readme-md-generator/commit/5f629edd4bb0f9d2eb7b6e7749a92454468c08a3)]
- ♻️ Code refactoring [[79cfbbf](https://github.com/kefranabg/readme-md-generator/commit/79cfbbf7e6cc5eefb6cd1f2a1a6809f4a9c9c593)]
- ♻️ CLI refactoring [[ead151b](https://github.com/kefranabg/readme-md-generator/commit/ead151b9a7c2e177cd9859fb3691c530f09ded3c)]
- ♻️ Code refactoring [[1ae6c40](https://github.com/kefranabg/readme-md-generator/commit/1ae6c40fb89f9099f0dc38e5bb843d2719d23b07)]
- 💬 Rename command in README [[4279e2e](https://github.com/kefranabg/readme-md-generator/commit/4279e2e99e9e21a58104632478be612f9f80dbf8)]
- 💬 Update project name [[2cad8e3](https://github.com/kefranabg/readme-md-generator/commit/2cad8e3cfca8afc33585f0de5e11378add9dad26)]
- 🔧 Add bin config [[56d7e78](https://github.com/kefranabg/readme-md-generator/commit/56d7e7840a48f8d6d653db00538303a2dac07a77)]
- 💬 Improve questions text [[67d611b](https://github.com/kefranabg/readme-md-generator/commit/67d611b4ba9489bdf2297e2ba120eddee0368a7a)]
- ♻️ Utils code refactoring [[97d675e](https://github.com/kefranabg/readme-md-generator/commit/97d675efb088139949cf57e1bc0c8d534f41b136)]
- ♻️ Code refactoring [[c14974c](https://github.com/kefranabg/readme-md-generator/commit/c14974c5b24e370c4af54ca1a7d71375eeb2bfc2)]
- 🎨 Improve README title [[8c79b5e](https://github.com/kefranabg/readme-md-generator/commit/8c79b5efbd5e8b94497b00164642796ce0b29033)]
- 🎨 Improve support section in README [[e855e38](https://github.com/kefranabg/readme-md-generator/commit/e855e385e0c3a8304e7e42cde4162c392269d787)]
- 💬 Update project description and README footer texts [[b1c9a87](https://github.com/kefranabg/readme-md-generator/commit/b1c9a877874b5dd925e072d84cc8e8f8cd856bab)]
- 🎨 Improve template format [[d27649f](https://github.com/kefranabg/readme-md-generator/commit/d27649f1a0a3f6344c74a735040436010dec86b8)]
- ♻️ Questions and utils code refactoring [[a5b5a4c](https://github.com/kefranabg/readme-md-generator/commit/a5b5a4c95da8643af319299448d93db0123fafa1)]
- ♻️ Questions and utils functions refactoring [[177c086](https://github.com/kefranabg/readme-md-generator/commit/177c08699989328d5ceeb71c139b196f58bd23c0)]
- 🚨 Fix file format with prettier [[aa6e3eb](https://github.com/kefranabg/readme-md-generator/commit/aa6e3eb6081cdc0d34c872c078f3a9e415a45d2b)]
### Removed
- 🔥 Remove unused export [[bdc0e3e](https://github.com/kefranabg/readme-md-generator/commit/bdc0e3eb4d2d37240715abb1703eedcbe0dc5e2a)]
### Fixed
- 🐛 Fix badge bad link [[d8c8e45](https://github.com/kefranabg/readme-md-generator/commit/d8c8e45e77f8f5f8c68b60c176da09808e4cbb4c)]
- 🐛 Fix bug when engines infos were not found [[918140e](https://github.com/kefranabg/readme-md-generator/commit/918140e6ad98f01279b5b2b617d4976b330faecd)]
- 🐛 Fix badges links [[acd0a22](https://github.com/kefranabg/readme-md-generator/commit/acd0a22b9885501503d298ed125942b043884c82)]
- 🐛 Fix badge display [[623afd9](https://github.com/kefranabg/readme-md-generator/commit/623afd9cc1831e144bcdf1ba0c0d0fc4c75c9324)]
- 🐛 Fix author infos [[2d8b2c2](https://github.com/kefranabg/readme-md-generator/commit/2d8b2c25096fbc05ac1a24aadfd68e93899782e3)]
### Miscellaneous
- 0.1.4 [[65ddd76](https://github.com/kefranabg/readme-md-generator/commit/65ddd767df2712ca39527a4a30dbbcffa00be87a)]
- 📝 Add demo to README [[19f04e2](https://github.com/kefranabg/readme-md-generator/commit/19f04e232f9363d72b9c0c5e7c8c7f4ab363528d)]
- Merge pull request [#20](https://github.com/kefranabg/readme-md-generator/issues/20) from kefranabg/greenkeeper/initial [[acfa940](https://github.com/kefranabg/readme-md-generator/commit/acfa9407c90edd2eff549f1d21a48b3add60428a)]
- docs(readme): add Greenkeeper badge [[d3ad805](https://github.com/kefranabg/readme-md-generator/commit/d3ad80571868c75e84de42cad13f3af64582bf8f)]
- 📝 Update project description [[6fadc05](https://github.com/kefranabg/readme-md-generator/commit/6fadc05bffd78dfa9855578ce4af708950dc7c4c)]
- Update README [[ee6f44f](https://github.com/kefranabg/readme-md-generator/commit/ee6f44f49ef29dba8163898a36f24efc656f762c)]
- docs(readme): add Greenkeeper badge [[1d6fe09](https://github.com/kefranabg/readme-md-generator/commit/1d6fe09fd824be7489c10978a228acac287360da)]
- Initial commit [[dd97da0](https://github.com/kefranabg/readme-md-generator/commit/dd97da0e0a4540806ec83152b586dd0b8f8421a1)]
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Readme Markdown Generator
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.
Please note we have a [code of conduct](https://github.com/kefranabg/readme-md-generator/blob/master/.github/CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
## Table of Contents
- [Setting Up the project locally](#setting-up-the-project-locally)
- [Submitting a Pull Request](#submitting-a-pull-request)
## Setting Up the project locally
To install the project you need to have `node` and `npm`
1. [Fork](https://help.github.com/articles/fork-a-repo/) the project, clone
your fork:
```sh
# Clone your fork
git clone https://github.com/<your-username>/readme-md-generator.git
# Navigate to the newly cloned directory
cd readme-md-generator
```
2. Your environment needs to be running `node` version >= 9.3.0 and `npm` version >= 5.5.0.
3. from the root of the project: `npm` to install all dependencies
- make sure you have latest `npm` version
4. from the root of the project: `npm start` to run the cli.
> Tip: Keep your `master` branch pointing at the original repository and make
> pull requests from branches on your fork. To do this, run:
>
> ```sh
> git remote add upstream https://github.com/kefranabg/readme-md-generator.git
> git fetch upstream
> git branch --set-upstream-to=upstream/master master
> ```
>
> This will add the original repository as a "remote" called "upstream," then
> fetch the git information from that remote, then set your local `master`
> branch to use the upstream master branch whenever you run `git pull`. Then you
> can make all of your pull request branches based on this `master` branch.
> Whenever you want to update your version of `master`, do a regular `git pull`.
## Submitting a Pull Request
Please go through existing issues and pull requests to check if somebody else is already working on it.
Also, make sure to run the tests and lint the code before you commit your
changes.
```sh
npm run test
npm run lint
```
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 Franck Abgrall
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<h1 align="center">Welcome to readme-md-generator 👋</h1>
<p align="center">
<img src="https://img.shields.io/npm/v/readme-md-generator.svg?orange=blue" />
<a href="https://www.npmjs.com/package/readme-md-generator">
<img alt="downloads" src="https://img.shields.io/npm/dm/readme-md-generator.svg?color=blue" target="_blank" />
</a>
<a href="https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE">
<img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-yellow.svg" target="_blank" />
</a>
<a href="https://codecov.io/gh/kefranabg/readme-md-generator">
<img src="https://codecov.io/gh/kefranabg/readme-md-generator/branch/master/graph/badge.svg" />
</a>
<a href="https://github.com/frinyvonnick/gitmoji-changelog">
<img src="https://img.shields.io/badge/changelog-gitmoji-brightgreen.svg" alt="gitmoji-changelog">
</a>
<a href="https://twitter.com/FranckAbgrall">
<img alt="Twitter: FranckAbgrall" src="https://img.shields.io/twitter/follow/FranckAbgrall.svg?style=social" target="_blank" />
</a>
</p>
> CLI that generates beautiful README.md files.<br /> `readme-md-generator` will suggest you default answers by reading your `package.json` and `git` configuration.
## ✨ Demo
`readme-md-generator` is able to read your environment (package.json, git config...) to suggest you default answers during the `README.md` creation process:
<p align="center">
<img width="700" align="center" src="https://user-images.githubusercontent.com/9840435/60266022-72a82400-98e7-11e9-9958-f9004c2f97e1.gif" alt="demo"/>
</p>
Generated `README.md`:
<p align="center">
<img width="700" src="https://user-images.githubusercontent.com/9840435/60266090-9cf9e180-98e7-11e9-9cac-3afeec349bbc.jpg" alt="cli output"/>
</p>
Example of `package.json` with good meta data:
```json
// The package.json is not required to run README-MD-GENERATOR
{
"name": "readme-md-generator",
"version": "0.1.3",
"description": "CLI that generates beautiful README.md files.",
"author": "Franck Abgrall",
"license": "MIT",
"homepage": "https://github.com/kefranabg/readme-md-generator#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/kefranabg/readme-md-generator.git"
},
"bugs": {
"url": "https://github.com/kefranabg/readme-md-generator/issues"
},
"engines": {
"npm": ">=5.5.0",
"node": ">=9.3.0"
}
}
```
## 🚀 Usage
Make sure you have [npx](https://www.npmjs.com/package/npx) installed (`npx` is shipped by default since npm `5.2.0`)
Just run the following command at the root of your project and answer questions:
```sh
npx readme-md-generator
```
Or use default values for all questions (`-y`):
```sh
npx readme-md-generator -y
```
Use your own `ejs` README template (`-p`):
```sh
npx readme-md-generator -p path/to/my/own/template.md
```
You can find [ejs README template examples here](https://github.com/kefranabg/readme-md-generator/tree/master/templates).
## Code Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/kefranabg/readme-md-generator/graphs/contributors"><img src="https://opencollective.com/readme-md-generator/contributors.svg?width=890&button=false" /></a>
## Financial Contributors
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/readme-md-generator/contribute)]
### Individuals
<a href="https://opencollective.com/readme-md-generator"><img src="https://opencollective.com/readme-md-generator/individuals.svg?width=890"></a>
### Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/readme-md-generator/contribute)]
<a href="https://opencollective.com/readme-md-generator/organization/0/website"><img src="https://opencollective.com/readme-md-generator/organization/0/avatar.svg"></a>
<a href="https://opencollective.com/readme-md-generator/organization/1/website"><img src="https://opencollective.com/readme-md-generator/organization/1/avatar.svg"></a>
<a href="https://opencollective.com/readme-md-generator/organization/2/website"><img src="https://opencollective.com/readme-md-generator/organization/2/avatar.svg"></a>
<a href="https://opencollective.com/readme-md-generator/organization/3/website"><img src="https://opencollective.com/readme-md-generator/organization/3/avatar.svg"></a>
<a href="https://opencollective.com/readme-md-generator/organization/4/website"><img src="https://opencollective.com/readme-md-generator/organization/4/avatar.svg"></a>
<a href="https://opencollective.com/readme-md-generator/organization/5/website"><img src="https://opencollective.com/readme-md-generator/organization/5/avatar.svg"></a>
<a href="https://opencollective.com/readme-md-generator/organization/6/website"><img src="https://opencollective.com/readme-md-generator/organization/6/avatar.svg"></a>
<a href="https://opencollective.com/readme-md-generator/organization/7/website"><img src="https://opencollective.com/readme-md-generator/organization/7/avatar.svg"></a>
<a href="https://opencollective.com/readme-md-generator/organization/8/website"><img src="https://opencollective.com/readme-md-generator/organization/8/avatar.svg"></a>
<a href="https://opencollective.com/readme-md-generator/organization/9/website"><img src="https://opencollective.com/readme-md-generator/organization/9/avatar.svg"></a>
## 🤝 Contributing
Contributions, issues and feature requests are welcome.<br />
Feel free to check [issues page](https://github.com/kefranabg/readme-md-generator/issues) if you want to contribute.<br />
[Check the contributing guide](./CONTRIBUTING.md).<br />
## Author
👤 **Franck Abgrall**
- Twitter: [@FranckAbgrall](https://twitter.com/FranckAbgrall)
- Github: [@kefranabg](https://github.com/kefranabg)
## Show your support
Please ⭐️ this repository if this project helped you!
<a href="https://www.patreon.com/FranckAbgrall">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160">
</a>
## 📝 License
Copyright © 2019 [Franck Abgrall](https://github.com/kefranabg).<br />
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)_
================================================
FILE: jest.config.js
================================================
module.exports = {
collectCoverageFrom: [
'./src/**/*.js',
'!./src/index.js',
'!**/node_modules/**',
'!**/vendor/**'
]
}
================================================
FILE: package.json
================================================
{
"name": "readme-md-generator",
"version": "1.0.0",
"description": "CLI that generates beautiful README.md files.",
"main": "src/index.js",
"bin": {
"readme": "src/index.js"
},
"dependencies": {
"boxen": "^4.0.0",
"date-fns": "^2.0.1",
"ejs": "^3.0.1",
"git-repo-name": "^1.0.1",
"inquirer": "~7.0.0",
"load-json-file": "^6.0.0",
"lodash": "^4.17.11",
"markdown-escape": "^1.0.2",
"node-fetch": "^2.6.0",
"ora": "4.0.3",
"yargs": "^15.0.1"
},
"devDependencies": {
"codecov": "^3.5.0",
"eslint": "^6.0.0",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-plugin-import": "^2.17.3",
"jest": "^24.8.0",
"prettier": "^1.17.1"
},
"scripts": {
"lint": "eslint src",
"prettier": "prettier \"**/*.{js,md,json}\"",
"prettier:check": "npm run prettier -- --check",
"prettier:fix": "npm run prettier -- --write",
"start": "node src/index.js",
"test": "jest",
"test:ci": "jest --coverage && codecov"
},
"repository": {
"type": "git",
"url": "git+https://github.com/kefranabg/readme-md-generator.git"
},
"keywords": [
"readme",
"md",
"cli",
"generator",
"template"
],
"author": "Franck Abgrall",
"license": "MIT",
"bugs": {
"url": "https://github.com/kefranabg/readme-md-generator/issues"
},
"homepage": "https://github.com/kefranabg/readme-md-generator#readme",
"publishConfig": {
"registry": "https://npm.pkg.github.com/@kefranabg"
},
"engines": {
"npm": ">=5.5.0",
"node": ">=9.3.0"
}
}
================================================
FILE: src/__snapshots__/readme.spec.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`readme buildReadmeContent should return readme default template content 1`] = `
"<h1 align=\\"center\\">Welcome to readme-md-generator 👋</h1>
<p>
<a href=\\"https://www.npmjs.com/package/readme-md-generator\\" target=\\"_blank\\">
<img alt=\\"Version\\" src=\\"https://img.shields.io/npm/v/readme-md-generator.svg\\">
</a>
<img src=\\"https://img.shields.io/badge/npm-%3E%3D5.5.0-blue.svg\\" />
<img src=\\"https://img.shields.io/badge/node-%3E%3D%209.3.0-blue.svg\\" />
<a href=\\"https://github.com/kefranabg/readme-md-generator#readme\\" target=\\"_blank\\">
<img alt=\\"Documentation\\" src=\\"https://img.shields.io/badge/documentation-yes-brightgreen.svg\\" />
</a>
<a href=\\"https://github.com/kefranabg/readme-md-generator/graphs/commit-activity\\" target=\\"_blank\\">
<img alt=\\"Maintenance\\" src=\\"https://img.shields.io/badge/Maintained%3F-yes-green.svg\\" />
</a>
<a href=\\"https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE\\" target=\\"_blank\\">
<img alt=\\"License: MIT\\" src=\\"https://img.shields.io/github/license/kefranabg/readme-md-generator\\" />
</a>
<a href=\\"https://twitter.com/FranckAbgrall\\" target=\\"_blank\\">
<img alt=\\"Twitter: FranckAbgrall\\" src=\\"https://img.shields.io/twitter/follow/FranckAbgrall.svg?style=social\\" />
</a>
</p>
> Generates beautiful README files from git config & package.json infos
### 🏠 [Homepage](https://github.com/kefranabg/readme-md-generator#readme)
### ✨ [Demo](https://github.com/kefranabg/readme-md-generator#-demo)
## Prerequisites
- npm >=5.5.0
- node >= 9.3.0
## Install
\`\`\`sh
npm install
\`\`\`
## Usage
\`\`\`sh
npm start
\`\`\`
## Run tests
\`\`\`sh
npm run test
\`\`\`
## Author
👤 **Franck Abgrall**
* Website: https://www.franck-abgrall.me/
* Twitter: [@FranckAbgrall](https://twitter.com/FranckAbgrall)
* GitHub: [@kefranabg](https://github.com/kefranabg)
* LinkedIn: [@franckabgrall](https://linkedin.com/in/franckabgrall)
## 🤝 Contributing
Contributions, issues and feature requests are welcome!<br />Feel free to check [issues page](https://github.com/kefranabg/readme-md-generator/issues). You can also take a look at the [contributing guide](https://github.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md).
## Show your support
Give a ⭐️ if this project helped you!
<a href=\\"https://www.patreon.com/FranckAbgrall\\">
<img src=\\"https://c5.patreon.com/external/logo/become_a_patron_button@2x.png\\" width=\\"160\\">
</a>
## 📝 License
Copyright © 2019 [Franck Abgrall](https://github.com/kefranabg).<br />
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)_"
`;
exports[`readme buildReadmeContent should return readme default template no html content 1`] = `
"# Welcome to readme-md-generator 👋
[](https://www.npmjs.com/package/readme-md-generator)


[](https://github.com/kefranabg/readme-md-generator#readme)
[](https://github.com/kefranabg/readme-md-generator/graphs/commit-activity)
[](https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE)
[](https://twitter.com/FranckAbgrall)
> Generates beautiful README files from git config & package.json infos
### 🏠 [Homepage](https://github.com/kefranabg/readme-md-generator#readme)
### ✨ [Demo](https://github.com/kefranabg/readme-md-generator#-demo)
## Prerequisites
- npm >=5.5.0
- node >= 9.3.0
## Install
\`\`\`sh
npm install
\`\`\`
## Usage
\`\`\`sh
npm start
\`\`\`
## Run tests
\`\`\`sh
npm run test
\`\`\`
## Author
👤 **Franck Abgrall**
* Website: https://www.franck-abgrall.me/
* Twitter: [@FranckAbgrall](https://twitter.com/FranckAbgrall)
* GitHub: [@kefranabg](https://github.com/kefranabg)
* LinkedIn: [@franckabgrall](https://linkedin.com/in/franckabgrall)
## 🤝 Contributing
Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/kefranabg/readme-md-generator/issues). You can also take a look at the [contributing guide](https://github.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md).
## Show your support
Give a ⭐️ if this project helped you!
[](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)_"
`;
================================================
FILE: src/ask-overwrite.js
================================================
const inquirer = require('inquirer')
const question = {
type: 'list',
message:
'🚨 readme-md-generator will overwrite your current README.md. Are you sure you want to continue? ',
name: 'overwriteReadme',
choices: [
{
name: 'No',
value: false
},
{
name: 'Yes ',
value: true
}
]
}
/**
* Ask users if they want to overwrite the existing README
*/
module.exports = async () => {
const { overwriteReadme } = await inquirer.prompt([question])
return overwriteReadme
}
================================================
FILE: src/ask-overwrite.spec.js
================================================
const inquirer = require('inquirer')
const askOverwrite = require('./ask-overwrite')
const expectedQuestion = {
type: 'list',
message:
'🚨 readme-md-generator will overwrite your current README.md. Are you sure you want to continue? ',
name: 'overwriteReadme',
choices: [
{
name: 'No',
value: false
},
{
name: 'Yes ',
value: true
}
]
}
inquirer.prompt = jest.fn(items =>
Promise.resolve(
items.reduce((result, item) => {
result[item.name] = 'value'
return result
}, {})
)
)
describe('ask-overwrite', () => {
beforeEach(() => {
inquirer.prompt.mockClear()
})
it('should call prompt right questions', async () => {
await askOverwrite()
expect(inquirer.prompt).toHaveBeenCalledWith([expectedQuestion])
})
it('should return the right value', async () => {
expect(await askOverwrite()).toEqual('value')
})
})
================================================
FILE: src/ask-questions.js
================================================
const inquirer = require('inquirer')
const { flatMap } = require('lodash')
const questionsBuilders = require('./questions')
const utils = require('./utils')
/**
* Ask user questions and return context to generate a README
*
* @param {Object} projectInfos
* @param {Boolean} useDefaultAnswers
*/
module.exports = async (projectInfos, useDefaultAnswers) => {
const questions = flatMap(Object.values(questionsBuilders), questionBuilder =>
questionBuilder(projectInfos)
)
const answersContext = useDefaultAnswers
? await utils.getDefaultAnswers(questions)
: await inquirer.prompt(questions)
return {
isGithubRepos: projectInfos.isGithubRepos,
repositoryUrl: projectInfos.repositoryUrl,
projectPrerequisites: undefined,
isProjectOnNpm: utils.isProjectAvailableOnNpm(answersContext.projectName),
...answersContext
}
}
================================================
FILE: src/ask-questions.spec.js
================================================
const inquirer = require('inquirer')
const questions = require('./questions')
const askQuestions = require('./ask-questions')
inquirer.prompt = jest.fn(items =>
Promise.resolve(
items.reduce((result, item) => {
result[item.name] = 'value'
return result
}, {})
)
)
jest.mock('./questions', () => ({
askProjectName: jest.fn(() => ({
name: 'projectName',
type: 'input',
default: 'defaultProjectName'
})),
askProjectVersion: jest.fn(() => ({
name: 'projectVersion',
type: 'input'
})),
askProjectDescription: jest.fn(() => ({
name: 'projectDescription',
type: 'checkbox',
choices: [
{ value: { name: 'choiceOne', value: 1 }, checked: true },
{ value: { name: 'choiceTwo', value: 2 }, checked: false }
]
}))
}))
describe('ask-questions', () => {
beforeEach(() => {
inquirer.prompt.mockClear()
})
it('should call all builder functions exported by questions', async () => {
const projectInfos = { name: 'readme-md-generator' }
await askQuestions(projectInfos, false)
expect(questions.askProjectName).toHaveBeenCalledTimes(1)
expect(questions.askProjectVersion).toHaveBeenCalledTimes(1)
expect(questions.askProjectDescription).toHaveBeenCalledTimes(1)
})
it('should use default values with --yes option', async () => {
const result = await askQuestions({}, true)
expect(inquirer.prompt).not.toHaveBeenCalled()
expect(result).toEqual({
projectName: 'defaultProjectName',
projectVersion: '',
projectDescription: [{ name: 'choiceOne', value: 1 }],
isGithubRepos: undefined,
repositoryUrl: undefined,
projectPrerequisites: undefined,
isProjectOnNpm: false
})
})
it('should return merged contexts', async () => {
const projectInfos = { name: 'readme-md-generator' }
const context = await askQuestions(projectInfos, false)
expect(context).toEqual({
projectName: 'value',
projectVersion: 'value',
projectDescription: 'value',
isGithubRepos: undefined,
repositoryUrl: undefined,
projectPrerequisites: undefined,
isProjectOnNpm: true
})
})
})
================================================
FILE: src/choose-template.js
================================================
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
}
================================================
FILE: src/choose-template.spec.js
================================================
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
}
]
}
])
})
})
================================================
FILE: src/clean-context.js
================================================
/**
* Clean answer context
*
* @param {Object} context
*/
module.exports = context => {
const cleanBadgeText = text => text.replace(/-/g, '--').replace(/_/g, '__')
// Why doing this?
// See https://github.com/kefranabg/readme-md-generator/pull/141
const licenseName = context.licenseName
.replace(/-/g, '--')
.replace(/_/g, '__')
const projectVersion = cleanBadgeText(context.projectVersion)
return {
...context,
licenseName,
projectVersion
}
}
================================================
FILE: src/clean-context.spec.js
================================================
const cleanContext = require('./clean-context')
describe('cleanContext', () => {
it('should replace licenseName and projectVersion - and _ characters by -- and __', () => {
const context = {
licenseName: 'Apache-2_0',
projectVersion: '1.0_0-alpha'
}
const cleanedContext = {
licenseName: 'Apache--2__0',
projectVersion: '1.0__0--alpha'
}
const result = cleanContext(context)
expect(result).toEqual(cleanedContext)
})
})
================================================
FILE: src/cli.js
================================================
const readme = require('./readme')
const infos = require('./project-infos')
const utils = require('./utils')
const askQuestions = require('./ask-questions')
const cleanContext = require('./clean-context')
/**
* Main process:
* 1) Check overwrite README.md
* 2) Get README template path
* 3) Gather project infos
* 4) Ask user questions
* 5) Clean answer context
* 6) Build README content
* 7) Create README.md file
*
* @param {Object} args
*/
module.exports = async ({ customTemplatePath, useDefaultAnswers }) => {
if (!(await readme.checkOverwriteReadme())) return
const templatePath = await readme.getReadmeTemplatePath(
customTemplatePath,
useDefaultAnswers
)
const projectInformations = await infos.getProjectInfos()
const answersContext = await askQuestions(
projectInformations,
useDefaultAnswers
)
const cleanedContext = cleanContext(answersContext)
const readmeContent = await readme.buildReadmeContent(
cleanedContext,
templatePath
)
await readme.writeReadme(readmeContent)
utils.showEndMessage()
}
================================================
FILE: src/cli.spec.js
================================================
const inquirer = require('inquirer')
const mainProcess = require('./cli')
const infos = require('./project-infos')
const readme = require('./readme')
const utils = require('./utils')
const askQuestions = require('./ask-questions')
const cleanContext = require('./clean-context')
inquirer.prompt = jest.fn(items =>
Promise.resolve(
items.reduce((result, item) => {
result[item.name] = 'value'
return result
}, {})
)
)
jest.mock('./ask-questions', () =>
jest.fn(() => Promise.resolve({ projectName: 'readme-md-generator' }))
)
jest.mock('./clean-context', () =>
jest.fn(() => ({ projectName: 'readme-md-generator-after-context-clean' }))
)
jest.mock('./questions', () => ({
askProjectName: jest.fn(() => ({
name: 'projectName',
type: 'input',
default: 'defaultProjectName'
})),
askProjectVersion: jest.fn(() => ({
name: 'projectVersion',
type: 'input'
})),
askProjectDescription: jest.fn(() => ({
name: 'projectDescription',
type: 'checkbox',
choices: [
{ value: { name: 'choiceOne', value: 1 }, checked: true },
{ value: { name: 'choiceTwo', value: 2 }, checked: false }
]
}))
}))
describe('mainProcess', () => {
afterEach(() => {
askQuestions.mockClear()
})
it('should stop immediatly if user dont want overwrite', async () => {
const customTemplatePath = undefined
const useDefaultAnswers = true
infos.getProjectInfos = jest.fn()
readme.buildReadmeContent = jest.fn()
readme.getReadmeTemplatePath = jest.fn()
readme.writeReadme = jest.fn()
readme.checkOverwriteReadme = jest.fn(() => Promise.resolve(false))
utils.showEndMessage = jest.fn()
await mainProcess({ customTemplatePath, useDefaultAnswers })
expect(infos.getProjectInfos).not.toHaveBeenCalled()
expect(cleanContext).not.toHaveBeenCalled()
expect(readme.buildReadmeContent).not.toHaveBeenCalled()
expect(readme.getReadmeTemplatePath).not.toHaveBeenCalled()
expect(readme.writeReadme).not.toHaveBeenCalled()
expect(utils.showEndMessage).not.toHaveBeenCalled()
})
it('should call main functions with correct args', async () => {
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.checkOverwriteReadme = jest.fn(() => Promise.resolve(true))
readme.writeReadme = jest.fn()
utils.showEndMessage = jest.fn()
await mainProcess({ customTemplatePath, useDefaultAnswers })
expect(readme.getReadmeTemplatePath).toHaveBeenNthCalledWith(
1,
customTemplatePath,
useDefaultAnswers
)
expect(infos.getProjectInfos).toHaveBeenCalledTimes(1)
expect(askQuestions).toHaveBeenNthCalledWith(
1,
projectInformations,
useDefaultAnswers
)
expect(cleanContext).toHaveBeenNthCalledWith(1, {
projectName: 'readme-md-generator'
})
expect(readme.buildReadmeContent).toHaveBeenNthCalledWith(
1,
{ projectName: 'readme-md-generator-after-context-clean' },
templatePath
)
expect(readme.writeReadme).toHaveBeenNthCalledWith(1, readmeContent)
expect(utils.showEndMessage).toHaveBeenCalledTimes(1)
})
})
================================================
FILE: src/index.js
================================================
#!/usr/bin/env node
const yargs = require('yargs')
const { noop } = require('lodash')
const mainProcess = require('./cli')
yargs
.usage('Usage: $0 <command> [options]')
.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')
.boolean('yes')
.alias('y', 'yes')
.describe('yes', 'Use default values for all fields')
.help()
.alias('v', 'version')
.epilog(
'for more information, find our manual at https://github.com/kefranabg/readme-md-generator'
)
.parse()
================================================
FILE: src/project-infos.js
================================================
const isNil = require('lodash/isNil')
const get = require('lodash/get')
const has = require('lodash/has')
const ora = require('ora')
const { execSync } = require('child_process')
const {
getPackageJson,
getProjectName,
getAuthorWebsiteFromGithubAPI,
getPackageManagerFromLockFile
} = require('./utils')
const GITHUB_URL = 'https://github.com/'
/**
* Clean repository url by removing '.git' and 'git+'
*
* @param {string} reposUrl
*/
const cleanReposUrl = reposUrl =>
reposUrl
.replace('\n', '')
.replace('git+', '')
.replace('.git', '')
/**
* Get repository url from pakage json
*
* @param {Object} reposUrl
*/
const getReposUrlFromPackageJson = async packageJson => {
const reposUrl = get(packageJson, 'repository.url', undefined)
return isNil(reposUrl) ? undefined : cleanReposUrl(reposUrl)
}
/**
* Get repository url from git
*/
const getReposUrlFromGit = () => {
try {
const stdout = execSync('git config --get remote.origin.url')
return cleanReposUrl(stdout)
} catch (err) {
return undefined
}
}
/**
* Get repository url from package.json or git
*
* @param {Object} packageJson
*/
const getReposUrl = async packageJson =>
(await getReposUrlFromPackageJson(packageJson)) || getReposUrlFromGit()
/**
* Get repository issues url from package.json or git
*
* @param {Object} packageJson
*/
const getReposIssuesUrl = async packageJson => {
let reposIssuesUrl = get(packageJson, 'bugs.url', undefined)
if (isNil(reposIssuesUrl)) {
const reposUrl = await getReposUrl()
if (!isNil(reposUrl)) {
reposIssuesUrl = `${reposUrl}/issues`
}
}
return reposIssuesUrl
}
/**
* Check if repository is a Github repository
*
* @param {string} repositoryUrl
*/
const isGithubRepository = repositoryUrl =>
!isNil(repositoryUrl) && repositoryUrl.includes(GITHUB_URL)
/**
* Get github username from repository url
*
* @param {string} repositoryUrl
*/
const getGithubUsernameFromRepositoryUrl = repositoryUrl =>
repositoryUrl.replace(GITHUB_URL, '').split('/')[0]
/**
* Get license url from github repository url
*
* @param {string} repositoryUrl
*/
const getLicenseUrlFromGithubRepositoryUrl = repositoryUrl =>
`${repositoryUrl}/blob/master/LICENSE`
const getReadmeUrlFromGithubRepositoryUrl = repositoryUrl =>
`${repositoryUrl}#readme`
const getContributingUrlFromRepositoryUrl = repositoryUrl =>
`${repositoryUrl}/blob/master/CONTRIBUTING.md`
/**
* Get project author name from package.json
*
* @param packageJson
* @returns {string} authorName
*/
const getAuthorName = packageJson => {
if (has(packageJson, 'author.name')) {
return get(packageJson, 'author.name', undefined)
}
if (has(packageJson, 'author') && typeof packageJson.author === 'string') {
return get(packageJson, 'author', undefined)
}
return undefined
}
/**
* Get project informations from git and package.json
*/
const getProjectInfos = async () => {
const spinner = ora('Gathering project infos').start()
const packageJson = await getPackageJson()
const isJSProject = !!packageJson
const packageManager = isJSProject
? getPackageManagerFromLockFile()
: undefined
const name = getProjectName(packageJson)
const description = get(packageJson, 'description', undefined)
const engines = get(packageJson, 'engines', undefined)
const author = getAuthorName(packageJson)
const version = get(packageJson, 'version', undefined)
const licenseName = get(packageJson, 'license', undefined)
const homepage = get(packageJson, 'homepage', undefined)
const hasStartCommand = has(packageJson, 'scripts.start')
const hasTestCommand = has(packageJson, 'scripts.test')
const repositoryUrl = await getReposUrl(packageJson)
const issuesUrl = await getReposIssuesUrl(packageJson)
const isGithubRepos = isGithubRepository(repositoryUrl)
const contributingUrl = repositoryUrl
? getContributingUrlFromRepositoryUrl(repositoryUrl)
: undefined
const documentationUrl = isGithubRepos
? getReadmeUrlFromGithubRepositoryUrl(repositoryUrl)
: undefined
const githubUsername = isGithubRepos
? getGithubUsernameFromRepositoryUrl(repositoryUrl)
: undefined
const authorWebsite = githubUsername
? await getAuthorWebsiteFromGithubAPI(githubUsername)
: undefined
const licenseUrl = isGithubRepos
? getLicenseUrlFromGithubRepositoryUrl(repositoryUrl)
: undefined
spinner.succeed('Project infos gathered')
return {
name,
description,
version,
author,
authorWebsite,
homepage,
repositoryUrl,
issuesUrl,
contributingUrl,
githubUsername,
engines,
licenseName,
licenseUrl,
documentationUrl,
isGithubRepos,
hasStartCommand,
hasTestCommand,
isJSProject,
packageManager
}
}
module.exports = {
getProjectInfos
}
================================================
FILE: src/project-infos.spec.js
================================================
const ora = require('ora')
const childProcess = require('child_process')
const utils = require('./utils')
const { getProjectInfos } = require('./project-infos')
jest.mock('ora')
jest.mock('child_process', () => ({
execSync: jest.fn()
}))
jest.mock('./utils', () => ({
getPackageJson: jest.fn(),
getProjectName: jest.fn(() => 'readme-md-generator'),
getAuthorWebsiteFromGithubAPI: jest.fn(
() => 'https://www.franck-abgrall.me/'
),
getPackageManagerFromLockFile: jest.fn(() => 'yarn')
}))
const succeed = jest.fn()
const fail = jest.fn()
ora.mockReturnValue({
start: () => ({
succeed,
fail
})
})
describe('projectInfos', () => {
describe('getProjectInfos', () => {
it('should call ora with correct parameters', async () => {
await getProjectInfos()
expect(ora).toHaveBeenCalledTimes(1)
expect(ora).toHaveBeenCalledWith('Gathering project infos')
expect(succeed).toHaveBeenCalledTimes(1)
expect(succeed).toHaveBeenCalledWith('Project infos gathered')
})
it('should return correct infos', async () => {
const packgeJsonInfos = {
name: 'readme-md-generator',
version: '0.1.3',
description: 'CLI that generates beautiful README.md files.',
author: 'Franck Abgrall',
license: 'MIT',
homepage: 'https://github.com/kefranabg/readme-md-generator',
repository: {
type: 'git',
url: 'git+https://github.com/kefranabg/readme-md-generator.git'
},
bugs: {
url: 'https://github.com/kefranabg/readme-md-generator/issues'
},
engines: {
npm: '>=5.5.0',
node: '>=9.3.0'
}
}
utils.getPackageJson.mockReturnValueOnce(Promise.resolve(packgeJsonInfos))
childProcess.execSync.mockReturnValue(
'https://github.com/kefranabg/readme-md-generator.git'
)
const projectInfos = await getProjectInfos()
expect(projectInfos).toEqual({
name: 'readme-md-generator',
description: 'CLI that generates beautiful README.md files.',
version: '0.1.3',
author: 'Franck Abgrall',
repositoryUrl: 'https://github.com/kefranabg/readme-md-generator',
homepage: 'https://github.com/kefranabg/readme-md-generator',
contributingUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md',
authorWebsite: 'https://www.franck-abgrall.me/',
githubUsername: 'kefranabg',
engines: {
npm: '>=5.5.0',
node: '>=9.3.0'
},
licenseName: 'MIT',
licenseUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE',
documentationUrl:
'https://github.com/kefranabg/readme-md-generator#readme',
isGithubRepos: true,
isJSProject: true,
issuesUrl: 'https://github.com/kefranabg/readme-md-generator/issues',
hasStartCommand: false,
hasTestCommand: false,
packageManager: 'yarn'
})
})
it('should return correct infos when repos is not github', async () => {
const packgeJsonInfos = {
name: 'readme-md-generator',
version: '0.1.3',
description: 'CLI that generates beautiful README.md files.',
author: 'Franck Abgrall',
license: 'MIT',
homepage: 'https://gitlab.com/kefranabg/readme-md-generator',
repository: {
type: 'git',
url: 'git+https://gitlab.com/kefranabg/readme-md-generator.git'
},
bugs: {
url: 'https://gitlab.com/kefranabg/readme-md-generator/issues'
},
engines: {
npm: '>=5.5.0',
node: '>=9.3.0'
}
}
utils.getPackageJson.mockReturnValueOnce(Promise.resolve(packgeJsonInfos))
childProcess.execSync.mockReturnValue(
'https://github.com/kefranabg/readme-md-generator.git'
)
const projectInfos = await getProjectInfos()
expect(projectInfos).toEqual({
name: 'readme-md-generator',
description: 'CLI that generates beautiful README.md files.',
version: '0.1.3',
author: 'Franck Abgrall',
repositoryUrl: 'https://gitlab.com/kefranabg/readme-md-generator',
contributingUrl:
'https://gitlab.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md',
homepage: 'https://gitlab.com/kefranabg/readme-md-generator',
githubUsername: undefined,
authorWebsite: undefined,
engines: {
npm: '>=5.5.0',
node: '>=9.3.0'
},
licenseName: 'MIT',
licenseUrl: undefined,
documentationUrl: undefined,
isGithubRepos: false,
isJSProject: true,
issuesUrl: 'https://gitlab.com/kefranabg/readme-md-generator/issues',
hasStartCommand: false,
hasTestCommand: false,
packageManager: 'yarn'
})
})
it('should return correct infos when package.json is not defined', async () => {
utils.getPackageJson.mockReturnValueOnce(Promise.resolve(undefined))
childProcess.execSync.mockReturnValue(
'https://github.com/kefranabg/readme-md-generator.git'
)
const projectInfos = await getProjectInfos()
expect(projectInfos).toEqual({
name: 'readme-md-generator',
description: undefined,
version: undefined,
author: undefined,
repositoryUrl: 'https://github.com/kefranabg/readme-md-generator',
contributingUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md',
homepage: undefined,
githubUsername: 'kefranabg',
authorWebsite: 'https://www.franck-abgrall.me/',
engines: undefined,
licenseName: undefined,
licenseUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE',
documentationUrl:
'https://github.com/kefranabg/readme-md-generator#readme',
isGithubRepos: true,
isJSProject: false,
issuesUrl: 'https://github.com/kefranabg/readme-md-generator/issues',
hasStartCommand: false,
hasTestCommand: false
})
})
it('should return correct infos when repos is not github and package.json are not defined', async () => {
utils.getPackageJson.mockReturnValueOnce(Promise.resolve(undefined))
childProcess.execSync.mockReturnValue(
'https://gitlab.com/kefranabg/readme-md-generator.git'
)
const projectInfos = await getProjectInfos()
expect(projectInfos).toEqual({
name: 'readme-md-generator',
description: undefined,
version: undefined,
author: undefined,
repositoryUrl: 'https://gitlab.com/kefranabg/readme-md-generator',
authorWebsite: undefined,
contributingUrl:
'https://gitlab.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md',
homepage: undefined,
githubUsername: undefined,
engines: undefined,
licenseName: undefined,
licenseUrl: undefined,
documentationUrl: undefined,
isGithubRepos: false,
isJSProject: false,
issuesUrl: 'https://gitlab.com/kefranabg/readme-md-generator/issues',
hasStartCommand: false,
hasTestCommand: false
})
})
it('should return correct infos when git config and package.json are not defined', async () => {
utils.getPackageJson.mockReturnValueOnce(Promise.resolve(undefined))
childProcess.execSync.mockImplementation(() => {
throw new Error('error')
})
const projectInfos = await getProjectInfos()
expect(projectInfos).toEqual({
name: 'readme-md-generator',
description: undefined,
version: undefined,
author: undefined,
repositoryUrl: undefined,
contributingUrl: undefined,
homepage: undefined,
authorWebsite: undefined,
githubUsername: undefined,
engines: undefined,
licenseName: undefined,
licenseUrl: undefined,
documentationUrl: undefined,
isGithubRepos: false,
isJSProject: false,
testCommand: undefined,
hasStartCommand: false,
hasTestCommand: false
})
})
it('should return correct infos when git config is not defined', async () => {
const packgeJsonInfos = {
name: 'readme-md-generator',
version: '0.1.3',
description: 'CLI that generates beautiful README.md files.',
author: 'Franck Abgrall',
license: 'MIT',
homepage: 'https://github.com/kefranabg/readme-md-generator',
repository: {
type: 'git',
url: 'git+https://github.com/kefranabg/readme-md-generator.git'
},
bugs: {
url: 'https://github.com/kefranabg/readme-md-generator/issues'
},
engines: {
npm: '>=5.5.0',
node: '>=9.3.0'
}
}
utils.getPackageJson.mockReturnValueOnce(Promise.resolve(packgeJsonInfos))
childProcess.execSync.mockImplementation(() => {
throw new Error('error')
})
const projectInfos = await getProjectInfos()
expect(projectInfos).toEqual({
name: 'readme-md-generator',
description: 'CLI that generates beautiful README.md files.',
version: '0.1.3',
author: 'Franck Abgrall',
repositoryUrl: 'https://github.com/kefranabg/readme-md-generator',
contributingUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md',
homepage: 'https://github.com/kefranabg/readme-md-generator',
githubUsername: 'kefranabg',
authorWebsite: 'https://www.franck-abgrall.me/',
engines: {
npm: '>=5.5.0',
node: '>=9.3.0'
},
licenseName: 'MIT',
licenseUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE',
documentationUrl:
'https://github.com/kefranabg/readme-md-generator#readme',
isGithubRepos: true,
isJSProject: true,
issuesUrl: 'https://github.com/kefranabg/readme-md-generator/issues',
hasStartCommand: false,
hasTestCommand: false,
packageManager: 'yarn'
})
})
it('should return correct infos when author is defined as an object', async () => {
const packgeJsonInfos = {
name: 'readme-md-generator',
version: '0.1.3',
description: 'CLI that generates beautiful README.md files.',
author: {
name: 'Franck Abgrall',
email: 'abgrallkefran@gmail.com',
url: ''
},
license: 'MIT',
homepage: 'https://github.com/kefranabg/readme-md-generator',
repository: {
type: 'git',
url: 'git+https://github.com/kefranabg/readme-md-generator.git'
},
bugs: {
url: 'https://github.com/kefranabg/readme-md-generator/issues'
},
engines: {
npm: '>=5.5.0',
node: '>=9.3.0'
}
}
utils.getPackageJson.mockReturnValueOnce(Promise.resolve(packgeJsonInfos))
childProcess.execSync.mockReturnValue(
'https://github.com/kefranabg/readme-md-generator.git'
)
const projectInfos = await getProjectInfos()
expect(projectInfos).toEqual({
name: 'readme-md-generator',
description: 'CLI that generates beautiful README.md files.',
version: '0.1.3',
author: 'Franck Abgrall',
repositoryUrl: 'https://github.com/kefranabg/readme-md-generator',
homepage: 'https://github.com/kefranabg/readme-md-generator',
contributingUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md',
githubUsername: 'kefranabg',
authorWebsite: 'https://www.franck-abgrall.me/',
engines: {
npm: '>=5.5.0',
node: '>=9.3.0'
},
licenseName: 'MIT',
licenseUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE',
documentationUrl:
'https://github.com/kefranabg/readme-md-generator#readme',
isGithubRepos: true,
isJSProject: true,
issuesUrl: 'https://github.com/kefranabg/readme-md-generator/issues',
hasStartCommand: false,
hasTestCommand: false,
packageManager: 'yarn'
})
})
it('should return correct infos when lock file is found', async () => {
const packgeJsonInfos = {
name: 'readme-md-generator',
version: '0.1.3',
description: 'CLI that generates beautiful README.md files.',
author: 'Franck Abgrall',
license: 'MIT',
homepage: 'https://github.com/kefranabg/readme-md-generator',
repository: {
type: 'git',
url: 'git+https://github.com/kefranabg/readme-md-generator.git'
},
bugs: {
url: 'https://github.com/kefranabg/readme-md-generator/issues'
},
engines: {
npm: '>=5.5.0',
node: '>=9.3.0'
},
scripts: {
start: 'node src/index.js',
test: 'jest'
}
}
utils.getPackageJson.mockReturnValueOnce(Promise.resolve(packgeJsonInfos))
utils.getPackageManagerFromLockFile.mockReturnValueOnce('yarn')
childProcess.execSync.mockReturnValue(
'https://github.com/kefranabg/readme-md-generator.git'
)
const projectInfos = await getProjectInfos()
expect(projectInfos).toEqual({
name: 'readme-md-generator',
description: 'CLI that generates beautiful README.md files.',
version: '0.1.3',
author: 'Franck Abgrall',
repositoryUrl: 'https://github.com/kefranabg/readme-md-generator',
homepage: 'https://github.com/kefranabg/readme-md-generator',
contributingUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md',
authorWebsite: 'https://www.franck-abgrall.me/',
githubUsername: 'kefranabg',
engines: {
npm: '>=5.5.0',
node: '>=9.3.0'
},
licenseName: 'MIT',
licenseUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE',
documentationUrl:
'https://github.com/kefranabg/readme-md-generator#readme',
isGithubRepos: true,
isJSProject: true,
issuesUrl: 'https://github.com/kefranabg/readme-md-generator/issues',
hasStartCommand: true,
hasTestCommand: true,
packageManager: 'yarn'
})
})
})
})
================================================
FILE: src/questions/author-github.js
================================================
const { cleanSocialNetworkUsername } = require('../utils')
module.exports = projectInfos => ({
type: 'input',
message: '👤 GitHub username (use empty value to skip)',
name: 'authorGithubUsername',
default: projectInfos.githubUsername,
filter: cleanSocialNetworkUsername
})
================================================
FILE: src/questions/author-github.spec.js
================================================
const askAuthorGithub = require('./author-github')
describe('askAuthorGithub', () => {
it('should return correct question format', () => {
const githubUsername = 'kefranabg'
const projectInfos = { githubUsername }
const result = askAuthorGithub(projectInfos)
expect(result).toEqual({
type: 'input',
message: '👤 GitHub username (use empty value to skip)',
name: 'authorGithubUsername',
default: githubUsername,
filter: expect.any(Function)
})
})
})
================================================
FILE: src/questions/author-linkedin.js
================================================
const { cleanSocialNetworkUsername } = require('../utils')
module.exports = () => ({
type: 'input',
message: '💼 LinkedIn username (use empty value to skip)',
name: 'authorLinkedInUsername',
filter: cleanSocialNetworkUsername
})
================================================
FILE: src/questions/author-linkedin.spec.js
================================================
const askAuthorLinkedIn = require('./author-linkedin')
describe('askAuthorLinkedIn', () => {
it('should return correct question format', () => {
const result = askAuthorLinkedIn()
expect(result).toEqual({
type: 'input',
message: '💼 LinkedIn username (use empty value to skip)',
name: 'authorLinkedInUsername',
filter: expect.any(Function)
})
})
})
================================================
FILE: src/questions/author-name.js
================================================
module.exports = projectInfos => ({
type: 'input',
message: '👤 Author name',
name: 'authorName',
default: projectInfos.author
})
================================================
FILE: src/questions/author-name.spec.js
================================================
const askAuthorName = require('./author-name')
describe('askAuthorName', () => {
it('should return correct question format', () => {
const author = 'Franck Abgrall'
const projectInfos = { author }
const result = askAuthorName(projectInfos)
expect(result).toEqual({
type: 'input',
message: '👤 Author name',
name: 'authorName',
default: author
})
})
})
================================================
FILE: src/questions/author-patreon.js
================================================
const { cleanSocialNetworkUsername } = require('../utils')
module.exports = () => ({
type: 'input',
message: '❤️ Patreon username (use empty value to skip)',
name: 'authorPatreonUsername',
filter: cleanSocialNetworkUsername
})
================================================
FILE: src/questions/author-patreon.spec.js
================================================
const askPatreonUsername = require('./author-patreon')
describe('askPatreonUsername', () => {
it('should return correct question format', () => {
const result = askPatreonUsername()
expect(result).toEqual({
type: 'input',
message: '❤️ Patreon username (use empty value to skip)',
name: 'authorPatreonUsername',
filter: expect.any(Function)
})
})
})
================================================
FILE: src/questions/author-twitter.js
================================================
const { cleanSocialNetworkUsername } = require('../utils')
module.exports = () => ({
type: 'input',
message: '🐦 Twitter username (use empty value to skip)',
name: 'authorTwitterUsername',
filter: cleanSocialNetworkUsername
})
================================================
FILE: src/questions/author-twitter.spec.js
================================================
const askAuthorTwitter = require('./author-twitter')
describe('askAuthorTwitter', () => {
it('should return correct question format', () => {
const result = askAuthorTwitter()
expect(result).toEqual({
type: 'input',
message: '🐦 Twitter username (use empty value to skip)',
name: 'authorTwitterUsername',
filter: expect.any(Function)
})
})
})
================================================
FILE: src/questions/author-website.js
================================================
const { getAuthorWebsiteFromGithubAPI } = require('../utils')
module.exports = projectInfos => ({
type: 'input',
message: '🏠 Author website (use empty value to skip)',
name: 'authorWebsite',
default: async answers =>
answers.authorGithubUsername !== projectInfos.githubUsername
? getAuthorWebsiteFromGithubAPI(answers.authorGithubUsername)
: projectInfos.authorWebsite
})
================================================
FILE: src/questions/author-website.spec.js
================================================
const fetch = require('node-fetch')
const askAuthorWebsite = require('./author-website')
jest.mock('node-fetch')
describe('askAuthorWebsite', () => {
it('should return correct question format', () => {
const authorWebsite = 'authorWebsite'
const projectInfos = { authorWebsite }
const result = askAuthorWebsite(projectInfos)
expect(result).toEqual(
expect.objectContaining({
type: 'input',
message: '🏠 Author website (use empty value to skip)',
name: 'authorWebsite'
})
)
})
it('should return a new website url if user changes its github username with the previous question', async () => {
const blog = 'https://www.new-website-url.com/'
const projectInfos = {
githubUsername: 'kefranabg',
authorWebsite: 'https://www.franck-abgrall.me/'
}
fetch.mockReturnValueOnce(
Promise.resolve({
json: () => Promise.resolve({ blog })
})
)
const result = await askAuthorWebsite(projectInfos).default({
authorGithubUsername: 'newGitHubUsername'
})
expect(result).toEqual(blog)
})
it('should return project infos website url if github username did not change', async () => {
const projectInfos = {
githubUsername: 'kefranabg',
authorWebsite: 'https://www.franck-abgrall.me/'
}
const result = await askAuthorWebsite(projectInfos).default({
authorGithubUsername: 'kefranabg'
})
expect(result).toEqual(projectInfos.authorWebsite)
})
})
================================================
FILE: src/questions/contributing-url.js
================================================
module.exports = projectInfos => ({
type: 'input',
message: '🤝 Contributing guide url (use empty value to skip)',
name: 'contributingUrl',
default: projectInfos.contributingUrl
})
================================================
FILE: src/questions/contributing-url.spec.js
================================================
const askContributingUrl = require('./contributing-url')
describe('askContributingUrl', () => {
it('should return correct question format', () => {
const contributingUrl =
'https://github.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md'
const projectInfos = { contributingUrl }
const result = askContributingUrl(projectInfos)
expect(result).toEqual({
type: 'input',
message: '🤝 Contributing guide url (use empty value to skip)',
name: 'contributingUrl',
default: contributingUrl
})
})
})
================================================
FILE: src/questions/index.js
================================================
/* eslint-disable global-require */
module.exports = {
askProjectName: require('./project-name'),
askProjectVersion: require('./project-version'),
askProjectDescription: require('./project-description'),
askPackageManager: require('./package-manager'),
askProjectHomepage: require('./project-homepage'),
askProjectDemoUrl: require('./project-demo-url'),
askProjectDocumentationUrl: require('./project-documentation-url'),
askAuhtorName: require('./author-name'),
askAuthorGithub: require('./author-github'),
askAuthorWebsite: require('./author-website'),
askAuthorTwitter: require('./author-twitter'),
askAuthorLinkedIn: require('./author-linkedin'),
askAuthorPatreon: require('./author-patreon'),
askProjectPrerequisites: require('./project-prerequisites'),
askLicenseName: require('./license-name'),
askLicenseUrl: require('./license-url'),
askIssuesUrl: require('./issues-url'),
askContributingUrl: require('./contributing-url'),
askInstallCommand: require('./install-command'),
askUsage: require('./usage'),
askTestCommand: require('./test-command')
}
================================================
FILE: src/questions/index.spec.js
================================================
const questions = require('./')
describe('questions', () => {
it('should export questions in the correct order', () => {
const questionsNameOrder = Object.keys(questions)
expect(questionsNameOrder).toEqual([
'askProjectName',
'askProjectVersion',
'askProjectDescription',
'askPackageManager',
'askProjectHomepage',
'askProjectDemoUrl',
'askProjectDocumentationUrl',
'askAuhtorName',
'askAuthorGithub',
'askAuthorWebsite',
'askAuthorTwitter',
'askAuthorLinkedIn',
'askAuthorPatreon',
'askProjectPrerequisites',
'askLicenseName',
'askLicenseUrl',
'askIssuesUrl',
'askContributingUrl',
'askInstallCommand',
'askUsage',
'askTestCommand'
])
})
})
================================================
FILE: src/questions/install-command.js
================================================
const isNil = require('lodash/isNil')
module.exports = projectInfos => ({
type: 'input',
message: '📦 Install command (use empty value to skip)',
name: 'installCommand',
default: answers => {
const packageManager = answers.packageManager || projectInfos.packageManager
return isNil(packageManager) ? undefined : `${packageManager} install`
}
})
================================================
FILE: src/questions/install-command.spec.js
================================================
const askInstallCommand = require('./install-command')
describe('askInstallCommand', () => {
it('should return correct question format', () => {
const result = askInstallCommand()
expect(result).toEqual(
expect.objectContaining({
type: 'input',
message: '📦 Install command (use empty value to skip)',
name: 'installCommand'
})
)
})
it('should return undefined default answer when package manager is not defined', () => {
const projectInfos = {}
const result = askInstallCommand(projectInfos).default({
packageManager: undefined
})
expect(result).toBeUndefined()
})
it('should return correct default answer when package manager is defined', () => {
const projectInfos = {}
const result = askInstallCommand(projectInfos).default({
packageManager: 'yarn'
})
expect(result).toEqual('yarn install')
})
})
================================================
FILE: src/questions/issues-url.js
================================================
module.exports = packageJson => ({
type: 'input',
message: '🔧 Issues page url (use empty value to skip)',
name: 'issuesUrl',
default: packageJson.issuesUrl
})
================================================
FILE: src/questions/issues-url.spec.js
================================================
const askIssues = require('./issues-url')
describe('askIssues', () => {
it('should return correct question format', () => {
const issuesUrl = 'https://github.com/kefranabg/readme-md-generator/issues'
const projectInfos = { issuesUrl }
const result = askIssues(projectInfos)
expect(result).toEqual({
type: 'input',
message: '🔧 Issues page url (use empty value to skip)',
name: 'issuesUrl',
default: issuesUrl
})
})
})
================================================
FILE: src/questions/license-name.js
================================================
module.exports = packageJson => ({
type: 'input',
message: '📝 License name (use empty value to skip)',
name: 'licenseName',
default: packageJson.licenseName
})
================================================
FILE: src/questions/license-name.spec.js
================================================
const askLicenseName = require('./license-name')
describe('askLicenseName', () => {
it('should return correct question format', () => {
const licenseName = 'MIT'
const projectInfos = { licenseName }
const result = askLicenseName(projectInfos)
expect(result).toEqual({
type: 'input',
message: '📝 License name (use empty value to skip)',
name: 'licenseName',
default: licenseName
})
})
})
================================================
FILE: src/questions/license-url.js
================================================
const isEmpty = require('lodash/isEmpty')
module.exports = projectInfos => ({
type: 'input',
message: '📝 License url (use empty value to skip)',
name: 'licenseUrl',
default: projectInfos.licenseUrl,
when: answersContext => !isEmpty(answersContext.licenseName)
})
================================================
FILE: src/questions/license-url.spec.js
================================================
const askLicenseUrl = require('./license-url')
describe('askLicenseUrl', () => {
it('should return correct question format', () => {
const licenseUrl =
'https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE'
const projectInfos = { licenseUrl }
const result = askLicenseUrl(projectInfos)
expect(result).toEqual(
expect.objectContaining({
type: 'input',
message: '📝 License url (use empty value to skip)',
name: 'licenseUrl',
default: licenseUrl
})
)
})
it('should show this question if licenseName is defined', () => {
const projectInfos = {
licenseUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE'
}
const answersContext = { licenseName: 'MIT' }
const question = askLicenseUrl(projectInfos)
const result = question.when(answersContext)
expect(result).toBe(true)
})
it('should not show this question if licenseName is not defined', () => {
const projectInfos = {
licenseUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE'
}
const answersContext = {}
const question = askLicenseUrl(projectInfos)
const result = question.when(answersContext)
expect(result).toBe(false)
})
})
================================================
FILE: src/questions/package-manager.js
================================================
const isEmpty = require('lodash/isEmpty')
module.exports = projectInfos => ({
type: 'list',
message: '📦 Choose Package Manager ',
name: 'packageManager',
choices: [
{
name: 'npm',
value: 'npm'
},
{
name: 'yarn',
value: 'yarn'
}
],
when: () => projectInfos.isJSProject && isEmpty(projectInfos.packageManager)
})
================================================
FILE: src/questions/package-manager.spec.js
================================================
const askPackageManager = require('./package-manager')
const expectedQuestion = {
type: 'list',
message: '📦 Choose Package Manager ',
name: 'packageManager',
choices: [
{
name: 'npm',
value: 'npm'
},
{
name: 'yarn',
value: 'yarn'
}
]
}
describe('askPackageManager', () => {
it('should return correct question format when package manager is undefined', () => {
const projectInfos = { packageManager: undefined }
const result = askPackageManager(projectInfos)
expect(result).toEqual(expect.objectContaining(expectedQuestion))
})
it('should not show question for a non JS Project', () => {
const projectInfos = { isJSProject: false, packageManager: undefined }
const result = askPackageManager(projectInfos).when(projectInfos)
expect(result).toBe(false)
})
it('should not show question when package manager has already been detected', () => {
const projectInfos = { isJSProject: true, packageManager: 'yarn' }
const result = askPackageManager(projectInfos).when(projectInfos)
expect(result).toBe(false)
})
it('should show question when package manager is undefined and if project is JS', () => {
const projectInfos = { isJSProject: true, packageManager: undefined }
const result = askPackageManager(projectInfos).when(projectInfos)
expect(result).toBe(true)
})
})
================================================
FILE: src/questions/project-demo-url.js
================================================
module.exports = () => ({
type: 'input',
message: '✨ Project demo url (use empty value to skip)',
name: 'projectDemoUrl'
})
================================================
FILE: src/questions/project-demo-url.spec.js
================================================
const askProjectDemoUrl = require('./project-demo-url')
describe('askProjectDemoUrl', () => {
it('should return the correct question format', () => {
const result = askProjectDemoUrl()
expect(result).toEqual({
type: 'input',
message: '✨ Project demo url (use empty value to skip)',
name: 'projectDemoUrl'
})
})
})
================================================
FILE: src/questions/project-description.js
================================================
module.exports = projectInfos => ({
type: 'input',
message: '📄 Project description',
name: 'projectDescription',
default: projectInfos.description
})
================================================
FILE: src/questions/project-description.spec.js
================================================
const askProjectDescription = require('./project-description')
describe('askProjectDescription', () => {
it('should return correct question format', () => {
const description = 'description'
const projectInfos = { description }
const result = askProjectDescription(projectInfos)
expect(result).toEqual({
type: 'input',
message: '📄 Project description',
name: 'projectDescription',
default: description
})
})
})
================================================
FILE: src/questions/project-documentation-url.js
================================================
module.exports = projectInfos => ({
type: 'input',
message: '📘 Project documentation url (use empty value to skip)',
name: 'projectDocumentationUrl',
default: projectInfos.documentationUrl
})
================================================
FILE: src/questions/project-documentation-url.spec.js
================================================
const askProjectName = require('./project-name')
describe('askProjectName', () => {
it('should return correct question format', () => {
const name = 'readme-md-generator'
const projectInfos = { name }
const result = askProjectName(projectInfos)
expect(result).toEqual({
type: 'input',
message: '💡 Project name',
name: 'projectName',
default: name
})
})
})
================================================
FILE: src/questions/project-homepage.js
================================================
module.exports = projectInfos => ({
type: 'input',
message: '🏠 Project homepage (use empty value to skip)',
name: 'projectHomepage',
default: projectInfos.homepage
})
================================================
FILE: src/questions/project-homepage.spec.js
================================================
const askProjectHomepage = require('./project-homepage')
describe('askProjectHomepage', () => {
it('should return correct question format', () => {
const homepage = 'homepage'
const projectInfos = { homepage }
const result = askProjectHomepage(projectInfos)
expect(result).toEqual({
type: 'input',
message: '🏠 Project homepage (use empty value to skip)',
name: 'projectHomepage',
default: homepage
})
})
})
================================================
FILE: src/questions/project-name.js
================================================
module.exports = projectInfos => ({
type: 'input',
message: '💡 Project name',
name: 'projectName',
default: projectInfos.name
})
================================================
FILE: src/questions/project-name.spec.js
================================================
const askProjectDocumentationUrl = require('./project-documentation-url')
describe('askProjectDocumentationUrl', () => {
it('should return correct question format', () => {
const documentationUrl =
'https://github.com/kefranabg/readme-md-generator/blob/master/README.md'
const projectInfos = { documentationUrl }
const result = askProjectDocumentationUrl(projectInfos)
expect(result).toEqual({
type: 'input',
message: '📘 Project documentation url (use empty value to skip)',
name: 'projectDocumentationUrl',
default: documentationUrl
})
})
})
================================================
FILE: src/questions/project-prerequisites.js
================================================
const isEmpty = require('lodash/isEmpty')
const isNil = require('lodash/isNil')
/**
* Return engines as formatted choices
*
* @param {Object} engines
*/
const buildFormattedChoices = engines =>
isNil(engines)
? null
: Object.keys(engines).map(key => ({
name: `${key} ${engines[key]}`,
value: {
name: key,
value: engines[key]
},
checked: true
}))
/**
* Check if projectInfos has engines properties
*
* @param {Object} projectInfos
*/
const hasProjectInfosEngines = projectInfos =>
!isNil(projectInfos.engines) && !isEmpty(projectInfos.engines)
module.exports = projectInfos => ({
type: 'checkbox',
message: '⚠️ Project prerequisites',
name: 'projectPrerequisites',
choices: buildFormattedChoices(projectInfos.engines),
when: () => hasProjectInfosEngines(projectInfos)
})
================================================
FILE: src/questions/project-prerequisites.spec.js
================================================
const askProjectPrerequisites = require('./project-prerequisites')
describe('askProjectPrerequisites', () => {
it('should return correct question format', () => {
const engines = {
npm: '>=5.5.0',
node: '>= 9.3.0'
}
const projectInfos = { engines }
const result = askProjectPrerequisites(projectInfos)
expect(result).toEqual(
expect.objectContaining({
type: 'checkbox',
message: '⚠️ Project prerequisites',
name: 'projectPrerequisites',
choices: [
{
checked: true,
name: 'npm >=5.5.0',
value: { name: 'npm', value: '>=5.5.0' }
},
{
checked: true,
name: 'node >= 9.3.0',
value: { name: 'node', value: '>= 9.3.0' }
}
]
})
)
})
it('should not show the question when engines property is empty object', () => {
const projectInfos = { engines: {} }
const question = askProjectPrerequisites(projectInfos)
const result = question.when()
expect(result).toEqual(false)
})
it('should not show the question when engines property is not defined', () => {
const projectInfos = {}
const question = askProjectPrerequisites(projectInfos)
const result = question.when()
expect(result).toEqual(false)
})
it('should show the question when engines property is defined and not empty', () => {
const projectInfos = {
engines: {
node: '>=10'
}
}
const question = askProjectPrerequisites(projectInfos)
const result = question.when()
expect(result).toEqual(true)
})
})
================================================
FILE: src/questions/project-version.js
================================================
module.exports = projectInfos => ({
type: 'input',
message: 'ℹ️ Project version (use empty value to skip)',
name: 'projectVersion',
default: projectInfos.version
})
================================================
FILE: src/questions/project-version.spec.js
================================================
const askProjectVersion = require('./project-version')
describe('askProjectVersion', () => {
it('should return correct question format', () => {
const version = '1.0.0'
const projectInfos = { version }
const result = askProjectVersion(projectInfos)
expect(result).toEqual({
type: 'input',
message: 'ℹ️ Project version (use empty value to skip)',
name: 'projectVersion',
default: version
})
})
})
================================================
FILE: src/questions/test-command.js
================================================
const isNil = require('lodash/isNil')
module.exports = projectInfos => ({
type: 'input',
message: '✅ Test command (use empty value to skip)',
name: 'testCommand',
default: answers => {
const packageManager = answers.packageManager || projectInfos.packageManager
return projectInfos.hasTestCommand && !isNil(packageManager)
? `${packageManager} run test`
: undefined
}
})
================================================
FILE: src/questions/test-command.spec.js
================================================
const askTestCommand = require('./test-command')
describe('askTestCommand', () => {
it('should return correct question format', () => {
const result = askTestCommand()
expect(result).toEqual(
expect.objectContaining({
type: 'input',
message: '✅ Test command (use empty value to skip)',
name: 'testCommand'
})
)
})
it('should return undefined default answer when package manager does not exists', () => {
const projectInfos = { hasTestCommand: true }
const result = askTestCommand(projectInfos).default({
packageManager: undefined
})
expect(result).toBeUndefined()
})
it('should return undefined default answer when test command does not exists', () => {
const projectInfos = { hasTestCommand: false }
const result = askTestCommand(projectInfos).default({
packageManager: 'yarn'
})
expect(result).toBeUndefined()
})
it('should return correct default answer when start command and package manager exists', () => {
const projectInfos = { hasTestCommand: true }
const result = askTestCommand(projectInfos).default({
packageManager: 'yarn'
})
expect(result).toEqual('yarn run test')
})
})
================================================
FILE: src/questions/usage.js
================================================
const isNil = require('lodash/isNil')
module.exports = projectInfos => ({
type: 'input',
message: '🚀 Usage command or instruction (use empty value to skip)',
name: 'usage',
default: answers => {
const packageManager = answers.packageManager || projectInfos.packageManager
return projectInfos.hasStartCommand && !isNil(packageManager)
? `${packageManager} run start`
: undefined
}
})
================================================
FILE: src/questions/usage.spec.js
================================================
const askUsage = require('./usage')
describe('askUsage', () => {
it('should return correct question format', () => {
const result = askUsage()
expect(result).toEqual(
expect.objectContaining({
type: 'input',
message: '🚀 Usage command or instruction (use empty value to skip)',
name: 'usage'
})
)
})
it('should return undefined default answer when package manager does not exists', () => {
const projectInfos = { hasStartCommand: true }
const result = askUsage(projectInfos).default({
packageManager: undefined
})
expect(result).toBeUndefined()
})
it('should return undefined default answer when start command does not exists', () => {
const projectInfos = { hasStartCommand: false }
const result = askUsage(projectInfos).default({
packageManager: 'yarn'
})
expect(result).toBeUndefined()
})
it('should return correct default answer when start command and packageManager exists', () => {
const projectInfos = { hasStartCommand: true }
const result = askUsage(projectInfos).default({
packageManager: 'yarn'
})
expect(result).toEqual('yarn run start')
})
})
================================================
FILE: src/readme.js
================================================
const ejs = require('ejs')
const ora = require('ora')
const { promisify } = require('util')
const { getYear } = require('date-fns')
const fs = require('fs')
const { isNil, unescape } = require('lodash')
const chooseTemplate = require('./choose-template')
const askOverwriteReadme = require('./ask-overwrite')
const README_PATH = 'README.md'
/**
* Create readme file from the given readmeContent
*
* @param {string} readmeContent
*/
const writeReadme = async readmeContent => {
const spinner = ora('Creating README').start()
try {
await promisify(fs.writeFile)(README_PATH, unescape(readmeContent))
spinner.succeed('README created')
} catch (err) {
spinner.fail('README creation fail')
throw err
}
}
/**
* Get README template content from the given templatePath
*
* @param {string} templatePath
*/
const getReadmeTemplate = async templatePath => {
const spinner = ora('Loading README template').start()
try {
const template = await promisify(fs.readFile)(templatePath, 'utf8')
spinner.succeed('README template loaded')
return template
} catch (err) {
spinner.fail('README template loading fail')
throw err
}
}
/**
* Build README content with the given context and templatePath
*
* @param {Object} context
* @param {string} templatePath
*/
const buildReadmeContent = async (context, templatePath) => {
const currentYear = getYear(new Date())
const template = await getReadmeTemplate(templatePath)
return ejs.render(template, {
filename: templatePath,
currentYear,
...context
})
}
/**
* Validate template path
*
* @param {string} templatePath
*/
const validateReadmeTemplatePath = templatePath => {
const spinner = ora('Resolving README template path').start()
try {
fs.lstatSync(templatePath).isFile()
} catch (err) {
spinner.fail(`The template path '${templatePath}' is not valid.`)
throw err
}
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
}
/**
* Check if readme generator can overwrite the existed readme
*/
const checkOverwriteReadme = () =>
!fs.existsSync(README_PATH) || askOverwriteReadme()
module.exports = {
writeReadme,
buildReadmeContent,
README_PATH,
getReadmeTemplatePath,
checkOverwriteReadme
}
================================================
FILE: src/readme.spec.js
================================================
const fs = require('fs')
const ora = require('ora')
const path = require('path')
const chooseTemplate = require('./choose-template')
const askOverwriteReadme = require('./ask-overwrite')
const defaultTemplatePath = path.resolve(__dirname, '../templates/default.md')
const defaultNoHtmlTemplatePath = path.resolve(
__dirname,
'../templates/default-no-html.md'
)
chooseTemplate.mockReturnValue(defaultTemplatePath)
const {
writeReadme,
buildReadmeContent,
README_PATH,
getReadmeTemplatePath,
checkOverwriteReadme
} = require('./readme')
describe('readme', () => {
const succeed = jest.fn()
const fail = jest.fn()
ora.mockReturnValue({
start: () => ({
succeed,
fail
})
})
afterEach(() => {
jest.clearAllMocks()
})
describe('writeReadme', () => {
it('should call ora with correct parameters in success case', async () => {
const readmeContent = 'content'
fs.writeFile = jest.fn((_, __, cb) => cb(null, 'done'))
await writeReadme(readmeContent)
expect(ora).toHaveBeenCalledTimes(1)
expect(ora).toHaveBeenCalledWith('Creating README')
expect(succeed).toHaveBeenCalledTimes(1)
expect(succeed).toHaveBeenCalledWith('README created')
})
it('should call ora with correct parameters in fail case', async () => {
const readmeContent = 'content'
fs.writeFile = jest.fn(() => {
throw new Error('error')
})
try {
await writeReadme(readmeContent)
// eslint-disable-next-line no-empty
} catch (err) {}
expect(ora).toHaveBeenCalledTimes(1)
expect(ora).toHaveBeenCalledWith('Creating README')
expect(fail).toHaveBeenCalledTimes(1)
expect(fail).toHaveBeenCalledWith('README creation fail')
})
it('should call writeFile with correct parameters', async () => {
const readmeContent = 'John & Bryan'
fs.writeFile = jest.fn((_, __, cb) => cb(null, 'done'))
await writeReadme(readmeContent)
expect(fs.writeFile).toHaveBeenCalledTimes(1)
expect(fs.writeFile.mock.calls[0][0]).toBe(README_PATH)
expect(fs.writeFile.mock.calls[0][1]).toBe('John & Bryan')
})
})
describe('buildReadmeContent', () => {
const context = {
isGithubRepos: true,
repositoryUrl: 'https://github.com/kefranabg/readme-md-generator',
projectPrerequisites: [
{ name: 'npm', value: '>=5.5.0' },
{ name: 'node', value: '>= 9.3.0' }
],
projectName: 'readme-md-generator',
projectVersion: '0.1.3',
projectDescription:
'Generates beautiful README files from git config & package.json infos',
projectDocumentationUrl:
'https://github.com/kefranabg/readme-md-generator#readme',
projectHomepage:
'https://github.com/kefranabg/readme-md-generator#readme',
projectDemoUrl: 'https://github.com/kefranabg/readme-md-generator#-demo',
authorName: 'Franck Abgrall',
authorWebsite: 'https://www.franck-abgrall.me/',
authorGithubUsername: 'kefranabg',
authorTwitterUsername: 'FranckAbgrall',
authorLinkedInUsername: 'franckabgrall',
authorPatreonUsername: 'FranckAbgrall',
licenseName: 'MIT',
licenseUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE',
issuesUrl: 'https://github.com/kefranabg/readme-md-generator/issues',
contributingUrl:
'https://github.com/kefranabg/readme-md-generator/blob/master/CONTRIBUTING.md',
installCommand: 'npm install',
usage: 'npm start',
testCommand: 'npm run test',
isProjectOnNpm: true
}
afterEach(() => {
jest.clearAllMocks()
})
it('should call ora with correct parameters in success case', async () => {
await buildReadmeContent(context, defaultTemplatePath)
expect(ora).toHaveBeenCalledTimes(1)
expect(ora).toHaveBeenCalledWith('Loading README template')
expect(succeed).toHaveBeenCalledTimes(1)
expect(succeed).toHaveBeenCalledWith('README template loaded')
})
it('should return readme default template content', async () => {
const result = await buildReadmeContent(context, defaultTemplatePath)
expect(result).toMatchSnapshot()
})
it('should return readme default template no html content', async () => {
const result = await buildReadmeContent(
context,
defaultNoHtmlTemplatePath
)
expect(result).toMatchSnapshot()
})
it('should call ora with correct parameters in fail case', async () => {
fs.readFile = jest.fn(() => {
throw new Error('error')
})
try {
await buildReadmeContent(context, defaultTemplatePath)
// eslint-disable-next-line no-empty
} catch (err) {}
expect(ora).toHaveBeenCalledTimes(1)
expect(ora).toHaveBeenCalledWith('Loading README template')
expect(fail).toHaveBeenCalledTimes(1)
expect(fail).toHaveBeenCalledWith('README template loading fail')
})
})
describe('getReadmeTemplatePath', () => {
it('should return template that user has selected', async () => {
const useDefaultAnswers = false
const actualResult = await getReadmeTemplatePath(
undefined,
useDefaultAnswers
)
expect(actualResult).toEqual(defaultTemplatePath)
expect(chooseTemplate).toHaveBeenNthCalledWith(1, useDefaultAnswers)
})
it('should return custom template path if customTemplatePath is defined', async () => {
const customTemplatePath = defaultTemplatePath
const actualResult = await getReadmeTemplatePath(
customTemplatePath,
false
)
expect(actualResult).toEqual(customTemplatePath)
expect(chooseTemplate).not.toHaveBeenCalled()
})
it('should throw an error if customTemplate is defined but invalid', () => {
const wrongPath = 'wrong path'
expect(getReadmeTemplatePath(wrongPath, false)).rejects.toThrow()
})
it('should call ora with correct parameters in fail case', async () => {
const wrongPath = 'wrong path'
try {
await getReadmeTemplatePath(wrongPath, false)
// eslint-disable-next-line no-empty
} catch (err) {}
expect(ora).toHaveBeenNthCalledWith(1, 'Resolving README template path')
expect(fail).toHaveBeenNthCalledWith(
1,
"The template path 'wrong path' is not valid."
)
})
it('should call ora with correct parameters in success case', async () => {
await getReadmeTemplatePath(defaultTemplatePath, false)
expect(ora).toHaveBeenNthCalledWith(1, 'Resolving README template path')
expect(succeed).toHaveBeenNthCalledWith(
1,
'README template path resolved'
)
})
})
describe('checkOverwrite', () => {
it('should return true if README does not exist', async () => {
fs.existsSync = jest.fn(p => p !== README_PATH)
expect(await checkOverwriteReadme()).toEqual(true)
})
it('should return true if README exist and user want to overwrite it', async () => {
fs.existsSync = jest.fn(p => p === README_PATH)
askOverwriteReadme.mockResolvedValue(true)
expect(await checkOverwriteReadme()).toEqual(true)
})
it('should return false if README exist and user dont want to overwrite it', async () => {
fs.existsSync = jest.fn(p => p === README_PATH)
askOverwriteReadme.mockResolvedValue(false)
expect(await checkOverwriteReadme()).toEqual(false)
})
})
})
jest.mock('ora')
jest.mock('./choose-template')
jest.mock('./ask-overwrite')
================================================
FILE: src/utils.js
================================================
const loadJsonFile = require('load-json-file')
const isNil = require('lodash/isNil')
const isEmpty = require('lodash/isEmpty')
const boxen = require('boxen')
const path = require('path')
const getReposName = require('git-repo-name')
const fetch = require('node-fetch')
const fs = require('fs')
const escapeMarkdown = require('markdown-escape')
const { execSync } = require('child_process')
const END_MSG = `README.md was successfully generated.
Thanks for using readme-md-generator!`
const GITHUB_API_URL = 'https://api.github.com'
const BOXEN_CONFIG = {
padding: 1,
margin: { top: 2, bottom: 3 },
borderColor: 'cyan',
align: 'center',
borderStyle: 'double'
}
/**
* Display end message
*/
const showEndMessage = () => process.stdout.write(boxen(END_MSG, BOXEN_CONFIG))
/**
* Get package json name property
*
* @param {Object} packageJson
*/
const getPackageJsonName = (packageJson = {}) => packageJson.name || undefined
/**
* Get git repository name
*
* @param {String} cwd
*/
const getGitRepositoryName = cwd => {
try {
return getReposName.sync({ cwd })
// eslint-disable-next-line no-empty
} catch (err) {
return undefined
}
}
/**
* Get project name
*/
const getProjectName = packageJson => {
const cwd = process.cwd()
return (
getPackageJsonName(packageJson) ||
getGitRepositoryName(cwd) ||
path.basename(cwd)
)
}
/**
* Get package.json content
*/
const getPackageJson = async () => {
try {
return await loadJsonFile('package.json')
} catch (err) {
return undefined
}
}
/**
* Get the default answer depending on the question type
*
* @param {Object} question
*/
const getDefaultAnswer = async (question, answersContext) => {
if (question.when && !question.when(answersContext)) return undefined
switch (question.type) {
case 'input':
return typeof question.default === 'function'
? question.default(answersContext)
: question.default || ''
case 'checkbox':
return question.choices
.filter(choice => choice.checked)
.map(choice => choice.value)
default:
return undefined
}
}
/**
* Return true if the project is available on NPM, return false otherwise.
*
* @param projectName
* @returns boolean
*/
const isProjectAvailableOnNpm = projectName => {
try {
execSync(`npm view ${projectName}`, { stdio: 'ignore' })
return true
} catch (err) {
return false
}
}
/**
* Get default question's answers
*
* @param {Array} questions
*/
const getDefaultAnswers = questions =>
questions.reduce(async (answersContextProm, question) => {
const answersContext = await answersContextProm
return {
...answersContext,
[question.name]: await getDefaultAnswer(question, answersContext)
}
}, Promise.resolve({}))
/**
* Clean social network username by removing the @ prefix and
* escaping markdown characters
*
* @param input social network username input
* @returns {*} escaped input without the prefix
*/
const cleanSocialNetworkUsername = input =>
escapeMarkdown(input.replace(/^@/, ''))
/**
* Get author's website from Github API
*
* @param {string} githubUsername
* @returns {string} authorWebsite
*/
const getAuthorWebsiteFromGithubAPI = async githubUsername => {
try {
const userData = await fetch(
`${GITHUB_API_URL}/users/${githubUsername}`
).then(res => res.json())
const authorWebsite = userData.blog
return isNil(authorWebsite) || isEmpty(authorWebsite)
? undefined
: authorWebsite
} catch (err) {
return undefined
}
}
/**
* Returns a boolean whether a file exists or not
*
* @param {String} filepath
* @returns {Boolean}
*/
const doesFileExist = filepath => {
try {
return fs.existsSync(filepath)
} catch (err) {
return false
}
}
/**
* Returns the package manager from the lock file
*
* @returns {String} packageManger or undefined
*/
const getPackageManagerFromLockFile = () => {
const packageLockExists = doesFileExist('package-lock.json')
const yarnLockExists = doesFileExist('yarn.lock')
if (packageLockExists && yarnLockExists) return undefined
if (packageLockExists) return 'npm'
if (yarnLockExists) return 'yarn'
return undefined
}
module.exports = {
getPackageJson,
showEndMessage,
getProjectName,
END_MSG,
BOXEN_CONFIG,
getDefaultAnswers,
getDefaultAnswer,
cleanSocialNetworkUsername,
isProjectAvailableOnNpm,
getAuthorWebsiteFromGithubAPI,
getPackageManagerFromLockFile,
doesFileExist
}
================================================
FILE: src/utils.spec.js
================================================
const loadJsonFile = require('load-json-file')
const boxen = require('boxen')
const path = require('path')
const getReposName = require('git-repo-name')
const fetch = require('node-fetch')
const fs = require('fs')
const { isNil } = require('lodash')
const realPathBasename = path.basename
const realGetReposNameSync = getReposName.sync
const {
getPackageJson,
showEndMessage,
getProjectName,
END_MSG,
BOXEN_CONFIG,
getDefaultAnswer,
getDefaultAnswers,
cleanSocialNetworkUsername,
isProjectAvailableOnNpm,
getAuthorWebsiteFromGithubAPI,
doesFileExist,
getPackageManagerFromLockFile
} = require('./utils')
jest.mock('load-json-file')
jest.mock('boxen')
jest.mock('node-fetch')
jest.mock('fs')
describe('utils', () => {
describe('getPackageJson', () => {
const packageJsonContent = {
name: 'readme-md-cli'
}
it('should return package.json content', async () => {
loadJsonFile.mockReturnValueOnce(Promise.resolve(packageJsonContent))
const result = await getPackageJson()
expect(result).toEqual(packageJsonContent)
})
it('should return undefined', async () => {
loadJsonFile.mockImplementationOnce(() => {
throw new Error('ERROR')
})
const result = await getPackageJson()
expect(result).toBeUndefined()
})
})
describe('showEndMessage', () => {
boxen.mockReturnValue(END_MSG)
it('should call boxen with correct parameters', () => {
showEndMessage()
expect(boxen).toHaveBeenCalledTimes(1)
expect(boxen).toHaveBeenCalledWith(END_MSG, BOXEN_CONFIG)
})
it('should call process.stdout.write with correct parameters', () => {
process.stdout.write = jest.fn()
showEndMessage()
expect(process.stdout.write).toHaveBeenCalledTimes(1)
expect(process.stdout.write).toHaveBeenCalledWith(END_MSG)
})
})
describe('getProjectName', () => {
const projectName = 'readme-md-generator'
beforeEach(() => {
path.basename = jest.fn(() => projectName)
getReposName.sync = jest.fn()
})
afterEach(() => {
path.basename = realPathBasename
getReposName.sync = realGetReposNameSync
})
it('should return package.json name prop when defined', () => {
const packageJson = { name: projectName }
getReposName.sync.mockReturnValueOnce('readme-md-generator')
const result = getProjectName(packageJson)
expect(result).toEqual(projectName)
expect(getReposName.sync).not.toHaveBeenCalled()
expect(path.basename).not.toHaveBeenCalled()
})
it('should return git repos when package.json it is not defined', () => {
const packageJson = undefined
getReposName.sync.mockReturnValueOnce('readme-md-generator')
const result = getProjectName(packageJson)
expect(result).toEqual(projectName)
expect(getReposName.sync).toHaveBeenCalled()
expect(path.basename).not.toHaveBeenCalled()
})
it('should return folder basename when package.json and git repos name is undefined', () => {
const packageJson = undefined
getReposName.sync.mockImplementation(() => {
throw new Error('error')
})
const result = getProjectName(packageJson)
expect(result).toEqual(projectName)
expect(getReposName.sync).toHaveBeenCalled()
expect(path.basename).toHaveBeenCalled()
})
})
describe('getDefaultAnswer', () => {
it('should handle input prompts correctly', async () => {
const question = { type: 'input', default: 'default' }
const result = await getDefaultAnswer(question)
expect(result).toEqual(question.default)
})
it('should handle choices prompts correctly', async () => {
const value = { name: 'name', value: 'value' }
const question = {
type: 'checkbox',
choices: [{ value, checked: true }, { checked: false }]
}
const result = await getDefaultAnswer(question)
expect(result).toEqual([value])
})
it('should return empty string for non-defaulted fields', async () => {
const question = { type: 'input' }
const result = await getDefaultAnswer(question)
expect(result).toEqual('')
})
it('should return undefined for invalid types', async () => {
const question = { type: 'invalid' }
const result = await getDefaultAnswer(question)
expect(result).toEqual(undefined)
})
it('should return undefined if when function is defined and return false', async () => {
const answersContext = {}
const question = {
type: 'input',
when: ansewersContext => !isNil(ansewersContext.licenseUrl)
}
const result = await getDefaultAnswer(question, answersContext)
expect(result).toEqual(undefined)
})
describe('isProjectAvailableOnNpm', () => {
it('should return true if project is available on npm', () => {
const result = isProjectAvailableOnNpm('readme-md-generator')
expect(result).toBe(true)
})
it('should return false if project is not available on npm', () => {
const result = isProjectAvailableOnNpm('bento-starter')
expect(result).toBe(false)
})
})
it('should return correct value if when function is defined and return true', async () => {
const answersContext = { licenseUrl: 'licenseUrl' }
const question = {
type: 'input',
default: 'default',
when: ansewersContext => !isNil(ansewersContext.licenseUrl)
}
const result = await getDefaultAnswer(question, answersContext)
expect(result).toEqual('default')
})
})
describe('getDefaultAnswers', () => {
it('should return default answers from questions', async () => {
const questions = [
{
type: 'input',
name: 'questionOne',
default: 'answer 1'
},
{
type: 'input',
name: 'questionTwo',
default: 'answer 2'
}
]
const result = await getDefaultAnswers(questions)
expect(result).toEqual({
questionOne: 'answer 1',
questionTwo: 'answer 2'
})
})
})
describe('cleanSocialNetworkUsername', () => {
it('should remove prefixed @', () => {
expect(cleanSocialNetworkUsername('@Slashgear')).toEqual('Slashgear')
})
it('should escape markdown characters', () => {
expect(cleanSocialNetworkUsername('Slashgear__')).toEqual(
'Slashgear\\_\\_'
)
expect(cleanSocialNetworkUsername('Slashgear**')).toEqual(
'Slashgear\\*\\*'
)
})
it('should return the same string when string is not prefixed or contains markdown chars', () => {
expect(cleanSocialNetworkUsername('Slashgear')).toEqual('Slashgear')
})
})
describe('getAuthorWebsiteFromGithubAPI', () => {
it('should return author website url when it exists', async () => {
const expectedAuthorWebsite = 'https://www.franck-abgrall.me/'
fetch.mockReturnValueOnce(
Promise.resolve({
json: () => Promise.resolve({ blog: expectedAuthorWebsite })
})
)
const githubUsername = 'kefranabg'
const authorWebsite = await getAuthorWebsiteFromGithubAPI(githubUsername)
expect(authorWebsite).toEqual(expectedAuthorWebsite)
})
it('should return undefined if author website url does not exist', async () => {
fetch.mockReturnValueOnce(Promise.resolve({ blog: '' }))
const githubUsername = 'kefranabg'
const authorWebsite = await getAuthorWebsiteFromGithubAPI(githubUsername)
expect(authorWebsite).toEqual(undefined)
})
it('should return undefined if there is an error', async () => {
fetch.mockImplementationOnce(() => {
throw new Error('ERROR')
})
const githubUsername = 'kefranabg'
const authorWebsite = await getAuthorWebsiteFromGithubAPI(githubUsername)
expect(authorWebsite).toEqual(undefined)
})
})
describe('doesFileExist', () => {
it('should return true when file exists for a given path', () => {
fs.existsSync.mockReturnValueOnce(true)
expect(doesFileExist('./file-path')).toBe(true)
})
it('should return false when file does not exist for a given path', () => {
fs.existsSync.mockReturnValueOnce(false)
expect(doesFileExist('./file-path')).toBe(false)
})
it('should return false if fs.existsSync throws an error', () => {
fs.existsSync.mockImplementationOnce(() => {
throw new Error('ERROR')
})
expect(doesFileExist('./file-path')).toBe(false)
})
})
describe('getPackageManagerFromLockFile', () => {
it('should return npm if only package-lock.json exists', () => {
fs.existsSync.mockImplementation(
filePath => filePath === 'package-lock.json'
)
const result = getPackageManagerFromLockFile()
expect(result).toEqual('npm')
})
it('should return yarn if only yarn.lock exists', () => {
fs.existsSync.mockImplementation(filePath => filePath === 'yarn.lock')
const result = getPackageManagerFromLockFile()
expect(result).toEqual('yarn')
})
it('should return undefined if only yarn.lock and package-lock.json exists', () => {
fs.existsSync.mockImplementation(
filePath => filePath === 'yarn.lock' || filePath === 'package-lock.json'
)
const result = getPackageManagerFromLockFile()
expect(result).toBeUndefined()
})
it('should return undefined if only no lock file exists', () => {
fs.existsSync.mockImplementation(() => false)
const result = getPackageManagerFromLockFile()
expect(result).toBeUndefined()
})
})
})
================================================
FILE: templates/default-no-html.md
================================================
# Welcome to <%= projectName %> 👋
<% if (isProjectOnNpm) { -%>
[](https://www.npmjs.com/package/<%= projectName %>)
<% } -%>
<% if (projectVersion && !isProjectOnNpm) { -%>

<% } -%>
<% if (projectPrerequisites) { -%>
<% projectPrerequisites.map(({ name, value }) => { -%>
 %>-blue.svg)
<% }) -%>
<% } -%>
<% if (projectDocumentationUrl) { -%>
[](<%= projectDocumentationUrl %>)
<% } -%>
<% if (isGithubRepos) { -%>
[](<%= repositoryUrl %>/graphs/commit-activity)
<% } -%>
<% if (licenseName) { -%>
[](<%= licenseUrl ? licenseUrl : '#' %>)
<% } -%>
<% if (authorTwitterUsername) { -%>
[](https://twitter.com/<%= authorTwitterUsername %>)
<% } -%>
<% if (projectDescription) { -%>
> <%= projectDescription %>
<% } -%>
<% if (projectHomepage) { -%>
### 🏠 [Homepage](<%= projectHomepage %>)
<% } -%>
<% if (projectDemoUrl) { -%>
### ✨ [Demo](<%= projectDemoUrl %>)
<% } -%>
<% if (projectPrerequisites && projectPrerequisites.length) { -%>
## Prerequisites
<% projectPrerequisites.map(({ name, value }) => { -%>
- <%= name %> <%= value %>
<% }) -%>
<% } -%>
<% if (installCommand) { -%>
## Install
```sh
<%= installCommand %>
```
<% } -%>
<% if (usage) { -%>
## Usage
```sh
<%= usage %>
```
<% } -%>
<% if (testCommand) { -%>
## Run tests
```sh
<%= testCommand %>
```
<% } -%>
<% if (authorName || authorTwitterUsername || authorGithubUsername) { -%>
## Author
<% if (authorName) { %>
👤 **<%= authorName %>**
<% } %>
<% if (authorWebsite) { -%>
* Website: <%= authorWebsite %>
<% } -%>
<% if (authorTwitterUsername) { -%>
* Twitter: [@<%= authorTwitterUsername %>](https://twitter.com/<%= authorTwitterUsername %>)
<% } -%>
<% if (authorGithubUsername) { -%>
* GitHub: [@<%= authorGithubUsername %>](https://github.com/<%= authorGithubUsername %>)
<% } -%>
<% if (authorLinkedInUsername) { -%>
* LinkedIn: [@<%= authorLinkedInUsername %>](https://linkedin.com/in/<%= authorLinkedInUsername %>)
<% } -%>
<% } -%>
<% if (issuesUrl) { -%>
## 🤝 Contributing
Contributions, issues and feature requests are welcome!
Feel free to check [issues page](<%= issuesUrl %>). <%= contributingUrl ? `You can also take a look at the [contributing guide](${contributingUrl}).` : '' %>
<% } -%>
## Show your support
Give a ⭐️ if this project helped you!
<% if (authorPatreonUsername) { -%>
[](https://www.patreon.com/<%= authorPatreonUsername %>)
<% } -%>
<% if (licenseName && licenseUrl) { -%>
## 📝 License
<% if (authorName && authorGithubUsername) { -%>
Copyright © <%= currentYear %> [<%= authorName %>](https://github.com/<%= authorGithubUsername %>).
<% } -%>
This project is [<%= licenseName %>](<%= licenseUrl %>) licensed.
<% } -%>
***
<%- include('footer.md'); -%>
================================================
FILE: templates/default.md
================================================
<h1 align="center">Welcome to <%= projectName %> 👋</h1>
<p>
<% if (isProjectOnNpm) { -%>
<a href="https://www.npmjs.com/package/<%= projectName %>" target="_blank">
<img alt="Version" src="https://img.shields.io/npm/v/<%= projectName %>.svg">
</a>
<% } -%>
<% if (projectVersion && !isProjectOnNpm) { -%>
<img alt="Version" src="https://img.shields.io/badge/version-<%= projectVersion %>-blue.svg?cacheSeconds=2592000" />
<% } -%>
<% if (projectPrerequisites) { -%>
<% projectPrerequisites.map(({ name, value }) => { -%>
<img src="https://img.shields.io/badge/<%= name %>-<%= encodeURIComponent(value) %>-blue.svg" />
<% }) -%>
<% } -%>
<% if (projectDocumentationUrl) { -%>
<a href="<%= projectDocumentationUrl %>" target="_blank">
<img alt="Documentation" src="https://img.shields.io/badge/documentation-yes-brightgreen.svg" />
</a>
<% } -%>
<% if (isGithubRepos) { -%>
<a href="<%= repositoryUrl %>/graphs/commit-activity" target="_blank">
<img alt="Maintenance" src="https://img.shields.io/badge/Maintained%3F-yes-green.svg" />
</a>
<% } -%>
<% if (licenseName) { -%>
<a href="<%= licenseUrl ? licenseUrl : '#' %>" target="_blank">
<img alt="License: <%= licenseName %>" src="https://img.shields.io/<%= isGithubRepos ? `github/license/${authorGithubUsername}/${projectName}` : `badge/License-${licenseName}-yellow.svg` %>" />
</a>
<% } -%>
<% if (authorTwitterUsername) { -%>
<a href="https://twitter.com/<%= authorTwitterUsername %>" target="_blank">
<img alt="Twitter: <%= authorTwitterUsername %>" src="https://img.shields.io/twitter/follow/<%= authorTwitterUsername %>.svg?style=social" />
</a>
<% } -%>
</p>
<% if (projectDescription) { -%>
> <%= projectDescription %>
<% } -%>
<% if (projectHomepage) { -%>
### 🏠 [Homepage](<%= projectHomepage %>)
<% } -%>
<% if (projectDemoUrl) { -%>
### ✨ [Demo](<%= projectDemoUrl %>)
<% } -%>
<% if (projectPrerequisites && projectPrerequisites.length) { -%>
## Prerequisites
<% projectPrerequisites.map(({ name, value }) => { -%>
- <%= name %> <%= value %>
<% }) -%>
<% } -%>
<% if (installCommand) { -%>
## Install
```sh
<%= installCommand %>
```
<% } -%>
<% if (usage) { -%>
## Usage
```sh
<%= usage %>
```
<% } -%>
<% if (testCommand) { -%>
## Run tests
```sh
<%= testCommand %>
```
<% } -%>
<% if (authorName || authorTwitterUsername || authorGithubUsername) { -%>
## Author
<% if (authorName) { %>
👤 **<%= authorName %>**
<% } %>
<% if (authorWebsite) { -%>
* Website: <%= authorWebsite %>
<% } -%>
<% if (authorTwitterUsername) { -%>
* Twitter: [@<%= authorTwitterUsername %>](https://twitter.com/<%= authorTwitterUsername %>)
<% } -%>
<% if (authorGithubUsername) { -%>
* GitHub: [@<%= authorGithubUsername %>](https://github.com/<%= authorGithubUsername %>)
<% } -%>
<% if (authorLinkedInUsername) { -%>
* LinkedIn: [@<%= authorLinkedInUsername %>](https://linkedin.com/in/<%= authorLinkedInUsername %>)
<% } -%>
<% } -%>
<% if (issuesUrl) { -%>
## 🤝 Contributing
Contributions, issues and feature requests are welcome!<br />Feel free to check [issues page](<%= issuesUrl %>). <%= contributingUrl ? `You can also take a look at the [contributing guide](${contributingUrl}).` : '' %>
<% } -%>
## Show your support
Give a ⭐️ if this project helped you!
<% if (authorPatreonUsername) { -%>
<a href="https://www.patreon.com/<%= authorPatreonUsername %>">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160">
</a>
<% } -%>
<% if (licenseName && licenseUrl) { -%>
## 📝 License
<% if (authorName && authorGithubUsername) { -%>
Copyright © <%= currentYear %> [<%= authorName %>](https://github.com/<%= authorGithubUsername %>).<br />
<% } -%>
This project is [<%= licenseName %>](<%= licenseUrl %>) licensed.
<% } -%>
***
<%- include('footer.md'); -%>
================================================
FILE: templates/footer.md
================================================
_This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_
gitextract_6qg20dua/
├── .eslintrc.js
├── .github/
│ ├── CODE_OF_CONDUCT.md
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ └── nodejs.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode/
│ └── settings.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── jest.config.js
├── package.json
├── src/
│ ├── __snapshots__/
│ │ └── readme.spec.js.snap
│ ├── ask-overwrite.js
│ ├── ask-overwrite.spec.js
│ ├── ask-questions.js
│ ├── ask-questions.spec.js
│ ├── choose-template.js
│ ├── choose-template.spec.js
│ ├── clean-context.js
│ ├── clean-context.spec.js
│ ├── cli.js
│ ├── cli.spec.js
│ ├── index.js
│ ├── project-infos.js
│ ├── project-infos.spec.js
│ ├── questions/
│ │ ├── author-github.js
│ │ ├── author-github.spec.js
│ │ ├── author-linkedin.js
│ │ ├── author-linkedin.spec.js
│ │ ├── author-name.js
│ │ ├── author-name.spec.js
│ │ ├── author-patreon.js
│ │ ├── author-patreon.spec.js
│ │ ├── author-twitter.js
│ │ ├── author-twitter.spec.js
│ │ ├── author-website.js
│ │ ├── author-website.spec.js
│ │ ├── contributing-url.js
│ │ ├── contributing-url.spec.js
│ │ ├── index.js
│ │ ├── index.spec.js
│ │ ├── install-command.js
│ │ ├── install-command.spec.js
│ │ ├── issues-url.js
│ │ ├── issues-url.spec.js
│ │ ├── license-name.js
│ │ ├── license-name.spec.js
│ │ ├── license-url.js
│ │ ├── license-url.spec.js
│ │ ├── package-manager.js
│ │ ├── package-manager.spec.js
│ │ ├── project-demo-url.js
│ │ ├── project-demo-url.spec.js
│ │ ├── project-description.js
│ │ ├── project-description.spec.js
│ │ ├── project-documentation-url.js
│ │ ├── project-documentation-url.spec.js
│ │ ├── project-homepage.js
│ │ ├── project-homepage.spec.js
│ │ ├── project-name.js
│ │ ├── project-name.spec.js
│ │ ├── project-prerequisites.js
│ │ ├── project-prerequisites.spec.js
│ │ ├── project-version.js
│ │ ├── project-version.spec.js
│ │ ├── test-command.js
│ │ ├── test-command.spec.js
│ │ ├── usage.js
│ │ └── usage.spec.js
│ ├── readme.js
│ ├── readme.spec.js
│ ├── utils.js
│ └── utils.spec.js
└── templates/
├── default-no-html.md
├── default.md
└── footer.md
SYMBOL INDEX (5 symbols across 3 files)
FILE: src/project-infos.js
constant GITHUB_URL (line 14) | const GITHUB_URL = 'https://github.com/'
FILE: src/readme.js
constant README_PATH (line 11) | const README_PATH = 'README.md'
FILE: src/utils.js
constant END_MSG (line 12) | const END_MSG = `README.md was successfully generated.
constant GITHUB_API_URL (line 15) | const GITHUB_API_URL = 'https://api.github.com'
constant BOXEN_CONFIG (line 17) | const BOXEN_CONFIG = {
Condensed preview — 81 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (149K chars).
[
{
"path": ".eslintrc.js",
"chars": 541,
"preview": "module.exports = {\n root: true,\n env: {\n node: true,\n jest: true\n },\n extends: ['airbnb-base', 'eslint:recomme"
},
{
"path": ".github/CODE_OF_CONDUCT.md",
"chars": 3219,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": ".github/FUNDING.yml",
"chars": 593,
"preview": "# These are supported funding model platforms\n\ngithub: [kefranabg]\npatreon: FranckAbgrall\nopen_collective: # Replace wit"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 829,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n---\n\n**Describe the bu"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 594,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n---\n\n**Is your feat"
},
{
"path": ".github/workflows/nodejs.yml",
"chars": 754,
"preview": "name: Node CI\n\non:\n pull_request:\n push:\n branches:\n - master\n\njobs:\n build:\n runs-on: ubuntu-latest\n\n "
},
{
"path": ".gitignore",
"chars": 211,
"preview": ".DS_Store\nnode_modules\n/report\n/coverage\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Editor directori"
},
{
"path": ".prettierignore",
"chars": 11,
"preview": "templates/*"
},
{
"path": ".prettierrc",
"chars": 43,
"preview": "{\n \"singleQuote\": true,\n \"semi\": false\n}\n"
},
{
"path": ".vscode/settings.json",
"chars": 34,
"preview": "{\n \"editor.formatOnSave\": true\n}\n"
},
{
"path": "CHANGELOG.md",
"chars": 28996,
"preview": "# Changelog\n\n<a name=\"1.0.0\"></a>\n\n## 1.0.0 (2019-12-03)\n\n### Added\n\n- ✨ Ask for package manager when is JS project [[29"
},
{
"path": "CONTRIBUTING.md",
"chars": 2233,
"preview": "# Contributing to Readme Markdown Generator\n\n👍🎉 First off, thanks for taking the time to contribute! 🎉👍\n\nWhen contributi"
},
{
"path": "LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2019 Franck Abgrall\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "README.md",
"chars": 6439,
"preview": "<h1 align=\"center\">Welcome to readme-md-generator 👋</h1>\n<p align=\"center\">\n <img src=\"https://img.shields.io/npm/v/rea"
},
{
"path": "jest.config.js",
"chars": 141,
"preview": "module.exports = {\n collectCoverageFrom: [\n './src/**/*.js',\n '!./src/index.js',\n '!**/node_modules/**',\n '"
},
{
"path": "package.json",
"chars": 1571,
"preview": "{\n \"name\": \"readme-md-generator\",\n \"version\": \"1.0.0\",\n \"description\": \"CLI that generates beautiful README.md files."
},
{
"path": "src/__snapshots__/readme.spec.js.snap",
"chars": 5327,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`readme buildReadmeContent should return readme default template con"
},
{
"path": "src/ask-overwrite.js",
"chars": 525,
"preview": "const inquirer = require('inquirer')\n\nconst question = {\n type: 'list',\n message:\n '🚨 readme-md-generator will ove"
},
{
"path": "src/ask-overwrite.spec.js",
"chars": 916,
"preview": "const inquirer = require('inquirer')\n\nconst askOverwrite = require('./ask-overwrite')\n\nconst expectedQuestion = {\n type"
},
{
"path": "src/ask-questions.js",
"chars": 863,
"preview": "const inquirer = require('inquirer')\nconst { flatMap } = require('lodash')\n\nconst questionsBuilders = require('./questio"
},
{
"path": "src/ask-questions.spec.js",
"chars": 2177,
"preview": "const inquirer = require('inquirer')\n\nconst questions = require('./questions')\nconst askQuestions = require('./ask-quest"
},
{
"path": "src/choose-template.js",
"chars": 780,
"preview": "const inquirer = require('inquirer')\nconst path = require('path')\n\nmodule.exports = async useDefaultAnswers => {\n const"
},
{
"path": "src/choose-template.spec.js",
"chars": 1306,
"preview": "const inquirer = require('inquirer')\nconst path = require('path')\n\nconst chooseTemplate = require('./choose-template')\n\n"
},
{
"path": "src/clean-context.js",
"chars": 485,
"preview": "/**\n * Clean answer context\n *\n * @param {Object} context\n */\nmodule.exports = context => {\n const cleanBadgeText = tex"
},
{
"path": "src/clean-context.spec.js",
"chars": 475,
"preview": "const cleanContext = require('./clean-context')\n\ndescribe('cleanContext', () => {\n it('should replace licenseName and p"
},
{
"path": "src/cli.js",
"chars": 1069,
"preview": "const readme = require('./readme')\nconst infos = require('./project-infos')\nconst utils = require('./utils')\nconst askQu"
},
{
"path": "src/cli.spec.js",
"chars": 3536,
"preview": "const inquirer = require('inquirer')\nconst mainProcess = require('./cli')\nconst infos = require('./project-infos')\nconst"
},
{
"path": "src/index.js",
"chars": 701,
"preview": "#!/usr/bin/env node\n\nconst yargs = require('yargs')\nconst { noop } = require('lodash')\n\nconst mainProcess = require('./c"
},
{
"path": "src/project-infos.js",
"chars": 4846,
"preview": "const isNil = require('lodash/isNil')\nconst get = require('lodash/get')\nconst has = require('lodash/has')\nconst ora = re"
},
{
"path": "src/project-infos.spec.js",
"chars": 14720,
"preview": "const ora = require('ora')\nconst childProcess = require('child_process')\n\nconst utils = require('./utils')\nconst { getPr"
},
{
"path": "src/questions/author-github.js",
"chars": 284,
"preview": "const { cleanSocialNetworkUsername } = require('../utils')\n\nmodule.exports = projectInfos => ({\n type: 'input',\n messa"
},
{
"path": "src/questions/author-github.spec.js",
"chars": 506,
"preview": "const askAuthorGithub = require('./author-github')\n\ndescribe('askAuthorGithub', () => {\n it('should return correct ques"
},
{
"path": "src/questions/author-linkedin.js",
"chars": 238,
"preview": "const { cleanSocialNetworkUsername } = require('../utils')\n\nmodule.exports = () => ({\n type: 'input',\n message: '💼 Li"
},
{
"path": "src/questions/author-linkedin.spec.js",
"chars": 391,
"preview": "const askAuthorLinkedIn = require('./author-linkedin')\n\ndescribe('askAuthorLinkedIn', () => {\n it('should return correc"
},
{
"path": "src/questions/author-name.js",
"chars": 138,
"preview": "module.exports = projectInfos => ({\n type: 'input',\n message: '👤 Author name',\n name: 'authorName',\n default: proje"
},
{
"path": "src/questions/author-name.spec.js",
"chars": 403,
"preview": "const askAuthorName = require('./author-name')\n\ndescribe('askAuthorName', () => {\n it('should return correct question f"
},
{
"path": "src/questions/author-patreon.js",
"chars": 237,
"preview": "const { cleanSocialNetworkUsername } = require('../utils')\n\nmodule.exports = () => ({\n type: 'input',\n message: '❤️ P"
},
{
"path": "src/questions/author-patreon.spec.js",
"chars": 392,
"preview": "const askPatreonUsername = require('./author-patreon')\n\ndescribe('askPatreonUsername', () => {\n it('should return corre"
},
{
"path": "src/questions/author-twitter.js",
"chars": 236,
"preview": "const { cleanSocialNetworkUsername } = require('../utils')\n\nmodule.exports = () => ({\n type: 'input',\n message: '🐦 Tw"
},
{
"path": "src/questions/author-twitter.spec.js",
"chars": 385,
"preview": "const askAuthorTwitter = require('./author-twitter')\n\ndescribe('askAuthorTwitter', () => {\n it('should return correct q"
},
{
"path": "src/questions/author-website.js",
"chars": 398,
"preview": "const { getAuthorWebsiteFromGithubAPI } = require('../utils')\n\nmodule.exports = projectInfos => ({\n type: 'input',\n me"
},
{
"path": "src/questions/author-website.spec.js",
"chars": 1507,
"preview": "const fetch = require('node-fetch')\nconst askAuthorWebsite = require('./author-website')\n\njest.mock('node-fetch')\n\ndescr"
},
{
"path": "src/questions/contributing-url.js",
"chars": 189,
"preview": "module.exports = projectInfos => ({\n type: 'input',\n message: '🤝 Contributing guide url (use empty value to skip)',\n "
},
{
"path": "src/questions/contributing-url.spec.js",
"chars": 560,
"preview": "const askContributingUrl = require('./contributing-url')\n\ndescribe('askContributingUrl', () => {\n it('should return cor"
},
{
"path": "src/questions/index.js",
"chars": 1098,
"preview": "/* eslint-disable global-require */\nmodule.exports = {\n askProjectName: require('./project-name'),\n askProjectVersion:"
},
{
"path": "src/questions/index.spec.js",
"chars": 786,
"preview": "const questions = require('./')\n\ndescribe('questions', () => {\n it('should export questions in the correct order', () ="
},
{
"path": "src/questions/install-command.js",
"chars": 364,
"preview": "const isNil = require('lodash/isNil')\n\nmodule.exports = projectInfos => ({\n type: 'input',\n message: '📦 Install comma"
},
{
"path": "src/questions/install-command.spec.js",
"chars": 912,
"preview": "const askInstallCommand = require('./install-command')\n\ndescribe('askInstallCommand', () => {\n it('should return correc"
},
{
"path": "src/questions/issues-url.js",
"chars": 168,
"preview": "module.exports = packageJson => ({\n type: 'input',\n message: '🔧 Issues page url (use empty value to skip)',\n name: '"
},
{
"path": "src/questions/issues-url.spec.js",
"chars": 469,
"preview": "const askIssues = require('./issues-url')\n\ndescribe('askIssues', () => {\n it('should return correct question format', ("
},
{
"path": "src/questions/license-name.js",
"chars": 169,
"preview": "module.exports = packageJson => ({\n type: 'input',\n message: '📝 License name (use empty value to skip)',\n name: 'lic"
},
{
"path": "src/questions/license-name.spec.js",
"chars": 439,
"preview": "const askLicenseName = require('./license-name')\n\ndescribe('askLicenseName', () => {\n it('should return correct questio"
},
{
"path": "src/questions/license-url.js",
"chars": 275,
"preview": "const isEmpty = require('lodash/isEmpty')\n\nmodule.exports = projectInfos => ({\n type: 'input',\n message: '📝 License u"
},
{
"path": "src/questions/license-url.spec.js",
"chars": 1305,
"preview": "const askLicenseUrl = require('./license-url')\n\ndescribe('askLicenseUrl', () => {\n it('should return correct question f"
},
{
"path": "src/questions/package-manager.js",
"chars": 365,
"preview": "const isEmpty = require('lodash/isEmpty')\n\nmodule.exports = projectInfos => ({\n type: 'list',\n message: '📦 Choose Pac"
},
{
"path": "src/questions/package-manager.spec.js",
"chars": 1385,
"preview": "const askPackageManager = require('./package-manager')\n\nconst expectedQuestion = {\n type: 'list',\n message: '📦 Choose"
},
{
"path": "src/questions/project-demo-url.js",
"chars": 131,
"preview": "module.exports = () => ({\n type: 'input',\n message: '✨ Project demo url (use empty value to skip)',\n name: 'projectD"
},
{
"path": "src/questions/project-demo-url.spec.js",
"chars": 351,
"preview": "const askProjectDemoUrl = require('./project-demo-url')\n\ndescribe('askProjectDemoUrl', () => {\n it('should return the c"
},
{
"path": "src/questions/project-description.js",
"chars": 159,
"preview": "module.exports = projectInfos => ({\n type: 'input',\n message: '📄 Project description',\n name: 'projectDescription',\n"
},
{
"path": "src/questions/project-description.spec.js",
"chars": 463,
"preview": "const askProjectDescription = require('./project-description')\n\ndescribe('askProjectDescription', () => {\n it('should r"
},
{
"path": "src/questions/project-documentation-url.js",
"chars": 201,
"preview": "module.exports = projectInfos => ({\n type: 'input',\n message: '📘 Project documentation url (use empty value to skip)'"
},
{
"path": "src/questions/project-documentation-url.spec.js",
"chars": 408,
"preview": "const askProjectName = require('./project-name')\n\ndescribe('askProjectName', () => {\n it('should return correct questio"
},
{
"path": "src/questions/project-homepage.js",
"chars": 176,
"preview": "module.exports = projectInfos => ({\n type: 'input',\n message: '🏠 Project homepage (use empty value to skip)',\n name:"
},
{
"path": "src/questions/project-homepage.spec.js",
"chars": 459,
"preview": "const askProjectHomepage = require('./project-homepage')\n\ndescribe('askProjectHomepage', () => {\n it('should return cor"
},
{
"path": "src/questions/project-name.js",
"chars": 138,
"preview": "module.exports = projectInfos => ({\n type: 'input',\n message: '💡 Project name',\n name: 'projectName',\n default: pro"
},
{
"path": "src/questions/project-name.spec.js",
"chars": 601,
"preview": "const askProjectDocumentationUrl = require('./project-documentation-url')\n\ndescribe('askProjectDocumentationUrl', () => "
},
{
"path": "src/questions/project-prerequisites.js",
"chars": 862,
"preview": "const isEmpty = require('lodash/isEmpty')\nconst isNil = require('lodash/isNil')\n\n/**\n * Return engines as formatted choi"
},
{
"path": "src/questions/project-prerequisites.spec.js",
"chars": 1644,
"preview": "const askProjectPrerequisites = require('./project-prerequisites')\n\ndescribe('askProjectPrerequisites', () => {\n it('sh"
},
{
"path": "src/questions/project-version.js",
"chars": 174,
"preview": "module.exports = projectInfos => ({\n type: 'input',\n message: 'ℹ️ Project version (use empty value to skip)',\n name:"
},
{
"path": "src/questions/project-version.spec.js",
"chars": 448,
"preview": "const askProjectVersion = require('./project-version')\n\ndescribe('askProjectVersion', () => {\n it('should return correc"
},
{
"path": "src/questions/test-command.js",
"chars": 403,
"preview": "const isNil = require('lodash/isNil')\n\nmodule.exports = projectInfos => ({\n type: 'input',\n message: '✅ Test command "
},
{
"path": "src/questions/test-command.spec.js",
"chars": 1225,
"preview": "const askTestCommand = require('./test-command')\n\ndescribe('askTestCommand', () => {\n it('should return correct questio"
},
{
"path": "src/questions/usage.js",
"chars": 415,
"preview": "const isNil = require('lodash/isNil')\n\nmodule.exports = projectInfos => ({\n type: 'input',\n message: '🚀 Usage command"
},
{
"path": "src/questions/usage.spec.js",
"chars": 1197,
"preview": "const askUsage = require('./usage')\n\ndescribe('askUsage', () => {\n it('should return correct question format', () => {\n"
},
{
"path": "src/readme.js",
"chars": 2660,
"preview": "const ejs = require('ejs')\nconst ora = require('ora')\nconst { promisify } = require('util')\nconst { getYear } = require("
},
{
"path": "src/readme.spec.js",
"chars": 7625,
"preview": "const fs = require('fs')\nconst ora = require('ora')\nconst path = require('path')\nconst chooseTemplate = require('./choos"
},
{
"path": "src/utils.js",
"chars": 4524,
"preview": "const loadJsonFile = require('load-json-file')\nconst isNil = require('lodash/isNil')\nconst isEmpty = require('lodash/isE"
},
{
"path": "src/utils.spec.js",
"chars": 9749,
"preview": "const loadJsonFile = require('load-json-file')\nconst boxen = require('boxen')\nconst path = require('path')\nconst getRepo"
},
{
"path": "templates/default-no-html.md",
"chars": 3478,
"preview": "# Welcome to <%= projectName %> 👋\n<% if (isProjectOnNpm) { -%>\n[ { -%>\n <a href=\"https://www.npmjs.co"
},
{
"path": "templates/footer.md",
"chars": 110,
"preview": "_This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_"
}
]
About this extraction
This page contains the full source code of the kefranabg/readme-md-generator GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 81 files (136.7 KB), approximately 40.7k tokens, and a symbol index with 5 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.