@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,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-3 editable() wrapping for IMPORTED data — PURE INSERTION.
|
|
3
|
+
*
|
|
4
|
+
* A very common Astro pattern keeps list content in a data file and renders it
|
|
5
|
+
* with `.map()`:
|
|
6
|
+
*
|
|
7
|
+
* import faqs from "./data/faqs.json";
|
|
8
|
+
* …
|
|
9
|
+
* {faqs.map((f) => <details>{f.question}…</details>)}
|
|
10
|
+
*
|
|
11
|
+
* caretize's Tier-1 wrap only sees inline-literal consts (`const x = [...]`), so
|
|
12
|
+
* this content was previously left un-editable. Tier-3 makes it editable WITHOUT
|
|
13
|
+
* moving any code: it suffixes the import binding and rebinds the original name
|
|
14
|
+
* to an `editable()` wrap of it —
|
|
15
|
+
*
|
|
16
|
+
* import faqsRaw from "./data/faqs.json";
|
|
17
|
+
* const faqs = await editable("pages::home::faqs", faqsRaw);
|
|
18
|
+
*
|
|
19
|
+
* Every original character survives in order (the import binding only GAINS a
|
|
20
|
+
* suffix; a new const line is inserted), so the result is a provable pure
|
|
21
|
+
* insertion — the same subsequence safety contract as Tier-1. The `.map()`
|
|
22
|
+
* consumer is untouched and now reads the stega-encoded, click-to-edit value.
|
|
23
|
+
*/
|
|
24
|
+
import { deriveScope, isValidField, slugifyText } from "./name.js";
|
|
25
|
+
import { parseAstro } from "./parse.js";
|
|
26
|
+
import { classifyConstUsage } from "./usage.js";
|
|
27
|
+
import { frontmatterRange, importBindingNames, } from "./frontmatter.js";
|
|
28
|
+
import { isIdentifier } from "./identifiers.js";
|
|
29
|
+
import { IMPORT_LINE, IMPORT_RE } from "./wrap.js";
|
|
30
|
+
/** Pick a non-colliding suffixed name for the raw (pre-editable) import binding. */
|
|
31
|
+
function rawNameFor(source, varName) {
|
|
32
|
+
for (const suffix of ["Raw", "Source", "Data"]) {
|
|
33
|
+
const candidate = `${varName}${suffix}`;
|
|
34
|
+
if (!new RegExp(`\\b${candidate}\\b`).test(source))
|
|
35
|
+
return candidate;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Rebind an imported `varName` to `await editable("<key>", <varName>Raw)` and
|
|
41
|
+
* ensure the import is present. Pure insertion: the import binding gains a
|
|
42
|
+
* suffix and a new const line is inserted; nothing is deleted.
|
|
43
|
+
*/
|
|
44
|
+
export function wrapImport(source, varName, key) {
|
|
45
|
+
if (!isIdentifier(varName)) {
|
|
46
|
+
return { output: source, ok: false, reason: `invalid identifier: ${varName}` };
|
|
47
|
+
}
|
|
48
|
+
const fm = frontmatterRange(source);
|
|
49
|
+
if (!fm)
|
|
50
|
+
return { output: source, ok: false, reason: "no frontmatter block" };
|
|
51
|
+
const fmText = source.slice(fm.start, fm.end);
|
|
52
|
+
// Idempotent: bail if this binding is already an editable() rebind.
|
|
53
|
+
if (new RegExp(`\\bconst\\s+${varName}\\s*=\\s*await\\s+editable\\s*\\(`).test(fmText)) {
|
|
54
|
+
return { output: source, ok: true, alreadyWrapped: true };
|
|
55
|
+
}
|
|
56
|
+
const importRe = new RegExp(`\\bimport\\s+(?!type\\b)(${varName})\\s+from\\s*['"][^'"]+['"]`);
|
|
57
|
+
const m = importRe.exec(fmText);
|
|
58
|
+
if (!m) {
|
|
59
|
+
return { output: source, ok: false, reason: `default import of ${varName} not found` };
|
|
60
|
+
}
|
|
61
|
+
const rawName = rawNameFor(source, varName);
|
|
62
|
+
if (!rawName) {
|
|
63
|
+
return { output: source, ok: false, reason: `could not pick a free name for ${varName}` };
|
|
64
|
+
}
|
|
65
|
+
// Offset just past the binding identifier (insert the suffix here).
|
|
66
|
+
const kw = /^import\s+/.exec(m[0])[0];
|
|
67
|
+
const identEndRel = m.index + kw.length + varName.length;
|
|
68
|
+
// Offset just past the import statement, swallowing an optional `;`.
|
|
69
|
+
let stmtEndRel = m.index + m[0].length;
|
|
70
|
+
if (fmText[stmtEndRel] === ";")
|
|
71
|
+
stmtEndRel++;
|
|
72
|
+
const identEndAbs = fm.start + identEndRel;
|
|
73
|
+
const stmtEndAbs = fm.start + stmtEndRel;
|
|
74
|
+
const suffix = rawName.slice(varName.length); // e.g. "Raw"
|
|
75
|
+
const constLine = `\nconst ${varName} = await editable(${JSON.stringify(key)}, ${rawName});`;
|
|
76
|
+
// Two pure insertions, applied left-to-right via slicing: the binding gains
|
|
77
|
+
// `suffix`, and a new const line follows the import statement.
|
|
78
|
+
let output = source.slice(0, identEndAbs) +
|
|
79
|
+
suffix +
|
|
80
|
+
source.slice(identEndAbs, stmtEndAbs) +
|
|
81
|
+
constLine +
|
|
82
|
+
source.slice(stmtEndAbs);
|
|
83
|
+
if (!IMPORT_RE.test(source)) {
|
|
84
|
+
output = output.slice(0, fm.start) + IMPORT_LINE + "\n" + output.slice(fm.start);
|
|
85
|
+
}
|
|
86
|
+
return { output, ok: true };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Detect Tier-3 candidates: DEFAULT imports of a `.json`/module data file that
|
|
90
|
+
* are `.map()`/`.flatMap()`'d in the template. Key is derived from the file's
|
|
91
|
+
* scope (`collection::id`) plus the binding name as the field.
|
|
92
|
+
*/
|
|
93
|
+
export function detectImportWrapCandidates(source, relPath) {
|
|
94
|
+
const fm = frontmatterRange(source);
|
|
95
|
+
if (!fm)
|
|
96
|
+
return [];
|
|
97
|
+
const fmText = source.slice(fm.start, fm.end);
|
|
98
|
+
const template = source.slice(fm.end);
|
|
99
|
+
const imports = importBindingNames(fmText);
|
|
100
|
+
if (imports.size === 0)
|
|
101
|
+
return [];
|
|
102
|
+
// Of the imported bindings, the ones actually iterated in the template.
|
|
103
|
+
const mapped = new Set();
|
|
104
|
+
const mapRe = /\b([A-Za-z_$][\w$]*)\s*\.\s*(?:map|flatMap)\b/g;
|
|
105
|
+
let mm;
|
|
106
|
+
while ((mm = mapRe.exec(template))) {
|
|
107
|
+
if (imports.has(mm[1]))
|
|
108
|
+
mapped.add(mm[1]);
|
|
109
|
+
}
|
|
110
|
+
if (mapped.size === 0)
|
|
111
|
+
return [];
|
|
112
|
+
const scoped = deriveScope(relPath);
|
|
113
|
+
if ("skip" in scoped)
|
|
114
|
+
return [];
|
|
115
|
+
const { collection, id } = scoped.scope;
|
|
116
|
+
const candidates = [];
|
|
117
|
+
for (const varName of mapped) {
|
|
118
|
+
// Already rebound on a prior run → not a candidate.
|
|
119
|
+
if (new RegExp(`\\bconst\\s+${varName}\\s*=\\s*await\\s+editable\\s*\\(`).test(fmText)) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const field = isValidField(varName) ? varName : slugifyText(varName);
|
|
123
|
+
if (!field)
|
|
124
|
+
continue;
|
|
125
|
+
const meta = imports.get(varName);
|
|
126
|
+
candidates.push({
|
|
127
|
+
varName,
|
|
128
|
+
key: `${collection}::${id}::${field}`,
|
|
129
|
+
specifier: meta.specifier,
|
|
130
|
+
importKind: meta.importKind,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return candidates;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Safety-checked Tier-3 detection: import-backed candidates minus any whose
|
|
137
|
+
* mapped fields flow into a native-element attribute (where `editable()`'s stega
|
|
138
|
+
* encoding would corrupt an href/src/class/…). Mirrors `detectWrapTargetsSafe`.
|
|
139
|
+
*/
|
|
140
|
+
export async function detectImportWrapTargetsSafe(source, relPath, root) {
|
|
141
|
+
const candidates = detectImportWrapCandidates(source, relPath);
|
|
142
|
+
if (candidates.length === 0)
|
|
143
|
+
return [];
|
|
144
|
+
const ast = root ?? (await parseAstro(source));
|
|
145
|
+
return candidates
|
|
146
|
+
.filter((c) => classifyConstUsage(ast, c.varName).safe)
|
|
147
|
+
.map((c) => ({ varName: c.varName, key: c.key, origin: "import" }));
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=import-wrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-wrap.js","sourceRoot":"","sources":["../src/import-wrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;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,EACL,gBAAgB,EAChB,kBAAkB,GAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAoC,MAAM,WAAW,CAAC;AAcrF,oFAAoF;AACpF,SAAS,UAAU,CAAC,MAAc,EAAE,OAAe;IACjD,KAAK,MAAM,MAAM,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,SAAS,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,OAAO,SAAS,CAAC;IACvE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,OAAe,EAAE,GAAW;IACrE,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;IAE9C,oEAAoE;IACpE,IAAI,IAAI,MAAM,CAAC,eAAe,OAAO,mCAAmC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACvF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;IAC5D,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,MAAM,CACzB,4BAA4B,OAAO,6BAA6B,CACjE,CAAC;IACF,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,OAAO,YAAY,EAAE,CAAC;IACzF,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,kCAAkC,OAAO,EAAE,EAAE,CAAC;IAC5F,CAAC;IAED,oEAAoE;IACpE,MAAM,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACzD,qEAAqE;IACrE,IAAI,UAAU,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,GAAG;QAAE,UAAU,EAAE,CAAC;IAE7C,MAAM,WAAW,GAAG,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC;IAC3C,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,GAAG,UAAU,CAAC;IAEzC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa;IAC3D,MAAM,SAAS,GAAG,WAAW,OAAO,qBAAqB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,OAAO,IAAI,CAAC;IAE7F,4EAA4E;IAC5E,+DAA+D;IAC/D,IAAI,MAAM,GACR,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC;QAC5B,MAAM;QACN,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,UAAU,CAAC;QACrC,SAAS;QACT,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAE3B,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;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAc,EACd,OAAe;IAEf,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,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,wEAAwE;IACxE,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,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjC,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,GAA0B,EAAE,CAAC;IAC7C,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;QAC7B,oDAAoD;QACpD,IAAI,IAAI,MAAM,CAAC,eAAe,OAAO,mCAAmC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACvF,SAAS;QACX,CAAC;QACD,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,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC;QACnC,UAAU,CAAC,IAAI,CAAC;YACd,OAAO;YACP,GAAG,EAAE,GAAG,UAAU,KAAK,EAAE,KAAK,KAAK,EAAE;YACrC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAc,EACd,OAAe,EACf,IAAgB;IAEhB,MAAM,UAAU,GAAG,0BAA0B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/D,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,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,QAAiB,EAAE,CAAC,CAAC,CAAC;AACjF,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @caretcms/caretize — public entry.
|
|
3
|
+
*
|
|
4
|
+
* v0.1 surfaces the byte-correct splice/parse core plus detection, naming, and
|
|
5
|
+
* planning. The interactive review loop and the CLI build on top of these.
|
|
6
|
+
*/
|
|
7
|
+
export { parseAstro, walkTags, isTagNode, tagElementAndVerify, type AstroNode, type TagNode, type ContainerNode, type TagResult, } from "./parse.js";
|
|
8
|
+
export { findOpenTagEnd, spliceAttribute, type OpenTagEnd, } from "./splice.js";
|
|
9
|
+
export { detect, type Candidate, type Skipped, type SkipReason, type Confidence, type CandidateKind, type IteratorFlag, type DetectResult, } from "./detect.js";
|
|
10
|
+
export { deriveScope, assignFields, slugifyText, isValidCollection, isValidId, isValidField, type Scope, type ScopeReason, type ScopeResult, } from "./name.js";
|
|
11
|
+
export { applyTags, type TagInsertion, type ApplyResult } from "./write.js";
|
|
12
|
+
export { planFile, type PlannedTag, type FilePlan, type PlanOptions, } from "./plan.js";
|
|
13
|
+
export { wrapConst, detectWrapTargetsSafe, type WrapResult, type WrapCandidate, type WrapTarget, type WrapOrigin, } from "./wrap.js";
|
|
14
|
+
export { wrapImport, detectImportWrapCandidates, detectImportWrapTargetsSafe, type ImportWrapCandidate, } from "./import-wrap.js";
|
|
15
|
+
export { importBindingNames, literalConstNames, type ImportKind, } from "./frontmatter.js";
|
|
16
|
+
export { detectPropWrapTargets, childRendersPropAsText, type FileReader } from "./props.js";
|
|
17
|
+
export { detectPropHoistTargets, hoistPropLiterals, verifyHoistResult, type PropHoistTarget, type HoistProp, type HoistResult, } from "./prop-hoist.js";
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,mBAAmB,EACnB,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,SAAS,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,MAAM,EACN,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,KAAK,KAAK,EACV,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EACL,QAAQ,EACR,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,WAAW,GACjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,SAAS,EACT,qBAAqB,EACrB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,UAAU,EACV,0BAA0B,EAC1B,2BAA2B,EAC3B,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5F,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,WAAW,GACjB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @caretcms/caretize — public entry.
|
|
3
|
+
*
|
|
4
|
+
* v0.1 surfaces the byte-correct splice/parse core plus detection, naming, and
|
|
5
|
+
* planning. The interactive review loop and the CLI build on top of these.
|
|
6
|
+
*/
|
|
7
|
+
export { parseAstro, walkTags, isTagNode, tagElementAndVerify, } from "./parse.js";
|
|
8
|
+
export { findOpenTagEnd, spliceAttribute, } from "./splice.js";
|
|
9
|
+
export { detect, } from "./detect.js";
|
|
10
|
+
export { deriveScope, assignFields, slugifyText, isValidCollection, isValidId, isValidField, } from "./name.js";
|
|
11
|
+
export { applyTags } from "./write.js";
|
|
12
|
+
export { planFile, } from "./plan.js";
|
|
13
|
+
export { wrapConst, detectWrapTargetsSafe, } from "./wrap.js";
|
|
14
|
+
export { wrapImport, detectImportWrapCandidates, detectImportWrapTargetsSafe, } from "./import-wrap.js";
|
|
15
|
+
export { importBindingNames, literalConstNames, } from "./frontmatter.js";
|
|
16
|
+
export { detectPropWrapTargets, childRendersPropAsText } from "./props.js";
|
|
17
|
+
export { detectPropHoistTargets, hoistPropLiterals, verifyHoistResult, } from "./prop-hoist.js";
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,mBAAmB,GAKpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,cAAc,EACd,eAAe,GAEhB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,MAAM,GAQP,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,YAAY,GAIb,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,SAAS,EAAuC,MAAM,YAAY,CAAC;AAE5E,OAAO,EACL,QAAQ,GAIT,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,SAAS,EACT,qBAAqB,GAKtB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,UAAU,EACV,0BAA0B,EAC1B,2BAA2B,GAE5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,kBAAkB,EAClB,iBAAiB,GAElB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAmB,MAAM,YAAY,CAAC;AAE5F,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,GAIlB,MAAM,iBAAiB,CAAC"}
|
package/dist/name.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Naming: derive a stable `collection::id` scope from a file path and assign a
|
|
3
|
+
* unique, valid field name to each candidate.
|
|
4
|
+
*
|
|
5
|
+
* The field names a candidate gets are *permanent storage keys* once a user
|
|
6
|
+
* edits — so naming must be deterministic (same input → same name every run),
|
|
7
|
+
* seeded from any `data-caret` names already in the file (so re-runs never
|
|
8
|
+
* reuse a name), unique within a scope (duplicate keys would mirror content at
|
|
9
|
+
* runtime), and valid against the runtime's parser regexes.
|
|
10
|
+
*/
|
|
11
|
+
import type { Candidate } from "./detect.js";
|
|
12
|
+
export declare const COLLECTION_RE: RegExp;
|
|
13
|
+
export declare const ID_RE: RegExp;
|
|
14
|
+
export declare function isValidCollection(s: string): boolean;
|
|
15
|
+
export declare function isValidId(s: string): boolean;
|
|
16
|
+
export declare function isValidField(s: string): boolean;
|
|
17
|
+
export interface Scope {
|
|
18
|
+
collection: string;
|
|
19
|
+
id: string;
|
|
20
|
+
}
|
|
21
|
+
export type ScopeReason = "dynamic-route" | "unsupported-location";
|
|
22
|
+
export type ScopeResult = {
|
|
23
|
+
scope: Scope;
|
|
24
|
+
} | {
|
|
25
|
+
skip: ScopeReason;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Derive the scope for a `.astro` file from its path relative to the project
|
|
29
|
+
* root (POSIX-style or OS-style accepted). Returns a skip reason for dynamic
|
|
30
|
+
* routes and locations we don't tag in v1.
|
|
31
|
+
*/
|
|
32
|
+
export declare function deriveScope(relPath: string): ScopeResult;
|
|
33
|
+
/**
|
|
34
|
+
* Derive a field name from an element's visible text — far more useful to an
|
|
35
|
+
* editor than `subhead_3` (e.g. "Our Programs 🎨" → `our_programs`). Decodes
|
|
36
|
+
* the few common HTML entities, strips emoji/accents/punctuation, and keeps the
|
|
37
|
+
* first few words. Returns null when nothing usable remains (all emoji, leading
|
|
38
|
+
* digits, etc.), so the caller falls back to a role-based name.
|
|
39
|
+
*/
|
|
40
|
+
export declare function slugifyText(text: string): string | null;
|
|
41
|
+
/**
|
|
42
|
+
* Assign a unique field name to each candidate, in document order.
|
|
43
|
+
*
|
|
44
|
+
* `existingFields` seeds the used-name set with whatever `data-caret` field
|
|
45
|
+
* names already live in the file's scope, so a partial first run, a manual
|
|
46
|
+
* edit, or a re-run never collides with an existing binding.
|
|
47
|
+
*/
|
|
48
|
+
export declare function assignFields(candidates: Candidate[], existingFields?: Iterable<string>): Map<Candidate, string>;
|
|
49
|
+
//# sourceMappingURL=name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name.d.ts","sourceRoot":"","sources":["../src/name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAM7C,eAAO,MAAM,aAAa,QAAuB,CAAC;AAClD,eAAO,MAAM,KAAK,QAA0B,CAAC;AAG7C,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEpD;AACD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAE5C;AACD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED,MAAM,WAAW,KAAK;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,sBAAsB,CAAC;AAEnE,MAAM,MAAM,WAAW,GACnB;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAY1B;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CA0BxD;AAKD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAavD;AAsDD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,SAAS,EAAE,EACvB,cAAc,GAAE,QAAQ,CAAC,MAAM,CAAM,GACpC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAexB"}
|
package/dist/name.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Naming: derive a stable `collection::id` scope from a file path and assign a
|
|
3
|
+
* unique, valid field name to each candidate.
|
|
4
|
+
*
|
|
5
|
+
* The field names a candidate gets are *permanent storage keys* once a user
|
|
6
|
+
* edits — so naming must be deterministic (same input → same name every run),
|
|
7
|
+
* seeded from any `data-caret` names already in the file (so re-runs never
|
|
8
|
+
* reuse a name), unique within a scope (duplicate keys would mirror content at
|
|
9
|
+
* runtime), and valid against the runtime's parser regexes.
|
|
10
|
+
*/
|
|
11
|
+
// Mirror the runtime's id-contract regexes exactly (core's
|
|
12
|
+
// runtime/storage/id-contracts.ts) — a label the runtime would reject must
|
|
13
|
+
// never be emitted. caretize deliberately has no dependency on core, so these
|
|
14
|
+
// are copies, held byte-identical by tests/unit/contracts-parity.test.ts.
|
|
15
|
+
export const COLLECTION_RE = /^[a-z][a-z0-9_-]*$/;
|
|
16
|
+
export const ID_RE = /^[a-z0-9][a-z0-9_-]*$/;
|
|
17
|
+
const FIELD_RE = /^[a-z][a-z0-9_]*$/; // generated fields: keep them clean identifiers
|
|
18
|
+
export function isValidCollection(s) {
|
|
19
|
+
return COLLECTION_RE.test(s);
|
|
20
|
+
}
|
|
21
|
+
export function isValidId(s) {
|
|
22
|
+
return ID_RE.test(s);
|
|
23
|
+
}
|
|
24
|
+
export function isValidField(s) {
|
|
25
|
+
return FIELD_RE.test(s);
|
|
26
|
+
}
|
|
27
|
+
/** Convert a PascalCase/camelCase or arbitrary filename to a valid id. */
|
|
28
|
+
function toId(name) {
|
|
29
|
+
const kebab = name
|
|
30
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
31
|
+
.toLowerCase()
|
|
32
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
33
|
+
.replace(/^-+|-+$/g, "");
|
|
34
|
+
return kebab || "page";
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Derive the scope for a `.astro` file from its path relative to the project
|
|
38
|
+
* root (POSIX-style or OS-style accepted). Returns a skip reason for dynamic
|
|
39
|
+
* routes and locations we don't tag in v1.
|
|
40
|
+
*/
|
|
41
|
+
export function deriveScope(relPath) {
|
|
42
|
+
const parts = relPath.replace(/\\/g, "/").replace(/^\.?\/+/, "").split("/");
|
|
43
|
+
const srcIdx = parts.indexOf("src");
|
|
44
|
+
const rel = srcIdx >= 0 ? parts.slice(srcIdx + 1) : parts;
|
|
45
|
+
const [area, ...rest] = rel;
|
|
46
|
+
if (rest.length === 0)
|
|
47
|
+
return { skip: "unsupported-location" };
|
|
48
|
+
// strip .astro from the final segment
|
|
49
|
+
rest[rest.length - 1] = rest[rest.length - 1].replace(/\.astro$/i, "");
|
|
50
|
+
// dynamic route segments like [slug] or [...rest] → no static identity
|
|
51
|
+
if (rest.some((seg) => /^\[.*\]$/.test(seg)))
|
|
52
|
+
return { skip: "dynamic-route" };
|
|
53
|
+
if (area === "pages") {
|
|
54
|
+
const segs = rest.filter((s) => s !== "index");
|
|
55
|
+
const id = segs.length === 0 ? "home" : segs.map(toId).join("_");
|
|
56
|
+
return { scope: { collection: "pages", id } };
|
|
57
|
+
}
|
|
58
|
+
if (area === "layouts") {
|
|
59
|
+
return { scope: { collection: "site", id: toId(rest[rest.length - 1]) } };
|
|
60
|
+
}
|
|
61
|
+
if (area === "components") {
|
|
62
|
+
return { scope: { collection: "components", id: toId(rest[rest.length - 1]) } };
|
|
63
|
+
}
|
|
64
|
+
return { skip: "unsupported-location" };
|
|
65
|
+
}
|
|
66
|
+
// Maximum words taken from text content when deriving a field name from it.
|
|
67
|
+
const SLUG_MAX_WORDS = 4;
|
|
68
|
+
/**
|
|
69
|
+
* Derive a field name from an element's visible text — far more useful to an
|
|
70
|
+
* editor than `subhead_3` (e.g. "Our Programs 🎨" → `our_programs`). Decodes
|
|
71
|
+
* the few common HTML entities, strips emoji/accents/punctuation, and keeps the
|
|
72
|
+
* first few words. Returns null when nothing usable remains (all emoji, leading
|
|
73
|
+
* digits, etc.), so the caller falls back to a role-based name.
|
|
74
|
+
*/
|
|
75
|
+
export function slugifyText(text) {
|
|
76
|
+
const decoded = text
|
|
77
|
+
.replace(/&/g, " and ")
|
|
78
|
+
.replace(/&(lt|gt|quot|nbsp|#0?39|apos);/g, " ")
|
|
79
|
+
.replace(/['’]/g, ""); // keep contractions joined: What's → whats
|
|
80
|
+
const ascii = decoded.normalize("NFKD").replace(/[̀-ͯ]/g, "");
|
|
81
|
+
const cleaned = ascii.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
82
|
+
if (!cleaned)
|
|
83
|
+
return null;
|
|
84
|
+
const slug = cleaned.split(/\s+/).slice(0, SLUG_MAX_WORDS).join("_");
|
|
85
|
+
// Field names must start with a letter; if the text led with digits/symbols,
|
|
86
|
+
// a role-based fallback reads better than a mangled slug.
|
|
87
|
+
if (!/^[a-z]/.test(slug) || !isValidField(slug))
|
|
88
|
+
return null;
|
|
89
|
+
return slug;
|
|
90
|
+
}
|
|
91
|
+
// Role-based field name, used when text isn't sluggable. `seenOfTag` lets the
|
|
92
|
+
// first <p> be "intro", first <img> "hero", etc.
|
|
93
|
+
function roleField(candidate, seenOfTag) {
|
|
94
|
+
if (candidate.kind === "image")
|
|
95
|
+
return seenOfTag === 0 ? "hero" : "image";
|
|
96
|
+
switch (candidate.tag) {
|
|
97
|
+
case "h1": return "headline";
|
|
98
|
+
case "h2": return "subhead";
|
|
99
|
+
case "h3":
|
|
100
|
+
case "h4":
|
|
101
|
+
case "h5":
|
|
102
|
+
case "h6": return "heading";
|
|
103
|
+
case "p": return seenOfTag === 0 ? "intro" : "body";
|
|
104
|
+
case "blockquote": return "quote";
|
|
105
|
+
case "li": return "item";
|
|
106
|
+
case "a": return "link";
|
|
107
|
+
case "button": return "button_label";
|
|
108
|
+
case "figcaption":
|
|
109
|
+
case "caption": return "caption";
|
|
110
|
+
case "summary": return "summary";
|
|
111
|
+
case "dt": return "term";
|
|
112
|
+
case "dd": return "definition";
|
|
113
|
+
case "th":
|
|
114
|
+
case "td": return "cell";
|
|
115
|
+
case "label": return "label";
|
|
116
|
+
default: return "text";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Prose elements hold sentences, where a 4-word slug is an awkward fragment
|
|
120
|
+
// ("here_s_what_a"); a role name (intro/body) reads better. Label-like
|
|
121
|
+
// elements (headings, links, buttons, list items…) hold short phrases that
|
|
122
|
+
// slug cleanly ("our_programs"), which is far more useful than "subhead_3".
|
|
123
|
+
const PROSE_TAGS = new Set(["p", "blockquote", "dd"]);
|
|
124
|
+
// Preferred base field name: a content slug for short label-like elements (the
|
|
125
|
+
// editor-friendly default), a role name for prose. Determinism is preserved —
|
|
126
|
+
// the same element always yields the same base.
|
|
127
|
+
function baseField(candidate, seenOfTag) {
|
|
128
|
+
if (candidate.kind === "text" && !PROSE_TAGS.has(candidate.tag)) {
|
|
129
|
+
const slug = slugifyText(candidate.text);
|
|
130
|
+
if (slug)
|
|
131
|
+
return slug;
|
|
132
|
+
}
|
|
133
|
+
return roleField(candidate, seenOfTag);
|
|
134
|
+
}
|
|
135
|
+
function uniquify(base, used) {
|
|
136
|
+
if (!used.has(base))
|
|
137
|
+
return base;
|
|
138
|
+
let i = 2;
|
|
139
|
+
while (used.has(`${base}_${i}`))
|
|
140
|
+
i++;
|
|
141
|
+
return `${base}_${i}`;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Assign a unique field name to each candidate, in document order.
|
|
145
|
+
*
|
|
146
|
+
* `existingFields` seeds the used-name set with whatever `data-caret` field
|
|
147
|
+
* names already live in the file's scope, so a partial first run, a manual
|
|
148
|
+
* edit, or a re-run never collides with an existing binding.
|
|
149
|
+
*/
|
|
150
|
+
export function assignFields(candidates, existingFields = []) {
|
|
151
|
+
const used = new Set(existingFields);
|
|
152
|
+
const seen = new Map();
|
|
153
|
+
const result = new Map();
|
|
154
|
+
for (const c of candidates) {
|
|
155
|
+
const key = c.kind === "image" ? "img" : c.tag;
|
|
156
|
+
const seenCount = seen.get(key) ?? 0;
|
|
157
|
+
seen.set(key, seenCount + 1);
|
|
158
|
+
const name = uniquify(baseField(c, seenCount), used);
|
|
159
|
+
used.add(name);
|
|
160
|
+
result.set(c, name);
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=name.js.map
|
package/dist/name.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name.js","sourceRoot":"","sources":["../src/name.ts"],"names":[],"mappings":"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"}
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting for the caretize CLI — pure functions that turn a plan /
|
|
3
|
+
* run result into the exact strings the CLI prints. Kept out of cli.ts (and free
|
|
4
|
+
* of process.stdout) so the formatting is unit-testable in isolation.
|
|
5
|
+
*/
|
|
6
|
+
import type { FilePlan, PlannedTag } from "./plan.js";
|
|
7
|
+
import type { WrapTarget } from "./wrap.js";
|
|
8
|
+
import type { PropHoistTarget } from "./prop-hoist.js";
|
|
9
|
+
import type { CollectionBindTarget } from "./bind-collection.js";
|
|
10
|
+
type BindsByFile = Map<string, CollectionBindTarget[]>;
|
|
11
|
+
/** One-line description of a tag candidate, e.g. `<h1> "Hello"` or `<img> src="…"`. */
|
|
12
|
+
export declare function tagLine(t: PlannedTag): string;
|
|
13
|
+
/** The post-scan tally line. */
|
|
14
|
+
export declare function formatScanSummary(fileCount: number, plans: FilePlan[], wrapsByFile: Map<string, WrapTarget[]>, hoistsByFile: Map<string, PropHoistTarget[]>, bindsByFile?: BindsByFile): string;
|
|
15
|
+
/** The full `--dry-run` plan dump, ending with the "nothing written" footer. */
|
|
16
|
+
export declare function formatPlan(plans: FilePlan[], wrapsByFile: Map<string, WrapTarget[]>, hoistsByFile: Map<string, PropHoistTarget[]>, bindsByFile?: BindsByFile): string;
|
|
17
|
+
/** The closing summary block after a commit. */
|
|
18
|
+
export declare function formatSummary(files: number, changes: number, wrapped: number, hoisted: number, flagged: number, hadBackups: boolean, bound?: number): string;
|
|
19
|
+
/**
|
|
20
|
+
* The actionable-skips hints — the "why isn't this editable?" answers — so a skip
|
|
21
|
+
* reads as a checklist item, not a silent omission. Adapts to the flags already
|
|
22
|
+
* passed: a hint only appears while its unlock flag is off. Returns "" when
|
|
23
|
+
* there's nothing to say.
|
|
24
|
+
*/
|
|
25
|
+
export declare function formatHints(plans: FilePlan[], rich: boolean, opts?: {
|
|
26
|
+
bindCollections?: boolean;
|
|
27
|
+
bindRoutes?: boolean;
|
|
28
|
+
}): string;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,KAAK,WAAW,GAAG,GAAG,CAAC,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC;AAEvD,uFAAuF;AACvF,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAK7C;AAED,gCAAgC;AAChC,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,QAAQ,EAAE,EACjB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,EACtC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,EAC5C,WAAW,GAAE,WAAuB,GACnC,MAAM,CASR;AAED,gFAAgF;AAChF,wBAAgB,UAAU,CACxB,KAAK,EAAE,QAAQ,EAAE,EACjB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,EACtC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,EAC5C,WAAW,GAAE,WAAuB,GACnC,MAAM,CA4BR;AAED,gDAAgD;AAChD,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,OAAO,EACnB,KAAK,SAAI,GACR,MAAM,CAUR;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,QAAQ,EAAE,EACjB,IAAI,EAAE,OAAO,EACb,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7D,MAAM,CA4BR"}
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting for the caretize CLI — pure functions that turn a plan /
|
|
3
|
+
* run result into the exact strings the CLI prints. Kept out of cli.ts (and free
|
|
4
|
+
* of process.stdout) so the formatting is unit-testable in isolation.
|
|
5
|
+
*/
|
|
6
|
+
/** One-line description of a tag candidate, e.g. `<h1> "Hello"` or `<img> src="…"`. */
|
|
7
|
+
export function tagLine(t) {
|
|
8
|
+
const text = t.candidate.text.replace(/\s+/g, " ").slice(0, 50);
|
|
9
|
+
const what = t.candidate.kind === "image" ? `src="${text}"` : `"${text}"`;
|
|
10
|
+
const rich = t.candidate.rich ? " [rich]" : "";
|
|
11
|
+
return `<${t.candidate.tag}>${rich} ${what}`;
|
|
12
|
+
}
|
|
13
|
+
/** The post-scan tally line. */
|
|
14
|
+
export function formatScanSummary(fileCount, plans, wrapsByFile, hoistsByFile, bindsByFile = new Map()) {
|
|
15
|
+
const candidateTotal = plans.reduce((n, p) => n + p.tags.length, 0);
|
|
16
|
+
const wrapTotal = [...wrapsByFile.values()].reduce((n, t) => n + t.length, 0);
|
|
17
|
+
const hoistTotal = [...hoistsByFile.values()].reduce((n, ts) => n + ts.reduce((m, t) => m + t.props.length, 0), 0);
|
|
18
|
+
const bindTotal = [...bindsByFile.values()].reduce((n, b) => n + b.length, 0);
|
|
19
|
+
const bindPart = bindTotal ? ` · ${bindTotal} collection binding(s)` : "";
|
|
20
|
+
return `✓ ${fileCount} .astro files · ${candidateTotal} tag candidate(s) · ${wrapTotal} wrap target(s) · ${hoistTotal} prop(s)${bindPart}\n`;
|
|
21
|
+
}
|
|
22
|
+
/** The full `--dry-run` plan dump, ending with the "nothing written" footer. */
|
|
23
|
+
export function formatPlan(plans, wrapsByFile, hoistsByFile, bindsByFile = new Map()) {
|
|
24
|
+
let out = "";
|
|
25
|
+
for (const plan of plans) {
|
|
26
|
+
const wraps = wrapsByFile.get(plan.relPath) ?? [];
|
|
27
|
+
const hoists = hoistsByFile.get(plan.relPath) ?? [];
|
|
28
|
+
const binds = bindsByFile.get(plan.relPath) ?? [];
|
|
29
|
+
if (plan.tags.length === 0 && plan.flags.length === 0 && wraps.length === 0 && hoists.length === 0 && binds.length === 0)
|
|
30
|
+
continue;
|
|
31
|
+
out += `\n${plan.relPath}${plan.scopeSkip ? ` (skipped: ${plan.scopeSkip})` : ""}\n`;
|
|
32
|
+
for (const t of plan.tags)
|
|
33
|
+
out += ` + data-caret="${t.binding}" ${tagLine(t)}\n`;
|
|
34
|
+
for (const w of wraps) {
|
|
35
|
+
const via = w.origin === "prop" ? " (via component prop)" : w.origin === "import" ? " (via data import)" : "";
|
|
36
|
+
const kind = w.origin === "import" ? "import" : "const";
|
|
37
|
+
out += ` ~ editable("${w.key}") wrap ${kind} ${w.varName}${via}\n`;
|
|
38
|
+
}
|
|
39
|
+
for (const h of hoists) {
|
|
40
|
+
for (const p of h.props) {
|
|
41
|
+
out += ` ⤴ editable("${p.key}") hoist <${h.componentName}> ${p.propName}${p.isRich ? " [rich]" : ""}\n`;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const b of binds) {
|
|
45
|
+
const id = b.kind === "route" ? "${entry}" : "*";
|
|
46
|
+
const note = b.kind === "route" ? "current entry" : "per-row collection loop";
|
|
47
|
+
out += ` ⟳ data-caret bind <${b.tag}> ${b.collection}::${id}::${b.field} (${note})\n`;
|
|
48
|
+
}
|
|
49
|
+
for (const f of plan.flags)
|
|
50
|
+
out += ` ⚠ ${f.method}() loop — consider a dynamic collection\n`;
|
|
51
|
+
}
|
|
52
|
+
out += "\n(dry run — nothing written)\n";
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
/** The closing summary block after a commit. */
|
|
56
|
+
export function formatSummary(files, changes, wrapped, hoisted, flagged, hadBackups, bound = 0) {
|
|
57
|
+
let out = `\n───────────────────────────────\n`;
|
|
58
|
+
out += `✓ ${changes} change(s) across ${files} file(s)\n`;
|
|
59
|
+
if (wrapped)
|
|
60
|
+
out += `✓ ${wrapped} data array(s) wrapped with editable()\n`;
|
|
61
|
+
if (hoisted)
|
|
62
|
+
out += `✓ ${hoisted} component prop(s) hoisted to editable()\n`;
|
|
63
|
+
if (bound)
|
|
64
|
+
out += `✓ ${bound} collection field(s) bound to data-caret\n`;
|
|
65
|
+
if (flagged)
|
|
66
|
+
out += `⚠ ${flagged} loop(s) flagged → consider dynamic collections\n`;
|
|
67
|
+
if (hadBackups)
|
|
68
|
+
out += `⤺ backups in .caret/.caretize-bak/ (caretize --restore to undo)\n`;
|
|
69
|
+
out += `───────────────────────────────\nNext: npm run dev → open your page → click to edit\n`;
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The actionable-skips hints — the "why isn't this editable?" answers — so a skip
|
|
74
|
+
* reads as a checklist item, not a silent omission. Adapts to the flags already
|
|
75
|
+
* passed: a hint only appears while its unlock flag is off. Returns "" when
|
|
76
|
+
* there's nothing to say.
|
|
77
|
+
*/
|
|
78
|
+
export function formatHints(plans, rich, opts = {}) {
|
|
79
|
+
let eligible = 0;
|
|
80
|
+
let styled = 0;
|
|
81
|
+
let inIterator = 0;
|
|
82
|
+
for (const p of plans) {
|
|
83
|
+
for (const s of p.skipped) {
|
|
84
|
+
if (s.reason === "rich-eligible")
|
|
85
|
+
eligible++;
|
|
86
|
+
else if (s.reason === "rich-unsafe-attrs")
|
|
87
|
+
styled++;
|
|
88
|
+
else if (s.reason === "inside-iterator")
|
|
89
|
+
inIterator++;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const dynamicRoutes = plans.filter((p) => p.scopeSkip === "dynamic-route").length;
|
|
93
|
+
let out = "";
|
|
94
|
+
if (eligible && !rich) {
|
|
95
|
+
out += `\n↪ ${eligible} mixed-content block(s) are sanitizer-safe inline markup — re-run with --rich to make them editable.\n`;
|
|
96
|
+
}
|
|
97
|
+
if (styled) {
|
|
98
|
+
out += `↪ ${styled} block(s) hold inline styling classes the rich-text sanitizer strips on save.\n` +
|
|
99
|
+
` Move the styling to CSS (style the semantic tag), or bless the class via\n` +
|
|
100
|
+
` caret({ allowedClasses: { tag: ["your-class"] } }) — then they're safe to tag.\n`;
|
|
101
|
+
}
|
|
102
|
+
if (inIterator && !opts.bindCollections) {
|
|
103
|
+
out += `↪ ${inIterator} element(s) render inside collection loops — re-run with --bind-collections to bind them per row.\n`;
|
|
104
|
+
}
|
|
105
|
+
if (dynamicRoutes && !opts.bindRoutes) {
|
|
106
|
+
out += `↪ ${dynamicRoutes} dynamic route(s) skipped — re-run with --bind-routes to bind each detail page to its entry.\n`;
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
|