@emailens/cli 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,6 +6,90 @@ import {
6
6
  // src/index.ts
7
7
  import { defineCommand as defineCommand8, runMain } from "citty";
8
8
 
9
+ // src/meta.ts
10
+ import { EMAIL_CLIENTS } from "@emailens/engine";
11
+
12
+ // package.json
13
+ var package_default = {
14
+ name: "@emailens/cli",
15
+ version: "0.3.5",
16
+ description: "CLI tool for email compatibility analysis \u2014 analyze, preview, and export email rendering across 15 email clients.",
17
+ type: "module",
18
+ bin: {
19
+ emailens: "./dist/index.js"
20
+ },
21
+ exports: {
22
+ ".": {
23
+ types: "./dist/index.d.ts",
24
+ import: "./dist/index.js"
25
+ }
26
+ },
27
+ main: "./dist/index.js",
28
+ types: "./dist/index.d.ts",
29
+ files: [
30
+ "dist",
31
+ "LICENSE"
32
+ ],
33
+ scripts: {
34
+ build: "tsup",
35
+ dev: "tsup --watch",
36
+ start: "bun run dist/index.js",
37
+ typecheck: "tsc --noEmit",
38
+ test: "bun test",
39
+ prepublishOnly: "bun run build"
40
+ },
41
+ dependencies: {
42
+ "@emailens/engine": "^0.9.3",
43
+ citty: "^0.1.6",
44
+ "cli-table3": "^0.6.5",
45
+ ora: "^8.2.0",
46
+ picocolors: "^1.1.1"
47
+ },
48
+ optionalDependencies: {
49
+ "@anthropic-ai/sdk": "^0.52.0",
50
+ "playwright-core": "^1.52.0"
51
+ },
52
+ devDependencies: {
53
+ "@types/bun": "^1.3.14",
54
+ "@types/mjml": "^4.7.4",
55
+ "@types/node": "^25.3.0",
56
+ "bun-types": "^1.3.9",
57
+ tsup: "^8.4.0",
58
+ typescript: "^5.9.3"
59
+ },
60
+ keywords: [
61
+ "email",
62
+ "html-email",
63
+ "css",
64
+ "compatibility",
65
+ "cli",
66
+ "gmail",
67
+ "outlook",
68
+ "apple-mail",
69
+ "email-testing",
70
+ "dark-mode"
71
+ ],
72
+ license: "MIT",
73
+ repository: {
74
+ type: "git",
75
+ url: "git+https://github.com/emailens/cli.git"
76
+ },
77
+ engines: {
78
+ node: ">=18"
79
+ },
80
+ homepage: "https://github.com/emailens/cli#readme",
81
+ bugs: {
82
+ url: "https://github.com/emailens/cli/issues"
83
+ }
84
+ };
85
+
86
+ // src/meta.ts
87
+ var meta = {
88
+ name: "emailens",
89
+ version: package_default.version,
90
+ description: `Email compatibility analysis CLI \u2014 preview how HTML emails render across ${EMAIL_CLIENTS.length} email clients.`
91
+ };
92
+
9
93
  // src/commands/analyze.ts
10
94
  import { defineCommand } from "citty";
11
95
  import ora from "ora";
@@ -18,7 +102,7 @@ import {
18
102
 
19
103
  // src/utils.ts
20
104
  import { readFileSync } from "fs";
21
- import { EMAIL_CLIENTS } from "@emailens/engine";
105
+ import { EMAIL_CLIENTS as EMAIL_CLIENTS2 } from "@emailens/engine";
22
106
  import { detectFormat } from "@emailens/engine/compile";
23
107
  var VALID_FORMATS = /* @__PURE__ */ new Set(["html", "jsx", "mjml", "maizzle"]);
24
108
  async function readInput(pathOrStdin) {
@@ -52,9 +136,9 @@ async function readInput(pathOrStdin) {
52
136
  }
53
137
  }
54
138
  function resolveClients(ids) {
55
- const validIds = new Set(EMAIL_CLIENTS.map((c) => c.id));
139
+ const validIds = new Set(EMAIL_CLIENTS2.map((c) => c.id));
56
140
  if (!ids) {
57
- return EMAIL_CLIENTS.map((c) => c.id);
141
+ return EMAIL_CLIENTS2.map((c) => c.id);
58
142
  }
59
143
  const requested = ids.split(",").map((s) => s.trim()).filter(Boolean);
60
144
  const invalid = requested.filter((id) => !validIds.has(id));
@@ -92,7 +176,7 @@ import { compile } from "@emailens/engine/compile";
92
176
  import pc from "picocolors";
93
177
  import Table from "cli-table3";
94
178
  import {
95
- EMAIL_CLIENTS as EMAIL_CLIENTS2
179
+ EMAIL_CLIENTS as EMAIL_CLIENTS3
96
180
  } from "@emailens/engine";
97
181
  function colorScore(score) {
98
182
  const str = String(score);
@@ -131,7 +215,7 @@ function printScoreTable(scores, warnings, options) {
131
215
  console.log(pc.bold(" Emailens \u2014 Compatibility Report"));
132
216
  console.log();
133
217
  }
134
- const clientMap = new Map(EMAIL_CLIENTS2.map((c) => [c.id, c.name]));
218
+ const clientMap = new Map(EMAIL_CLIENTS3.map((c) => [c.id, c.name]));
135
219
  const warningsByClient = /* @__PURE__ */ new Map();
136
220
  for (const w of warnings) {
137
221
  const existing = warningsByClient.get(w.client) ?? [];
@@ -172,7 +256,7 @@ function printWarnings(warnings, options) {
172
256
  existing.push(w);
173
257
  byClient.set(w.client, existing);
174
258
  }
175
- const clientMap = new Map(EMAIL_CLIENTS2.map((c) => [c.id, c.name]));
259
+ const clientMap = new Map(EMAIL_CLIENTS3.map((c) => [c.id, c.name]));
176
260
  for (const [clientId, clientWarnings] of byClient) {
177
261
  const clientName = clientMap.get(clientId) ?? clientId;
178
262
  const worst = worstSeverity(clientWarnings);
@@ -431,7 +515,7 @@ var preview_default = defineCommand2({
431
515
  import { defineCommand as defineCommand3 } from "citty";
432
516
  import pc2 from "picocolors";
433
517
  import Table2 from "cli-table3";
434
- import { EMAIL_CLIENTS as EMAIL_CLIENTS3 } from "@emailens/engine";
518
+ import { EMAIL_CLIENTS as EMAIL_CLIENTS4 } from "@emailens/engine";
435
519
  var clients_default = defineCommand3({
436
520
  meta: {
437
521
  name: "clients",
@@ -445,7 +529,7 @@ var clients_default = defineCommand3({
445
529
  },
446
530
  run({ args }) {
447
531
  if (args.json) {
448
- const data = EMAIL_CLIENTS3.map((c) => ({
532
+ const data = EMAIL_CLIENTS4.map((c) => ({
449
533
  id: c.id,
450
534
  name: c.name,
451
535
  category: c.category,
@@ -468,7 +552,7 @@ var clients_default = defineCommand3({
468
552
  ],
469
553
  style: { head: [], border: [] }
470
554
  });
471
- for (const client of EMAIL_CLIENTS3) {
555
+ for (const client of EMAIL_CLIENTS4) {
472
556
  table.push([
473
557
  client.id,
474
558
  client.name,
@@ -479,7 +563,7 @@ var clients_default = defineCommand3({
479
563
  }
480
564
  console.log(table.toString());
481
565
  console.log();
482
- console.log(pc2.dim(` ${EMAIL_CLIENTS3.length} clients supported`));
566
+ console.log(pc2.dim(` ${EMAIL_CLIENTS4.length} clients supported`));
483
567
  console.log();
484
568
  }
485
569
  });
@@ -500,9 +584,9 @@ import {
500
584
  import { compile as compile3 } from "@emailens/engine/compile";
501
585
 
502
586
  // src/output/html-report.ts
503
- import { EMAIL_CLIENTS as EMAIL_CLIENTS4 } from "@emailens/engine";
587
+ import { EMAIL_CLIENTS as EMAIL_CLIENTS5 } from "@emailens/engine";
504
588
  function generateHtmlReport(opts) {
505
- const clientMap = new Map(EMAIL_CLIENTS4.map((c) => [c.id, c]));
589
+ const clientMap = new Map(EMAIL_CLIENTS5.map((c) => [c.id, c]));
506
590
  const scoreValues = Object.values(opts.scores);
507
591
  const overallScore = scoreValues.length > 0 ? Math.round(scoreValues.reduce((a, b) => a + b.score, 0) / scoreValues.length) : 0;
508
592
  const scoreColor = (s) => s >= 90 ? "#22c55e" : s >= 70 ? "#eab308" : "#ef4444";
@@ -1298,11 +1382,7 @@ function flattenToLintIssues(report, skip) {
1298
1382
 
1299
1383
  // src/index.ts
1300
1384
  var main = defineCommand8({
1301
- meta: {
1302
- name: "emailens",
1303
- version: "0.4.0",
1304
- description: "Email compatibility analysis CLI \u2014 preview how HTML emails render across 12 email clients."
1305
- },
1385
+ meta,
1306
1386
  subCommands: {
1307
1387
  analyze: analyze_default,
1308
1388
  preview: preview_default,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/analyze.ts","../src/utils.ts","../src/output/terminal.ts","../src/output/json.ts","../src/commands/preview.ts","../src/commands/clients.ts","../src/commands/export.ts","../src/output/html-report.ts","../src/commands/fix.ts","../src/commands/audit.ts","../src/commands/lint.ts"],"sourcesContent":["import { defineCommand, runMain } from \"citty\";\r\nimport analyze from \"./commands/analyze.js\";\r\nimport preview from \"./commands/preview.js\";\r\nimport clients from \"./commands/clients.js\";\r\nimport exportCmd from \"./commands/export.js\";\r\nimport fix from \"./commands/fix.js\";\r\nimport audit from \"./commands/audit.js\";\r\nimport lint from \"./commands/lint.js\";\r\n\r\nconst main = defineCommand({\r\n meta: {\r\n name: \"emailens\",\r\n version: \"0.4.0\",\r\n description: \"Email compatibility analysis CLI — preview how HTML emails render across 12 email clients.\",\r\n },\r\n subCommands: {\r\n analyze,\r\n preview,\r\n clients,\r\n export: exportCmd,\r\n fix,\r\n audit,\r\n lint,\r\n },\r\n});\r\n\r\nrunMain(main);\r\n","import { defineCommand } from \"citty\";\r\nimport ora from \"ora\";\r\nimport {\r\n analyzeEmail,\r\n generateCompatibilityScore,\r\n warningsForClient,\r\n CompileError,\r\n} from \"@emailens/engine\";\r\nimport { readInput, resolveClients, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\nimport { printScoreTable, printWarnings } from \"../output/terminal.js\";\r\nimport { printJson } from \"../output/json.js\";\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"analyze\",\r\n description: \"Analyze email CSS compatibility across clients\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or - for stdin\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n clients: {\r\n type: \"string\",\r\n alias: \"c\",\r\n description: \"Comma-separated client IDs to filter\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON\",\r\n },\r\n quiet: {\r\n type: \"boolean\",\r\n alias: \"q\",\r\n description: \"Suppress spinners and decorations\",\r\n },\r\n },\r\n async run({ args }) {\r\n // --json implies quiet spinners\r\n const spinner = (args.quiet || args.json) ? null : ora();\r\n\r\n try {\r\n // Resolve format early so we fail fast on invalid --format\r\n const format = resolveFormat(args.format, args.input);\r\n\r\n // Read input\r\n spinner?.start(\"Reading input...\");\r\n const source = await readInput(args.input);\r\n spinner?.succeed(\"Input read\");\r\n\r\n // Compile (passthrough for html, auto-detects from extension)\r\n const html = await compile(source, format, args.input !== \"-\" ? args.input : undefined);\r\n\r\n // Resolve clients\r\n const clientIds = resolveClients(args.clients);\r\n\r\n // Analyze\r\n spinner?.start(\"Analyzing compatibility...\");\r\n const framework = toFramework(format);\r\n const warnings = analyzeEmail(html, framework);\r\n const allScores = generateCompatibilityScore(warnings);\r\n\r\n // Filter scores to requested clients\r\n const clientSet = new Set(clientIds);\r\n const scores: typeof allScores = {};\r\n for (const [id, data] of Object.entries(allScores)) {\r\n if (clientSet.has(id)) {\r\n scores[id] = data;\r\n }\r\n }\r\n\r\n // Filter warnings to requested clients\r\n const filteredWarnings = clientIds.flatMap(id => warningsForClient(warnings, id));\r\n\r\n spinner?.succeed(\"Analysis complete\");\r\n\r\n // Output\r\n if (args.json) {\r\n printJson({ scores, warnings: filteredWarnings });\r\n } else {\r\n printScoreTable(scores, filteredWarnings, { quiet: args.quiet });\r\n printWarnings(filteredWarnings, { quiet: args.quiet });\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);\r\n } else {\r\n spinner?.fail((err as Error).message);\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n","import { readFileSync } from \"node:fs\";\r\nimport { EMAIL_CLIENTS, type Framework, type InputFormat } from \"@emailens/engine\";\r\nimport { detectFormat } from \"@emailens/engine/compile\";\r\n\r\nconst VALID_FORMATS = new Set([\"html\", \"jsx\", \"mjml\", \"maizzle\"]);\r\n\r\n/**\r\n * Read HTML input from a file path or stdin (`-`).\r\n * Always returns a Promise for consistent caller ergonomics.\r\n */\r\nexport async function readInput(pathOrStdin: string): Promise<string> {\r\n if (pathOrStdin === \"-\") {\r\n // Try /dev/stdin first (works on Unix and Git Bash on Windows)\r\n try {\r\n return readFileSync(\"/dev/stdin\", \"utf-8\");\r\n } catch {\r\n // Fall through to async approach\r\n }\r\n\r\n // Async stdin reading for Windows compatibility\r\n return new Promise<string>((resolve, reject) => {\r\n const chunks: Buffer[] = [];\r\n process.stdin.resume();\r\n process.stdin.on(\"data\", (chunk) => chunks.push(Buffer.from(chunk)));\r\n process.stdin.on(\"end\", () => {\r\n const data = Buffer.concat(chunks).toString(\"utf-8\");\r\n if (!data.trim()) {\r\n reject(new Error(\"No input received from stdin. Pipe HTML or provide a file path.\"));\r\n } else {\r\n resolve(data);\r\n }\r\n });\r\n process.stdin.on(\"error\", () => {\r\n reject(new Error(\"No input received from stdin. Pipe HTML or provide a file path.\"));\r\n });\r\n });\r\n }\r\n\r\n try {\r\n return readFileSync(pathOrStdin, \"utf-8\");\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n throw new Error(`Failed to read file \"${pathOrStdin}\": ${message}`);\r\n }\r\n}\r\n\r\n/**\r\n * Validate and resolve client IDs. Returns all clients if none specified.\r\n */\r\nexport function resolveClients(ids?: string): string[] {\r\n const validIds = new Set(EMAIL_CLIENTS.map((c) => c.id));\r\n\r\n if (!ids) {\r\n return EMAIL_CLIENTS.map((c) => c.id);\r\n }\r\n\r\n const requested = ids.split(\",\").map((s) => s.trim()).filter(Boolean);\r\n const invalid = requested.filter((id) => !validIds.has(id));\r\n\r\n if (invalid.length > 0) {\r\n throw new Error(\r\n `Unknown client ID(s): ${invalid.join(\", \")}.\\n` +\r\n `Valid IDs: ${Array.from(validIds).join(\", \")}`\r\n );\r\n }\r\n\r\n return requested;\r\n}\r\n\r\n/**\r\n * Resolve the input format from explicit flag, file extension, or default.\r\n * Validates the --format flag and errors on unknown values.\r\n * Auto-detects from file extension when no flag is given.\r\n */\r\nexport function resolveFormat(formatFlag?: string, filePath?: string): InputFormat {\r\n if (formatFlag) {\r\n if (!VALID_FORMATS.has(formatFlag)) {\r\n throw new Error(\r\n `Unknown format \"${formatFlag}\". Valid formats: ${Array.from(VALID_FORMATS).join(\", \")}`\r\n );\r\n }\r\n return formatFlag as InputFormat;\r\n }\r\n\r\n // Auto-detect from file extension\r\n if (filePath && filePath !== \"-\") {\r\n return detectFormat(filePath);\r\n }\r\n\r\n return \"html\";\r\n}\r\n\r\n/**\r\n * Convert a format string to the engine's Framework type.\r\n */\r\nexport function toFramework(format: InputFormat): Framework | undefined {\r\n if (format === \"jsx\" || format === \"mjml\" || format === \"maizzle\") return format;\r\n return undefined;\r\n}\r\n","import pc from \"picocolors\";\r\nimport Table from \"cli-table3\";\r\nimport {\r\n EMAIL_CLIENTS,\r\n type CSSWarning,\r\n} from \"@emailens/engine\";\r\n\r\n/**\r\n * Color-code a score value: green >=90, yellow >=70, red <70.\r\n */\r\nfunction colorScore(score: number): string {\r\n const str = String(score);\r\n if (score >= 90) return pc.green(str);\r\n if (score >= 70) return pc.yellow(str);\r\n return pc.red(str);\r\n}\r\n\r\n/**\r\n * Get severity icon.\r\n */\r\nfunction severityIcon(severity: CSSWarning[\"severity\"]): string {\r\n switch (severity) {\r\n case \"error\": return pc.red(\"✗\");\r\n case \"warning\": return pc.yellow(\"⚠\");\r\n case \"info\": return pc.blue(\"ℹ\");\r\n }\r\n}\r\n\r\n/**\r\n * Get the worst severity from a list of warnings.\r\n */\r\nfunction worstSeverity(warnings: CSSWarning[]): CSSWarning[\"severity\"] {\r\n if (warnings.some((w) => w.severity === \"error\")) return \"error\";\r\n if (warnings.some((w) => w.severity === \"warning\")) return \"warning\";\r\n return \"info\";\r\n}\r\n\r\n/**\r\n * Format issue count with severity summary.\r\n */\r\nfunction formatIssueCount(warnings: CSSWarning[]): string {\r\n const errors = warnings.filter((w) => w.severity === \"error\").length;\r\n const warns = warnings.filter((w) => w.severity === \"warning\").length;\r\n const infos = warnings.filter((w) => w.severity === \"info\").length;\r\n\r\n const parts: string[] = [];\r\n if (errors > 0) parts.push(pc.red(`${errors} err`));\r\n if (warns > 0) parts.push(pc.yellow(`${warns} warn`));\r\n if (infos > 0) parts.push(pc.blue(`${infos} info`));\r\n\r\n return parts.join(\", \") || pc.green(\"none\");\r\n}\r\n\r\n/**\r\n * Print the compatibility score table to terminal.\r\n */\r\nexport function printScoreTable(\r\n scores: Record<string, { score: number; errors: number; warnings: number; info: number }>,\r\n warnings: CSSWarning[],\r\n options?: { quiet?: boolean }\r\n): void {\r\n if (!options?.quiet) {\r\n console.log();\r\n console.log(pc.bold(\" Emailens — Compatibility Report\"));\r\n console.log();\r\n }\r\n\r\n const clientMap = new Map(EMAIL_CLIENTS.map((c) => [c.id, c.name]));\r\n\r\n // Group warnings by client\r\n const warningsByClient = new Map<string, CSSWarning[]>();\r\n for (const w of warnings) {\r\n const existing = warningsByClient.get(w.client) ?? [];\r\n existing.push(w);\r\n warningsByClient.set(w.client, existing);\r\n }\r\n\r\n // Score table\r\n const table = new Table({\r\n head: [pc.bold(\"Client\"), pc.bold(\"Score\"), pc.bold(\"Issues\")],\r\n style: { head: [], border: [] },\r\n });\r\n\r\n const sortedClients = Object.entries(scores).sort(([, a], [, b]) => a.score - b.score);\r\n\r\n for (const [clientId, { score }] of sortedClients) {\r\n const clientWarnings = warningsByClient.get(clientId) ?? [];\r\n table.push([\r\n clientMap.get(clientId) ?? clientId,\r\n colorScore(score),\r\n formatIssueCount(clientWarnings),\r\n ]);\r\n }\r\n\r\n console.log(table.toString());\r\n\r\n // Overall score\r\n const scoreValues = Object.values(scores);\r\n const overall = scoreValues.length > 0\r\n ? Math.round(scoreValues.reduce((a, b) => a + b.score, 0) / scoreValues.length)\r\n : 0;\r\n\r\n console.log();\r\n console.log(` Overall: ${colorScore(overall)}/100`);\r\n console.log();\r\n}\r\n\r\n/**\r\n * Print detailed warnings grouped by client.\r\n */\r\nexport function printWarnings(\r\n warnings: CSSWarning[],\r\n options?: { quiet?: boolean }\r\n): void {\r\n if (warnings.length === 0) {\r\n if (!options?.quiet) {\r\n console.log(pc.green(\" No compatibility issues found.\"));\r\n console.log();\r\n }\r\n return;\r\n }\r\n\r\n // Group by client\r\n const byClient = new Map<string, CSSWarning[]>();\r\n for (const w of warnings) {\r\n const existing = byClient.get(w.client) ?? [];\r\n existing.push(w);\r\n byClient.set(w.client, existing);\r\n }\r\n\r\n const clientMap = new Map(EMAIL_CLIENTS.map((c) => [c.id, c.name]));\r\n\r\n for (const [clientId, clientWarnings] of byClient) {\r\n const clientName = clientMap.get(clientId) ?? clientId;\r\n const worst = worstSeverity(clientWarnings);\r\n console.log(` ${severityIcon(worst)} ${pc.bold(clientName)} (${clientWarnings.length} issue${clientWarnings.length === 1 ? \"\" : \"s\"})`);\r\n\r\n for (const w of clientWarnings) {\r\n const prop = pc.dim(w.property);\r\n console.log(` ${severityIcon(w.severity)} ${prop} — ${w.message}`);\r\n if (w.suggestion) {\r\n console.log(` ${pc.dim(\"→\")} ${w.suggestion}`);\r\n }\r\n }\r\n console.log();\r\n }\r\n}\r\n","import type { CSSWarning, TransformResult } from \"@emailens/engine\";\r\n\r\ninterface JsonOutput {\r\n overallScore: number;\r\n scores: Record<string, { score: number; errors: number; warnings: number; info: number }>;\r\n warnings: Array<{\r\n client: string;\r\n property: string;\r\n severity: string;\r\n message: string;\r\n suggestion?: string;\r\n fix?: {\r\n before: string;\r\n after: string;\r\n language: string;\r\n description: string;\r\n };\r\n }>;\r\n transforms?: Array<{\r\n clientId: string;\r\n html: string;\r\n }>;\r\n darkMode?: Record<string, {\r\n html: string;\r\n warningCount: number;\r\n }>;\r\n}\r\n\r\n/**\r\n * Build the JSON output object. Reusable by both printJson() and export command.\r\n */\r\nexport function formatJsonOutput(opts: {\r\n scores: Record<string, { score: number; errors: number; warnings: number; info: number }>;\r\n warnings: CSSWarning[];\r\n transforms?: TransformResult[];\r\n darkMode?: Record<string, { html: string; warnings: CSSWarning[] }>;\r\n}): JsonOutput {\r\n const scoreValues = Object.values(opts.scores);\r\n const overallScore = scoreValues.length > 0\r\n ? Math.round(scoreValues.reduce((a, b) => a + b.score, 0) / scoreValues.length)\r\n : 0;\r\n\r\n const output: JsonOutput = {\r\n overallScore,\r\n scores: opts.scores,\r\n warnings: opts.warnings.map((w) => ({\r\n client: w.client,\r\n property: w.property,\r\n severity: w.severity,\r\n message: w.message,\r\n suggestion: w.suggestion,\r\n fix: w.fix ? {\r\n before: w.fix.before,\r\n after: w.fix.after,\r\n language: w.fix.language,\r\n description: w.fix.description,\r\n } : undefined,\r\n })),\r\n };\r\n\r\n if (opts.transforms) {\r\n output.transforms = opts.transforms.map((t) => ({\r\n clientId: t.clientId,\r\n html: t.html,\r\n }));\r\n }\r\n\r\n if (opts.darkMode) {\r\n output.darkMode = {};\r\n for (const [clientId, dm] of Object.entries(opts.darkMode)) {\r\n output.darkMode[clientId] = {\r\n html: dm.html,\r\n warningCount: dm.warnings.length,\r\n };\r\n }\r\n }\r\n\r\n return output;\r\n}\r\n\r\n/**\r\n * Format analysis/preview results as JSON and print to stdout.\r\n */\r\nexport function printJson(opts: {\r\n scores: Record<string, { score: number; errors: number; warnings: number; info: number }>;\r\n warnings: CSSWarning[];\r\n transforms?: TransformResult[];\r\n darkMode?: Record<string, { html: string; warnings: CSSWarning[] }>;\r\n}): void {\r\n console.log(JSON.stringify(formatJsonOutput(opts), null, 2));\r\n}\r\n","import { defineCommand } from \"citty\";\r\nimport ora from \"ora\";\r\nimport {\r\n transformForAllClients,\r\n analyzeEmail,\r\n generateCompatibilityScore,\r\n simulateDarkMode,\r\n warningsForClient,\r\n CompileError,\r\n type CSSWarning,\r\n} from \"@emailens/engine\";\r\nimport { readInput, resolveClients, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\nimport { printScoreTable, printWarnings } from \"../output/terminal.js\";\r\nimport { printJson } from \"../output/json.js\";\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"preview\",\r\n description: \"Full email preview: transforms, analysis, dark mode, screenshots\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or - for stdin\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n clients: {\r\n type: \"string\",\r\n alias: \"c\",\r\n description: \"Comma-separated client IDs to filter\",\r\n },\r\n \"dark-mode\": {\r\n type: \"boolean\",\r\n alias: \"d\",\r\n description: \"Include dark mode simulation\",\r\n },\r\n screenshots: {\r\n type: \"boolean\",\r\n description: \"Capture screenshots (requires BROWSERLESS_URL)\",\r\n },\r\n out: {\r\n type: \"string\",\r\n alias: \"o\",\r\n description: \"Output directory for screenshots\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON\",\r\n },\r\n quiet: {\r\n type: \"boolean\",\r\n alias: \"q\",\r\n description: \"Suppress spinners and decorations\",\r\n },\r\n },\r\n async run({ args }) {\r\n const spinner = (args.quiet || args.json) ? null : ora();\r\n\r\n try {\r\n // Resolve format early so we fail fast on invalid --format\r\n const format = resolveFormat(args.format, args.input);\r\n\r\n // Read input\r\n spinner?.start(\"Reading input...\");\r\n const source = await readInput(args.input);\r\n spinner?.succeed(\"Input read\");\r\n\r\n // Compile (passthrough for html, auto-detects from extension)\r\n const html = await compile(source, format, args.input !== \"-\" ? args.input : undefined);\r\n\r\n // Resolve clients\r\n const clientIds = resolveClients(args.clients);\r\n const clientSet = new Set(clientIds);\r\n\r\n // Transform\r\n spinner?.start(\"Transforming for all clients...\");\r\n const allTransforms = transformForAllClients(html);\r\n const transforms = allTransforms.filter((t) => clientSet.has(t.clientId));\r\n spinner?.succeed(`Transformed for ${transforms.length} clients`);\r\n\r\n // Analyze\r\n spinner?.start(\"Analyzing compatibility...\");\r\n const framework = toFramework(format);\r\n const warnings = analyzeEmail(html, framework);\r\n const allScores = generateCompatibilityScore(warnings);\r\n\r\n const scores: typeof allScores = {};\r\n for (const [id, data] of Object.entries(allScores)) {\r\n if (clientSet.has(id)) {\r\n scores[id] = data;\r\n }\r\n }\r\n const filteredWarnings = clientIds.flatMap(id => warningsForClient(warnings, id));\r\n spinner?.succeed(\"Analysis complete\");\r\n\r\n // Dark mode\r\n let darkMode: Record<string, { html: string; warnings: CSSWarning[] }> | undefined;\r\n if (args[\"dark-mode\"]) {\r\n spinner?.start(\"Simulating dark mode...\");\r\n darkMode = {};\r\n for (const t of transforms) {\r\n darkMode[t.clientId] = simulateDarkMode(t.html, t.clientId);\r\n }\r\n spinner?.succeed(\"Dark mode simulation complete\");\r\n }\r\n\r\n // Screenshots\r\n if (args.screenshots) {\r\n const outDir = args.out ?? \"./emailens-screenshots\";\r\n spinner?.start(\"Capturing screenshots...\");\r\n try {\r\n const { captureScreenshots } = await import(\"../screenshots.js\");\r\n const results = await captureScreenshots(\r\n transforms,\r\n outDir,\r\n (clientId, index, total) => {\r\n if (spinner) spinner.text = `Capturing screenshots (${index}/${total}: ${clientId})...`;\r\n },\r\n );\r\n spinner?.succeed(`Screenshots saved to ${outDir} (${results.size} files)`);\r\n } catch (err) {\r\n spinner?.warn(`Screenshots skipped: ${(err as Error).message}`);\r\n }\r\n }\r\n\r\n // Output\r\n if (args.json) {\r\n printJson({ scores, warnings: filteredWarnings, transforms, darkMode });\r\n } else {\r\n printScoreTable(scores, filteredWarnings, { quiet: args.quiet });\r\n printWarnings(filteredWarnings, { quiet: args.quiet });\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);\r\n } else {\r\n spinner?.fail((err as Error).message);\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n","import { defineCommand } from \"citty\";\r\nimport pc from \"picocolors\";\r\nimport Table from \"cli-table3\";\r\nimport { EMAIL_CLIENTS } from \"@emailens/engine\";\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"clients\",\r\n description: \"List all supported email clients\",\r\n },\r\n args: {\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON\",\r\n },\r\n },\r\n run({ args }) {\r\n if (args.json) {\r\n const data = EMAIL_CLIENTS.map((c) => ({\r\n id: c.id,\r\n name: c.name,\r\n category: c.category,\r\n engine: c.engine,\r\n darkModeSupport: c.darkModeSupport,\r\n }));\r\n console.log(JSON.stringify(data, null, 2));\r\n return;\r\n }\r\n\r\n console.log();\r\n console.log(pc.bold(\" Emailens — Supported Email Clients\"));\r\n console.log();\r\n\r\n const table = new Table({\r\n head: [\r\n pc.bold(\"ID\"),\r\n pc.bold(\"Name\"),\r\n pc.bold(\"Category\"),\r\n pc.bold(\"Engine\"),\r\n pc.bold(\"Dark Mode\"),\r\n ],\r\n style: { head: [], border: [] },\r\n });\r\n\r\n for (const client of EMAIL_CLIENTS) {\r\n table.push([\r\n client.id,\r\n client.name,\r\n client.category,\r\n client.engine,\r\n client.darkModeSupport ? pc.green(\"Yes\") : pc.dim(\"No\"),\r\n ]);\r\n }\r\n\r\n console.log(table.toString());\r\n console.log();\r\n console.log(pc.dim(` ${EMAIL_CLIENTS.length} clients supported`));\r\n console.log();\r\n },\r\n});\r\n","import { mkdirSync, writeFileSync } from \"node:fs\";\r\nimport { join, resolve } from \"node:path\";\r\nimport { defineCommand } from \"citty\";\r\nimport ora from \"ora\";\r\nimport {\r\n transformForAllClients,\r\n analyzeEmail,\r\n generateCompatibilityScore,\r\n simulateDarkMode,\r\n warningsForClient,\r\n CompileError,\r\n type CSSWarning,\r\n} from \"@emailens/engine\";\r\n\r\n// toPlainText available in engine >=0.8.6\r\nlet toPlainText: ((html: string) => string) | null = null;\r\ntry {\r\n // eslint-disable-next-line @typescript-eslint/no-require-imports\r\n ({ toPlainText } = require(\"@emailens/engine\"));\r\n} catch {\r\n // older engine version\r\n}\r\nimport { readInput, resolveClients, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\nimport { generateHtmlReport } from \"../output/html-report.js\";\r\nimport { formatJsonOutput } from \"../output/json.js\";\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"export\",\r\n description: \"Export compatibility report as JSON or HTML\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or - for stdin\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n clients: {\r\n type: \"string\",\r\n alias: \"c\",\r\n description: \"Comma-separated client IDs to filter\",\r\n },\r\n \"dark-mode\": {\r\n type: \"boolean\",\r\n alias: \"d\",\r\n description: \"Include dark mode simulation\",\r\n },\r\n screenshots: {\r\n type: \"boolean\",\r\n description: \"Capture screenshots (requires BROWSERLESS_URL)\",\r\n },\r\n out: {\r\n type: \"string\",\r\n alias: \"o\",\r\n description: \"Output directory (default: ./emailens-report)\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Export as JSON instead of HTML\",\r\n },\r\n \"plain-text\": {\r\n type: \"boolean\",\r\n description: \"Also export a plain text version (.txt) for multipart emails\",\r\n },\r\n quiet: {\r\n type: \"boolean\",\r\n alias: \"q\",\r\n description: \"Suppress spinners and decorations\",\r\n },\r\n },\r\n async run({ args }) {\r\n const spinner = args.quiet ? null : ora();\r\n const outDir = resolve(args.out ?? \"./emailens-report\");\r\n\r\n try {\r\n // Resolve format early so we fail fast on invalid --format\r\n const format = resolveFormat(args.format, args.input);\r\n\r\n // Read input\r\n spinner?.start(\"Reading input...\");\r\n const source = await readInput(args.input);\r\n spinner?.succeed(\"Input read\");\r\n\r\n // Compile (passthrough for html, auto-detects from extension)\r\n const html = await compile(source, format, args.input !== \"-\" ? args.input : undefined);\r\n\r\n // Resolve clients\r\n const clientIds = resolveClients(args.clients);\r\n const clientSet = new Set(clientIds);\r\n\r\n // Transform\r\n spinner?.start(\"Transforming for all clients...\");\r\n const allTransforms = transformForAllClients(html);\r\n const transforms = allTransforms.filter((t) => clientSet.has(t.clientId));\r\n spinner?.succeed(`Transformed for ${transforms.length} clients`);\r\n\r\n // Analyze\r\n spinner?.start(\"Analyzing compatibility...\");\r\n const framework = toFramework(format);\r\n const warnings = analyzeEmail(html, framework);\r\n const allScores = generateCompatibilityScore(warnings);\r\n\r\n const scores: typeof allScores = {};\r\n for (const [id, data] of Object.entries(allScores)) {\r\n if (clientSet.has(id)) {\r\n scores[id] = data;\r\n }\r\n }\r\n const filteredWarnings = clientIds.flatMap(id => warningsForClient(warnings, id));\r\n spinner?.succeed(\"Analysis complete\");\r\n\r\n // Dark mode\r\n let darkMode: Record<string, { html: string; warnings: CSSWarning[] }> | undefined;\r\n if (args[\"dark-mode\"]) {\r\n spinner?.start(\"Simulating dark mode...\");\r\n darkMode = {};\r\n for (const t of transforms) {\r\n darkMode[t.clientId] = simulateDarkMode(t.html, t.clientId);\r\n }\r\n spinner?.succeed(\"Dark mode simulation complete\");\r\n }\r\n\r\n // Screenshots\r\n if (args.screenshots) {\r\n spinner?.start(\"Capturing screenshots...\");\r\n try {\r\n const { captureScreenshots } = await import(\"../screenshots.js\");\r\n const screenshotDir = join(outDir, \"screenshots\");\r\n const results = await captureScreenshots(\r\n transforms,\r\n screenshotDir,\r\n (clientId, index, total) => {\r\n if (spinner) spinner.text = `Capturing screenshots (${index}/${total}: ${clientId})...`;\r\n },\r\n );\r\n spinner?.succeed(`Screenshots saved (${results.size} files)`);\r\n } catch (err) {\r\n spinner?.warn(`Screenshots skipped: ${(err as Error).message}`);\r\n }\r\n }\r\n\r\n // Export\r\n mkdirSync(outDir, { recursive: true });\r\n\r\n if (args.json) {\r\n spinner?.start(\"Exporting JSON...\");\r\n const jsonData = formatJsonOutput({ scores, warnings: filteredWarnings, transforms });\r\n const jsonPath = join(outDir, \"report.json\");\r\n writeFileSync(jsonPath, JSON.stringify(jsonData, null, 2));\r\n spinner?.succeed(`JSON report saved to ${jsonPath}`);\r\n } else {\r\n spinner?.start(\"Generating HTML report...\");\r\n const htmlReport = generateHtmlReport({\r\n scores,\r\n warnings: filteredWarnings,\r\n transforms,\r\n darkMode,\r\n originalHtml: html,\r\n });\r\n\r\n const htmlPath = join(outDir, \"report.html\");\r\n writeFileSync(htmlPath, htmlReport);\r\n spinner?.succeed(`HTML report saved to ${htmlPath}`);\r\n }\r\n\r\n // Plain text export\r\n if (args[\"plain-text\"] && toPlainText) {\r\n spinner?.start(\"Generating plain text version...\");\r\n const plainText = toPlainText(html);\r\n const txtPath = join(outDir, \"email.txt\");\r\n writeFileSync(txtPath, plainText);\r\n spinner?.succeed(`Plain text saved to ${txtPath}`);\r\n } else if (args[\"plain-text\"] && !toPlainText) {\r\n spinner?.warn(\"Plain text export requires @emailens/engine >=0.8.6\");\r\n }\r\n\r\n if (!args.quiet) {\r\n console.log();\r\n console.log(` Output: ${outDir}`);\r\n console.log();\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);\r\n } else {\r\n spinner?.fail((err as Error).message);\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n","import { EMAIL_CLIENTS, type CSSWarning, type TransformResult } from \"@emailens/engine\";\r\n\r\n/**\r\n * Generate a self-contained HTML report file.\r\n */\r\nexport function generateHtmlReport(opts: {\r\n scores: Record<string, { score: number; errors: number; warnings: number; info: number }>;\r\n warnings: CSSWarning[];\r\n transforms?: TransformResult[];\r\n darkMode?: Record<string, { html: string; warnings: CSSWarning[] }>;\r\n originalHtml?: string;\r\n}): string {\r\n const clientMap = new Map(EMAIL_CLIENTS.map((c) => [c.id, c]));\r\n\r\n const scoreValues = Object.values(opts.scores);\r\n const overallScore = scoreValues.length > 0\r\n ? Math.round(scoreValues.reduce((a, b) => a + b.score, 0) / scoreValues.length)\r\n : 0;\r\n\r\n const scoreColor = (s: number) => s >= 90 ? \"#22c55e\" : s >= 70 ? \"#eab308\" : \"#ef4444\";\r\n\r\n // Build client cards\r\n const clientCards = Object.entries(opts.scores)\r\n .sort(([, a], [, b]) => a.score - b.score)\r\n .map(([clientId, { score, errors, warnings: warns, info }]) => {\r\n const client = clientMap.get(clientId);\r\n const name = client?.name ?? clientId;\r\n const clientWarnings = opts.warnings.filter((w) => w.client === clientId);\r\n const issueCount = errors + warns + info;\r\n\r\n const warningRows = clientWarnings.map((w) => {\r\n const icon = w.severity === \"error\" ? \"&#10007;\" : w.severity === \"warning\" ? \"&#9888;\" : \"&#8505;\";\r\n const color = w.severity === \"error\" ? \"#ef4444\" : w.severity === \"warning\" ? \"#eab308\" : \"#3b82f6\";\r\n return `<div style=\"padding:4px 0;border-bottom:1px solid #f1f1f1\">\r\n <span style=\"color:${color}\">${icon}</span>\r\n <strong>${escapeHtml(w.property)}</strong> — ${escapeHtml(w.message)}\r\n ${w.suggestion ? `<br><span style=\"color:#888;margin-left:20px\">&rarr; ${escapeHtml(w.suggestion)}</span>` : \"\"}\r\n </div>`;\r\n }).join(\"\");\r\n\r\n return `<div style=\"border:1px solid #e5e5e5;border-radius:8px;padding:16px;margin-bottom:16px\">\r\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\">\r\n <h3 style=\"margin:0;font-size:16px\">${escapeHtml(name)}</h3>\r\n <span style=\"font-size:24px;font-weight:bold;color:${scoreColor(score)}\">${score}</span>\r\n </div>\r\n <div style=\"font-size:13px;color:#888;margin-bottom:8px\">${client?.engine ?? \"\"} &middot; ${client?.category ?? \"\"} &middot; ${issueCount} issue${issueCount === 1 ? \"\" : \"s\"}</div>\r\n ${clientWarnings.length > 0 ? `<div style=\"font-size:13px\">${warningRows}</div>` : '<div style=\"color:#22c55e;font-size:13px\">No issues</div>'}\r\n </div>`;\r\n }).join(\"\");\r\n\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"utf-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n<title>Emailens Compatibility Report</title>\r\n<style>\r\n * { box-sizing: border-box; }\r\n body { font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif; margin: 0; padding: 24px; background: #fafafa; color: #333; }\r\n .container { max-width: 900px; margin: 0 auto; }\r\n .header { text-align: center; margin-bottom: 32px; }\r\n .header h1 { margin: 0 0 8px; font-size: 24px; }\r\n .overall { font-size: 48px; font-weight: bold; }\r\n .subtitle { color: #888; font-size: 14px; }\r\n .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); gap: 16px; }\r\n .footer { text-align: center; margin-top: 32px; color: #aaa; font-size: 12px; }\r\n</style>\r\n</head>\r\n<body>\r\n<div class=\"container\">\r\n <div class=\"header\">\r\n <h1>Emailens Compatibility Report</h1>\r\n <div class=\"overall\" style=\"color:${scoreColor(overallScore)}\">${overallScore}/100</div>\r\n <div class=\"subtitle\">${Object.keys(opts.scores).length} clients analyzed &middot; ${opts.warnings.length} total issues</div>\r\n </div>\r\n <div class=\"grid\">\r\n ${clientCards}\r\n </div>\r\n <div class=\"footer\">\r\n Generated by <a href=\"https://github.com/emailens/cli\" style=\"color:#888\">@emailens/cli</a>\r\n </div>\r\n</div>\r\n</body>\r\n</html>`;\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, \"&amp;\")\r\n .replace(/</g, \"&lt;\")\r\n .replace(/>/g, \"&gt;\")\r\n .replace(/\"/g, \"&quot;\");\r\n}\r\n","import { defineCommand } from \"citty\";\r\nimport ora from \"ora\";\r\nimport pc from \"picocolors\";\r\nimport {\r\n analyzeEmail,\r\n generateCompatibilityScore,\r\n generateAiFix,\r\n estimateAiFixTokens,\r\n AI_FIX_SYSTEM_PROMPT,\r\n CompileError,\r\n type AiProvider,\r\n} from \"@emailens/engine\";\r\nimport { readInput, resolveClients, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"fix\",\r\n description: \"Generate AI-powered fixes for email compatibility issues\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or - for stdin\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n clients: {\r\n type: \"string\",\r\n alias: \"c\",\r\n description: \"Comma-separated client IDs to scope the fix\",\r\n },\r\n output: {\r\n type: \"string\",\r\n alias: \"o\",\r\n description: \"Write fixed code to file instead of stdout\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON (includes token estimates and metadata)\",\r\n },\r\n quiet: {\r\n type: \"boolean\",\r\n alias: \"q\",\r\n description: \"Suppress spinners and decorations\",\r\n },\r\n estimate: {\r\n type: \"boolean\",\r\n description: \"Only show token estimate without calling the AI\",\r\n },\r\n \"max-tokens\": {\r\n type: \"string\",\r\n description: \"Maximum input tokens for the prompt (default: 16000)\",\r\n },\r\n },\r\n async run({ args }) {\r\n const spinner = (args.quiet || args.json) ? null : ora();\r\n\r\n try {\r\n const format = resolveFormat(args.format, args.input);\r\n const framework = toFramework(format);\r\n\r\n // Read and compile input\r\n spinner?.start(\"Reading input...\");\r\n const source = await readInput(args.input);\r\n const html = await compile(source, format, args.input !== \"-\" ? args.input : undefined);\r\n spinner?.succeed(\"Input read\");\r\n\r\n // Analyze\r\n spinner?.start(\"Analyzing compatibility...\");\r\n const warnings = analyzeEmail(html, framework);\r\n const scores = generateCompatibilityScore(warnings);\r\n spinner?.succeed(`Found ${warnings.length} warnings`);\r\n\r\n if (warnings.length === 0) {\r\n if (args.json) {\r\n console.log(JSON.stringify({ message: \"No issues found\", code: source }, null, 2));\r\n } else {\r\n console.log(pc.green(\"\\n No compatibility issues found — nothing to fix.\\n\"));\r\n }\r\n return;\r\n }\r\n\r\n // Resolve scope\r\n const clientIds = resolveClients(args.clients);\r\n let scope: \"current\" | \"all\";\r\n let selectedClientId: string | undefined;\r\n let scopedWarnings = warnings;\r\n let scopedScores = scores;\r\n\r\n if (args.clients && clientIds.length === 1) {\r\n // Single client: use engine's \"current\" scope\r\n scope = \"current\";\r\n selectedClientId = clientIds[0];\r\n } else if (args.clients && clientIds.length > 1) {\r\n // Multiple clients: pre-filter warnings/scores, then use \"all\" scope\r\n // so the engine processes all of them without needing \"current\" + single ID\r\n const clientSet = new Set(clientIds);\r\n scope = \"all\";\r\n selectedClientId = undefined;\r\n scopedWarnings = warnings.filter((w) => clientSet.has(w.client));\r\n scopedScores = Object.fromEntries(\r\n Object.entries(scores).filter(([id]) => clientSet.has(id)),\r\n );\r\n } else {\r\n // No --clients flag: fix for all clients\r\n scope = \"all\";\r\n selectedClientId = undefined;\r\n }\r\n\r\n // Token estimate\r\n const maxInputTokens = args[\"max-tokens\"] ? parseInt(args[\"max-tokens\"], 10) : 16000;\r\n const estimate = await estimateAiFixTokens({\r\n originalHtml: html,\r\n warnings: scopedWarnings,\r\n scores: scopedScores,\r\n scope,\r\n selectedClientId,\r\n format,\r\n maxInputTokens,\r\n });\r\n\r\n const structuralPct = estimate.warningCount > 0\r\n ? Math.round((estimate.structuralCount / estimate.warningCount) * 100)\r\n : 0;\r\n\r\n if (args.estimate) {\r\n if (args.json) {\r\n console.log(JSON.stringify(estimate, null, 2));\r\n } else {\r\n console.log(`\\n ${pc.bold(\"Token Estimate\")}`);\r\n console.log(` Input tokens: ~${estimate.inputTokens.toLocaleString()}`);\r\n console.log(` Output tokens: ~${estimate.estimatedOutputTokens.toLocaleString()}`);\r\n console.log(` Warnings: ${estimate.warningCount} (${estimate.structuralCount} structural)`);\r\n if (estimate.truncated) {\r\n console.log(` ${pc.yellow(`Truncated: ${estimate.warningsRemoved} low-priority warnings removed`)}`);\r\n }\r\n console.log();\r\n }\r\n return;\r\n }\r\n\r\n // Check for API key\r\n const apiKey = process.env.ANTHROPIC_API_KEY;\r\n if (!apiKey) {\r\n spinner?.fail(\"ANTHROPIC_API_KEY environment variable is required\");\r\n console.error(pc.dim(\"\\n Set it with: export ANTHROPIC_API_KEY=sk-ant-...\\n\"));\r\n process.exit(1);\r\n }\r\n\r\n // Show estimate before calling\r\n if (!args.quiet && !args.json) {\r\n console.log(pc.dim(` ~${estimate.inputTokens.toLocaleString()} input tokens, ${estimate.warningCount} warnings (${structuralPct}% structural)`));\r\n if (estimate.truncated) {\r\n console.log(pc.yellow(` Truncated ${estimate.warningsRemoved} low-priority warnings to fit token limit`));\r\n }\r\n }\r\n\r\n // Call AI\r\n spinner?.start(\"Generating AI fix...\");\r\n\r\n let Anthropic: typeof import(\"@anthropic-ai/sdk\").default;\r\n try {\r\n Anthropic = (await import(\"@anthropic-ai/sdk\")).default;\r\n } catch {\r\n spinner?.fail(\"@anthropic-ai/sdk is required for the fix command\");\r\n console.error(pc.dim(\"\\n Install it with: npm install @anthropic-ai/sdk\\n\"));\r\n process.exit(1);\r\n }\r\n\r\n const anthropic = new Anthropic({ apiKey });\r\n\r\n const provider: AiProvider = async (prompt) => {\r\n const msg = await anthropic.messages.create({\r\n model: \"claude-sonnet-4-6\",\r\n max_tokens: 8192,\r\n system: AI_FIX_SYSTEM_PROMPT,\r\n messages: [{ role: \"user\", content: prompt }],\r\n });\r\n const textBlock = msg.content.find((b: { type: string }) => b.type === \"text\");\r\n return textBlock?.type === \"text\" ? (textBlock as { type: \"text\"; text: string }).text : \"\";\r\n };\r\n\r\n const result = await generateAiFix({\r\n originalHtml: html,\r\n warnings: scopedWarnings,\r\n scores: scopedScores,\r\n scope,\r\n selectedClientId,\r\n format,\r\n maxInputTokens,\r\n provider,\r\n });\r\n\r\n spinner?.succeed(`Fixed ${result.targetedWarnings} warnings (${result.structuralCount} structural)`);\r\n\r\n // Output\r\n if (args.output) {\r\n const { writeFileSync } = await import(\"node:fs\");\r\n writeFileSync(args.output, result.code, \"utf-8\");\r\n if (!args.quiet) {\r\n console.log(pc.green(`\\n Fixed code written to ${args.output}\\n`));\r\n }\r\n } else if (args.json) {\r\n console.log(JSON.stringify({\r\n code: result.code,\r\n targetedWarnings: result.targetedWarnings,\r\n structuralCount: result.structuralCount,\r\n tokenEstimate: result.tokenEstimate,\r\n }, null, 2));\r\n } else {\r\n console.log(\"\\n\" + result.code);\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);\r\n } else {\r\n spinner?.fail((err as Error).message);\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n","import { defineCommand } from \"citty\";\r\nimport ora from \"ora\";\r\nimport pc from \"picocolors\";\r\nimport Table from \"cli-table3\";\r\nimport {\r\n auditEmail,\r\n CompileError,\r\n type AuditReport,\r\n} from \"@emailens/engine\";\r\nimport { readInput, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\nimport { printScoreTable, printWarnings } from \"../output/terminal.js\";\r\n\r\nconst VALID_SKIPS = new Set([\"spam\", \"links\", \"accessibility\", \"images\", \"compatibility\"]);\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"audit\",\r\n description: \"Full email audit: compatibility + spam + links + accessibility + images\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or - for stdin\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON\",\r\n },\r\n quiet: {\r\n type: \"boolean\",\r\n alias: \"q\",\r\n description: \"Suppress spinners and decorations\",\r\n },\r\n skip: {\r\n type: \"string\",\r\n description: \"Comma-separated checks to skip: spam,links,accessibility,images,compatibility\",\r\n },\r\n },\r\n async run({ args }) {\r\n const spinner = (args.quiet || args.json) ? null : ora();\r\n\r\n try {\r\n const format = resolveFormat(args.format, args.input);\r\n\r\n // Read input\r\n spinner?.start(\"Reading input...\");\r\n const source = await readInput(args.input);\r\n spinner?.succeed(\"Input read\");\r\n\r\n // Compile\r\n const html = await compile(source, format, args.input !== \"-\" ? args.input : undefined);\r\n\r\n // Parse --skip flag\r\n const skip: Array<\"spam\" | \"links\" | \"accessibility\" | \"images\" | \"compatibility\"> = [];\r\n if (args.skip) {\r\n for (const s of args.skip.split(\",\").map((s) => s.trim()).filter(Boolean)) {\r\n if (!VALID_SKIPS.has(s)) {\r\n throw new Error(`Unknown skip value \"${s}\". Valid: ${Array.from(VALID_SKIPS).join(\", \")}`);\r\n }\r\n skip.push(s as typeof skip[number]);\r\n }\r\n }\r\n\r\n // Run audit\r\n spinner?.start(\"Running full audit...\");\r\n const framework = toFramework(format);\r\n const report = auditEmail(html, { framework, skip });\r\n spinner?.succeed(\"Audit complete\");\r\n\r\n // Output\r\n if (args.json) {\r\n console.log(JSON.stringify(report, null, 2));\r\n } else {\r\n // Compatibility section\r\n if (!skip.includes(\"compatibility\")) {\r\n printScoreTable(report.compatibility.scores, report.compatibility.warnings, { quiet: args.quiet });\r\n printWarnings(report.compatibility.warnings, { quiet: args.quiet });\r\n }\r\n\r\n // Quality summary\r\n printQualitySummary(report, skip, { quiet: args.quiet });\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);\r\n } else {\r\n spinner?.fail((err as Error).message);\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n\r\nfunction printQualitySummary(\r\n report: AuditReport,\r\n skip: string[],\r\n options?: { quiet?: boolean },\r\n): void {\r\n if (!options?.quiet) {\r\n console.log(pc.bold(\" Quality Summary\"));\r\n console.log();\r\n }\r\n\r\n const table = new Table({\r\n head: [pc.bold(\"Check\"), pc.bold(\"Result\")],\r\n style: { head: [], border: [] },\r\n });\r\n\r\n if (!skip.includes(\"spam\")) {\r\n const { score, level, issues } = report.spam;\r\n const color = score >= 90 ? pc.green : score >= 70 ? pc.yellow : pc.red;\r\n table.push([\"Content Hygiene\", `${color(String(score))}/100 (${level}) — ${issues.length} issue${issues.length === 1 ? \"\" : \"s\"}`]);\r\n }\r\n\r\n if (!skip.includes(\"links\")) {\r\n const { totalLinks, issues } = report.links;\r\n const color = issues.length === 0 ? pc.green : pc.yellow;\r\n table.push([\"Links\", `${totalLinks} link${totalLinks === 1 ? \"\" : \"s\"} — ${color(`${issues.length} issue${issues.length === 1 ? \"\" : \"s\"}`)}`]);\r\n }\r\n\r\n if (!skip.includes(\"accessibility\")) {\r\n const { score, issues } = report.accessibility;\r\n const color = score >= 90 ? pc.green : score >= 70 ? pc.yellow : pc.red;\r\n table.push([\"Accessibility\", `${color(String(score))}/100 — ${issues.length} issue${issues.length === 1 ? \"\" : \"s\"}`]);\r\n }\r\n\r\n if (!skip.includes(\"images\")) {\r\n const { total, issues } = report.images;\r\n const color = issues.length === 0 ? pc.green : pc.yellow;\r\n table.push([\"Images\", `${total} image${total === 1 ? \"\" : \"s\"} — ${color(`${issues.length} issue${issues.length === 1 ? \"\" : \"s\"}`)}`]);\r\n }\r\n\r\n console.log(table.toString());\r\n console.log();\r\n}\r\n","import { defineCommand } from \"citty\";\r\nimport pc from \"picocolors\";\r\nimport { readInput, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\nimport {\r\n auditEmail,\r\n CompileError,\r\n type AuditReport,\r\n} from \"@emailens/engine\";\r\nimport { readdir } from \"node:fs/promises\";\r\nimport { resolve, relative } from \"node:path\";\r\n\r\ninterface LintIssue {\r\n severity: \"error\" | \"warning\" | \"info\";\r\n category: string;\r\n rule: string;\r\n message: string;\r\n detail?: string;\r\n}\r\n\r\ninterface LintFileResult {\r\n file: string;\r\n issues: LintIssue[];\r\n errors: number;\r\n warnings: number;\r\n}\r\n\r\nconst VALID_SKIPS = new Set([\r\n \"spam\", \"links\", \"accessibility\", \"images\",\r\n \"compatibility\", \"inboxPreview\", \"size\", \"templateVariables\",\r\n]);\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"lint\",\r\n description: \"Lint HTML emails for compatibility, spam, accessibility, and more. CI/CD-friendly with structured exit codes.\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or glob pattern\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON\",\r\n },\r\n failOnWarning: {\r\n type: \"boolean\",\r\n description: \"Exit 2 if warnings found\",\r\n },\r\n skip: {\r\n type: \"string\",\r\n description: \"Comma-separated checks to skip: spam,links,accessibility,images,compatibility,inboxPreview,size,templateVariables\",\r\n },\r\n maxWarnings: {\r\n type: \"string\",\r\n description: \"Fail if more than n warnings\",\r\n },\r\n },\r\n async run({ args }) {\r\n try {\r\n // Parse --skip\r\n const skip: Array<string> = [];\r\n if (args.skip) {\r\n for (const s of args.skip.split(\",\").map((s) => s.trim()).filter(Boolean)) {\r\n if (!VALID_SKIPS.has(s)) {\r\n throw new Error(`Unknown skip value \"${s}\". Valid: ${Array.from(VALID_SKIPS).join(\", \")}`);\r\n }\r\n skip.push(s);\r\n }\r\n }\r\n\r\n const maxWarningsRaw = args.maxWarnings !== undefined ? parseInt(args.maxWarnings, 10) : undefined;\r\n if (maxWarningsRaw !== undefined && isNaN(maxWarningsRaw)) {\r\n throw new Error(`--maxWarnings must be a number, got: ${args.maxWarnings}`);\r\n }\r\n const maxWarnings = maxWarningsRaw ?? Infinity;\r\n const files = await resolveGlob(args.input);\r\n\r\n if (files.length === 0) {\r\n if (args.json) {\r\n console.log(JSON.stringify({ files: [], totalErrors: 0, totalWarnings: 0 }));\r\n } else {\r\n console.error(pc.red(`No files found matching: ${args.input}`));\r\n }\r\n process.exit(1);\r\n }\r\n\r\n const results: LintFileResult[] = [];\r\n let totalErrors = 0;\r\n let totalWarnings = 0;\r\n\r\n for (const file of files) {\r\n const format = resolveFormat(args.format, file);\r\n const source = await readInput(file);\r\n const html = await compile(source, format, file);\r\n const framework = toFramework(format);\r\n\r\n const report = auditEmail(html, {\r\n framework,\r\n skip: skip as AuditSkipType[],\r\n });\r\n\r\n const issues = flattenToLintIssues(report, skip);\r\n const errors = issues.filter((i) => i.severity === \"error\").length;\r\n const warnings = issues.filter((i) => i.severity === \"warning\").length;\r\n\r\n results.push({ file: relative(process.cwd(), file), issues, errors, warnings });\r\n totalErrors += errors;\r\n totalWarnings += warnings;\r\n }\r\n\r\n // Output\r\n if (args.json) {\r\n console.log(JSON.stringify({ files: results, totalErrors, totalWarnings }, null, 2));\r\n } else {\r\n for (const result of results) {\r\n console.log(pc.underline(result.file));\r\n if (result.issues.length === 0) {\r\n console.log(` ${pc.green(\"pass\")} No issues found`);\r\n } else {\r\n for (const issue of result.issues) {\r\n const sev = issue.severity === \"error\"\r\n ? pc.red(\"error\")\r\n : issue.severity === \"warning\"\r\n ? pc.yellow(\"warn \")\r\n : pc.blue(\"info \");\r\n console.log(` ${sev} ${pc.dim(issue.category.padEnd(18))} ${pc.bold(issue.rule.padEnd(22))} ${issue.message}`);\r\n }\r\n }\r\n console.log();\r\n }\r\n\r\n const summary = [\r\n `${files.length} file${files.length === 1 ? \"\" : \"s\"}`,\r\n totalErrors > 0 ? pc.red(`${totalErrors} error${totalErrors === 1 ? \"\" : \"s\"}`) : null,\r\n totalWarnings > 0 ? pc.yellow(`${totalWarnings} warning${totalWarnings === 1 ? \"\" : \"s\"}`) : null,\r\n totalErrors === 0 && totalWarnings === 0 ? pc.green(\"all clean\") : null,\r\n ].filter(Boolean).join(\" | \");\r\n\r\n console.log(summary);\r\n }\r\n\r\n // Exit codes\r\n if (totalErrors > 0) {\r\n process.exit(1);\r\n }\r\n if (args.failOnWarning && totalWarnings > 0) {\r\n if (!args.json) {\r\n console.error(pc.yellow(`\\nFailed: ${totalWarnings} warning${totalWarnings === 1 ? \"\" : \"s\"} found (--failOnWarning)`));\r\n }\r\n process.exit(2);\r\n }\r\n if (Number.isFinite(maxWarnings) && totalWarnings > maxWarnings) {\r\n if (!args.json) {\r\n console.error(pc.red(`\\nExceeded max warnings: ${totalWarnings} > ${maxWarnings}`));\r\n }\r\n process.exit(2);\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n console.error(pc.red(`Compilation failed (${err.phase}): ${err.message}`));\r\n } else {\r\n console.error(pc.red((err as Error).message));\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n\r\ntype AuditSkipType = \"spam\" | \"links\" | \"accessibility\" | \"images\" | \"compatibility\" | \"inboxPreview\" | \"size\" | \"templateVariables\";\r\n\r\n/**\r\n * Resolve a file path or simple glob pattern to an array of files.\r\n * Supports basic * glob in the last path segment.\r\n */\r\nasync function resolveGlob(pattern: string): Promise<string[]> {\r\n // If it's a direct file, just return it\r\n if (!pattern.includes(\"*\")) {\r\n return [resolve(pattern)];\r\n }\r\n\r\n // Recursive glob is not supported — provide clear error\r\n if (pattern.includes(\"**\")) {\r\n throw new Error(\"Recursive glob (**) is not supported. Use a single-level wildcard (e.g., src/*.html) or list files explicitly.\");\r\n }\r\n\r\n // Simple glob: split into dir + glob pattern\r\n const lastSep = Math.max(pattern.lastIndexOf(\"/\"), pattern.lastIndexOf(\"\\\\\"));\r\n const dir = lastSep >= 0 ? pattern.slice(0, lastSep) : \".\";\r\n const glob = lastSep >= 0 ? pattern.slice(lastSep + 1) : pattern;\r\n\r\n // Convert glob to regex (only support * wildcard)\r\n const regex = new RegExp(\"^\" + glob.replace(/\\*/g, \".*\") + \"$\");\r\n\r\n const entries = await readdir(resolve(dir), { withFileTypes: true });\r\n return entries\r\n .filter((e) => e.isFile() && regex.test(e.name))\r\n .map((e) => resolve(dir, e.name))\r\n .sort();\r\n}\r\n\r\n/**\r\n * Flatten an AuditReport into a unified LintIssue array.\r\n */\r\nfunction flattenToLintIssues(report: AuditReport, skip: string[]): LintIssue[] {\r\n const issues: LintIssue[] = [];\r\n\r\n // CSS compatibility warnings → group by property (deduplicate across clients)\r\n if (!skip.includes(\"compatibility\")) {\r\n const seenProps = new Map<string, { severity: \"error\" | \"warning\" | \"info\"; clients: string[]; message: string }>();\r\n\r\n for (const w of report.compatibility.warnings) {\r\n const key = `${w.property}\\0${w.severity}`;\r\n const existing = seenProps.get(key);\r\n if (existing) {\r\n existing.clients.push(w.client);\r\n } else {\r\n seenProps.set(key, {\r\n severity: w.severity,\r\n clients: [w.client],\r\n message: w.message,\r\n });\r\n }\r\n }\r\n\r\n for (const [key, val] of seenProps) {\r\n const property = key.split(\"\\0\")[0];\r\n issues.push({\r\n severity: val.severity,\r\n category: val.clients.slice(0, 3).join(\",\") + (val.clients.length > 3 ? `+${val.clients.length - 3}` : \"\"),\r\n rule: property,\r\n message: val.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"spam\")) {\r\n for (const issue of report.spam.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"spam\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n detail: issue.detail,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"links\")) {\r\n for (const issue of report.links.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"links\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"accessibility\")) {\r\n for (const issue of report.accessibility.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"accessibility\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"images\")) {\r\n for (const issue of report.images.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"images\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"inboxPreview\")) {\r\n for (const issue of report.inboxPreview.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"inboxPreview\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"size\")) {\r\n for (const issue of report.size.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"size\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"templateVariables\")) {\r\n for (const issue of report.templateVariables.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"templateVars\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n // Sort: errors first, then warnings, then info\r\n const order = { error: 0, warning: 1, info: 2 };\r\n issues.sort((a, b) => order[a.severity] - order[b.severity]);\r\n\r\n return issues;\r\n}\r\n"],"mappings":"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","names":["defineCommand","resolve","EMAIL_CLIENTS","defineCommand","ora","analyzeEmail","generateCompatibilityScore","warningsForClient","CompileError","compile","defineCommand","ora","compile","analyzeEmail","generateCompatibilityScore","warningsForClient","CompileError","defineCommand","pc","Table","EMAIL_CLIENTS","defineCommand","ora","transformForAllClients","analyzeEmail","generateCompatibilityScore","simulateDarkMode","warningsForClient","CompileError","compile","EMAIL_CLIENTS","defineCommand","ora","compile","transformForAllClients","analyzeEmail","generateCompatibilityScore","warningsForClient","simulateDarkMode","CompileError","defineCommand","ora","pc","analyzeEmail","generateCompatibilityScore","CompileError","compile","defineCommand","ora","analyzeEmail","generateCompatibilityScore","pc","writeFileSync","CompileError","defineCommand","ora","pc","Table","CompileError","compile","defineCommand","ora","compile","s","CompileError","pc","Table","defineCommand","pc","compile","auditEmail","CompileError","resolve","VALID_SKIPS","defineCommand","s","pc","defineCommand"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/meta.ts","../package.json","../src/commands/analyze.ts","../src/utils.ts","../src/output/terminal.ts","../src/output/json.ts","../src/commands/preview.ts","../src/commands/clients.ts","../src/commands/export.ts","../src/output/html-report.ts","../src/commands/fix.ts","../src/commands/audit.ts","../src/commands/lint.ts"],"sourcesContent":["import { defineCommand, runMain } from \"citty\";\nimport { meta } from \"./meta.js\";\nimport analyze from \"./commands/analyze.js\";\nimport preview from \"./commands/preview.js\";\nimport clients from \"./commands/clients.js\";\nimport exportCmd from \"./commands/export.js\";\nimport fix from \"./commands/fix.js\";\nimport audit from \"./commands/audit.js\";\nimport lint from \"./commands/lint.js\";\n\nconst main = defineCommand({\n meta,\n subCommands: {\n analyze,\n preview,\n clients,\n export: exportCmd,\n fix,\n audit,\n lint,\n },\n});\n\nrunMain(main);\n","import { EMAIL_CLIENTS } from \"@emailens/engine\";\nimport pkg from \"../package.json\" with { type: \"json\" };\n\n/**\n * CLI identity. Both fields used to be hardcoded in index.ts and both had\n * drifted: `--version` reported 0.4.0 while the package was 0.3.4, and the\n * description claimed 12 clients while the engine shipped 15. Anyone filing a\n * bug would have quoted a version that never existed.\n *\n * Kept in its own module so it can be asserted directly. Testing it through the\n * binary means racing citty's process.exit() against the stdout flush.\n */\nexport const meta = {\n name: \"emailens\",\n version: pkg.version,\n description: `Email compatibility analysis CLI — preview how HTML emails render across ${EMAIL_CLIENTS.length} email clients.`,\n} as const;\n","{\n \"name\": \"@emailens/cli\",\n \"version\": \"0.3.5\",\n \"description\": \"CLI tool for email compatibility analysis — analyze, preview, and export email rendering across 15 email clients.\",\n \"type\": \"module\",\n \"bin\": {\n \"emailens\": \"./dist/index.js\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n }\n },\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"files\": [\n \"dist\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"start\": \"bun run dist/index.js\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"bun test\",\n \"prepublishOnly\": \"bun run build\"\n },\n \"dependencies\": {\n \"@emailens/engine\": \"^0.9.3\",\n \"citty\": \"^0.1.6\",\n \"cli-table3\": \"^0.6.5\",\n \"ora\": \"^8.2.0\",\n \"picocolors\": \"^1.1.1\"\n },\n \"optionalDependencies\": {\n \"@anthropic-ai/sdk\": \"^0.52.0\",\n \"playwright-core\": \"^1.52.0\"\n },\n \"devDependencies\": {\n \"@types/bun\": \"^1.3.14\",\n \"@types/mjml\": \"^4.7.4\",\n \"@types/node\": \"^25.3.0\",\n \"bun-types\": \"^1.3.9\",\n \"tsup\": \"^8.4.0\",\n \"typescript\": \"^5.9.3\"\n },\n \"keywords\": [\n \"email\",\n \"html-email\",\n \"css\",\n \"compatibility\",\n \"cli\",\n \"gmail\",\n \"outlook\",\n \"apple-mail\",\n \"email-testing\",\n \"dark-mode\"\n ],\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/emailens/cli.git\"\n },\n \"engines\": {\n \"node\": \">=18\"\n },\n \"homepage\": \"https://github.com/emailens/cli#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/emailens/cli/issues\"\n }\n}","import { defineCommand } from \"citty\";\r\nimport ora from \"ora\";\r\nimport {\r\n analyzeEmail,\r\n generateCompatibilityScore,\r\n warningsForClient,\r\n CompileError,\r\n} from \"@emailens/engine\";\r\nimport { readInput, resolveClients, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\nimport { printScoreTable, printWarnings } from \"../output/terminal.js\";\r\nimport { printJson } from \"../output/json.js\";\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"analyze\",\r\n description: \"Analyze email CSS compatibility across clients\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or - for stdin\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n clients: {\r\n type: \"string\",\r\n alias: \"c\",\r\n description: \"Comma-separated client IDs to filter\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON\",\r\n },\r\n quiet: {\r\n type: \"boolean\",\r\n alias: \"q\",\r\n description: \"Suppress spinners and decorations\",\r\n },\r\n },\r\n async run({ args }) {\r\n // --json implies quiet spinners\r\n const spinner = (args.quiet || args.json) ? null : ora();\r\n\r\n try {\r\n // Resolve format early so we fail fast on invalid --format\r\n const format = resolveFormat(args.format, args.input);\r\n\r\n // Read input\r\n spinner?.start(\"Reading input...\");\r\n const source = await readInput(args.input);\r\n spinner?.succeed(\"Input read\");\r\n\r\n // Compile (passthrough for html, auto-detects from extension)\r\n const html = await compile(source, format, args.input !== \"-\" ? args.input : undefined);\r\n\r\n // Resolve clients\r\n const clientIds = resolveClients(args.clients);\r\n\r\n // Analyze\r\n spinner?.start(\"Analyzing compatibility...\");\r\n const framework = toFramework(format);\r\n const warnings = analyzeEmail(html, framework);\r\n const allScores = generateCompatibilityScore(warnings);\r\n\r\n // Filter scores to requested clients\r\n const clientSet = new Set(clientIds);\r\n const scores: typeof allScores = {};\r\n for (const [id, data] of Object.entries(allScores)) {\r\n if (clientSet.has(id)) {\r\n scores[id] = data;\r\n }\r\n }\r\n\r\n // Filter warnings to requested clients\r\n const filteredWarnings = clientIds.flatMap(id => warningsForClient(warnings, id));\r\n\r\n spinner?.succeed(\"Analysis complete\");\r\n\r\n // Output\r\n if (args.json) {\r\n printJson({ scores, warnings: filteredWarnings });\r\n } else {\r\n printScoreTable(scores, filteredWarnings, { quiet: args.quiet });\r\n printWarnings(filteredWarnings, { quiet: args.quiet });\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);\r\n } else {\r\n spinner?.fail((err as Error).message);\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n","import { readFileSync } from \"node:fs\";\r\nimport { EMAIL_CLIENTS, type Framework, type InputFormat } from \"@emailens/engine\";\r\nimport { detectFormat } from \"@emailens/engine/compile\";\r\n\r\nconst VALID_FORMATS = new Set([\"html\", \"jsx\", \"mjml\", \"maizzle\"]);\r\n\r\n/**\r\n * Read HTML input from a file path or stdin (`-`).\r\n * Always returns a Promise for consistent caller ergonomics.\r\n */\r\nexport async function readInput(pathOrStdin: string): Promise<string> {\r\n if (pathOrStdin === \"-\") {\r\n // Try /dev/stdin first (works on Unix and Git Bash on Windows)\r\n try {\r\n return readFileSync(\"/dev/stdin\", \"utf-8\");\r\n } catch {\r\n // Fall through to async approach\r\n }\r\n\r\n // Async stdin reading for Windows compatibility\r\n return new Promise<string>((resolve, reject) => {\r\n const chunks: Buffer[] = [];\r\n process.stdin.resume();\r\n process.stdin.on(\"data\", (chunk) => chunks.push(Buffer.from(chunk)));\r\n process.stdin.on(\"end\", () => {\r\n const data = Buffer.concat(chunks).toString(\"utf-8\");\r\n if (!data.trim()) {\r\n reject(new Error(\"No input received from stdin. Pipe HTML or provide a file path.\"));\r\n } else {\r\n resolve(data);\r\n }\r\n });\r\n process.stdin.on(\"error\", () => {\r\n reject(new Error(\"No input received from stdin. Pipe HTML or provide a file path.\"));\r\n });\r\n });\r\n }\r\n\r\n try {\r\n return readFileSync(pathOrStdin, \"utf-8\");\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n throw new Error(`Failed to read file \"${pathOrStdin}\": ${message}`);\r\n }\r\n}\r\n\r\n/**\r\n * Validate and resolve client IDs. Returns all clients if none specified.\r\n */\r\nexport function resolveClients(ids?: string): string[] {\r\n const validIds = new Set(EMAIL_CLIENTS.map((c) => c.id));\r\n\r\n if (!ids) {\r\n return EMAIL_CLIENTS.map((c) => c.id);\r\n }\r\n\r\n const requested = ids.split(\",\").map((s) => s.trim()).filter(Boolean);\r\n const invalid = requested.filter((id) => !validIds.has(id));\r\n\r\n if (invalid.length > 0) {\r\n throw new Error(\r\n `Unknown client ID(s): ${invalid.join(\", \")}.\\n` +\r\n `Valid IDs: ${Array.from(validIds).join(\", \")}`\r\n );\r\n }\r\n\r\n return requested;\r\n}\r\n\r\n/**\r\n * Resolve the input format from explicit flag, file extension, or default.\r\n * Validates the --format flag and errors on unknown values.\r\n * Auto-detects from file extension when no flag is given.\r\n */\r\nexport function resolveFormat(formatFlag?: string, filePath?: string): InputFormat {\r\n if (formatFlag) {\r\n if (!VALID_FORMATS.has(formatFlag)) {\r\n throw new Error(\r\n `Unknown format \"${formatFlag}\". Valid formats: ${Array.from(VALID_FORMATS).join(\", \")}`\r\n );\r\n }\r\n return formatFlag as InputFormat;\r\n }\r\n\r\n // Auto-detect from file extension\r\n if (filePath && filePath !== \"-\") {\r\n return detectFormat(filePath);\r\n }\r\n\r\n return \"html\";\r\n}\r\n\r\n/**\r\n * Convert a format string to the engine's Framework type.\r\n */\r\nexport function toFramework(format: InputFormat): Framework | undefined {\r\n if (format === \"jsx\" || format === \"mjml\" || format === \"maizzle\") return format;\r\n return undefined;\r\n}\r\n","import pc from \"picocolors\";\r\nimport Table from \"cli-table3\";\r\nimport {\r\n EMAIL_CLIENTS,\r\n type CSSWarning,\r\n} from \"@emailens/engine\";\r\n\r\n/**\r\n * Color-code a score value: green >=90, yellow >=70, red <70.\r\n */\r\nfunction colorScore(score: number): string {\r\n const str = String(score);\r\n if (score >= 90) return pc.green(str);\r\n if (score >= 70) return pc.yellow(str);\r\n return pc.red(str);\r\n}\r\n\r\n/**\r\n * Get severity icon.\r\n */\r\nfunction severityIcon(severity: CSSWarning[\"severity\"]): string {\r\n switch (severity) {\r\n case \"error\": return pc.red(\"✗\");\r\n case \"warning\": return pc.yellow(\"⚠\");\r\n case \"info\": return pc.blue(\"ℹ\");\r\n }\r\n}\r\n\r\n/**\r\n * Get the worst severity from a list of warnings.\r\n */\r\nfunction worstSeverity(warnings: CSSWarning[]): CSSWarning[\"severity\"] {\r\n if (warnings.some((w) => w.severity === \"error\")) return \"error\";\r\n if (warnings.some((w) => w.severity === \"warning\")) return \"warning\";\r\n return \"info\";\r\n}\r\n\r\n/**\r\n * Format issue count with severity summary.\r\n */\r\nfunction formatIssueCount(warnings: CSSWarning[]): string {\r\n const errors = warnings.filter((w) => w.severity === \"error\").length;\r\n const warns = warnings.filter((w) => w.severity === \"warning\").length;\r\n const infos = warnings.filter((w) => w.severity === \"info\").length;\r\n\r\n const parts: string[] = [];\r\n if (errors > 0) parts.push(pc.red(`${errors} err`));\r\n if (warns > 0) parts.push(pc.yellow(`${warns} warn`));\r\n if (infos > 0) parts.push(pc.blue(`${infos} info`));\r\n\r\n return parts.join(\", \") || pc.green(\"none\");\r\n}\r\n\r\n/**\r\n * Print the compatibility score table to terminal.\r\n */\r\nexport function printScoreTable(\r\n scores: Record<string, { score: number; errors: number; warnings: number; info: number }>,\r\n warnings: CSSWarning[],\r\n options?: { quiet?: boolean }\r\n): void {\r\n if (!options?.quiet) {\r\n console.log();\r\n console.log(pc.bold(\" Emailens — Compatibility Report\"));\r\n console.log();\r\n }\r\n\r\n const clientMap = new Map(EMAIL_CLIENTS.map((c) => [c.id, c.name]));\r\n\r\n // Group warnings by client\r\n const warningsByClient = new Map<string, CSSWarning[]>();\r\n for (const w of warnings) {\r\n const existing = warningsByClient.get(w.client) ?? [];\r\n existing.push(w);\r\n warningsByClient.set(w.client, existing);\r\n }\r\n\r\n // Score table\r\n const table = new Table({\r\n head: [pc.bold(\"Client\"), pc.bold(\"Score\"), pc.bold(\"Issues\")],\r\n style: { head: [], border: [] },\r\n });\r\n\r\n const sortedClients = Object.entries(scores).sort(([, a], [, b]) => a.score - b.score);\r\n\r\n for (const [clientId, { score }] of sortedClients) {\r\n const clientWarnings = warningsByClient.get(clientId) ?? [];\r\n table.push([\r\n clientMap.get(clientId) ?? clientId,\r\n colorScore(score),\r\n formatIssueCount(clientWarnings),\r\n ]);\r\n }\r\n\r\n console.log(table.toString());\r\n\r\n // Overall score\r\n const scoreValues = Object.values(scores);\r\n const overall = scoreValues.length > 0\r\n ? Math.round(scoreValues.reduce((a, b) => a + b.score, 0) / scoreValues.length)\r\n : 0;\r\n\r\n console.log();\r\n console.log(` Overall: ${colorScore(overall)}/100`);\r\n console.log();\r\n}\r\n\r\n/**\r\n * Print detailed warnings grouped by client.\r\n */\r\nexport function printWarnings(\r\n warnings: CSSWarning[],\r\n options?: { quiet?: boolean }\r\n): void {\r\n if (warnings.length === 0) {\r\n if (!options?.quiet) {\r\n console.log(pc.green(\" No compatibility issues found.\"));\r\n console.log();\r\n }\r\n return;\r\n }\r\n\r\n // Group by client\r\n const byClient = new Map<string, CSSWarning[]>();\r\n for (const w of warnings) {\r\n const existing = byClient.get(w.client) ?? [];\r\n existing.push(w);\r\n byClient.set(w.client, existing);\r\n }\r\n\r\n const clientMap = new Map(EMAIL_CLIENTS.map((c) => [c.id, c.name]));\r\n\r\n for (const [clientId, clientWarnings] of byClient) {\r\n const clientName = clientMap.get(clientId) ?? clientId;\r\n const worst = worstSeverity(clientWarnings);\r\n console.log(` ${severityIcon(worst)} ${pc.bold(clientName)} (${clientWarnings.length} issue${clientWarnings.length === 1 ? \"\" : \"s\"})`);\r\n\r\n for (const w of clientWarnings) {\r\n const prop = pc.dim(w.property);\r\n console.log(` ${severityIcon(w.severity)} ${prop} — ${w.message}`);\r\n if (w.suggestion) {\r\n console.log(` ${pc.dim(\"→\")} ${w.suggestion}`);\r\n }\r\n }\r\n console.log();\r\n }\r\n}\r\n","import type { CSSWarning, TransformResult } from \"@emailens/engine\";\r\n\r\ninterface JsonOutput {\r\n overallScore: number;\r\n scores: Record<string, { score: number; errors: number; warnings: number; info: number }>;\r\n warnings: Array<{\r\n client: string;\r\n property: string;\r\n severity: string;\r\n message: string;\r\n suggestion?: string;\r\n fix?: {\r\n before: string;\r\n after: string;\r\n language: string;\r\n description: string;\r\n };\r\n }>;\r\n transforms?: Array<{\r\n clientId: string;\r\n html: string;\r\n }>;\r\n darkMode?: Record<string, {\r\n html: string;\r\n warningCount: number;\r\n }>;\r\n}\r\n\r\n/**\r\n * Build the JSON output object. Reusable by both printJson() and export command.\r\n */\r\nexport function formatJsonOutput(opts: {\r\n scores: Record<string, { score: number; errors: number; warnings: number; info: number }>;\r\n warnings: CSSWarning[];\r\n transforms?: TransformResult[];\r\n darkMode?: Record<string, { html: string; warnings: CSSWarning[] }>;\r\n}): JsonOutput {\r\n const scoreValues = Object.values(opts.scores);\r\n const overallScore = scoreValues.length > 0\r\n ? Math.round(scoreValues.reduce((a, b) => a + b.score, 0) / scoreValues.length)\r\n : 0;\r\n\r\n const output: JsonOutput = {\r\n overallScore,\r\n scores: opts.scores,\r\n warnings: opts.warnings.map((w) => ({\r\n client: w.client,\r\n property: w.property,\r\n severity: w.severity,\r\n message: w.message,\r\n suggestion: w.suggestion,\r\n fix: w.fix ? {\r\n before: w.fix.before,\r\n after: w.fix.after,\r\n language: w.fix.language,\r\n description: w.fix.description,\r\n } : undefined,\r\n })),\r\n };\r\n\r\n if (opts.transforms) {\r\n output.transforms = opts.transforms.map((t) => ({\r\n clientId: t.clientId,\r\n html: t.html,\r\n }));\r\n }\r\n\r\n if (opts.darkMode) {\r\n output.darkMode = {};\r\n for (const [clientId, dm] of Object.entries(opts.darkMode)) {\r\n output.darkMode[clientId] = {\r\n html: dm.html,\r\n warningCount: dm.warnings.length,\r\n };\r\n }\r\n }\r\n\r\n return output;\r\n}\r\n\r\n/**\r\n * Format analysis/preview results as JSON and print to stdout.\r\n */\r\nexport function printJson(opts: {\r\n scores: Record<string, { score: number; errors: number; warnings: number; info: number }>;\r\n warnings: CSSWarning[];\r\n transforms?: TransformResult[];\r\n darkMode?: Record<string, { html: string; warnings: CSSWarning[] }>;\r\n}): void {\r\n console.log(JSON.stringify(formatJsonOutput(opts), null, 2));\r\n}\r\n","import { defineCommand } from \"citty\";\r\nimport ora from \"ora\";\r\nimport {\r\n transformForAllClients,\r\n analyzeEmail,\r\n generateCompatibilityScore,\r\n simulateDarkMode,\r\n warningsForClient,\r\n CompileError,\r\n type CSSWarning,\r\n} from \"@emailens/engine\";\r\nimport { readInput, resolveClients, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\nimport { printScoreTable, printWarnings } from \"../output/terminal.js\";\r\nimport { printJson } from \"../output/json.js\";\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"preview\",\r\n description: \"Full email preview: transforms, analysis, dark mode, screenshots\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or - for stdin\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n clients: {\r\n type: \"string\",\r\n alias: \"c\",\r\n description: \"Comma-separated client IDs to filter\",\r\n },\r\n \"dark-mode\": {\r\n type: \"boolean\",\r\n alias: \"d\",\r\n description: \"Include dark mode simulation\",\r\n },\r\n screenshots: {\r\n type: \"boolean\",\r\n description: \"Capture screenshots (requires BROWSERLESS_URL)\",\r\n },\r\n out: {\r\n type: \"string\",\r\n alias: \"o\",\r\n description: \"Output directory for screenshots\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON\",\r\n },\r\n quiet: {\r\n type: \"boolean\",\r\n alias: \"q\",\r\n description: \"Suppress spinners and decorations\",\r\n },\r\n },\r\n async run({ args }) {\r\n const spinner = (args.quiet || args.json) ? null : ora();\r\n\r\n try {\r\n // Resolve format early so we fail fast on invalid --format\r\n const format = resolveFormat(args.format, args.input);\r\n\r\n // Read input\r\n spinner?.start(\"Reading input...\");\r\n const source = await readInput(args.input);\r\n spinner?.succeed(\"Input read\");\r\n\r\n // Compile (passthrough for html, auto-detects from extension)\r\n const html = await compile(source, format, args.input !== \"-\" ? args.input : undefined);\r\n\r\n // Resolve clients\r\n const clientIds = resolveClients(args.clients);\r\n const clientSet = new Set(clientIds);\r\n\r\n // Transform\r\n spinner?.start(\"Transforming for all clients...\");\r\n const allTransforms = transformForAllClients(html);\r\n const transforms = allTransforms.filter((t) => clientSet.has(t.clientId));\r\n spinner?.succeed(`Transformed for ${transforms.length} clients`);\r\n\r\n // Analyze\r\n spinner?.start(\"Analyzing compatibility...\");\r\n const framework = toFramework(format);\r\n const warnings = analyzeEmail(html, framework);\r\n const allScores = generateCompatibilityScore(warnings);\r\n\r\n const scores: typeof allScores = {};\r\n for (const [id, data] of Object.entries(allScores)) {\r\n if (clientSet.has(id)) {\r\n scores[id] = data;\r\n }\r\n }\r\n const filteredWarnings = clientIds.flatMap(id => warningsForClient(warnings, id));\r\n spinner?.succeed(\"Analysis complete\");\r\n\r\n // Dark mode\r\n let darkMode: Record<string, { html: string; warnings: CSSWarning[] }> | undefined;\r\n if (args[\"dark-mode\"]) {\r\n spinner?.start(\"Simulating dark mode...\");\r\n darkMode = {};\r\n for (const t of transforms) {\r\n darkMode[t.clientId] = simulateDarkMode(t.html, t.clientId);\r\n }\r\n spinner?.succeed(\"Dark mode simulation complete\");\r\n }\r\n\r\n // Screenshots\r\n if (args.screenshots) {\r\n const outDir = args.out ?? \"./emailens-screenshots\";\r\n spinner?.start(\"Capturing screenshots...\");\r\n try {\r\n const { captureScreenshots } = await import(\"../screenshots.js\");\r\n const results = await captureScreenshots(\r\n transforms,\r\n outDir,\r\n (clientId, index, total) => {\r\n if (spinner) spinner.text = `Capturing screenshots (${index}/${total}: ${clientId})...`;\r\n },\r\n );\r\n spinner?.succeed(`Screenshots saved to ${outDir} (${results.size} files)`);\r\n } catch (err) {\r\n spinner?.warn(`Screenshots skipped: ${(err as Error).message}`);\r\n }\r\n }\r\n\r\n // Output\r\n if (args.json) {\r\n printJson({ scores, warnings: filteredWarnings, transforms, darkMode });\r\n } else {\r\n printScoreTable(scores, filteredWarnings, { quiet: args.quiet });\r\n printWarnings(filteredWarnings, { quiet: args.quiet });\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);\r\n } else {\r\n spinner?.fail((err as Error).message);\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n","import { defineCommand } from \"citty\";\r\nimport pc from \"picocolors\";\r\nimport Table from \"cli-table3\";\r\nimport { EMAIL_CLIENTS } from \"@emailens/engine\";\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"clients\",\r\n description: \"List all supported email clients\",\r\n },\r\n args: {\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON\",\r\n },\r\n },\r\n run({ args }) {\r\n if (args.json) {\r\n const data = EMAIL_CLIENTS.map((c) => ({\r\n id: c.id,\r\n name: c.name,\r\n category: c.category,\r\n engine: c.engine,\r\n darkModeSupport: c.darkModeSupport,\r\n }));\r\n console.log(JSON.stringify(data, null, 2));\r\n return;\r\n }\r\n\r\n console.log();\r\n console.log(pc.bold(\" Emailens — Supported Email Clients\"));\r\n console.log();\r\n\r\n const table = new Table({\r\n head: [\r\n pc.bold(\"ID\"),\r\n pc.bold(\"Name\"),\r\n pc.bold(\"Category\"),\r\n pc.bold(\"Engine\"),\r\n pc.bold(\"Dark Mode\"),\r\n ],\r\n style: { head: [], border: [] },\r\n });\r\n\r\n for (const client of EMAIL_CLIENTS) {\r\n table.push([\r\n client.id,\r\n client.name,\r\n client.category,\r\n client.engine,\r\n client.darkModeSupport ? pc.green(\"Yes\") : pc.dim(\"No\"),\r\n ]);\r\n }\r\n\r\n console.log(table.toString());\r\n console.log();\r\n console.log(pc.dim(` ${EMAIL_CLIENTS.length} clients supported`));\r\n console.log();\r\n },\r\n});\r\n","import { mkdirSync, writeFileSync } from \"node:fs\";\r\nimport { join, resolve } from \"node:path\";\r\nimport { defineCommand } from \"citty\";\r\nimport ora from \"ora\";\r\nimport {\r\n transformForAllClients,\r\n analyzeEmail,\r\n generateCompatibilityScore,\r\n simulateDarkMode,\r\n warningsForClient,\r\n CompileError,\r\n type CSSWarning,\r\n} from \"@emailens/engine\";\r\n\r\n// toPlainText available in engine >=0.8.6\r\nlet toPlainText: ((html: string) => string) | null = null;\r\ntry {\r\n // eslint-disable-next-line @typescript-eslint/no-require-imports\r\n ({ toPlainText } = require(\"@emailens/engine\"));\r\n} catch {\r\n // older engine version\r\n}\r\nimport { readInput, resolveClients, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\nimport { generateHtmlReport } from \"../output/html-report.js\";\r\nimport { formatJsonOutput } from \"../output/json.js\";\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"export\",\r\n description: \"Export compatibility report as JSON or HTML\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or - for stdin\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n clients: {\r\n type: \"string\",\r\n alias: \"c\",\r\n description: \"Comma-separated client IDs to filter\",\r\n },\r\n \"dark-mode\": {\r\n type: \"boolean\",\r\n alias: \"d\",\r\n description: \"Include dark mode simulation\",\r\n },\r\n screenshots: {\r\n type: \"boolean\",\r\n description: \"Capture screenshots (requires BROWSERLESS_URL)\",\r\n },\r\n out: {\r\n type: \"string\",\r\n alias: \"o\",\r\n description: \"Output directory (default: ./emailens-report)\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Export as JSON instead of HTML\",\r\n },\r\n \"plain-text\": {\r\n type: \"boolean\",\r\n description: \"Also export a plain text version (.txt) for multipart emails\",\r\n },\r\n quiet: {\r\n type: \"boolean\",\r\n alias: \"q\",\r\n description: \"Suppress spinners and decorations\",\r\n },\r\n },\r\n async run({ args }) {\r\n const spinner = args.quiet ? null : ora();\r\n const outDir = resolve(args.out ?? \"./emailens-report\");\r\n\r\n try {\r\n // Resolve format early so we fail fast on invalid --format\r\n const format = resolveFormat(args.format, args.input);\r\n\r\n // Read input\r\n spinner?.start(\"Reading input...\");\r\n const source = await readInput(args.input);\r\n spinner?.succeed(\"Input read\");\r\n\r\n // Compile (passthrough for html, auto-detects from extension)\r\n const html = await compile(source, format, args.input !== \"-\" ? args.input : undefined);\r\n\r\n // Resolve clients\r\n const clientIds = resolveClients(args.clients);\r\n const clientSet = new Set(clientIds);\r\n\r\n // Transform\r\n spinner?.start(\"Transforming for all clients...\");\r\n const allTransforms = transformForAllClients(html);\r\n const transforms = allTransforms.filter((t) => clientSet.has(t.clientId));\r\n spinner?.succeed(`Transformed for ${transforms.length} clients`);\r\n\r\n // Analyze\r\n spinner?.start(\"Analyzing compatibility...\");\r\n const framework = toFramework(format);\r\n const warnings = analyzeEmail(html, framework);\r\n const allScores = generateCompatibilityScore(warnings);\r\n\r\n const scores: typeof allScores = {};\r\n for (const [id, data] of Object.entries(allScores)) {\r\n if (clientSet.has(id)) {\r\n scores[id] = data;\r\n }\r\n }\r\n const filteredWarnings = clientIds.flatMap(id => warningsForClient(warnings, id));\r\n spinner?.succeed(\"Analysis complete\");\r\n\r\n // Dark mode\r\n let darkMode: Record<string, { html: string; warnings: CSSWarning[] }> | undefined;\r\n if (args[\"dark-mode\"]) {\r\n spinner?.start(\"Simulating dark mode...\");\r\n darkMode = {};\r\n for (const t of transforms) {\r\n darkMode[t.clientId] = simulateDarkMode(t.html, t.clientId);\r\n }\r\n spinner?.succeed(\"Dark mode simulation complete\");\r\n }\r\n\r\n // Screenshots\r\n if (args.screenshots) {\r\n spinner?.start(\"Capturing screenshots...\");\r\n try {\r\n const { captureScreenshots } = await import(\"../screenshots.js\");\r\n const screenshotDir = join(outDir, \"screenshots\");\r\n const results = await captureScreenshots(\r\n transforms,\r\n screenshotDir,\r\n (clientId, index, total) => {\r\n if (spinner) spinner.text = `Capturing screenshots (${index}/${total}: ${clientId})...`;\r\n },\r\n );\r\n spinner?.succeed(`Screenshots saved (${results.size} files)`);\r\n } catch (err) {\r\n spinner?.warn(`Screenshots skipped: ${(err as Error).message}`);\r\n }\r\n }\r\n\r\n // Export\r\n mkdirSync(outDir, { recursive: true });\r\n\r\n if (args.json) {\r\n spinner?.start(\"Exporting JSON...\");\r\n const jsonData = formatJsonOutput({ scores, warnings: filteredWarnings, transforms });\r\n const jsonPath = join(outDir, \"report.json\");\r\n writeFileSync(jsonPath, JSON.stringify(jsonData, null, 2));\r\n spinner?.succeed(`JSON report saved to ${jsonPath}`);\r\n } else {\r\n spinner?.start(\"Generating HTML report...\");\r\n const htmlReport = generateHtmlReport({\r\n scores,\r\n warnings: filteredWarnings,\r\n transforms,\r\n darkMode,\r\n originalHtml: html,\r\n });\r\n\r\n const htmlPath = join(outDir, \"report.html\");\r\n writeFileSync(htmlPath, htmlReport);\r\n spinner?.succeed(`HTML report saved to ${htmlPath}`);\r\n }\r\n\r\n // Plain text export\r\n if (args[\"plain-text\"] && toPlainText) {\r\n spinner?.start(\"Generating plain text version...\");\r\n const plainText = toPlainText(html);\r\n const txtPath = join(outDir, \"email.txt\");\r\n writeFileSync(txtPath, plainText);\r\n spinner?.succeed(`Plain text saved to ${txtPath}`);\r\n } else if (args[\"plain-text\"] && !toPlainText) {\r\n spinner?.warn(\"Plain text export requires @emailens/engine >=0.8.6\");\r\n }\r\n\r\n if (!args.quiet) {\r\n console.log();\r\n console.log(` Output: ${outDir}`);\r\n console.log();\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);\r\n } else {\r\n spinner?.fail((err as Error).message);\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n","import { EMAIL_CLIENTS, type CSSWarning, type TransformResult } from \"@emailens/engine\";\r\n\r\n/**\r\n * Generate a self-contained HTML report file.\r\n */\r\nexport function generateHtmlReport(opts: {\r\n scores: Record<string, { score: number; errors: number; warnings: number; info: number }>;\r\n warnings: CSSWarning[];\r\n transforms?: TransformResult[];\r\n darkMode?: Record<string, { html: string; warnings: CSSWarning[] }>;\r\n originalHtml?: string;\r\n}): string {\r\n const clientMap = new Map(EMAIL_CLIENTS.map((c) => [c.id, c]));\r\n\r\n const scoreValues = Object.values(opts.scores);\r\n const overallScore = scoreValues.length > 0\r\n ? Math.round(scoreValues.reduce((a, b) => a + b.score, 0) / scoreValues.length)\r\n : 0;\r\n\r\n const scoreColor = (s: number) => s >= 90 ? \"#22c55e\" : s >= 70 ? \"#eab308\" : \"#ef4444\";\r\n\r\n // Build client cards\r\n const clientCards = Object.entries(opts.scores)\r\n .sort(([, a], [, b]) => a.score - b.score)\r\n .map(([clientId, { score, errors, warnings: warns, info }]) => {\r\n const client = clientMap.get(clientId);\r\n const name = client?.name ?? clientId;\r\n const clientWarnings = opts.warnings.filter((w) => w.client === clientId);\r\n const issueCount = errors + warns + info;\r\n\r\n const warningRows = clientWarnings.map((w) => {\r\n const icon = w.severity === \"error\" ? \"&#10007;\" : w.severity === \"warning\" ? \"&#9888;\" : \"&#8505;\";\r\n const color = w.severity === \"error\" ? \"#ef4444\" : w.severity === \"warning\" ? \"#eab308\" : \"#3b82f6\";\r\n return `<div style=\"padding:4px 0;border-bottom:1px solid #f1f1f1\">\r\n <span style=\"color:${color}\">${icon}</span>\r\n <strong>${escapeHtml(w.property)}</strong> — ${escapeHtml(w.message)}\r\n ${w.suggestion ? `<br><span style=\"color:#888;margin-left:20px\">&rarr; ${escapeHtml(w.suggestion)}</span>` : \"\"}\r\n </div>`;\r\n }).join(\"\");\r\n\r\n return `<div style=\"border:1px solid #e5e5e5;border-radius:8px;padding:16px;margin-bottom:16px\">\r\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px\">\r\n <h3 style=\"margin:0;font-size:16px\">${escapeHtml(name)}</h3>\r\n <span style=\"font-size:24px;font-weight:bold;color:${scoreColor(score)}\">${score}</span>\r\n </div>\r\n <div style=\"font-size:13px;color:#888;margin-bottom:8px\">${client?.engine ?? \"\"} &middot; ${client?.category ?? \"\"} &middot; ${issueCount} issue${issueCount === 1 ? \"\" : \"s\"}</div>\r\n ${clientWarnings.length > 0 ? `<div style=\"font-size:13px\">${warningRows}</div>` : '<div style=\"color:#22c55e;font-size:13px\">No issues</div>'}\r\n </div>`;\r\n }).join(\"\");\r\n\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"utf-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n<title>Emailens Compatibility Report</title>\r\n<style>\r\n * { box-sizing: border-box; }\r\n body { font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif; margin: 0; padding: 24px; background: #fafafa; color: #333; }\r\n .container { max-width: 900px; margin: 0 auto; }\r\n .header { text-align: center; margin-bottom: 32px; }\r\n .header h1 { margin: 0 0 8px; font-size: 24px; }\r\n .overall { font-size: 48px; font-weight: bold; }\r\n .subtitle { color: #888; font-size: 14px; }\r\n .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); gap: 16px; }\r\n .footer { text-align: center; margin-top: 32px; color: #aaa; font-size: 12px; }\r\n</style>\r\n</head>\r\n<body>\r\n<div class=\"container\">\r\n <div class=\"header\">\r\n <h1>Emailens Compatibility Report</h1>\r\n <div class=\"overall\" style=\"color:${scoreColor(overallScore)}\">${overallScore}/100</div>\r\n <div class=\"subtitle\">${Object.keys(opts.scores).length} clients analyzed &middot; ${opts.warnings.length} total issues</div>\r\n </div>\r\n <div class=\"grid\">\r\n ${clientCards}\r\n </div>\r\n <div class=\"footer\">\r\n Generated by <a href=\"https://github.com/emailens/cli\" style=\"color:#888\">@emailens/cli</a>\r\n </div>\r\n</div>\r\n</body>\r\n</html>`;\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, \"&amp;\")\r\n .replace(/</g, \"&lt;\")\r\n .replace(/>/g, \"&gt;\")\r\n .replace(/\"/g, \"&quot;\");\r\n}\r\n","import { defineCommand } from \"citty\";\r\nimport ora from \"ora\";\r\nimport pc from \"picocolors\";\r\nimport {\r\n analyzeEmail,\r\n generateCompatibilityScore,\r\n generateAiFix,\r\n estimateAiFixTokens,\r\n AI_FIX_SYSTEM_PROMPT,\r\n CompileError,\r\n type AiProvider,\r\n} from \"@emailens/engine\";\r\nimport { readInput, resolveClients, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"fix\",\r\n description: \"Generate AI-powered fixes for email compatibility issues\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or - for stdin\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n clients: {\r\n type: \"string\",\r\n alias: \"c\",\r\n description: \"Comma-separated client IDs to scope the fix\",\r\n },\r\n output: {\r\n type: \"string\",\r\n alias: \"o\",\r\n description: \"Write fixed code to file instead of stdout\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON (includes token estimates and metadata)\",\r\n },\r\n quiet: {\r\n type: \"boolean\",\r\n alias: \"q\",\r\n description: \"Suppress spinners and decorations\",\r\n },\r\n estimate: {\r\n type: \"boolean\",\r\n description: \"Only show token estimate without calling the AI\",\r\n },\r\n \"max-tokens\": {\r\n type: \"string\",\r\n description: \"Maximum input tokens for the prompt (default: 16000)\",\r\n },\r\n },\r\n async run({ args }) {\r\n const spinner = (args.quiet || args.json) ? null : ora();\r\n\r\n try {\r\n const format = resolveFormat(args.format, args.input);\r\n const framework = toFramework(format);\r\n\r\n // Read and compile input\r\n spinner?.start(\"Reading input...\");\r\n const source = await readInput(args.input);\r\n const html = await compile(source, format, args.input !== \"-\" ? args.input : undefined);\r\n spinner?.succeed(\"Input read\");\r\n\r\n // Analyze\r\n spinner?.start(\"Analyzing compatibility...\");\r\n const warnings = analyzeEmail(html, framework);\r\n const scores = generateCompatibilityScore(warnings);\r\n spinner?.succeed(`Found ${warnings.length} warnings`);\r\n\r\n if (warnings.length === 0) {\r\n if (args.json) {\r\n console.log(JSON.stringify({ message: \"No issues found\", code: source }, null, 2));\r\n } else {\r\n console.log(pc.green(\"\\n No compatibility issues found — nothing to fix.\\n\"));\r\n }\r\n return;\r\n }\r\n\r\n // Resolve scope\r\n const clientIds = resolveClients(args.clients);\r\n let scope: \"current\" | \"all\";\r\n let selectedClientId: string | undefined;\r\n let scopedWarnings = warnings;\r\n let scopedScores = scores;\r\n\r\n if (args.clients && clientIds.length === 1) {\r\n // Single client: use engine's \"current\" scope\r\n scope = \"current\";\r\n selectedClientId = clientIds[0];\r\n } else if (args.clients && clientIds.length > 1) {\r\n // Multiple clients: pre-filter warnings/scores, then use \"all\" scope\r\n // so the engine processes all of them without needing \"current\" + single ID\r\n const clientSet = new Set(clientIds);\r\n scope = \"all\";\r\n selectedClientId = undefined;\r\n scopedWarnings = warnings.filter((w) => clientSet.has(w.client));\r\n scopedScores = Object.fromEntries(\r\n Object.entries(scores).filter(([id]) => clientSet.has(id)),\r\n );\r\n } else {\r\n // No --clients flag: fix for all clients\r\n scope = \"all\";\r\n selectedClientId = undefined;\r\n }\r\n\r\n // Token estimate\r\n const maxInputTokens = args[\"max-tokens\"] ? parseInt(args[\"max-tokens\"], 10) : 16000;\r\n const estimate = await estimateAiFixTokens({\r\n originalHtml: html,\r\n warnings: scopedWarnings,\r\n scores: scopedScores,\r\n scope,\r\n selectedClientId,\r\n format,\r\n maxInputTokens,\r\n });\r\n\r\n const structuralPct = estimate.warningCount > 0\r\n ? Math.round((estimate.structuralCount / estimate.warningCount) * 100)\r\n : 0;\r\n\r\n if (args.estimate) {\r\n if (args.json) {\r\n console.log(JSON.stringify(estimate, null, 2));\r\n } else {\r\n console.log(`\\n ${pc.bold(\"Token Estimate\")}`);\r\n console.log(` Input tokens: ~${estimate.inputTokens.toLocaleString()}`);\r\n console.log(` Output tokens: ~${estimate.estimatedOutputTokens.toLocaleString()}`);\r\n console.log(` Warnings: ${estimate.warningCount} (${estimate.structuralCount} structural)`);\r\n if (estimate.truncated) {\r\n console.log(` ${pc.yellow(`Truncated: ${estimate.warningsRemoved} low-priority warnings removed`)}`);\r\n }\r\n console.log();\r\n }\r\n return;\r\n }\r\n\r\n // Check for API key\r\n const apiKey = process.env.ANTHROPIC_API_KEY;\r\n if (!apiKey) {\r\n spinner?.fail(\"ANTHROPIC_API_KEY environment variable is required\");\r\n console.error(pc.dim(\"\\n Set it with: export ANTHROPIC_API_KEY=sk-ant-...\\n\"));\r\n process.exit(1);\r\n }\r\n\r\n // Show estimate before calling\r\n if (!args.quiet && !args.json) {\r\n console.log(pc.dim(` ~${estimate.inputTokens.toLocaleString()} input tokens, ${estimate.warningCount} warnings (${structuralPct}% structural)`));\r\n if (estimate.truncated) {\r\n console.log(pc.yellow(` Truncated ${estimate.warningsRemoved} low-priority warnings to fit token limit`));\r\n }\r\n }\r\n\r\n // Call AI\r\n spinner?.start(\"Generating AI fix...\");\r\n\r\n let Anthropic: typeof import(\"@anthropic-ai/sdk\").default;\r\n try {\r\n Anthropic = (await import(\"@anthropic-ai/sdk\")).default;\r\n } catch {\r\n spinner?.fail(\"@anthropic-ai/sdk is required for the fix command\");\r\n console.error(pc.dim(\"\\n Install it with: npm install @anthropic-ai/sdk\\n\"));\r\n process.exit(1);\r\n }\r\n\r\n const anthropic = new Anthropic({ apiKey });\r\n\r\n const provider: AiProvider = async (prompt) => {\r\n const msg = await anthropic.messages.create({\r\n model: \"claude-sonnet-4-6\",\r\n max_tokens: 8192,\r\n system: AI_FIX_SYSTEM_PROMPT,\r\n messages: [{ role: \"user\", content: prompt }],\r\n });\r\n const textBlock = msg.content.find((b: { type: string }) => b.type === \"text\");\r\n return textBlock?.type === \"text\" ? (textBlock as { type: \"text\"; text: string }).text : \"\";\r\n };\r\n\r\n const result = await generateAiFix({\r\n originalHtml: html,\r\n warnings: scopedWarnings,\r\n scores: scopedScores,\r\n scope,\r\n selectedClientId,\r\n format,\r\n maxInputTokens,\r\n provider,\r\n });\r\n\r\n spinner?.succeed(`Fixed ${result.targetedWarnings} warnings (${result.structuralCount} structural)`);\r\n\r\n // Output\r\n if (args.output) {\r\n const { writeFileSync } = await import(\"node:fs\");\r\n writeFileSync(args.output, result.code, \"utf-8\");\r\n if (!args.quiet) {\r\n console.log(pc.green(`\\n Fixed code written to ${args.output}\\n`));\r\n }\r\n } else if (args.json) {\r\n console.log(JSON.stringify({\r\n code: result.code,\r\n targetedWarnings: result.targetedWarnings,\r\n structuralCount: result.structuralCount,\r\n tokenEstimate: result.tokenEstimate,\r\n }, null, 2));\r\n } else {\r\n console.log(\"\\n\" + result.code);\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);\r\n } else {\r\n spinner?.fail((err as Error).message);\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n","import { defineCommand } from \"citty\";\r\nimport ora from \"ora\";\r\nimport pc from \"picocolors\";\r\nimport Table from \"cli-table3\";\r\nimport {\r\n auditEmail,\r\n CompileError,\r\n type AuditReport,\r\n} from \"@emailens/engine\";\r\nimport { readInput, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\nimport { printScoreTable, printWarnings } from \"../output/terminal.js\";\r\n\r\nconst VALID_SKIPS = new Set([\"spam\", \"links\", \"accessibility\", \"images\", \"compatibility\"]);\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"audit\",\r\n description: \"Full email audit: compatibility + spam + links + accessibility + images\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or - for stdin\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON\",\r\n },\r\n quiet: {\r\n type: \"boolean\",\r\n alias: \"q\",\r\n description: \"Suppress spinners and decorations\",\r\n },\r\n skip: {\r\n type: \"string\",\r\n description: \"Comma-separated checks to skip: spam,links,accessibility,images,compatibility\",\r\n },\r\n },\r\n async run({ args }) {\r\n const spinner = (args.quiet || args.json) ? null : ora();\r\n\r\n try {\r\n const format = resolveFormat(args.format, args.input);\r\n\r\n // Read input\r\n spinner?.start(\"Reading input...\");\r\n const source = await readInput(args.input);\r\n spinner?.succeed(\"Input read\");\r\n\r\n // Compile\r\n const html = await compile(source, format, args.input !== \"-\" ? args.input : undefined);\r\n\r\n // Parse --skip flag\r\n const skip: Array<\"spam\" | \"links\" | \"accessibility\" | \"images\" | \"compatibility\"> = [];\r\n if (args.skip) {\r\n for (const s of args.skip.split(\",\").map((s) => s.trim()).filter(Boolean)) {\r\n if (!VALID_SKIPS.has(s)) {\r\n throw new Error(`Unknown skip value \"${s}\". Valid: ${Array.from(VALID_SKIPS).join(\", \")}`);\r\n }\r\n skip.push(s as typeof skip[number]);\r\n }\r\n }\r\n\r\n // Run audit\r\n spinner?.start(\"Running full audit...\");\r\n const framework = toFramework(format);\r\n const report = auditEmail(html, { framework, skip });\r\n spinner?.succeed(\"Audit complete\");\r\n\r\n // Output\r\n if (args.json) {\r\n console.log(JSON.stringify(report, null, 2));\r\n } else {\r\n // Compatibility section\r\n if (!skip.includes(\"compatibility\")) {\r\n printScoreTable(report.compatibility.scores, report.compatibility.warnings, { quiet: args.quiet });\r\n printWarnings(report.compatibility.warnings, { quiet: args.quiet });\r\n }\r\n\r\n // Quality summary\r\n printQualitySummary(report, skip, { quiet: args.quiet });\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);\r\n } else {\r\n spinner?.fail((err as Error).message);\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n\r\nfunction printQualitySummary(\r\n report: AuditReport,\r\n skip: string[],\r\n options?: { quiet?: boolean },\r\n): void {\r\n if (!options?.quiet) {\r\n console.log(pc.bold(\" Quality Summary\"));\r\n console.log();\r\n }\r\n\r\n const table = new Table({\r\n head: [pc.bold(\"Check\"), pc.bold(\"Result\")],\r\n style: { head: [], border: [] },\r\n });\r\n\r\n if (!skip.includes(\"spam\")) {\r\n const { score, level, issues } = report.spam;\r\n const color = score >= 90 ? pc.green : score >= 70 ? pc.yellow : pc.red;\r\n table.push([\"Content Hygiene\", `${color(String(score))}/100 (${level}) — ${issues.length} issue${issues.length === 1 ? \"\" : \"s\"}`]);\r\n }\r\n\r\n if (!skip.includes(\"links\")) {\r\n const { totalLinks, issues } = report.links;\r\n const color = issues.length === 0 ? pc.green : pc.yellow;\r\n table.push([\"Links\", `${totalLinks} link${totalLinks === 1 ? \"\" : \"s\"} — ${color(`${issues.length} issue${issues.length === 1 ? \"\" : \"s\"}`)}`]);\r\n }\r\n\r\n if (!skip.includes(\"accessibility\")) {\r\n const { score, issues } = report.accessibility;\r\n const color = score >= 90 ? pc.green : score >= 70 ? pc.yellow : pc.red;\r\n table.push([\"Accessibility\", `${color(String(score))}/100 — ${issues.length} issue${issues.length === 1 ? \"\" : \"s\"}`]);\r\n }\r\n\r\n if (!skip.includes(\"images\")) {\r\n const { total, issues } = report.images;\r\n const color = issues.length === 0 ? pc.green : pc.yellow;\r\n table.push([\"Images\", `${total} image${total === 1 ? \"\" : \"s\"} — ${color(`${issues.length} issue${issues.length === 1 ? \"\" : \"s\"}`)}`]);\r\n }\r\n\r\n console.log(table.toString());\r\n console.log();\r\n}\r\n","import { defineCommand } from \"citty\";\r\nimport pc from \"picocolors\";\r\nimport { readInput, resolveFormat, toFramework } from \"../utils.js\";\r\nimport { compile } from \"@emailens/engine/compile\";\r\nimport {\r\n auditEmail,\r\n CompileError,\r\n type AuditReport,\r\n} from \"@emailens/engine\";\r\nimport { readdir } from \"node:fs/promises\";\r\nimport { resolve, relative } from \"node:path\";\r\n\r\ninterface LintIssue {\r\n severity: \"error\" | \"warning\" | \"info\";\r\n category: string;\r\n rule: string;\r\n message: string;\r\n detail?: string;\r\n}\r\n\r\ninterface LintFileResult {\r\n file: string;\r\n issues: LintIssue[];\r\n errors: number;\r\n warnings: number;\r\n}\r\n\r\nconst VALID_SKIPS = new Set([\r\n \"spam\", \"links\", \"accessibility\", \"images\",\r\n \"compatibility\", \"inboxPreview\", \"size\", \"templateVariables\",\r\n]);\r\n\r\nexport default defineCommand({\r\n meta: {\r\n name: \"lint\",\r\n description: \"Lint HTML emails for compatibility, spam, accessibility, and more. CI/CD-friendly with structured exit codes.\",\r\n },\r\n args: {\r\n input: {\r\n type: \"positional\",\r\n description: \"HTML file path or glob pattern\",\r\n required: true,\r\n },\r\n format: {\r\n type: \"string\",\r\n alias: \"f\",\r\n description: \"Input format: html, jsx, mjml, maizzle\",\r\n },\r\n json: {\r\n type: \"boolean\",\r\n description: \"Output as JSON\",\r\n },\r\n failOnWarning: {\r\n type: \"boolean\",\r\n description: \"Exit 2 if warnings found\",\r\n },\r\n skip: {\r\n type: \"string\",\r\n description: \"Comma-separated checks to skip: spam,links,accessibility,images,compatibility,inboxPreview,size,templateVariables\",\r\n },\r\n maxWarnings: {\r\n type: \"string\",\r\n description: \"Fail if more than n warnings\",\r\n },\r\n },\r\n async run({ args }) {\r\n try {\r\n // Parse --skip\r\n const skip: Array<string> = [];\r\n if (args.skip) {\r\n for (const s of args.skip.split(\",\").map((s) => s.trim()).filter(Boolean)) {\r\n if (!VALID_SKIPS.has(s)) {\r\n throw new Error(`Unknown skip value \"${s}\". Valid: ${Array.from(VALID_SKIPS).join(\", \")}`);\r\n }\r\n skip.push(s);\r\n }\r\n }\r\n\r\n const maxWarningsRaw = args.maxWarnings !== undefined ? parseInt(args.maxWarnings, 10) : undefined;\r\n if (maxWarningsRaw !== undefined && isNaN(maxWarningsRaw)) {\r\n throw new Error(`--maxWarnings must be a number, got: ${args.maxWarnings}`);\r\n }\r\n const maxWarnings = maxWarningsRaw ?? Infinity;\r\n const files = await resolveGlob(args.input);\r\n\r\n if (files.length === 0) {\r\n if (args.json) {\r\n console.log(JSON.stringify({ files: [], totalErrors: 0, totalWarnings: 0 }));\r\n } else {\r\n console.error(pc.red(`No files found matching: ${args.input}`));\r\n }\r\n process.exit(1);\r\n }\r\n\r\n const results: LintFileResult[] = [];\r\n let totalErrors = 0;\r\n let totalWarnings = 0;\r\n\r\n for (const file of files) {\r\n const format = resolveFormat(args.format, file);\r\n const source = await readInput(file);\r\n const html = await compile(source, format, file);\r\n const framework = toFramework(format);\r\n\r\n const report = auditEmail(html, {\r\n framework,\r\n skip: skip as AuditSkipType[],\r\n });\r\n\r\n const issues = flattenToLintIssues(report, skip);\r\n const errors = issues.filter((i) => i.severity === \"error\").length;\r\n const warnings = issues.filter((i) => i.severity === \"warning\").length;\r\n\r\n results.push({ file: relative(process.cwd(), file), issues, errors, warnings });\r\n totalErrors += errors;\r\n totalWarnings += warnings;\r\n }\r\n\r\n // Output\r\n if (args.json) {\r\n console.log(JSON.stringify({ files: results, totalErrors, totalWarnings }, null, 2));\r\n } else {\r\n for (const result of results) {\r\n console.log(pc.underline(result.file));\r\n if (result.issues.length === 0) {\r\n console.log(` ${pc.green(\"pass\")} No issues found`);\r\n } else {\r\n for (const issue of result.issues) {\r\n const sev = issue.severity === \"error\"\r\n ? pc.red(\"error\")\r\n : issue.severity === \"warning\"\r\n ? pc.yellow(\"warn \")\r\n : pc.blue(\"info \");\r\n console.log(` ${sev} ${pc.dim(issue.category.padEnd(18))} ${pc.bold(issue.rule.padEnd(22))} ${issue.message}`);\r\n }\r\n }\r\n console.log();\r\n }\r\n\r\n const summary = [\r\n `${files.length} file${files.length === 1 ? \"\" : \"s\"}`,\r\n totalErrors > 0 ? pc.red(`${totalErrors} error${totalErrors === 1 ? \"\" : \"s\"}`) : null,\r\n totalWarnings > 0 ? pc.yellow(`${totalWarnings} warning${totalWarnings === 1 ? \"\" : \"s\"}`) : null,\r\n totalErrors === 0 && totalWarnings === 0 ? pc.green(\"all clean\") : null,\r\n ].filter(Boolean).join(\" | \");\r\n\r\n console.log(summary);\r\n }\r\n\r\n // Exit codes\r\n if (totalErrors > 0) {\r\n process.exit(1);\r\n }\r\n if (args.failOnWarning && totalWarnings > 0) {\r\n if (!args.json) {\r\n console.error(pc.yellow(`\\nFailed: ${totalWarnings} warning${totalWarnings === 1 ? \"\" : \"s\"} found (--failOnWarning)`));\r\n }\r\n process.exit(2);\r\n }\r\n if (Number.isFinite(maxWarnings) && totalWarnings > maxWarnings) {\r\n if (!args.json) {\r\n console.error(pc.red(`\\nExceeded max warnings: ${totalWarnings} > ${maxWarnings}`));\r\n }\r\n process.exit(2);\r\n }\r\n } catch (err) {\r\n if (err instanceof CompileError) {\r\n console.error(pc.red(`Compilation failed (${err.phase}): ${err.message}`));\r\n } else {\r\n console.error(pc.red((err as Error).message));\r\n }\r\n process.exit(1);\r\n }\r\n },\r\n});\r\n\r\ntype AuditSkipType = \"spam\" | \"links\" | \"accessibility\" | \"images\" | \"compatibility\" | \"inboxPreview\" | \"size\" | \"templateVariables\";\r\n\r\n/**\r\n * Resolve a file path or simple glob pattern to an array of files.\r\n * Supports basic * glob in the last path segment.\r\n */\r\nasync function resolveGlob(pattern: string): Promise<string[]> {\r\n // If it's a direct file, just return it\r\n if (!pattern.includes(\"*\")) {\r\n return [resolve(pattern)];\r\n }\r\n\r\n // Recursive glob is not supported — provide clear error\r\n if (pattern.includes(\"**\")) {\r\n throw new Error(\"Recursive glob (**) is not supported. Use a single-level wildcard (e.g., src/*.html) or list files explicitly.\");\r\n }\r\n\r\n // Simple glob: split into dir + glob pattern\r\n const lastSep = Math.max(pattern.lastIndexOf(\"/\"), pattern.lastIndexOf(\"\\\\\"));\r\n const dir = lastSep >= 0 ? pattern.slice(0, lastSep) : \".\";\r\n const glob = lastSep >= 0 ? pattern.slice(lastSep + 1) : pattern;\r\n\r\n // Convert glob to regex (only support * wildcard)\r\n const regex = new RegExp(\"^\" + glob.replace(/\\*/g, \".*\") + \"$\");\r\n\r\n const entries = await readdir(resolve(dir), { withFileTypes: true });\r\n return entries\r\n .filter((e) => e.isFile() && regex.test(e.name))\r\n .map((e) => resolve(dir, e.name))\r\n .sort();\r\n}\r\n\r\n/**\r\n * Flatten an AuditReport into a unified LintIssue array.\r\n */\r\nfunction flattenToLintIssues(report: AuditReport, skip: string[]): LintIssue[] {\r\n const issues: LintIssue[] = [];\r\n\r\n // CSS compatibility warnings → group by property (deduplicate across clients)\r\n if (!skip.includes(\"compatibility\")) {\r\n const seenProps = new Map<string, { severity: \"error\" | \"warning\" | \"info\"; clients: string[]; message: string }>();\r\n\r\n for (const w of report.compatibility.warnings) {\r\n const key = `${w.property}\\0${w.severity}`;\r\n const existing = seenProps.get(key);\r\n if (existing) {\r\n existing.clients.push(w.client);\r\n } else {\r\n seenProps.set(key, {\r\n severity: w.severity,\r\n clients: [w.client],\r\n message: w.message,\r\n });\r\n }\r\n }\r\n\r\n for (const [key, val] of seenProps) {\r\n const property = key.split(\"\\0\")[0];\r\n issues.push({\r\n severity: val.severity,\r\n category: val.clients.slice(0, 3).join(\",\") + (val.clients.length > 3 ? `+${val.clients.length - 3}` : \"\"),\r\n rule: property,\r\n message: val.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"spam\")) {\r\n for (const issue of report.spam.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"spam\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n detail: issue.detail,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"links\")) {\r\n for (const issue of report.links.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"links\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"accessibility\")) {\r\n for (const issue of report.accessibility.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"accessibility\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"images\")) {\r\n for (const issue of report.images.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"images\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"inboxPreview\")) {\r\n for (const issue of report.inboxPreview.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"inboxPreview\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"size\")) {\r\n for (const issue of report.size.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"size\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n if (!skip.includes(\"templateVariables\")) {\r\n for (const issue of report.templateVariables.issues) {\r\n issues.push({\r\n severity: issue.severity,\r\n category: \"templateVars\",\r\n rule: issue.rule,\r\n message: issue.message,\r\n });\r\n }\r\n }\r\n\r\n // Sort: errors first, then warnings, then info\r\n const order = { error: 0, warning: 1, info: 2 };\r\n issues.sort((a, b) => order[a.severity] - order[b.severity]);\r\n\r\n return issues;\r\n}\r\n"],"mappings":"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","names":["defineCommand","EMAIL_CLIENTS","resolve","EMAIL_CLIENTS","defineCommand","ora","analyzeEmail","generateCompatibilityScore","warningsForClient","CompileError","compile","defineCommand","ora","compile","analyzeEmail","generateCompatibilityScore","warningsForClient","CompileError","defineCommand","pc","Table","EMAIL_CLIENTS","defineCommand","ora","transformForAllClients","analyzeEmail","generateCompatibilityScore","simulateDarkMode","warningsForClient","CompileError","compile","EMAIL_CLIENTS","defineCommand","ora","compile","transformForAllClients","analyzeEmail","generateCompatibilityScore","warningsForClient","simulateDarkMode","CompileError","defineCommand","ora","pc","analyzeEmail","generateCompatibilityScore","CompileError","compile","defineCommand","ora","analyzeEmail","generateCompatibilityScore","pc","writeFileSync","CompileError","defineCommand","ora","pc","Table","CompileError","compile","defineCommand","ora","compile","s","CompileError","pc","Table","defineCommand","pc","compile","auditEmail","CompileError","resolve","VALID_SKIPS","defineCommand","s","pc","defineCommand"]}
package/package.json CHANGED
@@ -1,71 +1,72 @@
1
- {
2
- "name": "@emailens/cli",
3
- "version": "0.3.4",
4
- "description": "CLI tool for email compatibility analysis — analyze, preview, and export email rendering across 15 email clients.",
5
- "type": "module",
6
- "bin": {
7
- "emailens": "./dist/index.js"
8
- },
9
- "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js"
13
- }
14
- },
15
- "main": "./dist/index.js",
16
- "types": "./dist/index.d.ts",
17
- "files": [
18
- "dist",
19
- "LICENSE"
20
- ],
21
- "scripts": {
22
- "build": "tsup",
23
- "dev": "tsup --watch",
24
- "start": "bun run dist/index.js",
25
- "typecheck": "tsc --noEmit",
26
- "test": "bun test",
27
- "prepublishOnly": "bun run build"
28
- },
29
- "dependencies": {
30
- "@emailens/engine": "^0.8.6",
31
- "citty": "^0.1.6",
32
- "cli-table3": "^0.6.5",
33
- "ora": "^8.2.0",
34
- "picocolors": "^1.1.1"
35
- },
36
- "optionalDependencies": {
37
- "@anthropic-ai/sdk": "^0.52.0",
38
- "playwright-core": "^1.52.0"
39
- },
40
- "devDependencies": {
41
- "@types/mjml": "^4.7.4",
42
- "@types/node": "^25.3.0",
43
- "bun-types": "^1.3.9",
44
- "tsup": "^8.4.0",
45
- "typescript": "^5.9.3"
46
- },
47
- "keywords": [
48
- "email",
49
- "html-email",
50
- "css",
51
- "compatibility",
52
- "cli",
53
- "gmail",
54
- "outlook",
55
- "apple-mail",
56
- "email-testing",
57
- "dark-mode"
58
- ],
59
- "license": "MIT",
60
- "repository": {
61
- "type": "git",
62
- "url": "git+https://github.com/emailens/cli.git"
63
- },
64
- "engines": {
65
- "node": ">=18"
66
- },
67
- "homepage": "https://github.com/emailens/cli#readme",
68
- "bugs": {
69
- "url": "https://github.com/emailens/cli/issues"
70
- }
1
+ {
2
+ "name": "@emailens/cli",
3
+ "version": "0.3.5",
4
+ "description": "CLI tool for email compatibility analysis — analyze, preview, and export email rendering across 15 email clients.",
5
+ "type": "module",
6
+ "bin": {
7
+ "emailens": "./dist/index.js"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "files": [
18
+ "dist",
19
+ "LICENSE"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch",
24
+ "start": "bun run dist/index.js",
25
+ "typecheck": "tsc --noEmit",
26
+ "test": "bun test",
27
+ "prepublishOnly": "bun run build"
28
+ },
29
+ "dependencies": {
30
+ "@emailens/engine": "^0.9.3",
31
+ "citty": "^0.1.6",
32
+ "cli-table3": "^0.6.5",
33
+ "ora": "^8.2.0",
34
+ "picocolors": "^1.1.1"
35
+ },
36
+ "optionalDependencies": {
37
+ "@anthropic-ai/sdk": "^0.52.0",
38
+ "playwright-core": "^1.52.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/bun": "^1.3.14",
42
+ "@types/mjml": "^4.7.4",
43
+ "@types/node": "^25.3.0",
44
+ "bun-types": "^1.3.9",
45
+ "tsup": "^8.4.0",
46
+ "typescript": "^5.9.3"
47
+ },
48
+ "keywords": [
49
+ "email",
50
+ "html-email",
51
+ "css",
52
+ "compatibility",
53
+ "cli",
54
+ "gmail",
55
+ "outlook",
56
+ "apple-mail",
57
+ "email-testing",
58
+ "dark-mode"
59
+ ],
60
+ "license": "MIT",
61
+ "repository": {
62
+ "type": "git",
63
+ "url": "git+https://github.com/emailens/cli.git"
64
+ },
65
+ "engines": {
66
+ "node": ">=18"
67
+ },
68
+ "homepage": "https://github.com/emailens/cli#readme",
69
+ "bugs": {
70
+ "url": "https://github.com/emailens/cli/issues"
71
+ }
71
72
  }