@samva/markup 0.9.0 → 0.10.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.
Files changed (88) hide show
  1. package/AGENTS.md +48 -40
  2. package/CHANGELOG.md +345 -0
  3. package/README.md +6 -6
  4. package/dist/{brand-B-0bN_Ir.d.ts → assets-BIsyMQ92.d.ts} +41 -11
  5. package/dist/{email/brand.js → brand-C0MKTwmX.js} +64 -4
  6. package/dist/{theme-css.d.ts → brand.d.ts} +12 -3
  7. package/dist/brand.js +4 -0
  8. package/dist/compiler.d.ts +231 -11
  9. package/dist/compiler.js +1312 -13
  10. package/dist/components-BZCqegS8.js +1864 -0
  11. package/dist/diagnostic-model-DJtqbETd.js +38 -0
  12. package/dist/diagnostic-model-DxthUZBT.d.ts +31 -0
  13. package/dist/{email/diagnostics.js → diagnostics-CnKFefKz.js} +2 -2
  14. package/dist/diagnostics.d.ts +406 -27
  15. package/dist/diagnostics.js +402 -34
  16. package/dist/edit.d.ts +234 -0
  17. package/dist/{channel-edit.js → edit.js} +341 -3
  18. package/dist/email/jsx-dev-runtime.d.ts +1 -1
  19. package/dist/email/jsx-dev-runtime.js +1 -2
  20. package/dist/email/jsx-runtime.d.ts +1 -1
  21. package/dist/email/jsx-runtime.js +1 -85
  22. package/dist/{email/components.d.ts → email.d.ts} +2 -2
  23. package/dist/email.js +2 -0
  24. package/dist/index.d.ts +1 -1
  25. package/dist/index.js +1 -1
  26. package/dist/{cascade-t6kxlgEI.js → ir-CLhlklKV.js} +8 -4
  27. package/dist/jsx-runtime-CBlexoeR.js +98 -0
  28. package/dist/{elements-cqldpaJt.d.ts → jsx-runtime-ylIOnaSf.d.ts} +74 -74
  29. package/dist/{profile-BH-OtdDA.js → profile-pWGtWZXF.js} +153 -20
  30. package/dist/render-BPonDpCl.d.ts +539 -0
  31. package/dist/{email/render.js → render-BQmfh94k.js} +102 -8
  32. package/dist/render.d.ts +35 -0
  33. package/dist/render.js +49 -0
  34. package/dist/sms.d.ts +1 -1
  35. package/dist/sms.js +1 -1
  36. package/dist/{template-_QE_rQND.d.ts → template-DMPwxMSq.d.ts} +2 -2
  37. package/dist/{template.js → template-zLUjcwfF.js} +2 -2
  38. package/dist/{theme-css-hFqcPSar.js → theme-css-JtRCm1fb.js} +2 -2
  39. package/dist/whatsapp.d.ts +1 -1
  40. package/dist/whatsapp.js +1 -1
  41. package/generated/contract.json +16 -10
  42. package/generated/reference.md +17 -10
  43. package/package.json +36 -119
  44. package/samva-brand.d.ts +4 -4
  45. package/skills/sml/SKILL.md +2 -2
  46. package/dist/assets-C5duwTya.d.ts +0 -40
  47. package/dist/channel-edit.d.ts +0 -121
  48. package/dist/channel-specs-B6M_HlaV.js +0 -29
  49. package/dist/compatibility-DbISoFIq.js +0 -589
  50. package/dist/css-BVQKICKC.d.ts +0 -109
  51. package/dist/diagnostic-codes.d.ts +0 -403
  52. package/dist/diagnostic-codes.js +0 -399
  53. package/dist/email/assets.d.ts +0 -2
  54. package/dist/email/assets.js +0 -63
  55. package/dist/email/brand-footer.d.ts +0 -34
  56. package/dist/email/brand-footer.js +0 -63
  57. package/dist/email/brand.d.ts +0 -2
  58. package/dist/email/components.js +0 -275
  59. package/dist/email/diagnostics.d.ts +0 -2
  60. package/dist/email/elements.d.ts +0 -2
  61. package/dist/email/elements.js +0 -299
  62. package/dist/email/html.d.ts +0 -2
  63. package/dist/email/html.js +0 -321
  64. package/dist/email/render.d.ts +0 -40
  65. package/dist/email/text.d.ts +0 -7
  66. package/dist/email/text.js +0 -100
  67. package/dist/html-BJepOwZ4.d.ts +0 -56
  68. package/dist/ir-aaqNE987.d.ts +0 -252
  69. package/dist/ir.d.ts +0 -2
  70. package/dist/ir.js +0 -7
  71. package/dist/preview-Ekdg1dXG.d.ts +0 -100
  72. package/dist/preview.d.ts +0 -2
  73. package/dist/preview.js +0 -160
  74. package/dist/render-ir.d.ts +0 -19
  75. package/dist/render-ir.js +0 -826
  76. package/dist/sms-segments.d.ts +0 -13
  77. package/dist/sms-segments.js +0 -46
  78. package/dist/source-edit.d.ts +0 -116
  79. package/dist/source-edit.js +0 -343
  80. package/dist/source-locations.d.ts +0 -2
  81. package/dist/source-locations.js +0 -16
  82. package/dist/static.d.ts +0 -57
  83. package/dist/static.js +0 -69
  84. package/dist/tailwind-CMYpZf1v.js +0 -614
  85. package/dist/template.d.ts +0 -2
  86. package/dist/theme-css.js +0 -2
  87. package/dist/theme-imports-lvBw3AD1.js +0 -109
  88. package/dist/transform-Ct2OMkFN.d.ts +0 -153
@@ -1,77 +1,5 @@
1
1
  import { r as JsxSourceLocation } from "./source-locations-C8wCsiAy.js";
2
2
  import { r as EmailDiagnostic } from "./diagnostics-B-Gym34R.js";
3
- //#region src/email/jsx-runtime.d.ts
4
- /** Derived authoring tree; source stays canonical. Origins run from inner element to component call sites. */
5
- type EmailNode = {
6
- readonly type: "Text";
7
- readonly value: string;
8
- } | {
9
- readonly type: "Element";
10
- readonly tag: string;
11
- readonly props: Readonly<Record<string, unknown>>;
12
- readonly children: readonly EmailNode[];
13
- readonly origins: readonly JsxSourceLocation[];
14
- /**
15
- * True when this element is written at `origins[0]`; false when a compiler
16
- * primitive generated it and `origins[0]` is the call site that asked for
17
- * it. Both point at the same authoring target, but only an authored element
18
- * can have its own props edited there.
19
- */
20
- readonly authored: boolean;
21
- } | {
22
- readonly type: "Fragment";
23
- readonly children: readonly EmailNode[];
24
- } |
25
- /**
26
- * Compatibility markup a compiler primitive emits verbatim — conditional
27
- * comments and VML. Only the primitives in `./components` construct it;
28
- * nothing an author passes as a string reaches this node.
29
- */
30
- {
31
- readonly type: "Raw";
32
- readonly html: string;
33
- readonly text: string;
34
- readonly origins: readonly JsxSourceLocation[];
35
- };
36
- type EmailNodeOf<Type extends EmailNode["type"]> = Extract<EmailNode, {
37
- readonly type: Type;
38
- }>;
39
- type EmailNodeFields<Type extends EmailNode["type"]> = Omit<EmailNodeOf<Type>, "type">;
40
- /** Constructors for the authoring tree. The tree is data; nothing here validates it. */
41
- declare const EmailNode: {
42
- readonly Text: (fields: EmailNodeFields<"Text">) => EmailNodeOf<"Text">;
43
- readonly Element: (fields: EmailNodeFields<"Element">) => EmailNodeOf<"Element">;
44
- readonly Fragment: (fields: EmailNodeFields<"Fragment">) => EmailNodeOf<"Fragment">;
45
- readonly Raw: (fields: EmailNodeFields<"Raw">) => EmailNodeOf<"Raw">;
46
- };
47
- type EmailChild = EmailNode | string | number | boolean | null | undefined | readonly EmailChild[];
48
- type EmailComponent<P = never> = (props: P) => EmailChild;
49
- declare const Fragment: unique symbol;
50
- /** Call sites enclosing the element being built, innermost first. */
51
- declare const currentEmailOrigins: () => readonly JsxSourceLocation[];
52
- /** Record a finding from inside a compiler primitive, located at the authoring call site. */
53
- declare const reportEmailDiagnostic: (diagnostic: Omit<EmailDiagnostic, "origins">) => void;
54
- /** Take and clear the findings primitives reported during a render. */
55
- declare const drainEmailDiagnostics: () => readonly EmailDiagnostic[];
56
- /** Normalize actual values without interpolation or recording proxies. */
57
- declare const normalizeChildren: (input: unknown) => EmailNode[];
58
- /** Compatibility markup emitted by a compiler primitive, with the text it stands for. */
59
- declare const rawMarkup: (html: string, text?: string) => EmailNode;
60
- /** Automatic JSX factory for ordinary HTML and synchronous imported components. */
61
- declare const jsx: (type: string | EmailComponent<Record<string, unknown>> | typeof Fragment, props: Record<string, unknown> | null) => EmailNode;
62
- declare const jsxs: typeof jsx;
63
- declare namespace JSX {
64
- type Element = EmailNode;
65
- type ElementType = string | EmailComponent | typeof Fragment;
66
- interface ElementChildrenAttribute {
67
- readonly children: object;
68
- }
69
- interface IntrinsicAttributes {
70
- readonly key?: string | number | undefined;
71
- }
72
- interface IntrinsicElements extends EmailIntrinsicElements {}
73
- }
74
- //#endregion
75
3
  //#region src/email/elements.d.ts
76
4
  /** How one attribute is spelled and what values it accepts. */
77
5
  interface EmailAttributeSpec {
@@ -695,5 +623,77 @@ type ChildrenProp<Content extends EmailElementSpec["content"]> = Content extends
695
623
  /** Props each supported tag accepts, derived from `EMAIL_ELEMENTS`. */
696
624
  type EmailIntrinsicElements = { readonly [Tag in EmailTag]: EmailGlobalProps & AttributeProps<typeof EMAIL_GLOBAL_ATTRIBUTES> & AttributeProps<(typeof EMAIL_ELEMENTS)[Tag]["attributes"]> & ChildrenProp<(typeof EMAIL_ELEMENTS)[Tag]["content"]>; };
697
625
  //#endregion
698
- export { reportEmailDiagnostic as C, rawMarkup as S, currentEmailOrigins as _, EmailGlobalProps as a, jsxs as b, EmailStyle as c, isUrlAttribute as d, EmailChild as f, JSX as g, Fragment as h, EmailElementSpec as i, EmailTag as l, EmailNode as m, EMAIL_GLOBAL_ATTRIBUTES as n, EmailIntrinsicElements as o, EmailComponent as p, EmailAttributeSpec as r, EmailLayout as s, EMAIL_ELEMENTS as t, emailElement as u, drainEmailDiagnostics as v, normalizeChildren as x, jsx as y };
699
- //# sourceMappingURL=elements-cqldpaJt.d.ts.map
626
+ //#region src/email/jsx-runtime.d.ts
627
+ /** Derived authoring tree; source stays canonical. Origins run from inner element to component call sites. */
628
+ type EmailNode = {
629
+ readonly type: "Text";
630
+ readonly value: string;
631
+ } | {
632
+ readonly type: "Element";
633
+ readonly tag: string;
634
+ readonly props: Readonly<Record<string, unknown>>;
635
+ readonly children: readonly EmailNode[];
636
+ readonly origins: readonly JsxSourceLocation[];
637
+ /**
638
+ * True when this element is written at `origins[0]`; false when a compiler
639
+ * primitive generated it and `origins[0]` is the call site that asked for
640
+ * it. Both point at the same authoring target, but only an authored element
641
+ * can have its own props edited there.
642
+ */
643
+ readonly authored: boolean;
644
+ } | {
645
+ readonly type: "Fragment";
646
+ readonly children: readonly EmailNode[];
647
+ } |
648
+ /**
649
+ * Compatibility markup a compiler primitive emits verbatim — conditional
650
+ * comments and VML. Only the primitives in `./components` construct it;
651
+ * nothing an author passes as a string reaches this node.
652
+ */
653
+ {
654
+ readonly type: "Raw";
655
+ readonly html: string;
656
+ readonly text: string;
657
+ readonly origins: readonly JsxSourceLocation[];
658
+ };
659
+ type EmailNodeOf<Type extends EmailNode["type"]> = Extract<EmailNode, {
660
+ readonly type: Type;
661
+ }>;
662
+ type EmailNodeFields<Type extends EmailNode["type"]> = Omit<EmailNodeOf<Type>, "type">;
663
+ /** Constructors for the authoring tree. The tree is data; nothing here validates it. */
664
+ declare const EmailNode: {
665
+ readonly Text: (fields: EmailNodeFields<"Text">) => EmailNodeOf<"Text">;
666
+ readonly Element: (fields: EmailNodeFields<"Element">) => EmailNodeOf<"Element">;
667
+ readonly Fragment: (fields: EmailNodeFields<"Fragment">) => EmailNodeOf<"Fragment">;
668
+ readonly Raw: (fields: EmailNodeFields<"Raw">) => EmailNodeOf<"Raw">;
669
+ };
670
+ type EmailChild = EmailNode | string | number | boolean | null | undefined | readonly EmailChild[];
671
+ type EmailComponent<P = never> = (props: P) => EmailChild;
672
+ declare const Fragment: unique symbol;
673
+ /** Call sites enclosing the element being built, innermost first. */
674
+ declare const currentEmailOrigins: () => readonly JsxSourceLocation[];
675
+ /** Record a finding from inside a compiler primitive, located at the authoring call site. */
676
+ declare const reportEmailDiagnostic: (diagnostic: Omit<EmailDiagnostic, "origins">) => void;
677
+ /** Take and clear the findings primitives reported during a render. */
678
+ declare const drainEmailDiagnostics: () => readonly EmailDiagnostic[];
679
+ /** Normalize actual values without interpolation or recording proxies. */
680
+ declare const normalizeChildren: (input: unknown) => EmailNode[];
681
+ /** Compatibility markup emitted by a compiler primitive, with the text it stands for. */
682
+ declare const rawMarkup: (html: string, text?: string) => EmailNode;
683
+ /** Automatic JSX factory for ordinary HTML and synchronous imported components. */
684
+ declare const jsx: (type: string | EmailComponent<Record<string, unknown>> | typeof Fragment, props: Record<string, unknown> | null) => EmailNode;
685
+ declare const jsxs: typeof jsx;
686
+ declare namespace JSX {
687
+ type Element = EmailNode;
688
+ type ElementType = string | EmailComponent | typeof Fragment;
689
+ interface ElementChildrenAttribute {
690
+ readonly children: object;
691
+ }
692
+ interface IntrinsicAttributes {
693
+ readonly key?: string | number | undefined;
694
+ }
695
+ interface IntrinsicElements extends EmailIntrinsicElements {}
696
+ }
697
+ //#endregion
698
+ export { isUrlAttribute as C, emailElement as S, EmailGlobalProps as _, JSX as a, EmailStyle as b, jsx as c, rawMarkup as d, reportEmailDiagnostic as f, EmailElementSpec as g, EmailAttributeSpec as h, Fragment as i, jsxs as l, EMAIL_GLOBAL_ATTRIBUTES as m, EmailComponent as n, currentEmailOrigins as o, EMAIL_ELEMENTS as p, EmailNode as r, drainEmailDiagnostics as s, EmailChild as t, normalizeChildren as u, EmailIntrinsicElements as v, EmailTag as x, EmailLayout as y };
699
+ //# sourceMappingURL=jsx-runtime-ylIOnaSf.d.ts.map
@@ -1,20 +1,119 @@
1
1
  import { n as isObject } from "./guards-eV1qLbf2.js";
2
2
  import { n as inputSchema, r as jsonSchema } from "./input-schema-zjkgrXn2.js";
3
- import { TEMPLATE_ID_PATTERN, TEMPLATE_NAME_PATTERN } from "./template.js";
4
- import { FORMATTER_NAMES } from "./fmt.js";
5
- import { isAssetPath } from "./email/assets.js";
6
- import { buildLineMap, lineColumn } from "./diagnostics.js";
3
+ import { n as TEMPLATE_NAME_PATTERN, t as TEMPLATE_ID_PATTERN } from "./template-zLUjcwfF.js";
7
4
  import { n as RESERVED_FOOTER_ATTRIBUTES, t as BRAND_FOOTER_MARKER } from "./unsubscribe-link-CoesnQDU.js";
8
- import { EmailNode, drainEmailDiagnostics } from "./email/jsx-runtime.js";
9
- import { brandComponents } from "./email/brand.js";
10
- import { t as applyStylesheet } from "./cascade-t6kxlgEI.js";
11
- import { i as resolveFromDirectory, r as projectDirectory } from "./theme-imports-lvBw3AD1.js";
12
- import "./ir.js";
13
- import { a as WHATSAPP_HEADER_TYPES, i as WHATSAPP_CATEGORIES, n as SMS_CATEGORIES, r as WHATSAPP_ATTRIBUTES, t as SMS_ATTRIBUTES } from "./channel-specs-B6M_HlaV.js";
14
- import { EMAIL_ELEMENTS, emailElement } from "./email/elements.js";
15
- import { checkAttribute, serializeStyle } from "./email/html.js";
16
- import { Button, Column, Columns, Divider, Email, Image, Link, Section, Spacer, equalColumnWidth } from "./email/components.js";
17
- import { parse } from "@babel/parser";
5
+ import { M as EMAIL_ELEMENTS, P as emailElement, a as Email, d as equalColumnWidth, i as Divider, l as Section, n as Column, o as Image, p as checkAttribute, r as Columns, s as Link, t as Button, u as Spacer, y as serializeStyle } from "./components-BZCqegS8.js";
6
+ import { FORMATTER_NAMES } from "./fmt.js";
7
+ import { i as drainEmailDiagnostics, t as EmailNode } from "./jsx-runtime-CBlexoeR.js";
8
+ import { n as applyStylesheet } from "./ir-CLhlklKV.js";
9
+ import { i as lineColumn, t as buildLineMap } from "./diagnostic-model-DJtqbETd.js";
10
+ import { d as isAssetPath, i as brandComponents } from "./brand-C0MKTwmX.js";
11
+ import { parse } from "css-tree";
12
+ import { parse as parse$1 } from "@babel/parser";
13
+ //#region src/email/theme-imports.ts
14
+ /** The CSS and TSX specifier a template uses to reach its organization's brand. */
15
+ const BRAND_SPECIFIER = "samva:brand";
16
+ const BRAND_IMPORT = /^samva:brand(?:\/([a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?))?$/;
17
+ /** The brand a `samva:brand` specifier names: `undefined` slug means the default brand. */
18
+ const parseBrandSpecifier = (specifier) => {
19
+ const match = BRAND_IMPORT.exec(specifier);
20
+ return match === null ? void 0 : { slug: match[1] };
21
+ };
22
+ /** The directory part of a project path, with no trailing slash (`""` at the root). */
23
+ const projectDirectory = (path) => path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : "";
24
+ /** A relative or root-absolute stylesheet reference, resolved from a project directory. */
25
+ const resolveFromDirectory = (directory, reference) => {
26
+ const segments = reference.startsWith("/") || directory === "" ? [] : directory.split("/");
27
+ for (const segment of reference.split("/")) {
28
+ if (segment === "" || segment === ".") continue;
29
+ if (segment === "..") {
30
+ if (segments.length === 0) return void 0;
31
+ segments.pop();
32
+ } else segments.push(segment);
33
+ }
34
+ return segments.length === 0 ? void 0 : segments.join("/");
35
+ };
36
+ const importTarget = (node) => {
37
+ if (node.type !== "Atrule" || node.prelude === null || node.prelude.type !== "AtrulePrelude") return { extra: true };
38
+ const parts = [...node.prelude.children].filter((part) => part.type !== "WhiteSpace");
39
+ const first = parts[0];
40
+ const target = first?.type === "String" ? first.value : first?.type === "Url" ? first.value : void 0;
41
+ return target === void 0 ? { extra: true } : {
42
+ target,
43
+ extra: parts.length > 1
44
+ };
45
+ };
46
+ /**
47
+ * Walk the theme's `@import` graph. Project `.css` files resolve from the
48
+ * importing file's directory; `samva:brand` and `samva:brand/<slug>` are
49
+ * recorded for the brand the build supplies. Anything else is an error.
50
+ */
51
+ const resolveThemeImports = (themePath, themeCss, files) => {
52
+ const stylesheets = /* @__PURE__ */ new Map([[themePath, themeCss]]);
53
+ const brandSpecifiers = /* @__PURE__ */ new Set();
54
+ const diagnostics = [];
55
+ const visit = (path, source, chain) => {
56
+ const lineMap = buildLineMap(source);
57
+ const ast = parse(source, {
58
+ positions: true,
59
+ parseValue: false,
60
+ parseRulePrelude: false
61
+ });
62
+ if (ast.type !== "StyleSheet") return;
63
+ for (const node of ast.children) {
64
+ if (node.type !== "Atrule" || node.name.toLowerCase() !== "import") continue;
65
+ const position = lineColumn(lineMap, node.loc?.start.offset ?? 0);
66
+ const origins = [{
67
+ fileName: path,
68
+ lineNumber: position.line,
69
+ columnNumber: position.column
70
+ }];
71
+ const refuse = (message) => diagnostics.push({
72
+ code: "css-import-unresolved",
73
+ severity: "error",
74
+ message,
75
+ origins
76
+ });
77
+ const { target, extra } = importTarget(node);
78
+ if (target === void 0) {
79
+ refuse(`${path}: @import needs a quoted stylesheet path or "samva:brand".`);
80
+ continue;
81
+ }
82
+ if (extra) {
83
+ refuse(`${path}: @import ${JSON.stringify(target)} takes no layer, supports or media conditions; the import order is the layering.`);
84
+ continue;
85
+ }
86
+ if (parseBrandSpecifier(target) !== void 0) {
87
+ brandSpecifiers.add(target);
88
+ continue;
89
+ }
90
+ if (!/^\.{0,2}\//.test(target) || !/\.css$/i.test(target.replace(/[?#].*$/, ""))) {
91
+ 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.`);
92
+ continue;
93
+ }
94
+ const resolved = resolveFromDirectory(projectDirectory(path), target.replace(/[?#].*$/, ""));
95
+ const content = resolved === void 0 ? void 0 : files[resolved];
96
+ if (resolved === void 0 || typeof content !== "string") {
97
+ refuse(`${path}: @import ${JSON.stringify(target)} names no stylesheet in the project.`);
98
+ continue;
99
+ }
100
+ if (chain.includes(resolved)) {
101
+ refuse(`${path}: @import ${JSON.stringify(target)} imports itself through ${chain.join(" → ")}.`);
102
+ continue;
103
+ }
104
+ if (stylesheets.has(resolved)) continue;
105
+ stylesheets.set(resolved, content);
106
+ visit(resolved, content, [...chain, resolved]);
107
+ }
108
+ };
109
+ visit(themePath, themeCss, [themePath]);
110
+ return {
111
+ stylesheets,
112
+ brandSpecifiers: [...brandSpecifiers].sort(),
113
+ diagnostics
114
+ };
115
+ };
116
+ //#endregion
18
117
  //#region src/sml/diagnostics.ts
19
118
  /** Collects the findings of one compile. Every finding carries a code, a location and a fix. */
20
119
  var Findings = class {
@@ -125,7 +224,7 @@ const parseSource = (path, source) => {
125
224
  const position = (offset) => lineColumn(lines, offset);
126
225
  let program;
127
226
  try {
128
- program = parse(source, {
227
+ program = parse$1(source, {
129
228
  plugins: ["typescript", "jsx"],
130
229
  sourceType: "module"
131
230
  }).program;
@@ -163,6 +262,32 @@ const isValueNode = (node) => {
163
262
  return true;
164
263
  };
165
264
  //#endregion
265
+ //#region src/channel-specs.ts
266
+ const SMS_CATEGORIES = [
267
+ "transactional",
268
+ "promotional",
269
+ "service_implicit"
270
+ ];
271
+ const WHATSAPP_CATEGORIES = [
272
+ "marketing",
273
+ "utility",
274
+ "authentication"
275
+ ];
276
+ const WHATSAPP_HEADER_TYPES = [
277
+ "text",
278
+ "image",
279
+ "video",
280
+ "document"
281
+ ];
282
+ /** The attributes `<Sms>` accepts. */
283
+ const SMS_ATTRIBUTES = ["category"];
284
+ /** The attributes `<WhatsApp>` accepts. */
285
+ const WHATSAPP_ATTRIBUTES = [
286
+ "name",
287
+ "language",
288
+ "category"
289
+ ];
290
+ //#endregion
166
291
  //#region src/whatsapp-template.ts
167
292
  const isConcat = (value) => typeof value === "object" && value !== null && "concat" in value;
168
293
  /**
@@ -976,10 +1101,10 @@ const runBuiltinComponent = (call) => {
976
1101
  return [];
977
1102
  }
978
1103
  const exported = binding.imported;
979
- const isEmail = binding.kind === "markup" && specifier === "@samva/markup/email/components";
1104
+ const isEmail = binding.kind === "markup" && specifier === "@samva/markup/email";
980
1105
  const isBrand = binding.kind === "brand";
981
1106
  if (!(isEmail || isBrand)) {
982
- lowerer.error(ctx, node, "unknown-component", `<${call.name}> is not a component the profile can read.`, "Import components from @samva/markup/email/components, samva:brand, or the project.");
1107
+ lowerer.error(ctx, node, "unknown-component", `<${call.name}> is not a component the profile can read.`, "Import components from @samva/markup/email, samva:brand, or the project.");
983
1108
  return [];
984
1109
  }
985
1110
  let fn;
@@ -2187,7 +2312,7 @@ var Lowerer = class {
2187
2312
  value: local.value
2188
2313
  };
2189
2314
  if (fn === void 0 || !/Function|Arrow/.test(fn.value.type)) {
2190
- this.error(ctx, node, "unknown-component", `<${name}> is not a component the profile can read.`, "Import it from @samva/markup/email/components, or from a project file that exports it as a function.");
2315
+ this.error(ctx, node, "unknown-component", `<${name}> is not a component the profile can read.`, "Import it from @samva/markup/email, or from a project file that exports it as a function.");
2191
2316
  return [];
2192
2317
  }
2193
2318
  return this.partial(ctx, node, attributes, name, fn.module, fn.value);
@@ -3407,6 +3532,8 @@ const lowerProject = (options, project, findings, inputs) => {
3407
3532
  //#region src/sml/project.ts
3408
3533
  const MARKUP_SPECIFIER = "@samva/markup";
3409
3534
  const MARKUP_PREFIX = "@samva/markup/";
3535
+ /** Entries a template could import that moved; each is reported with its replacement. */
3536
+ const MOVED_MARKUP_ENTRIES = { "@samva/markup/email/components": "@samva/markup/email" };
3410
3537
  const SCRIPT_EXTENSIONS = [".tsx", ".ts"];
3411
3538
  /** Resolve a relative specifier to a project file, or `undefined`. */
3412
3539
  const resolveSpecifier = (from, specifier, files) => {
@@ -3486,6 +3613,12 @@ const loadProject = (files, entryPath, findings, loadOptions = {}) => {
3486
3613
  const imported = child(node, "imported");
3487
3614
  return imported === void 0 ? local(node) : text(imported, "name") ?? text(imported, "value") ?? local(node);
3488
3615
  };
3616
+ const moved = MOVED_MARKUP_ENTRIES[specifier];
3617
+ if (moved !== void 0) {
3618
+ findings.add(parsed, child(statement, "source") ?? statement, "moved-import", `\`${specifier}\` moved to \`${moved}\`; the imported names are unchanged.`, `Import from "${moved}".`);
3619
+ failed = true;
3620
+ break;
3621
+ }
3489
3622
  if (specifier === MARKUP_SPECIFIER || specifier.startsWith(MARKUP_PREFIX)) {
3490
3623
  for (const item of specifiers) {
3491
3624
  if (text(item, "importKind") === "type") continue;
@@ -3665,6 +3798,6 @@ const introducedProfileErrors = (before, after) => {
3665
3798
  return added;
3666
3799
  };
3667
3800
  //#endregion
3668
- export { lowerProject as a, completed as i, introducedProfileErrors as n, Findings as o, loadProject as r, checkStaticProfile as t };
3801
+ export { lowerProject as a, WHATSAPP_HEADER_TYPES as c, parseBrandSpecifier as d, projectDirectory as f, completed as i, Findings as l, resolveThemeImports as m, introducedProfileErrors as n, SMS_CATEGORIES as o, resolveFromDirectory as p, loadProject as r, WHATSAPP_CATEGORIES as s, checkStaticProfile as t, BRAND_SPECIFIER as u };
3669
3802
 
3670
- //# sourceMappingURL=profile-BH-OtdDA.js.map
3803
+ //# sourceMappingURL=profile-pWGtWZXF.js.map