Skip to content

Commit

Permalink
Update to version 5 (#23)
Browse files Browse the repository at this point in the history
* Update to version 5

* Tweak README
  • Loading branch information
joshwcomeau authored Feb 9, 2023
1 parent 0788c1d commit 60532a2
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 217 deletions.
9 changes: 9 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
The MIT License (MIT)

Copyright (c) 2017-present Joshua Comeau

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.
104 changes: 32 additions & 72 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
<a href="https://www.npmjs.org/package/new-component"><img src="https://img.shields.io/npm/v/new-component.svg?style=flat" alt="npm"></a>
</p>

# `new-component`
# new-component

### Simple, customizable utility for adding new React components to your project.

<img src="https://github.com/joshwcomeau/new-component/blob/master/docs/[email protected]?raw=true" width="888" height="100" role="presentation">

Anyone else sick of writing the same component boilerplate, over and over?
This project is a CLI tool that allows you to quickly scaffold new components. All of the necessary boilerplate will be generated automatically.

This project is a globally-installable CLI for adding new React components. It's dead simple to use, and requires no configuration, although it's easy to customize it to fit your project's coding style.
This project uses an opinionated file structure discussed in this blog post: [**Delightful React File/Directory Structure**](https://www.joshwcomeau.com/react/file-structure/).

> **NOTE: This project is not actively maintained.** I continue to use it in my own projects, but I don't have the bandwidth to review PRs or triage issues. Feel free to fork this project and tweak it however you wish. ❤️
<br />

Expand All @@ -25,6 +27,8 @@ This project is a globally-installable CLI for adding new React components. It's

<br />

> **Version 5:** The new version adds support for TypeScript, and removes support for passing a custom file extension;
## Quickstart

Install via NPM:
Expand All @@ -39,33 +43,29 @@ $ npm i -g new-component

`cd` into your project's directory, and try creating a new component:

<p align="center">
<img src="https://github.com/joshwcomeau/new-component/blob/master/docs/demo.gif?raw=true" width="888" height="369" alt="demo of CLI functionality">
</p>
```bash
$ new-component MyNewComponent
```

Your project will now have a new directory at `src/components/Button`. This directory has two files:
Your project will now have a new directory at `src/components/MyNewComponent`. This directory has two files:

```jsx
// `Button/index.js`
export { default } from './Button';
// `MyNewComponent/index.js`
export { default } from './MyNewComponent';
```

```jsx
// `Button/Button.js`
import React, { Component } from 'react';
// `MyNewComponent/MyNewComponent.js`
import React from 'react';

class Button extends Component {
render() {
return <div />;
}
function MyNewComponent() {
return <div></div>;
}

export default Button;
export default MyNewComponent;
```

> This structure might appear odd to you, with an `index.js` that points to a named file. I've found this to be an optimal way to set up components; the `index.js` allows you to `import` from the directory (eg. `import Button from 'components/Button'`), while having `Button.js` means that you're never lost in a sea of `index.js` files in your editor.
>
> This structure is not currently configurable, but I'm happy to consider implementing alternatives!
These files will be formatted according to your Prettier configuration.

<br />

Expand All @@ -83,21 +83,20 @@ The resulting values are merged, with command-line values overwriting local valu

## API Reference

### Type
### Language

Control the type of component created:
Controls which language, JavaScript or TypeScript, should be used.

- `functional` for a stateless functional component (default).
- `class` for a traditional Component class,
- `pure-class` for a PureComponent class,
- `js` — creates a `.js` file (default).
- `ts` — creates a `.tsx` file.

Legacy `createClass` components are not supported.
Note that all components created will be functional components. Class components are not supported.

**Usage:**

Command line: `--type <value>` or `-t <value>`
Command line: `--lang <value>` or `-l <value>`

JSON config: `{ "type": <value> }`
JSON config: `{ "lang": <value> }`
<br />

### Directory
Expand All @@ -111,56 +110,17 @@ Command line: `--dir <value>` or `-d <value>`
JSON config: `{ "dir": <value> }`
<br />

### File Extension

Controls the file extension for the created components. Can be either `js` (default) or `jsx`.

**Usage:**

Command line: `--extension <value>` or `-x <value>`

JSON config: `{ "extension": <value> }`
<br />

### Prettier Config

Delegate settings to Prettier, so that your new component is formatted as you'd like. Defaults to Prettier defaults.

For a full list of options, see the [Prettier docs](https://github.com/prettier/prettier#options).

**Usage:**

Command line: N/A (Prettier config is only controllable through JSON)

JSON config: `{ "prettierConfig": { "key": "value" } }`
<br />

**Example:**

```js
{
"prettierConfig": {
"singleQuote": true,
"semi": false,
}
}
```

(Ideally, the plugin would consume your project's prettier settings automatically! But I haven't built this yet. PRs welcome!)

<br />

## Platform Support

This has only been tested in macOS. I think it'd work fine in linux, but I haven't tested it. Windows is a big question mark (would welcome contribution here!).

This has only been tested in macOS. I think it'd work fine in linux, but I haven't tested it. Windows is a big question mark.
<br />

## Development

To get started with development:

- Check out this git repo locally, you will need to ensure you have Yarn installed globally.
- In the folder run `yarn install`
- Check that command runs `node ../new-component/src/index.js --help`
- Alternatively you can set up a symlink override by running `npm link` then `new-component --help`. Note: this will override any globally installed version of this package.
- Fork and clone the Git repo
- `cd` into the directory and install dependencies (`yarn install` or `npm install`)
- Set up a symlink by running `npm link`, while in the `new-component` directory. This will ensure that the `new-component` command uses this locally-cloned project, rather than the global NPM installation.
- Spin up a test React project.
- In that test project, use the `new-component` command to create components and test that your changes are working.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new-component",
"version": "4.0.1",
"version": "5.0.0",
"description": "CLI for creating new React components",
"homepage": "https://github.com/joshwcomeau/new-component",
"repository": {
Expand All @@ -27,8 +27,8 @@
"new-component": "./src/index.js"
},
"dependencies": {
"chalk": "^2.4.1",
"commander": "^2.15.1",
"prettier": "1.5.3"
"chalk": "4",
"commander": "10",
"prettier": "2.8.4"
}
}
42 changes: 42 additions & 0 deletions src/affirmations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module.exports = [
'Thanks for using new-component!',
'Thanks for using new-component!',
'Thanks for using new-component!',
'Thanks for using new-component!',
'Thanks for using new-component!',
"Hope you're having a great day!",
"Hope you're having a lovely day!",
"Hope you're having a stellar day!",
"Hope you're having a glorious day!",
"Hope you're having a marvelous day!",
"Hope you're having a brilliant day!",
"Hope you're having a wonderful day!",
"Hope you're having a fantastic day!",
"Hope you're having a phenomenal day!",
"Hope you're having a sensational day!",
"Hope you're having an incredible day!",
"Hope you're having the best day ever!",
'An apple a day keeps the doctor away. 🍎',
"Can't wait what to see what you do with it!",
'Same bat time, same bat channel. 🦇',
'Be kind, rewind.',
'Every day is an adventure. ✨',
"You miss 100% of the shots you don't take. 🏀",
"It's like sunshine on a rainy day. 🌦",
"💪 Let's do this.",
"💪 Let's go!",
"💪 You've got this.",
"You're a rockstar. 🤘",
'Have you gone for a walk today? 🚶',
'Be kind to people. Including yourself.',
'Woohoo!! ✨',
"Let's do some celebratory jumping jacks! ⭐️",
"Let's party 🥳",
'All good vibes. 🌈',
'🎉🎉🎉🎉🎉',
'You are an unstoppable force of nature.',
'Turn up the jam. 🔊',
'You belong in this world ❤️',
'Live your best life ❤️',
"Wherever it takes me, I'm down for the ride. 🎶",
];
96 changes: 49 additions & 47 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const path = require('path');
const prettier = require('prettier');
const chalk = require('chalk');

const { requireOptional } = require('./utils');
const { requireOptional, sample } = require('./utils');
const AFFIRMATIONS = require('./affirmations');

// Get the configuration for this component.
// Overrides are as follows:
Expand All @@ -30,9 +31,8 @@ module.exports.getConfig = () => {
const currentPath = process.cwd();

const defaults = {
type: 'functional',
lang: 'js',
dir: 'src/components',
extension: 'js',
};

const globalOverrides = requireOptional(
Expand All @@ -46,37 +46,31 @@ module.exports.getConfig = () => {
return Object.assign({}, defaults, globalOverrides, localOverrides);
};

module.exports.buildPrettifier = (prettierConfig) => {
// If they haven't supplied a prettier config, check for a
// `.prettierrc`!

let config = prettierConfig;

if (!config) {
const currentPath = process.cwd();

try {
config = fs.readFileSync(
path.join(currentPath, '/.prettierrc'),
{ encoding: 'utf8', flag: 'r' }
);
} catch (err) {
// No big deal, they don't have a prettier config
}

if (config) {
try {
config = JSON.parse(config);
} catch (err) {
console.error('Count not parse .prettierrc, does not appear to be JSON')
}
}
}
module.exports.buildPrettifier = () => {
let config = prettier.resolveConfig.sync(process.cwd());

// default config:
config = config || {
semi: true,
singleQuote: true,
trailingComma: 'es5',
};

// Prettier warns if we don't specify a parser or a file path.
// TODO: Maybe we should create the file first, so that it can
// serve as the file path?
config.parser = config.parser || 'babel';

return (text) => {
return prettier.format(text, config);
return (text) => prettier.format(text, config);
};

module.exports.createParentDirectoryIfNecessary = async (dir) => {
const fullPathToParentDir = path.resolve(dir);

if (!fs.existsSync(fullPathToParentDir)) {
fs.mkdirSync(dir);
}
}
};

// Emit a message confirming the creation of the component
const colors = {
Expand All @@ -88,30 +82,38 @@ const colors = {
darkGray: [90, 90, 90],
};

const logComponentType = (selected) =>
['class', 'pure-class', 'functional']
.sort((a, b) => (a === selected ? -1 : 1))
const langNames = {
js: 'JavaScript',
ts: 'TypeScript',
};

const logComponentLang = (selected) =>
['js', 'ts']
.map((option) =>
option === selected
? `${chalk.bold.rgb(...colors.blue)(option)}`
: `${chalk.rgb(...colors.darkGray)(option)}`
? `${chalk.bold.rgb(...colors.blue)(langNames[option])}`
: `${chalk.rgb(...colors.darkGray)(langNames[option])}`
)
.join(' ');

module.exports.logIntro = ({ name, dir, type }) => {
module.exports.logIntro = ({ name, dir, lang }) => {
console.info('\n');
console.info(
`✨ Creating the ${chalk.bold.rgb(...colors.gold)(name)} component ✨`
`✨ Creating the ${chalk.bold.rgb(...colors.gold)(
name
)} component ✨`
);
console.info('\n');

const pathString = chalk.bold.rgb(...colors.blue)(dir);
const typeString = logComponentType(type);
const langString = logComponentLang(lang);

console.info(`Directory: ${pathString}`);
console.info(`Type: ${typeString}`);
console.info(`Language: ${langString}`);
console.info(
chalk.rgb(...colors.darkGray)('=========================================')
chalk.rgb(...colors.darkGray)(
'========================================='
)
);

console.info('\n');
Expand All @@ -124,16 +126,16 @@ module.exports.logItemCompletion = (successText) => {

module.exports.logConclusion = () => {
console.info('\n');
console.info(chalk.bold.rgb(...colors.green)('Component created! 🚀 '));
console.info(
chalk.rgb(...colors.mediumGray)('Thanks for using new-component.')
);
console.info(chalk.bold.rgb(...colors.green)('Component created!'));
console.info(chalk.rgb(...colors.mediumGray)(sample(AFFIRMATIONS)));
console.info('\n');
};

module.exports.logError = (error) => {
console.info('\n');
console.info(chalk.bold.rgb(...colors.red)('Error creating component.'));
console.info(
chalk.bold.rgb(...colors.red)('Error creating component.')
);
console.info(chalk.rgb(...colors.red)(error));
console.info('\n');
};
Loading

0 comments on commit 60532a2

Please sign in to comment.