Skip to content

Commit

Permalink
Merge pull request #2 from tareqdayya/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
tareqdayya committed Jun 8, 2020
2 parents 5cdd006 + 5f4526c commit fb4a26e
Show file tree
Hide file tree
Showing 16 changed files with 238 additions and 262 deletions.
32 changes: 32 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module.exports = {
env: {
commonjs: true,
es6: true,
node: true,
},
extends: [
'standard', 'eslint',
],
parserOptions: {
ecmaVersion: 11,
},
rules: {
'require-jsdoc': 'off',
'jsdoc/require-returns': 'off',
'jsdoc/require-description': 'off',
'jsdoc/require-jsdoc': 'off',
quotes: ['error', 'single'],
strict: 'off',
'valid-jsdoc': 'off',
'comma-dangle': ['error', {
arrays: 'always-multiline',
objects: 'always-multiline',
imports: 'always-multiline',
exports: 'always-multiline',
functions: 'always-multiline',
}],
semi: ['error', 'always'],
'prefer-template': 'error',
curly: ['error', 'multi-line'],
},
};
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ This package **automates the generation of React/RN Components in typescript**.

##### 1- index.tsx
##### 2- ArticleTitle.tsx
##### 3- a style file: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;• for web: ArticleTitle.scss
&nbsp;&nbsp;&nbsp;&nbsp;• for RN: ArticleTitleStyles.ts <br/>
PS: You can control which extension your styling files are.
##### 3- a style file: You can choose one of the following options:
'CSS'| 'SCSS'| 'Less'| 'Sass'| 'React Native Style'| 'Styled Components'.
##### 4- an optional test file: ArticleTitle.test.tsx

-----------
Expand All @@ -34,5 +32,6 @@ on the command line:
You will get asked a few questions, answer them. <br/>
Boilerplate code generated :) <br/>

* If the path to the files doesn't exist, the package will create the directories for you.
* If the path to the files doesn't exist, worry not––the package will create the directories for
you.

182 changes: 43 additions & 139 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,143 +1,47 @@
#!/usr/bin/env node
const fs = require('fs');
const promisify = require('util').promisify;
const fsWrite = promisify(fs.writeFile);
const fsRead = promisify(fs.readFile);
const path = require('path');
const inquirer = require('inquirer');
const mustache = require('mustache');
const mkdirp = require('mkdirp');

let componentName = '';
let isFunctionComponent = false;
let styleSheetExtension = 'css';
let hasTestFile = false;
let targetPath = './src/components';
let isReactNative = false;

// get component name and css preprocessor
const writeFile = require('./lib/writeFile');
const { stylesheetType } = require('./lib/constants');

const styleSheetTypes = [
{ name: 'CSS', value: { extension: 'css', type: stylesheetType.cssBased } },
{ name: 'SCSS', value: { extension: 'scss', type: stylesheetType.cssBased } },
{ name: 'Less', value: { extension: 'less', type: stylesheetType.cssBased } },
{ name: 'Sass', value: { extension: 'sass', type: stylesheetType.cssBased } },
{ name: 'React Native Style', value: { extension: 'ts', type: stylesheetType.reactNative } },
{ name: 'Styled Components', value: { extension: 'ts', type: stylesheetType.styledComponents } },
];

// PROMPT
inquirer
.prompt([
{ type: 'input', name: 'componentName', message: 'whats your component\'s name?' },
{
type: 'input',
name: 'isFunction',
message: 'is this a function component? (y for yes, or press enter) : '
},
{
type: 'input',
name: 'styleSheetExtension',
message: 'whats stylesheet preprocessor are u using? (leave empty for css for web and ts for RN)'
},
{
type: 'input',
name: 'hasTestFile',
message: 'Do you want to generate a test file? (y for yes, or press enter) : ',
},
{
type: 'input',
name: 'finalPath',
message: 'what\'s the path to the folder? (leave empty for ./src/components)'
},
{
type: 'input',
name: 'isReactNative',
message: 'is this a react native component? (y for yes, or press enter) : '
},
])
.then(answers => {
componentName = answers['componentName'];
if (answers['isFunction'] && answers['isFunction'] === 'y') isFunctionComponent = true;
if (answers['styleSheetExtension']) styleSheetExtension = answers['styleSheetExtension'];
if (answers['hasTestFile'] && answers['hasTestFile'].toLowerCase() === 'y') hasTestFile = true;
if (answers['finalPath']) targetPath = answers['finalPath'];
if (answers['isReactNative'] && answers['isReactNative'].toLowerCase() === 'y') isReactNative = true;
main();
});

async function readFile(path) {
return await fsRead(path, 'utf-8');
}

async function writeFileToDir(dir, fileName, content) {
await fsWrite(path.join(dir, fileName), content);
}

function convertCamelCaseToSpinal(string) {
let i = 0;
let convertedString = '';
let character = '';
while (i <= string.length) {
character = string.charAt(i);
if (!isNaN(character * 1)) {
convertedString += character;
} else {
if (character == character.toUpperCase()) {
if (i) convertedString += '-';
convertedString += character.toLowerCase();
} else convertedString += character;
}
i++;
}

return convertedString;

}

function main() {
const targetDir = path.join(process.cwd(), targetPath, componentName);

async function pipeTemplateToFile() {
const componentTemplate = isFunctionComponent ? 'reactFunctionalComponentTemplate.txt' : 'reactComponentTemplate.txt';

const templatePaths = [
path.join(__dirname, 'templates', componentTemplate),
path.join(__dirname, 'templates', 'index.txt'),
path.join(__dirname, 'templates', 'reactWebStyleSheet.txt'),
];

const finalFileNames = [`${componentName}.tsx`, 'index.tsx', `${componentName}.${styleSheetExtension}`];

if (isReactNative) {
if (styleSheetExtension === 'css') styleSheetExtension = 'ts';

templatePaths.pop();
templatePaths.push(path.join(__dirname, 'templates', 'reactNativeStyleSheet.txt'));

finalFileNames.pop();
finalFileNames.push(`${componentName}Styles.${styleSheetExtension}`);
}

if (hasTestFile) {
templatePaths.push(path.join(__dirname, 'templates', 'testTemplate.txt'));
finalFileNames.push(`${componentName}.test.tsx`);
}

for (let templatePathIndex = 0; templatePathIndex < templatePaths.length; templatePathIndex++) {
const templatePath = templatePaths[templatePathIndex];

const template = await readFile(templatePath);

const output = mustache.render(template,
.prompt([
{ type: 'input', name: 'componentName', message: 'whats your component\'s name?' },
{
COMPONENT_NAME: componentName,
STYLESHEET_FILENAME: componentName + (isReactNative ? 'Styles' : ''),
STYLESHEET_EXTENSION: styleSheetExtension,
WEB_CLASS_NAME: convertCamelCaseToSpinal(componentName),
});

writeFileToDir(targetDir, finalFileNames[templatePathIndex], output);
}
}

if (!fs.existsSync(targetDir)) {
mkdirp(targetDir, (err) => {
if (err) return console.error(err);
pipeTemplateToFile();
});
} else return pipeTemplateToFile();
}




type: 'confirm',
name: 'isFunction',
message: 'is this a function component?',
},
{
type: 'list',
name: 'styleSheetExtension',
message: 'whats stylesheet preprocessor are u using?',
choices: styleSheetTypes,
},
{
type: 'confirm',
name: 'hasTestFile',
message: 'Do you want to generate a test file?',
},
{
type: 'input',
name: 'finalPath',
message: 'what\'s the path to the folder? (leave empty for ./src/components)',
},
])
.then(answers => writeFile(
answers.componentName,
answers.finalPath || './src/components',
!!answers.isFunction,
answers.styleSheetExtension,
!!answers.hasTestFile,
));
7 changes: 7 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const stylesheetType = {
cssBased: 'cssBased',
styledComponents: 'styledComponents',
reactNative: 'reactNativeStyles',
};

module.exports = { stylesheetType };
24 changes: 24 additions & 0 deletions lib/stringHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
function convertCamelCaseToSpinal(string) {
if (!(typeof string === 'string')) return string;
let convertedString = '';
let character = '';

// LOOP OVER CHARACTERS
for (let i = 0; i < string.length; i++) {
character = string.charAt(i);

// NUMERIC CHARACTER: KEEP AS IS
if (!isNaN(parseInt(character, 10))) convertedString += String(character);

// ALPHA CHARACTER
else { // SEPARATE AT UPPERCASE WITH '-'
if (character === character.toUpperCase() && i > 0) convertedString += '-';

convertedString += character.toLowerCase();
}
}

return convertedString;
}

module.exports = { convertCamelCaseToSpinal };
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { Component } from 'react';
import './{{STYLESHEET_FILENAME}}.{{STYLESHEET_EXTENSION}}';
import{{EXPLICIT_STYLESHEET_IMPORT}} './{{STYLESHEET_FILENAME}}{{STYLESHEET_EXTENSION}}';
import { connect } from 'react-redux';

class {{COMPONENT_NAME}} extends Component<Props, State> {

render() {
const {} = this.props;
const {} = this.props;

return (
<>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { FC, useEffect } from 'react';
import './{{STYLESHEET_FILENAME}}.{{STYLESHEET_EXTENSION}}';
import { connect } from 'react-redux';
import{{EXPLICIT_STYLESHEET_IMPORT}} './{{STYLESHEET_FILENAME}}{{STYLESHEET_EXTENSION}}';

const {{COMPONENT_NAME}}: FC<Props> = (props: Props) => {
const {} = props;
Expand All @@ -21,12 +20,4 @@ const {{COMPONENT_NAME}}: FC<Props> = (props: Props) => {

type Props = {};

// const mapStateToProps = (state: any) => {
// return {
//
// };
// };

// export default connect(mapStateToProps)({{COMPONENT_NAME}});
export default {{COMPONENT_NAME}};

File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions lib/templates/stylesheets/reactNative.styleSheet.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { StyleSheet } from 'react-native';

export default StyleSheet.create({});
5 changes: 5 additions & 0 deletions lib/templates/stylesheets/styledComponents.styleSheet.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import styled from 'styled-components';

export default {
Container: styled.div``,
};
24 changes: 24 additions & 0 deletions lib/templates/testTemplate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import {{COMPONENT_NAME}} from './{{COMPONENT_NAME}}';
import { shallow } from 'enzyme';

const mockInputs = {};
const mockOutputs = {};

describe.skip('{{COMPONENT_NAME}}', () => {
describe('What are we testing?', () => {
it('should pass smoke test', async () => {
wrapper = shallow(<{{COMPONENT_NAME}} />);
expect(wrapper).not.toBeEmptyRender();
wrapper.unmount();
});
});

describe('Snapshot Test', () => {
it('should match', async () => {
const tree = renderer.create(<{{COMPONENT_NAME}} />);
expect(tree.toJSON()).toMatchSnapshot();
tree.unmount();
});
});
});
Loading

0 comments on commit fb4a26e

Please sign in to comment.