diff --git a/.all-contributorsrc b/.all-contributorsrc
new file mode 100644
index 00000000..dcd84c21
--- /dev/null
+++ b/.all-contributorsrc
@@ -0,0 +1,23 @@
+{
+ "projectName": "kcd-scripts",
+ "projectOwner": "kentcdodds",
+ "files": [
+ "README.md"
+ ],
+ "imageSize": 100,
+ "commit": false,
+ "contributors": [
+ {
+ "login": "kentcdodds",
+ "name": "Kent C. Dodds",
+ "avatar_url": "https://avatars.githubusercontent.com/u/1500684?v=3",
+ "profile": "https://kentcdodds.com",
+ "contributions": [
+ "code",
+ "doc",
+ "infra",
+ "test"
+ ]
+ }
+ ]
+}
diff --git a/.babelrc b/.babelrc
new file mode 100644
index 00000000..a699d330
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,13 @@
+{
+ "presets": [
+ ["env", {
+ "targets": {
+ "node": "4.5"
+ }
+ }]
+ ],
+ "plugins": [
+ "transform-class-properties",
+ "transform-object-rest-spread"
+ ]
+}
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 00000000..9c628283
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,3 @@
+node_modules
+coverage
+dist
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 00000000..3fd3cbc2
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,23 @@
+{
+ "extends": [
+ "kentcdodds",
+ "kentcdodds/jest",
+ "kentcdodds/prettier"
+ ],
+ "rules": {
+ // stuff I haven't gotten around to updating in my config
+ "no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^ignored" }],
+ "func-style": "off",
+ "no-process-exit": "off",
+ "import/no-dynamic-require": "off",
+
+ // prettier does this for us
+ "max-len": "off",
+ "semi": "off",
+ "quotes": "off",
+ "comma-dangle": "off",
+ "no-console": "off",
+ "indent": "off",
+ "babel/object-curly-spacing": "off"
+ }
+}
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..391f0a4e
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+* text=auto
+*.js text eol=lf
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000..65162e38
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,43 @@
+
+
+- `kcd-scripts` version:
+- `node` version:
+- `npm` (or `yarn`) version:
+
+Relevant code or config
+
+```javascript
+
+```
+
+What you did:
+
+
+
+What happened:
+
+
+
+Reproduction repository:
+
+
+
+Problem description:
+
+
+
+Suggested solution:
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000..e421002c
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,35 @@
+
+
+
+**What**:
+
+
+**Why**:
+
+
+**How**:
+
+
+**Checklist**:
+
+
+- [ ] Documentation
+- [ ] Tests
+- [ ] Ready to be merged
+- [ ] Added myself to contributors table
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..09048d22
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+node_modules
+coverage
+dist
+.opt-in
+.opt-out
+.DS_Store
+.eslintcache
+
+# these cause more harm than good
+# when working with contributors
+package-lock.json
+yarn.lock
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 00000000..a57cc9e5
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+registry=http://registry.npmjs.org/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..6fdf7167
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,17 @@
+sudo: false
+language: node_js
+cache:
+ directories:
+ - node_modules
+notifications:
+ email: false
+node_js:
+ - '8'
+script:
+ - npm start validate
+after_success:
+ - npx codecov
+ - npm i -g semantic-release@7 && semantic-release pre && npm publish && semantic-release post
+branches:
+ only:
+ - master
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..06d221aa
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,4 @@
+# CHANGELOG
+
+The changelog is automatically updated using [semantic-release](https://github.com/semantic-release/semantic-release).
+You can see it on the [releases page](../../releases).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..cd514e9f
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,84 @@
+# Contributing
+
+Thanks for being willing to contribute!
+
+**Working on your first Pull Request?** You can learn how from this *free* series
+[How to Contribute to an Open Source Project on GitHub][egghead]
+
+## Project setup
+
+1. Fork and clone the repo
+2. `$ npm install` to install dependencies
+3. `$ npm start validate` to validate you've got it working
+4. Create a branch for your PR
+
+This project uses [`nps`][nps] and you can run `npm start help` to see what
+scripts are available.
+
+> Tip: Keep your `master` branch pointing at the original repository and make
+> pull requests from branches on your fork. To do this, run:
+>
+> ```
+> git remote add upstream https://github.com/kentcdodds/kcd-scripts.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`.
+
+## Add yourself as a contributor
+
+This project follows the [all contributors][all-contributors] specification.
+To add yourself to the table of contributors on the README.md, please use the
+automated script as part of your PR:
+
+```console
+npm start contributors.add
+```
+
+Follow the prompt and commit `.all-contributorsrc` and `README.md` in the PR.
+If you've already added yourself to the list and are making
+a new type of contribution, you can run it again and select the added
+contribution type.
+
+## Committing and Pushing changes
+
+This project uses [`semantic-release`][semantic-release] to do automatic
+releases and generate a changelog based on the commit history. So we follow
+[a convention][convention] for commit messages. You don't have to follow this
+convention if you don't like to. Just know that when we merge your commit, we'll
+probably use "Squash and Merge" so we can change the commit message :)
+
+Please make sure to run the tests before you commit your changes. You can run
+`npm start test.update` which will update any snapshots that need updating.
+Make sure to include those changes (if they exist) in your commit.
+
+### opt into git hooks
+
+There are git hooks set up with this project that are automatically installed
+when you install dependencies. They're really handy, but are turned off by
+default (so as to not hinder new contributors). You can opt into these by
+creating a file called `.opt-in` at the root of the project and putting this
+inside:
+
+```
+pre-commit
+```
+
+## Help needed
+
+Please checkout the [the open issues][issues]
+
+Also, please watch the repo and respond to questions/bug reports/feature requests! Thanks!
+
+[egghead]: https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github
+[semantic-release]: https://npmjs.com/package/semantic-release
+[convention]: https://github.com/conventional-changelog/conventional-changelog-angular/blob/ed32559941719a130bb0327f886d6a32a8cbc2ba/convention.md
+[all-contributors]: https://github.com/kentcdodds/all-contributors
+[issues]: https://github.com/kentcdodds/kcd-scripts/issues
+[nps]: https://github.com/kentcdodds/nps
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..4c43675b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+Copyright (c) 2017 Kent C. Dodds
+
+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.
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..b200c321
--- /dev/null
+++ b/README.md
@@ -0,0 +1,93 @@
+
+
kcd-scripts
+
+CLI for common scripts for my projects
+
+
+
+
+[![Build Status][build-badge]][build]
+[![Code Coverage][coverage-badge]][coverage]
+[![version][version-badge]][package]
+[![downloads][downloads-badge]][npmcharts]
+[![MIT License][license-badge]][LICENSE]
+
+[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors)
+[![PRs Welcome][prs-badge]][prs]
+[![Code of Conduct][coc-badge]][coc]
+
+[![Watch on GitHub][github-watch-badge]][github-watch]
+[![Star on GitHub][github-star-badge]][github-star]
+[![Tweet][twitter-badge]][twitter]
+
+## The problem
+
+// TODO
+
+## This solution
+
+// TODO
+
+## Installation
+
+This module is distributed via [npm][npm] which is bundled with [node][node] and
+should be installed as one of your project's `devDependencies`:
+
+```
+npm install --save-dev kcd-scripts
+```
+
+## Usage
+
+// TODO
+
+## Inspiration
+
+// TODO
+
+## Other Solutions
+
+I'm not aware of any, if you are please [make a pull request][prs] and add it
+here!
+
+## Contributors
+
+Thanks goes to these people ([emoji key][emojis]):
+
+
+| [
Kent C. Dodds](https://kentcdodds.com)
[💻](https://github.com/kentcdodds/kcd-scripts/commits?author=kentcdodds) [📖](https://github.com/kentcdodds/kcd-scripts/commits?author=kentcdodds) 🚇 [⚠️](https://github.com/kentcdodds/kcd-scripts/commits?author=kentcdodds) |
+| :---: |
+
+
+This project follows the [all-contributors][all-contributors] specification.
+Contributions of any kind welcome!
+
+## LICENSE
+
+MIT
+
+[npm]: https://www.npmjs.com/
+[node]: https://nodejs.org
+[build-badge]: https://img.shields.io/travis/kentcdodds/kcd-scripts.svg?style=flat-square
+[build]: https://travis-ci.org/kentcdodds/kcd-scripts
+[coverage-badge]: https://img.shields.io/codecov/c/github/kentcdodds/kcd-scripts.svg?style=flat-square
+[coverage]: https://codecov.io/github/kentcdodds/kcd-scripts
+[version-badge]: https://img.shields.io/npm/v/kcd-scripts.svg?style=flat-square
+[package]: https://www.npmjs.com/package/kcd-scripts
+[downloads-badge]: https://img.shields.io/npm/dm/kcd-scripts.svg?style=flat-square
+[npmcharts]: http://npmcharts.com/compare/kcd-scripts
+[license-badge]: https://img.shields.io/npm/l/kcd-scripts.svg?style=flat-square
+[license]: https://github.com/kentcdodds/kcd-scripts/blob/master/LICENSE
+[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
+[prs]: http://makeapullrequest.com
+[donate-badge]: https://img.shields.io/badge/$-support-green.svg?style=flat-square
+[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
+[coc]: https://github.com/kentcdodds/kcd-scripts/blob/master/other/CODE_OF_CONDUCT.md
+[github-watch-badge]: https://img.shields.io/github/watchers/kentcdodds/kcd-scripts.svg?style=social
+[github-watch]: https://github.com/kentcdodds/kcd-scripts/watchers
+[github-star-badge]: https://img.shields.io/github/stars/kentcdodds/kcd-scripts.svg?style=social
+[github-star]: https://github.com/kentcdodds/kcd-scripts/stargazers
+[twitter]: https://twitter.com/intent/tweet?text=Check%20out%20kcd-scripts!%20https://github.com/kentcdodds/kcd-scripts%20%F0%9F%91%8D
+[twitter-badge]: https://img.shields.io/twitter/url/https/github.com/kentcdodds/kcd-scripts.svg?style=social
+[emojis]: https://github.com/kentcdodds/all-contributors#emoji-key
+[all-contributors]: https://github.com/kentcdodds/all-contributors
diff --git a/jest.config.js b/jest.config.js
new file mode 100644
index 00000000..19758b9f
--- /dev/null
+++ b/jest.config.js
@@ -0,0 +1 @@
+module.exports = require('./src/config/jest.config')
diff --git a/kcd.config.js b/kcd.config.js
new file mode 100644
index 00000000..472503fd
--- /dev/null
+++ b/kcd.config.js
@@ -0,0 +1,10 @@
+const path = require('path')
+
+module.exports = {
+ eslint: {
+ extends: [path.join(__dirname, './.eslintrc')],
+ },
+ jest: {
+ coverageThreshold: {},
+ },
+}
diff --git a/other/CODE_OF_CONDUCT.md b/other/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..a62ad9c1
--- /dev/null
+++ b/other/CODE_OF_CONDUCT.md
@@ -0,0 +1,87 @@
+# Contributor Covenant Code of Conduct
+
+
+
+**Table of Contents**
+
+- [Our Pledge](#our-pledge)
+- [Our Standards](#our-standards)
+- [Our Responsibilities](#our-responsibilities)
+- [Scope](#scope)
+- [Enforcement](#enforcement)
+- [Attribution](#attribution)
+
+
+
+## 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 contributes 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 kent+coc@doddsfamily.us. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and 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/
diff --git a/other/MAINTAINING.md b/other/MAINTAINING.md
new file mode 100644
index 00000000..5232261b
--- /dev/null
+++ b/other/MAINTAINING.md
@@ -0,0 +1,75 @@
+# Maintaining
+
+
+
+**Table of Contents**
+
+- [Code of Conduct](#code-of-conduct)
+- [Issues](#issues)
+- [Pull Requests](#pull-requests)
+- [Release](#release)
+- [Thanks!](#thanks)
+
+
+
+This is documentation for maintainers of this project.
+
+## Code of Conduct
+
+Please review, understand, and be an example of it. Violations of the code of conduct are
+taken seriously, even (especially) for maintainers.
+
+## Issues
+
+We want to support and build the community. We do that best by helping people learn to solve
+their own problems. We have an issue template and hopefully most folks follow it. If it's
+not clear what the issue is, invite them to create a minimal reproduction of what they're trying
+to accomplish or the bug they think they've found.
+
+Once it's determined that a code change is necessary, point people to
+[makeapullrequest.com](http://makeapullrequest.com) and invite them to make a pull request.
+If they're the one who needs the feature, they're the one who can build it. If they need
+some hand holding and you have time to lend a hand, please do so. It's an investment into
+another human being, and an investment into a potential maintainer.
+
+Remember that this is open source, so the code is not yours, it's ours. If someone needs a change
+in the codebase, you don't have to make it happen yourself. Commit as much time to the project
+as you want/need to. Nobody can ask any more of you than that.
+
+## Pull Requests
+
+As a maintainer, you're fine to make your branches on the main repo or on your own fork. Either
+way is fine.
+
+When we receive a pull request, a travis build is kicked off automatically (see the `.travis.yml`
+for what runs in the travis build). We avoid merging anything that breaks the travis build.
+
+Please review PRs and focus on the code rather than the individual. You never know when this is
+someone's first ever PR and we want their experience to be as positive as possible, so be
+uplifting and constructive.
+
+When you merge the pull request, 99% of the time you should use the
+[Squash and merge](https://help.github.com/articles/merging-a-pull-request/) feature. This keeps
+our git history clean, but more importantly, this allows us to make any necessary changes to the
+commit message so we release what we want to release. See the next section on Releases for more
+about that.
+
+## Release
+
+Our releases are automatic. They happen whenever code lands into `master`. A travis build gets
+kicked off and if it's successful, a tool called
+[`semantic-release`](https://github.com/semantic-release/semantic-release) is used to
+automatically publish a new release to npm as well as a changelog to GitHub. It is only able to
+determine the version and whether a release is necessary by the git commit messages. With this
+in mind, **please brush up on [the commit message convention][commit] which drives our releases.**
+
+> One important note about this: Please make sure that commit messages do NOT contain the words
+> "BREAKING CHANGE" in them unless we want to push a major version. I've been burned by this
+> more than once where someone will include "BREAKING CHANGE: None" and it will end up releasing
+> a new major version. Not a huge deal honestly, but kind of annoying...
+
+## Thanks!
+
+Thank you so much for helping to maintain this project!
+
+[commit]: https://github.com/conventional-changelog-archived-repos/conventional-changelog-angular/blob/ed32559941719a130bb0327f886d6a32a8cbc2ba/convention.md
diff --git a/other/USERS.md b/other/USERS.md
new file mode 100644
index 00000000..5432378d
--- /dev/null
+++ b/other/USERS.md
@@ -0,0 +1,16 @@
+# Users
+
+
+
+
+
+If you or your company uses this project, add your name to this list! Eventually
+we may have a website to showcase these (wanna build it!?)
+
+> No users have been added yet!
+
+
diff --git a/other/manual-releases.md b/other/manual-releases.md
new file mode 100644
index 00000000..7f85823d
--- /dev/null
+++ b/other/manual-releases.md
@@ -0,0 +1,47 @@
+# manual-releases
+
+
+
+
+
+This project has an automated release set up. So things are only released when there are
+useful changes in the code that justify a release. But sometimes things get messed up one way or another
+and we need to trigger the release ourselves. When this happens, simply bump the number below and commit
+that with the following commit message based on your needs:
+
+**Major**
+
+```
+fix(release): manually release a major version
+
+There was an issue with a major release, so this manual-releases.md
+change is to release a new major version.
+
+Reference: #
+
+BREAKING CHANGE:
+```
+
+**Minor**
+
+```
+feat(release): manually release a minor version
+
+There was an issue with a minor release, so this manual-releases.md
+change is to release a new minor version.
+
+Reference: #
+```
+
+**Patch**
+
+```
+fix(release): manually release a patch version
+
+There was an issue with a patch release, so this manual-releases.md
+change is to release a new patch version.
+
+Reference: #
+```
+
+The number of times we've had to do a manual release is: 0
diff --git a/package-scripts.js b/package-scripts.js
new file mode 100644
index 00000000..15b7d3e4
--- /dev/null
+++ b/package-scripts.js
@@ -0,0 +1,45 @@
+const npsUtils = require('nps-utils')
+
+const series = npsUtils.series
+const concurrent = npsUtils.concurrent
+const rimraf = npsUtils.rimraf
+const crossEnv = npsUtils.crossEnv
+
+module.exports = {
+ scripts: {
+ contributors: {
+ add: {
+ description: 'When new people contribute to the project, run this',
+ script: 'all-contributors add',
+ },
+ generate: {
+ description: 'Update the badge and contributors table',
+ script: 'all-contributors generate',
+ },
+ },
+ test: {
+ default: crossEnv('NODE_ENV=test jest --coverage'),
+ update: crossEnv('NODE_ENV=test jest --coverage --updateSnapshot'),
+ watch: crossEnv('NODE_ENV=test jest --watch'),
+ openCoverage: 'open coverage/lcov-report/index.html',
+ },
+ build: {
+ description: 'delete the dist directory and run babel to build the files',
+ script: series(
+ rimraf('dist'),
+ 'babel --copy-files --out-dir dist --ignore __tests__ src'
+ ),
+ },
+ lint: {
+ description: 'lint the entire project',
+ script: 'eslint . --cache',
+ },
+ validate: {
+ description: `This runs several scripts to make sure things look good before committing or on clean install`,
+ script: concurrent.nps('lint', 'build', 'test'),
+ },
+ },
+ options: {
+ silent: false,
+ },
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..ddc53819
--- /dev/null
+++ b/package.json
@@ -0,0 +1,66 @@
+{
+ "name": "kcd-scripts",
+ "version": "0.0.0-semantically-released",
+ "description": "CLI for common scripts for my projects",
+ "main": "dist/index.js",
+ "engines": {
+ "node": "> 4",
+ "npm": "> 3"
+ },
+ "scripts": {
+ "start": "nps",
+ "test": "node src test",
+ "precommit":
+ "lint-staged && opt --in pre-commit --exec \"npm start validate\""
+ },
+ "files": ["dist"],
+ "keywords": [],
+ "author": "Kent C. Dodds (http://kentcdodds.com/)",
+ "license": "MIT",
+ "dependencies": {
+ "all-contributors-cli": "^4.3.0",
+ "babel-cli": "^6.24.1",
+ "babel-preset-env": "^1.6.0",
+ "babel-jest": "^20.0.3",
+ "babel-plugin-transform-class-properties": "^6.24.1",
+ "babel-plugin-transform-object-rest-spread": "^6.23.0",
+ "concurrently": "^3.5.0",
+ "cross-spawn": "^5.1.0",
+ "eslint-config-kentcdodds": "^12.4.1",
+ "eslint": "^4.2.0",
+ "husky": "^0.14.3",
+ "jest": "^20.0.4",
+ "lint-staged": "^4.0.1",
+ "lodash": "^4.17.4",
+ "opt-cli": "^1.5.1",
+ "prettier": "^1.6.1",
+ "read-pkg-up": "^2.0.0",
+ "resolve-bin": "^0.4.0",
+ "rimraf": "^2.6.1"
+ },
+ "devDependencies": {
+ "nps": "^5.4.0",
+ "nps-utils": "^1.2.0"
+ },
+ "lint-staged": {
+ "*.+(js|json)": ["prettier --write", "git add"]
+ },
+ "prettier": {
+ "printWidth": 80,
+ "tabWidth": 2,
+ "useTabs": false,
+ "semi": false,
+ "singleQuote": true,
+ "trailingComma": "es5",
+ "bracketSpacing": false,
+ "jsxBraketSameLine": false
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/kentcdodds/kcd-scripts.git"
+ },
+ "bugs": {
+ "url": "https://github.com/kentcdodds/kcd-scripts/issues"
+ },
+ "homepage": "https://github.com/kentcdodds/kcd-scripts#readme"
+}
diff --git a/src/__tests__/index.js b/src/__tests__/index.js
new file mode 100644
index 00000000..6eb18238
--- /dev/null
+++ b/src/__tests__/index.js
@@ -0,0 +1 @@
+test('works', () => {})
diff --git a/src/config/eslintignore b/src/config/eslintignore
new file mode 100644
index 00000000..5ab667c9
--- /dev/null
+++ b/src/config/eslintignore
@@ -0,0 +1,6 @@
+node_modules/
+coverage/
+dist/
+build/
+out/
+.next/
diff --git a/src/config/eslintrc.js b/src/config/eslintrc.js
new file mode 100644
index 00000000..c6fdc0a1
--- /dev/null
+++ b/src/config/eslintrc.js
@@ -0,0 +1,41 @@
+const {applyOverrides, ifDevDep} = require('../utils')
+
+const config = applyOverrides({
+ type: 'eslint',
+ config: {
+ extends: [
+ 'kentcdodds',
+ ifDevDep('jest', 'kentcdodds/jest'),
+ ifDevDep('webpack', 'kentcdodds/webpack'),
+ ifDevDep('react', 'kentcdodds/jsx-a11y'),
+ ifDevDep('react', 'kentcdodds/react'),
+ ifDevDep('prettier', 'kentcdodds/prettier'),
+ ].filter(Boolean),
+ rules: {
+ // stuff I haven't gotten around to updating in my config
+ 'no-unused-vars': [
+ 'error',
+ {argsIgnorePattern: '^_', varsIgnorePattern: '^ignored'},
+ ],
+ 'func-style': 'off',
+ 'no-process-exit': 'off',
+
+ // prettier does this for us
+ ...ifDevDep(
+ 'prettier',
+ {
+ 'max-len': 'off',
+ semi: 'off',
+ quotes: 'off',
+ 'comma-dangle': 'off',
+ 'no-console': 'off',
+ indent: 'off',
+ 'babel/object-curly-spacing': 'off',
+ },
+ {}
+ ),
+ },
+ },
+})
+
+module.exports = config
diff --git a/src/config/jest.config.js b/src/config/jest.config.js
new file mode 100644
index 00000000..3e256282
--- /dev/null
+++ b/src/config/jest.config.js
@@ -0,0 +1,29 @@
+const {ifDevDep, applyOverrides} = require('../utils')
+
+const ignores = [
+ '/node_modules/',
+ '/fixtures/',
+ '/__tests__/helpers/',
+ '__mocks__',
+]
+
+const config = applyOverrides({
+ type: 'jest',
+ config: {
+ testEnvironment: ifDevDep('webpack', 'jsdom', 'node'),
+ collectCoverageFrom: ['src/**/*.js'],
+ testMatch: ['**/__tests__/**/*.js'],
+ testPathIgnorePatterns: ignores,
+ coveragePathIgnorePatterns: ignores,
+ coverageThreshold: {
+ global: {
+ branches: 100,
+ functions: 100,
+ lines: 100,
+ statements: 100,
+ },
+ },
+ },
+})
+
+module.exports = config
diff --git a/src/config/prettierrc.js b/src/config/prettierrc.js
new file mode 100644
index 00000000..d487c288
--- /dev/null
+++ b/src/config/prettierrc.js
@@ -0,0 +1,17 @@
+const {applyOverrides} = require('../utils')
+
+const config = applyOverrides({
+ type: 'prettier',
+ config: {
+ printWidth: 80,
+ tabWidth: 2,
+ useTabs: false,
+ semi: false,
+ singleQuote: true,
+ trailingComma: 'all',
+ bracketSpacing: false,
+ jsxBraketSameLine: false,
+ },
+})
+
+module.exports = config
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 00000000..24b5cd1f
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,42 @@
+#!/usr/bin/env node
+const path = require('path')
+const spawn = require('cross-spawn')
+
+function attemptResolve(...args) {
+ try {
+ return require.resolve(...args)
+ } catch (error) {
+ return null
+ }
+}
+
+const [executor, ignoredBin, script, ...args] = process.argv
+const relativeScriptPath = path.join(__dirname, './scripts', script)
+const scriptPath = attemptResolve(relativeScriptPath)
+
+if (!scriptPath) {
+ console.log(`Unknown script "${script}".`)
+ console.log('Perhaps you need to update paypal-scripts?')
+}
+
+const result = spawn.sync(executor, [scriptPath, ...args], {
+ stdio: 'inherit',
+})
+
+if (result.signal) {
+ if (result.signal === 'SIGKILL') {
+ console.log(
+ 'The build failed because the process exited too early. ' +
+ 'This probably means the system ran out of memory or someone called ' +
+ '`kill -9` on the process.'
+ )
+ } else if (result.signal === 'SIGTERM') {
+ console.log(
+ 'The build failed because the process exited too early. ' +
+ 'Someone might have called `kill` or `killall`, or the system could ' +
+ 'be shutting down.'
+ )
+ }
+ process.exit(1)
+}
+process.exit(result.status)
diff --git a/src/paths.js b/src/paths.js
new file mode 100644
index 00000000..8a79d73d
--- /dev/null
+++ b/src/paths.js
@@ -0,0 +1,7 @@
+const path = require('path')
+const fs = require('fs')
+
+const appDirectory = fs.realpathSync(process.cwd())
+const fromRoot = (...p) => path.join(appDirectory, ...p)
+
+module.exports = {appDirectory, fromRoot}
diff --git a/src/scripts/build.js b/src/scripts/build.js
new file mode 100644
index 00000000..2d89b4fb
--- /dev/null
+++ b/src/scripts/build.js
@@ -0,0 +1,22 @@
+const resolveBin = require('resolve-bin')
+const spawn = require('cross-spawn')
+const rimraf = require('rimraf')
+const {fromRoot} = require('../paths')
+
+const argv = process.argv.slice(2)
+
+rimraf.sync(fromRoot('dist'))
+
+const result = spawn.sync(
+ resolveBin.sync('babel-cli', {executable: 'babel'}),
+ // prettier-ignore
+ [
+ '--copy-files',
+ '--out-dir', 'dist',
+ '--ignore', '__tests__,__mocks__',
+ 'src',
+ ].concat(argv),
+ {stdio: 'inherit'}
+)
+
+process.exit(result)
diff --git a/src/scripts/format.js b/src/scripts/format.js
new file mode 100644
index 00000000..224c97f7
--- /dev/null
+++ b/src/scripts/format.js
@@ -0,0 +1,20 @@
+const path = require('path')
+const resolveBin = require('resolve-bin')
+const spawn = require('cross-spawn')
+
+const argv = process.argv.slice(2)
+
+const here = p => path.join(__dirname, p)
+
+const result = spawn.sync(
+ resolveBin.sync('prettier'),
+ // prettier-ignore
+ [
+ '--write',
+ '--config', here('../config/prettierrc.js'),
+ '--ignore-path', here('../config/eslintignore'),
+ ].concat(argv),
+ {stdio: 'inherit'}
+)
+
+process.exit(result)
diff --git a/src/scripts/lint.js b/src/scripts/lint.js
new file mode 100644
index 00000000..7d8505b9
--- /dev/null
+++ b/src/scripts/lint.js
@@ -0,0 +1,25 @@
+const path = require('path')
+const resolveBin = require('resolve-bin')
+const spawn = require('cross-spawn')
+
+const [ignoredExecutor, ignoredBin, ignoredScript, ...args] = process.argv
+
+const here = p => path.join(__dirname, p)
+
+const result = spawn.sync(
+ resolveBin.sync('eslint'),
+ // prettier-ignore
+ [
+ '--config', here('../config/eslintrc.js'),
+ '--ignore-path', here('../config/eslintignore'),
+ '--cache',
+ '.',
+ ].concat(args),
+ {stdio: 'inherit'}
+)
+
+if (result.status === 0) {
+ console.error(`All's good 👍`)
+}
+
+process.exit(result.status)
diff --git a/src/scripts/test.js b/src/scripts/test.js
new file mode 100644
index 00000000..b9c1988b
--- /dev/null
+++ b/src/scripts/test.js
@@ -0,0 +1,13 @@
+process.env.BABEL_ENV = 'test'
+process.env.NODE_ENV = 'test'
+
+const jest = require('jest')
+
+const argv = process.argv.slice(2)
+
+if (!process.env.CI && !argv.includes('--coverage')) {
+ argv.push('--watch')
+}
+argv.push('--config', JSON.stringify(require('../config/jest.config')))
+
+jest.run(argv)
diff --git a/src/scripts/validate.js b/src/scripts/validate.js
new file mode 100644
index 00000000..86e8c45f
--- /dev/null
+++ b/src/scripts/validate.js
@@ -0,0 +1,27 @@
+const spawn = require('cross-spawn')
+const {ifScript} = require('../utils')
+
+const scriptNames = (...scripts) =>
+ scripts
+ .map(s => ifScript(s, s))
+ .filter(Boolean)
+ .join(',')
+
+const result = spawn.sync(
+ require.resolve('concurrently'),
+ // prettier-ignore
+ [
+ '--kill-others-on-fail',
+ '--prefix', '[{name}]',
+ '--names', scriptNames('build', 'lint', 'test'),
+ '--prefix-colors', 'bgBlue.bold,bgGreen.bold,bgOrang.bold',
+ ...[
+ ifScript('build', 'npm run build --silent'),
+ ifScript('lint', 'npm run lint --silent'),
+ ifScript('test', 'npm run test --silent -- --coverage'),
+ ].filter(Boolean),
+ ],
+ {stdio: 'inherit'}
+)
+
+process.exit(result)
diff --git a/src/utils.js b/src/utils.js
new file mode 100644
index 00000000..ffdeb023
--- /dev/null
+++ b/src/utils.js
@@ -0,0 +1,90 @@
+const fs = require('fs')
+const path = require('path')
+const {mergeWith} = require('lodash')
+const readPkgUp = require('read-pkg-up')
+
+function hasDevDependency(dep) {
+ return getPkgProp('devDependencies').hasOwnProperty(dep)
+}
+
+function getPkgProp(prop) {
+ const {pkg} = readPkgUp.sync({cwd: process.cwd()})
+ return pkg[prop]
+}
+
+function hasScript(script) {
+ return getPkgProp('scripts').hasOwnProperty(script)
+}
+
+function ifScript(script, t, f) {
+ return hasScript(script) ? t : f
+}
+
+function ifDevDep(dep, t, f) {
+ return hasDevDependency(dep) ? t : f
+}
+
+// this will do a deep merge of two objects
+// If the object has a value that's an array,
+// then the source's value will be concat-ed with it.
+function mergeWithArrayConcat(object, source) {
+ return mergeWith(object, source, (objValue, srcValue) => {
+ if (Array.isArray(objValue)) {
+ return objValue.concat(srcValue)
+ }
+ return srcValue
+ })
+}
+
+function applyOverrides({config = {}, type}) {
+ config = applyOverridesToPath({
+ config,
+ type,
+ overrideConfig: readUserConfig()[type],
+ })
+ return config
+}
+
+function readUserConfig() {
+ const appDirectory = fs.realpathSync(process.cwd())
+ const configPath = path.resolve(path.join(appDirectory, '/kcd.config.js'))
+ if (fs.existsSync(configPath)) {
+ return require(configPath)
+ } else {
+ return {}
+ }
+}
+
+// eslint-disable-next-line complexity
+function applyOverridesToPath({config, type, overrideConfig}) {
+ if (!overrideConfig) {
+ return config
+ }
+ try {
+ if (typeof overrideConfig === 'function') {
+ const overrides = overrideConfig(config, process.env.NODE_ENV)
+ if (!overrides) {
+ throw new Error(
+ `${type} overrides function provided, but the config was not returned. You need to return the config`
+ )
+ }
+ return overrides
+ } else if (typeof overrideConfig === 'object') {
+ return mergeWithArrayConcat(config, overrideConfig)
+ }
+ } catch (error) {
+ console.error(
+ `There was a problem trying to apply ${type} config overrides`
+ )
+ throw error
+ }
+ return config
+}
+
+module.exports = {
+ applyOverrides,
+ hasDevDependency,
+ ifDevDep,
+ hasScript,
+ ifScript,
+}