@samva/markup 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +90 -37
- package/README.md +188 -52
- package/dist/assets-C5duwTya.d.ts +40 -0
- package/dist/{brand-DcoVkh_S.d.ts → brand-B-0bN_Ir.d.ts} +2 -2
- package/dist/{render-vAv_4r9v.js → cascade-t6kxlgEI.js} +93 -280
- package/dist/channel-edit.d.ts +121 -0
- package/dist/channel-edit.js +609 -0
- package/dist/channel-specs-B6M_HlaV.js +29 -0
- package/dist/channel-specs-C2feJwuP.d.ts +13 -0
- package/dist/compatibility-DbISoFIq.js +589 -0
- package/dist/compiler.d.ts +10 -257
- package/dist/compiler.js +10 -730
- package/dist/{css-CS2jLID6.d.ts → css-BVQKICKC.d.ts} +3 -3
- package/dist/diagnostic-codes.d.ts +403 -0
- package/dist/diagnostic-codes.js +399 -0
- package/dist/{diagnostics-BMYtBCQk.d.ts → diagnostics-B-Gym34R.d.ts} +8 -4
- package/dist/diagnostics.d.ts +31 -2
- package/dist/diagnostics.js +1 -19
- package/dist/{elements-BzjjnoCS.d.ts → elements-cqldpaJt.d.ts} +3 -3
- package/dist/email/assets.d.ts +2 -40
- package/dist/email/brand-footer.d.ts +2 -2
- package/dist/email/brand-footer.js +4 -3
- package/dist/email/brand.d.ts +1 -1
- package/dist/email/brand.js +1 -1
- package/dist/email/components.d.ts +21 -10
- package/dist/email/components.js +46 -11
- package/dist/email/diagnostics.d.ts +2 -2
- package/dist/email/diagnostics.js +2 -1
- package/dist/email/elements.d.ts +1 -1
- package/dist/email/html.d.ts +2 -2
- package/dist/email/html.js +45 -2
- package/dist/email/jsx-dev-runtime.d.ts +2 -2
- package/dist/email/jsx-runtime.d.ts +1 -1
- package/dist/email/render.d.ts +8 -18
- package/dist/email/render.js +163 -3
- package/dist/email/text.d.ts +1 -1
- package/dist/fmt.d.ts +32 -0
- package/dist/fmt.js +174 -0
- package/dist/{html-Bl9BAdqc.d.ts → html-BJepOwZ4.d.ts} +19 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/ir-aaqNE987.d.ts +252 -0
- package/dist/ir.d.ts +2 -0
- package/dist/ir.js +7 -0
- package/dist/preview-Ekdg1dXG.d.ts +100 -0
- package/dist/preview.d.ts +2 -0
- package/dist/preview.js +160 -0
- package/dist/profile-BH-OtdDA.js +3670 -0
- package/dist/render-ir.d.ts +19 -0
- package/dist/render-ir.js +826 -0
- package/dist/sms-segments.d.ts +13 -2
- package/dist/sms.d.ts +16 -0
- package/dist/sms.js +12 -0
- package/dist/{email/source-edit.d.ts → source-edit.d.ts} +55 -6
- package/dist/source-edit.js +343 -0
- package/dist/source-locations-C8wCsiAy.d.ts +23 -0
- package/dist/source-locations.d.ts +2 -2
- package/dist/source-locations.js +3 -89
- package/dist/static.d.ts +57 -0
- package/dist/static.js +69 -0
- package/dist/tailwind-CMYpZf1v.js +614 -0
- package/dist/template-_QE_rQND.d.ts +65 -0
- package/dist/template.d.ts +2 -2
- package/dist/template.js +15 -10
- package/dist/theme-css.d.ts +1 -1
- package/dist/theme-imports-lvBw3AD1.js +109 -0
- package/dist/transform-Ct2OMkFN.d.ts +153 -0
- package/dist/whatsapp.d.ts +57 -0
- package/dist/whatsapp.js +22 -0
- package/generated/contract.json +1782 -0
- package/generated/reference.md +353 -0
- package/package.json +41 -151
- package/skills/sml/SKILL.md +123 -0
- package/dist/ast-BrDtApwS.d.ts +0 -107
- package/dist/ast.d.ts +0 -2
- package/dist/ast.js +0 -124
- package/dist/candidate.d.ts +0 -29
- package/dist/candidate.js +0 -88
- package/dist/catalog-CKuOooB8.d.ts +0 -354
- package/dist/checks-D73Xizbw.js +0 -59366
- package/dist/checks.d.ts +0 -33
- package/dist/checks.js +0 -2
- package/dist/classes.d.ts +0 -26
- package/dist/classes.js +0 -184
- package/dist/compile-sms.d.ts +0 -28
- package/dist/compile-sms.js +0 -44
- package/dist/compile-whatsapp.d.ts +0 -56
- package/dist/compile-whatsapp.js +0 -186
- package/dist/compile.d.ts +0 -18
- package/dist/compile.js +0 -29
- package/dist/components.d.ts +0 -289
- package/dist/components.js +0 -106
- package/dist/conditionals.d.ts +0 -10
- package/dist/conditionals.js +0 -74
- package/dist/corpus-CPPfgAHN.d.ts +0 -106
- package/dist/diagnostics-OcQKQYSY.d.ts +0 -49
- package/dist/email/selection.d.ts +0 -2
- package/dist/email/selection.js +0 -91
- package/dist/email/source-edit.js +0 -185
- package/dist/email/stylesheets.d.ts +0 -15
- package/dist/email/stylesheets.js +0 -48
- package/dist/emit.d.ts +0 -51
- package/dist/emit.js +0 -151
- package/dist/interpolate.d.ts +0 -24
- package/dist/interpolate.js +0 -43
- package/dist/jsx-dev-runtime.d.ts +0 -11
- package/dist/jsx-dev-runtime.js +0 -15
- package/dist/jsx-runtime-I-1nCtl2.d.ts +0 -57
- package/dist/jsx-runtime.d.ts +0 -2
- package/dist/jsx-runtime.js +0 -121
- package/dist/lexer.d.ts +0 -60
- package/dist/lexer.js +0 -281
- package/dist/model.d.ts +0 -24
- package/dist/model.js +0 -77
- package/dist/ops-BvwqHl7V.js +0 -630
- package/dist/ops.d.ts +0 -114
- package/dist/ops.js +0 -2
- package/dist/parser-t29cHLVL.d.ts +0 -396
- package/dist/parser.d.ts +0 -2
- package/dist/parser.js +0 -859
- package/dist/predicate-BI6uRRM-.js +0 -549
- package/dist/predicate-M-05Nd7R.d.ts +0 -56
- package/dist/predicate.d.ts +0 -2
- package/dist/predicate.js +0 -2
- package/dist/printer.d.ts +0 -6
- package/dist/printer.js +0 -122
- package/dist/registry-Dcp6QEK_.d.ts +0 -73
- package/dist/registry.d.ts +0 -2
- package/dist/registry.js +0 -646
- package/dist/render-template.d.ts +0 -45
- package/dist/render-template.js +0 -76
- package/dist/selection-CCArx9lU.d.ts +0 -91
- package/dist/showcase-egkusQBf.d.ts +0 -415
- package/dist/sms-segments-y4FpPilJ.d.ts +0 -13
- package/dist/source-locations-DrCM82Ym.d.ts +0 -67
- package/dist/starters/category-mapping.d.ts +0 -13
- package/dist/starters/category-mapping.js +0 -49
- package/dist/starters/corpus.d.ts +0 -2
- package/dist/starters/corpus.js +0 -194
- package/dist/starters/library.d.ts +0 -18
- package/dist/starters/library.js +0 -692
- package/dist/starters/public-gallery.d.ts +0 -266
- package/dist/starters/public-gallery.js +0 -916
- package/dist/starters/public-handoff.d.ts +0 -164
- package/dist/starters/public-handoff.js +0 -361
- package/dist/starters/public-preview-artifacts.d.ts +0 -43
- package/dist/starters/public-preview-artifacts.js +0 -104
- package/dist/starters/public-preview.d.ts +0 -61
- package/dist/starters/public-preview.js +0 -83
- package/dist/starters/showcase.d.ts +0 -2
- package/dist/starters/showcase.js +0 -335
- package/dist/starters/sources.d.ts +0 -45
- package/dist/starters/sources.js +0 -7762
- package/dist/starters/theme.d.ts +0 -45
- package/dist/starters/theme.js +0 -77
- package/dist/starters.d.ts +0 -2
- package/dist/starters.js +0 -874
- package/dist/tailwind-BYq7Lo6u.js +0 -727
- package/dist/template-DWftqh4x.d.ts +0 -60
- package/dist/tsx-source-instrumentation.d.ts +0 -30
- package/dist/tsx-source-instrumentation.js +0 -115
- package/dist/tsx-tracer.d.ts +0 -112
- package/dist/tsx-tracer.js +0 -985
- package/dist/variables-J_L3qxRa.d.ts +0 -77
- package/dist/variables.d.ts +0 -2
- package/dist/variables.js +0 -141
- package/dist/version-BITr58kk.js +0 -96
- package/generated/sml-agent-contract.json +0 -709
- package/generated/sml-email-agent-contract.json +0 -615
- package/generated/sml-email-language-reference.md +0 -94
- package/generated/sml-language-reference.md +0 -195
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { f as ElementNode, n as Attribute, x as SmlNode } from "./ast-BrDtApwS.js";
|
|
2
|
-
import { s as VariableRef } from "./variables-J_L3qxRa.js";
|
|
3
|
-
//#region src/jsx-runtime.d.ts
|
|
4
|
-
/** A component is a plain function of its props that returns a draft node. */
|
|
5
|
-
type Component<P> = (props: P) => SmlNode;
|
|
6
|
-
/**
|
|
7
|
-
* What may appear in a component's `children`. Booleans/null/undefined are
|
|
8
|
-
* skipped (so `{cond && <X/>}` and `{cond ? <A/> : null}` are BUILD-TIME
|
|
9
|
-
* conditionals that evaluate away); strings/numbers become text; VariableRefs
|
|
10
|
-
* become `{{interpolation}}` nodes; arrays flatten; nested nodes nest. Anything
|
|
11
|
-
* else is a typed authoring error.
|
|
12
|
-
*/
|
|
13
|
-
type SmlChild = SmlNode | FragmentDraft | VariableRef<unknown> | string | number | boolean | null | undefined | ReadonlyArray<SmlChild>;
|
|
14
|
-
type SmlChildren = SmlChild | ReadonlyArray<SmlChild>;
|
|
15
|
-
/** Fragment children pass through un-wrapped — a Fragment is not an element. */
|
|
16
|
-
interface FragmentDraft {
|
|
17
|
-
readonly kind: "fragment";
|
|
18
|
-
readonly children: ReadonlyArray<SmlNode>;
|
|
19
|
-
}
|
|
20
|
-
type JsxResult = SmlNode | FragmentDraft;
|
|
21
|
-
/**
|
|
22
|
-
* Flattens and normalizes a component's raw `children` prop into AST child
|
|
23
|
-
* nodes. Fragments splice their children in; booleans/null/undefined drop out.
|
|
24
|
-
*/
|
|
25
|
-
declare const normalizeChildren: (children: unknown) => Array<SmlNode>;
|
|
26
|
-
/**
|
|
27
|
-
* Builds an element draft from a tag, attribute list (already in authored
|
|
28
|
-
* order), and normalized children. Kept here so the runtime owns the AST shape;
|
|
29
|
-
* ./components maps typed props onto attributes and calls this.
|
|
30
|
-
*/
|
|
31
|
-
declare const elementDraft: (tag: ElementNode["tag"], attributes: ReadonlyArray<Attribute>, children: ReadonlyArray<SmlNode>) => ElementNode;
|
|
32
|
-
interface JsxProps {
|
|
33
|
-
readonly children?: unknown;
|
|
34
|
-
readonly [key: string]: unknown;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* The automatic-runtime entry point. `type` is always one of our typed
|
|
38
|
-
* component functions (or `Fragment`); we invoke it with its props. The JSX
|
|
39
|
-
* transform routes single-child elements here and multi-child elements to
|
|
40
|
-
* `jsxs` — behaviour is identical for us (components normalize their own
|
|
41
|
-
* children), so `jsxs` re-exports this.
|
|
42
|
-
*/
|
|
43
|
-
declare const jsx: (type: Component<JsxProps> | typeof Fragment, props: JsxProps) => JsxResult;
|
|
44
|
-
declare const jsxs: typeof jsx;
|
|
45
|
-
/** Groups children without an element wrapper. Its children splice into the parent. */
|
|
46
|
-
declare const Fragment: unique symbol;
|
|
47
|
-
declare namespace JSX {
|
|
48
|
-
type Element = JsxResult;
|
|
49
|
-
type ElementType = Component<never> | typeof Fragment;
|
|
50
|
-
interface ElementChildrenAttribute {
|
|
51
|
-
readonly children: object;
|
|
52
|
-
}
|
|
53
|
-
type IntrinsicElements = Record<string, never>;
|
|
54
|
-
}
|
|
55
|
-
//#endregion
|
|
56
|
-
export { JsxResult as a, elementDraft as c, normalizeChildren as d, JSX as i, jsx as l, Fragment as n, SmlChild as o, FragmentDraft as r, SmlChildren as s, Component as t, jsxs as u };
|
|
57
|
-
//# sourceMappingURL=jsx-runtime-I-1nCtl2.d.ts.map
|
package/dist/jsx-runtime.d.ts
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { a as JsxResult, c as elementDraft, d as normalizeChildren, i as JSX, l as jsx, n as Fragment, o as SmlChild, r as FragmentDraft, s as SmlChildren, t as Component, u as jsxs } from "./jsx-runtime-I-1nCtl2.js";
|
|
2
|
-
export { Component, Fragment, FragmentDraft, JSX, JsxResult, SmlChild, SmlChildren, elementDraft, jsx, jsxs, normalizeChildren };
|
package/dist/jsx-runtime.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { t as hasProperty } from "./guards-eV1qLbf2.js";
|
|
2
|
-
import { JSX_SOURCE_LOCATION_PROP, attachJsxSourceLocation, completeJsxSourceLocation } from "./source-locations.js";
|
|
3
|
-
import { VARIABLE_REF, isVariableRef } from "./variables.js";
|
|
4
|
-
//#region src/jsx-runtime.ts
|
|
5
|
-
const PLACEHOLDER_SPAN = {
|
|
6
|
-
start: 0,
|
|
7
|
-
end: 0
|
|
8
|
-
};
|
|
9
|
-
const isFragmentDraft = (value) => hasProperty(value, "kind") && value.kind === "fragment";
|
|
10
|
-
const isSmlNode = (value) => {
|
|
11
|
-
if (!hasProperty(value, "kind")) return false;
|
|
12
|
-
const kind = value.kind;
|
|
13
|
-
return kind === "element" || kind === "text" || kind === "interpolation";
|
|
14
|
-
};
|
|
15
|
-
const textNode = (value) => ({
|
|
16
|
-
kind: "text",
|
|
17
|
-
id: "",
|
|
18
|
-
value,
|
|
19
|
-
span: PLACEHOLDER_SPAN
|
|
20
|
-
});
|
|
21
|
-
const interpolationNode = (ref) => ({
|
|
22
|
-
kind: "interpolation",
|
|
23
|
-
id: "",
|
|
24
|
-
name: ref[VARIABLE_REF].path,
|
|
25
|
-
syntax: "curly",
|
|
26
|
-
span: PLACEHOLDER_SPAN
|
|
27
|
-
});
|
|
28
|
-
/**
|
|
29
|
-
* Flattens and normalizes a component's raw `children` prop into AST child
|
|
30
|
-
* nodes. Fragments splice their children in; booleans/null/undefined drop out.
|
|
31
|
-
*/
|
|
32
|
-
const normalizeChildren = (children) => {
|
|
33
|
-
const out = [];
|
|
34
|
-
const push = (child) => {
|
|
35
|
-
if (child === null || child === void 0 || typeof child === "boolean") return;
|
|
36
|
-
if (typeof child === "string") {
|
|
37
|
-
out.push(textNode(child));
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
if (typeof child === "number") {
|
|
41
|
-
out.push(textNode(String(child)));
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
if (Array.isArray(child)) {
|
|
45
|
-
for (const item of child) push(item);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
if (isVariableRef(child)) {
|
|
49
|
-
out.push(interpolationNode(child));
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (isFragmentDraft(child)) {
|
|
53
|
-
for (const node of child.children) out.push(node);
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
if (isSmlNode(child)) {
|
|
57
|
-
out.push(child);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
throw new TypeError(`invalid SML child: ${describe(child)} — children may be text, numbers, variables, elements, arrays of these, or false/null/undefined (which are skipped)`);
|
|
61
|
-
};
|
|
62
|
-
push(children);
|
|
63
|
-
return out;
|
|
64
|
-
};
|
|
65
|
-
const describe = (value) => {
|
|
66
|
-
if (typeof value === "function") return "a function (did you pass a component instead of an element?)";
|
|
67
|
-
if (typeof value === "object") return `an object (${JSON.stringify(value)})`;
|
|
68
|
-
return `${typeof value} (${JSON.stringify(value)})`;
|
|
69
|
-
};
|
|
70
|
-
/**
|
|
71
|
-
* Builds an element draft from a tag, attribute list (already in authored
|
|
72
|
-
* order), and normalized children. Kept here so the runtime owns the AST shape;
|
|
73
|
-
* ./components maps typed props onto attributes and calls this.
|
|
74
|
-
*/
|
|
75
|
-
const elementDraft = (tag, attributes, children) => ({
|
|
76
|
-
kind: "element",
|
|
77
|
-
id: "",
|
|
78
|
-
tag,
|
|
79
|
-
attributes,
|
|
80
|
-
children,
|
|
81
|
-
span: PLACEHOLDER_SPAN
|
|
82
|
-
});
|
|
83
|
-
const stripSourceLocation = (props) => {
|
|
84
|
-
const source = props[JSX_SOURCE_LOCATION_PROP];
|
|
85
|
-
if (source === void 0) return {
|
|
86
|
-
props,
|
|
87
|
-
source: void 0
|
|
88
|
-
};
|
|
89
|
-
const { [JSX_SOURCE_LOCATION_PROP]: _source, ...rest } = props;
|
|
90
|
-
return {
|
|
91
|
-
props: rest,
|
|
92
|
-
source
|
|
93
|
-
};
|
|
94
|
-
};
|
|
95
|
-
/**
|
|
96
|
-
* The automatic-runtime entry point. `type` is always one of our typed
|
|
97
|
-
* component functions (or `Fragment`); we invoke it with its props. The JSX
|
|
98
|
-
* transform routes single-child elements here and multi-child elements to
|
|
99
|
-
* `jsxs` — behaviour is identical for us (components normalize their own
|
|
100
|
-
* children), so `jsxs` re-exports this.
|
|
101
|
-
*/
|
|
102
|
-
const jsx = (type, props) => {
|
|
103
|
-
if (type === Fragment) return {
|
|
104
|
-
kind: "fragment",
|
|
105
|
-
children: normalizeChildren(props.children)
|
|
106
|
-
};
|
|
107
|
-
const { props: cleanProps, source } = stripSourceLocation(props);
|
|
108
|
-
const result = type(cleanProps);
|
|
109
|
-
if (source !== void 0 && result.kind === "element") {
|
|
110
|
-
const location = completeJsxSourceLocation(source);
|
|
111
|
-
if (location !== void 0) attachJsxSourceLocation(result, location);
|
|
112
|
-
}
|
|
113
|
-
return result;
|
|
114
|
-
};
|
|
115
|
-
const jsxs = jsx;
|
|
116
|
-
/** Groups children without an element wrapper. Its children splice into the parent. */
|
|
117
|
-
const Fragment = Symbol.for("@samva/markup/Fragment");
|
|
118
|
-
//#endregion
|
|
119
|
-
export { Fragment, elementDraft, jsx, jsxs, normalizeChildren };
|
|
120
|
-
|
|
121
|
-
//# sourceMappingURL=jsx-runtime.js.map
|
package/dist/lexer.d.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
//#region src/lexer.d.ts
|
|
2
|
-
declare const TokenKind: {
|
|
3
|
-
readonly EndOfFile: 0;
|
|
4
|
-
/** `<` opening a start tag (text mode). */
|
|
5
|
-
readonly LessThan: 1;
|
|
6
|
-
/** `</` opening a close tag (text mode). */
|
|
7
|
-
readonly LessThanSlash: 2;
|
|
8
|
-
readonly GreaterThan: 3;
|
|
9
|
-
readonly SlashGreaterThan: 4;
|
|
10
|
-
readonly Identifier: 5;
|
|
11
|
-
readonly Equals: 6;
|
|
12
|
-
/** Quoted attribute value; getStringValue decodes entities. */
|
|
13
|
-
readonly String: 7;
|
|
14
|
-
readonly OpenBrace: 8;
|
|
15
|
-
readonly CloseBrace: 9;
|
|
16
|
-
/** Unsigned integer inside a brace attribute value. */
|
|
17
|
-
readonly Number: 10;
|
|
18
|
-
/** Raw text run; getTextValue decodes entities. */
|
|
19
|
-
readonly Text: 11;
|
|
20
|
-
/** `{{name}}` or `${name}`; name/syntax carried on the token. */
|
|
21
|
-
readonly Interpolation: 12;
|
|
22
|
-
/** Lexically invalid input; error carried on the token. */
|
|
23
|
-
readonly Unknown: 13;
|
|
24
|
-
};
|
|
25
|
-
type TokenKind = (typeof TokenKind)[keyof typeof TokenKind];
|
|
26
|
-
interface TokenError {
|
|
27
|
-
readonly code: string;
|
|
28
|
-
readonly message: string;
|
|
29
|
-
}
|
|
30
|
-
interface Token {
|
|
31
|
-
readonly kind: TokenKind;
|
|
32
|
-
readonly start: number;
|
|
33
|
-
readonly end: number;
|
|
34
|
-
/** Interpolation only. */
|
|
35
|
-
readonly name?: string | undefined;
|
|
36
|
-
/** Interpolation only. */
|
|
37
|
-
readonly syntax?: "curly" | "dollar" | undefined;
|
|
38
|
-
/** Unknown only. */
|
|
39
|
-
readonly error?: TokenError | undefined;
|
|
40
|
-
}
|
|
41
|
-
/** Decodes entities in text that already passed `scanEntity` validation. */
|
|
42
|
-
declare const decodeEntities: (raw: string) => string;
|
|
43
|
-
interface Lexer {
|
|
44
|
-
/** Current scan position (start of the next token). */
|
|
45
|
-
readonly position: () => number;
|
|
46
|
-
/** Scan one token in text mode (between tags). */
|
|
47
|
-
readonly scanTextToken: () => Token;
|
|
48
|
-
/** Scan one token in tag mode (inside `<...>`), skipping whitespace. */
|
|
49
|
-
readonly scanTagToken: () => Token;
|
|
50
|
-
/** Lazy raw source slice for a token. */
|
|
51
|
-
readonly getText: (token: Token) => string;
|
|
52
|
-
/** Entity-decoded value of a Text token. */
|
|
53
|
-
readonly getTextValue: (token: Token) => string;
|
|
54
|
-
/** Entity-decoded contents of a String token (without quotes). */
|
|
55
|
-
readonly getStringValue: (token: Token) => string;
|
|
56
|
-
}
|
|
57
|
-
declare const createLexer: (source: string) => Lexer;
|
|
58
|
-
//#endregion
|
|
59
|
-
export { Lexer, Token, TokenError, TokenKind, createLexer, decodeEntities };
|
|
60
|
-
//# sourceMappingURL=lexer.d.ts.map
|
package/dist/lexer.js
DELETED
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
//#region src/lexer.ts
|
|
2
|
-
const CHAR_TAB = 9;
|
|
3
|
-
const CHAR_LINE_FEED = 10;
|
|
4
|
-
const CHAR_CARRIAGE_RETURN = 13;
|
|
5
|
-
const CHAR_SPACE = 32;
|
|
6
|
-
const CHAR_BANG = 33;
|
|
7
|
-
const CHAR_DOUBLE_QUOTE = 34;
|
|
8
|
-
const CHAR_HASH = 35;
|
|
9
|
-
const CHAR_DOLLAR = 36;
|
|
10
|
-
const CHAR_AMPERSAND = 38;
|
|
11
|
-
const CHAR_SINGLE_QUOTE = 39;
|
|
12
|
-
const CHAR_SLASH = 47;
|
|
13
|
-
const CHAR_SEMICOLON = 59;
|
|
14
|
-
const CHAR_LESS_THAN = 60;
|
|
15
|
-
const CHAR_EQUALS = 61;
|
|
16
|
-
const CHAR_GREATER_THAN = 62;
|
|
17
|
-
const CHAR_OPEN_BRACE = 123;
|
|
18
|
-
const CHAR_CLOSE_BRACE = 125;
|
|
19
|
-
const CHAR_DOT = 46;
|
|
20
|
-
const CHAR_UNDERSCORE = 95;
|
|
21
|
-
const CHAR_0 = 48;
|
|
22
|
-
const CHAR_9 = 57;
|
|
23
|
-
const CHAR_UPPER_A = 65;
|
|
24
|
-
const CHAR_UPPER_X = 88;
|
|
25
|
-
const CHAR_UPPER_Z = 90;
|
|
26
|
-
const CHAR_LOWER_A = 97;
|
|
27
|
-
const CHAR_LOWER_X = 120;
|
|
28
|
-
const CHAR_LOWER_Z = 122;
|
|
29
|
-
const TokenKind = {
|
|
30
|
-
EndOfFile: 0,
|
|
31
|
-
/** `<` opening a start tag (text mode). */
|
|
32
|
-
LessThan: 1,
|
|
33
|
-
/** `</` opening a close tag (text mode). */
|
|
34
|
-
LessThanSlash: 2,
|
|
35
|
-
GreaterThan: 3,
|
|
36
|
-
SlashGreaterThan: 4,
|
|
37
|
-
Identifier: 5,
|
|
38
|
-
Equals: 6,
|
|
39
|
-
/** Quoted attribute value; getStringValue decodes entities. */
|
|
40
|
-
String: 7,
|
|
41
|
-
OpenBrace: 8,
|
|
42
|
-
CloseBrace: 9,
|
|
43
|
-
/** Unsigned integer inside a brace attribute value. */
|
|
44
|
-
Number: 10,
|
|
45
|
-
/** Raw text run; getTextValue decodes entities. */
|
|
46
|
-
Text: 11,
|
|
47
|
-
/** `{{name}}` or `${name}`; name/syntax carried on the token. */
|
|
48
|
-
Interpolation: 12,
|
|
49
|
-
/** Lexically invalid input; error carried on the token. */
|
|
50
|
-
Unknown: 13
|
|
51
|
-
};
|
|
52
|
-
const isWhitespace = (code) => code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LINE_FEED || code === CHAR_CARRIAGE_RETURN;
|
|
53
|
-
const isDigit = (code) => code >= CHAR_0 && code <= CHAR_9;
|
|
54
|
-
const isLetter = (code) => code >= CHAR_UPPER_A && code <= CHAR_UPPER_Z || code >= CHAR_LOWER_A && code <= CHAR_LOWER_Z;
|
|
55
|
-
const isNameChar = (code) => isLetter(code) || isDigit(code) || code === CHAR_UNDERSCORE || code === CHAR_DOT;
|
|
56
|
-
const NAMED_ENTITIES = {
|
|
57
|
-
amp: "&",
|
|
58
|
-
lt: "<",
|
|
59
|
-
gt: ">",
|
|
60
|
-
quot: "\"",
|
|
61
|
-
apos: "'",
|
|
62
|
-
nbsp: "\xA0"
|
|
63
|
-
};
|
|
64
|
-
const numericEntityCodePoint = (digits, radix) => {
|
|
65
|
-
const codePoint = Number.parseInt(digits, radix);
|
|
66
|
-
return Number.isFinite(codePoint) && codePoint <= 1114111 ? codePoint : void 0;
|
|
67
|
-
};
|
|
68
|
-
/**
|
|
69
|
-
* Validates the entity starting at `offset` (which points at `&`).
|
|
70
|
-
* Returns the end offset (past `;`) or -1 when malformed.
|
|
71
|
-
*/
|
|
72
|
-
const scanEntity = (source, offset) => {
|
|
73
|
-
let index = offset + 1;
|
|
74
|
-
if (source.charCodeAt(index) === CHAR_HASH) {
|
|
75
|
-
index++;
|
|
76
|
-
const marker = source.charCodeAt(index);
|
|
77
|
-
const hex = marker === CHAR_LOWER_X || marker === CHAR_UPPER_X;
|
|
78
|
-
if (hex) index++;
|
|
79
|
-
const digitsStart = index;
|
|
80
|
-
while (index < source.length) {
|
|
81
|
-
const code = source.charCodeAt(index);
|
|
82
|
-
if (!(isDigit(code) || hex && (code >= 97 && code <= 102 || code >= 65 && code <= 70))) break;
|
|
83
|
-
index++;
|
|
84
|
-
}
|
|
85
|
-
if (index === digitsStart) return -1;
|
|
86
|
-
if (numericEntityCodePoint(source.slice(digitsStart, index), hex ? 16 : 10) === void 0) return -1;
|
|
87
|
-
return source.charCodeAt(index) === CHAR_SEMICOLON ? index + 1 : -1;
|
|
88
|
-
}
|
|
89
|
-
const nameStart = index;
|
|
90
|
-
while (index < source.length && isLetter(source.charCodeAt(index))) index++;
|
|
91
|
-
const name = source.slice(nameStart, index);
|
|
92
|
-
if (!Object.hasOwn(NAMED_ENTITIES, name)) return -1;
|
|
93
|
-
return source.charCodeAt(index) === CHAR_SEMICOLON ? index + 1 : -1;
|
|
94
|
-
};
|
|
95
|
-
/** Decodes entities in text that already passed `scanEntity` validation. */
|
|
96
|
-
const decodeEntities = (raw) => {
|
|
97
|
-
if (!raw.includes("&")) return raw;
|
|
98
|
-
let result = "";
|
|
99
|
-
let index = 0;
|
|
100
|
-
while (index < raw.length) {
|
|
101
|
-
const ampersand = raw.indexOf("&", index);
|
|
102
|
-
if (ampersand === -1) {
|
|
103
|
-
result += raw.slice(index);
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
result += raw.slice(index, ampersand);
|
|
107
|
-
const semicolon = raw.indexOf(";", ampersand);
|
|
108
|
-
if (semicolon === -1) {
|
|
109
|
-
result += raw.slice(ampersand);
|
|
110
|
-
break;
|
|
111
|
-
}
|
|
112
|
-
const body = raw.slice(ampersand + 1, semicolon);
|
|
113
|
-
if (body.startsWith("#x") || body.startsWith("#X")) {
|
|
114
|
-
const codePoint = numericEntityCodePoint(body.slice(2), 16);
|
|
115
|
-
result += codePoint === void 0 ? raw.slice(ampersand, semicolon + 1) : String.fromCodePoint(codePoint);
|
|
116
|
-
} else if (body.startsWith("#")) {
|
|
117
|
-
const codePoint = numericEntityCodePoint(body.slice(1), 10);
|
|
118
|
-
result += codePoint === void 0 ? raw.slice(ampersand, semicolon + 1) : String.fromCodePoint(codePoint);
|
|
119
|
-
} else result += Object.hasOwn(NAMED_ENTITIES, body) ? NAMED_ENTITIES[body] : raw.slice(ampersand, semicolon + 1);
|
|
120
|
-
index = semicolon + 1;
|
|
121
|
-
}
|
|
122
|
-
return result;
|
|
123
|
-
};
|
|
124
|
-
const createLexer = (source) => {
|
|
125
|
-
let position = 0;
|
|
126
|
-
const length = source.length;
|
|
127
|
-
const token = (kind, start, extra) => {
|
|
128
|
-
return {
|
|
129
|
-
kind,
|
|
130
|
-
start,
|
|
131
|
-
end: position,
|
|
132
|
-
...extra
|
|
133
|
-
};
|
|
134
|
-
};
|
|
135
|
-
const unknown = (start, code, message) => {
|
|
136
|
-
if (position === start) position = Math.min(start + 1, length);
|
|
137
|
-
return token(TokenKind.Unknown, start, { error: {
|
|
138
|
-
code,
|
|
139
|
-
message
|
|
140
|
-
} });
|
|
141
|
-
};
|
|
142
|
-
const scanInterpolation = (start, syntax) => {
|
|
143
|
-
position = start + 2;
|
|
144
|
-
while (position < length && isWhitespace(source.charCodeAt(position))) position++;
|
|
145
|
-
if (syntax === "dollar" && source.charCodeAt(position) === CHAR_SLASH) position++;
|
|
146
|
-
const nameStart = position;
|
|
147
|
-
while (position < length && isNameChar(source.charCodeAt(position))) position++;
|
|
148
|
-
const name = source.slice(nameStart, position);
|
|
149
|
-
while (position < length && isWhitespace(source.charCodeAt(position))) position++;
|
|
150
|
-
const closed = syntax === "curly" ? source.charCodeAt(position) === CHAR_CLOSE_BRACE && source.charCodeAt(position + 1) === CHAR_CLOSE_BRACE : source.charCodeAt(position) === CHAR_CLOSE_BRACE;
|
|
151
|
-
if (name.length === 0 || !closed) {
|
|
152
|
-
position = start;
|
|
153
|
-
return unknown(start, "invalid-interpolation", `malformed interpolation — write ${syntax === "curly" ? "{{variableName}}" : "${variableName}"} using letters, digits, underscore, or dot`);
|
|
154
|
-
}
|
|
155
|
-
position += syntax === "curly" ? 2 : 1;
|
|
156
|
-
return token(TokenKind.Interpolation, start, {
|
|
157
|
-
name,
|
|
158
|
-
syntax
|
|
159
|
-
});
|
|
160
|
-
};
|
|
161
|
-
const scanTextToken = () => {
|
|
162
|
-
const start = position;
|
|
163
|
-
if (position >= length) return token(TokenKind.EndOfFile, start);
|
|
164
|
-
const first = source.charCodeAt(position);
|
|
165
|
-
if (first === CHAR_LESS_THAN) {
|
|
166
|
-
const next = source.charCodeAt(position + 1);
|
|
167
|
-
if (next === CHAR_SLASH) {
|
|
168
|
-
position += 2;
|
|
169
|
-
return token(TokenKind.LessThanSlash, start);
|
|
170
|
-
}
|
|
171
|
-
if (isLetter(next)) {
|
|
172
|
-
position += 1;
|
|
173
|
-
return token(TokenKind.LessThan, start);
|
|
174
|
-
}
|
|
175
|
-
if (next === CHAR_BANG) return unknown(start, "comment-not-supported", source.startsWith("<!--", position) ? "comments are not part of SML — remove the <!-- ... --> block" : "unexpected <! — SML has no doctype or declaration syntax; remove it");
|
|
176
|
-
return unknown(start, "stray-angle-bracket", "stray < in text — escape it as <");
|
|
177
|
-
}
|
|
178
|
-
if (first === CHAR_OPEN_BRACE && source.charCodeAt(position + 1) === CHAR_OPEN_BRACE) return scanInterpolation(start, "curly");
|
|
179
|
-
if (first === CHAR_DOLLAR && source.charCodeAt(position + 1) === CHAR_OPEN_BRACE) return scanInterpolation(start, "dollar");
|
|
180
|
-
while (position < length) {
|
|
181
|
-
const code = source.charCodeAt(position);
|
|
182
|
-
if (code === CHAR_LESS_THAN) break;
|
|
183
|
-
if (code === CHAR_OPEN_BRACE && source.charCodeAt(position + 1) === CHAR_OPEN_BRACE) break;
|
|
184
|
-
if (code === CHAR_DOLLAR && source.charCodeAt(position + 1) === CHAR_OPEN_BRACE) break;
|
|
185
|
-
if (code === CHAR_AMPERSAND) {
|
|
186
|
-
const entityEnd = scanEntity(source, position);
|
|
187
|
-
if (entityEnd === -1) {
|
|
188
|
-
if (position > start) return token(TokenKind.Text, start);
|
|
189
|
-
return unknown(start, "bare-ampersand", "bare & in text — escape it as & (or use a supported entity like <)");
|
|
190
|
-
}
|
|
191
|
-
position = entityEnd;
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
position++;
|
|
195
|
-
}
|
|
196
|
-
return token(TokenKind.Text, start);
|
|
197
|
-
};
|
|
198
|
-
const scanTagToken = () => {
|
|
199
|
-
while (position < length && isWhitespace(source.charCodeAt(position))) position++;
|
|
200
|
-
const start = position;
|
|
201
|
-
if (position >= length) return token(TokenKind.EndOfFile, start);
|
|
202
|
-
const code = source.charCodeAt(position);
|
|
203
|
-
switch (code) {
|
|
204
|
-
case CHAR_GREATER_THAN:
|
|
205
|
-
position++;
|
|
206
|
-
return token(TokenKind.GreaterThan, start);
|
|
207
|
-
case CHAR_SLASH:
|
|
208
|
-
if (source.charCodeAt(position + 1) === CHAR_GREATER_THAN) {
|
|
209
|
-
position += 2;
|
|
210
|
-
return token(TokenKind.SlashGreaterThan, start);
|
|
211
|
-
}
|
|
212
|
-
return unknown(start, "unexpected-character", "unexpected / inside tag — write /> to self-close");
|
|
213
|
-
case CHAR_EQUALS:
|
|
214
|
-
position++;
|
|
215
|
-
return token(TokenKind.Equals, start);
|
|
216
|
-
case CHAR_OPEN_BRACE:
|
|
217
|
-
position++;
|
|
218
|
-
return token(TokenKind.OpenBrace, start);
|
|
219
|
-
case CHAR_CLOSE_BRACE:
|
|
220
|
-
position++;
|
|
221
|
-
return token(TokenKind.CloseBrace, start);
|
|
222
|
-
case CHAR_DOUBLE_QUOTE:
|
|
223
|
-
case CHAR_SINGLE_QUOTE:
|
|
224
|
-
position++;
|
|
225
|
-
while (position < length) {
|
|
226
|
-
const current = source.charCodeAt(position);
|
|
227
|
-
if (current === code) break;
|
|
228
|
-
if (current === CHAR_AMPERSAND) {
|
|
229
|
-
const entityEnd = scanEntity(source, position);
|
|
230
|
-
if (entityEnd === -1) return unknown(position, "bare-ampersand", "bare & in attribute value — escape it as &");
|
|
231
|
-
position = entityEnd;
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
if (current === CHAR_LESS_THAN || current === CHAR_LINE_FEED) break;
|
|
235
|
-
position++;
|
|
236
|
-
}
|
|
237
|
-
if (source.charCodeAt(position) !== code) {
|
|
238
|
-
const quote = String.fromCharCode(code);
|
|
239
|
-
return {
|
|
240
|
-
kind: TokenKind.Unknown,
|
|
241
|
-
start,
|
|
242
|
-
end: position,
|
|
243
|
-
error: {
|
|
244
|
-
code: "unterminated-string",
|
|
245
|
-
message: `unterminated attribute value — add a closing ${quote}`
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
position++;
|
|
250
|
-
return token(TokenKind.String, start);
|
|
251
|
-
default:
|
|
252
|
-
if (isLetter(code)) {
|
|
253
|
-
position++;
|
|
254
|
-
while (position < length) {
|
|
255
|
-
const current = source.charCodeAt(position);
|
|
256
|
-
if (!isLetter(current) && !isDigit(current)) break;
|
|
257
|
-
position++;
|
|
258
|
-
}
|
|
259
|
-
return token(TokenKind.Identifier, start);
|
|
260
|
-
}
|
|
261
|
-
if (isDigit(code)) {
|
|
262
|
-
position++;
|
|
263
|
-
while (position < length && isDigit(source.charCodeAt(position))) position++;
|
|
264
|
-
return token(TokenKind.Number, start);
|
|
265
|
-
}
|
|
266
|
-
return unknown(start, "unexpected-character", `unexpected character ${JSON.stringify(String.fromCharCode(code))} inside tag`);
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
return {
|
|
270
|
-
position: () => position,
|
|
271
|
-
scanTextToken,
|
|
272
|
-
scanTagToken,
|
|
273
|
-
getText: (t) => source.slice(t.start, t.end),
|
|
274
|
-
getTextValue: (t) => decodeEntities(source.slice(t.start, t.end)),
|
|
275
|
-
getStringValue: (t) => decodeEntities(source.slice(t.start + 1, t.end - 1))
|
|
276
|
-
};
|
|
277
|
-
};
|
|
278
|
-
//#endregion
|
|
279
|
-
export { TokenKind, createLexer, decodeEntities };
|
|
280
|
-
|
|
281
|
-
//# sourceMappingURL=lexer.js.map
|
package/dist/model.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { S as SmlTag, b as SmlDocument } from "./ast-BrDtApwS.js";
|
|
2
|
-
import { Result } from "better-result";
|
|
3
|
-
//#region src/model.d.ts
|
|
4
|
-
/** The subset of an element's attributes the navigator and agent tools read. */
|
|
5
|
-
type SmlNodeKeyAttrs = Readonly<Record<string, string | number>>;
|
|
6
|
-
interface SmlNodeIndexEntry {
|
|
7
|
-
readonly id: string;
|
|
8
|
-
readonly tag: SmlTag;
|
|
9
|
-
readonly order: number;
|
|
10
|
-
readonly parentId: string | null;
|
|
11
|
-
readonly childIndex: number;
|
|
12
|
-
readonly depth: number;
|
|
13
|
-
readonly path: string;
|
|
14
|
-
readonly textPreview: string;
|
|
15
|
-
readonly attrs: SmlNodeKeyAttrs;
|
|
16
|
-
}
|
|
17
|
-
interface SmlNodeIndex {
|
|
18
|
-
readonly nodes: readonly SmlNodeIndexEntry[];
|
|
19
|
-
}
|
|
20
|
-
declare const deriveNodeIndexFromDocument: (document: SmlDocument) => SmlNodeIndex;
|
|
21
|
-
declare const deriveNodeIndex: (source: string) => Result<SmlNodeIndex, string>;
|
|
22
|
-
//#endregion
|
|
23
|
-
export { SmlNodeIndex, SmlNodeIndexEntry, SmlNodeKeyAttrs, deriveNodeIndex, deriveNodeIndexFromDocument };
|
|
24
|
-
//# sourceMappingURL=model.d.ts.map
|
package/dist/model.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { parseSml } from "./parser.js";
|
|
2
|
-
import { Result } from "better-result";
|
|
3
|
-
//#region src/model.ts
|
|
4
|
-
const KEY_ATTRS = /* @__PURE__ */ new Set([
|
|
5
|
-
"alt",
|
|
6
|
-
"class",
|
|
7
|
-
"dir",
|
|
8
|
-
"height",
|
|
9
|
-
"hidden",
|
|
10
|
-
"href",
|
|
11
|
-
"label",
|
|
12
|
-
"lang",
|
|
13
|
-
"level",
|
|
14
|
-
"name",
|
|
15
|
-
"scheme",
|
|
16
|
-
"src",
|
|
17
|
-
"test",
|
|
18
|
-
"valign",
|
|
19
|
-
"width"
|
|
20
|
-
]);
|
|
21
|
-
const attrValue = (value) => value.value;
|
|
22
|
-
const truncate = (value, length) => value.length <= length ? value : `${value.slice(0, length - 3)}...`;
|
|
23
|
-
const normalizePreview = (value) => truncate(value.replace(/\s+/g, " ").trim(), 96);
|
|
24
|
-
const textPreview = (node) => {
|
|
25
|
-
const parts = [];
|
|
26
|
-
const visit = (child) => {
|
|
27
|
-
if (child.kind === "text") {
|
|
28
|
-
parts.push(child.value);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (child.kind === "interpolation") {
|
|
32
|
-
parts.push(`{{${child.name}}}`);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
for (const nested of child.children) visit(nested);
|
|
36
|
-
};
|
|
37
|
-
for (const child of node.children) visit(child);
|
|
38
|
-
return normalizePreview(parts.join(" "));
|
|
39
|
-
};
|
|
40
|
-
const keyAttrs = (node) => Object.fromEntries(node.attributes.filter((attribute) => KEY_ATTRS.has(attribute.name)).map((attribute) => [attribute.name, attrValue(attribute.value)]));
|
|
41
|
-
const deriveNodeIndexFromDocument = (document) => {
|
|
42
|
-
const nodes = [];
|
|
43
|
-
let order = 0;
|
|
44
|
-
const visit = (node, parentId, childIndex, depth, parentPath) => {
|
|
45
|
-
if (node.kind !== "element") return;
|
|
46
|
-
if (node.tag === "Source") return;
|
|
47
|
-
const pathSegment = `${node.tag}[${childIndex}]`;
|
|
48
|
-
const path = parentPath ? `${parentPath}/${pathSegment}` : pathSegment;
|
|
49
|
-
nodes.push({
|
|
50
|
-
id: node.id,
|
|
51
|
-
tag: node.tag,
|
|
52
|
-
order: order++,
|
|
53
|
-
parentId,
|
|
54
|
-
childIndex,
|
|
55
|
-
depth,
|
|
56
|
-
path,
|
|
57
|
-
textPreview: textPreview(node),
|
|
58
|
-
attrs: keyAttrs(node)
|
|
59
|
-
});
|
|
60
|
-
let elementChildIndex = 0;
|
|
61
|
-
for (const child of node.children) if (child.kind === "element") {
|
|
62
|
-
visit(child, node.id, elementChildIndex, depth + 1, path);
|
|
63
|
-
elementChildIndex++;
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
visit(document.root, null, 0, 0, "");
|
|
67
|
-
return { nodes };
|
|
68
|
-
};
|
|
69
|
-
const deriveNodeIndex = (source) => {
|
|
70
|
-
const parsed = parseSml(source);
|
|
71
|
-
if (Result.isError(parsed)) return Result.err(parsed.error.diagnostics.map((diagnostic) => diagnostic.message).join("\n"));
|
|
72
|
-
return Result.ok(deriveNodeIndexFromDocument(parsed.value));
|
|
73
|
-
};
|
|
74
|
-
//#endregion
|
|
75
|
-
export { deriveNodeIndex, deriveNodeIndexFromDocument };
|
|
76
|
-
|
|
77
|
-
//# sourceMappingURL=model.js.map
|