@caretcms/caretize 0.1.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/README.md +70 -0
- package/dist/backup.d.ts +30 -0
- package/dist/backup.d.ts.map +1 -0
- package/dist/backup.js +89 -0
- package/dist/backup.js.map +1 -0
- package/dist/bind-collection.d.ts +56 -0
- package/dist/bind-collection.d.ts.map +1 -0
- package/dist/bind-collection.js +140 -0
- package/dist/bind-collection.js.map +1 -0
- package/dist/bind-route.d.ts +40 -0
- package/dist/bind-route.d.ts.map +1 -0
- package/dist/bind-route.js +150 -0
- package/dist/bind-route.js.map +1 -0
- package/dist/cli-args.d.ts +30 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +118 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +356 -0
- package/dist/cli.js.map +1 -0
- package/dist/detect.d.ts +76 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +237 -0
- package/dist/detect.js.map +1 -0
- package/dist/discover.d.ts +13 -0
- package/dist/discover.d.ts.map +1 -0
- package/dist/discover.js +84 -0
- package/dist/discover.js.map +1 -0
- package/dist/frontmatter.d.ts +26 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +52 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/identifiers.d.ts +26 -0
- package/dist/identifiers.d.ts.map +1 -0
- package/dist/identifiers.js +34 -0
- package/dist/identifiers.js.map +1 -0
- package/dist/import-wrap.d.ts +56 -0
- package/dist/import-wrap.d.ts.map +1 -0
- package/dist/import-wrap.js +149 -0
- package/dist/import-wrap.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/name.d.ts +49 -0
- package/dist/name.d.ts.map +1 -0
- package/dist/name.js +164 -0
- package/dist/name.js.map +1 -0
- package/dist/output.d.ts +30 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +110 -0
- package/dist/output.js.map +1 -0
- package/dist/parse.d.ts +86 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +92 -0
- package/dist/parse.js.map +1 -0
- package/dist/plan.d.ts +46 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +76 -0
- package/dist/plan.js.map +1 -0
- package/dist/preflight.d.ts +19 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +95 -0
- package/dist/preflight.js.map +1 -0
- package/dist/prop-hoist.d.ts +67 -0
- package/dist/prop-hoist.d.ts.map +1 -0
- package/dist/prop-hoist.js +232 -0
- package/dist/prop-hoist.js.map +1 -0
- package/dist/props.d.ts +38 -0
- package/dist/props.d.ts.map +1 -0
- package/dist/props.js +116 -0
- package/dist/props.js.map +1 -0
- package/dist/report.d.ts +42 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +35 -0
- package/dist/report.js.map +1 -0
- package/dist/resolve.d.ts +15 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +35 -0
- package/dist/resolve.js.map +1 -0
- package/dist/run.d.ts +52 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +213 -0
- package/dist/run.js.map +1 -0
- package/dist/splice.d.ts +43 -0
- package/dist/splice.d.ts.map +1 -0
- package/dist/splice.js +90 -0
- package/dist/splice.js.map +1 -0
- package/dist/usage.d.ts +90 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +249 -0
- package/dist/usage.js.map +1 -0
- package/dist/wrap.d.ts +72 -0
- package/dist/wrap.d.ts.map +1 -0
- package/dist/wrap.js +170 -0
- package/dist/wrap.js.map +1 -0
- package/dist/write.d.ts +28 -0
- package/dist/write.d.ts.map +1 -0
- package/dist/write.js +37 -0
- package/dist/write.js.map +1 -0
- package/package.json +54 -0
package/dist/usage.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage safety classifier — the single safety primitive both wrap tiers depend on.
|
|
3
|
+
*
|
|
4
|
+
* `editable()` stega-encodes EVERY string leaf of the value it wraps (see
|
|
5
|
+
* `@caretcms/core`'s encodeLeaves). An encoded string is invisible and harmless
|
|
6
|
+
* when it renders as visible TEXT, but it CORRUPTS anything it lands in as an
|
|
7
|
+
* attribute — a broken href/src/class/id/datetime. So a literal const is only
|
|
8
|
+
* safe to wrap when every field that flows out of it reaches the DOM as text and
|
|
9
|
+
* never as a native-element attribute.
|
|
10
|
+
*
|
|
11
|
+
* This module answers exactly that, from the `@astrojs/compiler` AST:
|
|
12
|
+
* - native element (`type:"element"`) + a DYNAMIC attribute that references a
|
|
13
|
+
* field of the value → UNSAFE.
|
|
14
|
+
* - native element text position (`{item.title}`) → safe.
|
|
15
|
+
* - component (`type:"component"`) attribute that references a field → a prop
|
|
16
|
+
* hand-off; reported so a cross-file pass can verify the child (Tier-2),
|
|
17
|
+
* and — depending on `componentHandoffUnsafe` — either tolerated (Tier-1,
|
|
18
|
+
* preserving prior behavior) or treated as unprovable/UNSAFE (Tier-2 child).
|
|
19
|
+
*
|
|
20
|
+
* The bias is conservative throughout: anything we cannot positively prove is
|
|
21
|
+
* text-only is reported UNSAFE. False negatives (a safe const left unwrapped)
|
|
22
|
+
* are acceptable; a false positive (encoding into an attribute) is not. In line
|
|
23
|
+
* with that, the loop-variable scan over-approximates — within an expression
|
|
24
|
+
* that mentions the const, EVERY `.map()`/`.flatMap()` binding is treated as
|
|
25
|
+
* carrying a field of it, so nested and chained loops can never smuggle a field
|
|
26
|
+
* into an attribute unnoticed.
|
|
27
|
+
*/
|
|
28
|
+
import { walkTags, isTagNode } from "./parse.js";
|
|
29
|
+
import { IDENT, identRefRe, referencesIdent } from "./identifiers.js";
|
|
30
|
+
const HTML_DIRECTIVES = new Set(["set:html", "set:text"]);
|
|
31
|
+
/** Concatenated raw JS text of an expression node's direct text children. */
|
|
32
|
+
function exprJs(node) {
|
|
33
|
+
let s = "";
|
|
34
|
+
for (const child of node.children ?? []) {
|
|
35
|
+
if (child.type === "text")
|
|
36
|
+
s += child.value ?? "";
|
|
37
|
+
}
|
|
38
|
+
return s;
|
|
39
|
+
}
|
|
40
|
+
/** The first parameter of an arrow/function param list, respecting brackets. */
|
|
41
|
+
function firstParam(paramSrc) {
|
|
42
|
+
let depth = 0;
|
|
43
|
+
let out = "";
|
|
44
|
+
for (const c of paramSrc) {
|
|
45
|
+
if (c === "{" || c === "[" || c === "(")
|
|
46
|
+
depth++;
|
|
47
|
+
else if (c === "}" || c === "]" || c === ")")
|
|
48
|
+
depth--;
|
|
49
|
+
else if (c === "," && depth === 0)
|
|
50
|
+
break;
|
|
51
|
+
out += c;
|
|
52
|
+
}
|
|
53
|
+
return out.trim();
|
|
54
|
+
}
|
|
55
|
+
/** Identifiers bound by a single callback parameter (plain or destructured). */
|
|
56
|
+
function paramIdents(param) {
|
|
57
|
+
if (!param)
|
|
58
|
+
return [];
|
|
59
|
+
if (param.startsWith("{") || param.startsWith("[")) {
|
|
60
|
+
// Destructuring: collect every binding identifier. For `{ a: b }` the bound
|
|
61
|
+
// local is `b`; over-collecting (keeping `a` too) only makes us more
|
|
62
|
+
// conservative, which is safe. Rest elements (`...rest`) included likewise.
|
|
63
|
+
const out = [];
|
|
64
|
+
for (const tok of param.replace(/[[\]{}.]/g, " ").split(/[,\s:=]+/)) {
|
|
65
|
+
const t = tok.trim();
|
|
66
|
+
if (IDENT.test(t))
|
|
67
|
+
out.push(t);
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
// Plain param, possibly with a default (`item = {}`): keep the binding name.
|
|
72
|
+
const name = param.split("=")[0].trim();
|
|
73
|
+
return IDENT.test(name) ? [name] : [];
|
|
74
|
+
}
|
|
75
|
+
/** Read the callback's first-parameter source starting just after `map(`. */
|
|
76
|
+
function readCallbackFirstParam(js, from) {
|
|
77
|
+
let i = from;
|
|
78
|
+
const skipWs = () => {
|
|
79
|
+
while (i < js.length && /\s/.test(js[i]))
|
|
80
|
+
i++;
|
|
81
|
+
};
|
|
82
|
+
skipWs();
|
|
83
|
+
if (js.startsWith("async", i) && /[\s(]/.test(js[i + 5] ?? ""))
|
|
84
|
+
i += 5; // async arrow
|
|
85
|
+
skipWs();
|
|
86
|
+
if (js.startsWith("function", i)) {
|
|
87
|
+
const paren = js.indexOf("(", i);
|
|
88
|
+
if (paren < 0)
|
|
89
|
+
return "";
|
|
90
|
+
i = paren;
|
|
91
|
+
}
|
|
92
|
+
if (js[i] === "(") {
|
|
93
|
+
let depth = 0;
|
|
94
|
+
let src = "";
|
|
95
|
+
for (; i < js.length; i++) {
|
|
96
|
+
const c = js[i];
|
|
97
|
+
if (c === "(")
|
|
98
|
+
depth++;
|
|
99
|
+
else if (c === ")") {
|
|
100
|
+
depth--;
|
|
101
|
+
if (depth === 0)
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
else if (depth >= 1)
|
|
105
|
+
src += c;
|
|
106
|
+
}
|
|
107
|
+
return firstParam(src);
|
|
108
|
+
}
|
|
109
|
+
// Parenless arrow: `x => …` — read up to `=>`, `,` or `)`.
|
|
110
|
+
let src = "";
|
|
111
|
+
while (i < js.length && !/[=,)\s]/.test(js[i]))
|
|
112
|
+
src += js[i++];
|
|
113
|
+
return src;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Loop-binding identifiers introduced by `.map()`/`.flatMap()` callbacks in a JS
|
|
117
|
+
* fragment. With `receiver`, only loops over that exact variable are read; with
|
|
118
|
+
* no receiver, EVERY map/flatMap is read (the conservative scan used during
|
|
119
|
+
* classification, so chained/nested loops can't hide a field).
|
|
120
|
+
*/
|
|
121
|
+
export function mapParamIdents(js, receiver) {
|
|
122
|
+
const idents = new Set();
|
|
123
|
+
const head = receiver
|
|
124
|
+
? `${identRefRe(receiver).source}\\s*\\.\\s*(?:map|flatMap)\\s*\\(`
|
|
125
|
+
: `\\.\\s*(?:map|flatMap)\\s*\\(`;
|
|
126
|
+
const re = new RegExp(head, "g");
|
|
127
|
+
let m;
|
|
128
|
+
while ((m = re.exec(js))) {
|
|
129
|
+
for (const id of paramIdents(readCallbackFirstParam(js, m.index + m[0].length))) {
|
|
130
|
+
idents.add(id);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return [...idents];
|
|
134
|
+
}
|
|
135
|
+
/** Attribute kinds that can carry a JS reference (static `quoted`/`empty` cannot). */
|
|
136
|
+
function attrIsDynamic(kind) {
|
|
137
|
+
return kind === "expression" || kind === "template-literal" || kind === "shorthand" || kind === "spread";
|
|
138
|
+
}
|
|
139
|
+
/** Does this attribute reference any of `names` (its value, raw, or shorthand/spread name)? */
|
|
140
|
+
function attrReferences(attr, names) {
|
|
141
|
+
if (attr.kind === "shorthand" || attr.kind === "spread") {
|
|
142
|
+
// `{name}` / `{...name}` — the identifier is the attribute name.
|
|
143
|
+
return names.includes(attr.name) || referencesIdent(attr.name, names);
|
|
144
|
+
}
|
|
145
|
+
return referencesIdent(`${attr.value} ${attr.raw ?? ""}`, names);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Classify how a literal const `varName` is consumed in a parsed template.
|
|
149
|
+
*
|
|
150
|
+
* For every tag node, the field-carrying identifiers in scope are `varName`
|
|
151
|
+
* itself plus the binding variables of any ancestor expression that mentions
|
|
152
|
+
* `varName` and loops. A dynamic attribute referencing one of those names is the
|
|
153
|
+
* encoded value escaping into a sink: a native element → UNSAFE; a component → a
|
|
154
|
+
* recorded prop hand-off (and UNSAFE too under `componentHandoffUnsafe`). Text
|
|
155
|
+
* positions (`{item.x}` as an element's child) are never attributes, so they
|
|
156
|
+
* never trip this — exactly the leaves `editable()` can safely encode.
|
|
157
|
+
*/
|
|
158
|
+
export function classifyConstUsage(root, varName, opts = {}) {
|
|
159
|
+
const handoffs = [];
|
|
160
|
+
let unsafe;
|
|
161
|
+
const varRe = identRefRe(varName);
|
|
162
|
+
walkTags(root, (node, ancestors) => {
|
|
163
|
+
const names = [varName];
|
|
164
|
+
for (const anc of ancestors) {
|
|
165
|
+
if (anc.type !== "expression")
|
|
166
|
+
continue;
|
|
167
|
+
const js = exprJs(anc);
|
|
168
|
+
if (varRe.test(js))
|
|
169
|
+
names.push(...mapParamIdents(js));
|
|
170
|
+
}
|
|
171
|
+
for (const attr of node.attributes) {
|
|
172
|
+
if (!attrIsDynamic(attr.kind))
|
|
173
|
+
continue; // static `quoted`/`empty` are inert
|
|
174
|
+
if (!attrReferences(attr, names))
|
|
175
|
+
continue;
|
|
176
|
+
if (node.type === "element") {
|
|
177
|
+
// set:html / set:text render the value as CONTENT, not a real attribute;
|
|
178
|
+
// stega survives there, so (when opted in) it's a safe text sink.
|
|
179
|
+
if (opts.htmlDirectivesSafe && HTML_DIRECTIVES.has(attr.name))
|
|
180
|
+
continue;
|
|
181
|
+
// Encoded field would land in a real DOM attribute → corrupting.
|
|
182
|
+
unsafe ??= `field of "${varName}" used in <${node.name}> attribute "${attr.name}"`;
|
|
183
|
+
}
|
|
184
|
+
else if (node.type === "component") {
|
|
185
|
+
handoffs.push({ component: node.name, prop: attr.name });
|
|
186
|
+
if (opts.componentHandoffUnsafe) {
|
|
187
|
+
unsafe ??= `field of "${varName}" handed to <${node.name}> prop "${attr.name}" (child not verified)`;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
// custom-element / fragment — unknown rendering; be conservative.
|
|
192
|
+
unsafe ??= `field of "${varName}" used on <${node.name}> (unverifiable)`;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
if (unsafe)
|
|
197
|
+
return { safe: false, reason: unsafe, handoffs };
|
|
198
|
+
return { safe: true, handoffs };
|
|
199
|
+
}
|
|
200
|
+
/** Elements that live in (or feed) the document `<head>`. A field rendered only
|
|
201
|
+
* here is text-safe for stega, but the inline editor's click-to-edit can never
|
|
202
|
+
* surface it — so it isn't a real editable sink. */
|
|
203
|
+
const HEAD_ELEMENTS = new Set(["head", "title", "meta", "base", "link"]);
|
|
204
|
+
function inHead(ancestors, node) {
|
|
205
|
+
if (node && isTagNode(node) && HEAD_ELEMENTS.has(node.name))
|
|
206
|
+
return true;
|
|
207
|
+
return ancestors.some((a) => isTagNode(a) && HEAD_ELEMENTS.has(a.name));
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Does the template render any of `names` in a BODY-reachable position — a text
|
|
211
|
+
* expression (`{title}`) or a `set:html`/`set:text` content sink — that is NOT
|
|
212
|
+
* inside the document `<head>`?
|
|
213
|
+
*
|
|
214
|
+
* `classifyConstUsage` proves a field never lands in a corrupting attribute, but
|
|
215
|
+
* a field that renders ONLY into `<head>` (a layout's `<title>{title}</title>`)
|
|
216
|
+
* is text-safe yet has no click-to-edit target. The prop-hoist tier requires a
|
|
217
|
+
* positive body sink so it doesn't mint `editable()` bindings the editor can't
|
|
218
|
+
* surface (and, incidentally, won't hoist a prop the child never renders at all).
|
|
219
|
+
*/
|
|
220
|
+
export function rendersOutsideHead(root, names) {
|
|
221
|
+
let found = false;
|
|
222
|
+
const stack = [];
|
|
223
|
+
const visit = (node) => {
|
|
224
|
+
if (found || !node || typeof node !== "object")
|
|
225
|
+
return;
|
|
226
|
+
if (node.type === "expression" && referencesIdent(exprJs(node), names) && !inHead(stack)) {
|
|
227
|
+
found = true;
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (isTagNode(node) && !inHead(stack, node)) {
|
|
231
|
+
for (const attr of node.attributes) {
|
|
232
|
+
if (HTML_DIRECTIVES.has(attr.name) && attrReferences(attr, names)) {
|
|
233
|
+
found = true;
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const children = node.children;
|
|
239
|
+
if (Array.isArray(children)) {
|
|
240
|
+
stack.push(node);
|
|
241
|
+
for (const child of children)
|
|
242
|
+
visit(child);
|
|
243
|
+
stack.pop();
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
visit(root);
|
|
247
|
+
return found;
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAmCtE,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;AAE1D,6EAA6E;AAC7E,SAAS,MAAM,CAAC,IAAe;IAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QACxC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,CAAC,IAAK,KAA4B,CAAC,KAAK,IAAI,EAAE,CAAC;IAC5E,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,gFAAgF;AAChF,SAAS,UAAU,CAAC,QAAgB;IAClC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aAC5C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aACjD,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,KAAK,CAAC;YAAE,MAAM;QACzC,GAAG,IAAI,CAAC,CAAC;IACX,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,gFAAgF;AAChF,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,4EAA4E;QAC5E,qEAAqE;QACrE,4EAA4E;QAC5E,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YACpE,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;YACrB,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,6EAA6E;IAC7E,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxC,CAAC;AAED,6EAA6E;AAC7E,SAAS,sBAAsB,CAAC,EAAU,EAAE,IAAY;IACtD,IAAI,CAAC,GAAG,IAAI,CAAC;IACb,MAAM,MAAM,GAAG,GAAS,EAAE;QACxB,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAAE,CAAC,EAAE,CAAC;IAChD,CAAC,CAAC;IACF,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAAE,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc;IACtF,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACjC,IAAI,KAAK,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QACzB,CAAC,GAAG,KAAK,CAAC;IACZ,CAAC;IACD,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;QAClB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;YAChB,IAAI,CAAC,KAAK,GAAG;gBAAE,KAAK,EAAE,CAAC;iBAClB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBACnB,KAAK,EAAE,CAAC;gBACR,IAAI,KAAK,KAAK,CAAC;oBAAE,MAAM;YACzB,CAAC;iBAAM,IAAI,KAAK,IAAI,CAAC;gBAAE,GAAG,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IACD,2DAA2D;IAC3D,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAAE,GAAG,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/D,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,EAAU,EAAE,QAAiB;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,MAAM,IAAI,GAAG,QAAQ;QACnB,CAAC,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,mCAAmC;QACnE,CAAC,CAAC,+BAA+B,CAAC;IACpC,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACjC,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,EAAE,IAAI,WAAW,CAAC,sBAAsB,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YAChF,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;AACrB,CAAC;AAED,sFAAsF;AACtF,SAAS,aAAa,CAAC,IAAwB;IAC7C,OAAO,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,kBAAkB,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,QAAQ,CAAC;AAC3G,CAAC;AAED,+FAA+F;AAC/F,SAAS,cAAc,CAAC,IAAmC,EAAE,KAAe;IAC1E,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACxD,iEAAiE;QACjE,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,eAAe,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAe,EACf,OAAe,EACf,OAAwB,EAAE;IAE1B,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,MAA0B,CAAC;IAC/B,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAElC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE;QACjC,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC;QACxB,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC5B,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY;gBAAE,SAAS;YACxC,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;QACxD,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACnC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,SAAS,CAAC,oCAAoC;YAC7E,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC;gBAAE,SAAS;YAE3C,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC5B,yEAAyE;gBACzE,kEAAkE;gBAClE,IAAI,IAAI,CAAC,kBAAkB,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE,SAAS;gBACxE,iEAAiE;gBACjE,MAAM,KAAK,aAAa,OAAO,cAAc,IAAI,CAAC,IAAI,gBAAgB,IAAI,CAAC,IAAI,GAAG,CAAC;YACrF,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBACzD,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;oBAChC,MAAM,KAAK,aAAa,OAAO,gBAAgB,IAAI,CAAC,IAAI,WAAW,IAAI,CAAC,IAAI,wBAAwB,CAAC;gBACvG,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,kEAAkE;gBAClE,MAAM,KAAK,aAAa,OAAO,cAAc,IAAI,CAAC,IAAI,kBAAkB,CAAC;YAC3E,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC7D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAClC,CAAC;AAED;;qDAEqD;AACrD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEzE,SAAS,MAAM,CAAC,SAAsB,EAAE,IAAgB;IACtD,IAAI,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACzE,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAe,EAAE,KAAe;IACjE,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,CAAC,IAAe,EAAQ,EAAE;QACtC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO;QAEvD,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACzF,KAAK,GAAG,IAAI,CAAC;YACb,OAAO;QACT,CAAC;QACD,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;YAC5C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACnC,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;oBAClE,KAAK,GAAG,IAAI,CAAC;oBACb,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,KAAK,MAAM,KAAK,IAAI,QAAQ;gBAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YAC3C,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,CAAC;IACH,CAAC,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/wrap.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-1 editable() wrapping — PURE INSERTION.
|
|
3
|
+
*
|
|
4
|
+
* Wraps a frontmatter `const`/`let`/`var` initializer with
|
|
5
|
+
* `await editable('key', …)` and inserts the import, WITHOUT moving any code:
|
|
6
|
+
* the original initializer is preserved verbatim between two inserted spans, so
|
|
7
|
+
* the transform is provably reversible (strip the inserted text → original
|
|
8
|
+
* restored) — the same safety contract as caretize's attribute insertion.
|
|
9
|
+
*
|
|
10
|
+
* const services = ['a', 'b'];
|
|
11
|
+
* → const services = await editable("pages::home::services", ['a', 'b']);
|
|
12
|
+
* (+ `import { editable } from '@caretcms/core';` at the top of frontmatter)
|
|
13
|
+
*
|
|
14
|
+
* Restructuring cases (an inline array literal inside JSX that must be hoisted
|
|
15
|
+
* to frontmatter) are intentionally NOT handled here — that breaks pure
|
|
16
|
+
* insertion and belongs to a separate, opt-in migrator.
|
|
17
|
+
*/
|
|
18
|
+
import { type AstroNode } from "./parse.js";
|
|
19
|
+
/** The `editable()` import line + a detector for it, shared with import-wrap.ts. */
|
|
20
|
+
export declare const IMPORT_LINE = "import { editable } from '@caretcms/core';";
|
|
21
|
+
export declare const IMPORT_RE: RegExp;
|
|
22
|
+
/** A literal const the wrapper could target, before its provenance is known. */
|
|
23
|
+
export interface WrapCandidate {
|
|
24
|
+
/** Frontmatter const/let/var to wrap. */
|
|
25
|
+
varName: string;
|
|
26
|
+
/** Binding key, e.g. `pages::home::services`. */
|
|
27
|
+
key: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* How a wrap target was found:
|
|
31
|
+
* - `loop` — a same-file literal const iterated in the template (Tier-1)
|
|
32
|
+
* - `prop` — a literal const passed to a component that renders it as text (Tier-2)
|
|
33
|
+
* - `import` — a default JSON/module import iterated in the template (Tier-3)
|
|
34
|
+
*/
|
|
35
|
+
export type WrapOrigin = "loop" | "prop" | "import";
|
|
36
|
+
/** A safety-verified wrap target, tagged with how it was found. */
|
|
37
|
+
export interface WrapTarget extends WrapCandidate {
|
|
38
|
+
origin: WrapOrigin;
|
|
39
|
+
}
|
|
40
|
+
export interface WrapResult {
|
|
41
|
+
output: string;
|
|
42
|
+
ok: boolean;
|
|
43
|
+
/** Reason when ok === false. */
|
|
44
|
+
reason?: string;
|
|
45
|
+
/** True when the source already had the wrap (no-op, idempotent). */
|
|
46
|
+
alreadyWrapped?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Wrap the initializer of `const <varName> = …` in the frontmatter with
|
|
50
|
+
* `await editable('<key>', …)` and ensure the import is present. Pure insertion.
|
|
51
|
+
*/
|
|
52
|
+
export declare function wrapConst(source: string, varName: string, key: string): WrapResult;
|
|
53
|
+
/**
|
|
54
|
+
* Detect Tier-1 wrap targets: frontmatter consts initialized to an array/object
|
|
55
|
+
* LITERAL that are `.map()`/`.flatMap()`'d in the template. Only literal-inited
|
|
56
|
+
* consts qualify — loops over fetched data (getCollection/await) or imports
|
|
57
|
+
* aren't inline content and are left alone. The key is derived from the file's
|
|
58
|
+
* scope (`collection::id`) plus the variable name as the field.
|
|
59
|
+
*/
|
|
60
|
+
export declare function detectWrapTargets(source: string, relPath: string): WrapCandidate[];
|
|
61
|
+
/**
|
|
62
|
+
* Safety-checked Tier-1 detection: the literal-const candidates from
|
|
63
|
+
* `detectWrapTargets`, minus any whose mapped fields flow into a native-element
|
|
64
|
+
* attribute (where `editable()`'s stega encoding would corrupt an href/src/class
|
|
65
|
+
* /…). Component prop hand-offs are tolerated here — Tier-1's long-standing
|
|
66
|
+
* behavior — and verified across files by the Tier-2 prop pass instead.
|
|
67
|
+
*
|
|
68
|
+
* Async because the safety check needs the parsed AST; `root` may be passed when
|
|
69
|
+
* the caller has already parsed `source` (the CLI does, to avoid re-parsing).
|
|
70
|
+
*/
|
|
71
|
+
export declare function detectWrapTargetsSafe(source: string, relPath: string, root?: AstroNode): Promise<WrapTarget[]>;
|
|
72
|
+
//# sourceMappingURL=wrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap.d.ts","sourceRoot":"","sources":["../src/wrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAKxD,oFAAoF;AACpF,eAAO,MAAM,WAAW,+CAA+C,CAAC;AACxE,eAAO,MAAM,SAAS,QACkD,CAAC;AAEzE,gFAAgF;AAChF,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEpD,mEAAmE;AACnE,MAAM,WAAW,UAAW,SAAQ,aAAa;IAC/C,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAmCD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAiDlF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CA+BlF;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,SAAS,GACf,OAAO,CAAC,UAAU,EAAE,CAAC,CAOvB"}
|
package/dist/wrap.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-1 editable() wrapping — PURE INSERTION.
|
|
3
|
+
*
|
|
4
|
+
* Wraps a frontmatter `const`/`let`/`var` initializer with
|
|
5
|
+
* `await editable('key', …)` and inserts the import, WITHOUT moving any code:
|
|
6
|
+
* the original initializer is preserved verbatim between two inserted spans, so
|
|
7
|
+
* the transform is provably reversible (strip the inserted text → original
|
|
8
|
+
* restored) — the same safety contract as caretize's attribute insertion.
|
|
9
|
+
*
|
|
10
|
+
* const services = ['a', 'b'];
|
|
11
|
+
* → const services = await editable("pages::home::services", ['a', 'b']);
|
|
12
|
+
* (+ `import { editable } from '@caretcms/core';` at the top of frontmatter)
|
|
13
|
+
*
|
|
14
|
+
* Restructuring cases (an inline array literal inside JSX that must be hoisted
|
|
15
|
+
* to frontmatter) are intentionally NOT handled here — that breaks pure
|
|
16
|
+
* insertion and belongs to a separate, opt-in migrator.
|
|
17
|
+
*/
|
|
18
|
+
import { deriveScope, isValidField, slugifyText } from "./name.js";
|
|
19
|
+
import { parseAstro } from "./parse.js";
|
|
20
|
+
import { classifyConstUsage } from "./usage.js";
|
|
21
|
+
import { frontmatterRange, literalConstNames } from "./frontmatter.js";
|
|
22
|
+
import { isIdentifier } from "./identifiers.js";
|
|
23
|
+
/** The `editable()` import line + a detector for it, shared with import-wrap.ts. */
|
|
24
|
+
export const IMPORT_LINE = `import { editable } from '@caretcms/core';`;
|
|
25
|
+
export const IMPORT_RE = /import\s*\{[^}]*\beditable\b[^}]*\}\s*from\s*['"]@caretcms\/core['"]/;
|
|
26
|
+
/**
|
|
27
|
+
* Given the offset of `=`, return the offset just past the initializer
|
|
28
|
+
* expression by balancing brackets and skipping strings. Stops at a `;` or
|
|
29
|
+
* newline encountered at bracket-depth 0.
|
|
30
|
+
*/
|
|
31
|
+
function initializerEnd(source, eq, limit) {
|
|
32
|
+
let i = eq + 1;
|
|
33
|
+
while (i < limit && /\s/.test(source[i]))
|
|
34
|
+
i++;
|
|
35
|
+
if (i >= limit)
|
|
36
|
+
return null;
|
|
37
|
+
let depth = 0;
|
|
38
|
+
let quote = null;
|
|
39
|
+
for (; i < limit; i++) {
|
|
40
|
+
const c = source[i];
|
|
41
|
+
if (quote) {
|
|
42
|
+
if (c === "\\") {
|
|
43
|
+
i++;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (c === quote)
|
|
47
|
+
quote = null;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
51
|
+
quote = c;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (c === "[" || c === "(" || c === "{")
|
|
55
|
+
depth++;
|
|
56
|
+
else if (c === "]" || c === ")" || c === "}")
|
|
57
|
+
depth--;
|
|
58
|
+
else if (depth === 0 && (c === ";" || c === "\n"))
|
|
59
|
+
return i;
|
|
60
|
+
}
|
|
61
|
+
return depth === 0 ? limit : null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Wrap the initializer of `const <varName> = …` in the frontmatter with
|
|
65
|
+
* `await editable('<key>', …)` and ensure the import is present. Pure insertion.
|
|
66
|
+
*/
|
|
67
|
+
export function wrapConst(source, varName, key) {
|
|
68
|
+
if (!isIdentifier(varName)) {
|
|
69
|
+
return { output: source, ok: false, reason: `invalid identifier: ${varName}` };
|
|
70
|
+
}
|
|
71
|
+
const fm = frontmatterRange(source);
|
|
72
|
+
if (!fm)
|
|
73
|
+
return { output: source, ok: false, reason: "no frontmatter block" };
|
|
74
|
+
const fmText = source.slice(fm.start, fm.end);
|
|
75
|
+
const declRe = new RegExp(`\\b(?:const|let|var)\\s+${varName}\\b`);
|
|
76
|
+
const m = declRe.exec(fmText);
|
|
77
|
+
if (!m) {
|
|
78
|
+
return { output: source, ok: false, reason: `declaration of ${varName} not found in frontmatter` };
|
|
79
|
+
}
|
|
80
|
+
const eqRel = fmText.indexOf("=", m.index + m[0].length);
|
|
81
|
+
if (eqRel < 0)
|
|
82
|
+
return { output: source, ok: false, reason: "no initializer" };
|
|
83
|
+
const eqAbs = fm.start + eqRel;
|
|
84
|
+
// Idempotent: bail if already wrapped.
|
|
85
|
+
if (/^\s*await\s+editable\s*\(/.test(source.slice(eqAbs + 1, eqAbs + 48))) {
|
|
86
|
+
return { output: source, ok: true, alreadyWrapped: true };
|
|
87
|
+
}
|
|
88
|
+
let initStart = eqAbs + 1;
|
|
89
|
+
while (initStart < fm.end && /\s/.test(source[initStart]))
|
|
90
|
+
initStart++;
|
|
91
|
+
const initEnd = initializerEnd(source, eqAbs, fm.end);
|
|
92
|
+
if (initEnd === null || initStart >= fm.end) {
|
|
93
|
+
return { output: source, ok: false, reason: "could not bound initializer" };
|
|
94
|
+
}
|
|
95
|
+
const prefix = `await editable(${JSON.stringify(key)}, `;
|
|
96
|
+
const suffix = `)`;
|
|
97
|
+
// Pure insertion: keep every original character, add prefix/suffix around the
|
|
98
|
+
// untouched initializer.
|
|
99
|
+
let output = source.slice(0, initStart) +
|
|
100
|
+
prefix +
|
|
101
|
+
source.slice(initStart, initEnd) +
|
|
102
|
+
suffix +
|
|
103
|
+
source.slice(initEnd);
|
|
104
|
+
// Add the import at the top of the frontmatter unless it's already there.
|
|
105
|
+
if (!IMPORT_RE.test(source)) {
|
|
106
|
+
output = output.slice(0, fm.start) + IMPORT_LINE + "\n" + output.slice(fm.start);
|
|
107
|
+
}
|
|
108
|
+
return { output, ok: true };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Detect Tier-1 wrap targets: frontmatter consts initialized to an array/object
|
|
112
|
+
* LITERAL that are `.map()`/`.flatMap()`'d in the template. Only literal-inited
|
|
113
|
+
* consts qualify — loops over fetched data (getCollection/await) or imports
|
|
114
|
+
* aren't inline content and are left alone. The key is derived from the file's
|
|
115
|
+
* scope (`collection::id`) plus the variable name as the field.
|
|
116
|
+
*/
|
|
117
|
+
export function detectWrapTargets(source, relPath) {
|
|
118
|
+
const fm = frontmatterRange(source);
|
|
119
|
+
if (!fm)
|
|
120
|
+
return [];
|
|
121
|
+
const fmText = source.slice(fm.start, fm.end);
|
|
122
|
+
const template = source.slice(fm.end);
|
|
123
|
+
// 1. frontmatter consts whose initializer is an array/object literal
|
|
124
|
+
const literalConsts = literalConstNames(fmText);
|
|
125
|
+
if (literalConsts.size === 0)
|
|
126
|
+
return [];
|
|
127
|
+
// 2. of those, the ones actually iterated in the template
|
|
128
|
+
const mapped = new Set();
|
|
129
|
+
const mapRe = /\b([A-Za-z_$][\w$]*)\s*\.\s*(?:map|flatMap)\b/g;
|
|
130
|
+
let mm;
|
|
131
|
+
while ((mm = mapRe.exec(template))) {
|
|
132
|
+
if (literalConsts.has(mm[1]))
|
|
133
|
+
mapped.add(mm[1]);
|
|
134
|
+
}
|
|
135
|
+
if (mapped.size === 0)
|
|
136
|
+
return [];
|
|
137
|
+
// 3. derive the scope + a key per target
|
|
138
|
+
const scoped = deriveScope(relPath);
|
|
139
|
+
if ("skip" in scoped)
|
|
140
|
+
return [];
|
|
141
|
+
const { collection, id } = scoped.scope;
|
|
142
|
+
const candidates = [];
|
|
143
|
+
for (const varName of mapped) {
|
|
144
|
+
const field = isValidField(varName) ? varName : slugifyText(varName);
|
|
145
|
+
if (!field)
|
|
146
|
+
continue;
|
|
147
|
+
candidates.push({ varName, key: `${collection}::${id}::${field}` });
|
|
148
|
+
}
|
|
149
|
+
return candidates;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Safety-checked Tier-1 detection: the literal-const candidates from
|
|
153
|
+
* `detectWrapTargets`, minus any whose mapped fields flow into a native-element
|
|
154
|
+
* attribute (where `editable()`'s stega encoding would corrupt an href/src/class
|
|
155
|
+
* /…). Component prop hand-offs are tolerated here — Tier-1's long-standing
|
|
156
|
+
* behavior — and verified across files by the Tier-2 prop pass instead.
|
|
157
|
+
*
|
|
158
|
+
* Async because the safety check needs the parsed AST; `root` may be passed when
|
|
159
|
+
* the caller has already parsed `source` (the CLI does, to avoid re-parsing).
|
|
160
|
+
*/
|
|
161
|
+
export async function detectWrapTargetsSafe(source, relPath, root) {
|
|
162
|
+
const candidates = detectWrapTargets(source, relPath);
|
|
163
|
+
if (candidates.length === 0)
|
|
164
|
+
return [];
|
|
165
|
+
const ast = root ?? (await parseAstro(source));
|
|
166
|
+
return candidates
|
|
167
|
+
.filter((t) => classifyConstUsage(ast, t.varName).safe)
|
|
168
|
+
.map((t) => ({ ...t, origin: "loop" }));
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=wrap.js.map
|
package/dist/wrap.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap.js","sourceRoot":"","sources":["../src/wrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,UAAU,EAAkB,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,oFAAoF;AACpF,MAAM,CAAC,MAAM,WAAW,GAAG,4CAA4C,CAAC;AACxE,MAAM,CAAC,MAAM,SAAS,GACpB,sEAAsE,CAAC;AAgCzE;;;;GAIG;AACH,SAAS,cAAc,CAAC,MAAc,EAAE,EAAU,EAAE,KAAa;IAC/D,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACf,OAAO,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAAE,CAAC,EAAE,CAAC;IAC9C,IAAI,CAAC,IAAI,KAAK;QAAE,OAAO,IAAI,CAAC;IAE5B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,OAAO,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gBACf,CAAC,EAAE,CAAC;gBACJ,SAAS;YACX,CAAC;YACD,IAAI,CAAC,KAAK,KAAK;gBAAE,KAAK,GAAG,IAAI,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACxC,KAAK,GAAG,CAAC,CAAC;YACV,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aAC5C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aACjD,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,OAAe,EAAE,GAAW;IACpE,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,OAAO,EAAE,EAAE,CAAC;IACjF,CAAC;IAED,MAAM,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IAE9E,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,2BAA2B,OAAO,KAAK,CAAC,CAAC;IACnE,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,OAAO,2BAA2B,EAAE,CAAC;IACrG,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACzD,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC9E,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC;IAE/B,uCAAuC;IACvC,IAAI,2BAA2B,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QAC1E,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;IAC5D,CAAC;IAED,IAAI,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;IAC1B,OAAO,SAAS,GAAG,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAAE,SAAS,EAAE,CAAC;IACvE,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IACtD,IAAI,OAAO,KAAK,IAAI,IAAI,SAAS,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;QAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,6BAA6B,EAAE,CAAC;IAC9E,CAAC;IAED,MAAM,MAAM,GAAG,kBAAkB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;IACzD,MAAM,MAAM,GAAG,GAAG,CAAC;IAEnB,8EAA8E;IAC9E,yBAAyB;IACzB,IAAI,MAAM,GACR,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC;QAC1B,MAAM;QACN,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC;QAChC,MAAM;QACN,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAExB,0EAA0E;IAC1E,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,WAAW,GAAG,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IACnF,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,OAAe;IAC/D,MAAM,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,CAAC;IACnB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IAEtC,qEAAqE;IACrE,MAAM,aAAa,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,aAAa,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAExC,0DAA0D;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,MAAM,KAAK,GAAG,gDAAgD,CAAC;IAC/D,IAAI,EAA0B,CAAC;IAC/B,OAAO,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QACnC,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjC,yCAAyC;IACzC,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,MAAM,IAAI,MAAM;QAAE,OAAO,EAAE,CAAC;IAChC,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC;IAExC,MAAM,UAAU,GAAoB,EAAE,CAAC;IACvC,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACrE,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,UAAU,KAAK,EAAE,KAAK,KAAK,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAc,EACd,OAAe,EACf,IAAgB;IAEhB,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACvC,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/C,OAAO,UAAU;SACd,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;SACtD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,MAAe,EAAE,CAAC,CAAC,CAAC;AACrD,CAAC"}
|
package/dist/write.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The multi-tag writer primitive: splice many `data-caret` attributes into one
|
|
3
|
+
* source. Works on a UTF-8 Buffer (byte offsets) and applies insertions
|
|
4
|
+
* right-to-left so each splice leaves the not-yet-applied (smaller) offsets
|
|
5
|
+
* valid. Pure insertion only — never reformats.
|
|
6
|
+
*
|
|
7
|
+
* This is the in-memory core; the CLI layer wraps it with backups + atomic
|
|
8
|
+
* file writes + a re-parse verification gate.
|
|
9
|
+
*/
|
|
10
|
+
export interface TagInsertion {
|
|
11
|
+
/** Byte offset of the target element's opening `<`. */
|
|
12
|
+
startOffset: number;
|
|
13
|
+
/** Attribute text WITHOUT a leading space, e.g. `data-caret="a::b::c"`. */
|
|
14
|
+
attribute: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ApplyResult {
|
|
17
|
+
output: string;
|
|
18
|
+
/** The exact strings inserted (each with its leading space), in source
|
|
19
|
+
* order — useful for reversibility checks. */
|
|
20
|
+
inserted: string[];
|
|
21
|
+
/** Insertions that could not be placed (their opening tag end wasn't found). */
|
|
22
|
+
failures: Array<{
|
|
23
|
+
startOffset: number;
|
|
24
|
+
reason: string;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export declare function applyTags(source: string, items: TagInsertion[]): ApplyResult;
|
|
28
|
+
//# sourceMappingURL=write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../src/write.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf;mDAC+C;IAC/C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gFAAgF;IAChF,QAAQ,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1D;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,WAAW,CA8B5E"}
|
package/dist/write.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The multi-tag writer primitive: splice many `data-caret` attributes into one
|
|
3
|
+
* source. Works on a UTF-8 Buffer (byte offsets) and applies insertions
|
|
4
|
+
* right-to-left so each splice leaves the not-yet-applied (smaller) offsets
|
|
5
|
+
* valid. Pure insertion only — never reformats.
|
|
6
|
+
*
|
|
7
|
+
* This is the in-memory core; the CLI layer wraps it with backups + atomic
|
|
8
|
+
* file writes + a re-parse verification gate.
|
|
9
|
+
*/
|
|
10
|
+
import { findOpenTagEnd } from "./splice.js";
|
|
11
|
+
export function applyTags(source, items) {
|
|
12
|
+
const buf = Buffer.from(source, "utf8");
|
|
13
|
+
const resolved = [];
|
|
14
|
+
const failures = [];
|
|
15
|
+
for (const item of items) {
|
|
16
|
+
const found = findOpenTagEnd(buf, item.startOffset);
|
|
17
|
+
if (!found) {
|
|
18
|
+
failures.push({ startOffset: item.startOffset, reason: "open tag end not found" });
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
resolved.push({ insertAt: found.insertAt, text: ` ${item.attribute}` });
|
|
22
|
+
}
|
|
23
|
+
// Apply largest-offset-first so earlier splices don't shift later targets.
|
|
24
|
+
resolved.sort((a, b) => b.insertAt - a.insertAt);
|
|
25
|
+
let out = buf;
|
|
26
|
+
for (const r of resolved) {
|
|
27
|
+
out = Buffer.concat([
|
|
28
|
+
out.subarray(0, r.insertAt),
|
|
29
|
+
Buffer.from(r.text, "utf8"),
|
|
30
|
+
out.subarray(r.insertAt),
|
|
31
|
+
]);
|
|
32
|
+
}
|
|
33
|
+
// Report inserted strings in source order (resolved is currently desc).
|
|
34
|
+
const inserted = [...resolved].sort((a, b) => a.insertAt - b.insertAt).map((r) => r.text);
|
|
35
|
+
return { output: out.toString("utf8"), inserted, failures };
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../src/write.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAkB7C,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,KAAqB;IAC7D,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAExC,MAAM,QAAQ,GAA8C,EAAE,CAAC;IAC/D,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC,CAAC;YACnF,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAEjD,IAAI,GAAG,GAAG,GAAG,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC;YAClB,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC;YAC3B,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;SACzB,CAAC,CAAC;IACL,CAAC;IAED,wEAAwE;IACxE,MAAM,QAAQ,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAE1F,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC9D,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@caretcms/caretize",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "CLI that scans an Astro project and interactively adds data-caret attributes, turning a static site into a CaretCMS-editable one.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"astro",
|
|
9
|
+
"cms",
|
|
10
|
+
"caret",
|
|
11
|
+
"codemod",
|
|
12
|
+
"cli",
|
|
13
|
+
"data-caret",
|
|
14
|
+
"inline-editing"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/web-stacked/caretcms/tree/main/packages/caretize#readme",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/web-stacked/caretcms.git",
|
|
20
|
+
"directory": "packages/caretize"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/web-stacked/caretcms/issues"
|
|
24
|
+
},
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"bin": {
|
|
28
|
+
"caretize": "./dist/cli.js"
|
|
29
|
+
},
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc -p tsconfig.build.json && chmod +x dist/cli.js",
|
|
41
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
42
|
+
"clean": "rm -rf dist"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@astrojs/compiler": "2.13.1"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "25.6.0",
|
|
52
|
+
"typescript": "6.0.3"
|
|
53
|
+
}
|
|
54
|
+
}
|