@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
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-4 prop hoisting — a guarded REWRITE (not pure insertion).
|
|
3
|
+
*
|
|
4
|
+
* The most common pattern caretize couldn't touch is a static string passed to a
|
|
5
|
+
* shared component as a prop:
|
|
6
|
+
*
|
|
7
|
+
* <PageHero title="ABOUT US" description="Since 2010 …" />
|
|
8
|
+
*
|
|
9
|
+
* The text never appears as a tag-able text leaf (it's an attribute on a
|
|
10
|
+
* component), and `data-caret` can't ride a component boundary. The fix is to
|
|
11
|
+
* hoist each literal into an `editable()` frontmatter const and reference it:
|
|
12
|
+
*
|
|
13
|
+
* const pageHeroTitle = await editable("pages::about::title", "ABOUT US");
|
|
14
|
+
* …
|
|
15
|
+
* <PageHero title={pageHeroTitle} description={pageHeroDesc} />
|
|
16
|
+
*
|
|
17
|
+
* Unlike the other tiers this DELETES bytes (the attribute literal), so it can't
|
|
18
|
+
* use the subsequence gate. Instead it is verified by an INVERSE check: undo
|
|
19
|
+
* every edit (swap the reference back to the literal, strip the const lines) and
|
|
20
|
+
* assert the result is byte-identical to the input — proving the only changes
|
|
21
|
+
* were the intended hoists. A hand-off is rewritten only on positive proof the
|
|
22
|
+
* child renders the prop as text (reusing the Tier-2 cross-file verifier), and
|
|
23
|
+
* only when the exact `prop="value"` token occurs exactly once (unambiguous).
|
|
24
|
+
*/
|
|
25
|
+
import { parseAstro, walkTags } from "./parse.js";
|
|
26
|
+
import { deriveScope, isValidField, slugifyText } from "./name.js";
|
|
27
|
+
import { resolveComponentImport } from "./resolve.js";
|
|
28
|
+
import { propLocalName } from "./props.js";
|
|
29
|
+
import { classifyConstUsage, rendersOutsideHead } from "./usage.js";
|
|
30
|
+
import { frontmatterRange } from "./frontmatter.js";
|
|
31
|
+
import { IMPORT_LINE, IMPORT_RE } from "./wrap.js";
|
|
32
|
+
const RICH_RE = (local) => new RegExp(`set:html\\s*=\\s*\\{[^}]*\\b${local}\\b[^}]*\\}`);
|
|
33
|
+
function ucFirst(s) {
|
|
34
|
+
return s ? s[0].toUpperCase() + s.slice(1) : s;
|
|
35
|
+
}
|
|
36
|
+
/** camelCase identifier from parts, e.g. ["PageHero","title"] → "pageHeroTitle". */
|
|
37
|
+
function camelIdent(parts) {
|
|
38
|
+
const words = parts.flatMap((p) => p.split(/[^A-Za-z0-9]+/)).filter(Boolean);
|
|
39
|
+
if (words.length === 0)
|
|
40
|
+
return "field";
|
|
41
|
+
return words
|
|
42
|
+
.map((w, i) => (i === 0 ? w[0].toLowerCase() + w.slice(1) : ucFirst(w)))
|
|
43
|
+
.join("");
|
|
44
|
+
}
|
|
45
|
+
function uniquify(base, used) {
|
|
46
|
+
let name = base;
|
|
47
|
+
let n = 2;
|
|
48
|
+
while (used.has(name))
|
|
49
|
+
name = `${base}_${n++}`;
|
|
50
|
+
used.add(name);
|
|
51
|
+
return name;
|
|
52
|
+
}
|
|
53
|
+
/** Existing frontmatter binding names, so hoisted consts never shadow one. */
|
|
54
|
+
function declaredNames(fmText) {
|
|
55
|
+
const set = new Set();
|
|
56
|
+
const re = /\b(?:const|let|var|import)\s+([A-Za-z_$][\w$]*)/g;
|
|
57
|
+
let m;
|
|
58
|
+
while ((m = re.exec(fmText)))
|
|
59
|
+
set.add(m[1]);
|
|
60
|
+
return set;
|
|
61
|
+
}
|
|
62
|
+
/** Existing data-caret field segments in the file, so keys stay unique. */
|
|
63
|
+
function usedFields(source) {
|
|
64
|
+
const set = new Set();
|
|
65
|
+
const re = /data-caret(?:-rich)?="[^"]*::([A-Za-z0-9_]+)"/g;
|
|
66
|
+
let m;
|
|
67
|
+
while ((m = re.exec(source)))
|
|
68
|
+
set.add(m[1]);
|
|
69
|
+
return set;
|
|
70
|
+
}
|
|
71
|
+
/** The exact `name="value"` (or single-quoted) token, if it occurs exactly once. */
|
|
72
|
+
function uniqueAttrToken(source, name, value) {
|
|
73
|
+
for (const q of ['"', "'"]) {
|
|
74
|
+
if (value.includes(q))
|
|
75
|
+
continue;
|
|
76
|
+
const tok = `${name}=${q}${value}${q}`;
|
|
77
|
+
const first = source.indexOf(tok);
|
|
78
|
+
if (first >= 0 && source.indexOf(tok, first + tok.length) < 0)
|
|
79
|
+
return tok;
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Detect prop-hoist targets: component invocations with static string props
|
|
85
|
+
* whose child provably renders them as text. `readFile` resolves sibling files.
|
|
86
|
+
*/
|
|
87
|
+
export async function detectPropHoistTargets(source, relPath, readFile, root) {
|
|
88
|
+
const scoped = deriveScope(relPath);
|
|
89
|
+
if ("skip" in scoped)
|
|
90
|
+
return [];
|
|
91
|
+
const { collection, id } = scoped.scope;
|
|
92
|
+
const fm = frontmatterRange(source);
|
|
93
|
+
if (!fm)
|
|
94
|
+
return [];
|
|
95
|
+
const fmText = source.slice(fm.start, fm.end);
|
|
96
|
+
const ast = root ?? (await parseAstro(source));
|
|
97
|
+
const usedConsts = declaredNames(fmText);
|
|
98
|
+
const fields = usedFields(source);
|
|
99
|
+
// Cache child source + its parsed AST across repeated component uses.
|
|
100
|
+
const childCache = new Map();
|
|
101
|
+
const readChild = async (rel) => {
|
|
102
|
+
if (!childCache.has(rel)) {
|
|
103
|
+
const src = readFile(rel);
|
|
104
|
+
childCache.set(rel, src === null ? null : { src, ast: await parseAstro(src) });
|
|
105
|
+
}
|
|
106
|
+
return childCache.get(rel) ?? null;
|
|
107
|
+
};
|
|
108
|
+
/** Does the child render `prop` purely as text (incl. set:html), no re-handoff,
|
|
109
|
+
* AND in a body-reachable position the editor can actually click? */
|
|
110
|
+
const childTextSafe = (child, prop) => {
|
|
111
|
+
const local = propLocalName(child.src, prop);
|
|
112
|
+
if (!local)
|
|
113
|
+
return false;
|
|
114
|
+
const verdict = classifyConstUsage(child.ast, local, {
|
|
115
|
+
componentHandoffUnsafe: true,
|
|
116
|
+
htmlDirectivesSafe: true,
|
|
117
|
+
});
|
|
118
|
+
// Safe (never a corrupting attribute) AND has at least one body sink — a
|
|
119
|
+
// prop rendered only into <head> (e.g. a layout's <title>) is editable in
|
|
120
|
+
// name only, so don't hoist it.
|
|
121
|
+
return verdict.safe && rendersOutsideHead(child.ast, [local]);
|
|
122
|
+
};
|
|
123
|
+
const targets = [];
|
|
124
|
+
const componentNodes = [];
|
|
125
|
+
walkTags(ast, (node) => {
|
|
126
|
+
if (node.type === "component")
|
|
127
|
+
componentNodes.push(node);
|
|
128
|
+
});
|
|
129
|
+
for (const node of componentNodes) {
|
|
130
|
+
const childRel = resolveComponentImport(source, node.name, relPath);
|
|
131
|
+
const child = childRel ? await readChild(childRel) : null;
|
|
132
|
+
if (!child)
|
|
133
|
+
continue;
|
|
134
|
+
const props = [];
|
|
135
|
+
for (const attr of node.attributes) {
|
|
136
|
+
if (attr.kind !== "quoted")
|
|
137
|
+
continue;
|
|
138
|
+
const value = attr.value ?? "";
|
|
139
|
+
if (value.trim() === "")
|
|
140
|
+
continue;
|
|
141
|
+
if (!isValidField(attr.name) && !slugifyText(attr.name))
|
|
142
|
+
continue;
|
|
143
|
+
// Positive proof: the child renders this prop as text (no native-attr, no
|
|
144
|
+
// re-handoff). set:html counts as text (stega-safe content sink).
|
|
145
|
+
if (!childTextSafe(child, attr.name))
|
|
146
|
+
continue;
|
|
147
|
+
// Locate an unambiguous source token; skip if absent/duplicated.
|
|
148
|
+
const attrBefore = uniqueAttrToken(source, attr.name, value);
|
|
149
|
+
if (!attrBefore)
|
|
150
|
+
continue;
|
|
151
|
+
const local = propLocalName(child.src, attr.name);
|
|
152
|
+
const isRich = local ? RICH_RE(local).test(child.src) : false;
|
|
153
|
+
const baseField = (isValidField(attr.name) ? attr.name : slugifyText(attr.name));
|
|
154
|
+
const field = uniquify(baseField, fields);
|
|
155
|
+
const constName = uniquify(camelIdent([node.name, attr.name]), usedConsts);
|
|
156
|
+
const key = `${collection}::${id}::${field}`;
|
|
157
|
+
const constInsert = `\nconst ${constName} = await editable(${JSON.stringify(key)}, ${JSON.stringify(value)});`;
|
|
158
|
+
props.push({
|
|
159
|
+
propName: attr.name,
|
|
160
|
+
literalValue: value,
|
|
161
|
+
key,
|
|
162
|
+
constName,
|
|
163
|
+
isRich,
|
|
164
|
+
attrBefore,
|
|
165
|
+
attrAfter: `${attr.name}={${constName}}`,
|
|
166
|
+
constInsert,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (props.length)
|
|
170
|
+
targets.push({ componentName: node.name, props });
|
|
171
|
+
}
|
|
172
|
+
return targets;
|
|
173
|
+
}
|
|
174
|
+
/** Apply the hoist rewrite. Self-locating: finds each `attrBefore` token by content. */
|
|
175
|
+
export function hoistPropLiterals(source, targets) {
|
|
176
|
+
const base = {
|
|
177
|
+
output: source, ok: true, propsRewritten: 0, constsDeclared: [], addedImport: false,
|
|
178
|
+
};
|
|
179
|
+
const flat = targets.flatMap((t) => t.props);
|
|
180
|
+
if (flat.length === 0)
|
|
181
|
+
return base;
|
|
182
|
+
let output = source;
|
|
183
|
+
// 1. Rewrite each attribute literal → expression reference (template region).
|
|
184
|
+
for (const p of flat) {
|
|
185
|
+
if (!output.includes(p.attrBefore)) {
|
|
186
|
+
return { ...base, ok: false, reason: `attr token not found: ${p.attrBefore}` };
|
|
187
|
+
}
|
|
188
|
+
output = output.replace(p.attrBefore, p.attrAfter);
|
|
189
|
+
}
|
|
190
|
+
// 2. Insert the editable() consts at the end of the frontmatter, and the
|
|
191
|
+
// import at the top (once). Recompute the range on the rewritten source.
|
|
192
|
+
const fm = frontmatterRange(output);
|
|
193
|
+
if (!fm)
|
|
194
|
+
return { ...base, ok: false, reason: "no frontmatter block" };
|
|
195
|
+
const addedImport = !IMPORT_RE.test(output);
|
|
196
|
+
const constBlock = flat.map((p) => p.constInsert).join("");
|
|
197
|
+
output =
|
|
198
|
+
output.slice(0, fm.start) +
|
|
199
|
+
(addedImport ? `${IMPORT_LINE}\n` : "") +
|
|
200
|
+
output.slice(fm.start, fm.end) +
|
|
201
|
+
constBlock +
|
|
202
|
+
output.slice(fm.end);
|
|
203
|
+
return {
|
|
204
|
+
output,
|
|
205
|
+
ok: true,
|
|
206
|
+
propsRewritten: flat.length,
|
|
207
|
+
constsDeclared: flat.map((p) => p.constName),
|
|
208
|
+
addedImport,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Inverse gate: undo every hoist edit on `output` and assert the result is
|
|
213
|
+
* byte-identical to `intermediate` (the source the hoist was applied to). This
|
|
214
|
+
* proves the ONLY changes were the intended hoists — no collateral edits.
|
|
215
|
+
*/
|
|
216
|
+
export function verifyHoistResult(intermediate, output, targets, addedImport) {
|
|
217
|
+
let restored = output;
|
|
218
|
+
if (addedImport)
|
|
219
|
+
restored = restored.replace(`${IMPORT_LINE}\n`, "");
|
|
220
|
+
for (const p of targets.flatMap((t) => t.props)) {
|
|
221
|
+
if (!restored.includes(p.constInsert))
|
|
222
|
+
return false;
|
|
223
|
+
restored = restored.replace(p.constInsert, "");
|
|
224
|
+
if (!restored.includes(p.attrAfter))
|
|
225
|
+
return false;
|
|
226
|
+
// Function replacement: `attrBefore` is a verbatim source token and may hold
|
|
227
|
+
// `$&`/`$$`/etc., which string-replacement would interpret as patterns.
|
|
228
|
+
restored = restored.replace(p.attrAfter, () => p.attrBefore);
|
|
229
|
+
}
|
|
230
|
+
return restored === intermediate;
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=prop-hoist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-hoist.js","sourceRoot":"","sources":["../src/prop-hoist.ts"],"names":[],"mappings":"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"}
|
package/dist/props.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-2 cross-file prop wrapping — detection only.
|
|
3
|
+
*
|
|
4
|
+
* Finds frontmatter array/object literals that a page passes straight into a
|
|
5
|
+
* component as a prop (`<Features items={features} />`), follows the import into
|
|
6
|
+
* that child, and confirms — strictly — that every field of the value renders
|
|
7
|
+
* there as visible TEXT and never as a native-element attribute. Only then is the
|
|
8
|
+
* parent const a safe `editable()` wrap target. The wrap itself stays in the
|
|
9
|
+
* parent file (the same pure-insertion `wrapConst` Tier-1 uses); no child file is
|
|
10
|
+
* ever modified.
|
|
11
|
+
*
|
|
12
|
+
* Conservative by construction — a hand-off is wrapped only on positive proof:
|
|
13
|
+
* - import not a resolvable relative `.astro` → skip
|
|
14
|
+
* - child file unreadable → skip
|
|
15
|
+
* - prop not a simple `Astro.props` destructure → skip
|
|
16
|
+
* - child re-passes the prop to a component → skip (grandchild unverified)
|
|
17
|
+
* - any field used in a native attribute (here or in the child) → skip
|
|
18
|
+
*/
|
|
19
|
+
import { type AstroNode } from "./parse.js";
|
|
20
|
+
import type { WrapTarget } from "./wrap.js";
|
|
21
|
+
/** Reads a project-root-relative path, or returns null if it doesn't exist. */
|
|
22
|
+
export type FileReader = (relPath: string) => string | null;
|
|
23
|
+
/**
|
|
24
|
+
* The local identifier a child binds `prop` to via `const { … } = Astro.props`.
|
|
25
|
+
* Returns the destructured name (or its `prop: alias` rename), or null when the
|
|
26
|
+
* child doesn't destructure props simply — in which case we can't trace usage
|
|
27
|
+
* and the caller skips.
|
|
28
|
+
*/
|
|
29
|
+
export declare function propLocalName(childSource: string, prop: string): string | null;
|
|
30
|
+
/** Verify a child renders `prop`'s fields as text only (strict: no re-handoff). */
|
|
31
|
+
export declare function childRendersPropAsText(childSource: string, prop: string): Promise<boolean>;
|
|
32
|
+
/**
|
|
33
|
+
* Detect Tier-2 wrap targets: literal consts handed to a component as a prop
|
|
34
|
+
* whose child provably renders them as text. `readFile` resolves sibling files
|
|
35
|
+
* (injected so this stays testable without a real filesystem).
|
|
36
|
+
*/
|
|
37
|
+
export declare function detectPropWrapTargets(source: string, relPath: string, readFile: FileReader, root?: AstroNode): Promise<WrapTarget[]>;
|
|
38
|
+
//# sourceMappingURL=props.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../src/props.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAMxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,+EAA+E;AAC/E,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AAE5D;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmB9E;AAED,mFAAmF;AACnF,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAKlB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,UAAU,EACpB,IAAI,CAAC,EAAE,SAAS,GACf,OAAO,CAAC,UAAU,EAAE,CAAC,CAgDvB"}
|
package/dist/props.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-2 cross-file prop wrapping — detection only.
|
|
3
|
+
*
|
|
4
|
+
* Finds frontmatter array/object literals that a page passes straight into a
|
|
5
|
+
* component as a prop (`<Features items={features} />`), follows the import into
|
|
6
|
+
* that child, and confirms — strictly — that every field of the value renders
|
|
7
|
+
* there as visible TEXT and never as a native-element attribute. Only then is the
|
|
8
|
+
* parent const a safe `editable()` wrap target. The wrap itself stays in the
|
|
9
|
+
* parent file (the same pure-insertion `wrapConst` Tier-1 uses); no child file is
|
|
10
|
+
* ever modified.
|
|
11
|
+
*
|
|
12
|
+
* Conservative by construction — a hand-off is wrapped only on positive proof:
|
|
13
|
+
* - import not a resolvable relative `.astro` → skip
|
|
14
|
+
* - child file unreadable → skip
|
|
15
|
+
* - prop not a simple `Astro.props` destructure → skip
|
|
16
|
+
* - child re-passes the prop to a component → skip (grandchild unverified)
|
|
17
|
+
* - any field used in a native attribute (here or in the child) → skip
|
|
18
|
+
*/
|
|
19
|
+
import { parseAstro } from "./parse.js";
|
|
20
|
+
import { deriveScope, isValidField, slugifyText } from "./name.js";
|
|
21
|
+
import { classifyConstUsage } from "./usage.js";
|
|
22
|
+
import { resolveComponentImport } from "./resolve.js";
|
|
23
|
+
import { frontmatterRange, literalConstNames } from "./frontmatter.js";
|
|
24
|
+
import { IDENT } from "./identifiers.js";
|
|
25
|
+
/**
|
|
26
|
+
* The local identifier a child binds `prop` to via `const { … } = Astro.props`.
|
|
27
|
+
* Returns the destructured name (or its `prop: alias` rename), or null when the
|
|
28
|
+
* child doesn't destructure props simply — in which case we can't trace usage
|
|
29
|
+
* and the caller skips.
|
|
30
|
+
*/
|
|
31
|
+
export function propLocalName(childSource, prop) {
|
|
32
|
+
const re = /const\s*\{([^}]*)\}\s*=\s*Astro\.props/g;
|
|
33
|
+
let m;
|
|
34
|
+
while ((m = re.exec(childSource))) {
|
|
35
|
+
for (const part of m[1].split(",")) {
|
|
36
|
+
const seg = part.trim();
|
|
37
|
+
if (!seg || seg.startsWith("..."))
|
|
38
|
+
continue;
|
|
39
|
+
// `prop`, `prop: alias`, or `prop = default` (strip the default).
|
|
40
|
+
const key = seg.split(/[:=]/)[0].trim();
|
|
41
|
+
if (key !== prop)
|
|
42
|
+
continue;
|
|
43
|
+
const colon = seg.indexOf(":");
|
|
44
|
+
if (colon >= 0) {
|
|
45
|
+
const alias = seg.slice(colon + 1).split("=")[0].trim();
|
|
46
|
+
return IDENT.test(alias) ? alias : null;
|
|
47
|
+
}
|
|
48
|
+
return IDENT.test(key) ? key : null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/** Verify a child renders `prop`'s fields as text only (strict: no re-handoff). */
|
|
54
|
+
export async function childRendersPropAsText(childSource, prop) {
|
|
55
|
+
const local = propLocalName(childSource, prop);
|
|
56
|
+
if (!local)
|
|
57
|
+
return false;
|
|
58
|
+
const root = await parseAstro(childSource);
|
|
59
|
+
return classifyConstUsage(root, local, { componentHandoffUnsafe: true }).safe;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Detect Tier-2 wrap targets: literal consts handed to a component as a prop
|
|
63
|
+
* whose child provably renders them as text. `readFile` resolves sibling files
|
|
64
|
+
* (injected so this stays testable without a real filesystem).
|
|
65
|
+
*/
|
|
66
|
+
export async function detectPropWrapTargets(source, relPath, readFile, root) {
|
|
67
|
+
const scoped = deriveScope(relPath);
|
|
68
|
+
if ("skip" in scoped)
|
|
69
|
+
return [];
|
|
70
|
+
const { collection, id } = scoped.scope;
|
|
71
|
+
const fm = frontmatterRange(source);
|
|
72
|
+
if (!fm)
|
|
73
|
+
return [];
|
|
74
|
+
const literals = literalConstNames(source.slice(fm.start, fm.end));
|
|
75
|
+
if (literals.size === 0)
|
|
76
|
+
return [];
|
|
77
|
+
const ast = root ?? (await parseAstro(source));
|
|
78
|
+
const targets = [];
|
|
79
|
+
for (const varName of literals) {
|
|
80
|
+
// Local usage: gather this const's component hand-offs, and bail if a field
|
|
81
|
+
// already lands in a native-element attribute in THIS file.
|
|
82
|
+
const local = classifyConstUsage(ast, varName); // lenient: collect handoffs
|
|
83
|
+
if (!local.safe)
|
|
84
|
+
continue;
|
|
85
|
+
// Only consts actually passed to a component as a prop are Tier-2's business;
|
|
86
|
+
// pure local-loop consts are Tier-1's. Dedup hand-offs by component+prop.
|
|
87
|
+
const seen = new Set();
|
|
88
|
+
const handoffs = local.handoffs.filter((h) => {
|
|
89
|
+
const k = `${h.component}::${h.prop}`;
|
|
90
|
+
if (seen.has(k))
|
|
91
|
+
return false;
|
|
92
|
+
seen.add(k);
|
|
93
|
+
return true;
|
|
94
|
+
});
|
|
95
|
+
if (handoffs.length === 0)
|
|
96
|
+
continue;
|
|
97
|
+
// Every hand-off must resolve to a child that renders the prop as text.
|
|
98
|
+
let allSafe = true;
|
|
99
|
+
for (const h of handoffs) {
|
|
100
|
+
const childRel = resolveComponentImport(source, h.component, relPath);
|
|
101
|
+
const childSrc = childRel ? readFile(childRel) : null;
|
|
102
|
+
if (!childSrc || !(await childRendersPropAsText(childSrc, h.prop))) {
|
|
103
|
+
allSafe = false;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!allSafe)
|
|
108
|
+
continue;
|
|
109
|
+
const field = isValidField(varName) ? varName : slugifyText(varName);
|
|
110
|
+
if (!field)
|
|
111
|
+
continue;
|
|
112
|
+
targets.push({ varName, key: `${collection}::${id}::${field}`, origin: "prop" });
|
|
113
|
+
}
|
|
114
|
+
return targets;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=props.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.js","sourceRoot":"","sources":["../src/props.ts"],"names":[],"mappings":"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"}
|
package/dist/report.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Machine-readable report (for --report) and the human summary counts. Pure
|
|
3
|
+
* functions over plans + the prepared results so they're easy to test.
|
|
4
|
+
*/
|
|
5
|
+
import type { FilePlan } from "./plan.js";
|
|
6
|
+
import type { PreparedFile } from "./run.js";
|
|
7
|
+
export interface CaretizeReport {
|
|
8
|
+
version: 1;
|
|
9
|
+
scope: {
|
|
10
|
+
collection: string;
|
|
11
|
+
id: string;
|
|
12
|
+
} | null;
|
|
13
|
+
files: Array<{
|
|
14
|
+
path: string;
|
|
15
|
+
scope: {
|
|
16
|
+
collection: string;
|
|
17
|
+
id: string;
|
|
18
|
+
} | null;
|
|
19
|
+
scopeSkip?: string;
|
|
20
|
+
tags: Array<{
|
|
21
|
+
binding: string;
|
|
22
|
+
tag: string;
|
|
23
|
+
confidence: string;
|
|
24
|
+
text: string;
|
|
25
|
+
}>;
|
|
26
|
+
skipped: Array<{
|
|
27
|
+
tag: string;
|
|
28
|
+
reason: string;
|
|
29
|
+
}>;
|
|
30
|
+
flags: Array<{
|
|
31
|
+
method: string;
|
|
32
|
+
}>;
|
|
33
|
+
}>;
|
|
34
|
+
totals: {
|
|
35
|
+
tagged: number;
|
|
36
|
+
skipped: number;
|
|
37
|
+
flagged: number;
|
|
38
|
+
filesModified: number;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export declare function buildReport(plans: FilePlan[], prepared?: PreparedFile[]): CaretizeReport;
|
|
42
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;QACjD,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAChF,OAAO,EAAE,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAChD,KAAK,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAClC,CAAC,CAAC;IACH,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CACrF;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,QAAQ,EAAE,EACjB,QAAQ,GAAE,YAAY,EAAO,GAC5B,cAAc,CAgChB"}
|
package/dist/report.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Machine-readable report (for --report) and the human summary counts. Pure
|
|
3
|
+
* functions over plans + the prepared results so they're easy to test.
|
|
4
|
+
*/
|
|
5
|
+
export function buildReport(plans, prepared = []) {
|
|
6
|
+
const modified = new Set(prepared.filter((p) => p.tagCount > 0).map((p) => p.relPath));
|
|
7
|
+
let tagged = 0;
|
|
8
|
+
let skipped = 0;
|
|
9
|
+
let flagged = 0;
|
|
10
|
+
const files = plans.map((plan) => {
|
|
11
|
+
tagged += plan.tags.length;
|
|
12
|
+
skipped += plan.skipped.length;
|
|
13
|
+
flagged += plan.flags.length;
|
|
14
|
+
return {
|
|
15
|
+
path: plan.relPath,
|
|
16
|
+
scope: plan.scope ?? null,
|
|
17
|
+
...(plan.scopeSkip ? { scopeSkip: plan.scopeSkip } : {}),
|
|
18
|
+
tags: plan.tags.map((t) => ({
|
|
19
|
+
binding: t.binding,
|
|
20
|
+
tag: t.candidate.tag,
|
|
21
|
+
confidence: t.confidence,
|
|
22
|
+
text: t.candidate.text,
|
|
23
|
+
})),
|
|
24
|
+
skipped: plan.skipped.map((s) => ({ tag: s.tag, reason: s.reason })),
|
|
25
|
+
flags: plan.flags.map((f) => ({ method: f.method })),
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
version: 1,
|
|
30
|
+
scope: plans.find((p) => p.scope)?.scope ?? null,
|
|
31
|
+
files,
|
|
32
|
+
totals: { tagged, skipped, flagged, filesModified: modified.size },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH,MAAM,UAAU,WAAW,CACzB,KAAiB,EACjB,WAA2B,EAAE;IAE7B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvF,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC/B,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QAC3B,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QAC/B,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QAC7B,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;YACzB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC1B,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,GAAG,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG;gBACpB,UAAU,EAAE,CAAC,CAAC,UAAU;gBACxB,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI;aACvB,CAAC,CAAC;YACH,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YACpE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;SACrD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,OAAO,EAAE,CAAC;QACV,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI,IAAI;QAChD,KAAK;QACL,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,IAAI,EAAE;KACnE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal component-import resolution for the cross-file prop pass.
|
|
3
|
+
*
|
|
4
|
+
* Given an importer's source and a component name, find its `import … from`
|
|
5
|
+
* specifier and resolve it to a project-root-relative `.astro` path. Only RELATIVE
|
|
6
|
+
* specifiers are resolved: bare/`npm` packages and tsconfig path aliases
|
|
7
|
+
* (`~/…`, `@/…`) need build config we don't read, so they return null and the
|
|
8
|
+
* caller conservatively skips that hand-off rather than guess.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Resolve `componentName`'s source path relative to the project root, or null
|
|
12
|
+
* when the import is absent or not a resolvable relative `.astro` specifier.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveComponentImport(importerSource: string, componentName: string, importerRelPath: string): string | null;
|
|
15
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,GACtB,MAAM,GAAG,IAAI,CAoBf"}
|
package/dist/resolve.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal component-import resolution for the cross-file prop pass.
|
|
3
|
+
*
|
|
4
|
+
* Given an importer's source and a component name, find its `import … from`
|
|
5
|
+
* specifier and resolve it to a project-root-relative `.astro` path. Only RELATIVE
|
|
6
|
+
* specifiers are resolved: bare/`npm` packages and tsconfig path aliases
|
|
7
|
+
* (`~/…`, `@/…`) need build config we don't read, so they return null and the
|
|
8
|
+
* caller conservatively skips that hand-off rather than guess.
|
|
9
|
+
*/
|
|
10
|
+
import { posix } from "node:path";
|
|
11
|
+
import { escapeRe } from "./identifiers.js";
|
|
12
|
+
/**
|
|
13
|
+
* Resolve `componentName`'s source path relative to the project root, or null
|
|
14
|
+
* when the import is absent or not a resolvable relative `.astro` specifier.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveComponentImport(importerSource, componentName, importerRelPath) {
|
|
17
|
+
// Default import of the component, tolerating a trailing named group:
|
|
18
|
+
// `import Name from '…'` and `import Name, { X } from '…'`. The `(?![\w$])`
|
|
19
|
+
// bounds the name so `Card` doesn't match `CardList`.
|
|
20
|
+
const re = new RegExp(`import\\s+${escapeRe(componentName)}(?![\\w$])[^'"\\n]*?from\\s*['"]([^'"]+)['"]`);
|
|
21
|
+
const m = re.exec(importerSource);
|
|
22
|
+
if (!m)
|
|
23
|
+
return null;
|
|
24
|
+
let spec = m[1];
|
|
25
|
+
if (!spec.startsWith("./") && !spec.startsWith("../"))
|
|
26
|
+
return null; // alias/bare → unresolvable here
|
|
27
|
+
if (!spec.endsWith(".astro")) {
|
|
28
|
+
if (/\.\w+$/.test(spec))
|
|
29
|
+
return null; // a non-.astro file (e.g. .tsx) — out of scope for v1
|
|
30
|
+
spec += ".astro";
|
|
31
|
+
}
|
|
32
|
+
const dir = posix.dirname(importerRelPath.replace(/\\/g, "/"));
|
|
33
|
+
return posix.normalize(posix.join(dir, spec));
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,cAAsB,EACtB,aAAqB,EACrB,eAAuB;IAEvB,sEAAsE;IACtE,4EAA4E;IAC5E,sDAAsD;IACtD,MAAM,EAAE,GAAG,IAAI,MAAM,CACnB,aAAa,QAAQ,CAAC,aAAa,CAAC,8CAA8C,CACnF,CAAC;IACF,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAClC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpB,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAChB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,iCAAiC;IAErG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,sDAAsD;QAC5F,IAAI,IAAI,QAAQ,CAAC;IACnB,CAAC;IAED,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/D,OAAO,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAChD,CAAC"}
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run orchestration. The atomicity model is "validate everything in memory,
|
|
3
|
+
* then write": every file's tagged output is computed and verified (re-parses +
|
|
4
|
+
* is pure-insertion-reversible) BEFORE a single byte hits disk. If any file
|
|
5
|
+
* fails verification, the run aborts having written nothing. During the write
|
|
6
|
+
* phase, backups are taken per file; if a write throws, everything written so
|
|
7
|
+
* far is restored from those backups.
|
|
8
|
+
*/
|
|
9
|
+
import { type TagInsertion } from "./write.js";
|
|
10
|
+
import { type WrapTarget } from "./wrap.js";
|
|
11
|
+
import { type PropHoistTarget } from "./prop-hoist.js";
|
|
12
|
+
export interface PreparedFile {
|
|
13
|
+
relPath: string;
|
|
14
|
+
source: string;
|
|
15
|
+
output: string;
|
|
16
|
+
inserted: string[];
|
|
17
|
+
tagCount: number;
|
|
18
|
+
ok: boolean;
|
|
19
|
+
reason?: string;
|
|
20
|
+
}
|
|
21
|
+
/** Compute and verify a single file's tagged output. No disk access. */
|
|
22
|
+
export declare function prepareFile(relPath: string, source: string, items: TagInsertion[]): Promise<PreparedFile>;
|
|
23
|
+
export type { WrapTarget };
|
|
24
|
+
/**
|
|
25
|
+
* Compute and verify a single file's editable()-wrapped output (Tier-1). Same
|
|
26
|
+
* atomicity contract as prepareFile, so the result feeds commitRun unchanged.
|
|
27
|
+
*
|
|
28
|
+
* Gate 2 here is a SUBSEQUENCE check rather than strip-by-string: the inserted
|
|
29
|
+
* `await editable(…, ` / `)` spans contain characters (`)`, commas) that also
|
|
30
|
+
* occur elsewhere, so verifying "original is a subsequence of output" is the
|
|
31
|
+
* robust way to prove pure insertion (no original char deleted or reordered).
|
|
32
|
+
*/
|
|
33
|
+
export declare function prepareWrapFile(relPath: string, source: string, targets: WrapTarget[]): Promise<PreparedFile>;
|
|
34
|
+
/**
|
|
35
|
+
* Compute and verify a file's output with BOTH passes: attribute tags and
|
|
36
|
+
* editable() wraps. Tags are applied first (offset-based, in the template), then
|
|
37
|
+
* wraps (content-scan, in the frontmatter) — so the frontmatter insertions never
|
|
38
|
+
* shift the template tag offsets. Same atomicity gates; one PreparedFile out.
|
|
39
|
+
*/
|
|
40
|
+
export declare function prepareFileFull(relPath: string, source: string, items: TagInsertion[], targets: WrapTarget[], hoistTargets?: PropHoistTarget[]): Promise<PreparedFile>;
|
|
41
|
+
export interface CommitResult {
|
|
42
|
+
written: string[];
|
|
43
|
+
backups: string[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Write verified files to disk with backups. Throws (after rolling back) if any
|
|
47
|
+
* prepared file failed verification or any write fails.
|
|
48
|
+
*/
|
|
49
|
+
export declare function commitRun(rootDir: string, prepared: PreparedFile[], stamp: string): CommitResult;
|
|
50
|
+
/** Convenience: read a file from disk for preparation. */
|
|
51
|
+
export declare function readSource(rootDir: string, relPath: string): string;
|
|
52
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAwC,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAU7F,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wEAAwE;AACxE,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,EAAE,GACpB,OAAO,CAAC,YAAY,CAAC,CA8BvB;AAED,YAAY,EAAE,UAAU,EAAE,CAAC;AAW3B;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,UAAU,EAAE,GACpB,OAAO,CAAC,YAAY,CAAC,CA8BvB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,EAAE,EACrB,OAAO,EAAE,UAAU,EAAE,EACrB,YAAY,GAAE,eAAe,EAAO,GACnC,OAAO,CAAC,YAAY,CAAC,CAqEvB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,YAAY,EAAE,EACxB,KAAK,EAAE,MAAM,GACZ,YAAY,CA4Bd;AAED,0DAA0D;AAC1D,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnE"}
|