Skip to content

Commit

Permalink
feat: enable custom eslint configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
jepser committed Oct 12, 2019
1 parent 26860e9 commit a18e6f2
Show file tree
Hide file tree
Showing 7 changed files with 648 additions and 76 deletions.
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "airbnb"
}
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
"dependencies": {
"arg": "^4.1.1",
"chalk": "^2.4.2",
"eslint": "6.1.0",
"esm": "^3.2.25",
"find-up": "^4.1.0",
"inquirer": "^7.0.0",
"ncp": "^2.0.0",
"read-pkg-up": "^6.0.0",
Expand All @@ -32,6 +34,11 @@
"devDependencies": {
"@commitlint/cli": "^8.2.0",
"@commitlint/config-conventional": "^8.2.0",
"eslint-config-airbnb": "18.0.1",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.14.3",
"eslint-plugin-react-hooks": "^1.7.0",
"husky": "^3.0.8",
"jest": "^24.9.0",
"semantic-release": "^15.13.24"
Expand Down
49 changes: 38 additions & 11 deletions src/create-files.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import fs from 'fs'
import path from 'path'
import toPascalCase from 'to-pascal-case'

import { getEslintConfig, lintFile } from './linter'
import { CLASS_COMPONENT_TYPE, PURE_COMPONENT_TYPE } from './constants'

export const isClassComponent = (type) => ['class', 'pure'].includes(type) ? type : false
export const getComponentType = type => type === 'pure' ? PURE_COMPONENT_TYPE : CLASS_COMPONENT_TYPE

export const copyTemplate = ({ file, target, transform = i => i }) => {
const pipe = (...functors) => input => {
return functors.reduce((result, functor) => functor(result) , input)
}

export const copyTemplate = ({ file, target, transform = [] }) => {

const currentFileUrl = import.meta.url;
const templateDir = path.resolve(
new URL(currentFileUrl).pathname,
Expand All @@ -18,38 +23,58 @@ export const copyTemplate = ({ file, target, transform = i => i }) => {
const targetFile = path.resolve(process.cwd(), target)

return fs.readFile(templateDir, (err, data) => {
const fileContent = transform(data.toString())
const fileContent = pipe(...transform)({ dir: templateDir, data: data.toString() })

fs.writeFileSync(targetFile, fileContent)
});
}

export const getFilesToBeCreated = (fileName, options) => {
export const getFilesToBeCreated = async (fileName, options) => {
const componentFileName = isClassComponent(options.type) ? 'class-component.js' : 'component.js'
const componentName = toPascalCase(fileName)
const componentType = getComponentType(options.type)

const eslintConfig = options.eslint ? await getEslintConfig(options.eslint) : {}
const defaultTransforms = options.eslint ? [lintFile(eslintConfig)] : []
const templates = [
{
file: componentFileName,
target: `${fileName}/${fileName}.js`,
transform: data => {
transform: [
({ data, ...rest }) => {
const withComponentName = data.replace(/\$ComponentName/g, componentName)
return withComponentName.replace(/\$ComponentType/g, componentType)
}
return {
data: withComponentName.replace(/\$ComponentType/g, componentType),
...rest
}
},
...defaultTransforms,
]
},
{
file: 'index.js',
target: `${fileName}/index.js`,
transform: data => data.replace(/\$fileName/g, fileName)
transform: [
({ data, ...rest }) => ({
data: data.replace(/\$fileName/g, fileName),
...rest
}),
...defaultTransforms,
]
}
]

if(options.withTest) {
templates.push({
file: 'component.test.js',
target: `${fileName}/${fileName}.${options.testSuffix}.js`,
transform: data => data.replace(/\$ComponentName/g, componentName)
transform: [
({ data, ...rest }) => ({
data: data.replace(/\$ComponentName/g, componentName),
...rest
}),
...defaultTransforms,
]
})
}

Expand All @@ -63,10 +88,12 @@ export const getFilesToBeCreated = (fileName, options) => {
return templates
}

const createFiles = (fileName, options) => {
const files = getFilesToBeCreated(fileName, options)
const createFiles = async (fileName, options) => {
const files = await getFilesToBeCreated(fileName, options)
try {
fs.mkdirSync(fileName)
if(!fs.existsSync(fileName)) {
fs.mkdirSync(fileName)
}

files.forEach(copyTemplate)

Expand Down
17 changes: 9 additions & 8 deletions src/get-configuration.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import readPkgUp from 'read-pkg-up'
import readPkgUp from 'read-pkg-up';

const DEFAULT_CONF = {
withTest: false,
withStyled: false,
testSuffix: 'test',
}
eslint: '',
};

const getConfiguration = async () => {
const packageJson = await readPkgUp()
const packageJson = await readPkgUp();

if(!packageJson || !packageJson.package.mkcomponent) return DEFAULT_CONF
if (!packageJson || !packageJson.package.mkcomponent) return DEFAULT_CONF;

return {
...DEFAULT_CONF,
...packageJson.package.mkcomponent
}
}
...packageJson.package.mkcomponent,
};
};

export default getConfiguration
export default getConfiguration;
21 changes: 21 additions & 0 deletions src/linter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* eslint-disable global-require */
import fs from 'fs';
import findUp from 'find-up';

export const lintFile = (config) => ({ dir, data }) => {
const { CLIEngine, Linter } = require('eslint');

const linter = new Linter();
const cli = new CLIEngine({ baseConfig: config });
const fileConfig = cli.getConfigForFile(dir);

const lintedData = linter.verifyAndFix(data, fileConfig);

return lintedData.output;
};

export const getEslintConfig = async (option) => {
const configFile = await findUp(option);
const file = fs.readFileSync(configFile, 'utf8');
return JSON.parse(file);
};
61 changes: 30 additions & 31 deletions src/mkcomponent.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import arg from 'arg'
import chalk from 'chalk'
import { promptForMissingOptions } from './interactive-prompt'
import createFiles from './create-files'
import arg from 'arg';
import chalk from 'chalk';
import { promptForMissingOptions } from './interactive-prompt';
import createFiles from './create-files';
import getConfiguration from './get-configuration';

const getComponentType = (options) => {
switch(true) {
switch (true) {
case options['--pure']:
return 'pure'
return 'pure';
case options['--class']:
return 'class'
return 'class';
case options['--func']:
return 'func'
return 'func';
default:
return ''
return '';
}
}
};
const parseArgsToOptions = (rawArgs) => {
const args = arg({
'--class': Boolean,
Expand All @@ -24,22 +24,22 @@ const parseArgsToOptions = (rawArgs) => {
'--help': Boolean,
'-c': '--class',
'-p': '--pure',
'-f': '--func'
'-f': '--func',
}, {
argv: rawArgs.slice(2),
})
});

return {
name: args._[0],
type: getComponentType(args),
help: args['--help']
}
}
help: args['--help'],
};
};

const mkcomponent = async (args) => {
const options = parseArgsToOptions(args)
const options = parseArgsToOptions(args);

if(options.help) {
if (options.help) {
return console.log(chalk`
Usage:
mkcomponent {bold component-name}
Expand All @@ -49,25 +49,24 @@ const mkcomponent = async (args) => {
--class: for class component
--pure: for pure component
--func: for functional component (default)
`
)
`);
}

delete options.help
delete options.help;

const defaultConfiguration = await getConfiguration()
const defaultConfiguration = await getConfiguration();
const { name, ...componentOptions } = await promptForMissingOptions({
...defaultConfiguration,
...options
})
...options,
});

const result = await createFiles(name, componentOptions);

const result = createFiles(name, componentOptions)

if(result.done) {
console.log(chalk.green.bold(`Your component "${name}" has been created 🎉`))
if (result.done) {
console.log(chalk.green.bold(`Your component "${name}" has been created 🎉`));
} else {
console.log(chalk.red(`Ups... "${name}" component couldn't be created 😞`))
}
}
console.log(chalk.red(`Ups... "${name}" component couldn't be created 😞`));
}
};

export default mkcomponent
export default mkcomponent;
Loading

0 comments on commit a18e6f2

Please sign in to comment.