@solid-email/render 0.1.1 → 0.1.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/shared/render.ts"],"sourcesContent":["import type { Options, Plugin } from 'prettier';\nimport type { builders } from 'prettier/doc';\nimport * as html from 'prettier/plugins/html';\nimport { format } from 'prettier/standalone';\n\ninterface HtmlNode {\n type?: 'element' | 'text' | 'ieConditionalComment';\n kind?: 'element' | 'text' | 'ieConditionalComment' | 'root';\n name?: string;\n sourceSpan?: {\n start: { file: unknown[]; offset: number; line: number; col: number };\n end: { file: unknown[]; offset: number; line: number; col: number };\n details: null;\n };\n parent?: HtmlNode;\n}\n\nfunction getHtmlNode(path: {\n node?: HtmlNode;\n stack?: Array<Record<string, unknown>>;\n}) {\n const topNode = path.node;\n if (topNode) {\n return topNode;\n }\n\n return path.stack?.[path.stack.length - 1] as unknown as HtmlNode | undefined;\n}\n\nfunction recursivelyMapDoc(\n doc: builders.Doc,\n callback: (innerDoc: string | builders.DocCommand) => builders.Doc,\n): builders.Doc {\n if (Array.isArray(doc)) {\n return doc.map((innerDoc) => recursivelyMapDoc(innerDoc, callback));\n }\n\n if (typeof doc === 'object') {\n if (doc.type === 'line') {\n return callback(doc.soft ? '' : ' ');\n }\n\n if (doc.type === 'group') {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n expandedStates: recursivelyMapDoc(\n doc.expandedStates,\n callback,\n ) as builders.Doc[],\n };\n }\n\n if ('contents' in doc) {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n };\n }\n\n if ('parts' in doc) {\n return {\n ...doc,\n parts: recursivelyMapDoc(doc.parts, callback) as builders.Doc[],\n };\n }\n\n if (doc.type === 'if-break') {\n return {\n ...doc,\n breakContents: recursivelyMapDoc(doc.breakContents, callback),\n flatContents: recursivelyMapDoc(doc.flatContents, callback),\n };\n }\n\n const nextDoc = { ...doc } as Record<string, unknown>;\n for (const [key, value] of Object.entries(nextDoc)) {\n if (value && typeof value === 'object') {\n nextDoc[key] = recursivelyMapDoc(value as builders.Doc, callback);\n }\n }\n\n return nextDoc as unknown as builders.Doc;\n }\n\n return callback(doc);\n}\n\nconst modifiedHtml = { ...html } as Plugin;\nconst htmlPrinter = modifiedHtml.printers?.html;\nif (htmlPrinter?.print) {\n const previousPrint = htmlPrinter.print;\n htmlPrinter.print = (path, options, print, args) => {\n const node = getHtmlNode(path as Parameters<typeof previousPrint>[0]);\n\n const rawPrintingResult = previousPrint(path, options, print, args);\n\n if (\n node?.type === 'ieConditionalComment' ||\n node?.kind === 'ieConditionalComment'\n ) {\n const printingResult = recursivelyMapDoc(rawPrintingResult, (doc) => {\n if (typeof doc === 'object' && doc.type === 'line') {\n return doc.soft ? '' : ' ';\n }\n\n return doc;\n });\n\n return printingResult;\n }\n\n return rawPrintingResult;\n };\n}\n\nconst defaults: Options = {\n endOfLine: 'lf',\n tabWidth: 2,\n plugins: [modifiedHtml],\n bracketSameLine: true,\n parser: 'html',\n};\n\nexport const pretty = (str: string, options: Options = {}) => {\n return format(str.replaceAll('\\0', ''), {\n ...defaults,\n ...options,\n });\n};\n","import {\n convert,\n type HtmlToTextOptions,\n type SelectorDefinition,\n} from 'html-to-text';\n\n// Text-export note: images and\n// preview-only nodes are skipped, and links render without duplicated hrefs.\nexport const plainTextSelectors: SelectorDefinition[] = [\n { selector: 'img', format: 'skip' },\n { selector: '[data-skip-in-text=true]', format: 'skip' },\n {\n selector: 'a',\n options: { linkBrackets: false, hideLinkHrefIfSameAsText: true },\n },\n];\n\nexport function toPlainText(html: string, options?: HtmlToTextOptions) {\n return convert(html, {\n wordwrap: false,\n ...options,\n selectors: [...plainTextSelectors, ...(options?.selectors ?? [])],\n });\n}\n","import type { JSX } from 'solid-js';\nimport {\n renderToString,\n renderToStringAsync,\n} from 'solid-js/web/dist/server.js';\nimport type { Options, RenderSyncOptions } from './options';\nimport { pretty } from './utils/pretty';\nimport { toPlainText } from './utils/to-plain-text';\n\nexport type Renderable = JSX.Element | (() => JSX.Element);\n\nconst doctype =\n '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">';\n\nfunction normalizeRenderable(node: Renderable) {\n return typeof node === 'function' ? (node as () => JSX.Element) : () => node;\n}\n\nfunction decodeSerializedString(value: string): string {\n try {\n const jsonSafe = value.replace(\n /\\\\x([0-9A-Fa-f]{2})/g,\n (_match, hex: string) => String.fromCharCode(Number.parseInt(hex, 16)),\n );\n const parsed: unknown = JSON.parse(`\"${jsonSafe}\"`);\n return typeof parsed === 'string' ? parsed : value;\n } catch {\n return value;\n }\n}\n\nfunction removeSolidResourceScripts(html: string): string {\n const errorMatch = /Object\\.assign\\(new Error\\(\"((?:\\\\.|[^\"\\\\])*)\"\\)/.exec(\n html,\n );\n if (errorMatch) {\n throw new Error(decodeSerializedString(errorMatch[1] ?? ''));\n }\n return html.replace(\n /<script>self\\.\\$R=self\\.\\$R\\|\\|\\[\\];[\\s\\S]*?<\\/script>/g,\n '',\n );\n}\n\nfunction renderDocument(html: string): string {\n return `${doctype}${html.replace(/<!DOCTYPE.*?>/, '')}`;\n}\n\nfunction renderSyncOutput(html: string, options?: RenderSyncOptions): string {\n if (options?.plainText) {\n return toPlainText(html, options.htmlToTextOptions);\n }\n\n return renderDocument(html);\n}\n\nasync function renderOutput(html: string, options?: Options): Promise<string> {\n if (options?.plainText) {\n return toPlainText(html, options.htmlToTextOptions);\n }\n\n const document = renderDocument(html);\n\n if (options?.pretty) {\n return pretty(document);\n }\n\n return document;\n}\n\n// API note: render accepts either a component function or an already\n// constructed node. Keep that API while rendering through Solid SSR.\nexport async function render(\n node: Renderable,\n options?: Options,\n): Promise<string> {\n const html = removeSolidResourceScripts(\n await renderToStringAsync(normalizeRenderable(node)),\n );\n\n return renderOutput(html, options);\n}\n\nexport function renderSync(\n node: Renderable,\n options?: RenderSyncOptions,\n): string {\n if (options?.pretty) {\n throw new Error('renderSync does not support pretty output; use render.');\n }\n\n const html = removeSolidResourceScripts(\n renderToString(normalizeRenderable(node)),\n );\n\n return renderSyncOutput(html, options);\n}\n"],"mappings":";;;;;AAiBA,SAAS,YAAY,MAGlB;CACD,MAAM,UAAU,KAAK;CACrB,IAAI,SACF,OAAO;CAGT,OAAO,KAAK,QAAQ,KAAK,MAAM,SAAS;AAC1C;AAEA,SAAS,kBACP,KACA,UACc;CACd,IAAI,MAAM,QAAQ,GAAG,GACnB,OAAO,IAAI,KAAK,aAAa,kBAAkB,UAAU,QAAQ,CAAC;CAGpE,IAAI,OAAO,QAAQ,UAAU;EAC3B,IAAI,IAAI,SAAS,QACf,OAAO,SAAS,IAAI,OAAO,KAAK,GAAG;EAGrC,IAAI,IAAI,SAAS,SACf,OAAO;GACL,GAAG;GACH,UAAU,kBAAkB,IAAI,UAAU,QAAQ;GAClD,gBAAgB,kBACd,IAAI,gBACJ,QACF;EACF;EAGF,IAAI,cAAc,KAChB,OAAO;GACL,GAAG;GACH,UAAU,kBAAkB,IAAI,UAAU,QAAQ;EACpD;EAGF,IAAI,WAAW,KACb,OAAO;GACL,GAAG;GACH,OAAO,kBAAkB,IAAI,OAAO,QAAQ;EAC9C;EAGF,IAAI,IAAI,SAAS,YACf,OAAO;GACL,GAAG;GACH,eAAe,kBAAkB,IAAI,eAAe,QAAQ;GAC5D,cAAc,kBAAkB,IAAI,cAAc,QAAQ;EAC5D;EAGF,MAAM,UAAU,EAAE,GAAG,IAAI;EACzB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAC/C,IAAI,SAAS,OAAO,UAAU,UAC5B,QAAQ,OAAO,kBAAkB,OAAuB,QAAQ;EAIpE,OAAO;CACT;CAEA,OAAO,SAAS,GAAG;AACrB;AAEA,MAAM,eAAe,EAAE,GAAG,KAAK;AAC/B,MAAM,cAAc,aAAa,UAAU;AAC3C,IAAI,aAAa,OAAO;CACtB,MAAM,gBAAgB,YAAY;CAClC,YAAY,SAAS,MAAM,SAAS,OAAO,SAAS;EAClD,MAAM,OAAO,YAAY,IAA2C;EAEpE,MAAM,oBAAoB,cAAc,MAAM,SAAS,OAAO,IAAI;EAElE,IACE,MAAM,SAAS,0BACf,MAAM,SAAS,wBAUf,OARuB,kBAAkB,oBAAoB,QAAQ;GACnE,IAAI,OAAO,QAAQ,YAAY,IAAI,SAAS,QAC1C,OAAO,IAAI,OAAO,KAAK;GAGzB,OAAO;EACT,CAEoB;EAGtB,OAAO;CACT;AACF;AAEA,MAAM,WAAoB;CACxB,WAAW;CACX,UAAU;CACV,SAAS,CAAC,YAAY;CACtB,iBAAiB;CACjB,QAAQ;AACV;AAEA,MAAa,UAAU,KAAa,UAAmB,CAAC,MAAM;CAC5D,OAAO,OAAO,IAAI,WAAW,MAAM,EAAE,GAAG;EACtC,GAAG;EACH,GAAG;CACL,CAAC;AACH;;;ACzHA,MAAa,qBAA2C;CACtD;EAAE,UAAU;EAAO,QAAQ;CAAO;CAClC;EAAE,UAAU;EAA4B,QAAQ;CAAO;CACvD;EACE,UAAU;EACV,SAAS;GAAE,cAAc;GAAO,0BAA0B;EAAK;CACjE;AACF;AAEA,SAAgB,YAAY,MAAc,SAA6B;CACrE,OAAO,QAAQ,MAAM;EACnB,UAAU;EACV,GAAG;EACH,WAAW,CAAC,GAAG,oBAAoB,GAAI,SAAS,aAAa,CAAC,CAAE;CAClE,CAAC;AACH;;;ACZA,MAAM,UACJ;AAEF,SAAS,oBAAoB,MAAkB;CAC7C,OAAO,OAAO,SAAS,aAAc,aAAmC;AAC1E;AAEA,SAAS,uBAAuB,OAAuB;CACrD,IAAI;EACF,MAAM,WAAW,MAAM,QACrB,yBACC,QAAQ,QAAgB,OAAO,aAAa,OAAO,SAAS,KAAK,EAAE,CAAC,CACvE;EACA,MAAM,SAAkB,KAAK,MAAM,IAAI,SAAS,EAAE;EAClD,OAAO,OAAO,WAAW,WAAW,SAAS;CAC/C,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,2BAA2B,MAAsB;CACxD,MAAM,aAAa,mDAAmD,KACpE,IACF;CACA,IAAI,YACF,MAAM,IAAI,MAAM,uBAAuB,WAAW,MAAM,EAAE,CAAC;CAE7D,OAAO,KAAK,QACV,2DACA,EACF;AACF;AAEA,SAAS,eAAe,MAAsB;CAC5C,OAAO,GAAG,UAAU,KAAK,QAAQ,iBAAiB,EAAE;AACtD;AAEA,SAAS,iBAAiB,MAAc,SAAqC;CAC3E,IAAI,SAAS,WACX,OAAO,YAAY,MAAM,QAAQ,iBAAiB;CAGpD,OAAO,eAAe,IAAI;AAC5B;AAEA,eAAe,aAAa,MAAc,SAAoC;CAC5E,IAAI,SAAS,WACX,OAAO,YAAY,MAAM,QAAQ,iBAAiB;CAGpD,MAAM,WAAW,eAAe,IAAI;CAEpC,IAAI,SAAS,QACX,OAAO,OAAO,QAAQ;CAGxB,OAAO;AACT;AAIA,eAAsB,OACpB,MACA,SACiB;CAKjB,OAAO,aAJM,2BACX,MAAM,oBAAoB,oBAAoB,IAAI,CAAC,CAG9B,GAAG,OAAO;AACnC;AAEA,SAAgB,WACd,MACA,SACQ;CACR,IAAI,SAAS,QACX,MAAM,IAAI,MAAM,wDAAwD;CAO1E,OAAO,iBAJM,2BACX,eAAe,oBAAoB,IAAI,CAAC,CAGf,GAAG,OAAO;AACvC"}
1
+ {"version":3,"file":"index.mjs","names":["compile","escapeRegex","CONTENT_START","CONTENT_END","ATTR_PREFIX","escapeRegex"],"sources":["../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts","../../src/shared/render.ts","../../src/shared/slot-values.ts","../../src/shared/slot-replacer.ts","../../src/shared/slots.ts","../../src/shared/text-template.ts","../../src/shared/compile.ts"],"sourcesContent":["import type { Options, Plugin } from 'prettier';\nimport type { builders } from 'prettier/doc';\nimport * as html from 'prettier/plugins/html';\nimport { format } from 'prettier/standalone';\n\ninterface HtmlNode {\n type?: 'element' | 'text' | 'ieConditionalComment';\n kind?: 'element' | 'text' | 'ieConditionalComment' | 'root';\n name?: string;\n sourceSpan?: {\n start: { file: unknown[]; offset: number; line: number; col: number };\n end: { file: unknown[]; offset: number; line: number; col: number };\n details: null;\n };\n parent?: HtmlNode;\n}\n\nfunction getHtmlNode(path: {\n node?: HtmlNode;\n stack?: Array<Record<string, unknown>>;\n}) {\n const topNode = path.node;\n if (topNode) {\n return topNode;\n }\n\n return path.stack?.[path.stack.length - 1] as unknown as HtmlNode | undefined;\n}\n\nfunction recursivelyMapDoc(\n doc: builders.Doc,\n callback: (innerDoc: string | builders.DocCommand) => builders.Doc,\n): builders.Doc {\n if (Array.isArray(doc)) {\n return doc.map((innerDoc) => recursivelyMapDoc(innerDoc, callback));\n }\n\n if (typeof doc === 'object') {\n if (doc.type === 'line') {\n return callback(doc.soft ? '' : ' ');\n }\n\n if (doc.type === 'group') {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n expandedStates: recursivelyMapDoc(\n doc.expandedStates,\n callback,\n ) as builders.Doc[],\n };\n }\n\n if ('contents' in doc) {\n return {\n ...doc,\n contents: recursivelyMapDoc(doc.contents, callback),\n };\n }\n\n if ('parts' in doc) {\n return {\n ...doc,\n parts: recursivelyMapDoc(doc.parts, callback) as builders.Doc[],\n };\n }\n\n if (doc.type === 'if-break') {\n return {\n ...doc,\n breakContents: recursivelyMapDoc(doc.breakContents, callback),\n flatContents: recursivelyMapDoc(doc.flatContents, callback),\n };\n }\n\n const nextDoc = { ...doc } as Record<string, unknown>;\n for (const [key, value] of Object.entries(nextDoc)) {\n if (value && typeof value === 'object') {\n nextDoc[key] = recursivelyMapDoc(value as builders.Doc, callback);\n }\n }\n\n return nextDoc as unknown as builders.Doc;\n }\n\n return callback(doc);\n}\n\nconst modifiedHtml = { ...html } as Plugin;\nconst htmlPrinter = modifiedHtml.printers?.html;\nif (htmlPrinter?.print) {\n const previousPrint = htmlPrinter.print;\n htmlPrinter.print = (path, options, print, args) => {\n const node = getHtmlNode(path as Parameters<typeof previousPrint>[0]);\n\n const rawPrintingResult = previousPrint(path, options, print, args);\n\n if (\n node?.type === 'ieConditionalComment' ||\n node?.kind === 'ieConditionalComment'\n ) {\n const printingResult = recursivelyMapDoc(rawPrintingResult, (doc) => {\n if (typeof doc === 'object' && doc.type === 'line') {\n return doc.soft ? '' : ' ';\n }\n\n return doc;\n });\n\n return printingResult;\n }\n\n return rawPrintingResult;\n };\n}\n\nconst defaults: Options = {\n endOfLine: 'lf',\n tabWidth: 2,\n plugins: [modifiedHtml],\n bracketSameLine: true,\n parser: 'html',\n};\n\nexport const pretty = (str: string, options: Options = {}) => {\n return format(str.replaceAll('\\0', ''), {\n ...defaults,\n ...options,\n });\n};\n","import {\n type CompiledFunction,\n compile,\n type HtmlToTextOptions,\n type SelectorDefinition,\n} from '@solid-email/html-to-text';\n\n// Text-export note: images and\n// preview-only nodes are skipped, and links render without duplicated hrefs.\nexport const plainTextSelectors: SelectorDefinition[] = [\n { selector: 'img', format: 'skip' },\n { selector: '[data-skip-in-text=true]', format: 'skip' },\n {\n selector: 'a',\n options: { linkBrackets: false, hideLinkHrefIfSameAsText: true },\n },\n];\nlet defaultConverter: CompiledFunction | undefined;\nlet defaultSelectorSnapshot: SelectorDefinition[] | undefined;\n\nconst OPTION_SNAPSHOT_KEYS = [\n 'baseElements',\n 'decodeEntities',\n 'encodeCharacters',\n 'formatters',\n 'limits',\n 'longWordSplit',\n 'preserveNewlines',\n 'selectors',\n 'whitespaceCharacters',\n 'wordwrap',\n] as const satisfies readonly (keyof HtmlToTextOptions)[];\n\ntype OptionSnapshotKey = (typeof OPTION_SNAPSHOT_KEYS)[number];\n\ntype OptionsSnapshot = Readonly<Pick<HtmlToTextOptions, OptionSnapshotKey>> & {\n readonly customSelectorSnapshot: SelectorDefinition[] | undefined;\n readonly plainSelectorSnapshot: SelectorDefinition[];\n};\n\ntype CachedConverter = {\n readonly converter: CompiledFunction;\n readonly snapshot: OptionsSnapshot;\n};\n\nconst customConverterCache = new WeakMap<HtmlToTextOptions, CachedConverter>();\n\nfunction plainSelectorsChanged(snapshot: SelectorDefinition[]) {\n return (\n snapshot.length !== plainTextSelectors.length ||\n snapshot.some((selector, index) => selector !== plainTextSelectors[index])\n );\n}\n\nfunction getDefaultConverter() {\n const changed =\n !defaultSelectorSnapshot || plainSelectorsChanged(defaultSelectorSnapshot);\n\n if (!defaultConverter || changed) {\n defaultSelectorSnapshot = [...plainTextSelectors];\n defaultConverter = compile({\n wordwrap: false,\n selectors: defaultSelectorSnapshot,\n });\n }\n\n return defaultConverter;\n}\n\nfunction createOptionsSnapshot(\n options: HtmlToTextOptions,\n plainSelectorSnapshot: SelectorDefinition[],\n customSelectorSnapshot: SelectorDefinition[] | undefined,\n): OptionsSnapshot {\n return {\n baseElements: options.baseElements,\n decodeEntities: options.decodeEntities,\n encodeCharacters: options.encodeCharacters,\n formatters: options.formatters,\n limits: options.limits,\n longWordSplit: options.longWordSplit,\n preserveNewlines: options.preserveNewlines,\n customSelectorSnapshot,\n plainSelectorSnapshot,\n selectors: options.selectors,\n whitespaceCharacters: options.whitespaceCharacters,\n wordwrap: options.wordwrap,\n };\n}\n\nfunction customOptionsChanged(\n options: HtmlToTextOptions,\n snapshot: OptionsSnapshot,\n) {\n return (\n plainSelectorsChanged(snapshot.plainSelectorSnapshot) ||\n OPTION_SNAPSHOT_KEYS.some((key) => options[key] !== snapshot[key]) ||\n options.selectors?.length !== snapshot.customSelectorSnapshot?.length ||\n (options.selectors?.some(\n (selector, index) =>\n selector !== snapshot.customSelectorSnapshot?.[index],\n ) ??\n false)\n );\n}\n\nfunction getCustomConverter(options: HtmlToTextOptions) {\n const cached = customConverterCache.get(options);\n if (cached && !customOptionsChanged(options, cached.snapshot)) {\n return cached.converter;\n }\n\n const plainSelectorSnapshot = [...plainTextSelectors];\n const customSelectorSnapshot = options.selectors\n ? [...options.selectors]\n : undefined;\n const selectors = [\n ...plainSelectorSnapshot,\n ...(customSelectorSnapshot ?? []),\n ];\n const converter = compile({\n wordwrap: false,\n ...options,\n selectors,\n });\n customConverterCache.set(options, {\n converter,\n snapshot: createOptionsSnapshot(\n options,\n plainSelectorSnapshot,\n customSelectorSnapshot,\n ),\n });\n\n return converter;\n}\n\nexport function toPlainText(html: string, options?: HtmlToTextOptions) {\n if (!options) {\n return getDefaultConverter()(html);\n }\n\n return getCustomConverter(options)(html);\n}\n","import type { JSX } from 'solid-js';\nimport {\n renderToString,\n renderToStringAsync,\n} from 'solid-js/web/dist/server.js';\nimport type { Options, RenderSyncOptions } from './options';\nimport { pretty } from './utils/pretty';\nimport { toPlainText } from './utils/to-plain-text';\n\nexport type Renderable = JSX.Element | (() => JSX.Element);\n\nconst doctype =\n '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">';\n\nexport function normalizeRenderable(node: Renderable) {\n return typeof node === 'function' ? (node as () => JSX.Element) : () => node;\n}\n\nfunction decodeSerializedString(value: string): string {\n try {\n const jsonSafe = value.replace(\n /\\\\x([0-9A-Fa-f]{2})/g,\n (_match, hex: string) => String.fromCharCode(Number.parseInt(hex, 16)),\n );\n const parsed: unknown = JSON.parse(`\"${jsonSafe}\"`);\n return typeof parsed === 'string' ? parsed : value;\n } catch {\n return value;\n }\n}\n\nexport function removeSolidResourceScripts(html: string): string {\n const errorMatch = /Object\\.assign\\(new Error\\(\"((?:\\\\.|[^\"\\\\])*)\"\\)/.exec(\n html,\n );\n if (errorMatch) {\n throw new Error(decodeSerializedString(errorMatch[1] ?? ''));\n }\n return html.replace(\n /<script>self\\.\\$R=self\\.\\$R\\|\\|\\[\\];[\\s\\S]*?<\\/script>/g,\n '',\n );\n}\n\nexport function renderDocument(html: string): string {\n return `${doctype}${html.replace(/<!DOCTYPE.*?>/, '')}`;\n}\n\nexport function renderSyncOutput(\n html: string,\n options?: RenderSyncOptions,\n): string {\n if (options?.plainText) {\n return toPlainText(html, options.htmlToTextOptions);\n }\n\n return renderDocument(html);\n}\n\nexport async function renderOutput(\n html: string,\n options?: Options,\n): Promise<string> {\n if (options?.plainText) {\n return toPlainText(html, options.htmlToTextOptions);\n }\n\n const document = renderDocument(html);\n\n if (options?.pretty) {\n return pretty(document);\n }\n\n return document;\n}\n\n// API note: render accepts either a component function or an already\n// constructed node. Keep that API while rendering through Solid SSR.\nexport async function render(\n node: Renderable,\n options?: Options,\n): Promise<string> {\n const html = removeSolidResourceScripts(\n await renderToStringAsync(normalizeRenderable(node)),\n );\n\n return renderOutput(html, options);\n}\n\nexport function renderSync(\n node: Renderable,\n options?: RenderSyncOptions,\n): string {\n if (options?.pretty) {\n throw new Error('renderSync does not support pretty output; use render.');\n }\n\n const html = removeSolidResourceScripts(\n renderToString(normalizeRenderable(node)),\n );\n\n return renderSyncOutput(html, options);\n}\n","import type { HtmlToTextOptions } from '@solid-email/html-to-text';\nimport type { JSX } from 'solid-js';\nimport {\n renderToString,\n renderToStringAsync,\n} from 'solid-js/web/dist/server.js';\nimport { removeSolidResourceScripts } from './render';\nimport type { SlotValue } from './slots';\nimport { toPlainText } from './utils/to-plain-text';\n\nexport async function renderSlotValueAsync(value: SlotValue): Promise<string> {\n if (value == null) return '';\n if (Array.isArray(value)) {\n return Promise.all(value.map(renderSlotValueAsync)).then((results) =>\n results.join(''),\n );\n }\n if (typeof value === 'boolean') return value ? 'true' : '';\n if (typeof value === 'string') return escapeHtml(value);\n if (typeof value === 'number') return String(value);\n return removeSolidResourceScripts(\n await renderToStringAsync(() => value as JSX.Element),\n );\n}\n\nexport function renderSlotValueSync(value: SlotValue): string {\n if (value == null) return '';\n if (Array.isArray(value)) return value.map(renderSlotValueSync).join('');\n if (typeof value === 'boolean') return value ? 'true' : '';\n if (typeof value === 'string') return escapeHtml(value);\n if (typeof value === 'number') return String(value);\n return removeSolidResourceScripts(renderToString(() => value as JSX.Element));\n}\n\nexport async function renderSlotValueTextAsync(\n value: SlotValue,\n options?: HtmlToTextOptions,\n): Promise<string> {\n if (value == null) return '';\n if (Array.isArray(value)) {\n const results = await Promise.all(\n value.map((item) => renderSlotValueTextAsync(item, options)),\n );\n return results.join('');\n }\n if (typeof value === 'boolean') return value ? 'true' : '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number') return String(value);\n\n const html = removeSolidResourceScripts(\n await renderToStringAsync(() => value as JSX.Element),\n );\n return toPlainText(html, options);\n}\n\nexport function renderSlotValueTextSync(\n value: SlotValue,\n options?: HtmlToTextOptions,\n): string {\n if (value == null) return '';\n if (Array.isArray(value)) {\n return value.map((item) => renderSlotValueTextSync(item, options)).join('');\n }\n if (typeof value === 'boolean') return value ? 'true' : '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number') return String(value);\n\n const html = removeSolidResourceScripts(\n renderToString(() => value as JSX.Element),\n );\n return toPlainText(html, options);\n}\n\nexport function renderAttrValue(name: string, value: unknown): string {\n if (value == null) return '';\n if (typeof value === 'boolean') return value ? 'true' : '';\n if (typeof value === 'string') return escapeAttr(value);\n if (typeof value === 'number') return String(value);\n throw new TypeError(\n `Attribute slot \"${name}\" only accepts string, number, boolean, null, or undefined. Use <Slot name=\"${name}\" /> for JSX/content values.`,\n );\n}\n\nexport function renderTextAttrValue(name: string, value: unknown): string {\n if (value == null) return '';\n if (typeof value === 'boolean') return value ? 'true' : '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number') return String(value);\n throw new TypeError(\n `Attribute slot \"${name}\" only accepts string, number, boolean, null, or undefined. Use <Slot name=\"${name}\" /> for JSX/content values.`,\n );\n}\n\nexport function renderTextLinkHrefValue(name: string, value: unknown): string {\n const href = renderTextAttrValue(name, value).replace(/^mailto:/, '');\n return href.startsWith('#') ? '' : href;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;');\n}\n\nfunction escapeAttr(str: string): string {\n return str\n .replaceAll('&', '&amp;')\n .replaceAll('\"', '&quot;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;');\n}\n","import {\n renderAttrValue,\n renderSlotValueAsync,\n renderSlotValueSync,\n} from './slot-values';\nimport type { SlotOccurrence, SlotValue } from './slots';\n\nexport type SlotLookup = {\n content: Map<string, SlotOccurrence[]>;\n attr: Map<string, string[]>;\n};\n\nexport function buildMarkerRegex(lookup: SlotLookup): RegExp {\n const markers = new Set<string>();\n for (const occurrences of lookup.content.values()) {\n for (const occ of occurrences) {\n markers.add(occ.full);\n }\n }\n for (const attrMarkers of lookup.attr.values()) {\n for (const marker of attrMarkers) {\n markers.add(marker);\n }\n }\n\n if (markers.size === 0) {\n return /$^/g;\n }\n\n return new RegExp(\n Array.from(markers)\n .sort((a, b) => b.length - a.length)\n .map(escapeRegex)\n .join('|'),\n 'g',\n );\n}\n\nexport function validateSlots<TSlots extends Record<string, SlotValue>>(\n data: TSlots,\n lookup: SlotLookup,\n): void {\n const allSlotNames = new Set([\n ...lookup.content.keys(),\n ...lookup.attr.keys(),\n ]);\n\n for (const name of allSlotNames) {\n const value = (data as Record<string, unknown>)[name];\n\n if (value === undefined) {\n const hasDefault =\n lookup.content.get(name)?.some((occ) => occ.hasDefault) ?? false;\n if (!hasDefault) {\n console.warn(\n `[solid-email] Slot \"${name}\" has no default and was not provided in render data. It will render as empty.`,\n );\n }\n }\n }\n}\n\nexport async function replaceSlots<TSlots extends Record<string, SlotValue>>({\n result,\n data,\n lookup,\n markerRegex,\n validate,\n}: {\n result: string;\n data: TSlots;\n lookup: SlotLookup;\n markerRegex: RegExp;\n validate: boolean;\n}): Promise<string> {\n if (validate) validateSlots(data, lookup);\n const replacements = new Map<string, string>();\n\n for (const [name, occurrences] of lookup.content) {\n const value = data[name as keyof TSlots] as SlotValue | undefined;\n const rendered =\n value !== undefined ? await renderSlotValueAsync(value) : undefined;\n for (const occ of occurrences) {\n if (!result.includes(occ.full)) continue;\n const replacement =\n rendered ??\n (await replaceSlots({\n result: occ.defaultValue,\n data,\n lookup,\n markerRegex,\n validate: false,\n }));\n replacements.set(occ.full, replacement);\n }\n }\n\n for (const [name, markers] of lookup.attr) {\n const value = data[name as keyof TSlots] as SlotValue | undefined;\n const replacement = renderAttrValue(name, value);\n for (const marker of markers) {\n replacements.set(marker, replacement);\n }\n }\n\n if (replacements.size === 0) return result;\n\n return result.replace(\n markerRegex,\n (marker) => replacements.get(marker) ?? marker,\n );\n}\n\nexport function replaceSlotsSync<TSlots extends Record<string, SlotValue>>({\n result,\n data,\n lookup,\n markerRegex,\n validate,\n}: {\n result: string;\n data: TSlots;\n lookup: SlotLookup;\n markerRegex: RegExp;\n validate: boolean;\n}): string {\n if (validate) validateSlots(data, lookup);\n const replacements = new Map<string, string>();\n\n for (const [name, occurrences] of lookup.content) {\n const value = data[name as keyof TSlots] as SlotValue | undefined;\n const rendered =\n value !== undefined ? renderSlotValueSync(value) : undefined;\n for (const occ of occurrences) {\n if (!result.includes(occ.full)) continue;\n const replacement =\n rendered ??\n replaceSlotsSync({\n result: occ.defaultValue,\n data,\n lookup,\n markerRegex,\n validate: false,\n });\n replacements.set(occ.full, replacement);\n }\n }\n\n for (const [name, markers] of lookup.attr) {\n const value = data[name as keyof TSlots] as SlotValue | undefined;\n const replacement = renderAttrValue(name, value);\n for (const marker of markers) {\n replacements.set(marker, replacement);\n }\n }\n\n if (replacements.size === 0) return result;\n\n return result.replace(\n markerRegex,\n (marker) => replacements.get(marker) ?? marker,\n );\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","import type { JSX } from 'solid-js';\nimport { ssr } from 'solid-js/web';\n\nconst MARKER_PREFIX = '__SM_';\nconst CONTENT_START = `${MARKER_PREFIX}CNT_`;\nconst CONTENT_END = `${MARKER_PREFIX}CNE_`;\nconst ATTR_PREFIX = `${MARKER_PREFIX}ATR_`;\n\nexport type SlotPrimitive = string | number | boolean | null | undefined;\nexport type SlotValue = SlotPrimitive | JSX.Element | SlotValue[];\nexport type SlotRecord = Record<string, SlotValue>;\n\nfunction encodeName(name: string): string {\n return encodeURIComponent(name).replace(\n /[!'()*_]/g,\n (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`,\n );\n}\n\nexport function decodeName(encoded: string): string {\n return decodeURIComponent(encoded);\n}\n\nexport function makeContentMarker(name: string, defaultValue?: string): string {\n const encoded = encodeName(name);\n const start = `${CONTENT_START}${encoded}__`;\n if (defaultValue !== undefined) {\n return `${start}${defaultValue}${CONTENT_END}${encoded}__`;\n }\n return `${start}${CONTENT_END}${encoded}__`;\n}\n\nexport function makeAttrMarker(name: string): string {\n return `${ATTR_PREFIX}${encodeName(name)}__`;\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport interface SlotOccurrence {\n full: string;\n hasDefault: boolean;\n defaultValue: string;\n}\n\nexport function buildSlotLookup(html: string): {\n content: Map<string, SlotOccurrence[]>;\n attr: Map<string, string[]>;\n} {\n const contentSlots = new Map<string, SlotOccurrence[]>();\n const attrSlots = new Map<string, string[]>();\n\n const nameChars = '(?:[A-Za-z0-9.~-]|%[0-9A-Fa-f]{2})+';\n\n const tokenRegex = new RegExp(\n `${escapeRegex(CONTENT_START)}(${nameChars})__|${escapeRegex(CONTENT_END)}(${nameChars})__`,\n 'g',\n );\n const stack: Array<{\n encodedName: string;\n name: string;\n startIndex: number;\n contentStartIndex: number;\n }> = [];\n let match: RegExpExecArray | null;\n while (true) {\n match = tokenRegex.exec(html);\n if (match === null) break;\n\n const startName = match[1];\n if (startName !== undefined) {\n stack.push({\n encodedName: startName,\n name: decodeName(startName),\n startIndex: match.index,\n contentStartIndex: tokenRegex.lastIndex,\n });\n continue;\n }\n\n const endName = match[2];\n if (endName === undefined) continue;\n\n let openIndex = -1;\n for (let index = stack.length - 1; index >= 0; index -= 1) {\n if (stack[index]?.encodedName === endName) {\n openIndex = index;\n break;\n }\n }\n if (openIndex === -1) continue;\n\n const [open] = stack.splice(openIndex, 1);\n if (open === undefined) continue;\n\n const innerContent = html.slice(open.contentStartIndex, match.index);\n const occurrence = {\n full: html.slice(open.startIndex, tokenRegex.lastIndex),\n hasDefault: innerContent.length > 0,\n defaultValue: innerContent,\n };\n const existing = contentSlots.get(open.name);\n if (existing) {\n existing.push(occurrence);\n } else {\n contentSlots.set(open.name, [occurrence]);\n }\n }\n\n const attrRegex = new RegExp(\n `${escapeRegex(ATTR_PREFIX)}(${nameChars})__`,\n 'g',\n );\n while (true) {\n match = attrRegex.exec(html);\n if (match === null) break;\n const name = decodeName(match[1] ?? '');\n const existing = attrSlots.get(name);\n if (existing) {\n existing.push(match[0]);\n } else {\n attrSlots.set(name, [match[0]]);\n }\n }\n\n return { content: contentSlots, attr: attrSlots };\n}\n\nexport function Slot(props: {\n name: string;\n children?: JSX.Element;\n}): JSX.Element {\n const encoded = encodeName(props.name);\n const start = ssr(`${CONTENT_START}${encoded}__`) as unknown as JSX.Element;\n const end = ssr(`${CONTENT_END}${encoded}__`) as unknown as JSX.Element;\n if (props.children !== undefined && props.children !== null) {\n return [start, props.children, end] as unknown as JSX.Element;\n }\n return [start, end] as unknown as JSX.Element;\n}\n\nexport function slot(name: string): string {\n return makeAttrMarker(name);\n}\n\nexport interface SlotDefinition<T extends SlotRecord> {\n content: <K extends keyof T & string>(\n name: K,\n defaultValue?: string,\n ) => string;\n attr: <K extends keyof T & string>(name: K) => string;\n}\n\nexport function defineSlots<T extends SlotRecord>(): SlotDefinition<T> {\n return {\n content: (name, defaultValue) =>\n makeContentMarker(name as string, defaultValue),\n attr: (name) => makeAttrMarker(name as string),\n };\n}\n","import type { HtmlToTextOptions } from '@solid-email/html-to-text';\nimport {\n renderSlotValueTextAsync,\n renderSlotValueTextSync,\n renderTextAttrValue,\n renderTextLinkHrefValue,\n} from './slot-values';\nimport { decodeName, type SlotOccurrence, type SlotValue } from './slots';\nimport { toPlainText } from './utils/to-plain-text';\n\nexport type TextTemplateNode =\n | { type: 'text'; value: string }\n | { type: 'contentSlot'; name: string; fallback: TextTemplateNode[] }\n | { type: 'attrSlot'; name: string; marker: string }\n | { type: 'linkHrefSlot'; name: string; marker: string }\n | { type: 'conditionalSkip'; slotName: string; children: TextTemplateNode[] };\n\nexport type PlainTextTemplate = {\n nodes: TextTemplateNode[];\n usable: boolean;\n};\n\ntype ParsedTextTemplate = {\n nodes: TextTemplateNode[];\n contentSlotCounts: Map<string, number>;\n attrMarkerCounts: Map<string, number>;\n linkMarkerCounts: Map<string, number>;\n conditionalCount: number;\n valid: boolean;\n};\n\ntype TextTemplateFrame = {\n kind: 'root' | 'contentSlot' | 'conditionalSkip';\n encodedName?: string;\n name?: string;\n nodes: TextTemplateNode[];\n};\n\nconst MARKER_NAME_CHARS = '(?:[A-Za-z0-9.~-]|%[0-9A-Fa-f]{2})+';\nconst CONTENT_START = '__SM_CNT_';\nconst CONTENT_END = '__SM_CNE_';\nconst ATTR_PREFIX = '__SM_ATR_';\nconst TEXT_SKIP_START = '__SM_TXS_';\nconst TEXT_SKIP_END = '__SM_TXE_';\nconst LINK_HREF_PREFIX = '__SM_LNK_';\n\nexport function createPlainTextTemplate({\n html,\n options,\n contentSlots,\n attrSlots,\n}: {\n html: string;\n options?: HtmlToTextOptions;\n contentSlots: Map<string, SlotOccurrence[]>;\n attrSlots: Map<string, string[]>;\n}): PlainTextTemplate {\n const marked = markTextTemplateSlots(html, options);\n const text = toPlainText(marked.html, options);\n const parsed = parseTextTemplate(text);\n\n return {\n nodes: parsed.nodes,\n usable: canUsePlainTextTemplate({\n parsed,\n supportedAttrMarkerCounts: marked.supportedAttrMarkerCounts,\n expectedConditionalCount: marked.conditionalCount,\n expectedLinkMarkerCounts: marked.expectedLinkMarkerCounts,\n contentSlots,\n attrSlots,\n }),\n };\n}\n\nexport async function renderTextTemplate<\n TSlots extends Record<string, SlotValue>,\n>(\n nodes: TextTemplateNode[],\n data: TSlots,\n options?: HtmlToTextOptions,\n): Promise<string> {\n const chunks: string[] = [];\n\n for (const node of nodes) {\n switch (node.type) {\n case 'text':\n chunks.push(node.value);\n break;\n case 'contentSlot': {\n const value = data[node.name as keyof TSlots] as SlotValue | undefined;\n chunks.push(\n value !== undefined\n ? await renderSlotValueTextAsync(value, options)\n : await renderTextTemplate(node.fallback, data, options),\n );\n break;\n }\n case 'attrSlot': {\n const value = data[node.name as keyof TSlots] as SlotValue | undefined;\n chunks.push(renderTextAttrValue(node.name, value));\n break;\n }\n case 'linkHrefSlot': {\n const value = data[node.name as keyof TSlots] as SlotValue | undefined;\n chunks.push(renderTextLinkHrefValue(node.name, value));\n break;\n }\n case 'conditionalSkip': {\n const value = data[node.slotName as keyof TSlots] as\n | SlotValue\n | undefined;\n if (renderTextAttrValue(node.slotName, value) !== 'true') {\n chunks.push(await renderTextTemplate(node.children, data, options));\n }\n break;\n }\n }\n }\n\n return chunks.join('');\n}\n\nexport function renderTextTemplateSync<\n TSlots extends Record<string, SlotValue>,\n>(\n nodes: TextTemplateNode[],\n data: TSlots,\n options?: HtmlToTextOptions,\n): string {\n const chunks: string[] = [];\n\n for (const node of nodes) {\n switch (node.type) {\n case 'text':\n chunks.push(node.value);\n break;\n case 'contentSlot': {\n const value = data[node.name as keyof TSlots] as SlotValue | undefined;\n chunks.push(\n value !== undefined\n ? renderSlotValueTextSync(value, options)\n : renderTextTemplateSync(node.fallback, data, options),\n );\n break;\n }\n case 'attrSlot': {\n const value = data[node.name as keyof TSlots] as SlotValue | undefined;\n chunks.push(renderTextAttrValue(node.name, value));\n break;\n }\n case 'linkHrefSlot': {\n const value = data[node.name as keyof TSlots] as SlotValue | undefined;\n chunks.push(renderTextLinkHrefValue(node.name, value));\n break;\n }\n case 'conditionalSkip': {\n const value = data[node.slotName as keyof TSlots] as\n | SlotValue\n | undefined;\n if (renderTextAttrValue(node.slotName, value) !== 'true') {\n chunks.push(renderTextTemplateSync(node.children, data, options));\n }\n break;\n }\n }\n }\n\n return chunks.join('');\n}\n\nfunction canUsePlainTextTemplate({\n parsed,\n supportedAttrMarkerCounts,\n expectedConditionalCount,\n expectedLinkMarkerCounts,\n contentSlots,\n attrSlots,\n}: {\n parsed: ParsedTextTemplate;\n supportedAttrMarkerCounts: Map<string, number>;\n expectedConditionalCount: number;\n expectedLinkMarkerCounts: Map<string, number>;\n contentSlots: Map<string, SlotOccurrence[]>;\n attrSlots: Map<string, string[]>;\n}): boolean {\n if (!parsed.valid) return false;\n\n const remainingSupportedAttrMarkers = new Map(supportedAttrMarkerCounts);\n for (const attrMarkers of attrSlots.values()) {\n for (const marker of attrMarkers) {\n const remaining = remainingSupportedAttrMarkers.get(marker) ?? 0;\n if (remaining < 1) return false;\n remainingSupportedAttrMarkers.set(marker, remaining - 1);\n }\n }\n\n if (parsed.conditionalCount !== expectedConditionalCount) return false;\n if (parsed.attrMarkerCounts.size > 0) return false;\n\n for (const [marker, count] of expectedLinkMarkerCounts) {\n if ((parsed.linkMarkerCounts.get(marker) ?? 0) < count) return false;\n }\n\n for (const [name, occurrences] of contentSlots) {\n if ((parsed.contentSlotCounts.get(name) ?? 0) < occurrences.length) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction markTextTemplateSlots(\n html: string,\n options?: HtmlToTextOptions,\n): {\n html: string;\n supportedAttrMarkerCounts: Map<string, number>;\n expectedLinkMarkerCounts: Map<string, number>;\n conditionalCount: number;\n} {\n const supportedAttrMarkerCounts = new Map<string, number>();\n const expectedLinkMarkerCounts = new Map<string, number>();\n let conditionalCount = 0;\n const incrementSupported = (marker: string) => {\n incrementCount(supportedAttrMarkerCounts, marker);\n };\n\n const dataSkipRegex = new RegExp(\n `<([A-Za-z][\\\\w:-]*)([^>]*)\\\\sdata-skip-in-text=([\"'])(__SM_ATR_(${MARKER_NAME_CHARS})__)\\\\3([^>]*)>([\\\\s\\\\S]*?)</\\\\1>`,\n 'g',\n );\n\n let markedHtml = html.replace(\n dataSkipRegex,\n (\n _match,\n tagName: string,\n beforeAttrs: string,\n _quote: string,\n marker: string,\n encodedName: string,\n afterAttrs: string,\n children: string,\n ) => {\n incrementSupported(marker);\n conditionalCount += 1;\n return `<${tagName}${beforeAttrs}${afterAttrs}>${TEXT_SKIP_START}${encodedName}__${children}${TEXT_SKIP_END}${encodedName}__</${tagName}>`;\n },\n );\n\n if (!options) {\n const linkHrefRegex = new RegExp(\n `<a([^>]*)\\\\shref=([\"'])(__SM_ATR_(${MARKER_NAME_CHARS})__)\\\\2([^>]*)>([\\\\s\\\\S]*?)</a>`,\n 'g',\n );\n markedHtml = markedHtml.replace(\n linkHrefRegex,\n (\n match,\n beforeAttrs: string,\n quote: string,\n marker: string,\n encodedName: string,\n afterAttrs: string,\n children: string,\n ) => {\n const sameContentMarker = `${CONTENT_START}${encodedName}__`;\n if (children.includes(sameContentMarker)) return match;\n\n incrementSupported(marker);\n incrementCount(expectedLinkMarkerCounts, marker);\n return `<a${beforeAttrs} href=${quote}${LINK_HREF_PREFIX}${encodedName}__${quote}${afterAttrs}>${children}</a>`;\n },\n );\n }\n\n return {\n html: markedHtml,\n supportedAttrMarkerCounts,\n expectedLinkMarkerCounts,\n conditionalCount,\n };\n}\n\nfunction parseTextTemplate(text: string): ParsedTextTemplate {\n const tokenRegex = new RegExp(\n `${escapeRegex(CONTENT_START)}(${MARKER_NAME_CHARS})__|${escapeRegex(CONTENT_END)}(${MARKER_NAME_CHARS})__|${escapeRegex(ATTR_PREFIX)}(${MARKER_NAME_CHARS})__|${escapeRegex(LINK_HREF_PREFIX)}(${MARKER_NAME_CHARS})__|${escapeRegex(TEXT_SKIP_START)}(${MARKER_NAME_CHARS})__|${escapeRegex(TEXT_SKIP_END)}(${MARKER_NAME_CHARS})__`,\n 'g',\n );\n const root: TextTemplateFrame = { kind: 'root', nodes: [] };\n const stack = [root];\n const contentSlotCounts = new Map<string, number>();\n const attrMarkerCounts = new Map<string, number>();\n const linkMarkerCounts = new Map<string, number>();\n let conditionalCount = 0;\n let valid = true;\n let offset = 0;\n let match: RegExpExecArray | null;\n\n const currentNodes = () => stack[stack.length - 1]?.nodes ?? root.nodes;\n const addText = (value: string) => {\n if (!value) return;\n currentNodes().push({ type: 'text', value });\n };\n\n while (true) {\n match = tokenRegex.exec(text);\n if (match === null) break;\n\n addText(text.slice(offset, match.index));\n offset = tokenRegex.lastIndex;\n\n const [\n token,\n contentStart,\n contentEnd,\n attrName,\n linkName,\n conditionalStart,\n conditionalEnd,\n ] = match;\n\n if (contentStart !== undefined) {\n stack.push({\n kind: 'contentSlot',\n encodedName: contentStart,\n name: decodeName(contentStart),\n nodes: [],\n });\n continue;\n }\n\n if (contentEnd !== undefined) {\n const frame = stack[stack.length - 1];\n if (\n frame?.kind !== 'contentSlot' ||\n frame.encodedName !== contentEnd ||\n !frame.name\n ) {\n valid = false;\n addText(token);\n continue;\n }\n stack.pop();\n currentNodes().push({\n type: 'contentSlot',\n name: frame.name,\n fallback: frame.nodes,\n });\n incrementCount(contentSlotCounts, frame.name);\n continue;\n }\n\n if (attrName !== undefined) {\n const marker = `${ATTR_PREFIX}${attrName}__`;\n currentNodes().push({\n type: 'attrSlot',\n name: decodeName(attrName),\n marker,\n });\n incrementCount(attrMarkerCounts, marker);\n continue;\n }\n\n if (linkName !== undefined) {\n const marker = `${ATTR_PREFIX}${linkName}__`;\n currentNodes().push({\n type: 'linkHrefSlot',\n name: decodeName(linkName),\n marker,\n });\n incrementCount(linkMarkerCounts, marker);\n continue;\n }\n\n if (conditionalStart !== undefined) {\n stack.push({\n kind: 'conditionalSkip',\n encodedName: conditionalStart,\n name: decodeName(conditionalStart),\n nodes: [],\n });\n continue;\n }\n\n if (conditionalEnd !== undefined) {\n const frame = stack[stack.length - 1];\n if (\n frame?.kind !== 'conditionalSkip' ||\n frame.encodedName !== conditionalEnd ||\n !frame.name\n ) {\n valid = false;\n addText(token);\n continue;\n }\n stack.pop();\n currentNodes().push({\n type: 'conditionalSkip',\n slotName: frame.name,\n children: frame.nodes,\n });\n conditionalCount += 1;\n }\n }\n\n addText(text.slice(offset));\n\n return {\n nodes: root.nodes,\n contentSlotCounts,\n attrMarkerCounts,\n linkMarkerCounts,\n conditionalCount,\n valid: valid && stack.length === 1,\n };\n}\n\nfunction incrementCount(map: Map<string, number>, key: string): void {\n map.set(key, (map.get(key) ?? 0) + 1);\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","import {\n renderToString,\n renderToStringAsync,\n} from 'solid-js/web/dist/server.js';\nimport type {\n CompiledRenderOptions,\n CompiledRenderSyncOptions,\n CompileOptions,\n CompileSyncOptions,\n} from './options';\nimport type { Renderable } from './render';\nimport {\n normalizeRenderable,\n removeSolidResourceScripts,\n renderOutput,\n renderSyncOutput,\n} from './render';\nimport {\n buildMarkerRegex,\n replaceSlots,\n replaceSlotsSync,\n type SlotLookup,\n validateSlots,\n} from './slot-replacer';\nimport { buildSlotLookup, type SlotValue } from './slots';\nimport {\n createPlainTextTemplate,\n type PlainTextTemplate,\n renderTextTemplate,\n renderTextTemplateSync,\n} from './text-template';\nimport { toPlainText } from './utils/to-plain-text';\n\nexport type { SlotRecord, SlotValue } from './slots';\n\nexport class CompiledTemplate<\n TSlots extends Record<string, SlotValue> = Record<string, SlotValue>,\n> {\n private readonly html: string;\n private readonly htmlToTextOptions?: CompileOptions['htmlToTextOptions'];\n private readonly slotLookup: SlotLookup;\n private readonly markerRegex: RegExp;\n private readonly plainTextTemplate?: PlainTextTemplate;\n\n constructor(html: string, options: CompileOptions = {}) {\n this.html = html;\n this.htmlToTextOptions = options.htmlToTextOptions;\n this.slotLookup = buildSlotLookup(html);\n this.markerRegex = buildMarkerRegex(this.slotLookup);\n\n if (options.withPlainText) {\n this.plainTextTemplate = createPlainTextTemplate({\n html,\n options: options.htmlToTextOptions,\n contentSlots: this.slotLookup.content,\n attrSlots: this.slotLookup.attr,\n });\n }\n }\n\n async render(data: TSlots, options?: CompiledRenderOptions): Promise<string> {\n if (options?.plainText) {\n return this.renderPlainText(data);\n }\n\n const result = await this.replaceHtmlSlots(data);\n\n return renderOutput(result, options?.pretty ? { pretty: true } : undefined);\n }\n\n renderSync(data: TSlots, options?: CompiledRenderSyncOptions): string {\n if (options?.pretty) {\n throw new Error('renderSync does not support pretty output; use render.');\n }\n\n if (options?.plainText) {\n return this.renderPlainTextSync(data);\n }\n\n return renderSyncOutput(this.replaceHtmlSlotsSync(data));\n }\n\n private async replaceHtmlSlots(data: TSlots): Promise<string> {\n return replaceSlots({\n result: this.html,\n data,\n lookup: this.slotLookup,\n markerRegex: this.markerRegex,\n validate: true,\n });\n }\n\n private replaceHtmlSlotsSync(data: TSlots): string {\n return replaceSlotsSync({\n result: this.html,\n data,\n lookup: this.slotLookup,\n markerRegex: this.markerRegex,\n validate: true,\n });\n }\n\n private async renderPlainText(data: TSlots): Promise<string> {\n if (this.plainTextTemplate?.usable) {\n validateSlots(data, this.slotLookup);\n return renderTextTemplate(\n this.plainTextTemplate.nodes,\n data,\n this.htmlToTextOptions,\n );\n }\n\n return toPlainText(\n await this.replaceHtmlSlots(data),\n this.htmlToTextOptions,\n );\n }\n\n private renderPlainTextSync(data: TSlots): string {\n if (this.plainTextTemplate?.usable) {\n validateSlots(data, this.slotLookup);\n return renderTextTemplateSync(\n this.plainTextTemplate.nodes,\n data,\n this.htmlToTextOptions,\n );\n }\n\n return toPlainText(this.replaceHtmlSlotsSync(data), this.htmlToTextOptions);\n }\n}\n\nexport async function compile<\n TSlots extends Record<string, SlotValue> = Record<string, SlotValue>,\n>(\n node: Renderable,\n options?: CompileOptions,\n): Promise<CompiledTemplate<TSlots>> {\n const html = removeSolidResourceScripts(\n await renderToStringAsync(normalizeRenderable(node)),\n );\n return new CompiledTemplate<TSlots>(html, options);\n}\n\nexport function compileSync<\n TSlots extends Record<string, SlotValue> = Record<string, SlotValue>,\n>(node: Renderable, options?: CompileSyncOptions): CompiledTemplate<TSlots> {\n if ((options as { pretty?: boolean } | undefined)?.pretty) {\n throw new Error('compileSync does not support pretty output; use compile.');\n }\n const html = removeSolidResourceScripts(\n renderToString(normalizeRenderable(node)),\n );\n return new CompiledTemplate<TSlots>(html, options);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solid-email/render",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Transform Solid components into HTML email templates",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,6 +12,8 @@
12
12
  "module": "./dist/node/index.mjs",
13
13
  "types": "./dist/node/index.d.mts",
14
14
  "files": [
15
+ "LICENSE",
16
+ "README.md",
15
17
  "dist/**"
16
18
  ],
17
19
  "exports": {
@@ -100,20 +102,19 @@
100
102
  }
101
103
  },
102
104
  "dependencies": {
103
- "html-to-text": "10.0.0",
104
- "prettier": "3.8.4"
105
+ "prettier": "3.8.4",
106
+ "@solid-email/html-to-text": "0.1.1"
105
107
  },
106
108
  "peerDependencies": {
107
109
  "solid-js": "1.9.13"
108
110
  },
109
111
  "devDependencies": {
110
- "@types/html-to-text": "9.0.4",
111
112
  "solid-js": "1.9.13",
112
113
  "tsdown": "0.22.3",
113
114
  "vite-plugin-solid": "2.11.12",
114
115
  "typescript": "6.0.3",
115
116
  "vitest": "4.1.9",
116
- "tsconfig": "0.1.1"
117
+ "tsconfig": "0.1.3"
117
118
  },
118
119
  "scripts": {
119
120
  "build": "tsdown",