Skip to content

Commit

Permalink
feat(create-jsx-email): choose JS or TS (#160)
Browse files Browse the repository at this point in the history
  • Loading branch information
shellscape committed Feb 5, 2024
1 parent 1867e83 commit 22f9a4e
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 35 deletions.
7 changes: 2 additions & 5 deletions packages/create-jsx-email/generators/package.json.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@
"dev": "email preview ./templates"
},
"dependencies": {
"jsx-email": "^1.0.1",
"superstruct": "^1.0.3"
"jsx-email": "^1.0.1"
},
"devDependencies": {
"@types/react": "^18.2.0",
"react": "^18.2.0",
"typescript": "^5.2.2"
"react": "^18.2.0"{{ typeDep }}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,7 @@ import {
Text
} from 'jsx-email';

/**
* Note: Superstruct is a fantastic validation package. It's smaller and faster than alternatives
* and uses a delightful API without chaining. docs.superstructjs.org
*
* To install run `pnpm add superstruct`.
*/
import { defaulted, object, string, type Infer } from 'superstruct';
import React from 'react';

export const TemplateName = '{{ name }}';

export const TemplateStruct = object({
email: defaulted(string(), 'batman@example.com'),
name: defaulted(string(), 'Bruce Wayne')
});

export type TemplateProps = Infer<typeof TemplateStruct>;
{{{ typeProps }}}

const main = {
backgroundColor: '#f6f9fc',
Expand Down Expand Up @@ -69,18 +53,23 @@ const button = {
display: 'block',
fontSize: '16px',
fontWeight: 'bold',
padding: '10px',
textAlign: 'center' as const,
textDecoration: 'none',
width: '100%'
width: '100%',
padding: '10px'
};

export const Template = ({ email, name }: TemplateProps) => (
export const defaultProps = {
email: 'batman@example.com',
name: 'Bruce Wayne'
} as TemplateProps;

export const templateName = '{{name}}';

export const Template = ({ email, name }{{ propsType }}) => (
<Html>
<Head />
<Preview>
This is our email preview text for {name} &lt;{email}&gt;
</Preview>
<Preview>This is our email preview text for {name} &lt;{email}&gt;</Preview>
<Body style={main}>
<Container style={container}>
<Section style={box}>
Expand All @@ -94,6 +83,7 @@ export const Template = ({ email, name }: TemplateProps) => (
<Link style={anchor} href="mailto:{email}">
link
</Link>
.
</Text>
</Section>
</Container>
Expand Down
2 changes: 2 additions & 0 deletions packages/create-jsx-email/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"url": "https://github.com/shellscape/jsx-email.git",
"directory": "packages/create-jsx-email"
},
"main": "dist/src/index.js",
"bin": {
"create-jsx-email": "./dist/src/index.js"
},
Expand All @@ -37,6 +38,7 @@
"@types/fs-extra": "^11.0.2",
"@types/prompts": "^2.4.8"
},
"types": "dist/src/index.d.ts",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/shellscape"
Expand Down
60 changes: 53 additions & 7 deletions packages/create-jsx-email/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import prompts from 'prompts';

import pkg from '../package.json';

interface CreateEmailArgs {
jsx: boolean;
name: string;
outputPath: string;
}

const cancelled = () => {
throw new Error(chalk`{red ✖} Operation cancelled`);
};
Expand All @@ -35,13 +41,39 @@ const isEmpty = (path: string) => {
};
const { log } = console;
const normalizePath = (filename: string) => filename.split(win32.sep).join(posix.sep);
const typeDep = ',\n"@types/react": "^18.2.0",\n"typescript": "^5.2.2"';
const typeProps = `\nexport type TemplateProps = {
email: string;
name: string;
}`;

export const createEmail = async ({ jsx, name, outputPath }: CreateEmailArgs) => {
const data = {
name,
propsType: jsx ? '' : ': TemplateProps',
typeProps: jsx ? '' : typeProps
};
const templatePath = resolve(__dirname, '../generators/templates/email.mustache');
const template = await readFile(templatePath, 'utf8');
const contents = mustache.render(template, data);
const fileName = basename(templatePath)
.replace('_', '')
.replace('.mustache', jsx ? '.jsx' : '.tsx');
const outPath = join(outputPath, fileName);

log('Creating a new template at', outPath);

await writeFile(outPath, contents, 'utf8');

return outPath;
};

const run = async () => {
log(intro);

const argTargetDir = formatTargetDir(process.argv[2]);
let targetPath = argTargetDir || defaultTargetDir;
let result: prompts.Answers<'projectName' | 'overwrite'>;
let result: prompts.Answers<'projectName' | 'projectType' | 'overwrite'>;

try {
result = await prompts(
Expand All @@ -55,6 +87,15 @@ const run = async () => {
},
type: argTargetDir ? null : 'text'
},
{
choices: [
{ title: 'TypeScript', value: 'TypeScript' },
{ title: 'JavaScript', value: 'JavaScript' }
],
message: 'TypeScript or JavaScript:',
name: 'projectType',
type: 'select'
},
{
message: () =>
targetPath === '.'
Expand All @@ -78,20 +119,23 @@ const run = async () => {
return;
}

const { overwrite, projectName } = result;
const { overwrite, projectName, projectType } = result;
const root = join(process.cwd(), targetPath);
const generatorsPath = resolve(__dirname, '../generators');
const jsx = projectType === 'JavaScript';
const templates = await globby([normalizePath(join(generatorsPath, '/*.*'))]);
const outputPath = join(root, 'templates');
const templateData = { name: projectName, typeDep: jsx ? '' : typeDep };

log(chalk`\n{blue Creating Project} at: {dim ${root}}`);

const generatorsPath = resolve(__dirname, '../generators');
const templates = await globby([normalizePath(join(generatorsPath, '/**/*.*'))]);
const templateData = { name: projectName };

if (overwrite && existsSync(root)) clearDirectory(root);

await mkdir(join(root, 'templates'), { recursive: true });
await mkdir(outputPath, { recursive: true });

for (const path of templates) {
// eslint-disable-next-line no-continue
if (path.endsWith('_tsconfig.json') && jsx) continue;
const template = await readFile(path, 'utf8');
const contents = mustache.render(template, templateData);
const basePath = dirname(path);
Expand All @@ -101,6 +145,8 @@ const run = async () => {
await writeFile(outPath, contents, 'utf8');
}

await createEmail({ jsx, name: projectName, outputPath });

const packageManager = await detect();
const install =
packageManager === 'yarn'
Expand Down

0 comments on commit 22f9a4e

Please sign in to comment.