@samva/markup 0.8.0 → 0.9.0
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/AGENTS.md +90 -37
- package/README.md +188 -52
- package/dist/assets-C5duwTya.d.ts +40 -0
- package/dist/{brand-DcoVkh_S.d.ts → brand-B-0bN_Ir.d.ts} +2 -2
- package/dist/{render-vAv_4r9v.js → cascade-t6kxlgEI.js} +93 -280
- package/dist/channel-edit.d.ts +121 -0
- package/dist/channel-edit.js +609 -0
- package/dist/channel-specs-B6M_HlaV.js +29 -0
- package/dist/channel-specs-C2feJwuP.d.ts +13 -0
- package/dist/compatibility-DbISoFIq.js +589 -0
- package/dist/compiler.d.ts +10 -257
- package/dist/compiler.js +10 -730
- package/dist/{css-CS2jLID6.d.ts → css-BVQKICKC.d.ts} +3 -3
- package/dist/diagnostic-codes.d.ts +403 -0
- package/dist/diagnostic-codes.js +399 -0
- package/dist/{diagnostics-BMYtBCQk.d.ts → diagnostics-B-Gym34R.d.ts} +8 -4
- package/dist/diagnostics.d.ts +31 -2
- package/dist/diagnostics.js +1 -19
- package/dist/{elements-BzjjnoCS.d.ts → elements-cqldpaJt.d.ts} +3 -3
- package/dist/email/assets.d.ts +2 -40
- package/dist/email/brand-footer.d.ts +2 -2
- package/dist/email/brand-footer.js +4 -3
- package/dist/email/brand.d.ts +1 -1
- package/dist/email/brand.js +1 -1
- package/dist/email/components.d.ts +21 -10
- package/dist/email/components.js +46 -11
- package/dist/email/diagnostics.d.ts +2 -2
- package/dist/email/diagnostics.js +2 -1
- package/dist/email/elements.d.ts +1 -1
- package/dist/email/html.d.ts +2 -2
- package/dist/email/html.js +45 -2
- package/dist/email/jsx-dev-runtime.d.ts +2 -2
- package/dist/email/jsx-runtime.d.ts +1 -1
- package/dist/email/render.d.ts +8 -18
- package/dist/email/render.js +163 -3
- package/dist/email/text.d.ts +1 -1
- package/dist/fmt.d.ts +32 -0
- package/dist/fmt.js +174 -0
- package/dist/{html-Bl9BAdqc.d.ts → html-BJepOwZ4.d.ts} +19 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/ir-aaqNE987.d.ts +252 -0
- package/dist/ir.d.ts +2 -0
- package/dist/ir.js +7 -0
- package/dist/preview-Ekdg1dXG.d.ts +100 -0
- package/dist/preview.d.ts +2 -0
- package/dist/preview.js +160 -0
- package/dist/profile-BH-OtdDA.js +3670 -0
- package/dist/render-ir.d.ts +19 -0
- package/dist/render-ir.js +826 -0
- package/dist/sms-segments.d.ts +13 -2
- package/dist/sms.d.ts +16 -0
- package/dist/sms.js +12 -0
- package/dist/{email/source-edit.d.ts → source-edit.d.ts} +55 -6
- package/dist/source-edit.js +343 -0
- package/dist/source-locations-C8wCsiAy.d.ts +23 -0
- package/dist/source-locations.d.ts +2 -2
- package/dist/source-locations.js +3 -89
- package/dist/static.d.ts +57 -0
- package/dist/static.js +69 -0
- package/dist/tailwind-CMYpZf1v.js +614 -0
- package/dist/template-_QE_rQND.d.ts +65 -0
- package/dist/template.d.ts +2 -2
- package/dist/template.js +15 -10
- package/dist/theme-css.d.ts +1 -1
- package/dist/theme-imports-lvBw3AD1.js +109 -0
- package/dist/transform-Ct2OMkFN.d.ts +153 -0
- package/dist/whatsapp.d.ts +57 -0
- package/dist/whatsapp.js +22 -0
- package/generated/contract.json +1782 -0
- package/generated/reference.md +353 -0
- package/package.json +41 -151
- package/skills/sml/SKILL.md +123 -0
- package/dist/ast-BrDtApwS.d.ts +0 -107
- package/dist/ast.d.ts +0 -2
- package/dist/ast.js +0 -124
- package/dist/candidate.d.ts +0 -29
- package/dist/candidate.js +0 -88
- package/dist/catalog-CKuOooB8.d.ts +0 -354
- package/dist/checks-D73Xizbw.js +0 -59366
- package/dist/checks.d.ts +0 -33
- package/dist/checks.js +0 -2
- package/dist/classes.d.ts +0 -26
- package/dist/classes.js +0 -184
- package/dist/compile-sms.d.ts +0 -28
- package/dist/compile-sms.js +0 -44
- package/dist/compile-whatsapp.d.ts +0 -56
- package/dist/compile-whatsapp.js +0 -186
- package/dist/compile.d.ts +0 -18
- package/dist/compile.js +0 -29
- package/dist/components.d.ts +0 -289
- package/dist/components.js +0 -106
- package/dist/conditionals.d.ts +0 -10
- package/dist/conditionals.js +0 -74
- package/dist/corpus-CPPfgAHN.d.ts +0 -106
- package/dist/diagnostics-OcQKQYSY.d.ts +0 -49
- package/dist/email/selection.d.ts +0 -2
- package/dist/email/selection.js +0 -91
- package/dist/email/source-edit.js +0 -185
- package/dist/email/stylesheets.d.ts +0 -15
- package/dist/email/stylesheets.js +0 -48
- package/dist/emit.d.ts +0 -51
- package/dist/emit.js +0 -151
- package/dist/interpolate.d.ts +0 -24
- package/dist/interpolate.js +0 -43
- package/dist/jsx-dev-runtime.d.ts +0 -11
- package/dist/jsx-dev-runtime.js +0 -15
- package/dist/jsx-runtime-I-1nCtl2.d.ts +0 -57
- package/dist/jsx-runtime.d.ts +0 -2
- package/dist/jsx-runtime.js +0 -121
- package/dist/lexer.d.ts +0 -60
- package/dist/lexer.js +0 -281
- package/dist/model.d.ts +0 -24
- package/dist/model.js +0 -77
- package/dist/ops-BvwqHl7V.js +0 -630
- package/dist/ops.d.ts +0 -114
- package/dist/ops.js +0 -2
- package/dist/parser-t29cHLVL.d.ts +0 -396
- package/dist/parser.d.ts +0 -2
- package/dist/parser.js +0 -859
- package/dist/predicate-BI6uRRM-.js +0 -549
- package/dist/predicate-M-05Nd7R.d.ts +0 -56
- package/dist/predicate.d.ts +0 -2
- package/dist/predicate.js +0 -2
- package/dist/printer.d.ts +0 -6
- package/dist/printer.js +0 -122
- package/dist/registry-Dcp6QEK_.d.ts +0 -73
- package/dist/registry.d.ts +0 -2
- package/dist/registry.js +0 -646
- package/dist/render-template.d.ts +0 -45
- package/dist/render-template.js +0 -76
- package/dist/selection-CCArx9lU.d.ts +0 -91
- package/dist/showcase-egkusQBf.d.ts +0 -415
- package/dist/sms-segments-y4FpPilJ.d.ts +0 -13
- package/dist/source-locations-DrCM82Ym.d.ts +0 -67
- package/dist/starters/category-mapping.d.ts +0 -13
- package/dist/starters/category-mapping.js +0 -49
- package/dist/starters/corpus.d.ts +0 -2
- package/dist/starters/corpus.js +0 -194
- package/dist/starters/library.d.ts +0 -18
- package/dist/starters/library.js +0 -692
- package/dist/starters/public-gallery.d.ts +0 -266
- package/dist/starters/public-gallery.js +0 -916
- package/dist/starters/public-handoff.d.ts +0 -164
- package/dist/starters/public-handoff.js +0 -361
- package/dist/starters/public-preview-artifacts.d.ts +0 -43
- package/dist/starters/public-preview-artifacts.js +0 -104
- package/dist/starters/public-preview.d.ts +0 -61
- package/dist/starters/public-preview.js +0 -83
- package/dist/starters/showcase.d.ts +0 -2
- package/dist/starters/showcase.js +0 -335
- package/dist/starters/sources.d.ts +0 -45
- package/dist/starters/sources.js +0 -7762
- package/dist/starters/theme.d.ts +0 -45
- package/dist/starters/theme.js +0 -77
- package/dist/starters.d.ts +0 -2
- package/dist/starters.js +0 -874
- package/dist/tailwind-BYq7Lo6u.js +0 -727
- package/dist/template-DWftqh4x.d.ts +0 -60
- package/dist/tsx-source-instrumentation.d.ts +0 -30
- package/dist/tsx-source-instrumentation.js +0 -115
- package/dist/tsx-tracer.d.ts +0 -112
- package/dist/tsx-tracer.js +0 -985
- package/dist/variables-J_L3qxRa.d.ts +0 -77
- package/dist/variables.d.ts +0 -2
- package/dist/variables.js +0 -141
- package/dist/version-BITr58kk.js +0 -96
- package/generated/sml-agent-contract.json +0 -709
- package/generated/sml-email-agent-contract.json +0 -615
- package/generated/sml-email-language-reference.md +0 -94
- package/generated/sml-language-reference.md +0 -195
package/dist/email/components.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx, rawMarkup, reportEmailDiagnostic } from "./jsx-runtime.js";
|
|
1
|
+
import { EmailNode, Fragment, jsx, normalizeChildren, rawMarkup, reportEmailDiagnostic } from "./jsx-runtime.js";
|
|
2
2
|
import { escapeAttribute, escapeText } from "./html.js";
|
|
3
3
|
//#region src/email/components.ts
|
|
4
4
|
/** Marks the hidden preview block so the renderer can read it back and the text lane can keep it. */
|
|
@@ -34,7 +34,7 @@ const preheaderNode = (text) => jsx("div", {
|
|
|
34
34
|
})]
|
|
35
35
|
});
|
|
36
36
|
/** Document shell: the head every target client needs, plus the body content cell. */
|
|
37
|
-
const Email = ({ className, lang = "en", dir = "ltr", title,
|
|
37
|
+
const Email = ({ className, lang = "en", dir = "ltr", title, backgroundColor, style, children }) => jsx("html", {
|
|
38
38
|
lang,
|
|
39
39
|
dir,
|
|
40
40
|
xmlns: "http://www.w3.org/1999/xhtml",
|
|
@@ -66,7 +66,7 @@ const Email = ({ className, lang = "en", dir = "ltr", title, preheader, backgrou
|
|
|
66
66
|
padding: 0,
|
|
67
67
|
...backgroundColor === void 0 ? {} : { backgroundColor }
|
|
68
68
|
},
|
|
69
|
-
children: [
|
|
69
|
+
children: [presentation({
|
|
70
70
|
align: "center",
|
|
71
71
|
width: "100%",
|
|
72
72
|
...backgroundColor === void 0 ? {} : { bgcolor: backgroundColor }
|
|
@@ -88,13 +88,48 @@ const Section = ({ className, align = "center", width = "100%", bgcolor, style,
|
|
|
88
88
|
...style === void 0 ? {} : { style },
|
|
89
89
|
children
|
|
90
90
|
}));
|
|
91
|
-
/**
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
width
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
/** The equal share of a row that each of `count` cells takes, whole percent rounded down. */
|
|
92
|
+
const equalColumnWidth = (count) => `${Math.floor(100 / count)}%`;
|
|
93
|
+
/** Give a `Column` that states no width its equal share, keeping the primitive's attribute order. */
|
|
94
|
+
const withColumnWidth = (node, width) => {
|
|
95
|
+
if (node.type === "Fragment") return EmailNode.Fragment({ children: node.children.map((child) => withColumnWidth(child, width)) });
|
|
96
|
+
if (node.type !== "Element" || node.tag !== "td" || node.props.width !== void 0) return node;
|
|
97
|
+
const props = {};
|
|
98
|
+
for (const [key, value] of Object.entries(node.props)) {
|
|
99
|
+
if (key === "style") props.width = width;
|
|
100
|
+
props[key] = value;
|
|
101
|
+
}
|
|
102
|
+
if (props.width === void 0) props.width = width;
|
|
103
|
+
return EmailNode.Element({
|
|
104
|
+
...node,
|
|
105
|
+
props
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* A row of side-by-side `Column`s. No flex or grid conversion happens here. With `each` it repeats
|
|
110
|
+
* its cells over a list, `per` to a row, and splits the row equally between cells that state no
|
|
111
|
+
* width.
|
|
112
|
+
*/
|
|
113
|
+
const Columns = ({ className, align = "center", width = "100%", style, each, per, children }) => {
|
|
114
|
+
const table = {
|
|
115
|
+
className,
|
|
116
|
+
align,
|
|
117
|
+
width,
|
|
118
|
+
...style === void 0 ? {} : { style }
|
|
119
|
+
};
|
|
120
|
+
if (each === void 0 || typeof children !== "function") return presentation(table, children, { style: { width: "100%" } });
|
|
121
|
+
if (per !== void 0 && (!Number.isInteger(per) || per < 1)) reportEmailDiagnostic({
|
|
122
|
+
code: "invalid-columns-per",
|
|
123
|
+
severity: "error",
|
|
124
|
+
message: "<Columns per> must be a positive integer."
|
|
125
|
+
});
|
|
126
|
+
const size = per !== void 0 && Number.isInteger(per) && per >= 1 ? per : void 0;
|
|
127
|
+
const chunks = [];
|
|
128
|
+
if (size === void 0) chunks.push(each);
|
|
129
|
+
else for (let at = 0; at < each.length; at += size) chunks.push(each.slice(at, at + size));
|
|
130
|
+
const share = equalColumnWidth(size ?? Math.max(each.length, 1));
|
|
131
|
+
return jsx(Fragment, { children: chunks.map((chunk) => presentation(table, chunk.flatMap((item, index) => normalizeChildren(children(item, index)).map((cell) => withColumnWidth(cell, share))), { style: { width: "100%" } })) });
|
|
132
|
+
};
|
|
98
133
|
/** One cell of a `Columns` row. */
|
|
99
134
|
const Column = ({ className, align, valign, width, style, children }) => jsx("td", {
|
|
100
135
|
className,
|
|
@@ -235,6 +270,6 @@ const Link = ({ className, href, target = "_blank", rel = "noopener noreferrer",
|
|
|
235
270
|
children
|
|
236
271
|
});
|
|
237
272
|
//#endregion
|
|
238
|
-
export { Button, Column, Columns, Divider, Email, Image, Link, PREHEADER_ATTRIBUTE, Section, Spacer, preheaderNode };
|
|
273
|
+
export { Button, Column, Columns, Divider, Email, Image, Link, PREHEADER_ATTRIBUTE, Section, Spacer, equalColumnWidth, preheaderNode };
|
|
239
274
|
|
|
240
275
|
//# sourceMappingURL=components.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { EmailCompatibilityAssessment, EmailCompileError, EmailDiagnostic, EmailDiagnosticSeverity, formatEmailDiagnostic, hasBlockingDiagnostic };
|
|
1
|
+
import { a as TemplateDiagnostic, i as EmailDiagnosticSeverity, n as EmailCompileError, o as formatEmailDiagnostic, r as EmailDiagnostic, s as hasBlockingDiagnostic, t as EmailCompatibilityAssessment } from "../diagnostics-B-Gym34R.js";
|
|
2
|
+
export { EmailCompatibilityAssessment, EmailCompileError, EmailDiagnostic, EmailDiagnosticSeverity, TemplateDiagnostic, formatEmailDiagnostic, hasBlockingDiagnostic };
|
|
@@ -11,7 +11,8 @@ var EmailCompileError = class extends TaggedError("EmailCompileError") {
|
|
|
11
11
|
/** `emails/welcome.tsx:12:3 unsupported-element: …` — the shape agents iterate on. */
|
|
12
12
|
const formatEmailDiagnostic = (diagnostic) => {
|
|
13
13
|
const origin = diagnostic.origins[0];
|
|
14
|
-
|
|
14
|
+
const head = `${origin === void 0 ? "<unknown source>" : `${origin.fileName}:${origin.lineNumber}:${origin.columnNumber}`} ${diagnostic.code}: ${diagnostic.message}`;
|
|
15
|
+
return diagnostic.fix === void 0 ? head : `${head}\n Fix: ${diagnostic.fix}`;
|
|
15
16
|
};
|
|
16
17
|
/** True when a set of findings must stop the compile or refuse a publication. */
|
|
17
18
|
const hasBlockingDiagnostic = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error");
|
package/dist/email/elements.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as EmailGlobalProps, c as EmailStyle, d as isUrlAttribute, i as EmailElementSpec, l as EmailTag, n as EMAIL_GLOBAL_ATTRIBUTES, o as EmailIntrinsicElements, r as EmailAttributeSpec, s as EmailLayout, t as EMAIL_ELEMENTS, u as emailElement } from "../elements-
|
|
1
|
+
import { a as EmailGlobalProps, c as EmailStyle, d as isUrlAttribute, i as EmailElementSpec, l as EmailTag, n as EMAIL_GLOBAL_ATTRIBUTES, o as EmailIntrinsicElements, r as EmailAttributeSpec, s as EmailLayout, t as EMAIL_ELEMENTS, u as emailElement } from "../elements-cqldpaJt.js";
|
|
2
2
|
export { EMAIL_ELEMENTS, EMAIL_GLOBAL_ATTRIBUTES, EmailAttributeSpec, EmailElementSpec, EmailGlobalProps, EmailIntrinsicElements, EmailLayout, EmailStyle, EmailTag, emailElement, isUrlAttribute };
|
package/dist/email/html.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { EmailHtmlOutput, SerializeEmailOptions, declarationValue, escapeAttribute, escapeText, kebab, serializeEmailHtml };
|
|
1
|
+
import { a as escapeAttribute, c as serializeEmailHtml, i as declarationValue, l as serializeStyle, n as SerializeEmailOptions, o as escapeText, r as checkAttribute, s as kebab, t as EmailHtmlOutput } from "../html-BJepOwZ4.js";
|
|
2
|
+
export { EmailHtmlOutput, SerializeEmailOptions, checkAttribute, declarationValue, escapeAttribute, escapeText, kebab, serializeEmailHtml, serializeStyle };
|
package/dist/email/html.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as isObject } from "../guards-eV1qLbf2.js";
|
|
2
2
|
import { i as UNSUBSCRIBE_URL_PLACEHOLDER, n as RESERVED_FOOTER_ATTRIBUTES, r as UNSUBSCRIBE_LINK, t as BRAND_FOOTER_MARKER } from "../unsubscribe-link-CoesnQDU.js";
|
|
3
3
|
import { EMAIL_ELEMENTS, EMAIL_GLOBAL_ATTRIBUTES, emailElement } from "./elements.js";
|
|
4
|
-
import { INSTANCE_PATH_ATTRIBUTE } from "
|
|
4
|
+
import { INSTANCE_PATH_ATTRIBUTE } from "../preview.js";
|
|
5
5
|
//#region src/email/html.ts
|
|
6
6
|
/** Escape a value for element content. */
|
|
7
7
|
const escapeText = (value) => value.replace(/[&<>]/g, (character) => ({
|
|
@@ -272,7 +272,50 @@ const serializeEmailHtml = (node, options = {}) => {
|
|
|
272
272
|
positions: sink.positions
|
|
273
273
|
};
|
|
274
274
|
};
|
|
275
|
+
/** An authored style object as a declaration list, checked by the same rules as a serialized tree. */
|
|
276
|
+
const serializeStyle = (style, origins) => {
|
|
277
|
+
const sink = {
|
|
278
|
+
diagnostics: [],
|
|
279
|
+
positions: [],
|
|
280
|
+
written: 0,
|
|
281
|
+
relativeUrls: false,
|
|
282
|
+
instancePaths: false
|
|
283
|
+
};
|
|
284
|
+
return {
|
|
285
|
+
css: declarations(sink, style, origins),
|
|
286
|
+
diagnostics: sink.diagnostics
|
|
287
|
+
};
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* Check one static attribute value against its element's spec, as serialization does. Returns
|
|
291
|
+
* the text that would be emitted, or `undefined` when the attribute is dropped or invalid.
|
|
292
|
+
*/
|
|
293
|
+
const checkAttribute = (tag, name, value, origins) => {
|
|
294
|
+
const sink = {
|
|
295
|
+
diagnostics: [],
|
|
296
|
+
positions: [],
|
|
297
|
+
written: 0,
|
|
298
|
+
relativeUrls: false,
|
|
299
|
+
instancePaths: false
|
|
300
|
+
};
|
|
301
|
+
const element = emailElement(tag);
|
|
302
|
+
const globals = EMAIL_GLOBAL_ATTRIBUTES;
|
|
303
|
+
const attributeSpec = () => {
|
|
304
|
+
if (/^(data|aria)-[a-z0-9-]+$/.test(name)) return { type: "string" };
|
|
305
|
+
if (Object.hasOwn(globals, name)) return globals[name];
|
|
306
|
+
if (element !== void 0 && Object.hasOwn(element.attributes, name)) return element.attributes[name];
|
|
307
|
+
};
|
|
308
|
+
const spec = attributeSpec();
|
|
309
|
+
if (spec === void 0) return {
|
|
310
|
+
text: void 0,
|
|
311
|
+
diagnostics: sink.diagnostics
|
|
312
|
+
};
|
|
313
|
+
return {
|
|
314
|
+
text: attributeValue(sink, tag, name, spec, value, origins),
|
|
315
|
+
diagnostics: sink.diagnostics
|
|
316
|
+
};
|
|
317
|
+
};
|
|
275
318
|
//#endregion
|
|
276
|
-
export { declarationValue, escapeAttribute, escapeText, kebab, serializeEmailHtml };
|
|
319
|
+
export { checkAttribute, declarationValue, escapeAttribute, escapeText, kebab, serializeEmailHtml, serializeStyle };
|
|
277
320
|
|
|
278
321
|
//# sourceMappingURL=html.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { g as JSX, h as Fragment, m as EmailNode, p as EmailComponent } from "../elements-
|
|
1
|
+
import { n as JsxSource } from "../source-locations-C8wCsiAy.js";
|
|
2
|
+
import { g as JSX, h as Fragment, m as EmailNode, p as EmailComponent } from "../elements-cqldpaJt.js";
|
|
3
3
|
//#region src/email/jsx-dev-runtime.d.ts
|
|
4
4
|
/** Development JSX retains compiler-provided origins directly on the semantic tree. */
|
|
5
5
|
declare const jsxDEV: (type: string | EmailComponent<Record<string, unknown>> | typeof Fragment, props: Record<string, unknown> | null, _key?: unknown, _staticChildren?: boolean, source?: JsxSource) => EmailNode;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as reportEmailDiagnostic, S as rawMarkup, _ as currentEmailOrigins, b as jsxs, f as EmailChild, g as JSX, h as Fragment, m as EmailNode, p as EmailComponent, v as drainEmailDiagnostics, x as normalizeChildren, y as jsx } from "../elements-
|
|
1
|
+
import { C as reportEmailDiagnostic, S as rawMarkup, _ as currentEmailOrigins, b as jsxs, f as EmailChild, g as JSX, h as Fragment, m as EmailNode, p as EmailComponent, v as drainEmailDiagnostics, x as normalizeChildren, y as jsx } from "../elements-cqldpaJt.js";
|
|
2
2
|
export { EmailChild, EmailComponent, EmailNode, Fragment, JSX, currentEmailOrigins, drainEmailDiagnostics, jsx, jsxs, normalizeChildren, rawMarkup, reportEmailDiagnostic };
|
package/dist/email/render.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { r as EmailDiagnostic } from "../diagnostics-
|
|
2
|
-
import { m as EmailNode } from "../elements-
|
|
3
|
-
import { n as EmittedPosition } from "../
|
|
4
|
-
import { n as SerializeEmailOptions } from "../html-
|
|
5
|
-
import {
|
|
6
|
-
import { i as Stylesheet } from "../css-
|
|
1
|
+
import { r as EmailDiagnostic } from "../diagnostics-B-Gym34R.js";
|
|
2
|
+
import { m as EmailNode } from "../elements-cqldpaJt.js";
|
|
3
|
+
import { n as EmittedPosition } from "../preview-Ekdg1dXG.js";
|
|
4
|
+
import { n as SerializeEmailOptions } from "../html-BJepOwZ4.js";
|
|
5
|
+
import { n as EmailContent } from "../template-_QE_rQND.js";
|
|
6
|
+
import { i as Stylesheet } from "../css-BVQKICKC.js";
|
|
7
7
|
//#region src/email/render.d.ts
|
|
8
8
|
/** Classic Outlook lays a document out correctly only under a transitional doctype. */
|
|
9
9
|
declare const EMAIL_DOCTYPE = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
|
|
@@ -30,21 +30,11 @@ interface RenderedEmail {
|
|
|
30
30
|
readonly diagnostics: readonly EmailDiagnostic[];
|
|
31
31
|
readonly positions: readonly EmittedPosition[];
|
|
32
32
|
}
|
|
33
|
-
/** Render one validated input through the template's only content function. Host isolation is required for untrusted source. */
|
|
34
|
-
declare const renderEmail: <Input>(template: TemplateDefinition<Input>, data: unknown, options?: SerializeEmailOptions) => RenderedEmail;
|
|
35
|
-
/**
|
|
36
|
-
* A render bound to the sheets registered so far. A compiled project's wrapper
|
|
37
|
-
* calls this once its own stylesheet imports have run, so a later project
|
|
38
|
-
* loaded into the same process cannot restyle an entry that is rendered again.
|
|
39
|
-
*/
|
|
40
|
-
declare const bindStylesheets: (stylesheet?: Stylesheet | undefined) => typeof renderEmail;
|
|
41
33
|
/**
|
|
42
34
|
* Render authored content against a stylesheet: inline what a client honors,
|
|
43
|
-
* keep the rest for `<head>`, and lower to HTML and text.
|
|
44
|
-
* validated template through it; a host that composes content without a
|
|
45
|
-
* template definition calls it directly.
|
|
35
|
+
* keep the rest for `<head>`, and lower to HTML and text.
|
|
46
36
|
*/
|
|
47
37
|
declare const renderEmailContent: (stylesheet: Stylesheet | undefined, render: () => EmailContent, options?: SerializeEmailOptions) => RenderedEmail;
|
|
48
38
|
//#endregion
|
|
49
|
-
export { EMAIL_DOCTYPE, EmailCompileOutput, RenderedEmail,
|
|
39
|
+
export { EMAIL_DOCTYPE, EmailCompileOutput, RenderedEmail, compileEmail, renderEmailContent };
|
|
50
40
|
//# sourceMappingURL=render.d.ts.map
|
package/dist/email/render.js
CHANGED
|
@@ -1,3 +1,163 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "./
|
|
3
|
-
|
|
1
|
+
import { EmailCompileError, hasBlockingDiagnostic } from "./diagnostics.js";
|
|
2
|
+
import { EmailNode, drainEmailDiagnostics } from "./jsx-runtime.js";
|
|
3
|
+
import { t as applyStylesheet } from "../cascade-t6kxlgEI.js";
|
|
4
|
+
import { serializeEmailHtml } from "./html.js";
|
|
5
|
+
import { preheaderNode } from "./components.js";
|
|
6
|
+
import { deriveEmailText } from "./text.js";
|
|
7
|
+
//#region src/email/render.ts
|
|
8
|
+
/** Classic Outlook lays a document out correctly only under a transitional doctype. */
|
|
9
|
+
const EMAIL_DOCTYPE = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
|
|
10
|
+
const settle = (diagnostics) => {
|
|
11
|
+
if (hasBlockingDiagnostic(diagnostics)) throw new EmailCompileError({ diagnostics });
|
|
12
|
+
return diagnostics;
|
|
13
|
+
};
|
|
14
|
+
/** Lower the derived tree to HTML and its plain-text alternative. */
|
|
15
|
+
const compileEmail = (node, options = {}) => {
|
|
16
|
+
const serialized = serializeEmailHtml(node, options);
|
|
17
|
+
const diagnostics = settle([...drainEmailDiagnostics(), ...serialized.diagnostics]);
|
|
18
|
+
return {
|
|
19
|
+
html: serialized.html,
|
|
20
|
+
text: deriveEmailText(node),
|
|
21
|
+
diagnostics,
|
|
22
|
+
positions: serialized.positions
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
/** Put the hidden preview block first inside `<body>`, or first overall when there is no shell. */
|
|
26
|
+
const withPreheader = (node, text) => {
|
|
27
|
+
const insert = (current) => {
|
|
28
|
+
if (current.type === "Fragment") {
|
|
29
|
+
for (const [index, child] of current.children.entries()) {
|
|
30
|
+
const replaced = insert(child);
|
|
31
|
+
if (replaced !== void 0) return EmailNode.Fragment({ children: current.children.with(index, replaced) });
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (current.type !== "Element") return void 0;
|
|
36
|
+
if (current.tag === "body") return EmailNode.Element({
|
|
37
|
+
...current,
|
|
38
|
+
children: [preheaderNode(text), ...current.children]
|
|
39
|
+
});
|
|
40
|
+
for (const [index, child] of current.children.entries()) {
|
|
41
|
+
const replaced = insert(child);
|
|
42
|
+
if (replaced !== void 0) return EmailNode.Element({
|
|
43
|
+
...current,
|
|
44
|
+
children: current.children.with(index, replaced)
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
return insert(node) ?? EmailNode.Fragment({ children: [preheaderNode(text), node] });
|
|
49
|
+
};
|
|
50
|
+
const headStyle = (css, origins) => EmailNode.Element({
|
|
51
|
+
tag: "style",
|
|
52
|
+
props: {},
|
|
53
|
+
children: [EmailNode.Text({ value: css })],
|
|
54
|
+
origins,
|
|
55
|
+
authored: false
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Put the retained rules in a `<style>` at the end of `<head>`, and project
|
|
59
|
+
* `@font-face` rules in a sibling classic Outlook cannot see. Outlook for
|
|
60
|
+
* Windows registers a face it cannot load and then renders the family in Times
|
|
61
|
+
* New Roman, ignoring the stack; hidden, the family is merely missing and the
|
|
62
|
+
* stack's fallback applies.
|
|
63
|
+
*/
|
|
64
|
+
const withHeadCss = (node, css, fontFaceCss) => {
|
|
65
|
+
const insert = (current) => {
|
|
66
|
+
if (current.type === "Fragment") {
|
|
67
|
+
for (const [index, child] of current.children.entries()) {
|
|
68
|
+
const replaced = insert(child);
|
|
69
|
+
if (replaced !== void 0) return EmailNode.Fragment({ children: current.children.with(index, replaced) });
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (current.type !== "Element") return void 0;
|
|
74
|
+
if (current.tag === "head") return EmailNode.Element({
|
|
75
|
+
...current,
|
|
76
|
+
children: [
|
|
77
|
+
...current.children,
|
|
78
|
+
...css === "" ? [] : [headStyle(css, current.origins)],
|
|
79
|
+
...fontFaceCss === "" ? [] : [
|
|
80
|
+
EmailNode.Raw({
|
|
81
|
+
html: "<!--[if !mso]><!-->",
|
|
82
|
+
text: "",
|
|
83
|
+
origins: []
|
|
84
|
+
}),
|
|
85
|
+
headStyle(fontFaceCss, current.origins),
|
|
86
|
+
EmailNode.Raw({
|
|
87
|
+
html: "<!--<![endif]-->",
|
|
88
|
+
text: "",
|
|
89
|
+
origins: []
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
]
|
|
93
|
+
});
|
|
94
|
+
for (const [index, child] of current.children.entries()) {
|
|
95
|
+
const replaced = insert(child);
|
|
96
|
+
if (replaced !== void 0) return EmailNode.Element({
|
|
97
|
+
...current,
|
|
98
|
+
children: current.children.with(index, replaced)
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return insert(node);
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Render authored content against a stylesheet: inline what a client honors,
|
|
106
|
+
* keep the rest for `<head>`, and lower to HTML and text.
|
|
107
|
+
*/
|
|
108
|
+
const renderEmailContent = (stylesheet, render, options = {}) => {
|
|
109
|
+
drainEmailDiagnostics();
|
|
110
|
+
const content = render();
|
|
111
|
+
const invalid = [];
|
|
112
|
+
const fail = (code, message) => invalid.push({
|
|
113
|
+
code,
|
|
114
|
+
severity: "error",
|
|
115
|
+
message,
|
|
116
|
+
origins: []
|
|
117
|
+
});
|
|
118
|
+
if (typeof content.subject !== "string" || /[\r\n\u0000]/.test(content.subject)) fail("invalid-subject", "Invalid email subject: it must be one line of text.");
|
|
119
|
+
if (content.preheader !== void 0 && typeof content.preheader !== "string") fail("invalid-preheader", "Invalid email preheader: it must be a string.");
|
|
120
|
+
if (content.text !== void 0 && typeof content.text !== "string") fail("invalid-text", "Invalid plain text: it must be a string.");
|
|
121
|
+
settle(invalid);
|
|
122
|
+
const base = content.preheader === void 0 ? content.body : withPreheader(content.body, content.preheader);
|
|
123
|
+
const styled = stylesheet === void 0 ? {
|
|
124
|
+
tree: base,
|
|
125
|
+
headCss: "",
|
|
126
|
+
fontFaceCss: "",
|
|
127
|
+
diagnostics: []
|
|
128
|
+
} : applyStylesheet(base, stylesheet);
|
|
129
|
+
const style = [...styled.diagnostics];
|
|
130
|
+
let tree = styled.tree;
|
|
131
|
+
if (styled.headCss !== "" || styled.fontFaceCss !== "") {
|
|
132
|
+
const placed = withHeadCss(tree, styled.headCss, styled.fontFaceCss);
|
|
133
|
+
if (placed === void 0) style.push({
|
|
134
|
+
code: "missing-head",
|
|
135
|
+
severity: "error",
|
|
136
|
+
message: "Styles that cannot be inlined — media queries, dark-scheme rules and pseudo-selectors — need a <head> to live in. Wrap the message in <Email>, or write those declarations as inline styles.",
|
|
137
|
+
origins: []
|
|
138
|
+
});
|
|
139
|
+
else tree = placed;
|
|
140
|
+
}
|
|
141
|
+
settle(style);
|
|
142
|
+
const compiled = compileEmail(tree, options);
|
|
143
|
+
const prefix = compiled.html.startsWith("<html") ? EMAIL_DOCTYPE : "";
|
|
144
|
+
const html = `${prefix}${compiled.html}`;
|
|
145
|
+
const positions = prefix === "" ? compiled.positions : compiled.positions.map((position) => ({
|
|
146
|
+
...position,
|
|
147
|
+
start: position.start + prefix.length,
|
|
148
|
+
end: position.end + prefix.length
|
|
149
|
+
}));
|
|
150
|
+
return {
|
|
151
|
+
subject: content.subject,
|
|
152
|
+
preheader: content.preheader,
|
|
153
|
+
html,
|
|
154
|
+
text: content.text ?? compiled.text,
|
|
155
|
+
tree,
|
|
156
|
+
diagnostics: [...style, ...compiled.diagnostics],
|
|
157
|
+
positions
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
//#endregion
|
|
161
|
+
export { EMAIL_DOCTYPE, compileEmail, renderEmailContent };
|
|
162
|
+
|
|
163
|
+
//# sourceMappingURL=render.js.map
|
package/dist/email/text.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as EmailNode } from "../elements-
|
|
1
|
+
import { m as EmailNode } from "../elements-cqldpaJt.js";
|
|
2
2
|
//#region src/email/text.d.ts
|
|
3
3
|
/** Derive the plain-text alternative from the semantic tree in reading order. */
|
|
4
4
|
declare const deriveEmailText: (node: EmailNode) => string;
|
package/dist/fmt.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/fmt.d.ts
|
|
2
|
+
declare const DEFAULT_LOCALE = "en-US";
|
|
3
|
+
declare const DEFAULT_TIME_ZONE = "UTC";
|
|
4
|
+
interface FormatContext {
|
|
5
|
+
readonly locale?: string | undefined;
|
|
6
|
+
readonly timeZone?: string | undefined;
|
|
7
|
+
}
|
|
8
|
+
type DateStyle = "short" | "medium" | "long" | "full";
|
|
9
|
+
interface PluralForms {
|
|
10
|
+
readonly zero?: string;
|
|
11
|
+
readonly one?: string;
|
|
12
|
+
readonly two?: string;
|
|
13
|
+
readonly few?: string;
|
|
14
|
+
readonly many?: string;
|
|
15
|
+
readonly other: string;
|
|
16
|
+
}
|
|
17
|
+
interface Fmt {
|
|
18
|
+
money(amount: number, currency: string, locale?: string): string;
|
|
19
|
+
number(value: number, options?: Intl.NumberFormatOptions, locale?: string): string;
|
|
20
|
+
date(iso: string, style?: DateStyle, locale?: string): string;
|
|
21
|
+
time(iso: string, style?: DateStyle, locale?: string): string;
|
|
22
|
+
plural(count: number, forms: PluralForms, locale?: string): string;
|
|
23
|
+
list(values: readonly string[], locale?: string): string;
|
|
24
|
+
}
|
|
25
|
+
declare const FORMATTER_NAMES: readonly ["money", "number", "date", "time", "plural", "list"];
|
|
26
|
+
declare const createFmt: (context?: FormatContext) => Fmt;
|
|
27
|
+
declare const withFormatContext: <T>(context: FormatContext, run: () => T) => T;
|
|
28
|
+
declare const fmt: Fmt;
|
|
29
|
+
declare const callFormatter: (formatter: Fmt, name: string, args: readonly unknown[]) => string;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { DEFAULT_LOCALE, DEFAULT_TIME_ZONE, DateStyle, FORMATTER_NAMES, Fmt, FormatContext, PluralForms, callFormatter, createFmt, fmt, withFormatContext };
|
|
32
|
+
//# sourceMappingURL=fmt.d.ts.map
|
package/dist/fmt.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
//#region src/fmt.ts
|
|
2
|
+
const DEFAULT_LOCALE = "en-US";
|
|
3
|
+
const DEFAULT_TIME_ZONE = "UTC";
|
|
4
|
+
const FORMATTER_NAMES = [
|
|
5
|
+
"money",
|
|
6
|
+
"number",
|
|
7
|
+
"date",
|
|
8
|
+
"time",
|
|
9
|
+
"plural",
|
|
10
|
+
"list"
|
|
11
|
+
];
|
|
12
|
+
const CACHE_LIMIT = 200;
|
|
13
|
+
const cache = /* @__PURE__ */ new Map();
|
|
14
|
+
const cached = (kind, locale, options, make) => {
|
|
15
|
+
const key = `${kind}\u0000${locale}\u0000${options === void 0 ? "" : JSON.stringify(options)}`;
|
|
16
|
+
const hit = cache.get(key);
|
|
17
|
+
if (hit !== void 0) return hit;
|
|
18
|
+
const value = make();
|
|
19
|
+
if (cache.size >= CACHE_LIMIT) cache.clear();
|
|
20
|
+
cache.set(key, value);
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
const assertFinite = (value, what) => {
|
|
24
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new TypeError(`${what} must be a finite number.`);
|
|
25
|
+
};
|
|
26
|
+
const DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
|
|
27
|
+
const parseIso = (iso) => {
|
|
28
|
+
if (typeof iso !== "string") throw new TypeError("ISO date must be a string.");
|
|
29
|
+
const date = new Date(DATE_ONLY.test(iso) ? `${iso}T00:00:00Z` : iso);
|
|
30
|
+
if (Number.isNaN(date.getTime())) throw new RangeError(`Cannot parse "${iso}" as an ISO 8601 date.`);
|
|
31
|
+
return date;
|
|
32
|
+
};
|
|
33
|
+
const createFmt = (context = {}) => {
|
|
34
|
+
const defaultLocale = context.locale ?? "en-US";
|
|
35
|
+
const timeZone = context.timeZone ?? "UTC";
|
|
36
|
+
const pick = (locale) => locale ?? defaultLocale;
|
|
37
|
+
return {
|
|
38
|
+
money: (amount, currency, locale) => {
|
|
39
|
+
assertFinite(amount, "money amount");
|
|
40
|
+
const l = pick(locale);
|
|
41
|
+
return cached("money", l, currency, () => new Intl.NumberFormat(l, {
|
|
42
|
+
style: "currency",
|
|
43
|
+
currency
|
|
44
|
+
})).format(amount);
|
|
45
|
+
},
|
|
46
|
+
number: (value, options, locale) => {
|
|
47
|
+
assertFinite(value, "number value");
|
|
48
|
+
const l = pick(locale);
|
|
49
|
+
return cached("number", l, options, () => new Intl.NumberFormat(l, options)).format(value);
|
|
50
|
+
},
|
|
51
|
+
date: (iso, style = "medium", locale) => {
|
|
52
|
+
const d = parseIso(iso);
|
|
53
|
+
const l = pick(locale);
|
|
54
|
+
return cached("date", l, {
|
|
55
|
+
style,
|
|
56
|
+
timeZone
|
|
57
|
+
}, () => new Intl.DateTimeFormat(l, {
|
|
58
|
+
dateStyle: style,
|
|
59
|
+
timeZone
|
|
60
|
+
})).format(d);
|
|
61
|
+
},
|
|
62
|
+
time: (iso, style = "short", locale) => {
|
|
63
|
+
const d = parseIso(iso);
|
|
64
|
+
const l = pick(locale);
|
|
65
|
+
return cached("time", l, {
|
|
66
|
+
style,
|
|
67
|
+
timeZone
|
|
68
|
+
}, () => new Intl.DateTimeFormat(l, {
|
|
69
|
+
timeStyle: style,
|
|
70
|
+
timeZone
|
|
71
|
+
})).format(d);
|
|
72
|
+
},
|
|
73
|
+
plural: (count, forms, locale) => {
|
|
74
|
+
assertFinite(count, "plural count");
|
|
75
|
+
const l = pick(locale);
|
|
76
|
+
return forms[cached("plural", l, void 0, () => new Intl.PluralRules(l)).select(count)] ?? forms.other;
|
|
77
|
+
},
|
|
78
|
+
list: (values, locale) => {
|
|
79
|
+
const l = pick(locale);
|
|
80
|
+
return cached("list", l, void 0, () => new Intl.ListFormat(l, {
|
|
81
|
+
type: "conjunction",
|
|
82
|
+
style: "long"
|
|
83
|
+
})).format(values);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
let ambient = {};
|
|
88
|
+
const withFormatContext = (context, run) => {
|
|
89
|
+
const previous = ambient;
|
|
90
|
+
ambient = context;
|
|
91
|
+
try {
|
|
92
|
+
return run();
|
|
93
|
+
} finally {
|
|
94
|
+
ambient = previous;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const fmt = {
|
|
98
|
+
money: (a, c, l) => createFmt(ambient).money(a, c, l),
|
|
99
|
+
number: (v, o, l) => createFmt(ambient).number(v, o, l),
|
|
100
|
+
date: (i, s, l) => createFmt(ambient).date(i, s, l),
|
|
101
|
+
time: (i, s, l) => createFmt(ambient).time(i, s, l),
|
|
102
|
+
plural: (c, f, l) => createFmt(ambient).plural(c, f, l),
|
|
103
|
+
list: (v, l) => createFmt(ambient).list(v, l)
|
|
104
|
+
};
|
|
105
|
+
const STYLES = [
|
|
106
|
+
"short",
|
|
107
|
+
"medium",
|
|
108
|
+
"long",
|
|
109
|
+
"full"
|
|
110
|
+
];
|
|
111
|
+
const PLURAL_KEYS = [
|
|
112
|
+
"zero",
|
|
113
|
+
"one",
|
|
114
|
+
"two",
|
|
115
|
+
"few",
|
|
116
|
+
"many",
|
|
117
|
+
"other"
|
|
118
|
+
];
|
|
119
|
+
const arity = (name, args, min, max) => {
|
|
120
|
+
if (args.length < min || args.length > max) {
|
|
121
|
+
const expected = min === max ? `${min}` : `${min} to ${max}`;
|
|
122
|
+
throw new TypeError(`${name} takes ${expected} arguments but received ${args.length}.`);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const str = (name, index, value, optional = false) => {
|
|
126
|
+
if (value === void 0 && optional) return void 0;
|
|
127
|
+
if (typeof value !== "string") throw new TypeError(`${name} argument ${index + 1} must be a string.`);
|
|
128
|
+
return value;
|
|
129
|
+
};
|
|
130
|
+
const num = (name, index, value) => {
|
|
131
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new TypeError(`${name} argument ${index + 1} must be a finite number.`);
|
|
132
|
+
return value;
|
|
133
|
+
};
|
|
134
|
+
const style = (name, index, value) => {
|
|
135
|
+
if (value === void 0) return void 0;
|
|
136
|
+
if (typeof value !== "string" || !STYLES.includes(value)) throw new TypeError(`${name} argument ${index + 1} must be one of ${STYLES.join(", ")}.`);
|
|
137
|
+
return value;
|
|
138
|
+
};
|
|
139
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
140
|
+
const callFormatter = (formatter, name, args) => {
|
|
141
|
+
switch (name) {
|
|
142
|
+
case "money":
|
|
143
|
+
arity(name, args, 2, 3);
|
|
144
|
+
return formatter.money(num(name, 0, args[0]), str(name, 1, args[1]), str(name, 2, args[2], true));
|
|
145
|
+
case "number": {
|
|
146
|
+
arity(name, args, 1, 3);
|
|
147
|
+
const options = args[1];
|
|
148
|
+
if (options !== void 0 && !isRecord(options)) throw new TypeError("number argument 2 must be an options object.");
|
|
149
|
+
return formatter.number(num(name, 0, args[0]), options, str(name, 2, args[2], true));
|
|
150
|
+
}
|
|
151
|
+
case "date":
|
|
152
|
+
case "time":
|
|
153
|
+
arity(name, args, 1, 3);
|
|
154
|
+
return formatter[name](str(name, 0, args[0]), style(name, 1, args[1]), str(name, 2, args[2], true));
|
|
155
|
+
case "plural": {
|
|
156
|
+
arity(name, args, 2, 3);
|
|
157
|
+
const forms = args[1];
|
|
158
|
+
if (!isRecord(forms) || typeof forms.other !== "string") throw new TypeError("plural argument 2 must be an object with a string `other` form.");
|
|
159
|
+
for (const key of PLURAL_KEYS) if (forms[key] !== void 0 && typeof forms[key] !== "string") throw new TypeError(`plural argument 2 form \`${key}\` must be a string.`);
|
|
160
|
+
return formatter.plural(num(name, 0, args[0]), forms, str(name, 2, args[2], true));
|
|
161
|
+
}
|
|
162
|
+
case "list": {
|
|
163
|
+
arity(name, args, 1, 2);
|
|
164
|
+
const values = args[0];
|
|
165
|
+
if (!Array.isArray(values) || values.some((v) => typeof v !== "string")) throw new TypeError("list argument 1 must be an array of strings.");
|
|
166
|
+
return formatter.list(values, str(name, 1, args[1], true));
|
|
167
|
+
}
|
|
168
|
+
default: throw new TypeError(`Unknown formatter "${name}".`);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
//#endregion
|
|
172
|
+
export { DEFAULT_LOCALE, DEFAULT_TIME_ZONE, FORMATTER_NAMES, callFormatter, createFmt, fmt, withFormatContext };
|
|
173
|
+
|
|
174
|
+
//# sourceMappingURL=fmt.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { r as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { r as JsxSourceLocation } from "./source-locations-C8wCsiAy.js";
|
|
2
|
+
import { r as EmailDiagnostic } from "./diagnostics-B-Gym34R.js";
|
|
3
|
+
import { m as EmailNode } from "./elements-cqldpaJt.js";
|
|
4
|
+
import { n as EmittedPosition } from "./preview-Ekdg1dXG.js";
|
|
4
5
|
//#region src/email/html.d.ts
|
|
5
6
|
/** Escape a value for element content. */
|
|
6
7
|
declare const escapeText: (value: string) => string;
|
|
@@ -37,6 +38,19 @@ interface SerializeEmailOptions {
|
|
|
37
38
|
}
|
|
38
39
|
/** Lower the derived tree to email HTML, reporting every unsupported construct with its origin. */
|
|
39
40
|
declare const serializeEmailHtml: (node: EmailNode, options?: SerializeEmailOptions) => EmailHtmlOutput;
|
|
41
|
+
/** An authored style object as a declaration list, checked by the same rules as a serialized tree. */
|
|
42
|
+
declare const serializeStyle: (style: Readonly<Record<string, unknown>>, origins: readonly JsxSourceLocation[]) => {
|
|
43
|
+
readonly css: string;
|
|
44
|
+
readonly diagnostics: readonly EmailDiagnostic[];
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Check one static attribute value against its element's spec, as serialization does. Returns
|
|
48
|
+
* the text that would be emitted, or `undefined` when the attribute is dropped or invalid.
|
|
49
|
+
*/
|
|
50
|
+
declare const checkAttribute: (tag: string, name: string, value: unknown, origins: readonly JsxSourceLocation[]) => {
|
|
51
|
+
readonly text: string | undefined;
|
|
52
|
+
readonly diagnostics: readonly EmailDiagnostic[];
|
|
53
|
+
};
|
|
40
54
|
//#endregion
|
|
41
|
-
export {
|
|
42
|
-
//# sourceMappingURL=html-
|
|
55
|
+
export { escapeAttribute as a, serializeEmailHtml as c, declarationValue as i, serializeStyle as l, SerializeEmailOptions as n, escapeText as o, checkAttribute as r, kebab as s, EmailHtmlOutput as t };
|
|
56
|
+
//# sourceMappingURL=html-BJepOwZ4.d.ts.map
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED