@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
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { m as EmailNode } from "./elements-cqldpaJt.js";
|
|
2
|
+
import { r as InputSchema } from "./input-schema-7dPFVvNE.js";
|
|
3
|
+
import { StandardJSONSchemaV1 } from "@standard-schema/spec";
|
|
4
|
+
//#region src/template.d.ts
|
|
5
|
+
/** One actual-input render owns all of a message's authored content. */
|
|
6
|
+
interface EmailContent {
|
|
7
|
+
readonly subject: string;
|
|
8
|
+
readonly preheader?: string;
|
|
9
|
+
readonly body: EmailNode;
|
|
10
|
+
readonly text?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The one naming contract for a template id and a fixture key: a letter, a digit or `_` first,
|
|
14
|
+
* then those plus `.`, `_` and `-`.
|
|
15
|
+
*
|
|
16
|
+
* Both names are written into file paths — a local export writes one page at
|
|
17
|
+
* `templates/<id>/<fixture>.html` — so each has to be a single plain path segment. The rule lives
|
|
18
|
+
* at the declaration, so a project that could not be exported is refused where the name is
|
|
19
|
+
* written rather than at the end of a build. Consumers that resolve a path from these names
|
|
20
|
+
* import this pattern; they do not restate it.
|
|
21
|
+
*/
|
|
22
|
+
declare const TEMPLATE_NAME_PATTERN: RegExp;
|
|
23
|
+
/** Caller input for generated references and separate authoring consumers. */
|
|
24
|
+
type TemplateInput<T extends {
|
|
25
|
+
readonly schema: unknown;
|
|
26
|
+
}> = T["schema"] extends InputSchema<infer Input> ? Input : never;
|
|
27
|
+
/**
|
|
28
|
+
* The one naming contract for a template `id`: lowercase kebab-case, the same rule as the CLI and
|
|
29
|
+
* API slug, so the id a definition declares is the handle a caller sends by.
|
|
30
|
+
*/
|
|
31
|
+
declare const TEMPLATE_ID_PATTERN: RegExp;
|
|
32
|
+
/** The email channel of a template: an envelope and a body, each a function of the input. */
|
|
33
|
+
interface EmailChannel<Input> {
|
|
34
|
+
readonly subject: (input: Input) => string;
|
|
35
|
+
readonly preheader?: ((input: Input) => string | undefined) | undefined;
|
|
36
|
+
readonly body: (input: Input) => EmailNode;
|
|
37
|
+
}
|
|
38
|
+
/** A template as `defineTemplate` returns it: its identity, input contract and each channel it declares. */
|
|
39
|
+
interface SmlTemplate<Input> {
|
|
40
|
+
readonly id: string;
|
|
41
|
+
readonly schema: InputSchema<Input>;
|
|
42
|
+
readonly fixtures: Readonly<Record<string, Input>>;
|
|
43
|
+
readonly locale?: string | undefined;
|
|
44
|
+
readonly email?: EmailChannel<Input> | undefined;
|
|
45
|
+
readonly sms?: ((input: Input) => EmailNode) | undefined;
|
|
46
|
+
readonly whatsapp?: ((input: Input) => EmailNode) | undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Define a template: one id, one input schema, named fixtures and one body per channel. Every
|
|
50
|
+
* function in it receives the validated input and returns JSX or a string; a compiler reads them
|
|
51
|
+
* without running them, so nothing here executes at send time. Types are inferred from the
|
|
52
|
+
* Standard JSON Schema input.
|
|
53
|
+
*/
|
|
54
|
+
declare const defineTemplate: <S extends StandardJSONSchemaV1>(definition: {
|
|
55
|
+
readonly id: string;
|
|
56
|
+
readonly schema: S;
|
|
57
|
+
readonly fixtures: Readonly<Record<string, NoInfer<StandardJSONSchemaV1.InferInput<S>>>>;
|
|
58
|
+
readonly locale?: string | undefined;
|
|
59
|
+
readonly email?: EmailChannel<NoInfer<StandardJSONSchemaV1.InferInput<S>>> | undefined;
|
|
60
|
+
readonly sms?: ((input: NoInfer<StandardJSONSchemaV1.InferInput<S>>) => EmailNode) | undefined;
|
|
61
|
+
readonly whatsapp?: ((input: NoInfer<StandardJSONSchemaV1.InferInput<S>>) => EmailNode) | undefined;
|
|
62
|
+
}) => SmlTemplate<StandardJSONSchemaV1.InferInput<S>>;
|
|
63
|
+
//#endregion
|
|
64
|
+
export { TEMPLATE_NAME_PATTERN as a, TEMPLATE_ID_PATTERN as i, EmailContent as n, TemplateInput as o, SmlTemplate as r, defineTemplate as s, EmailChannel as t };
|
|
65
|
+
//# sourceMappingURL=template-_QE_rQND.d.ts.map
|
package/dist/template.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export {
|
|
1
|
+
import { a as TEMPLATE_NAME_PATTERN, i as TEMPLATE_ID_PATTERN, n as EmailContent, o as TemplateInput, r as SmlTemplate, s as defineTemplate, t as EmailChannel } from "./template-_QE_rQND.js";
|
|
2
|
+
export { EmailChannel, EmailContent, SmlTemplate, TEMPLATE_ID_PATTERN, TEMPLATE_NAME_PATTERN, TemplateInput, defineTemplate };
|
package/dist/template.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { n as isObject } from "./guards-eV1qLbf2.js";
|
|
2
1
|
import { n as inputSchema } from "./input-schema-zjkgrXn2.js";
|
|
3
2
|
//#region src/template.ts
|
|
4
|
-
/** Classify an evaluated module export without executing helpers as templates. */
|
|
5
|
-
const isTemplateDefinition = (value) => isObject(value) && typeof value.id === "string" && typeof value.render === "function" && isObject(value.schema);
|
|
6
3
|
/**
|
|
7
4
|
* The one naming contract for a template id and a fixture key: a letter, a digit or `_` first,
|
|
8
5
|
* then those plus `.`, `_` and `-`.
|
|
@@ -19,19 +16,27 @@ const checkTemplateName = (kind, value) => {
|
|
|
19
16
|
throw new TypeError(`${kind} ${JSON.stringify(value)} is not one path segment. A template id and a fixture key are written into file paths, so each must start with a letter, a digit or "_" and continue with letters, digits, ".", "_" or "-".`);
|
|
20
17
|
};
|
|
21
18
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* and `TemplateInput` stay channel-neutral.
|
|
19
|
+
* The one naming contract for a template `id`: lowercase kebab-case, the same rule as the CLI and
|
|
20
|
+
* API slug, so the id a definition declares is the handle a caller sends by.
|
|
25
21
|
*/
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
const TEMPLATE_ID_PATTERN = /^(?=.{1,100}$)[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
23
|
+
/**
|
|
24
|
+
* Define a template: one id, one input schema, named fixtures and one body per channel. Every
|
|
25
|
+
* function in it receives the validated input and returns JSX or a string; a compiler reads them
|
|
26
|
+
* without running them, so nothing here executes at send time. Types are inferred from the
|
|
27
|
+
* Standard JSON Schema input.
|
|
28
|
+
*/
|
|
29
|
+
const defineTemplate = (definition) => {
|
|
30
|
+
if (!TEMPLATE_ID_PATTERN.test(definition.id)) throw new TypeError(`Template id ${JSON.stringify(definition.id)} is not lowercase kebab-case. The id is the handle a send names, so write lowercase letters and digits joined by single hyphens, for example "order-shipped".`);
|
|
31
|
+
const fixtureNames = Object.keys(definition.fixtures);
|
|
32
|
+
if (fixtureNames.length === 0) throw new TypeError(`Template ${definition.id} declares no fixtures. Fixtures are the preview, the agent's render targets and the publish check; declare at least one.`);
|
|
33
|
+
for (const fixture of fixtureNames) checkTemplateName("Fixture key", fixture);
|
|
29
34
|
return {
|
|
30
35
|
...definition,
|
|
31
36
|
schema: inputSchema(definition.schema)
|
|
32
37
|
};
|
|
33
38
|
};
|
|
34
39
|
//#endregion
|
|
35
|
-
export {
|
|
40
|
+
export { TEMPLATE_ID_PATTERN, TEMPLATE_NAME_PATTERN, defineTemplate };
|
|
36
41
|
|
|
37
42
|
//# sourceMappingURL=template.js.map
|
package/dist/theme-css.d.ts
CHANGED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { buildLineMap, lineColumn } from "./diagnostics.js";
|
|
2
|
+
import { parse } from "css-tree";
|
|
3
|
+
//#region src/email/theme-imports.ts
|
|
4
|
+
/** The CSS and TSX specifier a template uses to reach its organization's brand. */
|
|
5
|
+
const BRAND_SPECIFIER = "samva:brand";
|
|
6
|
+
const BRAND_IMPORT = /^samva:brand(?:\/([a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?))?$/;
|
|
7
|
+
/** The brand a `samva:brand` specifier names: `undefined` slug means the default brand. */
|
|
8
|
+
const parseBrandSpecifier = (specifier) => {
|
|
9
|
+
const match = BRAND_IMPORT.exec(specifier);
|
|
10
|
+
return match === null ? void 0 : { slug: match[1] };
|
|
11
|
+
};
|
|
12
|
+
/** The directory part of a project path, with no trailing slash (`""` at the root). */
|
|
13
|
+
const projectDirectory = (path) => path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : "";
|
|
14
|
+
/** A relative or root-absolute stylesheet reference, resolved from a project directory. */
|
|
15
|
+
const resolveFromDirectory = (directory, reference) => {
|
|
16
|
+
const segments = reference.startsWith("/") || directory === "" ? [] : directory.split("/");
|
|
17
|
+
for (const segment of reference.split("/")) {
|
|
18
|
+
if (segment === "" || segment === ".") continue;
|
|
19
|
+
if (segment === "..") {
|
|
20
|
+
if (segments.length === 0) return void 0;
|
|
21
|
+
segments.pop();
|
|
22
|
+
} else segments.push(segment);
|
|
23
|
+
}
|
|
24
|
+
return segments.length === 0 ? void 0 : segments.join("/");
|
|
25
|
+
};
|
|
26
|
+
const importTarget = (node) => {
|
|
27
|
+
if (node.type !== "Atrule" || node.prelude === null || node.prelude.type !== "AtrulePrelude") return { extra: true };
|
|
28
|
+
const parts = [...node.prelude.children].filter((part) => part.type !== "WhiteSpace");
|
|
29
|
+
const first = parts[0];
|
|
30
|
+
const target = first?.type === "String" ? first.value : first?.type === "Url" ? first.value : void 0;
|
|
31
|
+
return target === void 0 ? { extra: true } : {
|
|
32
|
+
target,
|
|
33
|
+
extra: parts.length > 1
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Walk the theme's `@import` graph. Project `.css` files resolve from the
|
|
38
|
+
* importing file's directory; `samva:brand` and `samva:brand/<slug>` are
|
|
39
|
+
* recorded for the brand the build supplies. Anything else is an error.
|
|
40
|
+
*/
|
|
41
|
+
const resolveThemeImports = (themePath, themeCss, files) => {
|
|
42
|
+
const stylesheets = /* @__PURE__ */ new Map([[themePath, themeCss]]);
|
|
43
|
+
const brandSpecifiers = /* @__PURE__ */ new Set();
|
|
44
|
+
const diagnostics = [];
|
|
45
|
+
const visit = (path, source, chain) => {
|
|
46
|
+
const lineMap = buildLineMap(source);
|
|
47
|
+
const ast = parse(source, {
|
|
48
|
+
positions: true,
|
|
49
|
+
parseValue: false,
|
|
50
|
+
parseRulePrelude: false
|
|
51
|
+
});
|
|
52
|
+
if (ast.type !== "StyleSheet") return;
|
|
53
|
+
for (const node of ast.children) {
|
|
54
|
+
if (node.type !== "Atrule" || node.name.toLowerCase() !== "import") continue;
|
|
55
|
+
const position = lineColumn(lineMap, node.loc?.start.offset ?? 0);
|
|
56
|
+
const origins = [{
|
|
57
|
+
fileName: path,
|
|
58
|
+
lineNumber: position.line,
|
|
59
|
+
columnNumber: position.column
|
|
60
|
+
}];
|
|
61
|
+
const refuse = (message) => diagnostics.push({
|
|
62
|
+
code: "css-import-unresolved",
|
|
63
|
+
severity: "error",
|
|
64
|
+
message,
|
|
65
|
+
origins
|
|
66
|
+
});
|
|
67
|
+
const { target, extra } = importTarget(node);
|
|
68
|
+
if (target === void 0) {
|
|
69
|
+
refuse(`${path}: @import needs a quoted stylesheet path or "samva:brand".`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (extra) {
|
|
73
|
+
refuse(`${path}: @import ${JSON.stringify(target)} takes no layer, supports or media conditions; the import order is the layering.`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (parseBrandSpecifier(target) !== void 0) {
|
|
77
|
+
brandSpecifiers.add(target);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (!/^\.{0,2}\//.test(target) || !/\.css$/i.test(target.replace(/[?#].*$/, ""))) {
|
|
81
|
+
refuse(`${path}: @import ${JSON.stringify(target)} is not a project stylesheet or "samva:brand". The compiler supplies Tailwind itself; import project .css files by relative path.`);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const resolved = resolveFromDirectory(projectDirectory(path), target.replace(/[?#].*$/, ""));
|
|
85
|
+
const content = resolved === void 0 ? void 0 : files[resolved];
|
|
86
|
+
if (resolved === void 0 || typeof content !== "string") {
|
|
87
|
+
refuse(`${path}: @import ${JSON.stringify(target)} names no stylesheet in the project.`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (chain.includes(resolved)) {
|
|
91
|
+
refuse(`${path}: @import ${JSON.stringify(target)} imports itself through ${chain.join(" → ")}.`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (stylesheets.has(resolved)) continue;
|
|
95
|
+
stylesheets.set(resolved, content);
|
|
96
|
+
visit(resolved, content, [...chain, resolved]);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
visit(themePath, themeCss, [themePath]);
|
|
100
|
+
return {
|
|
101
|
+
stylesheets,
|
|
102
|
+
brandSpecifiers: [...brandSpecifiers].sort(),
|
|
103
|
+
diagnostics
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
//#endregion
|
|
107
|
+
export { resolveThemeImports as a, resolveFromDirectory as i, parseBrandSpecifier as n, projectDirectory as r, BRAND_SPECIFIER as t };
|
|
108
|
+
|
|
109
|
+
//# sourceMappingURL=theme-imports-lvBw3AD1.js.map
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { r as EmailDiagnostic } from "./diagnostics-B-Gym34R.js";
|
|
2
|
+
import { n as EmittedPosition } from "./preview-Ekdg1dXG.js";
|
|
3
|
+
import { i as Stylesheet } from "./css-BVQKICKC.js";
|
|
4
|
+
import { n as AssetEntry } from "./assets-C5duwTya.js";
|
|
5
|
+
import { a as EmailBrand } from "./brand-B-0bN_Ir.js";
|
|
6
|
+
import { caniemail } from "caniemail";
|
|
7
|
+
//#region src/email/compatibility.d.ts
|
|
8
|
+
type CaniemailClient = Parameters<typeof caniemail>[0]["clients"][number];
|
|
9
|
+
/** One client this compiler makes claims about. */
|
|
10
|
+
interface EmailClientTarget {
|
|
11
|
+
readonly id: CaniemailClient;
|
|
12
|
+
readonly label: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The pinned matrix. Every finding is reported per client, and a client absent
|
|
16
|
+
* from this list is a client Samva makes no claim about.
|
|
17
|
+
*/
|
|
18
|
+
declare const EMAIL_CLIENT_MATRIX: readonly EmailClientTarget[];
|
|
19
|
+
interface CompatibilityProvenance {
|
|
20
|
+
/** The exact rules package a finding came from. */
|
|
21
|
+
readonly rules: string;
|
|
22
|
+
readonly apiVersion: string;
|
|
23
|
+
/** The day caniemail last changed the data this build was checked against. */
|
|
24
|
+
readonly lastUpdate: string;
|
|
25
|
+
}
|
|
26
|
+
declare const COMPATIBILITY_PROVENANCE: CompatibilityProvenance;
|
|
27
|
+
/**
|
|
28
|
+
* The constructs whose loss actually breaks a message: the recipient reads
|
|
29
|
+
* something different, in a different order, follows a link that does not work,
|
|
30
|
+
* or sees a layout that has collapsed. A target client dropping one of these
|
|
31
|
+
* blocks publication.
|
|
32
|
+
*
|
|
33
|
+
* The list is deliberately short and enumerated, because the contract is to
|
|
34
|
+
* block *known* failures. Nonessential differences require an assessment of
|
|
35
|
+
* emitted values: a concrete risk warns, expected differences and unverified
|
|
36
|
+
* behavior remain compatibility observations.
|
|
37
|
+
*/
|
|
38
|
+
declare const ESSENTIAL_CONSTRUCTS: ReadonlySet<string>;
|
|
39
|
+
interface CompatibilityInput {
|
|
40
|
+
/** The document the recipient receives. */
|
|
41
|
+
readonly html: string;
|
|
42
|
+
/** The declared fixture checked by this invocation. */
|
|
43
|
+
readonly fixture?: string | undefined;
|
|
44
|
+
/** Retained head rules, when they are not already inside the HTML. */
|
|
45
|
+
readonly css?: string | undefined;
|
|
46
|
+
/** Emitted-offset ranges with the origins of the node that produced them. */
|
|
47
|
+
readonly positions?: readonly EmittedPosition[] | undefined;
|
|
48
|
+
readonly clients?: readonly EmailClientTarget[] | undefined;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check the emitted document against the pinned matrix.
|
|
52
|
+
*
|
|
53
|
+
* Findings are grouped by construct rather than repeated per client, so one
|
|
54
|
+
* unsupported property is one diagnostic naming every client that drops it.
|
|
55
|
+
*/
|
|
56
|
+
declare const checkEmailCompatibility: (input: CompatibilityInput) => readonly EmailDiagnostic[];
|
|
57
|
+
/**
|
|
58
|
+
* Constructs the pinned data says nothing about for a target client. These are
|
|
59
|
+
* reported so "we did not check that" is never mistaken for "that works".
|
|
60
|
+
*/
|
|
61
|
+
declare const unknownCoverage: (titles: Iterable<string>) => readonly EmailDiagnostic[];
|
|
62
|
+
/** A publication carrying one of these is refused; the message would arrive broken. */
|
|
63
|
+
declare const hasBlockingCompatibility: (findings: readonly EmailDiagnostic[]) => boolean;
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/email/tailwind.d.ts
|
|
66
|
+
interface TailwindOptions {
|
|
67
|
+
/**
|
|
68
|
+
* Project CSS appended to the compiled entry: `@theme` overrides, `@utility`
|
|
69
|
+
* definitions and ordinary rules. This is the project's pinned configuration.
|
|
70
|
+
*/
|
|
71
|
+
readonly css?: string | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* The project path `css` was read from (`theme.css` by default). Its
|
|
74
|
+
* relative `@import`s resolve from this file's directory.
|
|
75
|
+
*/
|
|
76
|
+
readonly cssPath?: string | undefined;
|
|
77
|
+
/** Classes the compiler cannot discover, declared by the project on purpose. */
|
|
78
|
+
readonly safelist?: readonly string[] | undefined;
|
|
79
|
+
/** Tailwind's browser reset is off by default; email clients do not want it. */
|
|
80
|
+
readonly preflight?: boolean | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Bounds on what the compiler may generate. Class discovery reads authored
|
|
83
|
+
* source, so a project can hand it an unbounded candidate set and get an
|
|
84
|
+
* unbounded stylesheet back — inside a build that has a wall clock and a
|
|
85
|
+
* bundle a Worker then has to load. A host that publishes supplies these.
|
|
86
|
+
*/
|
|
87
|
+
readonly limits?: TailwindLimits | undefined;
|
|
88
|
+
}
|
|
89
|
+
interface TailwindLimits {
|
|
90
|
+
/** Distinct classes handed to the compiler. */
|
|
91
|
+
readonly candidates: number;
|
|
92
|
+
/** Bytes of generated CSS. */
|
|
93
|
+
readonly cssBytes: number;
|
|
94
|
+
}
|
|
95
|
+
interface TailwindOutput {
|
|
96
|
+
readonly css: string;
|
|
97
|
+
readonly version: string;
|
|
98
|
+
/** Every candidate handed to the compiler, sorted, for the build manifest. */
|
|
99
|
+
readonly candidates: readonly string[];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* What the project theme's `@import`s resolve to, already checked by
|
|
103
|
+
* `resolveThemeImports`: project stylesheets by path, and the brand theme
|
|
104
|
+
* `samva:brand` stands for.
|
|
105
|
+
*/
|
|
106
|
+
interface TailwindImports {
|
|
107
|
+
readonly stylesheets: ReadonlyMap<string, string>;
|
|
108
|
+
readonly brandCss?: string | undefined;
|
|
109
|
+
}
|
|
110
|
+
/** Compile the discovered class set into CSS with the pinned Tailwind release. */
|
|
111
|
+
declare const compileTailwind: (candidates: Iterable<string>, options?: TailwindOptions, imports?: TailwindImports) => Promise<TailwindOutput>;
|
|
112
|
+
interface ClassDiscovery {
|
|
113
|
+
readonly candidates: readonly string[];
|
|
114
|
+
readonly diagnostics: readonly EmailDiagnostic[];
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Collect the class names one module states literally, and report the positions
|
|
118
|
+
* where a class is assembled from values the compiler cannot see.
|
|
119
|
+
*/
|
|
120
|
+
declare const discoverClassCandidates: (source: string, fileName: string) => ClassDiscovery;
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/email/transform.d.ts
|
|
123
|
+
/** Where this build serves assets from, and how Tailwind is configured. */
|
|
124
|
+
interface TransformOptions {
|
|
125
|
+
readonly assetBase: string;
|
|
126
|
+
/** `false` compiles no Tailwind at all. */
|
|
127
|
+
readonly tailwind?: TailwindOptions | false | undefined;
|
|
128
|
+
/**
|
|
129
|
+
* The brand `samva:brand` resolves to, supplied by the host. A project that
|
|
130
|
+
* imports `samva:brand` with no brand here fails to compile.
|
|
131
|
+
*/
|
|
132
|
+
readonly brand?: EmailBrand | undefined;
|
|
133
|
+
}
|
|
134
|
+
interface ProjectTransform {
|
|
135
|
+
readonly assets: readonly AssetEntry[];
|
|
136
|
+
/** The compiled Tailwind sheet, when the project used any utility class. */
|
|
137
|
+
readonly tailwindSheet: Stylesheet | undefined;
|
|
138
|
+
/** Every project stylesheet, parsed, by path. */
|
|
139
|
+
readonly stylesheets: ReadonlyMap<string, Stylesheet>;
|
|
140
|
+
readonly diagnostics: readonly EmailDiagnostic[];
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The `samva:brand` specifier a project imports — from its theme's `@import`s
|
|
144
|
+
* or its TSX — so a host can fetch that brand before it compiles. `undefined`
|
|
145
|
+
* when the project imports no brand. A project that names two brands gets the
|
|
146
|
+
* first here and a refusal from the compile.
|
|
147
|
+
*/
|
|
148
|
+
declare const projectBrandSpecifier: (files: Readonly<Record<string, string | Uint8Array>>, themePath?: string) => string | undefined;
|
|
149
|
+
/** Read a whole project, then compile the classes its scripts used. */
|
|
150
|
+
declare const transformProject: (files: Readonly<Record<string, string | Uint8Array>>, options: TransformOptions) => Promise<ProjectTransform>;
|
|
151
|
+
//#endregion
|
|
152
|
+
export { checkEmailCompatibility as _, ClassDiscovery as a, TailwindOutput as c, COMPATIBILITY_PROVENANCE as d, CompatibilityInput as f, EmailClientTarget as g, ESSENTIAL_CONSTRUCTS as h, transformProject as i, compileTailwind as l, EMAIL_CLIENT_MATRIX as m, TransformOptions as n, TailwindLimits as o, CompatibilityProvenance as p, projectBrandSpecifier as r, TailwindOptions as s, ProjectTransform as t, discoverClassCandidates as u, hasBlockingCompatibility as v, unknownCoverage as y };
|
|
153
|
+
//# sourceMappingURL=transform-Ct2OMkFN.d.ts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { n as WhatsAppCategory, r as WhatsAppHeaderType } from "./channel-specs-C2feJwuP.js";
|
|
2
|
+
import { f as EmailChild, m as EmailNode } from "./elements-cqldpaJt.js";
|
|
3
|
+
//#region src/whatsapp.d.ts
|
|
4
|
+
interface WhatsAppProps {
|
|
5
|
+
readonly name?: string | undefined;
|
|
6
|
+
/** The Meta language code, for example `en_US`. */
|
|
7
|
+
readonly language: string;
|
|
8
|
+
readonly category: WhatsAppCategory;
|
|
9
|
+
readonly children?: EmailChild;
|
|
10
|
+
}
|
|
11
|
+
interface WhatsAppHeaderProps {
|
|
12
|
+
/** `text` by default; for `image`, `video` and `document` the child is the media URL. */
|
|
13
|
+
readonly type?: WhatsAppHeaderType | undefined;
|
|
14
|
+
readonly children?: EmailChild;
|
|
15
|
+
}
|
|
16
|
+
interface WhatsAppTextProps {
|
|
17
|
+
readonly children?: EmailChild;
|
|
18
|
+
}
|
|
19
|
+
interface WhatsAppButtonsProps {
|
|
20
|
+
readonly children?: EmailChild;
|
|
21
|
+
}
|
|
22
|
+
interface WhatsAppUrlButtonProps {
|
|
23
|
+
readonly url: string;
|
|
24
|
+
/** The button label. */
|
|
25
|
+
readonly children?: EmailChild;
|
|
26
|
+
}
|
|
27
|
+
interface WhatsAppPhoneButtonProps {
|
|
28
|
+
readonly phone: string;
|
|
29
|
+
/** The button label. */
|
|
30
|
+
readonly children?: EmailChild;
|
|
31
|
+
}
|
|
32
|
+
interface WhatsAppQuickReplyButtonProps {
|
|
33
|
+
/** The button label. */
|
|
34
|
+
readonly children?: EmailChild;
|
|
35
|
+
}
|
|
36
|
+
interface WhatsAppCopyCodeButtonProps {
|
|
37
|
+
/** The code the button copies. */
|
|
38
|
+
readonly children?: EmailChild;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The root of a WhatsApp body. Meta's template anatomy is the vocabulary: `WhatsApp.Header`,
|
|
42
|
+
* `WhatsApp.Body`, `WhatsApp.Footer` and `WhatsApp.Buttons`, whose children are the four button
|
|
43
|
+
* kinds.
|
|
44
|
+
*/
|
|
45
|
+
declare const WhatsApp: ((props: WhatsAppProps) => EmailNode) & {
|
|
46
|
+
Header: (props: WhatsAppHeaderProps) => EmailNode;
|
|
47
|
+
Body: (props: WhatsAppTextProps) => EmailNode;
|
|
48
|
+
Footer: (props: WhatsAppTextProps) => EmailNode;
|
|
49
|
+
Buttons: (props: WhatsAppButtonsProps) => EmailNode;
|
|
50
|
+
UrlButton: (props: WhatsAppUrlButtonProps) => EmailNode;
|
|
51
|
+
QuickReplyButton: (props: WhatsAppQuickReplyButtonProps) => EmailNode;
|
|
52
|
+
PhoneButton: (props: WhatsAppPhoneButtonProps) => EmailNode;
|
|
53
|
+
CopyCodeButton: (props: WhatsAppCopyCodeButtonProps) => EmailNode;
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
export { WhatsApp, WhatsAppButtonsProps, type WhatsAppCategory, WhatsAppCopyCodeButtonProps, WhatsAppHeaderProps, type WhatsAppHeaderType, WhatsAppPhoneButtonProps, WhatsAppProps, WhatsAppQuickReplyButtonProps, WhatsAppTextProps, WhatsAppUrlButtonProps };
|
|
57
|
+
//# sourceMappingURL=whatsapp.d.ts.map
|
package/dist/whatsapp.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Fragment, jsx } from "./email/jsx-runtime.js";
|
|
2
|
+
//#region src/whatsapp.ts
|
|
3
|
+
const fragment = (children) => jsx(Fragment, { children });
|
|
4
|
+
/**
|
|
5
|
+
* The root of a WhatsApp body. Meta's template anatomy is the vocabulary: `WhatsApp.Header`,
|
|
6
|
+
* `WhatsApp.Body`, `WhatsApp.Footer` and `WhatsApp.Buttons`, whose children are the four button
|
|
7
|
+
* kinds.
|
|
8
|
+
*/
|
|
9
|
+
const WhatsApp = Object.assign((props) => fragment(props.children), {
|
|
10
|
+
Header: (props) => fragment(props.children),
|
|
11
|
+
Body: (props) => fragment(props.children),
|
|
12
|
+
Footer: (props) => fragment(props.children),
|
|
13
|
+
Buttons: (props) => fragment(props.children),
|
|
14
|
+
UrlButton: (props) => fragment(props.children),
|
|
15
|
+
QuickReplyButton: (props) => fragment(props.children),
|
|
16
|
+
PhoneButton: (props) => fragment(props.children),
|
|
17
|
+
CopyCodeButton: (props) => fragment(props.children)
|
|
18
|
+
});
|
|
19
|
+
//#endregion
|
|
20
|
+
export { WhatsApp };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=whatsapp.js.map
|