From 5a25d0b8475622eccff858400f94a18b97671ea8 Mon Sep 17 00:00:00 2001 From: Huyen Nguyen <25715018+huyenltnguyen@users.noreply.github.com> Date: Tue, 8 Feb 2022 15:38:00 +0700 Subject: [PATCH] feat(tools): add component generation script to ui-components (#44951) * feat(tools): add component generation script to ui-components * Yes, Oliver. I do want to use TS for these --- tools/ui-components/package.json | 3 +- tools/ui-components/tsconfig.json | 6 ++ .../utils/gen-component-script.ts | 70 +++++++++++++++++++ .../utils/gen-component-template.ts | 59 ++++++++++++++++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 tools/ui-components/utils/gen-component-script.ts create mode 100644 tools/ui-components/utils/gen-component-template.ts diff --git a/tools/ui-components/package.json b/tools/ui-components/package.json index 4dfd803784..3bfbd6f4b8 100644 --- a/tools/ui-components/package.json +++ b/tools/ui-components/package.json @@ -60,6 +60,7 @@ "build-storybook": "build-storybook", "build": "cross-env NODE_ENV=production rollup -c", "dev": "cross-env NODE_ENV=development rollup -c -w", - "clean": "rimraf dist/*" + "clean": "rimraf dist/*", + "gen-component": "ts-node ./utils/gen-component-script" } } diff --git a/tools/ui-components/tsconfig.json b/tools/ui-components/tsconfig.json index 276e8af6ca..815279307b 100644 --- a/tools/ui-components/tsconfig.json +++ b/tools/ui-components/tsconfig.json @@ -10,5 +10,11 @@ "strict": true, "noEmit": true, "typeRoots": ["../../node_modules/@types"] + }, + "ts-node": { + "compilerOptions": { + "module": "commonjs" + }, + "transpileOnly": true } } diff --git a/tools/ui-components/utils/gen-component-script.ts b/tools/ui-components/utils/gen-component-script.ts new file mode 100644 index 0000000000..18250a1947 --- /dev/null +++ b/tools/ui-components/utils/gen-component-script.ts @@ -0,0 +1,70 @@ +import fs from 'fs'; +import path from 'path'; +import { component, story, test, barrel, type } from './gen-component-template'; + +// Grab component name from terminal argument +const [name] = process.argv.slice(2); +if (!name) { + throw new Error('You must include a component name.'); +} + +if (!name.match(/^[A-Z]/)) { + throw new Error('Component name must be in PascalCase.'); +} + +const toKebabCase = (pascalCasedName: string) => + pascalCasedName + .replace(/([A-Z][a-z])/g, '-$1') // Add a hyphen before each capital letter + .toLowerCase() + .substring(1); // Return the string but exclude the hyphen at the beginning + +const kebabCasedName = toKebabCase(name); + +const dir = path.join(__dirname, `../src/${kebabCasedName}`); + +// Throw an error if the component's folder already exists +if (fs.existsSync(dir)) { + throw new Error('A component with that name already exists.'); +} + +// Create the folder +fs.mkdirSync(dir); + +const writeFileErrorHandler = (err: Error | null) => { + if (err) { + throw err; + } +}; + +// Create the component file - my-component.tsx +fs.writeFile( + `${dir}/${kebabCasedName}.tsx`, + component(name), + writeFileErrorHandler +); + +// Create the type file - types.ts +fs.writeFile(`${dir}/types.ts`, type(name), writeFileErrorHandler); + +// Create the test file - my-component.test.tsx +fs.writeFile( + `${dir}/${kebabCasedName}.test.tsx`, + test(name), + writeFileErrorHandler +); + +// Create the Storybook file - my-component.stories.tsx +fs.writeFile( + `${dir}/${kebabCasedName}.stories.tsx`, + story(name), + writeFileErrorHandler +); + +// Create the barrel file - index.ts +fs.writeFile( + `${dir}/index.ts`, + barrel(name, kebabCasedName), + writeFileErrorHandler +); + +console.log(`The ${name} component has been created successfully! 🎉`); diff --git a/tools/ui-components/utils/gen-component-template.ts b/tools/ui-components/utils/gen-component-template.ts new file mode 100644 index 0000000000..70f268903e --- /dev/null +++ b/tools/ui-components/utils/gen-component-template.ts @@ -0,0 +1,59 @@ +// component.tsx +export const component = (name: string) => ` +import React from 'react'; + +import { ${name}Props } from './types'; + +export const ${name} = ({}: ${name}Props) => { + return