@caretcms/caretize 0.1.0 → 0.1.2
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 +41 -5
- package/dist/bind-collection.js +1 -1
- package/dist/bind-collection.js.map +1 -1
- package/dist/bind-route.d.ts.map +1 -1
- package/dist/bind-route.js +9 -4
- package/dist/bind-route.js.map +1 -1
- package/dist/cli-args.d.ts +16 -1
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +39 -3
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +390 -27
- package/dist/cli.js.map +1 -1
- package/dist/detect.d.ts +17 -1
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +61 -22
- package/dist/detect.js.map +1 -1
- package/dist/diff.d.ts +20 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +75 -0
- package/dist/diff.js.map +1 -0
- package/dist/discover.d.ts.map +1 -1
- package/dist/discover.js +8 -2
- package/dist/discover.js.map +1 -1
- package/dist/escalation.d.ts +47 -0
- package/dist/escalation.d.ts.map +1 -0
- package/dist/escalation.js +112 -0
- package/dist/escalation.js.map +1 -0
- package/dist/frontmatter.d.ts +41 -4
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +122 -12
- package/dist/frontmatter.js.map +1 -1
- package/dist/import-wrap.d.ts +30 -0
- package/dist/import-wrap.d.ts.map +1 -1
- package/dist/import-wrap.js +101 -7
- package/dist/import-wrap.js.map +1 -1
- package/dist/init.d.ts +70 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +198 -0
- package/dist/init.js.map +1 -0
- package/dist/keys.d.ts +55 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +84 -0
- package/dist/keys.js.map +1 -0
- package/dist/output.d.ts +63 -10
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +190 -22
- package/dist/output.js.map +1 -1
- package/dist/plan.d.ts +7 -0
- package/dist/plan.d.ts.map +1 -1
- package/dist/plan.js +17 -4
- package/dist/plan.js.map +1 -1
- package/dist/preflight.d.ts +2 -0
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +18 -3
- package/dist/preflight.js.map +1 -1
- package/dist/run.js +6 -4
- package/dist/run.js.map +1 -1
- package/dist/select-policy.d.ts +38 -0
- package/dist/select-policy.d.ts.map +1 -0
- package/dist/select-policy.js +44 -0
- package/dist/select-policy.js.map +1 -0
- package/dist/tiers.d.ts +42 -0
- package/dist/tiers.d.ts.map +1 -0
- package/dist/tiers.js +67 -0
- package/dist/tiers.js.map +1 -0
- package/dist/wrap.d.ts +9 -4
- package/dist/wrap.d.ts.map +1 -1
- package/dist/wrap.js +3 -2
- package/dist/wrap.js.map +1 -1
- package/package.json +2 -2
package/dist/detect.d.ts
CHANGED
|
@@ -35,6 +35,22 @@ export interface DetectOptions {
|
|
|
35
35
|
* call, so it's opt-in via the CLI `--rich` flag.
|
|
36
36
|
*/
|
|
37
37
|
rich?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Also promote a mixed-content block whose inline children carry a `class` the
|
|
40
|
+
* sanitizer strips unless blessed via the runtime `allowedClasses` config —
|
|
41
|
+
* tagging it `data-caret-rich` even though caretize can't see that config. The
|
|
42
|
+
* styled `class` round-trips only once the user blesses it; the hint names the
|
|
43
|
+
* exact classes. Requires `rich`. Off by default; turned on by `--all` /
|
|
44
|
+
* `--rich-class`. Blocks with any OTHER stripped attr stay `rich-unsafe-attrs`.
|
|
45
|
+
*/
|
|
46
|
+
richClass?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Local names that `astro:assets` `Image`/`Picture` are imported under (from
|
|
49
|
+
* `imageComponentNames`). These component nodes render to a native `<img>`
|
|
50
|
+
* Astro forwards `data-caret` to, so they're treated as image candidates.
|
|
51
|
+
* Empty/absent by default → components are skipped as before.
|
|
52
|
+
*/
|
|
53
|
+
imageComponents?: ReadonlySet<string>;
|
|
38
54
|
}
|
|
39
55
|
export interface Skipped {
|
|
40
56
|
decision: "skip";
|
|
@@ -43,7 +59,7 @@ export interface Skipped {
|
|
|
43
59
|
startOffset: number;
|
|
44
60
|
reason: SkipReason;
|
|
45
61
|
}
|
|
46
|
-
export type SkipReason = "already-tagged" | "component" | "inside-expression" | "inside-iterator" | "dynamic-content" | "inside-rich" | "mixed-children" | "rich-eligible" | "rich-unsafe-attrs" | "empty" | "not-content";
|
|
62
|
+
export type SkipReason = "already-tagged" | "component" | "inside-expression" | "inside-iterator" | "dynamic-content" | "inside-rich" | "mixed-children" | "rich-eligible" | "rich-class-promotable" | "rich-unsafe-attrs" | "empty" | "not-content";
|
|
47
63
|
export interface IteratorFlag {
|
|
48
64
|
/** Byte offset of the enclosing expression. */
|
|
49
65
|
startOffset: number;
|
package/dist/detect.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAa,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AACnD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC;AAE7C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,KAAK,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAa,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AACnD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC;AAE7C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,KAAK,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACvC;AAID,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,MAAM,UAAU,GAClB,gBAAgB,GAChB,WAAW,GACX,mBAAmB,GACnB,iBAAiB,GACjB,iBAAiB,GACjB,aAAa,GACb,gBAAgB,GAChB,eAAe,GACf,uBAAuB,GACvB,mBAAmB,GACnB,OAAO,GACP,aAAa,CAAC;AAElB,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf;kFAC8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,2EAA2E;IAC3E,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AASD,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAOjD,CAAC;AAEF;gFACgF;AAChF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAExD;AAcD,eAAO,MAAM,gBAAgB,aAE3B,CAAC;AAOH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAEvD,CAAC;AACF,eAAO,MAAM,YAAY,QAAkC,CAAC;AA8G5D;;;;;GAKG;AACH,wBAAgB,MAAM,CACpB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,IAAI,KAAK,IAAI,EACpF,OAAO,GAAE,aAAkB,GAC1B,YAAY,CA6Gd"}
|
package/dist/detect.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* edit is skipped (with a reason) rather than tagged into an inert binding.
|
|
10
10
|
*/
|
|
11
11
|
import { isTagNode } from "./parse.js";
|
|
12
|
+
const NO_IMAGE_COMPONENTS = new Set();
|
|
12
13
|
// Content tags we'll tag, with their confidence tier. Anything not listed is
|
|
13
14
|
// treated as non-content and skipped (whitelist, not blacklist).
|
|
14
15
|
//
|
|
@@ -41,7 +42,7 @@ const ITERATOR_RE = /(?:([A-Za-z_$][\w$]*)\s*)?\.\s*(map|filter|forEach|flatMap|
|
|
|
41
42
|
// save, so promoting it would not round-trip. Held in lockstep by
|
|
42
43
|
// tests/unit/contracts-parity.test.ts.
|
|
43
44
|
export const RICH_INLINE_TAGS = new Set([
|
|
44
|
-
"b", "strong", "i", "em", "u", "s", "a", "br", "sub", "sup",
|
|
45
|
+
"b", "strong", "i", "em", "u", "s", "a", "br", "sub", "sup", "span",
|
|
45
46
|
]);
|
|
46
47
|
// Attributes the sanitizer keeps. Everything else (notably `class`) is stripped
|
|
47
48
|
// on save unless blessed via the runtime `allowedClasses` option — which the
|
|
@@ -52,25 +53,31 @@ export const RICH_SAFE_ATTRS = {
|
|
|
52
53
|
a: new Set(["href", "target", "rel"]),
|
|
53
54
|
};
|
|
54
55
|
export const SAFE_HREF_RE = /^(?:https?:|mailto:|tel:|\/)/i;
|
|
55
|
-
|
|
56
|
-
function inlineAttrsSafe(node) {
|
|
56
|
+
function inlineAttrVerdict(node) {
|
|
57
57
|
const allowed = RICH_SAFE_ATTRS[node.name.toLowerCase()];
|
|
58
|
+
let sawClass = false;
|
|
58
59
|
for (const a of node.attributes ?? []) {
|
|
60
|
+
if (a.name === "class") {
|
|
61
|
+
sawClass = true;
|
|
62
|
+
continue; // class is gated by allowedClasses, not stripped outright
|
|
63
|
+
}
|
|
59
64
|
if (!allowed || !allowed.has(a.name))
|
|
60
|
-
return
|
|
65
|
+
return "unsafe";
|
|
61
66
|
if (a.name === "href" && !SAFE_HREF_RE.test(a.value ?? ""))
|
|
62
|
-
return
|
|
67
|
+
return "unsafe";
|
|
63
68
|
}
|
|
64
|
-
return
|
|
69
|
+
return sawClass ? "class-only" : "safe";
|
|
65
70
|
}
|
|
66
71
|
/**
|
|
67
72
|
* Classify a mixed-content element's subtree for rich promotion. Walks every
|
|
68
73
|
* descendant: a non-inline tag / component / expression makes it "not-inline";
|
|
69
|
-
* an inline tag carrying a stripped
|
|
70
|
-
*
|
|
74
|
+
* an inline tag carrying a non-class stripped attr makes it "rich-unsafe-attrs";
|
|
75
|
+
* an inline tag whose only stripped attr is class makes it "rich-class";
|
|
76
|
+
* otherwise "rich-safe". The worst verdict seen wins (unsafe > class > safe).
|
|
71
77
|
*/
|
|
72
78
|
function classifyRichShape(node) {
|
|
73
|
-
let
|
|
79
|
+
let sawClassOnly = false;
|
|
80
|
+
let sawUnsafe = false;
|
|
74
81
|
const visit = (n) => {
|
|
75
82
|
for (const child of n.children ?? []) {
|
|
76
83
|
if (child.type === "text")
|
|
@@ -82,10 +89,12 @@ function classifyRichShape(node) {
|
|
|
82
89
|
return "not-inline"; // component/fragment
|
|
83
90
|
if (!RICH_INLINE_TAGS.has(child.name.toLowerCase()))
|
|
84
91
|
return "not-inline";
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (
|
|
92
|
+
const verdict = inlineAttrVerdict(child);
|
|
93
|
+
if (verdict === "unsafe")
|
|
94
|
+
sawUnsafe = true;
|
|
95
|
+
else if (verdict === "class-only")
|
|
96
|
+
sawClassOnly = true;
|
|
97
|
+
if (visit(child) === "not-inline")
|
|
89
98
|
return "not-inline";
|
|
90
99
|
}
|
|
91
100
|
// comments/doctype are inert — ignore
|
|
@@ -94,7 +103,11 @@ function classifyRichShape(node) {
|
|
|
94
103
|
};
|
|
95
104
|
if (visit(node) === "not-inline")
|
|
96
105
|
return "not-inline";
|
|
97
|
-
|
|
106
|
+
if (sawUnsafe)
|
|
107
|
+
return "rich-unsafe-attrs";
|
|
108
|
+
if (sawClassOnly)
|
|
109
|
+
return "rich-class";
|
|
110
|
+
return "rich-safe";
|
|
98
111
|
}
|
|
99
112
|
function attr(node, name) {
|
|
100
113
|
return node.attributes.find((a) => a.name === name)?.value;
|
|
@@ -153,6 +166,7 @@ function expressionText(expr) {
|
|
|
153
166
|
export function detect(root, walk, options = {}) {
|
|
154
167
|
const candidates = [];
|
|
155
168
|
const skipped = [];
|
|
169
|
+
const imageComponents = options.imageComponents ?? NO_IMAGE_COMPONENTS;
|
|
156
170
|
const flagsByOffset = new Map();
|
|
157
171
|
// Nodes promoted to data-caret-rich. Their descendants must NOT be tagged
|
|
158
172
|
// separately (the rich field owns the whole subtree); walkTags is preorder,
|
|
@@ -164,13 +178,28 @@ export function detect(root, walk, options = {}) {
|
|
|
164
178
|
const skip = (reason) => {
|
|
165
179
|
skipped.push({ decision: "skip", node, tag, startOffset, reason });
|
|
166
180
|
};
|
|
167
|
-
if (hasCaretAttr(node))
|
|
181
|
+
if (hasCaretAttr(node)) {
|
|
182
|
+
// An element already promoted to data-caret-rich still owns its whole
|
|
183
|
+
// subtree on a re-run. Register it as a rich host so its inline
|
|
184
|
+
// descendants are skipped as inside-rich rather than re-tagged at low
|
|
185
|
+
// confidence — without this, a second pass (e.g. --all = rich + low) would
|
|
186
|
+
// mint a duplicate binding inside an existing rich field.
|
|
187
|
+
if (node.attributes.some((a) => a.name === "data-caret-rich"))
|
|
188
|
+
richHosts.add(node);
|
|
168
189
|
return skip("already-tagged");
|
|
190
|
+
}
|
|
169
191
|
// Inside a node we already promoted to rich → the rich field owns it.
|
|
170
192
|
if (ancestors.some((a) => richHosts.has(a)))
|
|
171
193
|
return skip("inside-rich");
|
|
172
|
-
|
|
173
|
-
|
|
194
|
+
// astro:assets <Image>/<Picture> are component nodes, but they render to a
|
|
195
|
+
// native <img> that Astro forwards data-caret to — so they're image
|
|
196
|
+
// candidates, not opaque components. Recognized only when resolved from an
|
|
197
|
+
// `import … from "astro:assets"` (via options.imageComponents); they still
|
|
198
|
+
// fall through the iterator/expression skip below, so an <Image> inside a
|
|
199
|
+
// .map() is deferred, not mis-tagged.
|
|
200
|
+
const isImageComponent = node.type === "component" && imageComponents.has(node.name);
|
|
201
|
+
if (node.type !== "element" && !isImageComponent)
|
|
202
|
+
return skip("component");
|
|
174
203
|
// Dynamic context: inside any {expression}. Record an iterator flag if the
|
|
175
204
|
// enclosing expression looks like a .map()/.filter() loop.
|
|
176
205
|
const expr = nearestExpressionAncestor(ancestors);
|
|
@@ -185,13 +214,17 @@ export function detect(root, walk, options = {}) {
|
|
|
185
214
|
}
|
|
186
215
|
return skip(m ? "inside-iterator" : "inside-expression");
|
|
187
216
|
}
|
|
188
|
-
if (tag === "img") {
|
|
189
|
-
const
|
|
190
|
-
if (
|
|
217
|
+
if (tag === "img" || isImageComponent) {
|
|
218
|
+
const srcAttr = node.attributes.find((a) => a.name === "src");
|
|
219
|
+
if (srcAttr === undefined || srcAttr.value.trim() === "")
|
|
191
220
|
return skip("empty");
|
|
221
|
+
// A dynamic src (`src={expr}`, template literal, shorthand) has no
|
|
222
|
+
// author-time URL to surface in review; the binding key is assigned by
|
|
223
|
+
// assignFields regardless, and the engine swaps the rendered <img> src.
|
|
224
|
+
const staticSrc = srcAttr.kind === "quoted" || srcAttr.kind === undefined;
|
|
192
225
|
candidates.push({
|
|
193
226
|
decision: "tag", kind: "image", node, tag, startOffset,
|
|
194
|
-
confidence: "high", text:
|
|
227
|
+
confidence: "high", text: staticSrc ? srcAttr.value : "",
|
|
195
228
|
});
|
|
196
229
|
return;
|
|
197
230
|
}
|
|
@@ -213,8 +246,14 @@ export function detect(root, walk, options = {}) {
|
|
|
213
246
|
return skip("mixed-children");
|
|
214
247
|
if (richShape === "rich-unsafe-attrs")
|
|
215
248
|
return skip("rich-unsafe-attrs");
|
|
249
|
+
if (richShape === "rich-class" && !(options.rich && options.richClass)) {
|
|
250
|
+
// Inline-only except for a class the sanitizer strips unless blessed via
|
|
251
|
+
// allowedClasses. Surfaced (so the hint can name the classes) until both
|
|
252
|
+
// --rich and --rich-class (the latter rides in --all) are on.
|
|
253
|
+
return skip("rich-class-promotable");
|
|
254
|
+
}
|
|
216
255
|
// rich-safe: promote only when opted in; otherwise report it as eligible.
|
|
217
|
-
if (!options.rich)
|
|
256
|
+
if (richShape === "rich-safe" && !options.rich)
|
|
218
257
|
return skip("rich-eligible");
|
|
219
258
|
richHosts.add(node);
|
|
220
259
|
candidates.push({
|
package/dist/detect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAgC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"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"}
|
package/dist/diff.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tiny line-level diff (LCS) — no dependency. caretize's writes are pure
|
|
3
|
+
* insertions plus a few rewritten frontmatter lines (the `editable()` wraps), so
|
|
4
|
+
* a line diff renders "what changed" faithfully for the `--diff` preview. O(n·m)
|
|
5
|
+
* over line counts, which is fine for source files.
|
|
6
|
+
*/
|
|
7
|
+
export interface DiffLine {
|
|
8
|
+
/** " " unchanged · "-" removed (original) · "+" added (output). */
|
|
9
|
+
kind: " " | "-" | "+";
|
|
10
|
+
text: string;
|
|
11
|
+
}
|
|
12
|
+
/** Line-level diff of `before` → `after` via a longest-common-subsequence walk. */
|
|
13
|
+
export declare function lineDiff(before: string, after: string): DiffLine[];
|
|
14
|
+
/**
|
|
15
|
+
* Collapse a full diff into hunks: changed lines plus up to `context` unchanged
|
|
16
|
+
* lines around them; long unchanged runs become a single `…` marker. Returns the
|
|
17
|
+
* rendered hunk body (no file header). Empty string when nothing changed.
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatHunks(lines: DiffLine[], context?: number): string;
|
|
20
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,QAAQ;IACvB,mEAAmE;IACnE,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,mFAAmF;AACnF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAiClE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,SAAI,GAAG,MAAM,CAwBlE"}
|
package/dist/diff.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tiny line-level diff (LCS) — no dependency. caretize's writes are pure
|
|
3
|
+
* insertions plus a few rewritten frontmatter lines (the `editable()` wraps), so
|
|
4
|
+
* a line diff renders "what changed" faithfully for the `--diff` preview. O(n·m)
|
|
5
|
+
* over line counts, which is fine for source files.
|
|
6
|
+
*/
|
|
7
|
+
/** Line-level diff of `before` → `after` via a longest-common-subsequence walk. */
|
|
8
|
+
export function lineDiff(before, after) {
|
|
9
|
+
const a = before.split("\n");
|
|
10
|
+
const b = after.split("\n");
|
|
11
|
+
const m = a.length;
|
|
12
|
+
const n = b.length;
|
|
13
|
+
// dp[i][j] = LCS length of a[i:] and b[j:].
|
|
14
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
15
|
+
for (let i = m - 1; i >= 0; i--) {
|
|
16
|
+
for (let j = n - 1; j >= 0; j--) {
|
|
17
|
+
dp[i][j] = a[i] === b[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const out = [];
|
|
21
|
+
let i = 0;
|
|
22
|
+
let j = 0;
|
|
23
|
+
while (i < m && j < n) {
|
|
24
|
+
if (a[i] === b[j]) {
|
|
25
|
+
out.push({ kind: " ", text: a[i] });
|
|
26
|
+
i++;
|
|
27
|
+
j++;
|
|
28
|
+
}
|
|
29
|
+
else if (dp[i + 1][j] >= dp[i][j + 1]) {
|
|
30
|
+
out.push({ kind: "-", text: a[i] });
|
|
31
|
+
i++;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
out.push({ kind: "+", text: b[j] });
|
|
35
|
+
j++;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
while (i < m)
|
|
39
|
+
out.push({ kind: "-", text: a[i++] });
|
|
40
|
+
while (j < n)
|
|
41
|
+
out.push({ kind: "+", text: b[j++] });
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Collapse a full diff into hunks: changed lines plus up to `context` unchanged
|
|
46
|
+
* lines around them; long unchanged runs become a single `…` marker. Returns the
|
|
47
|
+
* rendered hunk body (no file header). Empty string when nothing changed.
|
|
48
|
+
*/
|
|
49
|
+
export function formatHunks(lines, context = 2) {
|
|
50
|
+
// Mark which unchanged lines are within `context` of a change → kept.
|
|
51
|
+
const changed = lines.map((l) => l.kind !== " ");
|
|
52
|
+
const keep = new Array(lines.length).fill(false);
|
|
53
|
+
for (let i = 0; i < lines.length; i++) {
|
|
54
|
+
if (!changed[i])
|
|
55
|
+
continue;
|
|
56
|
+
for (let k = Math.max(0, i - context); k <= Math.min(lines.length - 1, i + context); k++) {
|
|
57
|
+
keep[k] = true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const rows = [];
|
|
61
|
+
let gap = false;
|
|
62
|
+
for (let i = 0; i < lines.length; i++) {
|
|
63
|
+
if (keep[i]) {
|
|
64
|
+
rows.push(` ${lines[i].kind} ${lines[i].text}`);
|
|
65
|
+
gap = false;
|
|
66
|
+
}
|
|
67
|
+
else if (!gap) {
|
|
68
|
+
rows.push(" …");
|
|
69
|
+
gap = true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// A pure-gap result (no kept lines) means no changes.
|
|
73
|
+
return rows.some((r) => r !== " …") ? rows.join("\n") + "\n" : "";
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=diff.js.map
|
package/dist/diff.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
|
package/dist/discover.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4BH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAkD7E"}
|
package/dist/discover.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* inside the project it was pointed at).
|
|
7
7
|
*/
|
|
8
8
|
import { readdirSync, statSync, lstatSync, realpathSync } from "node:fs";
|
|
9
|
-
import { join, relative, resolve, sep } from "node:path";
|
|
9
|
+
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
10
10
|
const SKIP_DIRS = new Set([
|
|
11
11
|
"node_modules",
|
|
12
12
|
".astro",
|
|
@@ -25,7 +25,8 @@ function isSkippedFile(name) {
|
|
|
25
25
|
/** True if `child` resolves to a path inside `root` (no symlink escape). */
|
|
26
26
|
function isInside(root, child) {
|
|
27
27
|
const rel = relative(root, child);
|
|
28
|
-
|
|
28
|
+
// `relative` is absolute only when the paths share no root (other drive).
|
|
29
|
+
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
31
32
|
* Walk `target` (a file or directory) under `rootDir`, returning project-root-
|
|
@@ -34,6 +35,11 @@ function isInside(root, child) {
|
|
|
34
35
|
export function discoverAstroFiles(rootDir, target) {
|
|
35
36
|
const root = resolve(rootDir);
|
|
36
37
|
const start = resolve(root, target ?? "src");
|
|
38
|
+
// SKIP_DIRS guards descent below, but an EXPLICIT target like
|
|
39
|
+
// `node_modules/pkg/src` starts inside one — check every ancestor segment.
|
|
40
|
+
const startRel = relative(root, start);
|
|
41
|
+
if (startRel.split(sep).some((segment) => SKIP_DIRS.has(segment)))
|
|
42
|
+
return [];
|
|
37
43
|
const found = [];
|
|
38
44
|
const visit = (abs) => {
|
|
39
45
|
let st;
|
package/dist/discover.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for the in-flow escalation step (the interactive "I can also make
|
|
3
|
+
* these editable" prompt). Kept out of cli.ts — which self-executes on import —
|
|
4
|
+
* so the decision/merge logic is unit-testable. cli.ts owns only the readline
|
|
5
|
+
* I/O and the (cheap, side-effect-free) re-analysis; everything it decides flows
|
|
6
|
+
* through these functions and `selectTiers`.
|
|
7
|
+
*/
|
|
8
|
+
import type { FilePlan, PlannedTag } from "./plan.js";
|
|
9
|
+
import type { CollectionBindTarget } from "./bind-collection.js";
|
|
10
|
+
import { type TierId } from "./tiers.js";
|
|
11
|
+
export type EscalationCounts = Record<TierId, number>;
|
|
12
|
+
/**
|
|
13
|
+
* Tally the remaining opt-in coverage per tier, from the CONSERVATIVE analysis
|
|
14
|
+
* plus the collection/route bind targets detected for the offer:
|
|
15
|
+
* - rich = elements skipped as "rich-eligible" (would tag with --rich)
|
|
16
|
+
* - rich-class = elements skipped as "rich-class-promotable" (need --rich-class)
|
|
17
|
+
* - lowconf = candidates dropped by the confidence floor (`belowConfidence`)
|
|
18
|
+
* - collections / routes = the bind targets, split by kind
|
|
19
|
+
*/
|
|
20
|
+
export declare function escalationCounts(conservativePlans: FilePlan[], offerBinds: Map<string, CollectionBindTarget[]>): EscalationCounts;
|
|
21
|
+
/** Total across all tiers — 0 means there's nothing to offer. */
|
|
22
|
+
export declare function totalOffer(counts: EscalationCounts): number;
|
|
23
|
+
/** Zero out tiers that are already on (Phase A flags / --all) so the offer never
|
|
24
|
+
* re-counts coverage the conservative pass already applied. Returns a copy. */
|
|
25
|
+
export declare function offerableCounts(counts: EscalationCounts, active: ReadonlySet<TierId>): EscalationCounts;
|
|
26
|
+
/** Tier ids with a non-zero count, in TIERS order — what the prompt can offer. */
|
|
27
|
+
export declare function offeredTiers(counts: Partial<Record<TierId, number>>): TierId[];
|
|
28
|
+
/** The set the in-flow [Y] applies: the recommended tiers that are actually on
|
|
29
|
+
* offer. Falls back to ALL offered tiers when none of the offered ones are
|
|
30
|
+
* recommended (e.g. only low-confidence is left), so [Y] is never a no-op. */
|
|
31
|
+
export declare function recommendedBundle(counts: Partial<Record<TierId, number>>): TierId[];
|
|
32
|
+
/**
|
|
33
|
+
* The escalation-only tags: tags in the FINAL (chosen-tier) analysis at offsets
|
|
34
|
+
* the CONSERVATIVE analysis did not already produce — i.e. the rich promotions
|
|
35
|
+
* and below-floor tags the chosen tiers unlocked. The default-tier tags (same
|
|
36
|
+
* offsets in both passes) are excluded; the user already reviewed those.
|
|
37
|
+
* Returned per relPath, ready to merge into the reviewed selection.
|
|
38
|
+
*/
|
|
39
|
+
export declare function deltaTags(conservativePlans: FilePlan[], finalPlans: FilePlan[]): Map<string, PlannedTag[]>;
|
|
40
|
+
/** Append `delta` tag lists onto a copy of `base`, per relPath. */
|
|
41
|
+
export declare function mergeTagMaps(base: Map<string, PlannedTag[]>, delta: Map<string, PlannedTag[]>): Map<string, PlannedTag[]>;
|
|
42
|
+
export type RawAnswer = "yes" | "no" | "customize" | "unknown";
|
|
43
|
+
/** Classify the top-level escalation answer. Empty = the [Y] default. */
|
|
44
|
+
export declare function parseAnswer(raw: string): RawAnswer;
|
|
45
|
+
/** Classify a per-tier customize answer. Empty = keep the tier's recommendation. */
|
|
46
|
+
export declare function parseToggle(raw: string, recommended: boolean): boolean;
|
|
47
|
+
//# sourceMappingURL=escalation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escalation.d.ts","sourceRoot":"","sources":["../src/escalation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAS,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAGhD,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,iBAAiB,EAAE,QAAQ,EAAE,EAC7B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,EAAE,CAAC,GAC9C,gBAAgB,CAoBlB;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAE3D;AAED;gFACgF;AAChF,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,GAC1B,gBAAgB,CAIlB;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE,CAE9E;AAED;;+EAE+E;AAC/E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE,CAKnF;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,iBAAiB,EAAE,QAAQ,EAAE,EAC7B,UAAU,EAAE,QAAQ,EAAE,GACrB,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAW3B;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAC1B,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,EAC/B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,GAC/B,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAM3B;AAED,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,IAAI,GAAG,WAAW,GAAG,SAAS,CAAC;AAE/D,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAMlD;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO,CAItE"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for the in-flow escalation step (the interactive "I can also make
|
|
3
|
+
* these editable" prompt). Kept out of cli.ts — which self-executes on import —
|
|
4
|
+
* so the decision/merge logic is unit-testable. cli.ts owns only the readline
|
|
5
|
+
* I/O and the (cheap, side-effect-free) re-analysis; everything it decides flows
|
|
6
|
+
* through these functions and `selectTiers`.
|
|
7
|
+
*/
|
|
8
|
+
import { TIERS } from "./tiers.js";
|
|
9
|
+
import { recommendedTiers } from "./select-policy.js";
|
|
10
|
+
/**
|
|
11
|
+
* Tally the remaining opt-in coverage per tier, from the CONSERVATIVE analysis
|
|
12
|
+
* plus the collection/route bind targets detected for the offer:
|
|
13
|
+
* - rich = elements skipped as "rich-eligible" (would tag with --rich)
|
|
14
|
+
* - rich-class = elements skipped as "rich-class-promotable" (need --rich-class)
|
|
15
|
+
* - lowconf = candidates dropped by the confidence floor (`belowConfidence`)
|
|
16
|
+
* - collections / routes = the bind targets, split by kind
|
|
17
|
+
*/
|
|
18
|
+
export function escalationCounts(conservativePlans, offerBinds) {
|
|
19
|
+
let rich = 0;
|
|
20
|
+
let richClass = 0;
|
|
21
|
+
let lowconf = 0;
|
|
22
|
+
let collections = 0;
|
|
23
|
+
let routes = 0;
|
|
24
|
+
for (const p of conservativePlans) {
|
|
25
|
+
lowconf += p.belowConfidence;
|
|
26
|
+
for (const s of p.skipped) {
|
|
27
|
+
if (s.reason === "rich-eligible")
|
|
28
|
+
rich++;
|
|
29
|
+
else if (s.reason === "rich-class-promotable")
|
|
30
|
+
richClass++;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const binds of offerBinds.values()) {
|
|
34
|
+
for (const b of binds) {
|
|
35
|
+
if (b.kind === "route")
|
|
36
|
+
routes++;
|
|
37
|
+
else
|
|
38
|
+
collections++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { collections, routes, rich, "rich-class": richClass, lowconf };
|
|
42
|
+
}
|
|
43
|
+
/** Total across all tiers — 0 means there's nothing to offer. */
|
|
44
|
+
export function totalOffer(counts) {
|
|
45
|
+
return counts.collections + counts.routes + counts.rich + counts["rich-class"] + counts.lowconf;
|
|
46
|
+
}
|
|
47
|
+
/** Zero out tiers that are already on (Phase A flags / --all) so the offer never
|
|
48
|
+
* re-counts coverage the conservative pass already applied. Returns a copy. */
|
|
49
|
+
export function offerableCounts(counts, active) {
|
|
50
|
+
const out = { ...counts };
|
|
51
|
+
for (const id of active)
|
|
52
|
+
out[id] = 0;
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
/** Tier ids with a non-zero count, in TIERS order — what the prompt can offer. */
|
|
56
|
+
export function offeredTiers(counts) {
|
|
57
|
+
return TIERS.filter((t) => (counts[t.id] ?? 0) > 0).map((t) => t.id);
|
|
58
|
+
}
|
|
59
|
+
/** The set the in-flow [Y] applies: the recommended tiers that are actually on
|
|
60
|
+
* offer. Falls back to ALL offered tiers when none of the offered ones are
|
|
61
|
+
* recommended (e.g. only low-confidence is left), so [Y] is never a no-op. */
|
|
62
|
+
export function recommendedBundle(counts) {
|
|
63
|
+
const offered = offeredTiers(counts);
|
|
64
|
+
const rec = recommendedTiers();
|
|
65
|
+
const recOffered = offered.filter((id) => rec.has(id));
|
|
66
|
+
return recOffered.length > 0 ? recOffered : offered;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The escalation-only tags: tags in the FINAL (chosen-tier) analysis at offsets
|
|
70
|
+
* the CONSERVATIVE analysis did not already produce — i.e. the rich promotions
|
|
71
|
+
* and below-floor tags the chosen tiers unlocked. The default-tier tags (same
|
|
72
|
+
* offsets in both passes) are excluded; the user already reviewed those.
|
|
73
|
+
* Returned per relPath, ready to merge into the reviewed selection.
|
|
74
|
+
*/
|
|
75
|
+
export function deltaTags(conservativePlans, finalPlans) {
|
|
76
|
+
const seenByPath = new Map(conservativePlans.map((p) => [p.relPath, new Set(p.tags.map((t) => t.startOffset))]));
|
|
77
|
+
const out = new Map();
|
|
78
|
+
for (const p of finalPlans) {
|
|
79
|
+
const seen = seenByPath.get(p.relPath) ?? new Set();
|
|
80
|
+
const delta = p.tags.filter((t) => !seen.has(t.startOffset));
|
|
81
|
+
if (delta.length)
|
|
82
|
+
out.set(p.relPath, delta);
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
/** Append `delta` tag lists onto a copy of `base`, per relPath. */
|
|
87
|
+
export function mergeTagMaps(base, delta) {
|
|
88
|
+
const out = new Map(base);
|
|
89
|
+
for (const [rel, tags] of delta) {
|
|
90
|
+
out.set(rel, [...(out.get(rel) ?? []), ...tags]);
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
/** Classify the top-level escalation answer. Empty = the [Y] default. */
|
|
95
|
+
export function parseAnswer(raw) {
|
|
96
|
+
const a = raw.trim().toLowerCase();
|
|
97
|
+
if (a === "" || a === "y" || a === "yes")
|
|
98
|
+
return "yes";
|
|
99
|
+
if (a === "n" || a === "no")
|
|
100
|
+
return "no";
|
|
101
|
+
if (a === "c" || a === "customize")
|
|
102
|
+
return "customize";
|
|
103
|
+
return "unknown";
|
|
104
|
+
}
|
|
105
|
+
/** Classify a per-tier customize answer. Empty = keep the tier's recommendation. */
|
|
106
|
+
export function parseToggle(raw, recommended) {
|
|
107
|
+
const a = raw.trim().toLowerCase();
|
|
108
|
+
if (a === "")
|
|
109
|
+
return recommended;
|
|
110
|
+
return a === "y" || a === "yes";
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=escalation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escalation.js","sourceRoot":"","sources":["../src/escalation.ts"],"names":[],"mappings":"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"}
|