-
Notifications
You must be signed in to change notification settings - Fork 53
fix(jsx-email): fix email check + --use-preview-props #389
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next/v3
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ import { type IssueGroup, caniemail, groupIssues, sortIssues } from 'caniemail'; | |
| import chalk from 'chalk'; | ||
| import chalkTmpl from 'chalk-template'; | ||
| import stripAnsi from 'strip-ansi'; | ||
| import { type InferOutput as Infer, parse as assert, object } from 'valibot'; | ||
| import { type InferOutput as Infer, parse as assert, boolean, object, optional } from 'valibot'; | ||
|
|
||
| import { formatBytes, gmailByteLimit, gmailBytesSafe } from '../helpers.js'; | ||
|
|
||
|
|
@@ -13,7 +13,9 @@ import { type CommandFn } from './types.js'; | |
|
|
||
| const { error, log } = console; | ||
|
|
||
| const CheckOptionsStruct = object({}); | ||
| const CheckOptionsStruct = object({ | ||
| usePreviewProps: optional(boolean()) | ||
| }); | ||
|
|
||
| type CheckOptions = Infer<typeof CheckOptionsStruct>; | ||
|
|
||
|
|
@@ -32,17 +34,24 @@ export const help = chalkTmpl` | |
| Check jsx-email templates for client compatibility | ||
|
|
||
| {underline Usage} | ||
| $ email check <template file name> | ||
| $ email check <template file name> [...options] | ||
|
|
||
| {underline Options} | ||
| --use-preview-props | ||
| When set, use the \`previewProps\` exported by the template file (if present). | ||
|
|
||
| {underline Examples} | ||
| $ email check ./emails/Batman.tsx | ||
| $ email check ./emails/Batman.tsx --use-preview-props | ||
| `; | ||
|
|
||
| const formatNotes = (notes: string[], indent: string) => { | ||
| if (!notes.length) return ''; | ||
| const noteLines = (notes as string[]).join(`\n${'.'.repeat(indent.length)}**`); | ||
| console.log({ noteLines }); | ||
| return chalkTmpl`\n${indent}{cyan Notes}:\n${'.'.repeat(indent.length)}asshole\n`; | ||
|
|
||
| const noteIndent = `${indent} `; | ||
| const noteLines = notes.map((note) => `${noteIndent}${chalk.dim(note)}`).join('\n'); | ||
|
|
||
|
Comment on lines
48
to
+53
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Also, SuggestionGuard the const loc = position
? chalkTmpl`{dim ${position.start.line}:${position.start.column}}`
: chalk.dim('?:?');and use Reply with "@CharlieHelps yes please" if you’d like me to add a commit with this change. |
||
| return `\n${indent}${chalk.cyan('Notes')}:\n${noteLines}`; | ||
| }; | ||
|
|
||
| const formatIssue = (group: IssueGroup): string => { | ||
|
|
@@ -129,7 +138,11 @@ export const command: CommandFn = async (argv: CheckOptions, input) => { | |
| log(chalkTmpl`{blue Checking email template for Client Compatibility...}\n`); | ||
|
|
||
| const [file] = await buildTemplates({ | ||
| buildOptions: { showStats: false, writeToFile: false }, | ||
| buildOptions: { | ||
| showStats: false, | ||
| usePreviewProps: argv.usePreviewProps, | ||
| writeToFile: false | ||
| }, | ||
| targetPath: input[0] | ||
| }); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,35 @@ | ||
| import { loadConfig } from '../../../../src/config.js'; | ||
| import { createRequire } from 'node:module'; | ||
| import { dirname } from 'node:path'; | ||
|
|
||
| import loglevelnext from 'loglevelnext'; | ||
|
|
||
| const require = createRequire(import.meta.url); | ||
|
|
||
| describe('loadConfig → mjs', async () => { | ||
| beforeEach(() => { | ||
| vi.restoreAllMocks(); | ||
| vi.resetModules(); | ||
|
|
||
| process.env.FORCE_COLOR = '1'; | ||
|
|
||
| const dotLogPath = require.resolve('@dot/log'); | ||
| const chalkPath = require.resolve('chalk', { paths: [dirname(dotLogPath)] }); | ||
|
|
||
| delete require.cache[dotLogPath]; | ||
| delete require.cache[chalkPath]; | ||
| require(chalkPath).level = 1; | ||
|
|
||
| delete (globalThis as any)[Symbol.for('jsx-email/global/config')]; | ||
| delete process.env.DOT_LOG_LEVEL; | ||
|
|
||
| for (const key of Object.keys(loglevelnext.loggers)) { | ||
| if (key === 'default') continue; | ||
| delete loglevelnext.loggers[key]; | ||
| } | ||
| }); | ||
|
Comment on lines
+9
to
+29
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There’s substantial repeated SuggestionExtract the repeated stabilization logic into a shared helper used by all config tests. Example: // test/helpers/reset-config-test-env.ts
export function resetConfigTestEnv() {
vi.restoreAllMocks();
vi.resetModules();
process.env.FORCE_COLOR = '1';
// …chalk/@dot/log cache reset…
// …global config + loglevelnext loggers reset…
}Then in each test file: import { resetConfigTestEnv } from '../helpers/reset-config-test-env';
beforeEach(resetConfigTestEnv);Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion. |
||
|
|
||
| test('loadConfig', async () => { | ||
| const { loadConfig } = await import('../../../../src/config.js'); | ||
| const config = await loadConfig(__dirname); | ||
| expect(config).toMatchSnapshot(); | ||
| }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import { resolve } from 'node:path'; | ||
|
|
||
| import { execa } from 'execa'; | ||
| import strip from 'strip-ansi'; | ||
| import { describe, expect, test } from 'vitest'; | ||
|
|
||
| process.chdir(__dirname); | ||
|
|
||
| describe('cli', async () => { | ||
| test('email check supports --use-preview-props', async () => { | ||
| const templatePath = resolve(__dirname, './fixtures/check-preview-props.tsx'); | ||
|
|
||
| await expect( | ||
| execa({ cwd: __dirname, shell: true })`email check ${templatePath}` | ||
| ).rejects.toMatchObject({ | ||
| exitCode: 1 | ||
| }); | ||
|
|
||
| const { stdout } = await execa({ | ||
| cwd: __dirname, | ||
| shell: true | ||
| })`email check ${templatePath} --use-preview-props`; | ||
|
Comment on lines
+13
to
+22
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The new test uses SuggestionAvoid await expect(execa('email', ['check', templatePath], { cwd: __dirname }))
.rejects.toMatchObject({ exitCode: 1 });
const { stdout } = await execa('email', ['check', templatePath, '--use-preview-props'], {
cwd: __dirname,
});Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion.
Comment on lines
+7
to
+22
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This CLI test relies on It also depends on SuggestionPrefer running the CLI without a shell and avoid global const cwd = __dirname;
await expect(execa('email', ['check', templatePath], { cwd }))
.rejects.toMatchObject({ exitCode: 1 });
const { stdout } = await execa('email', ['check', templatePath, '--use-preview-props'], { cwd });and remove Reply with "@CharlieHelps yes please" if you’d like me to add a commit with this change. |
||
|
|
||
| const plain = strip(stdout); | ||
|
|
||
| expect(plain).toContain('Checking email template for Client Compatibility'); | ||
| expect(plain).toContain('Check Complete'); | ||
| expect(plain).not.toContain('noteLines'); | ||
| expect(plain).not.toContain('asshole'); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| interface PreviewProps { | ||
| label: string; | ||
| } | ||
|
|
||
| export const previewProps: PreviewProps = { | ||
| label: 'Preview props loaded' | ||
| }; | ||
|
|
||
| export const Template = ({ label }: PreviewProps) => <div>{label.toUpperCase()}</div>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
usePreviewPropsis defined asoptional(boolean()), which meansargv.usePreviewPropscan beundefined. Passingundefinedthrough tobuildTemplates()can create ambiguous behavior ifbuildTemplatesdistinguishes betweenfalseandundefined(e.g., defaulting totruewhen missing, or changing cache keys). Since this is a CLI flag, it’s usually better to normalize to a concrete boolean (falseby default) at the command boundary.Suggestion
Normalize the flag to a strict boolean so downstream behavior is deterministic.
If
valibotdoesn’t support defaults in your version, do it at the callsite:Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion.