@samva/markup 0.1.2 → 0.3.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 +25 -5
- package/README.md +92 -26
- package/dist/{ast-DAhnAvQN.d.ts → ast-63I-VLQx.d.ts} +15 -2
- package/dist/ast.d.ts +2 -2
- package/dist/ast.js +14 -1
- package/dist/{checks-D-zFQt5R.js → checks-DXuERO4B.js} +36 -2
- package/dist/checks.d.ts +8 -1
- package/dist/checks.js +2 -2
- package/dist/compile-sms.d.ts +2 -2
- package/dist/compile-whatsapp.d.ts +2 -2
- package/dist/compile.d.ts +9 -84
- package/dist/compile.js +11 -920
- package/dist/compiler.d.ts +303 -0
- package/dist/compiler.js +1390 -0
- package/dist/components.d.ts +3 -3
- package/dist/corpus-qrUD5O6r.d.ts +254 -0
- package/dist/css-ar2lU3NC.d.ts +84 -0
- package/dist/diagnostics-Djd9ckLg.d.ts +90 -0
- package/dist/diagnostics.js +4 -1
- package/dist/elements-DtwKlFVH.d.ts +820 -0
- package/dist/email/components.d.ts +125 -0
- package/dist/email/components.js +210 -0
- package/dist/email/diagnostics.d.ts +2 -0
- package/dist/email/diagnostics.js +56 -0
- package/dist/email/elements.d.ts +2 -0
- package/dist/email/elements.js +299 -0
- package/dist/email/html.d.ts +42 -0
- package/dist/email/html.js +266 -0
- package/dist/email/jsx-dev-runtime.d.ts +26 -0
- package/dist/email/jsx-dev-runtime.js +12 -0
- package/dist/email/jsx-runtime.d.ts +2 -0
- package/dist/email/jsx-runtime.js +60 -0
- package/dist/email/render.d.ts +43 -0
- package/dist/email/render.js +6 -0
- package/dist/email/selection.d.ts +102 -0
- package/dist/email/selection.js +143 -0
- package/dist/email/source-edit.d.ts +67 -0
- package/dist/email/source-edit.js +185 -0
- package/dist/email/stylesheets.d.ts +15 -0
- package/dist/email/stylesheets.js +45 -0
- package/dist/email/text.d.ts +7 -0
- package/dist/email/text.js +100 -0
- package/dist/emit.d.ts +13 -12
- package/dist/emit.js +63 -63
- package/dist/input-schema-BIfzI63B.d.ts +23 -0
- package/dist/input-schema.d.ts +2 -0
- package/dist/input-schema.js +170 -0
- package/dist/jsx-dev-runtime.d.ts +4 -3
- package/dist/jsx-dev-runtime.js +9 -1
- package/dist/{jsx-runtime-eNIMY87F.d.ts → jsx-runtime-C5k_Zq0A.d.ts} +3 -3
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +20 -1
- package/dist/model.d.ts +1 -1
- package/dist/ops.d.ts +1 -1
- package/dist/ops.js +1 -1
- package/dist/{parser-DkQKIjDa.d.ts → parser-CGBS73Gz.d.ts} +2 -2
- package/dist/parser.d.ts +1 -1
- package/dist/presets/category-mapping.d.ts +1 -1
- package/dist/presets/corpus.d.ts +2 -0
- package/dist/presets/corpus.js +247 -0
- package/dist/presets/public-gallery.d.ts +290 -2
- package/dist/presets/public-gallery.js +428 -6
- package/dist/presets/public-handoff.d.ts +164 -2
- package/dist/presets/public-handoff.js +229 -61
- package/dist/presets/public-preview-artifacts.d.ts +2 -2
- package/dist/presets/public-preview-artifacts.js +25 -31
- package/dist/presets/public-preview.d.ts +65 -2
- package/dist/presets/public-preview.js +402 -1152
- package/dist/presets/sources.d.ts +35 -4
- package/dist/presets/sources.js +2328 -43
- package/dist/presets.d.ts +39 -5
- package/dist/presets.js +96 -0
- package/dist/printer.d.ts +1 -1
- package/dist/render-template.d.ts +5 -2
- package/dist/render-template.js +3 -1
- package/dist/render-ykQhtMs_.js +592 -0
- package/dist/source-locations-BCJQnIfU.d.ts +89 -0
- package/dist/source-locations.d.ts +2 -0
- package/dist/source-locations.js +125 -0
- package/dist/template-Dy5yOPyp.d.ts +60 -0
- package/dist/template.d.ts +2 -0
- package/dist/template.js +37 -0
- package/dist/tsx-source-instrumentation.d.ts +23 -0
- package/dist/tsx-source-instrumentation.js +97 -0
- package/dist/tsx-tracer.d.ts +116 -0
- package/dist/tsx-tracer.js +985 -0
- package/generated/sml-agent-contract.json +574 -782
- package/generated/sml-email-agent-contract.json +502 -677
- package/generated/sml-email-language-reference.md +94 -160
- package/generated/sml-language-reference.md +195 -220
- package/package.json +111 -9
- package/dist/public-gallery-D0Zv0pZE.d.ts +0 -611
- package/dist/public-preview-u1Z9aaGq.d.ts +0 -1168
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
import { EmailNode, drainEmailDiagnostics } from "./email/jsx-runtime.js";
|
|
2
|
+
import { declarationValue, kebab, serializeEmailHtml } from "./email/html.js";
|
|
3
|
+
import { PREHEADER_ATTRIBUTE, preheaderNode } from "./email/components.js";
|
|
4
|
+
import { EmailCompileError, hasBlockingDiagnostic } from "./email/diagnostics.js";
|
|
5
|
+
import { snapshotStylesheets } from "./email/stylesheets.js";
|
|
6
|
+
import { deriveEmailText } from "./email/text.js";
|
|
7
|
+
import { Predicate } from "effect";
|
|
8
|
+
//#region src/email/css-values.ts
|
|
9
|
+
/** Expand `var(--x, fallback)` against the collected custom properties. */
|
|
10
|
+
const resolveVariables = (value, variables, depth = 0) => {
|
|
11
|
+
if (depth > 8 || !value.includes("var(")) return value;
|
|
12
|
+
let result = "";
|
|
13
|
+
let rest = value;
|
|
14
|
+
while (rest.length > 0) {
|
|
15
|
+
const start = rest.indexOf("var(");
|
|
16
|
+
if (start < 0) {
|
|
17
|
+
result += rest;
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
result += rest.slice(0, start);
|
|
21
|
+
let level = 0;
|
|
22
|
+
let end = -1;
|
|
23
|
+
for (let index = start + 3; index < rest.length; index++) if (rest[index] === "(") level += 1;
|
|
24
|
+
else if (rest[index] === ")") {
|
|
25
|
+
level -= 1;
|
|
26
|
+
if (level === 0) {
|
|
27
|
+
end = index;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (end < 0) {
|
|
32
|
+
result += rest.slice(start);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
const body = rest.slice(start + 4, end);
|
|
36
|
+
const comma = body.indexOf(",");
|
|
37
|
+
const name = (comma < 0 ? body : body.slice(0, comma)).trim();
|
|
38
|
+
const fallback = comma < 0 ? void 0 : body.slice(comma + 1).trim();
|
|
39
|
+
const replacement = variables[name] ?? fallback;
|
|
40
|
+
result += replacement === void 0 ? rest.slice(start, end + 1) : resolveVariables(replacement, variables, depth + 1);
|
|
41
|
+
rest = rest.slice(end + 1);
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Fold a constant `calc()` to a plain value. Tailwind writes every spacing
|
|
47
|
+
* utility as `calc(var(--spacing) * n)`, and classic Outlook does not implement
|
|
48
|
+
* `calc()` at all, so an unfolded value is a silently missing style. An
|
|
49
|
+
* expression that cannot be reduced to one term is left exactly as authored.
|
|
50
|
+
*/
|
|
51
|
+
const foldCalc = (value) => {
|
|
52
|
+
if (!value.includes("calc(")) return value;
|
|
53
|
+
let result = "";
|
|
54
|
+
let rest = value;
|
|
55
|
+
while (rest.length > 0) {
|
|
56
|
+
const start = rest.indexOf("calc(");
|
|
57
|
+
if (start < 0) {
|
|
58
|
+
result += rest;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
result += rest.slice(0, start);
|
|
62
|
+
let level = 0;
|
|
63
|
+
let end = -1;
|
|
64
|
+
for (let index = start + 4; index < rest.length; index++) if (rest[index] === "(") level += 1;
|
|
65
|
+
else if (rest[index] === ")") {
|
|
66
|
+
level -= 1;
|
|
67
|
+
if (level === 0) {
|
|
68
|
+
end = index;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (end < 0) {
|
|
73
|
+
result += rest.slice(start);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
const folded = evaluate(rest.slice(start + 5, end));
|
|
77
|
+
result += folded === void 0 ? rest.slice(start, end + 1) : format(folded);
|
|
78
|
+
rest = rest.slice(end + 1);
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
};
|
|
82
|
+
const format = (value) => `${Math.round(value.n * 1e6) / 1e6}${value.n === 0 && value.unit !== "%" ? "" : value.unit}`;
|
|
83
|
+
const evaluate = (expression) => {
|
|
84
|
+
const tokens = expression.match(/\(|\)|[+-]\s|[*/]|[^\s()*/]+/g);
|
|
85
|
+
if (tokens === null) return void 0;
|
|
86
|
+
let position = 0;
|
|
87
|
+
const peek = () => tokens[position]?.trim();
|
|
88
|
+
const sum = () => {
|
|
89
|
+
let left = product();
|
|
90
|
+
while (left !== void 0 && (peek() === "+" || peek() === "-")) {
|
|
91
|
+
const operator = peek();
|
|
92
|
+
position += 1;
|
|
93
|
+
const right = product();
|
|
94
|
+
if (right === void 0 || left.unit !== right.unit) return void 0;
|
|
95
|
+
left = {
|
|
96
|
+
n: operator === "+" ? left.n + right.n : left.n - right.n,
|
|
97
|
+
unit: left.unit
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return left;
|
|
101
|
+
};
|
|
102
|
+
const product = () => {
|
|
103
|
+
let left = term();
|
|
104
|
+
while (left !== void 0 && (peek() === "*" || peek() === "/")) {
|
|
105
|
+
const operator = peek();
|
|
106
|
+
position += 1;
|
|
107
|
+
const right = term();
|
|
108
|
+
if (right === void 0) return void 0;
|
|
109
|
+
if (operator === "*") {
|
|
110
|
+
if (left.unit !== "" && right.unit !== "") return void 0;
|
|
111
|
+
left = {
|
|
112
|
+
n: left.n * right.n,
|
|
113
|
+
unit: left.unit === "" ? right.unit : left.unit
|
|
114
|
+
};
|
|
115
|
+
} else {
|
|
116
|
+
if (right.unit !== "" || right.n === 0) return void 0;
|
|
117
|
+
left = {
|
|
118
|
+
n: left.n / right.n,
|
|
119
|
+
unit: left.unit
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return left;
|
|
124
|
+
};
|
|
125
|
+
const term = () => {
|
|
126
|
+
const token = tokens[position];
|
|
127
|
+
if (token === void 0) return void 0;
|
|
128
|
+
if (token === "(") {
|
|
129
|
+
position += 1;
|
|
130
|
+
const inner = sum();
|
|
131
|
+
if (peek() !== ")") return void 0;
|
|
132
|
+
position += 1;
|
|
133
|
+
return inner;
|
|
134
|
+
}
|
|
135
|
+
const match = /^(-?(?:\d+\.?\d*|\.\d+))([a-z%]*)$/i.exec(token.trim());
|
|
136
|
+
if (match === null) return void 0;
|
|
137
|
+
position += 1;
|
|
138
|
+
return {
|
|
139
|
+
n: Number.parseFloat(match[1]),
|
|
140
|
+
unit: (match[2] ?? "").toLowerCase()
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
const value = sum();
|
|
144
|
+
return position === tokens.length ? value : void 0;
|
|
145
|
+
};
|
|
146
|
+
/** Resolve custom properties, then fold what the arithmetic allows. */
|
|
147
|
+
const finalizeValue = (value, variables) => foldCalc(resolveVariables(value, variables));
|
|
148
|
+
const RANGE_FEATURE = /\(\s*([a-z-]+)\s*(<=|>=|<|>)\s*([^)]+?)\s*\)/gi;
|
|
149
|
+
/** Media Queries Level 4 range syntax down to the `min-`/`max-` prefixes clients support. */
|
|
150
|
+
const downlevelMediaQuery = (condition) => condition.replace(RANGE_FEATURE, (whole, feature, comparison, bound) => {
|
|
151
|
+
return `(${comparison.startsWith(">") ? "min-" : "max-"}${feature}:${bound})`;
|
|
152
|
+
});
|
|
153
|
+
/** Render the rules that could not be inlined as one `<style>` body. */
|
|
154
|
+
const renderHeadCss = (rules, headAtRules, variables) => {
|
|
155
|
+
const blocks = [...headAtRules];
|
|
156
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
157
|
+
for (const rule of rules) {
|
|
158
|
+
const conditions = rule.conditions.map(downlevelMediaQuery);
|
|
159
|
+
const key = conditions.join("\0");
|
|
160
|
+
const bucket = grouped.get(key);
|
|
161
|
+
if (bucket === void 0) grouped.set(key, {
|
|
162
|
+
conditions,
|
|
163
|
+
rules: [rule]
|
|
164
|
+
});
|
|
165
|
+
else bucket.rules.push(rule);
|
|
166
|
+
}
|
|
167
|
+
for (const { conditions, rules: bucket } of grouped.values()) {
|
|
168
|
+
const body = bucket.map((rule) => {
|
|
169
|
+
const declarations = rule.declarations.filter((declaration) => !declaration.property.startsWith("--")).map((declaration) => `${declaration.property}:${finalizeValue(declaration.value, variables)}!important`).join(";");
|
|
170
|
+
return declarations === "" ? "" : `${rule.selector}{${declarations}}`;
|
|
171
|
+
}).filter((block) => block !== "").join("");
|
|
172
|
+
if (body === "") continue;
|
|
173
|
+
blocks.push(conditions.reduceRight((inner, condition) => `${condition}{${inner}}`, body));
|
|
174
|
+
}
|
|
175
|
+
return blocks.join("");
|
|
176
|
+
};
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region src/email/selectors.ts
|
|
179
|
+
const classListOf = (element) => {
|
|
180
|
+
const value = element.props.class ?? element.props.className;
|
|
181
|
+
return typeof value === "string" ? value.split(/\s+/).filter((name) => name !== "") : [];
|
|
182
|
+
};
|
|
183
|
+
const attributeOf = (element, name) => {
|
|
184
|
+
const value = element.props[name];
|
|
185
|
+
if (value === void 0 || value === null || value === false) return void 0;
|
|
186
|
+
if (value === true) return "";
|
|
187
|
+
return typeof value === "string" || typeof value === "number" ? String(value) : void 0;
|
|
188
|
+
};
|
|
189
|
+
const matchesAttribute = (element, test) => {
|
|
190
|
+
const actual = test.name === "class" ? classListOf(element).join(" ") : attributeOf(element, test.name);
|
|
191
|
+
if (actual === void 0) return false;
|
|
192
|
+
if (test.operator === void 0 || test.value === void 0) return true;
|
|
193
|
+
switch (test.operator) {
|
|
194
|
+
case "=": return actual === test.value;
|
|
195
|
+
case "~=": return actual.split(/\s+/).includes(test.value);
|
|
196
|
+
case "^=": return actual.startsWith(test.value);
|
|
197
|
+
case "$=": return actual.endsWith(test.value);
|
|
198
|
+
case "*=": return actual.includes(test.value);
|
|
199
|
+
case "|=": return actual === test.value || actual.startsWith(`${test.value}-`);
|
|
200
|
+
default: return false;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
const matchesCompound = (element, compound) => {
|
|
204
|
+
if (compound.opaque) return false;
|
|
205
|
+
if (compound.tag !== void 0 && compound.tag !== element.tag) return false;
|
|
206
|
+
if (compound.id !== void 0 && attributeOf(element, "id") !== compound.id) return false;
|
|
207
|
+
if (compound.classes.length > 0) {
|
|
208
|
+
const classes = classListOf(element);
|
|
209
|
+
if (!compound.classes.every((name) => classes.includes(name))) return false;
|
|
210
|
+
}
|
|
211
|
+
return compound.attributes.every((test) => matchesAttribute(element, test));
|
|
212
|
+
};
|
|
213
|
+
const matchesFrom = (selector, index, ancestry) => {
|
|
214
|
+
if (ancestry === void 0) return false;
|
|
215
|
+
const part = selector.parts[index];
|
|
216
|
+
if (part === void 0) return false;
|
|
217
|
+
if (!matchesCompound(ancestry.element, part.compound)) return false;
|
|
218
|
+
const left = selector.parts[index - 1];
|
|
219
|
+
if (left === void 0) return true;
|
|
220
|
+
switch (left.after ?? "descendant") {
|
|
221
|
+
case "child": return matchesFrom(selector, index - 1, ancestry.parent);
|
|
222
|
+
case "descendant":
|
|
223
|
+
for (let parent = ancestry.parent; parent !== void 0; parent = parent.parent) if (matchesFrom(selector, index - 1, parent)) return true;
|
|
224
|
+
return false;
|
|
225
|
+
case "adjacent": {
|
|
226
|
+
const sibling = ancestry.previous.at(-1);
|
|
227
|
+
return sibling === void 0 ? false : matchesFrom(selector, index - 1, {
|
|
228
|
+
element: sibling,
|
|
229
|
+
parent: ancestry.parent,
|
|
230
|
+
previous: ancestry.previous.slice(0, -1)
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
case "sibling":
|
|
234
|
+
for (let position = ancestry.previous.length - 1; position >= 0; position--) if (matchesFrom(selector, index - 1, {
|
|
235
|
+
element: ancestry.previous[position],
|
|
236
|
+
parent: ancestry.parent,
|
|
237
|
+
previous: ancestry.previous.slice(0, position)
|
|
238
|
+
})) return true;
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
/** Match a compiled selector against one element in its tree position. */
|
|
243
|
+
const matchesSelector = (selector, ancestry) => selector === void 0 || selector.parts.length === 0 ? false : matchesFrom(selector, selector.parts.length - 1, ancestry);
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/email/cascade.ts
|
|
246
|
+
/**
|
|
247
|
+
* Cascade rank as the tuple CSS actually sorts by: importance first, then
|
|
248
|
+
* whether the declaration is attached to the element itself, then layer, then
|
|
249
|
+
* specificity, then order of appearance down to the declaration. Normal
|
|
250
|
+
* declarations sort by layer ascending (unlayered last, so it wins); important
|
|
251
|
+
* declarations reverse the layer order, which is why the layer term is negated
|
|
252
|
+
* for them. Element-attached declarations are compared before layers and
|
|
253
|
+
* specificity, so an author's important inline value beats an important
|
|
254
|
+
* stylesheet declaration exactly as it does in a browser. Two declarations never
|
|
255
|
+
* tie: rule order is unique across every registered sheet, and the position
|
|
256
|
+
* inside a rule separates the declarations that share it.
|
|
257
|
+
*/
|
|
258
|
+
const rank = (important, attached, layer, specificity, order, position) => [
|
|
259
|
+
important ? 1 : 0,
|
|
260
|
+
attached ? 1 : 0,
|
|
261
|
+
important ? -layer : layer,
|
|
262
|
+
specificity[0],
|
|
263
|
+
specificity[1],
|
|
264
|
+
specificity[2],
|
|
265
|
+
order,
|
|
266
|
+
position
|
|
267
|
+
];
|
|
268
|
+
const compareRank = (left, right) => {
|
|
269
|
+
for (let index = 0; index < Math.max(left.length, right.length); index++) {
|
|
270
|
+
const a = left[index] ?? 0;
|
|
271
|
+
const b = right[index] ?? 0;
|
|
272
|
+
if (a !== b) return a - b;
|
|
273
|
+
}
|
|
274
|
+
return 0;
|
|
275
|
+
};
|
|
276
|
+
const outranks = (left, right) => compareRank(left, right) >= 0;
|
|
277
|
+
/** An authored `style` object becomes declarations with the same normalization the serializer uses. */
|
|
278
|
+
const inlineDeclarations = (style) => {
|
|
279
|
+
if (!Predicate.isObject(style) || Array.isArray(style)) return [];
|
|
280
|
+
const output = [];
|
|
281
|
+
for (const [property, value] of Object.entries(style)) {
|
|
282
|
+
if (value === void 0 || value === null) continue;
|
|
283
|
+
if (typeof value !== "string" && typeof value !== "number") continue;
|
|
284
|
+
const text = declarationValue(property, value);
|
|
285
|
+
const important = /!important\s*$/i.test(text);
|
|
286
|
+
output.push({
|
|
287
|
+
property: kebab(property),
|
|
288
|
+
value: important ? text.replace(/\s*!important\s*$/i, "") : text,
|
|
289
|
+
important
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
return output;
|
|
293
|
+
};
|
|
294
|
+
const horizontalWriting = {
|
|
295
|
+
direction: "ltr",
|
|
296
|
+
writingMode: "horizontal-tb"
|
|
297
|
+
};
|
|
298
|
+
const paddingValues = (value) => {
|
|
299
|
+
const values = [];
|
|
300
|
+
let depth = 0;
|
|
301
|
+
let start = 0;
|
|
302
|
+
for (let index = 0; index < value.length; index++) {
|
|
303
|
+
const character = value[index];
|
|
304
|
+
if (character === "(") depth++;
|
|
305
|
+
else if (character === ")") depth--;
|
|
306
|
+
else if (/\s/.test(character) && depth === 0) {
|
|
307
|
+
if (index > start) values.push(value.slice(start, index));
|
|
308
|
+
start = index + 1;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (start < value.length) values.push(value.slice(start));
|
|
312
|
+
return values;
|
|
313
|
+
};
|
|
314
|
+
const physicalPadding = (property, value, context) => {
|
|
315
|
+
const original = [[property, value]];
|
|
316
|
+
const match = /^padding-(inline|block)(?:-(start|end))?$/.exec(property);
|
|
317
|
+
if (match === null || context.writingMode !== "horizontal-tb" || !["ltr", "rtl"].includes(context.direction) || /^(inherit|revert|revert-layer)$/.test(value) || value.includes("var(")) return original;
|
|
318
|
+
const values = paddingValues(value.trim());
|
|
319
|
+
if (values.length < 1 || values.length > (match[2] === void 0 ? 2 : 1)) return original;
|
|
320
|
+
const sides = match[1] === "block" ? ["top", "bottom"] : context.direction === "rtl" ? ["right", "left"] : ["left", "right"];
|
|
321
|
+
if (match[2] !== void 0) return [[`padding-${sides[match[2] === "start" ? 0 : 1]}`, values[0]]];
|
|
322
|
+
return [[`padding-${sides[0]}`, values[0]], [`padding-${sides[1]}`, values[1] ?? values[0]]];
|
|
323
|
+
};
|
|
324
|
+
/**
|
|
325
|
+
* Resolve every stylesheet against the tree: inline what a client will honor on
|
|
326
|
+
* the element, and keep the rest for `<head>`.
|
|
327
|
+
*/
|
|
328
|
+
const applyStylesheet = (root, sheet, options = {}) => {
|
|
329
|
+
const diagnostics = [...sheet.diagnostics];
|
|
330
|
+
const inlinable = [];
|
|
331
|
+
const retained = [];
|
|
332
|
+
const styledClasses = /* @__PURE__ */ new Set();
|
|
333
|
+
for (const rule of sheet.rules) {
|
|
334
|
+
(rule.inlinable ? inlinable : retained).push(rule);
|
|
335
|
+
for (const name of rule.classes) styledClasses.add(name);
|
|
336
|
+
}
|
|
337
|
+
const conditionalWritingRules = retained.filter((rule) => rule.declarations.some((declaration) => declaration.property === "direction" || declaration.property === "writing-mode" || declaration.property === "all"));
|
|
338
|
+
const unmatched = /* @__PURE__ */ new Map();
|
|
339
|
+
/**
|
|
340
|
+
* Children are visited with their own preceding-sibling list so `+`/`~` work.
|
|
341
|
+
* A fragment is not an element in the serialized document, so its children
|
|
342
|
+
* join that same list rather than starting a new one.
|
|
343
|
+
*/
|
|
344
|
+
const visitChildren = (children, ancestry, variables, writing) => {
|
|
345
|
+
const previous = [];
|
|
346
|
+
const visit = (nodes) => nodes.map((child) => {
|
|
347
|
+
if (child._tag === "Element") {
|
|
348
|
+
const result = applyTo(child, {
|
|
349
|
+
element: child,
|
|
350
|
+
parent: ancestry,
|
|
351
|
+
previous: [...previous]
|
|
352
|
+
}, variables, writing);
|
|
353
|
+
previous.push(child);
|
|
354
|
+
return result;
|
|
355
|
+
}
|
|
356
|
+
if (child._tag === "Fragment") return EmailNode.Fragment({ children: visit(child.children) });
|
|
357
|
+
return child;
|
|
358
|
+
});
|
|
359
|
+
return visit(children);
|
|
360
|
+
};
|
|
361
|
+
/**
|
|
362
|
+
* `inherited` is the custom-property scope this element sees from its
|
|
363
|
+
* ancestors, rooted in the sheet's unconditional properties. Custom properties
|
|
364
|
+
* cascade like any other declaration and then inherit, so a `--brand` declared
|
|
365
|
+
* on `.card` has to reach `var(--brand)` on `.card` and everything under it.
|
|
366
|
+
*/
|
|
367
|
+
const applyTo = (element, ancestry, inherited, inheritedWriting) => {
|
|
368
|
+
const conditionalWriting = conditionalWritingRules.some((rule) => {
|
|
369
|
+
if (rule.matcher === void 0 || rule.matcher.parts.length === 0 || rule.matcher.parts.some((part) => part.compound.opaque)) return true;
|
|
370
|
+
for (let context = ancestry; context !== void 0; context = context.parent) if (matchesSelector(rule.matcher, context)) return true;
|
|
371
|
+
return false;
|
|
372
|
+
});
|
|
373
|
+
const winners = /* @__PURE__ */ new Map();
|
|
374
|
+
const claim = (declaration, key) => {
|
|
375
|
+
const current = winners.get(declaration.property);
|
|
376
|
+
if (current === void 0 || outranks(key, current.key)) winners.set(declaration.property, {
|
|
377
|
+
value: declaration.value,
|
|
378
|
+
key
|
|
379
|
+
});
|
|
380
|
+
};
|
|
381
|
+
for (const rule of inlinable) {
|
|
382
|
+
if (!matchesSelector(rule.matcher, ancestry)) continue;
|
|
383
|
+
for (const [position, declaration] of rule.declarations.entries()) claim(declaration, rank(declaration.important, false, rule.layer, rule.specificity, rule.order, position));
|
|
384
|
+
}
|
|
385
|
+
for (const [position, declaration] of inlineDeclarations(element.props.style).entries()) claim(declaration, rank(declaration.important, true, 0, [
|
|
386
|
+
0,
|
|
387
|
+
0,
|
|
388
|
+
0
|
|
389
|
+
], 0, position));
|
|
390
|
+
for (const name of classListOf(element)) if (!styledClasses.has(name) && options.knownClasses?.has(name) !== true) unmatched.set(name, [...unmatched.get(name) ?? [], ...element.origins]);
|
|
391
|
+
const declared = {};
|
|
392
|
+
for (const [property, entry] of winners) if (property.startsWith("--")) declared[property] = entry.value;
|
|
393
|
+
const variables = Object.keys(declared).length === 0 ? inherited : {
|
|
394
|
+
...inherited,
|
|
395
|
+
...declared
|
|
396
|
+
};
|
|
397
|
+
const inheritedValue = (property, parent, initial, fallback = parent) => {
|
|
398
|
+
const value = winners.get(property)?.value;
|
|
399
|
+
if (value === void 0) return fallback;
|
|
400
|
+
const resolved = finalizeValue(value, variables);
|
|
401
|
+
return resolved === "inherit" || resolved === "unset" ? parent : resolved === "initial" ? initial : resolved;
|
|
402
|
+
};
|
|
403
|
+
const writing = {
|
|
404
|
+
direction: inheritedValue("direction", inheritedWriting.direction, "ltr", typeof element.props.dir === "string" ? element.props.dir : element.tag === "bdi" ? "auto" : inheritedWriting.direction),
|
|
405
|
+
writingMode: winners.has("all") ? "unknown" : inheritedValue("writing-mode", inheritedWriting.writingMode, "horizontal-tb")
|
|
406
|
+
};
|
|
407
|
+
const emitted = [...winners].filter(([property]) => !property.startsWith("--")).sort(([, left], [, right]) => compareRank(left.key, right.key)).map(([property, entry]) => [property, finalizeValue(entry.value, variables)]);
|
|
408
|
+
const physical = /* @__PURE__ */ new Map();
|
|
409
|
+
for (const [property, value] of emitted) for (const [name, lowered] of conditionalWriting ? [[property, value]] : physicalPadding(property, value, writing)) {
|
|
410
|
+
physical.delete(name);
|
|
411
|
+
physical.set(name, lowered);
|
|
412
|
+
}
|
|
413
|
+
return EmailNode.Element({
|
|
414
|
+
...element,
|
|
415
|
+
props: emitted.length === 0 ? element.props : {
|
|
416
|
+
...element.props,
|
|
417
|
+
style: Object.fromEntries(physical)
|
|
418
|
+
},
|
|
419
|
+
children: visitChildren(element.children, ancestry, variables, writing)
|
|
420
|
+
});
|
|
421
|
+
};
|
|
422
|
+
const tree = root._tag === "Element" ? applyTo(root, {
|
|
423
|
+
element: root,
|
|
424
|
+
parent: void 0,
|
|
425
|
+
previous: []
|
|
426
|
+
}, sheet.variables, horizontalWriting) : root._tag === "Fragment" ? EmailNode.Fragment({ children: visitChildren(root.children, void 0, sheet.variables, horizontalWriting) }) : root;
|
|
427
|
+
for (const [name, origins] of unmatched) diagnostics.push({
|
|
428
|
+
code: "unmatched-class",
|
|
429
|
+
severity: "warning",
|
|
430
|
+
message: `Class ${JSON.stringify(name)} produced no styles. If it is composed at run time, the compiler cannot discover it; list it in the template's declared classes or write the style inline.`,
|
|
431
|
+
origins: origins.slice(0, 1)
|
|
432
|
+
});
|
|
433
|
+
return {
|
|
434
|
+
tree,
|
|
435
|
+
headCss: renderHeadCss(retained, sheet.headAtRules, sheet.variables),
|
|
436
|
+
diagnostics
|
|
437
|
+
};
|
|
438
|
+
};
|
|
439
|
+
//#endregion
|
|
440
|
+
//#region src/email/render.ts
|
|
441
|
+
/** Classic Outlook lays a document out correctly only under a transitional doctype. */
|
|
442
|
+
const EMAIL_DOCTYPE = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
|
|
443
|
+
const settle = (diagnostics) => {
|
|
444
|
+
if (hasBlockingDiagnostic(diagnostics)) throw new EmailCompileError({ diagnostics });
|
|
445
|
+
return diagnostics;
|
|
446
|
+
};
|
|
447
|
+
/** Lower the derived tree to HTML and its plain-text alternative. */
|
|
448
|
+
const compileEmail = (node, options = {}) => {
|
|
449
|
+
const serialized = serializeEmailHtml(node, options);
|
|
450
|
+
const diagnostics = settle([...drainEmailDiagnostics(), ...serialized.diagnostics]);
|
|
451
|
+
return {
|
|
452
|
+
html: serialized.html,
|
|
453
|
+
text: deriveEmailText(node),
|
|
454
|
+
diagnostics,
|
|
455
|
+
positions: serialized.positions
|
|
456
|
+
};
|
|
457
|
+
};
|
|
458
|
+
/** The preview text already present in the tree, from `<Email preheader>`. */
|
|
459
|
+
const declaredPreheader = (node) => {
|
|
460
|
+
switch (node._tag) {
|
|
461
|
+
case "Text":
|
|
462
|
+
case "Raw": return;
|
|
463
|
+
case "Fragment": return node.children.reduce((found, child) => found ?? declaredPreheader(child), void 0);
|
|
464
|
+
case "Element": {
|
|
465
|
+
const declared = node.props[PREHEADER_ATTRIBUTE];
|
|
466
|
+
if (typeof declared === "string") return declared;
|
|
467
|
+
return node.children.reduce((found, child) => found ?? declaredPreheader(child), void 0);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
/** Put the hidden preview block first inside `<body>`, or first overall when there is no shell. */
|
|
472
|
+
const withPreheader = (node, text) => {
|
|
473
|
+
const insert = (current) => {
|
|
474
|
+
if (current._tag === "Fragment") {
|
|
475
|
+
for (const [index, child] of current.children.entries()) {
|
|
476
|
+
const replaced = insert(child);
|
|
477
|
+
if (replaced !== void 0) return EmailNode.Fragment({ children: current.children.with(index, replaced) });
|
|
478
|
+
}
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (current._tag !== "Element") return void 0;
|
|
482
|
+
if (current.tag === "body") return EmailNode.Element({
|
|
483
|
+
...current,
|
|
484
|
+
children: [preheaderNode(text), ...current.children]
|
|
485
|
+
});
|
|
486
|
+
for (const [index, child] of current.children.entries()) {
|
|
487
|
+
const replaced = insert(child);
|
|
488
|
+
if (replaced !== void 0) return EmailNode.Element({
|
|
489
|
+
...current,
|
|
490
|
+
children: current.children.with(index, replaced)
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
return insert(node) ?? EmailNode.Fragment({ children: [preheaderNode(text), node] });
|
|
495
|
+
};
|
|
496
|
+
/** Put the retained rules in a `<style>` at the end of `<head>`. */
|
|
497
|
+
const withHeadCss = (node, css) => {
|
|
498
|
+
const insert = (current) => {
|
|
499
|
+
if (current._tag === "Fragment") {
|
|
500
|
+
for (const [index, child] of current.children.entries()) {
|
|
501
|
+
const replaced = insert(child);
|
|
502
|
+
if (replaced !== void 0) return EmailNode.Fragment({ children: current.children.with(index, replaced) });
|
|
503
|
+
}
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (current._tag !== "Element") return void 0;
|
|
507
|
+
if (current.tag === "head") return EmailNode.Element({
|
|
508
|
+
...current,
|
|
509
|
+
children: [...current.children, EmailNode.Element({
|
|
510
|
+
tag: "style",
|
|
511
|
+
props: {},
|
|
512
|
+
children: [EmailNode.Text({ value: css })],
|
|
513
|
+
origins: current.origins,
|
|
514
|
+
authored: false
|
|
515
|
+
})]
|
|
516
|
+
});
|
|
517
|
+
for (const [index, child] of current.children.entries()) {
|
|
518
|
+
const replaced = insert(child);
|
|
519
|
+
if (replaced !== void 0) return EmailNode.Element({
|
|
520
|
+
...current,
|
|
521
|
+
children: current.children.with(index, replaced)
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
return insert(node);
|
|
526
|
+
};
|
|
527
|
+
/** Render one validated input through the template's only content function. Host isolation is required for untrusted source. */
|
|
528
|
+
const renderEmail = (template, data, options = {}) => renderEmailWith(snapshotStylesheets(), template, data, options);
|
|
529
|
+
/**
|
|
530
|
+
* A render bound to the sheets registered so far. A compiled project's wrapper
|
|
531
|
+
* calls this once its own stylesheet imports have run, so a later project
|
|
532
|
+
* loaded into the same process cannot restyle an entry that is rendered again.
|
|
533
|
+
*/
|
|
534
|
+
const bindStylesheets = (stylesheet = snapshotStylesheets()) => (template, data, options = {}) => renderEmailWith(stylesheet, template, data, options);
|
|
535
|
+
const renderEmailWith = (stylesheet, template, data, options) => {
|
|
536
|
+
if (!template.schema.validate(data)) throw new TypeError(`Invalid template input: ${JSON.stringify(template.schema.validate.errors)}`);
|
|
537
|
+
drainEmailDiagnostics();
|
|
538
|
+
const content = template.render(data);
|
|
539
|
+
const invalid = [];
|
|
540
|
+
const fail = (code, message) => invalid.push({
|
|
541
|
+
code,
|
|
542
|
+
severity: "error",
|
|
543
|
+
message,
|
|
544
|
+
origins: []
|
|
545
|
+
});
|
|
546
|
+
if (typeof content.subject !== "string" || /[\r\n\u0000]/.test(content.subject)) fail("invalid-subject", "Invalid email subject: it must be one line of text.");
|
|
547
|
+
if (content.preheader !== void 0 && typeof content.preheader !== "string") fail("invalid-preheader", "Invalid email preheader: it must be a string.");
|
|
548
|
+
if (content.text !== void 0 && typeof content.text !== "string") fail("invalid-text", "Invalid plain text: it must be a string.");
|
|
549
|
+
const declared = declaredPreheader(content.body);
|
|
550
|
+
if (content.preheader !== void 0 && declared !== void 0) fail("duplicate-preheader", "Preheader is set on both the template content and <Email preheader>; keep one.");
|
|
551
|
+
settle(invalid);
|
|
552
|
+
const base = content.preheader === void 0 ? content.body : withPreheader(content.body, content.preheader);
|
|
553
|
+
const styled = stylesheet === void 0 ? {
|
|
554
|
+
tree: base,
|
|
555
|
+
headCss: "",
|
|
556
|
+
diagnostics: []
|
|
557
|
+
} : applyStylesheet(base, stylesheet);
|
|
558
|
+
const style = [...styled.diagnostics];
|
|
559
|
+
let tree = styled.tree;
|
|
560
|
+
if (styled.headCss !== "") {
|
|
561
|
+
const placed = withHeadCss(tree, styled.headCss);
|
|
562
|
+
if (placed === void 0) style.push({
|
|
563
|
+
code: "missing-head",
|
|
564
|
+
severity: "error",
|
|
565
|
+
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.",
|
|
566
|
+
origins: []
|
|
567
|
+
});
|
|
568
|
+
else tree = placed;
|
|
569
|
+
}
|
|
570
|
+
settle(style);
|
|
571
|
+
const compiled = compileEmail(tree, options);
|
|
572
|
+
const prefix = compiled.html.startsWith("<html") ? EMAIL_DOCTYPE : "";
|
|
573
|
+
const html = `${prefix}${compiled.html}`;
|
|
574
|
+
const positions = prefix === "" ? compiled.positions : compiled.positions.map((position) => ({
|
|
575
|
+
...position,
|
|
576
|
+
start: position.start + prefix.length,
|
|
577
|
+
end: position.end + prefix.length
|
|
578
|
+
}));
|
|
579
|
+
return {
|
|
580
|
+
subject: content.subject,
|
|
581
|
+
preheader: content.preheader ?? declared,
|
|
582
|
+
html,
|
|
583
|
+
text: content.text ?? compiled.text,
|
|
584
|
+
tree,
|
|
585
|
+
diagnostics: [...style, ...compiled.diagnostics],
|
|
586
|
+
positions
|
|
587
|
+
};
|
|
588
|
+
};
|
|
589
|
+
//#endregion
|
|
590
|
+
export { applyStylesheet as a, downlevelMediaQuery as c, renderHeadCss as d, resolveVariables as f, renderEmail as i, finalizeValue as l, bindStylesheets as n, classListOf as o, compileEmail as r, matchesSelector as s, EMAIL_DOCTYPE as t, foldCalc as u };
|
|
591
|
+
|
|
592
|
+
//# sourceMappingURL=render-ykQhtMs_.js.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { E as SmlNode, m as ElementNode } from "./ast-63I-VLQx.js";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
//#region src/source-locations.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The source payload emitted by the JSX development transform. The transform
|
|
6
|
+
* may omit any field for synthetic calls; only a complete payload can identify
|
|
7
|
+
* a source origin safely.
|
|
8
|
+
*/
|
|
9
|
+
interface JsxSource {
|
|
10
|
+
readonly fileName?: string | undefined;
|
|
11
|
+
readonly lineNumber?: number | undefined;
|
|
12
|
+
readonly columnNumber?: number | undefined;
|
|
13
|
+
}
|
|
14
|
+
/** A complete, normalized source origin for a JSX element. */
|
|
15
|
+
interface JsxSourceLocation {
|
|
16
|
+
readonly fileName: string;
|
|
17
|
+
readonly lineNumber: number;
|
|
18
|
+
readonly columnNumber: number;
|
|
19
|
+
}
|
|
20
|
+
/** JSON-safe source location shape shared by preview and editor contracts. */
|
|
21
|
+
declare const JsxSourceLocation: Schema.Struct<{
|
|
22
|
+
readonly fileName: Schema.String;
|
|
23
|
+
readonly lineNumber: Schema.Int;
|
|
24
|
+
readonly columnNumber: Schema.Int;
|
|
25
|
+
}>;
|
|
26
|
+
/** Reasons a preview cannot safely expose an authored source map. */
|
|
27
|
+
declare const SourceLocationUnavailableReason: Schema.Literals<readonly ["no-source-metadata", "structure-mismatch", "duplicate-source-origin", "render-failed", "stale-preview"]>;
|
|
28
|
+
/**
|
|
29
|
+
* Runtime-only carrier for JSX source metadata. It is global so separately
|
|
30
|
+
* bundled `jsx-dev-runtime` and `render-template` entries still agree on the
|
|
31
|
+
* sidecar key, and it is a Symbol so it cannot enter SML, HTML, or JSON.
|
|
32
|
+
*/
|
|
33
|
+
declare const JSX_SOURCE_LOCATION: unique symbol;
|
|
34
|
+
/** Internal JSX prop used only by an editor preview source transform. */
|
|
35
|
+
declare const JSX_SOURCE_LOCATION_PROP: "__samva_source_location";
|
|
36
|
+
/**
|
|
37
|
+
* A source map is useful only when it is trustworthy. Production `jsx`/`jsxs`
|
|
38
|
+
* currently provide no source metadata, so that path reports a typed absence
|
|
39
|
+
* rather than guessing from output order.
|
|
40
|
+
*/
|
|
41
|
+
type SourceLocationUnavailableReason = typeof SourceLocationUnavailableReason.Type;
|
|
42
|
+
type UnboundTemplateSourceLocations = {
|
|
43
|
+
readonly kind: "available";
|
|
44
|
+
/** Parsed SML node id → the JSX origin that produced that element. */
|
|
45
|
+
readonly byNodeId: Readonly<Record<string, JsxSourceLocation>>;
|
|
46
|
+
} | {
|
|
47
|
+
readonly kind: "unavailable";
|
|
48
|
+
readonly reason: SourceLocationUnavailableReason;
|
|
49
|
+
};
|
|
50
|
+
/** Revision-fenced source map exposed by a mutable workspace preview. */
|
|
51
|
+
type TemplateSourceLocations = {
|
|
52
|
+
readonly kind: "available";
|
|
53
|
+
readonly revision: string;
|
|
54
|
+
/** Parsed SML node id → the JSX origin that produced that element. */
|
|
55
|
+
readonly byNodeId: Readonly<Record<string, JsxSourceLocation>>;
|
|
56
|
+
} | {
|
|
57
|
+
readonly kind: "unavailable";
|
|
58
|
+
readonly reason: SourceLocationUnavailableReason;
|
|
59
|
+
};
|
|
60
|
+
/** JSON-safe schema for a parsed-node-id → JSX-origin map. */
|
|
61
|
+
declare const TemplateSourceLocationsSchema: Schema.Union<readonly [Schema.Struct<{
|
|
62
|
+
readonly kind: Schema.Literal<"available">;
|
|
63
|
+
readonly revision: Schema.String;
|
|
64
|
+
readonly byNodeId: Schema.$Record<Schema.String, Schema.Struct<{
|
|
65
|
+
readonly fileName: Schema.String;
|
|
66
|
+
readonly lineNumber: Schema.Int;
|
|
67
|
+
readonly columnNumber: Schema.Int;
|
|
68
|
+
}>>;
|
|
69
|
+
}>, Schema.Struct<{
|
|
70
|
+
readonly kind: Schema.Literal<"unavailable">;
|
|
71
|
+
readonly reason: Schema.Literals<readonly ["no-source-metadata", "structure-mismatch", "duplicate-source-origin", "render-failed", "stale-preview"]>;
|
|
72
|
+
}>]>;
|
|
73
|
+
/** Normalize the optional payload accepted by `jsxDEV`. */
|
|
74
|
+
declare const completeJsxSourceLocation: (source: JsxSource | null | undefined) => JsxSourceLocation | undefined;
|
|
75
|
+
/** Attach a source origin without changing the serialized draft shape. */
|
|
76
|
+
declare const attachJsxSourceLocation: (node: ElementNode, source: JsxSourceLocation) => void;
|
|
77
|
+
/** Read the ephemeral origin, if this draft element has one. */
|
|
78
|
+
declare const jsxSourceLocationOf: (node: SmlNode) => JsxSourceLocation | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Pair a draft tree with its parsed SML tree by element preorder. Text nodes
|
|
81
|
+
* are intentionally ignored: the SML parser normalizes inline whitespace, so
|
|
82
|
+
* only the element structure is stable enough to be a source-map contract.
|
|
83
|
+
*/
|
|
84
|
+
declare const mapJsxSourceLocations: (draft: ElementNode, parsed: ElementNode) => UnboundTemplateSourceLocations;
|
|
85
|
+
/** Compare source-map statuses for the emission determinism guard. */
|
|
86
|
+
declare const sameTemplateSourceLocations: (left: UnboundTemplateSourceLocations, right: UnboundTemplateSourceLocations) => boolean;
|
|
87
|
+
//#endregion
|
|
88
|
+
export { SourceLocationUnavailableReason as a, UnboundTemplateSourceLocations as c, jsxSourceLocationOf as d, mapJsxSourceLocations as f, JsxSourceLocation as i, attachJsxSourceLocation as l, JSX_SOURCE_LOCATION_PROP as n, TemplateSourceLocations as o, sameTemplateSourceLocations as p, JsxSource as r, TemplateSourceLocationsSchema as s, JSX_SOURCE_LOCATION as t, completeJsxSourceLocation as u };
|
|
89
|
+
//# sourceMappingURL=source-locations-BCJQnIfU.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as SourceLocationUnavailableReason, c as UnboundTemplateSourceLocations, d as jsxSourceLocationOf, f as mapJsxSourceLocations, i as JsxSourceLocation, l as attachJsxSourceLocation, n as JSX_SOURCE_LOCATION_PROP, o as TemplateSourceLocations, p as sameTemplateSourceLocations, r as JsxSource, s as TemplateSourceLocationsSchema, t as JSX_SOURCE_LOCATION, u as completeJsxSourceLocation } from "./source-locations-BCJQnIfU.js";
|
|
2
|
+
export { JSX_SOURCE_LOCATION, JSX_SOURCE_LOCATION_PROP, JsxSource, JsxSourceLocation, SourceLocationUnavailableReason, TemplateSourceLocations, TemplateSourceLocationsSchema, UnboundTemplateSourceLocations, attachJsxSourceLocation, completeJsxSourceLocation, jsxSourceLocationOf, mapJsxSourceLocations, sameTemplateSourceLocations };
|