-
-
Notifications
You must be signed in to change notification settings - Fork 389
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7f5ef6c
commit f309c3a
Showing
2 changed files
with
59 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,71 +1,92 @@ | ||
#!/usr/bin/env node | ||
|
||
/** | ||
Usage | ||
$ new-component ComponentName | ||
* Usage | ||
* $ yarn new-component ComponentName | ||
*/ | ||
|
||
import { mkdirSync, readFileSync, writeFileSync } from 'fs' | ||
import * as Mustache from 'mustache' | ||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs' | ||
import Mustache from 'mustache' | ||
import { resolve } from 'path' | ||
|
||
const basePath: string = resolve(__dirname, '../src') as string | ||
|
||
const [inputName] = process.argv.slice(2) | ||
|
||
if (!inputName) { | ||
console.log(`⚠️ Component name is required. Example usage: | ||
$ yarn new-component ComponentName`) | ||
console.error( | ||
'⚠️ Component name is required. Example usage:\n$ yarn new-component ComponentName', | ||
) | ||
process.exit(1) | ||
} | ||
|
||
const componentName = toPascalCase(inputName) | ||
const componentPath = resolve(basePath, componentName) | ||
|
||
// Ensure the component does not already exist | ||
if (existsSync(componentPath)) { | ||
console.error(`Error: Component ${componentName} already exists.`) | ||
process.exit(1) | ||
} | ||
|
||
try { | ||
mkdirSync(resolve(__dirname, `../src/${componentName}`)) | ||
} catch (e) { | ||
console.log(`${componentName} already exists`) | ||
mkdirSync(componentPath) | ||
console.log(`Created a new component: ${componentName}`) | ||
} catch (error: any) { | ||
console.error( | ||
`Failed to create directory for ${componentName}: ${error.message}`, | ||
) | ||
process.exit(1) | ||
} | ||
|
||
console.log(`Created a new component: ${componentName}`) | ||
const templates = [ | ||
'{componentName}.tsx.mst', | ||
'{componentName}.stories.tsx.mst', | ||
'{componentName}.test.tsx.mst', | ||
] | ||
|
||
templates.forEach((templateName) => | ||
createComponentFileFromTemplate(templateName, componentPath, componentName), | ||
) | ||
|
||
function createComponentFileFromTemplate(templateName: string) { | ||
const componentPath = resolve(__dirname, './templates/' + templateName) | ||
// Transform to include `componentName` | ||
const fileTemplate = readFileSync(componentPath, { | ||
encoding: 'utf8', | ||
}) | ||
// Append export to index.ts | ||
appendToIndexFile(basePath, componentName) | ||
|
||
// Write files to directory | ||
const newFilePath = resolve( | ||
__dirname, | ||
`../src/${componentName}/`, | ||
templateName.replace('{componentName}', componentName).replace('.mst', ''), | ||
) | ||
console.log(`Writing:`, newFilePath) | ||
function createComponentFileFromTemplate( | ||
templateName: string, | ||
componentPath: string, | ||
componentName: string, | ||
) { | ||
const templateFilePath = resolve(__dirname, './templates', templateName) | ||
if (!existsSync(templateFilePath)) { | ||
console.error(`Template file ${templateFilePath} does not exist.`) | ||
return | ||
} | ||
|
||
const fileTemplate = readFileSync(templateFilePath, { encoding: 'utf8' }) | ||
const newFileName = templateName | ||
.replace('{componentName}', componentName) | ||
.replace('.mst', '') | ||
const newFilePath = resolve(componentPath, newFileName) | ||
|
||
console.log(`Writing: ${newFilePath}`) | ||
writeFileSync( | ||
newFilePath, | ||
Mustache.render(fileTemplate, { ComponentName: componentName }), | ||
) | ||
} | ||
|
||
;[ | ||
'{componentName}.tsx.mst', | ||
'{componentName}.stories.tsx.mst', | ||
'{componentName}.test.tsx.mst', | ||
].map(createComponentFileFromTemplate) | ||
|
||
writeFileSync( | ||
resolve(__dirname, '../src/index.ts'), | ||
`export { ${componentName} } from './${componentName}/${componentName}'\n`, | ||
{ | ||
encoding: 'utf-8', | ||
flag: 'a+', | ||
}, | ||
) | ||
function appendToIndexFile(basePath: string, componentName: string) { | ||
const indexPath = resolve(basePath, 'index.ts') | ||
const exportLine = `export { ${componentName} } from './${componentName}/${componentName}'\n` | ||
|
||
console.log(`Appending to ${indexPath}`) | ||
writeFileSync(indexPath, exportLine, { encoding: 'utf8', flag: 'a+' }) | ||
} | ||
|
||
/** from: https://quickref.me/convert-a-string-to-pascal-case */ | ||
function toPascalCase(str: string) { | ||
return (str.match(/[a-zA-Z0-9]+/g) || []) | ||
.map((w) => `${w.charAt(0).toUpperCase()}${w.slice(1)}`) | ||
.map((word: string) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`) | ||
.join('') | ||
} |