@solid-email/render 0.1.1 → 0.1.2
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/browser/index.cjs +240 -0
- package/dist/browser/index.d.cts +53 -1
- package/dist/browser/index.d.cts.map +1 -1
- package/dist/browser/index.d.mts +53 -1
- package/dist/browser/index.d.mts.map +1 -1
- package/dist/browser/index.mjs +226 -1
- package/dist/browser/index.mjs.map +1 -1
- package/dist/edge/index.cjs +240 -0
- package/dist/edge/index.d.cts +53 -1
- package/dist/edge/index.d.cts.map +1 -1
- package/dist/edge/index.d.mts +53 -1
- package/dist/edge/index.d.mts.map +1 -1
- package/dist/edge/index.mjs +226 -1
- package/dist/edge/index.mjs.map +1 -1
- package/dist/node/index.cjs +240 -0
- package/dist/node/index.d.cts +53 -1
- package/dist/node/index.d.cts.map +1 -1
- package/dist/node/index.d.mts +53 -1
- package/dist/node/index.d.mts.map +1 -1
- package/dist/node/index.mjs +226 -1
- package/dist/node/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/browser/index.cjs
CHANGED
|
@@ -26,6 +26,7 @@ let prettier_plugins_html = require("prettier/plugins/html");
|
|
|
26
26
|
prettier_plugins_html = __toESM(prettier_plugins_html, 1);
|
|
27
27
|
let prettier_standalone = require("prettier/standalone");
|
|
28
28
|
let html_to_text = require("html-to-text");
|
|
29
|
+
let solid_js_web = require("solid-js/web");
|
|
29
30
|
//#region src/shared/utils/pretty.ts
|
|
30
31
|
function getHtmlNode(path) {
|
|
31
32
|
const topNode = path.node;
|
|
@@ -154,8 +155,247 @@ function renderSync(node, options) {
|
|
|
154
155
|
return renderSyncOutput(removeSolidResourceScripts((0, solid_js_web_dist_server_js.renderToString)(normalizeRenderable(node))), options);
|
|
155
156
|
}
|
|
156
157
|
//#endregion
|
|
158
|
+
//#region src/shared/slots.ts
|
|
159
|
+
const MARKER_PREFIX = "__SM_";
|
|
160
|
+
const CONTENT_START = `${MARKER_PREFIX}CNT_`;
|
|
161
|
+
const CONTENT_END = `${MARKER_PREFIX}CNE_`;
|
|
162
|
+
const ATTR_PREFIX = `${MARKER_PREFIX}ATR_`;
|
|
163
|
+
function encodeName(name) {
|
|
164
|
+
return encodeURIComponent(name).replace(/[!'()*_]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
165
|
+
}
|
|
166
|
+
function decodeName(encoded) {
|
|
167
|
+
return decodeURIComponent(encoded);
|
|
168
|
+
}
|
|
169
|
+
function makeContentMarker(name, defaultValue) {
|
|
170
|
+
const encoded = encodeName(name);
|
|
171
|
+
const start = `${CONTENT_START}${encoded}__`;
|
|
172
|
+
if (defaultValue !== void 0) return `${start}${defaultValue}${CONTENT_END}${encoded}__`;
|
|
173
|
+
return `${start}${CONTENT_END}${encoded}__`;
|
|
174
|
+
}
|
|
175
|
+
function makeAttrMarker(name) {
|
|
176
|
+
return `${ATTR_PREFIX}${encodeName(name)}__`;
|
|
177
|
+
}
|
|
178
|
+
function escapeRegex$1(str) {
|
|
179
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
180
|
+
}
|
|
181
|
+
function buildSlotLookup(html) {
|
|
182
|
+
const contentSlots = /* @__PURE__ */ new Map();
|
|
183
|
+
const attrSlots = /* @__PURE__ */ new Map();
|
|
184
|
+
const nameChars = "(?:[A-Za-z0-9.~-]|%[0-9A-Fa-f]{2})+";
|
|
185
|
+
const tokenRegex = new RegExp(`${escapeRegex$1(CONTENT_START)}(${nameChars})__|${escapeRegex$1(CONTENT_END)}(${nameChars})__`, "g");
|
|
186
|
+
const stack = [];
|
|
187
|
+
let match;
|
|
188
|
+
while (true) {
|
|
189
|
+
match = tokenRegex.exec(html);
|
|
190
|
+
if (match === null) break;
|
|
191
|
+
const startName = match[1];
|
|
192
|
+
if (startName !== void 0) {
|
|
193
|
+
stack.push({
|
|
194
|
+
encodedName: startName,
|
|
195
|
+
name: decodeName(startName),
|
|
196
|
+
startIndex: match.index,
|
|
197
|
+
contentStartIndex: tokenRegex.lastIndex
|
|
198
|
+
});
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const endName = match[2];
|
|
202
|
+
if (endName === void 0) continue;
|
|
203
|
+
let openIndex = -1;
|
|
204
|
+
for (let index = stack.length - 1; index >= 0; index -= 1) if (stack[index]?.encodedName === endName) {
|
|
205
|
+
openIndex = index;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
if (openIndex === -1) continue;
|
|
209
|
+
const [open] = stack.splice(openIndex, 1);
|
|
210
|
+
if (open === void 0) continue;
|
|
211
|
+
const innerContent = html.slice(open.contentStartIndex, match.index);
|
|
212
|
+
const occurrence = {
|
|
213
|
+
full: html.slice(open.startIndex, tokenRegex.lastIndex),
|
|
214
|
+
hasDefault: innerContent.length > 0,
|
|
215
|
+
defaultValue: innerContent
|
|
216
|
+
};
|
|
217
|
+
const existing = contentSlots.get(open.name);
|
|
218
|
+
if (existing) existing.push(occurrence);
|
|
219
|
+
else contentSlots.set(open.name, [occurrence]);
|
|
220
|
+
}
|
|
221
|
+
const attrRegex = new RegExp(`${escapeRegex$1(ATTR_PREFIX)}(${nameChars})__`, "g");
|
|
222
|
+
while (true) {
|
|
223
|
+
match = attrRegex.exec(html);
|
|
224
|
+
if (match === null) break;
|
|
225
|
+
const name = decodeName(match[1] ?? "");
|
|
226
|
+
const existing = attrSlots.get(name);
|
|
227
|
+
if (existing) existing.push(match[0]);
|
|
228
|
+
else attrSlots.set(name, [match[0]]);
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
content: contentSlots,
|
|
232
|
+
attr: attrSlots
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function Slot(props) {
|
|
236
|
+
const encoded = encodeName(props.name);
|
|
237
|
+
const start = (0, solid_js_web.ssr)(`${CONTENT_START}${encoded}__`);
|
|
238
|
+
const end = (0, solid_js_web.ssr)(`${CONTENT_END}${encoded}__`);
|
|
239
|
+
if (props.children !== void 0 && props.children !== null) return [
|
|
240
|
+
start,
|
|
241
|
+
props.children,
|
|
242
|
+
end
|
|
243
|
+
];
|
|
244
|
+
return [start, end];
|
|
245
|
+
}
|
|
246
|
+
function slot(name) {
|
|
247
|
+
return makeAttrMarker(name);
|
|
248
|
+
}
|
|
249
|
+
function defineSlots() {
|
|
250
|
+
return {
|
|
251
|
+
content: (name, defaultValue) => makeContentMarker(name, defaultValue),
|
|
252
|
+
attr: (name) => makeAttrMarker(name)
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
//#endregion
|
|
256
|
+
//#region src/shared/compile.ts
|
|
257
|
+
var CompiledTemplate = class {
|
|
258
|
+
html;
|
|
259
|
+
options;
|
|
260
|
+
contentSlots;
|
|
261
|
+
attrSlots;
|
|
262
|
+
markerRegex;
|
|
263
|
+
constructor(html, options) {
|
|
264
|
+
this.html = html;
|
|
265
|
+
this.options = options;
|
|
266
|
+
const lookup = buildSlotLookup(html);
|
|
267
|
+
this.contentSlots = lookup.content;
|
|
268
|
+
this.attrSlots = lookup.attr;
|
|
269
|
+
this.markerRegex = this.buildMarkerRegex();
|
|
270
|
+
}
|
|
271
|
+
async render(data, options) {
|
|
272
|
+
let result = this.html;
|
|
273
|
+
result = await this.replaceSlots(result, data);
|
|
274
|
+
return renderOutput(result, options ?? this.options);
|
|
275
|
+
}
|
|
276
|
+
renderSync(data, options) {
|
|
277
|
+
if ((options ?? this.options)?.pretty) throw new Error("renderSync does not support pretty output; use render.");
|
|
278
|
+
let result = this.html;
|
|
279
|
+
result = this.replaceSlotsSync(result, data);
|
|
280
|
+
return renderSyncOutput(result, options ?? this.options);
|
|
281
|
+
}
|
|
282
|
+
buildMarkerRegex() {
|
|
283
|
+
const markers = /* @__PURE__ */ new Set();
|
|
284
|
+
for (const occurrences of this.contentSlots.values()) for (const occ of occurrences) markers.add(occ.full);
|
|
285
|
+
for (const attrMarkers of this.attrSlots.values()) for (const marker of attrMarkers) markers.add(marker);
|
|
286
|
+
if (markers.size === 0) return /$^/g;
|
|
287
|
+
return new RegExp(Array.from(markers).sort((a, b) => b.length - a.length).map(escapeRegex).join("|"), "g");
|
|
288
|
+
}
|
|
289
|
+
validateSlots(data) {
|
|
290
|
+
const allSlotNames = /* @__PURE__ */ new Set([...this.contentSlots.keys(), ...this.attrSlots.keys()]);
|
|
291
|
+
for (const name of allSlotNames) if (data[name] === void 0) {
|
|
292
|
+
if (!(this.contentSlots.get(name)?.some((occ) => occ.hasDefault) ?? false)) console.warn(`[solid-email] Slot "${name}" has no default and was not provided in render data. It will render as empty.`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async replaceSlots(result, data) {
|
|
296
|
+
return this.replaceSlotsInFragment(result, data, true);
|
|
297
|
+
}
|
|
298
|
+
async replaceSlotsInFragment(result, data, validate) {
|
|
299
|
+
if (validate) this.validateSlots(data);
|
|
300
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
301
|
+
for (const [name, occurrences] of this.contentSlots) {
|
|
302
|
+
const value = data[name];
|
|
303
|
+
const rendered = value !== void 0 ? await renderSlotValueAsync(value) : void 0;
|
|
304
|
+
for (const occ of occurrences) {
|
|
305
|
+
if (!result.includes(occ.full)) continue;
|
|
306
|
+
const replacement = rendered ?? await this.replaceSlotsInFragment(occ.defaultValue, data, false);
|
|
307
|
+
replacements.set(occ.full, replacement);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
for (const [name, markers] of this.attrSlots) {
|
|
311
|
+
const value = data[name];
|
|
312
|
+
const replacement = renderAttrValue(name, value);
|
|
313
|
+
for (const marker of markers) replacements.set(marker, replacement);
|
|
314
|
+
}
|
|
315
|
+
if (replacements.size === 0) return result;
|
|
316
|
+
return result.replace(this.markerRegex, (marker) => replacements.get(marker) ?? marker);
|
|
317
|
+
}
|
|
318
|
+
replaceSlotsSync(result, data) {
|
|
319
|
+
return this.replaceSlotsInFragmentSync(result, data, true);
|
|
320
|
+
}
|
|
321
|
+
replaceSlotsInFragmentSync(result, data, validate) {
|
|
322
|
+
if (validate) this.validateSlots(data);
|
|
323
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
324
|
+
for (const [name, occurrences] of this.contentSlots) {
|
|
325
|
+
const value = data[name];
|
|
326
|
+
const rendered = value !== void 0 ? renderSlotValueSync(value) : void 0;
|
|
327
|
+
for (const occ of occurrences) {
|
|
328
|
+
if (!result.includes(occ.full)) continue;
|
|
329
|
+
const replacement = rendered ?? this.replaceSlotsInFragmentSync(occ.defaultValue, data, false);
|
|
330
|
+
replacements.set(occ.full, replacement);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
for (const [name, markers] of this.attrSlots) {
|
|
334
|
+
const value = data[name];
|
|
335
|
+
const replacement = renderAttrValue(name, value);
|
|
336
|
+
for (const marker of markers) replacements.set(marker, replacement);
|
|
337
|
+
}
|
|
338
|
+
if (replacements.size === 0) return result;
|
|
339
|
+
return result.replace(this.markerRegex, (marker) => replacements.get(marker) ?? marker);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
async function renderSlotValueAsync(value) {
|
|
343
|
+
if (value == null) return "";
|
|
344
|
+
if (Array.isArray(value)) return Promise.all(value.map(renderSlotValueAsync)).then((results) => results.join(""));
|
|
345
|
+
if (typeof value === "boolean") return value ? "true" : "";
|
|
346
|
+
if (typeof value === "string") return escapeHtml(value);
|
|
347
|
+
if (typeof value === "number") return String(value);
|
|
348
|
+
return removeSolidResourceScripts(await (0, solid_js_web_dist_server_js.renderToStringAsync)(() => value));
|
|
349
|
+
}
|
|
350
|
+
function renderSlotValueSync(value) {
|
|
351
|
+
if (value == null) return "";
|
|
352
|
+
if (Array.isArray(value)) return value.map(renderSlotValueSync).join("");
|
|
353
|
+
if (typeof value === "boolean") return value ? "true" : "";
|
|
354
|
+
if (typeof value === "string") return escapeHtml(value);
|
|
355
|
+
if (typeof value === "number") return String(value);
|
|
356
|
+
return removeSolidResourceScripts((0, solid_js_web_dist_server_js.renderToString)(() => value));
|
|
357
|
+
}
|
|
358
|
+
function renderAttrValue(name, value) {
|
|
359
|
+
if (value == null) return "";
|
|
360
|
+
if (typeof value === "boolean") return value ? "true" : "";
|
|
361
|
+
if (typeof value === "string") return escapeAttr(value);
|
|
362
|
+
if (typeof value === "number") return String(value);
|
|
363
|
+
throw new TypeError(`Attribute slot "${name}" only accepts string, number, boolean, null, or undefined. Use <Slot name="${name}" /> for JSX/content values.`);
|
|
364
|
+
}
|
|
365
|
+
function escapeHtml(str) {
|
|
366
|
+
return str.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
367
|
+
}
|
|
368
|
+
function escapeAttr(str) {
|
|
369
|
+
return str.replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<").replaceAll(">", ">");
|
|
370
|
+
}
|
|
371
|
+
function escapeRegex(str) {
|
|
372
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
373
|
+
}
|
|
374
|
+
async function compile(node, options) {
|
|
375
|
+
return new CompiledTemplate(removeSolidResourceScripts(await (0, solid_js_web_dist_server_js.renderToStringAsync)(normalizeRenderable(node))), options);
|
|
376
|
+
}
|
|
377
|
+
function compileSync(node, options) {
|
|
378
|
+
if (options?.pretty) throw new Error("compileSync does not support pretty output; use compile.");
|
|
379
|
+
return new CompiledTemplate(removeSolidResourceScripts((0, solid_js_web_dist_server_js.renderToString)(normalizeRenderable(node))), options);
|
|
380
|
+
}
|
|
381
|
+
//#endregion
|
|
382
|
+
exports.CompiledTemplate = CompiledTemplate;
|
|
383
|
+
exports.Slot = Slot;
|
|
384
|
+
exports.buildSlotLookup = buildSlotLookup;
|
|
385
|
+
exports.compile = compile;
|
|
386
|
+
exports.compileSync = compileSync;
|
|
387
|
+
exports.decodeName = decodeName;
|
|
388
|
+
exports.defineSlots = defineSlots;
|
|
389
|
+
exports.makeAttrMarker = makeAttrMarker;
|
|
390
|
+
exports.makeContentMarker = makeContentMarker;
|
|
391
|
+
exports.normalizeRenderable = normalizeRenderable;
|
|
157
392
|
exports.plainTextSelectors = plainTextSelectors;
|
|
158
393
|
exports.pretty = pretty;
|
|
394
|
+
exports.removeSolidResourceScripts = removeSolidResourceScripts;
|
|
159
395
|
exports.render = render;
|
|
396
|
+
exports.renderDocument = renderDocument;
|
|
397
|
+
exports.renderOutput = renderOutput;
|
|
160
398
|
exports.renderSync = renderSync;
|
|
399
|
+
exports.renderSyncOutput = renderSyncOutput;
|
|
400
|
+
exports.slot = slot;
|
|
161
401
|
exports.toPlainText = toPlainText;
|
package/dist/browser/index.d.cts
CHANGED
|
@@ -20,9 +20,61 @@ type RenderSyncOptions = {
|
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region src/shared/render.d.ts
|
|
22
22
|
type Renderable = JSX.Element | (() => JSX.Element);
|
|
23
|
+
declare function normalizeRenderable(node: Renderable): () => JSX.Element;
|
|
24
|
+
declare function removeSolidResourceScripts(html: string): string;
|
|
25
|
+
declare function renderDocument(html: string): string;
|
|
26
|
+
declare function renderSyncOutput(html: string, options?: RenderSyncOptions): string;
|
|
27
|
+
declare function renderOutput(html: string, options?: Options): Promise<string>;
|
|
23
28
|
declare function render(node: Renderable, options?: Options): Promise<string>;
|
|
24
29
|
declare function renderSync(node: Renderable, options?: RenderSyncOptions): string;
|
|
25
30
|
//#endregion
|
|
31
|
+
//#region src/shared/slots.d.ts
|
|
32
|
+
type SlotPrimitive = string | number | boolean | null | undefined;
|
|
33
|
+
type SlotValue = SlotPrimitive | JSX.Element | SlotValue[];
|
|
34
|
+
type SlotRecord = Record<string, SlotValue>;
|
|
35
|
+
declare function decodeName(encoded: string): string;
|
|
36
|
+
declare function makeContentMarker(name: string, defaultValue?: string): string;
|
|
37
|
+
declare function makeAttrMarker(name: string): string;
|
|
38
|
+
interface SlotOccurrence {
|
|
39
|
+
full: string;
|
|
40
|
+
hasDefault: boolean;
|
|
41
|
+
defaultValue: string;
|
|
42
|
+
}
|
|
43
|
+
declare function buildSlotLookup(html: string): {
|
|
44
|
+
content: Map<string, SlotOccurrence[]>;
|
|
45
|
+
attr: Map<string, string[]>;
|
|
46
|
+
};
|
|
47
|
+
declare function Slot(props: {
|
|
48
|
+
name: string;
|
|
49
|
+
children?: JSX.Element;
|
|
50
|
+
}): JSX.Element;
|
|
51
|
+
declare function slot(name: string): string;
|
|
52
|
+
interface SlotDefinition<T extends SlotRecord> {
|
|
53
|
+
content: <K extends keyof T & string>(name: K, defaultValue?: string) => string;
|
|
54
|
+
attr: <K extends keyof T & string>(name: K) => string;
|
|
55
|
+
}
|
|
56
|
+
declare function defineSlots<T extends SlotRecord>(): SlotDefinition<T>;
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/shared/compile.d.ts
|
|
59
|
+
declare class CompiledTemplate<TSlots extends Record<string, SlotValue> = Record<string, SlotValue>> {
|
|
60
|
+
private readonly html;
|
|
61
|
+
private readonly options?;
|
|
62
|
+
private readonly contentSlots;
|
|
63
|
+
private readonly attrSlots;
|
|
64
|
+
private readonly markerRegex;
|
|
65
|
+
constructor(html: string, options?: Options);
|
|
66
|
+
render(data: TSlots, options?: Options): Promise<string>;
|
|
67
|
+
renderSync(data: TSlots, options?: RenderSyncOptions): string;
|
|
68
|
+
private buildMarkerRegex;
|
|
69
|
+
private validateSlots;
|
|
70
|
+
private replaceSlots;
|
|
71
|
+
private replaceSlotsInFragment;
|
|
72
|
+
private replaceSlotsSync;
|
|
73
|
+
private replaceSlotsInFragmentSync;
|
|
74
|
+
}
|
|
75
|
+
declare function compile<TSlots extends Record<string, SlotValue> = Record<string, SlotValue>>(node: Renderable, options?: Options): Promise<CompiledTemplate<TSlots>>;
|
|
76
|
+
declare function compileSync<TSlots extends Record<string, SlotValue> = Record<string, SlotValue>>(node: Renderable, options?: RenderSyncOptions): CompiledTemplate<TSlots>;
|
|
77
|
+
//#endregion
|
|
26
78
|
//#region src/shared/utils/pretty.d.ts
|
|
27
79
|
declare const pretty: (str: string, options?: Options$1) => Promise<string>;
|
|
28
80
|
//#endregion
|
|
@@ -30,5 +82,5 @@ declare const pretty: (str: string, options?: Options$1) => Promise<string>;
|
|
|
30
82
|
declare const plainTextSelectors: SelectorDefinition[];
|
|
31
83
|
declare function toPlainText(html: string, options?: HtmlToTextOptions): string;
|
|
32
84
|
//#endregion
|
|
33
|
-
export { Options, RenderSyncOptions, Renderable, plainTextSelectors, pretty, render, renderSync, toPlainText };
|
|
85
|
+
export { CompiledTemplate, Options, RenderSyncOptions, Renderable, Slot, SlotDefinition, SlotOccurrence, SlotPrimitive, SlotRecord, SlotValue, buildSlotLookup, compile, compileSync, decodeName, defineSlots, makeAttrMarker, makeContentMarker, normalizeRenderable, plainTextSelectors, pretty, removeSolidResourceScripts, render, renderDocument, renderOutput, renderSync, renderSyncOutput, slot, toPlainText };
|
|
34
86
|
//# sourceMappingURL=index.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/render.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts"],"mappings":";;;;;KAEK,iBAAA;EACH,SAAS;AAAA;AAAA,KAGN,gBAAA;EACH,SAAA;EACA,iBAAA,GAAoB,iBAAiB;AAAA;AAAA,KAGlC,gBAAA,GAAmB,iBAAA,GAAoB,gBAAgB;AAAA,KAEhD,OAAA;EACV,MAAA;AAAA,IACE,gBAAgB;AAAA,KAER,iBAAA;EACV,MAAA;AAAA,IACE,gBAAgB;;;KCVR,UAAA,GAAa,GAAA,CAAI,OAAA,UAAiB,GAAA,CAAI,OAAO;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/render.ts","../../src/shared/slots.ts","../../src/shared/compile.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts"],"mappings":"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"}
|
package/dist/browser/index.d.mts
CHANGED
|
@@ -20,9 +20,61 @@ type RenderSyncOptions = {
|
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region src/shared/render.d.ts
|
|
22
22
|
type Renderable = JSX.Element | (() => JSX.Element);
|
|
23
|
+
declare function normalizeRenderable(node: Renderable): () => JSX.Element;
|
|
24
|
+
declare function removeSolidResourceScripts(html: string): string;
|
|
25
|
+
declare function renderDocument(html: string): string;
|
|
26
|
+
declare function renderSyncOutput(html: string, options?: RenderSyncOptions): string;
|
|
27
|
+
declare function renderOutput(html: string, options?: Options): Promise<string>;
|
|
23
28
|
declare function render(node: Renderable, options?: Options): Promise<string>;
|
|
24
29
|
declare function renderSync(node: Renderable, options?: RenderSyncOptions): string;
|
|
25
30
|
//#endregion
|
|
31
|
+
//#region src/shared/slots.d.ts
|
|
32
|
+
type SlotPrimitive = string | number | boolean | null | undefined;
|
|
33
|
+
type SlotValue = SlotPrimitive | JSX.Element | SlotValue[];
|
|
34
|
+
type SlotRecord = Record<string, SlotValue>;
|
|
35
|
+
declare function decodeName(encoded: string): string;
|
|
36
|
+
declare function makeContentMarker(name: string, defaultValue?: string): string;
|
|
37
|
+
declare function makeAttrMarker(name: string): string;
|
|
38
|
+
interface SlotOccurrence {
|
|
39
|
+
full: string;
|
|
40
|
+
hasDefault: boolean;
|
|
41
|
+
defaultValue: string;
|
|
42
|
+
}
|
|
43
|
+
declare function buildSlotLookup(html: string): {
|
|
44
|
+
content: Map<string, SlotOccurrence[]>;
|
|
45
|
+
attr: Map<string, string[]>;
|
|
46
|
+
};
|
|
47
|
+
declare function Slot(props: {
|
|
48
|
+
name: string;
|
|
49
|
+
children?: JSX.Element;
|
|
50
|
+
}): JSX.Element;
|
|
51
|
+
declare function slot(name: string): string;
|
|
52
|
+
interface SlotDefinition<T extends SlotRecord> {
|
|
53
|
+
content: <K extends keyof T & string>(name: K, defaultValue?: string) => string;
|
|
54
|
+
attr: <K extends keyof T & string>(name: K) => string;
|
|
55
|
+
}
|
|
56
|
+
declare function defineSlots<T extends SlotRecord>(): SlotDefinition<T>;
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/shared/compile.d.ts
|
|
59
|
+
declare class CompiledTemplate<TSlots extends Record<string, SlotValue> = Record<string, SlotValue>> {
|
|
60
|
+
private readonly html;
|
|
61
|
+
private readonly options?;
|
|
62
|
+
private readonly contentSlots;
|
|
63
|
+
private readonly attrSlots;
|
|
64
|
+
private readonly markerRegex;
|
|
65
|
+
constructor(html: string, options?: Options);
|
|
66
|
+
render(data: TSlots, options?: Options): Promise<string>;
|
|
67
|
+
renderSync(data: TSlots, options?: RenderSyncOptions): string;
|
|
68
|
+
private buildMarkerRegex;
|
|
69
|
+
private validateSlots;
|
|
70
|
+
private replaceSlots;
|
|
71
|
+
private replaceSlotsInFragment;
|
|
72
|
+
private replaceSlotsSync;
|
|
73
|
+
private replaceSlotsInFragmentSync;
|
|
74
|
+
}
|
|
75
|
+
declare function compile<TSlots extends Record<string, SlotValue> = Record<string, SlotValue>>(node: Renderable, options?: Options): Promise<CompiledTemplate<TSlots>>;
|
|
76
|
+
declare function compileSync<TSlots extends Record<string, SlotValue> = Record<string, SlotValue>>(node: Renderable, options?: RenderSyncOptions): CompiledTemplate<TSlots>;
|
|
77
|
+
//#endregion
|
|
26
78
|
//#region src/shared/utils/pretty.d.ts
|
|
27
79
|
declare const pretty: (str: string, options?: Options$1) => Promise<string>;
|
|
28
80
|
//#endregion
|
|
@@ -30,5 +82,5 @@ declare const pretty: (str: string, options?: Options$1) => Promise<string>;
|
|
|
30
82
|
declare const plainTextSelectors: SelectorDefinition[];
|
|
31
83
|
declare function toPlainText(html: string, options?: HtmlToTextOptions): string;
|
|
32
84
|
//#endregion
|
|
33
|
-
export { Options, RenderSyncOptions, Renderable, plainTextSelectors, pretty, render, renderSync, toPlainText };
|
|
85
|
+
export { CompiledTemplate, Options, RenderSyncOptions, Renderable, Slot, SlotDefinition, SlotOccurrence, SlotPrimitive, SlotRecord, SlotValue, buildSlotLookup, compile, compileSync, decodeName, defineSlots, makeAttrMarker, makeContentMarker, normalizeRenderable, plainTextSelectors, pretty, removeSolidResourceScripts, render, renderDocument, renderOutput, renderSync, renderSyncOutput, slot, toPlainText };
|
|
34
86
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/render.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts"],"mappings":";;;;;KAEK,iBAAA;EACH,SAAS;AAAA;AAAA,KAGN,gBAAA;EACH,SAAA;EACA,iBAAA,GAAoB,iBAAiB;AAAA;AAAA,KAGlC,gBAAA,GAAmB,iBAAA,GAAoB,gBAAgB;AAAA,KAEhD,OAAA;EACV,MAAA;AAAA,IACE,gBAAgB;AAAA,KAER,iBAAA;EACV,MAAA;AAAA,IACE,gBAAgB;;;KCVR,UAAA,GAAa,GAAA,CAAI,OAAA,UAAiB,GAAA,CAAI,OAAO;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/shared/options.ts","../../src/shared/render.ts","../../src/shared/slots.ts","../../src/shared/compile.ts","../../src/shared/utils/pretty.ts","../../src/shared/utils/to-plain-text.ts"],"mappings":"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"}
|
package/dist/browser/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { renderToString, renderToStringAsync } from "solid-js/web/dist/server.js
|
|
|
2
2
|
import * as html from "prettier/plugins/html";
|
|
3
3
|
import { format } from "prettier/standalone";
|
|
4
4
|
import { convert } from "html-to-text";
|
|
5
|
+
import { ssr } from "solid-js/web";
|
|
5
6
|
//#region src/shared/utils/pretty.ts
|
|
6
7
|
function getHtmlNode(path) {
|
|
7
8
|
const topNode = path.node;
|
|
@@ -130,6 +131,230 @@ function renderSync(node, options) {
|
|
|
130
131
|
return renderSyncOutput(removeSolidResourceScripts(renderToString(normalizeRenderable(node))), options);
|
|
131
132
|
}
|
|
132
133
|
//#endregion
|
|
133
|
-
|
|
134
|
+
//#region src/shared/slots.ts
|
|
135
|
+
const MARKER_PREFIX = "__SM_";
|
|
136
|
+
const CONTENT_START = `${MARKER_PREFIX}CNT_`;
|
|
137
|
+
const CONTENT_END = `${MARKER_PREFIX}CNE_`;
|
|
138
|
+
const ATTR_PREFIX = `${MARKER_PREFIX}ATR_`;
|
|
139
|
+
function encodeName(name) {
|
|
140
|
+
return encodeURIComponent(name).replace(/[!'()*_]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
141
|
+
}
|
|
142
|
+
function decodeName(encoded) {
|
|
143
|
+
return decodeURIComponent(encoded);
|
|
144
|
+
}
|
|
145
|
+
function makeContentMarker(name, defaultValue) {
|
|
146
|
+
const encoded = encodeName(name);
|
|
147
|
+
const start = `${CONTENT_START}${encoded}__`;
|
|
148
|
+
if (defaultValue !== void 0) return `${start}${defaultValue}${CONTENT_END}${encoded}__`;
|
|
149
|
+
return `${start}${CONTENT_END}${encoded}__`;
|
|
150
|
+
}
|
|
151
|
+
function makeAttrMarker(name) {
|
|
152
|
+
return `${ATTR_PREFIX}${encodeName(name)}__`;
|
|
153
|
+
}
|
|
154
|
+
function escapeRegex$1(str) {
|
|
155
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
156
|
+
}
|
|
157
|
+
function buildSlotLookup(html) {
|
|
158
|
+
const contentSlots = /* @__PURE__ */ new Map();
|
|
159
|
+
const attrSlots = /* @__PURE__ */ new Map();
|
|
160
|
+
const nameChars = "(?:[A-Za-z0-9.~-]|%[0-9A-Fa-f]{2})+";
|
|
161
|
+
const tokenRegex = new RegExp(`${escapeRegex$1(CONTENT_START)}(${nameChars})__|${escapeRegex$1(CONTENT_END)}(${nameChars})__`, "g");
|
|
162
|
+
const stack = [];
|
|
163
|
+
let match;
|
|
164
|
+
while (true) {
|
|
165
|
+
match = tokenRegex.exec(html);
|
|
166
|
+
if (match === null) break;
|
|
167
|
+
const startName = match[1];
|
|
168
|
+
if (startName !== void 0) {
|
|
169
|
+
stack.push({
|
|
170
|
+
encodedName: startName,
|
|
171
|
+
name: decodeName(startName),
|
|
172
|
+
startIndex: match.index,
|
|
173
|
+
contentStartIndex: tokenRegex.lastIndex
|
|
174
|
+
});
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const endName = match[2];
|
|
178
|
+
if (endName === void 0) continue;
|
|
179
|
+
let openIndex = -1;
|
|
180
|
+
for (let index = stack.length - 1; index >= 0; index -= 1) if (stack[index]?.encodedName === endName) {
|
|
181
|
+
openIndex = index;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
if (openIndex === -1) continue;
|
|
185
|
+
const [open] = stack.splice(openIndex, 1);
|
|
186
|
+
if (open === void 0) continue;
|
|
187
|
+
const innerContent = html.slice(open.contentStartIndex, match.index);
|
|
188
|
+
const occurrence = {
|
|
189
|
+
full: html.slice(open.startIndex, tokenRegex.lastIndex),
|
|
190
|
+
hasDefault: innerContent.length > 0,
|
|
191
|
+
defaultValue: innerContent
|
|
192
|
+
};
|
|
193
|
+
const existing = contentSlots.get(open.name);
|
|
194
|
+
if (existing) existing.push(occurrence);
|
|
195
|
+
else contentSlots.set(open.name, [occurrence]);
|
|
196
|
+
}
|
|
197
|
+
const attrRegex = new RegExp(`${escapeRegex$1(ATTR_PREFIX)}(${nameChars})__`, "g");
|
|
198
|
+
while (true) {
|
|
199
|
+
match = attrRegex.exec(html);
|
|
200
|
+
if (match === null) break;
|
|
201
|
+
const name = decodeName(match[1] ?? "");
|
|
202
|
+
const existing = attrSlots.get(name);
|
|
203
|
+
if (existing) existing.push(match[0]);
|
|
204
|
+
else attrSlots.set(name, [match[0]]);
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
content: contentSlots,
|
|
208
|
+
attr: attrSlots
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function Slot(props) {
|
|
212
|
+
const encoded = encodeName(props.name);
|
|
213
|
+
const start = ssr(`${CONTENT_START}${encoded}__`);
|
|
214
|
+
const end = ssr(`${CONTENT_END}${encoded}__`);
|
|
215
|
+
if (props.children !== void 0 && props.children !== null) return [
|
|
216
|
+
start,
|
|
217
|
+
props.children,
|
|
218
|
+
end
|
|
219
|
+
];
|
|
220
|
+
return [start, end];
|
|
221
|
+
}
|
|
222
|
+
function slot(name) {
|
|
223
|
+
return makeAttrMarker(name);
|
|
224
|
+
}
|
|
225
|
+
function defineSlots() {
|
|
226
|
+
return {
|
|
227
|
+
content: (name, defaultValue) => makeContentMarker(name, defaultValue),
|
|
228
|
+
attr: (name) => makeAttrMarker(name)
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/shared/compile.ts
|
|
233
|
+
var CompiledTemplate = class {
|
|
234
|
+
html;
|
|
235
|
+
options;
|
|
236
|
+
contentSlots;
|
|
237
|
+
attrSlots;
|
|
238
|
+
markerRegex;
|
|
239
|
+
constructor(html, options) {
|
|
240
|
+
this.html = html;
|
|
241
|
+
this.options = options;
|
|
242
|
+
const lookup = buildSlotLookup(html);
|
|
243
|
+
this.contentSlots = lookup.content;
|
|
244
|
+
this.attrSlots = lookup.attr;
|
|
245
|
+
this.markerRegex = this.buildMarkerRegex();
|
|
246
|
+
}
|
|
247
|
+
async render(data, options) {
|
|
248
|
+
let result = this.html;
|
|
249
|
+
result = await this.replaceSlots(result, data);
|
|
250
|
+
return renderOutput(result, options ?? this.options);
|
|
251
|
+
}
|
|
252
|
+
renderSync(data, options) {
|
|
253
|
+
if ((options ?? this.options)?.pretty) throw new Error("renderSync does not support pretty output; use render.");
|
|
254
|
+
let result = this.html;
|
|
255
|
+
result = this.replaceSlotsSync(result, data);
|
|
256
|
+
return renderSyncOutput(result, options ?? this.options);
|
|
257
|
+
}
|
|
258
|
+
buildMarkerRegex() {
|
|
259
|
+
const markers = /* @__PURE__ */ new Set();
|
|
260
|
+
for (const occurrences of this.contentSlots.values()) for (const occ of occurrences) markers.add(occ.full);
|
|
261
|
+
for (const attrMarkers of this.attrSlots.values()) for (const marker of attrMarkers) markers.add(marker);
|
|
262
|
+
if (markers.size === 0) return /$^/g;
|
|
263
|
+
return new RegExp(Array.from(markers).sort((a, b) => b.length - a.length).map(escapeRegex).join("|"), "g");
|
|
264
|
+
}
|
|
265
|
+
validateSlots(data) {
|
|
266
|
+
const allSlotNames = /* @__PURE__ */ new Set([...this.contentSlots.keys(), ...this.attrSlots.keys()]);
|
|
267
|
+
for (const name of allSlotNames) if (data[name] === void 0) {
|
|
268
|
+
if (!(this.contentSlots.get(name)?.some((occ) => occ.hasDefault) ?? false)) console.warn(`[solid-email] Slot "${name}" has no default and was not provided in render data. It will render as empty.`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
async replaceSlots(result, data) {
|
|
272
|
+
return this.replaceSlotsInFragment(result, data, true);
|
|
273
|
+
}
|
|
274
|
+
async replaceSlotsInFragment(result, data, validate) {
|
|
275
|
+
if (validate) this.validateSlots(data);
|
|
276
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
277
|
+
for (const [name, occurrences] of this.contentSlots) {
|
|
278
|
+
const value = data[name];
|
|
279
|
+
const rendered = value !== void 0 ? await renderSlotValueAsync(value) : void 0;
|
|
280
|
+
for (const occ of occurrences) {
|
|
281
|
+
if (!result.includes(occ.full)) continue;
|
|
282
|
+
const replacement = rendered ?? await this.replaceSlotsInFragment(occ.defaultValue, data, false);
|
|
283
|
+
replacements.set(occ.full, replacement);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
for (const [name, markers] of this.attrSlots) {
|
|
287
|
+
const value = data[name];
|
|
288
|
+
const replacement = renderAttrValue(name, value);
|
|
289
|
+
for (const marker of markers) replacements.set(marker, replacement);
|
|
290
|
+
}
|
|
291
|
+
if (replacements.size === 0) return result;
|
|
292
|
+
return result.replace(this.markerRegex, (marker) => replacements.get(marker) ?? marker);
|
|
293
|
+
}
|
|
294
|
+
replaceSlotsSync(result, data) {
|
|
295
|
+
return this.replaceSlotsInFragmentSync(result, data, true);
|
|
296
|
+
}
|
|
297
|
+
replaceSlotsInFragmentSync(result, data, validate) {
|
|
298
|
+
if (validate) this.validateSlots(data);
|
|
299
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
300
|
+
for (const [name, occurrences] of this.contentSlots) {
|
|
301
|
+
const value = data[name];
|
|
302
|
+
const rendered = value !== void 0 ? renderSlotValueSync(value) : void 0;
|
|
303
|
+
for (const occ of occurrences) {
|
|
304
|
+
if (!result.includes(occ.full)) continue;
|
|
305
|
+
const replacement = rendered ?? this.replaceSlotsInFragmentSync(occ.defaultValue, data, false);
|
|
306
|
+
replacements.set(occ.full, replacement);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
for (const [name, markers] of this.attrSlots) {
|
|
310
|
+
const value = data[name];
|
|
311
|
+
const replacement = renderAttrValue(name, value);
|
|
312
|
+
for (const marker of markers) replacements.set(marker, replacement);
|
|
313
|
+
}
|
|
314
|
+
if (replacements.size === 0) return result;
|
|
315
|
+
return result.replace(this.markerRegex, (marker) => replacements.get(marker) ?? marker);
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
async function renderSlotValueAsync(value) {
|
|
319
|
+
if (value == null) return "";
|
|
320
|
+
if (Array.isArray(value)) return Promise.all(value.map(renderSlotValueAsync)).then((results) => results.join(""));
|
|
321
|
+
if (typeof value === "boolean") return value ? "true" : "";
|
|
322
|
+
if (typeof value === "string") return escapeHtml(value);
|
|
323
|
+
if (typeof value === "number") return String(value);
|
|
324
|
+
return removeSolidResourceScripts(await renderToStringAsync(() => value));
|
|
325
|
+
}
|
|
326
|
+
function renderSlotValueSync(value) {
|
|
327
|
+
if (value == null) return "";
|
|
328
|
+
if (Array.isArray(value)) return value.map(renderSlotValueSync).join("");
|
|
329
|
+
if (typeof value === "boolean") return value ? "true" : "";
|
|
330
|
+
if (typeof value === "string") return escapeHtml(value);
|
|
331
|
+
if (typeof value === "number") return String(value);
|
|
332
|
+
return removeSolidResourceScripts(renderToString(() => value));
|
|
333
|
+
}
|
|
334
|
+
function renderAttrValue(name, value) {
|
|
335
|
+
if (value == null) return "";
|
|
336
|
+
if (typeof value === "boolean") return value ? "true" : "";
|
|
337
|
+
if (typeof value === "string") return escapeAttr(value);
|
|
338
|
+
if (typeof value === "number") return String(value);
|
|
339
|
+
throw new TypeError(`Attribute slot "${name}" only accepts string, number, boolean, null, or undefined. Use <Slot name="${name}" /> for JSX/content values.`);
|
|
340
|
+
}
|
|
341
|
+
function escapeHtml(str) {
|
|
342
|
+
return str.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
343
|
+
}
|
|
344
|
+
function escapeAttr(str) {
|
|
345
|
+
return str.replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<").replaceAll(">", ">");
|
|
346
|
+
}
|
|
347
|
+
function escapeRegex(str) {
|
|
348
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
349
|
+
}
|
|
350
|
+
async function compile(node, options) {
|
|
351
|
+
return new CompiledTemplate(removeSolidResourceScripts(await renderToStringAsync(normalizeRenderable(node))), options);
|
|
352
|
+
}
|
|
353
|
+
function compileSync(node, options) {
|
|
354
|
+
if (options?.pretty) throw new Error("compileSync does not support pretty output; use compile.");
|
|
355
|
+
return new CompiledTemplate(removeSolidResourceScripts(renderToString(normalizeRenderable(node))), options);
|
|
356
|
+
}
|
|
357
|
+
//#endregion
|
|
358
|
+
export { CompiledTemplate, Slot, buildSlotLookup, compile, compileSync, decodeName, defineSlots, makeAttrMarker, makeContentMarker, normalizeRenderable, plainTextSelectors, pretty, removeSolidResourceScripts, render, renderDocument, renderOutput, renderSync, renderSyncOutput, slot, toPlainText };
|
|
134
359
|
|
|
135
360
|
//# sourceMappingURL=index.mjs.map
|