@samva/markup 0.7.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 +104 -37
- package/README.md +188 -52
- package/dist/assets-C5duwTya.d.ts +40 -0
- package/dist/brand-B-0bN_Ir.d.ts +88 -0
- package/dist/{render-aaJBnsXK.js → cascade-t6kxlgEI.js} +130 -160
- 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 +19 -249
- package/dist/compiler.js +10 -1408
- package/dist/{css-COcFOT1y.d.ts → css-BVQKICKC.d.ts} +30 -4
- 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 -0
- package/dist/email/assets.js +63 -0
- package/dist/email/brand-footer.d.ts +34 -0
- package/dist/email/brand-footer.js +63 -0
- package/dist/email/brand.d.ts +2 -0
- package/dist/email/brand.js +148 -0
- 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 -42
- package/dist/email/html.js +56 -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 +10 -13
- package/dist/email/render.js +163 -6
- package/dist/email/text.d.ts +1 -1
- package/dist/fmt.d.ts +32 -0
- package/dist/fmt.js +174 -0
- package/dist/html-BJepOwZ4.d.ts +56 -0
- 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-hFqcPSar.js +587 -0
- package/dist/theme-css.d.ts +57 -16
- package/dist/theme-css.js +2 -509
- package/dist/theme-imports-lvBw3AD1.js +109 -0
- package/dist/transform-Ct2OMkFN.d.ts +153 -0
- package/dist/unsubscribe-link-CoesnQDU.js +26 -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 +56 -154
- package/samva-brand.d.ts +14 -0
- 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-60eaYC7b.d.ts +0 -356
- package/dist/checks-DBweSIPN.js +0 -58954
- package/dist/checks.d.ts +0 -33
- package/dist/checks.js +0 -2
- package/dist/classes.d.ts +0 -27
- 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-BjYMqOoY.d.ts +0 -106
- package/dist/diagnostics-OcQKQYSY.d.ts +0 -49
- package/dist/email/selection.d.ts +0 -91
- 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 -45
- package/dist/emit.d.ts +0 -51
- package/dist/emit.js +0 -151
- package/dist/footer.d.ts +0 -66
- package/dist/footer.js +0 -93
- 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-2aiiYO7m.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/presets/category-mapping.d.ts +0 -13
- package/dist/presets/category-mapping.js +0 -49
- package/dist/presets/corpus.d.ts +0 -2
- package/dist/presets/corpus.js +0 -194
- package/dist/presets/public-gallery.d.ts +0 -266
- package/dist/presets/public-gallery.js +0 -916
- package/dist/presets/public-handoff.d.ts +0 -164
- package/dist/presets/public-handoff.js +0 -361
- package/dist/presets/public-preview-artifacts.d.ts +0 -43
- package/dist/presets/public-preview-artifacts.js +0 -104
- package/dist/presets/public-preview.d.ts +0 -61
- package/dist/presets/public-preview.js +0 -83
- package/dist/presets/showcase.d.ts +0 -2
- package/dist/presets/showcase.js +0 -627
- package/dist/presets/sources.d.ts +0 -38
- package/dist/presets/sources.js +0 -6083
- package/dist/presets.d.ts +0 -2
- package/dist/presets.js +0 -881
- package/dist/printer.d.ts +0 -6
- package/dist/printer.js +0 -122
- package/dist/registry.d.ts +0 -42
- package/dist/registry.js +0 -646
- package/dist/render-template.d.ts +0 -45
- package/dist/render-template.js +0 -76
- package/dist/showcase-DGZAWn4Z.d.ts +0 -456
- package/dist/sms-segments-y4FpPilJ.d.ts +0 -13
- package/dist/source-locations-DrCM82Ym.d.ts +0 -67
- package/dist/template-DWftqh4x.d.ts +0 -60
- package/dist/theme-6ApjjiBo.d.ts +0 -116
- package/dist/theme.d.ts +0 -2
- package/dist/theme.js +0 -118
- package/dist/tokens.d.ts +0 -6
- package/dist/tokens.js +0 -417
- package/dist/tsx-source-instrumentation.d.ts +0 -30
- package/dist/tsx-source-instrumentation.js +0 -115
- package/dist/tsx-tracer.d.ts +0 -112
- package/dist/tsx-tracer.js +0 -985
- package/dist/variables-J_L3qxRa.d.ts +0 -77
- package/dist/variables.d.ts +0 -2
- package/dist/variables.js +0 -141
- package/dist/version-BITr58kk.js +0 -96
- package/generated/sml-agent-contract.json +0 -709
- package/generated/sml-email-agent-contract.json +0 -615
- package/generated/sml-email-language-reference.md +0 -94
- package/generated/sml-language-reference.md +0 -195
package/dist/sms-segments.d.ts
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/sms-segments.d.ts
|
|
2
|
+
/** The encoding a message needs: GSM-7 when every character fits, UCS-2 otherwise. */
|
|
3
|
+
type SmsEncoding = "gsm7" | "ucs2";
|
|
4
|
+
interface SmsSegmentInfo {
|
|
5
|
+
readonly encoding: SmsEncoding;
|
|
6
|
+
readonly characterCount: number;
|
|
7
|
+
readonly segmentCount: number;
|
|
8
|
+
}
|
|
9
|
+
declare const smsSegmentInfo: (text: string) => SmsSegmentInfo;
|
|
10
|
+
declare const hasSmsOptOut: (text: string) => boolean;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { SmsEncoding, SmsSegmentInfo, hasSmsOptOut, smsSegmentInfo };
|
|
13
|
+
//# sourceMappingURL=sms-segments.d.ts.map
|
package/dist/sms.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { t as SmsCategory } from "./channel-specs-C2feJwuP.js";
|
|
2
|
+
import { f as EmailChild, m as EmailNode } from "./elements-cqldpaJt.js";
|
|
3
|
+
//#region src/sms.d.ts
|
|
4
|
+
interface SmsProps {
|
|
5
|
+
readonly category?: SmsCategory | undefined;
|
|
6
|
+
readonly children?: EmailChild;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The root of an SMS body: plain text with bindings, conditionals and formatters. The compiler
|
|
10
|
+
* reads it from source; executed, it is a fragment of its children so a template file that also
|
|
11
|
+
* declares an email body still evaluates.
|
|
12
|
+
*/
|
|
13
|
+
declare const Sms: (props: SmsProps) => EmailNode;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { Sms, type SmsCategory, SmsProps };
|
|
16
|
+
//# sourceMappingURL=sms.d.ts.map
|
package/dist/sms.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Fragment, jsx } from "./email/jsx-runtime.js";
|
|
2
|
+
//#region src/sms.ts
|
|
3
|
+
/**
|
|
4
|
+
* The root of an SMS body: plain text with bindings, conditionals and formatters. The compiler
|
|
5
|
+
* reads it from source; executed, it is a fragment of its children so a template file that also
|
|
6
|
+
* declares an email body still evaluates.
|
|
7
|
+
*/
|
|
8
|
+
const Sms = (props) => jsx(Fragment, { children: props.children });
|
|
9
|
+
//#endregion
|
|
10
|
+
export { Sms };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=sms.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region src/
|
|
1
|
+
import { r as JsxSourceLocation } from "./source-locations-C8wCsiAy.js";
|
|
2
|
+
//#region src/source-edit.d.ts
|
|
3
3
|
/** One exact source replacement; before text guards against concurrent changes. */
|
|
4
4
|
interface SourceReplacement {
|
|
5
5
|
readonly start: number;
|
|
@@ -33,6 +33,13 @@ interface SourceElement {
|
|
|
33
33
|
readonly hasSpread: boolean;
|
|
34
34
|
readonly properties: readonly SourceProperty[];
|
|
35
35
|
readonly structural: boolean;
|
|
36
|
+
/** The JSX element sibling directly before / after this one, when both share a JSX parent. */
|
|
37
|
+
readonly previous: SourceRange | null;
|
|
38
|
+
readonly next: SourceRange | null;
|
|
39
|
+
}
|
|
40
|
+
interface SourceRange {
|
|
41
|
+
readonly start: number;
|
|
42
|
+
readonly end: number;
|
|
36
43
|
}
|
|
37
44
|
/** Resolve a renderer origin against the unchanged authored entry, never against HTML offsets. */
|
|
38
45
|
declare const inspectSourceElement: (source: string, file: string, origin: JsxSourceLocation) => SourceElement | null;
|
|
@@ -40,11 +47,39 @@ declare const inspectSourceElement: (source: string, file: string, origin: JsxSo
|
|
|
40
47
|
declare const literalReplacement: (source: string, field: SourceProperty, value: string) => SourceReplacement | null;
|
|
41
48
|
/** Explicit expression changes are proposals: callers show before/after and require Apply. */
|
|
42
49
|
declare const expressionReplacement: (source: string, field: SourceProperty, expression: string) => SourceReplacement;
|
|
50
|
+
/**
|
|
51
|
+
* Where an edited file sits in its template project. Every edit of a template is checked against
|
|
52
|
+
* the static profile: one that would leave it is refused, so a visual edit can never produce a
|
|
53
|
+
* template the compiler rejects.
|
|
54
|
+
*/
|
|
55
|
+
interface ProfileGuard {
|
|
56
|
+
/** The template entry the profile check reads. */
|
|
57
|
+
readonly entry: string;
|
|
58
|
+
/** The file the edit changes; the entry when omitted. A partial names itself here. */
|
|
59
|
+
readonly file?: string | undefined;
|
|
60
|
+
/** The project's other files, when the edited file is not the entry. */
|
|
61
|
+
readonly files?: Readonly<Record<string, string>> | undefined;
|
|
62
|
+
}
|
|
63
|
+
interface ApplyOptions {
|
|
64
|
+
readonly profile?: ProfileGuard | undefined;
|
|
65
|
+
}
|
|
43
66
|
/** Apply exact, nonoverlapping edits and refuse syntax damage without changing the original. */
|
|
44
|
-
declare const applySourceReplacements: (source: string, edits: readonly SourceReplacement[]) => SourceEditResult;
|
|
67
|
+
declare const applySourceReplacements: (source: string, edits: readonly SourceReplacement[], options?: ApplyOptions) => SourceEditResult;
|
|
68
|
+
type SourceProposal = {
|
|
69
|
+
readonly ok: true;
|
|
70
|
+
readonly edits: readonly SourceReplacement[];
|
|
71
|
+
} | {
|
|
72
|
+
readonly ok: false;
|
|
73
|
+
readonly reason: string;
|
|
74
|
+
};
|
|
45
75
|
/** Structural edits name a whole authored block; loop iterations are never source nodes. */
|
|
46
76
|
declare const structuralReplacements: (source: string, element: SourceElement, operation: {
|
|
47
77
|
readonly kind: "delete";
|
|
78
|
+
} | {
|
|
79
|
+
readonly kind: "duplicate";
|
|
80
|
+
} | {
|
|
81
|
+
readonly kind: "reorder";
|
|
82
|
+
readonly direction: "before" | "after";
|
|
48
83
|
} | {
|
|
49
84
|
readonly kind: "insert";
|
|
50
85
|
readonly tsx: string;
|
|
@@ -60,8 +95,22 @@ interface SourceFixture {
|
|
|
60
95
|
}
|
|
61
96
|
/** Declared fixture values are separate source targets from body bindings and literals. */
|
|
62
97
|
declare const inspectSourceFixtures: (source: string) => readonly SourceFixture[];
|
|
63
|
-
|
|
64
|
-
|
|
98
|
+
type ClassNameOperation = {
|
|
99
|
+
readonly kind: "set";
|
|
100
|
+
readonly value: string;
|
|
101
|
+
} | {
|
|
102
|
+
readonly kind: "add";
|
|
103
|
+
readonly tokens: string;
|
|
104
|
+
} | {
|
|
105
|
+
readonly kind: "remove";
|
|
106
|
+
readonly tokens: string;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Edit an element's class list where it is written. A literal `className` is replaced, extended or
|
|
110
|
+
* trimmed in place; a missing one is added; one that is a condition or any other expression is
|
|
111
|
+
* refused, because rewriting it would discard the choice the author encoded.
|
|
112
|
+
*/
|
|
113
|
+
declare const classNameEdit: (source: string, element: SourceElement, operation: ClassNameOperation) => SourceProposal;
|
|
65
114
|
//#endregion
|
|
66
|
-
export { SourceEditResult, SourceElement, SourceFixture, SourceProperty,
|
|
115
|
+
export { ApplyOptions, ClassNameOperation, ProfileGuard, SourceEditResult, SourceElement, SourceFixture, SourceProperty, SourceProposal, SourceRange, SourceReplacement, applySourceReplacements, classNameEdit, expressionReplacement, inspectSourceElement, inspectSourceFixtures, literalReplacement, structuralReplacements };
|
|
67
116
|
//# sourceMappingURL=source-edit.d.ts.map
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { n as isObject } from "./guards-eV1qLbf2.js";
|
|
2
|
+
import { buildLineMap } from "./diagnostics.js";
|
|
3
|
+
import { n as introducedProfileErrors, t as checkStaticProfile } from "./profile-BH-OtdDA.js";
|
|
4
|
+
import { parse } from "@babel/parser";
|
|
5
|
+
//#region src/source-edit.ts
|
|
6
|
+
const node = (value) => isObject(value) && "type" in value && typeof value.type === "string" && "start" in value && typeof value.start === "number" && "end" in value && typeof value.end === "number";
|
|
7
|
+
const children = (value) => Array.isArray(value) ? value.filter(node) : [];
|
|
8
|
+
const walk = (value, visit, parent = null) => {
|
|
9
|
+
if (Array.isArray(value)) {
|
|
10
|
+
for (const item of value) walk(item, visit, parent);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (!node(value)) return;
|
|
14
|
+
visit(value, parent);
|
|
15
|
+
for (const [key, child] of Object.entries(value)) if (key !== "loc" && key !== "extra" && key !== "comments") walk(child, visit, value);
|
|
16
|
+
};
|
|
17
|
+
const parsed = (source) => {
|
|
18
|
+
try {
|
|
19
|
+
const result = parse(source, {
|
|
20
|
+
sourceType: "module",
|
|
21
|
+
plugins: ["typescript", "jsx"]
|
|
22
|
+
});
|
|
23
|
+
return node(result) ? result : null;
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const binding = (value) => value.type === "Identifier" || value.type === "MemberExpression" && value.computed === false && node(value.object) && binding(value.object);
|
|
29
|
+
/** JSX trims each line of text and joins the non-empty lines with one space. */
|
|
30
|
+
const collapseJsxText = (value) => value.split(/\r\n|\n|\r|\u2028|\u2029/).map((line) => line.trim()).filter((line) => line !== "").join(" ");
|
|
31
|
+
const property = (name, value, source, syntax) => {
|
|
32
|
+
const expression = value.type === "JSXExpressionContainer" && node(value.expression) ? value.expression : value;
|
|
33
|
+
const literal = expression.type === "StringLiteral" || expression.type === "NumericLiteral" || expression.type === "BooleanLiteral" || expression.type === "JSXText";
|
|
34
|
+
const raw = source.slice(expression.start, expression.end);
|
|
35
|
+
const inset = expression.type === "JSXText" ? {
|
|
36
|
+
start: expression.start + (raw.length - raw.trimStart().length),
|
|
37
|
+
end: expression.end - (raw.length - raw.trimEnd().length)
|
|
38
|
+
} : {
|
|
39
|
+
start: value.start,
|
|
40
|
+
end: value.end
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
name,
|
|
44
|
+
literalType: expression.type === "NumericLiteral" ? "number" : expression.type === "BooleanLiteral" ? "boolean" : "string",
|
|
45
|
+
kind: literal ? "literal" : binding(expression) ? "binding" : "computed",
|
|
46
|
+
value: literal && expression.type === "JSXText" && typeof expression.value === "string" ? collapseJsxText(expression.value) : literal && (typeof expression.value === "string" || typeof expression.value === "number" || typeof expression.value === "boolean") ? String(expression.value) : source.slice(expression.start, expression.end),
|
|
47
|
+
start: inset.start,
|
|
48
|
+
end: inset.end,
|
|
49
|
+
syntax
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
/** The JSX elements directly before and after `element` in its parent's child list. */
|
|
53
|
+
const siblingsOf = (element, parent, source) => {
|
|
54
|
+
if (parent?.type !== "JSXElement" && parent?.type !== "JSXFragment") return {
|
|
55
|
+
previous: null,
|
|
56
|
+
next: null
|
|
57
|
+
};
|
|
58
|
+
const list = children(parent.children).filter((child) => child.type !== "JSXText" || source.slice(child.start, child.end).trim() !== "");
|
|
59
|
+
const index = list.findIndex((child) => child.start === element.start);
|
|
60
|
+
const range = (child) => child?.type === "JSXElement" ? {
|
|
61
|
+
start: child.start,
|
|
62
|
+
end: child.end
|
|
63
|
+
} : null;
|
|
64
|
+
return {
|
|
65
|
+
previous: range(list[index - 1]),
|
|
66
|
+
next: range(list[index + 1])
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
/** Resolve a renderer origin against the unchanged authored entry, never against HTML offsets. */
|
|
70
|
+
const inspectSourceElement = (source, file, origin) => {
|
|
71
|
+
if (file !== origin.fileName) return null;
|
|
72
|
+
const tree = parsed(source);
|
|
73
|
+
if (tree === null) return null;
|
|
74
|
+
const lines = buildLineMap(source);
|
|
75
|
+
const lineStart = lines[origin.lineNumber - 1];
|
|
76
|
+
if (lineStart === void 0 || !Number.isInteger(origin.columnNumber) || origin.columnNumber < 1) return null;
|
|
77
|
+
const offset = lineStart + origin.columnNumber - 1;
|
|
78
|
+
if (offset >= (lines[origin.lineNumber] ?? source.length)) return null;
|
|
79
|
+
let found = null;
|
|
80
|
+
walk(tree, (element, parent) => {
|
|
81
|
+
if (element.type !== "JSXElement" || element.start !== offset || !node(element.openingElement)) return;
|
|
82
|
+
const opening = element.openingElement;
|
|
83
|
+
const properties = [];
|
|
84
|
+
for (const attribute of children(opening.attributes)) if (attribute.type === "JSXAttribute" && node(attribute.name) && typeof attribute.name.name === "string" && node(attribute.value)) {
|
|
85
|
+
const value = attribute.value;
|
|
86
|
+
const expression = value.type === "JSXExpressionContainer" && node(value.expression) ? value.expression : null;
|
|
87
|
+
if (attribute.name.name === "style" && expression?.type === "ObjectExpression" && !children(expression.properties).some((member) => member.type === "SpreadElement")) for (const member of children(expression.properties)) {
|
|
88
|
+
if (member.type !== "ObjectProperty" || member.computed === true || !node(member.key) || !node(member.value)) continue;
|
|
89
|
+
const key = member.key.type === "Identifier" ? member.key.name : member.key.value;
|
|
90
|
+
if (typeof key === "string") properties.push(property(`style.${key}`, member.value, source, "value"));
|
|
91
|
+
}
|
|
92
|
+
else properties.push(property(attribute.name.name, value, source, "attribute"));
|
|
93
|
+
}
|
|
94
|
+
const meaningful = children(element.children).filter((child) => child.type !== "JSXText" || source.slice(child.start, child.end).trim() !== "");
|
|
95
|
+
if (meaningful.length === 1 && meaningful[0] !== void 0 && meaningful[0].type !== "JSXElement" && meaningful[0].type !== "JSXFragment") properties.unshift(property("children", meaningful[0], source, "child"));
|
|
96
|
+
else if (meaningful.length > 1) {
|
|
97
|
+
const texts = meaningful.flatMap((child, index) => child.type === "JSXText" ? [property(`text.${index}`, child, source, "child")] : []);
|
|
98
|
+
properties.unshift(...texts);
|
|
99
|
+
}
|
|
100
|
+
found = {
|
|
101
|
+
start: element.start,
|
|
102
|
+
end: element.end,
|
|
103
|
+
contentStart: opening.selfClosing === true ? null : opening.end,
|
|
104
|
+
contentEnd: node(element.closingElement) ? element.closingElement.start : null,
|
|
105
|
+
tag: node(opening.name) ? source.slice(opening.name.start, opening.name.end) : "element",
|
|
106
|
+
properties,
|
|
107
|
+
attributeInsertion: (() => {
|
|
108
|
+
const last = children(opening.attributes).at(-1);
|
|
109
|
+
if (last !== void 0) return last.end;
|
|
110
|
+
return node(opening.name) ? opening.name.end : opening.end - 1;
|
|
111
|
+
})(),
|
|
112
|
+
hasSpread: children(opening.attributes).some((attribute) => attribute.type === "JSXSpreadAttribute"),
|
|
113
|
+
structural: parent?.type === "JSXElement" || parent?.type === "JSXFragment",
|
|
114
|
+
...siblingsOf(element, parent, source)
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
return found;
|
|
118
|
+
};
|
|
119
|
+
const PLAIN_JSX_TEXT = /^[^\s{}<>&](?:[^{}<>&\r\n\u2028\u2029]*[^\s{}<>&])?$/;
|
|
120
|
+
/** Literal controls cannot overwrite a binding or computed expression. */
|
|
121
|
+
const literalReplacement = (source, field, value) => {
|
|
122
|
+
if (field.kind !== "literal") return null;
|
|
123
|
+
if (field.literalType === "number" && (value.trim() === "" || !Number.isFinite(Number(value)))) return null;
|
|
124
|
+
if (field.literalType === "boolean" && value !== "true" && value !== "false") return null;
|
|
125
|
+
const literal = field.literalType === "string" ? JSON.stringify(value) : field.literalType === "number" ? String(Number(value)) : value;
|
|
126
|
+
const before = source.slice(field.start, field.end);
|
|
127
|
+
const plainText = field.syntax === "child" && !before.startsWith("{") && PLAIN_JSX_TEXT.test(value);
|
|
128
|
+
return {
|
|
129
|
+
start: field.start,
|
|
130
|
+
end: field.end,
|
|
131
|
+
before,
|
|
132
|
+
after: plainText ? value : field.syntax === "child" || field.syntax === "attribute" && field.literalType !== "string" ? `{${literal}}` : literal
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
/** Explicit expression changes are proposals: callers show before/after and require Apply. */
|
|
136
|
+
const expressionReplacement = (source, field, expression) => ({
|
|
137
|
+
start: field.start,
|
|
138
|
+
end: field.end,
|
|
139
|
+
before: source.slice(field.start, field.end),
|
|
140
|
+
after: field.syntax === "value" ? expression : `{${expression}}`
|
|
141
|
+
});
|
|
142
|
+
const profileRefusal = (source, result, guard) => {
|
|
143
|
+
const file = guard.file ?? guard.entry;
|
|
144
|
+
const project = (content) => ({
|
|
145
|
+
...guard.files,
|
|
146
|
+
[file]: content
|
|
147
|
+
});
|
|
148
|
+
const introduced = introducedProfileErrors(checkStaticProfile(project(source), guard.entry), checkStaticProfile(project(result), guard.entry));
|
|
149
|
+
const first = introduced[0];
|
|
150
|
+
if (first === void 0) return null;
|
|
151
|
+
const more = introduced.length > 1 ? ` (and ${introduced.length - 1} more)` : "";
|
|
152
|
+
return `This change leaves the static profile: ${first.message}${first.fix === void 0 ? "" : ` ${first.fix}`}${more}`;
|
|
153
|
+
};
|
|
154
|
+
/** Apply exact, nonoverlapping edits and refuse syntax damage without changing the original. */
|
|
155
|
+
const applySourceReplacements = (source, edits, options = {}) => {
|
|
156
|
+
const sorted = [...edits].sort((a, b) => b.start - a.start);
|
|
157
|
+
let boundary = source.length;
|
|
158
|
+
let result = source;
|
|
159
|
+
for (const edit of sorted) {
|
|
160
|
+
if (edit.start < 0 || edit.end < edit.start || edit.end > boundary || source.slice(edit.start, edit.end) !== edit.before) return {
|
|
161
|
+
ok: false,
|
|
162
|
+
reason: "Source changed at this target. Select it again before applying the edit."
|
|
163
|
+
};
|
|
164
|
+
result = result.slice(0, edit.start) + edit.after + result.slice(edit.end);
|
|
165
|
+
boundary = edit.start;
|
|
166
|
+
}
|
|
167
|
+
if (parsed(result) === null) return {
|
|
168
|
+
ok: false,
|
|
169
|
+
reason: "This change is not valid TSX. Review it in Source."
|
|
170
|
+
};
|
|
171
|
+
if (options.profile !== void 0 && result !== source) {
|
|
172
|
+
const refusal = profileRefusal(source, result, options.profile);
|
|
173
|
+
if (refusal !== null) return {
|
|
174
|
+
ok: false,
|
|
175
|
+
reason: refusal
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
ok: true,
|
|
180
|
+
source: result
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
const indentation = (source, offset) => {
|
|
184
|
+
const lineStart = Math.max(source.lastIndexOf("\n", offset - 1), source.lastIndexOf("\r", offset - 1));
|
|
185
|
+
const lead = source.slice(lineStart + 1, offset);
|
|
186
|
+
return /^[ \t]*$/.test(lead) ? lead : null;
|
|
187
|
+
};
|
|
188
|
+
/** The whole lines an element alone occupies, so removing it leaves no blank line behind. */
|
|
189
|
+
const ownLines = (source, element) => {
|
|
190
|
+
if (indentation(source, element.start) === null) return element;
|
|
191
|
+
const trailing = /^[ \t]*(\r\n|\n|\r)/.exec(source.slice(element.end));
|
|
192
|
+
if (trailing === null) return element;
|
|
193
|
+
return {
|
|
194
|
+
start: element.start - (indentation(source, element.start) ?? "").length,
|
|
195
|
+
end: element.end + trailing[0].length
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
/** Structural edits name a whole authored block; loop iterations are never source nodes. */
|
|
199
|
+
const structuralReplacements = (source, element, operation) => {
|
|
200
|
+
if (operation.kind === "insert") {
|
|
201
|
+
if (element.contentEnd === null) return null;
|
|
202
|
+
return [{
|
|
203
|
+
start: element.contentEnd,
|
|
204
|
+
end: element.contentEnd,
|
|
205
|
+
before: "",
|
|
206
|
+
after: operation.tsx
|
|
207
|
+
}];
|
|
208
|
+
}
|
|
209
|
+
if (!element.structural) return null;
|
|
210
|
+
const text = source.slice(element.start, element.end);
|
|
211
|
+
if (operation.kind === "duplicate") {
|
|
212
|
+
const indent = indentation(source, element.start);
|
|
213
|
+
return [{
|
|
214
|
+
start: element.end,
|
|
215
|
+
end: element.end,
|
|
216
|
+
before: "",
|
|
217
|
+
after: indent === null ? text : `\n${indent}${text}`
|
|
218
|
+
}];
|
|
219
|
+
}
|
|
220
|
+
if (operation.kind === "reorder") {
|
|
221
|
+
const neighbour = operation.direction === "before" ? element.previous : element.next;
|
|
222
|
+
if (neighbour === null) return null;
|
|
223
|
+
return [{
|
|
224
|
+
start: neighbour.start,
|
|
225
|
+
end: neighbour.end,
|
|
226
|
+
before: source.slice(neighbour.start, neighbour.end),
|
|
227
|
+
after: text
|
|
228
|
+
}, {
|
|
229
|
+
start: element.start,
|
|
230
|
+
end: element.end,
|
|
231
|
+
before: text,
|
|
232
|
+
after: source.slice(neighbour.start, neighbour.end)
|
|
233
|
+
}];
|
|
234
|
+
}
|
|
235
|
+
const removal = ownLines(source, element);
|
|
236
|
+
const removed = {
|
|
237
|
+
start: removal.start,
|
|
238
|
+
end: removal.end,
|
|
239
|
+
before: source.slice(removal.start, removal.end),
|
|
240
|
+
after: ""
|
|
241
|
+
};
|
|
242
|
+
if (operation.kind === "delete") return [removed];
|
|
243
|
+
const destination = operation.destination.contentEnd;
|
|
244
|
+
if (destination === null || destination >= element.start && destination <= element.end) return null;
|
|
245
|
+
return [removed, {
|
|
246
|
+
start: destination,
|
|
247
|
+
end: destination,
|
|
248
|
+
before: "",
|
|
249
|
+
after: text
|
|
250
|
+
}];
|
|
251
|
+
};
|
|
252
|
+
/** The object literal a top-level `const name = { ... }` holds. */
|
|
253
|
+
const topLevelObject = (tree, name) => {
|
|
254
|
+
const program = tree.program;
|
|
255
|
+
if (!node(program)) return null;
|
|
256
|
+
for (const item of children(program.body)) {
|
|
257
|
+
const declaration = item.type === "ExportNamedDeclaration" && node(item.declaration) ? item.declaration : item;
|
|
258
|
+
if (declaration.type !== "VariableDeclaration") continue;
|
|
259
|
+
for (const declarator of children(declaration.declarations)) if (node(declarator.id) && declarator.id.name === name && node(declarator.init) && declarator.init.type === "ObjectExpression") return declarator.init;
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
};
|
|
263
|
+
/** Declared fixture values are separate source targets from body bindings and literals. */
|
|
264
|
+
const inspectSourceFixtures = (source) => {
|
|
265
|
+
const tree = parsed(source);
|
|
266
|
+
if (tree === null) return [];
|
|
267
|
+
const found = [];
|
|
268
|
+
walk(tree, (call) => {
|
|
269
|
+
if (call.type !== "CallExpression" || !node(call.callee) || call.callee.type !== "Identifier" || call.callee.name !== "defineTemplate") return;
|
|
270
|
+
const definition = children(call.arguments)[0];
|
|
271
|
+
if (definition?.type !== "ObjectExpression") return;
|
|
272
|
+
const fixtures = children(definition.properties).find((field) => field.type === "ObjectProperty" && node(field.key) && field.key.name === "fixtures" && field.computed !== true);
|
|
273
|
+
if (fixtures === void 0 || !node(fixtures.value) || fixtures.value.type !== "ObjectExpression") return;
|
|
274
|
+
for (const field of children(fixtures.value.properties)) {
|
|
275
|
+
if (field.type !== "ObjectProperty" || field.computed === true || !node(field.key) || !node(field.value)) continue;
|
|
276
|
+
const name = field.key.type === "Identifier" ? field.key.name : field.key.value;
|
|
277
|
+
const value = field.value.type === "Identifier" && typeof field.value.name === "string" ? topLevelObject(tree, field.value.name) ?? field.value : field.value;
|
|
278
|
+
if (typeof name === "string") found.push({
|
|
279
|
+
name,
|
|
280
|
+
start: value.start,
|
|
281
|
+
end: value.end,
|
|
282
|
+
source: source.slice(value.start, value.end)
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
return found;
|
|
287
|
+
};
|
|
288
|
+
const tokens = (value) => value.split(/\s+/).filter((item) => item !== "");
|
|
289
|
+
/**
|
|
290
|
+
* Edit an element's class list where it is written. A literal `className` is replaced, extended or
|
|
291
|
+
* trimmed in place; a missing one is added; one that is a condition or any other expression is
|
|
292
|
+
* refused, because rewriting it would discard the choice the author encoded.
|
|
293
|
+
*/
|
|
294
|
+
const classNameEdit = (source, element, operation) => {
|
|
295
|
+
const field = element.properties.find((item) => item.name === "className");
|
|
296
|
+
const next = (current) => {
|
|
297
|
+
if (operation.kind === "set") return tokens(operation.value).join(" ");
|
|
298
|
+
const wanted = tokens(operation.tokens);
|
|
299
|
+
return operation.kind === "add" ? [...current, ...wanted.filter((item) => !current.includes(item))].join(" ") : current.filter((item) => !wanted.includes(item)).join(" ");
|
|
300
|
+
};
|
|
301
|
+
if (field === void 0) {
|
|
302
|
+
if (element.hasSpread) return {
|
|
303
|
+
ok: false,
|
|
304
|
+
reason: "A spread attribute can supply className here, so a class list cannot be added safely. Edit it in Source."
|
|
305
|
+
};
|
|
306
|
+
if (operation.kind === "remove") return {
|
|
307
|
+
ok: true,
|
|
308
|
+
edits: []
|
|
309
|
+
};
|
|
310
|
+
const value = next([]);
|
|
311
|
+
if (value === "") return {
|
|
312
|
+
ok: true,
|
|
313
|
+
edits: []
|
|
314
|
+
};
|
|
315
|
+
return {
|
|
316
|
+
ok: true,
|
|
317
|
+
edits: [{
|
|
318
|
+
start: element.attributeInsertion,
|
|
319
|
+
end: element.attributeInsertion,
|
|
320
|
+
before: "",
|
|
321
|
+
after: ` className=${JSON.stringify(value)}`
|
|
322
|
+
}]
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
if (field.kind !== "literal" || field.literalType !== "string") return {
|
|
326
|
+
ok: false,
|
|
327
|
+
reason: `className is ${field.kind === "binding" ? "bound to" : "computed from"} \`${field.value}\`, so editing it would discard that choice. Change the literal classes inside it in Source.`
|
|
328
|
+
};
|
|
329
|
+
const value = next(tokens(field.value));
|
|
330
|
+
return {
|
|
331
|
+
ok: true,
|
|
332
|
+
edits: [{
|
|
333
|
+
start: field.start,
|
|
334
|
+
end: field.end,
|
|
335
|
+
before: source.slice(field.start, field.end),
|
|
336
|
+
after: JSON.stringify(value)
|
|
337
|
+
}]
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
//#endregion
|
|
341
|
+
export { applySourceReplacements, classNameEdit, expressionReplacement, inspectSourceElement, inspectSourceFixtures, literalReplacement, structuralReplacements };
|
|
342
|
+
|
|
343
|
+
//# sourceMappingURL=source-edit.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/source-locations.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The source payload a JSX transform may attach to an element. The transform may omit any field
|
|
4
|
+
* for synthetic calls; only a complete payload can identify a source origin safely.
|
|
5
|
+
*/
|
|
6
|
+
interface JsxSource {
|
|
7
|
+
readonly fileName?: string | undefined;
|
|
8
|
+
readonly lineNumber?: number | undefined;
|
|
9
|
+
readonly columnNumber?: number | undefined;
|
|
10
|
+
}
|
|
11
|
+
/** A complete, normalized source origin for a JSX element. */
|
|
12
|
+
interface JsxSourceLocation {
|
|
13
|
+
readonly fileName: string;
|
|
14
|
+
readonly lineNumber: number;
|
|
15
|
+
readonly columnNumber: number;
|
|
16
|
+
}
|
|
17
|
+
/** The JSX prop that carries a {@link JsxSource} to the email JSX runtime. */
|
|
18
|
+
declare const JSX_SOURCE_LOCATION_PROP: "__samva_source_location";
|
|
19
|
+
/** Normalize the optional payload a JSX transform attaches. */
|
|
20
|
+
declare const completeJsxSourceLocation: (source: JsxSource | null | undefined) => JsxSourceLocation | undefined;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { completeJsxSourceLocation as i, JsxSource as n, JsxSourceLocation as r, JSX_SOURCE_LOCATION_PROP as t };
|
|
23
|
+
//# sourceMappingURL=source-locations-C8wCsiAy.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { i as completeJsxSourceLocation, n as JsxSource, r as JsxSourceLocation, t as JSX_SOURCE_LOCATION_PROP } from "./source-locations-C8wCsiAy.js";
|
|
2
|
+
export { JSX_SOURCE_LOCATION_PROP, JsxSource, JsxSourceLocation, completeJsxSourceLocation };
|
package/dist/source-locations.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import { t as hasProperty } from "./guards-eV1qLbf2.js";
|
|
2
1
|
//#region src/source-locations.ts
|
|
3
|
-
/**
|
|
4
|
-
* Runtime-only carrier for JSX source metadata. It is global so separately
|
|
5
|
-
* bundled `jsx-dev-runtime` and `render-template` entries still agree on the
|
|
6
|
-
* sidecar key, and it is a Symbol so it cannot enter SML, HTML, or JSON.
|
|
7
|
-
*/
|
|
8
|
-
const JSX_SOURCE_LOCATION = Symbol.for("@samva/markup/jsx-source-location");
|
|
9
|
-
/** Internal JSX prop used only by an editor preview source transform. */
|
|
2
|
+
/** The JSX prop that carries a {@link JsxSource} to the email JSX runtime. */
|
|
10
3
|
const JSX_SOURCE_LOCATION_PROP = "__samva_source_location";
|
|
11
|
-
/** Normalize the optional payload
|
|
4
|
+
/** Normalize the optional payload a JSX transform attaches. */
|
|
12
5
|
const completeJsxSourceLocation = (source) => {
|
|
13
6
|
if (source?.fileName === void 0 || source.lineNumber === void 0 || source.columnNumber === void 0) return;
|
|
14
7
|
return Object.freeze({
|
|
@@ -17,86 +10,7 @@ const completeJsxSourceLocation = (source) => {
|
|
|
17
10
|
columnNumber: source.columnNumber
|
|
18
11
|
});
|
|
19
12
|
};
|
|
20
|
-
/** Attach a source origin without changing the serialized draft shape. */
|
|
21
|
-
const attachJsxSourceLocation = (node, source) => {
|
|
22
|
-
if (Object.hasOwn(node, JSX_SOURCE_LOCATION)) return;
|
|
23
|
-
Object.defineProperty(node, JSX_SOURCE_LOCATION, {
|
|
24
|
-
configurable: false,
|
|
25
|
-
enumerable: false,
|
|
26
|
-
value: source,
|
|
27
|
-
writable: false
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
const isJsxSourceLocation = (value) => hasProperty(value, "fileName") && typeof value.fileName === "string" && hasProperty(value, "lineNumber") && typeof value.lineNumber === "number" && Number.isInteger(value.lineNumber) && hasProperty(value, "columnNumber") && typeof value.columnNumber === "number" && Number.isInteger(value.columnNumber);
|
|
31
|
-
/** Read the ephemeral origin, if this draft element has one. */
|
|
32
|
-
const jsxSourceLocationOf = (node) => {
|
|
33
|
-
if (node.kind !== "element") return void 0;
|
|
34
|
-
const value = Object.getOwnPropertyDescriptor(node, JSX_SOURCE_LOCATION)?.value;
|
|
35
|
-
return isJsxSourceLocation(value) ? value : void 0;
|
|
36
|
-
};
|
|
37
|
-
const elementChildren = (node) => node.children.filter((child) => child.kind === "element");
|
|
38
|
-
const sourceOriginKey = (source) => JSON.stringify([
|
|
39
|
-
source.fileName,
|
|
40
|
-
source.lineNumber,
|
|
41
|
-
source.columnNumber
|
|
42
|
-
]);
|
|
43
|
-
/**
|
|
44
|
-
* Pair a draft tree with its parsed SML tree by element preorder. Text nodes
|
|
45
|
-
* are intentionally ignored: the SML parser normalizes inline whitespace, so
|
|
46
|
-
* only the element structure is stable enough to be a source-map contract.
|
|
47
|
-
*/
|
|
48
|
-
const mapJsxSourceLocations = (draft, parsed) => {
|
|
49
|
-
const byNodeId = {};
|
|
50
|
-
const origins = /* @__PURE__ */ new Set();
|
|
51
|
-
let duplicateOrigin = false;
|
|
52
|
-
const visit = (draftNode, parsedNode) => {
|
|
53
|
-
if (draftNode.tag !== parsedNode.tag) return false;
|
|
54
|
-
const source = jsxSourceLocationOf(draftNode);
|
|
55
|
-
if (source !== void 0) {
|
|
56
|
-
const origin = sourceOriginKey(source);
|
|
57
|
-
if (origins.has(origin)) duplicateOrigin = true;
|
|
58
|
-
origins.add(origin);
|
|
59
|
-
if (Object.hasOwn(byNodeId, parsedNode.id)) return false;
|
|
60
|
-
byNodeId[parsedNode.id] = source;
|
|
61
|
-
}
|
|
62
|
-
const draftChildren = elementChildren(draftNode);
|
|
63
|
-
const parsedChildren = elementChildren(parsedNode);
|
|
64
|
-
if (draftChildren.length !== parsedChildren.length) return false;
|
|
65
|
-
for (let index = 0; index < draftChildren.length; index++) if (!visit(draftChildren[index], parsedChildren[index])) return false;
|
|
66
|
-
return true;
|
|
67
|
-
};
|
|
68
|
-
if (!visit(draft, parsed)) return {
|
|
69
|
-
kind: "unavailable",
|
|
70
|
-
reason: "structure-mismatch"
|
|
71
|
-
};
|
|
72
|
-
if (duplicateOrigin) return {
|
|
73
|
-
kind: "unavailable",
|
|
74
|
-
reason: "duplicate-source-origin"
|
|
75
|
-
};
|
|
76
|
-
if (Object.keys(byNodeId).length === 0) return {
|
|
77
|
-
kind: "unavailable",
|
|
78
|
-
reason: "no-source-metadata"
|
|
79
|
-
};
|
|
80
|
-
return {
|
|
81
|
-
kind: "available",
|
|
82
|
-
byNodeId: Object.freeze(byNodeId)
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
/** Compare source-map statuses for the emission determinism guard. */
|
|
86
|
-
const sameTemplateSourceLocations = (left, right) => {
|
|
87
|
-
if (left.kind !== right.kind) return false;
|
|
88
|
-
if (left.kind === "unavailable") return right.kind === "unavailable" && left.reason === right.reason;
|
|
89
|
-
if (right.kind === "unavailable") return false;
|
|
90
|
-
const leftEntries = Object.entries(left.byNodeId);
|
|
91
|
-
const rightEntries = Object.entries(right.byNodeId);
|
|
92
|
-
if (leftEntries.length !== rightEntries.length) return false;
|
|
93
|
-
for (const [nodeId, source] of leftEntries) {
|
|
94
|
-
const other = right.byNodeId[nodeId];
|
|
95
|
-
if (other === void 0 || other.fileName !== source.fileName || other.lineNumber !== source.lineNumber || other.columnNumber !== source.columnNumber) return false;
|
|
96
|
-
}
|
|
97
|
-
return true;
|
|
98
|
-
};
|
|
99
13
|
//#endregion
|
|
100
|
-
export {
|
|
14
|
+
export { JSX_SOURCE_LOCATION_PROP, completeJsxSourceLocation };
|
|
101
15
|
|
|
102
16
|
//# sourceMappingURL=source-locations.js.map
|