davaux 0.8.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/BASELINE.md +169 -0
- package/CLAUDE.md +518 -0
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/ROADMAP.md +198 -0
- package/build.mjs +101 -0
- package/client/control.ts +247 -0
- package/client/hydrate.ts +37 -0
- package/client/index.ts +19 -0
- package/client/jsx-runtime.ts +209 -0
- package/client/resource.ts +122 -0
- package/client/signal.ts +211 -0
- package/client/store.ts +110 -0
- package/client/useHead.ts +63 -0
- package/dist/build/config.d.ts +3 -0
- package/dist/build/config.d.ts.map +1 -0
- package/dist/build/config.js +38 -0
- package/dist/build/config.js.map +7 -0
- package/dist/build/index.d.ts +2 -0
- package/dist/build/index.d.ts.map +1 -0
- package/dist/build/index.js +13 -0
- package/dist/build/index.js.map +7 -0
- package/dist/build/plugins.d.ts +7 -0
- package/dist/build/plugins.d.ts.map +1 -0
- package/dist/build/plugins.js +85 -0
- package/dist/build/plugins.js.map +7 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +427 -0
- package/dist/cli.js.map +7 -0
- package/dist/client/control.d.ts +49 -0
- package/dist/client/control.d.ts.map +1 -0
- package/dist/client/control.js +154 -0
- package/dist/client/control.js.map +7 -0
- package/dist/client/hydrate.d.ts +7 -0
- package/dist/client/hydrate.d.ts.map +1 -0
- package/dist/client/hydrate.js +23 -0
- package/dist/client/hydrate.js.map +7 -0
- package/dist/client/index.d.ts +12 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +32 -0
- package/dist/client/index.js.map +7 -0
- package/dist/client/jsx-runtime.d.ts +40 -0
- package/dist/client/jsx-runtime.d.ts.map +1 -0
- package/dist/client/jsx-runtime.js +139 -0
- package/dist/client/jsx-runtime.js.map +7 -0
- package/dist/client/resource.d.ts +31 -0
- package/dist/client/resource.d.ts.map +1 -0
- package/dist/client/resource.js +64 -0
- package/dist/client/resource.js.map +7 -0
- package/dist/client/signal.d.ts +90 -0
- package/dist/client/signal.d.ts.map +1 -0
- package/dist/client/signal.js +115 -0
- package/dist/client/signal.js.map +7 -0
- package/dist/client/store.d.ts +26 -0
- package/dist/client/store.d.ts.map +1 -0
- package/dist/client/store.js +63 -0
- package/dist/client/store.js.map +7 -0
- package/dist/client/useHead.d.ts +28 -0
- package/dist/client/useHead.d.ts.map +1 -0
- package/dist/client/useHead.js +33 -0
- package/dist/client/useHead.js.map +7 -0
- package/dist/config.d.ts +182 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +21 -0
- package/dist/config.js.map +7 -0
- package/dist/create-multisite.d.ts +2 -0
- package/dist/create-multisite.d.ts.map +1 -0
- package/dist/create-multisite.js +291 -0
- package/dist/create-multisite.js.map +7 -0
- package/dist/create.d.ts +2 -0
- package/dist/create.d.ts.map +1 -0
- package/dist/create.js +179 -0
- package/dist/create.js.map +7 -0
- package/dist/dev/blueprints.d.ts +11 -0
- package/dist/dev/blueprints.d.ts.map +1 -0
- package/dist/dev/blueprints.js +65 -0
- package/dist/dev/blueprints.js.map +7 -0
- package/dist/dev/components.d.ts +19 -0
- package/dist/dev/components.d.ts.map +1 -0
- package/dist/dev/components.js +87 -0
- package/dist/dev/components.js.map +7 -0
- package/dist/dev/insert.d.ts +11 -0
- package/dist/dev/insert.d.ts.map +1 -0
- package/dist/dev/insert.js +160 -0
- package/dist/dev/insert.js.map +7 -0
- package/dist/dev/remove.d.ts +53 -0
- package/dist/dev/remove.d.ts.map +1 -0
- package/dist/dev/remove.js +518 -0
- package/dist/dev/remove.js.map +7 -0
- package/dist/dev/watch.d.ts +26 -0
- package/dist/dev/watch.d.ts.map +1 -0
- package/dist/dev/watch.js +2905 -0
- package/dist/dev/watch.js.map +7 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +63 -0
- package/dist/errors.js.map +7 -0
- package/dist/generate.d.ts +2 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +191 -0
- package/dist/generate.js.map +7 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +7 -0
- package/dist/island.d.ts +24 -0
- package/dist/island.d.ts.map +1 -0
- package/dist/island.js +15 -0
- package/dist/island.js.map +7 -0
- package/dist/jsx-runtime.d.ts +406 -0
- package/dist/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx-runtime.js +90 -0
- package/dist/jsx-runtime.js.map +7 -0
- package/dist/link.d.ts +27 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +29 -0
- package/dist/link.js.map +7 -0
- package/dist/oml/fragment.d.ts +16 -0
- package/dist/oml/fragment.d.ts.map +1 -0
- package/dist/oml/fragment.js +26 -0
- package/dist/oml/fragment.js.map +7 -0
- package/dist/oml/index.d.ts +11 -0
- package/dist/oml/index.d.ts.map +1 -0
- package/dist/oml/index.js +21 -0
- package/dist/oml/index.js.map +7 -0
- package/dist/oml/jsx-runtime.d.ts +34 -0
- package/dist/oml/jsx-runtime.d.ts.map +1 -0
- package/dist/oml/jsx-runtime.js +59 -0
- package/dist/oml/jsx-runtime.js.map +7 -0
- package/dist/oml/jsx.d.ts +14 -0
- package/dist/oml/jsx.d.ts.map +1 -0
- package/dist/oml/jsx.js +96 -0
- package/dist/oml/jsx.js.map +7 -0
- package/dist/oml/page.d.ts +7 -0
- package/dist/oml/page.d.ts.map +1 -0
- package/dist/oml/page.js +6 -0
- package/dist/oml/page.js.map +7 -0
- package/dist/oml/render.d.ts +13 -0
- package/dist/oml/render.d.ts.map +1 -0
- package/dist/oml/render.js +117 -0
- package/dist/oml/render.js.map +7 -0
- package/dist/oml/types.d.ts +79 -0
- package/dist/oml/types.d.ts.map +1 -0
- package/dist/oml/types.js +64 -0
- package/dist/oml/types.js.map +7 -0
- package/dist/router/handler.d.ts +53 -0
- package/dist/router/handler.d.ts.map +1 -0
- package/dist/router/handler.js +342 -0
- package/dist/router/handler.js.map +7 -0
- package/dist/router/matcher.d.ts +21 -0
- package/dist/router/matcher.d.ts.map +1 -0
- package/dist/router/matcher.js +28 -0
- package/dist/router/matcher.js.map +7 -0
- package/dist/router/scanner.d.ts +17 -0
- package/dist/router/scanner.d.ts.map +1 -0
- package/dist/router/scanner.js +197 -0
- package/dist/router/scanner.js.map +7 -0
- package/dist/server/index.d.ts +23 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +29 -0
- package/dist/server/index.js.map +7 -0
- package/dist/signal.d.ts +15 -0
- package/dist/signal.d.ts.map +1 -0
- package/dist/signal.js +29 -0
- package/dist/signal.js.map +7 -0
- package/dist/ssg.d.ts +45 -0
- package/dist/ssg.d.ts.map +1 -0
- package/dist/ssg.js +175 -0
- package/dist/ssg.js.map +7 -0
- package/dist/test/actions.test.d.ts +2 -0
- package/dist/test/actions.test.d.ts.map +1 -0
- package/dist/test/body-limits.test.d.ts +2 -0
- package/dist/test/body-limits.test.d.ts.map +1 -0
- package/dist/test/errors.test.d.ts +2 -0
- package/dist/test/errors.test.d.ts.map +1 -0
- package/dist/test/fixtures/routes/[id].page.d.ts +4 -0
- package/dist/test/fixtures/routes/[id].page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_error.d.ts +3 -0
- package/dist/test/fixtures/routes/_error.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_global.d.ts +3 -0
- package/dist/test/fixtures/routes/_global.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_layout-template.d.ts +3 -0
- package/dist/test/fixtures/routes/_layout-template.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_layout.d.ts +3 -0
- package/dist/test/fixtures/routes/_layout.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_layout_scripts.d.ts +3 -0
- package/dist/test/fixtures/routes/_layout_scripts.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_middleware.d.ts +3 -0
- package/dist/test/fixtures/routes/_middleware.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_redirect301_mw.d.ts +3 -0
- package/dist/test/fixtures/routes/_redirect301_mw.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_redirect_mw.d.ts +3 -0
- package/dist/test/fixtures/routes/_redirect_mw.d.ts.map +1 -0
- package/dist/test/fixtures/routes/about.page.d.ts +3 -0
- package/dist/test/fixtures/routes/about.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/action.page.d.ts +6 -0
- package/dist/test/fixtures/routes/action.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/form-all.post.d.ts +3 -0
- package/dist/test/fixtures/routes/api/form-all.post.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/form-limited.post.d.ts +6 -0
- package/dist/test/fixtures/routes/api/form-limited.post.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/response-obj.get.d.ts +3 -0
- package/dist/test/fixtures/routes/api/response-obj.get.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/upload.post.d.ts +12 -0
- package/dist/test/fixtures/routes/api/upload.post.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/users.get.d.ts +6 -0
- package/dist/test/fixtures/routes/api/users.get.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/xml.get.d.ts +3 -0
- package/dist/test/fixtures/routes/api/xml.get.d.ts.map +1 -0
- package/dist/test/fixtures/routes/auth/_middleware.d.ts +3 -0
- package/dist/test/fixtures/routes/auth/_middleware.d.ts.map +1 -0
- package/dist/test/fixtures/routes/auth/protected.page.d.ts +3 -0
- package/dist/test/fixtures/routes/auth/protected.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/index.page.d.ts +3 -0
- package/dist/test/fixtures/routes/index.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/oml.page.d.ts +3 -0
- package/dist/test/fixtures/routes/oml.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/redirect.page.d.ts +3 -0
- package/dist/test/fixtures/routes/redirect.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/ssg/[slug].page.d.ts +5 -0
- package/dist/test/fixtures/routes/ssg/[slug].page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/ssg/server.page.d.ts +4 -0
- package/dist/test/fixtures/routes/ssg/server.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/state.page.d.ts +3 -0
- package/dist/test/fixtures/routes/state.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/throw.page.d.ts +3 -0
- package/dist/test/fixtures/routes/throw.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/wiki/[...slug].page.d.ts +3 -0
- package/dist/test/fixtures/routes/wiki/[...slug].page.d.ts.map +1 -0
- package/dist/test/helpers.d.ts +37 -0
- package/dist/test/helpers.d.ts.map +1 -0
- package/dist/test/layouts.test.d.ts +2 -0
- package/dist/test/layouts.test.d.ts.map +1 -0
- package/dist/test/middleware.test.d.ts +2 -0
- package/dist/test/middleware.test.d.ts.map +1 -0
- package/dist/test/multipart.test.d.ts +2 -0
- package/dist/test/multipart.test.d.ts.map +1 -0
- package/dist/test/oml-routing.test.d.ts +2 -0
- package/dist/test/oml-routing.test.d.ts.map +1 -0
- package/dist/test/oml.test.d.ts +2 -0
- package/dist/test/oml.test.d.ts.map +1 -0
- package/dist/test/redirects.test.d.ts +2 -0
- package/dist/test/redirects.test.d.ts.map +1 -0
- package/dist/test/routing.test.d.ts +2 -0
- package/dist/test/routing.test.d.ts.map +1 -0
- package/dist/test/ssg.test.d.ts +2 -0
- package/dist/test/ssg.test.d.ts.map +1 -0
- package/dist/test/web-response.test.d.ts +2 -0
- package/dist/test/web-response.test.d.ts.map +1 -0
- package/dist/types.d.ts +314 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +292 -0
- package/dist/types.js.map +7 -0
- package/package.json +103 -0
- package/pka.config.json +32 -0
- package/src/build/config.ts +42 -0
- package/src/build/index.ts +6 -0
- package/src/build/plugins.ts +118 -0
- package/src/cli.ts +502 -0
- package/src/config.ts +197 -0
- package/src/create-multisite.ts +310 -0
- package/src/create.ts +194 -0
- package/src/dev/blueprints.ts +75 -0
- package/src/dev/components.ts +108 -0
- package/src/dev/insert.ts +221 -0
- package/src/dev/remove.ts +677 -0
- package/src/dev/watch.ts +3098 -0
- package/src/env.d.ts +5 -0
- package/src/errors.ts +64 -0
- package/src/generate.ts +228 -0
- package/src/index.ts +67 -0
- package/src/island.ts +47 -0
- package/src/jsx-runtime.d.ts +408 -0
- package/src/jsx-runtime.d.ts.map +1 -0
- package/src/jsx-runtime.ts +536 -0
- package/src/link.ts +49 -0
- package/src/oml/fragment.ts +54 -0
- package/src/oml/index.ts +21 -0
- package/src/oml/jsx-runtime.ts +121 -0
- package/src/oml/jsx.ts +151 -0
- package/src/oml/page.ts +13 -0
- package/src/oml/render.ts +181 -0
- package/src/oml/types.ts +159 -0
- package/src/router/handler.ts +515 -0
- package/src/router/matcher.ts +52 -0
- package/src/router/scanner.ts +272 -0
- package/src/server/index.ts +49 -0
- package/src/signal.ts +39 -0
- package/src/ssg.ts +253 -0
- package/src/test/actions.test.ts +40 -0
- package/src/test/body-limits.test.ts +83 -0
- package/src/test/errors.test.ts +53 -0
- package/src/test/fixtures/routes/[id].page.ts +3 -0
- package/src/test/fixtures/routes/_error.ts +6 -0
- package/src/test/fixtures/routes/_global.ts +8 -0
- package/src/test/fixtures/routes/_layout-template.ts +7 -0
- package/src/test/fixtures/routes/_layout.ts +7 -0
- package/src/test/fixtures/routes/_layout_scripts.ts +8 -0
- package/src/test/fixtures/routes/_middleware.ts +8 -0
- package/src/test/fixtures/routes/_redirect301_mw.ts +5 -0
- package/src/test/fixtures/routes/_redirect_mw.ts +5 -0
- package/src/test/fixtures/routes/about.page.ts +6 -0
- package/src/test/fixtures/routes/action.page.ts +11 -0
- package/src/test/fixtures/routes/api/form-all.post.ts +5 -0
- package/src/test/fixtures/routes/api/form-limited.post.ts +6 -0
- package/src/test/fixtures/routes/api/response-obj.get.ts +17 -0
- package/src/test/fixtures/routes/api/upload.post.ts +14 -0
- package/src/test/fixtures/routes/api/users.get.ts +3 -0
- package/src/test/fixtures/routes/api/xml.get.ts +5 -0
- package/src/test/fixtures/routes/auth/_middleware.ts +11 -0
- package/src/test/fixtures/routes/auth/protected.page.ts +3 -0
- package/src/test/fixtures/routes/index.page.ts +3 -0
- package/src/test/fixtures/routes/oml.page.ts +7 -0
- package/src/test/fixtures/routes/redirect.page.ts +3 -0
- package/src/test/fixtures/routes/ssg/[slug].page.ts +8 -0
- package/src/test/fixtures/routes/ssg/server.page.ts +5 -0
- package/src/test/fixtures/routes/state.page.ts +4 -0
- package/src/test/fixtures/routes/throw.page.ts +5 -0
- package/src/test/fixtures/routes/wiki/[...slug].page.ts +3 -0
- package/src/test/helpers.ts +132 -0
- package/src/test/layouts.test.ts +76 -0
- package/src/test/middleware.test.ts +69 -0
- package/src/test/multipart.test.ts +91 -0
- package/src/test/oml-routing.test.ts +59 -0
- package/src/test/oml.test.ts +429 -0
- package/src/test/redirects.test.ts +32 -0
- package/src/test/routing.test.ts +118 -0
- package/src/test/ssg.test.ts +273 -0
- package/src/test/web-response.test.ts +33 -0
- package/src/types.ts +670 -0
- package/tsconfig.client.json +17 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
function findComponentSpan(lines, name, startFrom = 0) {
|
|
3
|
+
const openRe = new RegExp(`^\\s*<${name}(\\s|/>|>|$)`);
|
|
4
|
+
let openIdx = -1;
|
|
5
|
+
for (let i = startFrom; i < lines.length; i++) {
|
|
6
|
+
if (openRe.test(lines[i])) {
|
|
7
|
+
openIdx = i;
|
|
8
|
+
break;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
if (openIdx === -1) return null;
|
|
12
|
+
const openIndent = (lines[openIdx].match(/^(\s*)/) ?? ["", ""])[1];
|
|
13
|
+
const tagStart = lines[openIdx].indexOf(`<${name}`);
|
|
14
|
+
const rest = lines[openIdx].slice(tagStart);
|
|
15
|
+
if (/\/>/.test(rest) || new RegExp(`</${name}>`).test(rest)) return [openIdx, openIdx];
|
|
16
|
+
for (let i = openIdx + 1; i < lines.length; i++) {
|
|
17
|
+
const t = lines[i].trim();
|
|
18
|
+
const ind = (lines[i].match(/^(\s*)/) ?? ["", ""])[1];
|
|
19
|
+
if ((t === "/>" || t.startsWith(`</${name}>`)) && ind.length <= openIndent.length + 2) {
|
|
20
|
+
return [openIdx, i];
|
|
21
|
+
}
|
|
22
|
+
if (t && ind.length <= openIndent.length && i > openIdx + 1) break;
|
|
23
|
+
}
|
|
24
|
+
return [openIdx, openIdx];
|
|
25
|
+
}
|
|
26
|
+
function removeJsx(filePath, componentName, instanceIndex) {
|
|
27
|
+
let source;
|
|
28
|
+
try {
|
|
29
|
+
source = readFileSync(filePath, "utf-8");
|
|
30
|
+
} catch {
|
|
31
|
+
return { removed: false, error: `Cannot read file: ${filePath}` };
|
|
32
|
+
}
|
|
33
|
+
const lines = source.split("\n");
|
|
34
|
+
const spans = [];
|
|
35
|
+
let from = 0;
|
|
36
|
+
while (true) {
|
|
37
|
+
const span = findComponentSpan(lines, componentName, from);
|
|
38
|
+
if (!span) break;
|
|
39
|
+
spans.push(span);
|
|
40
|
+
from = span[1] + 1;
|
|
41
|
+
}
|
|
42
|
+
if (spans.length === 0) {
|
|
43
|
+
return { removed: false, error: `No <${componentName}> found in source.` };
|
|
44
|
+
}
|
|
45
|
+
const idx = instanceIndex ?? (spans.length === 1 ? 0 : -1);
|
|
46
|
+
if (idx === -1) {
|
|
47
|
+
return {
|
|
48
|
+
removed: false,
|
|
49
|
+
error: `${spans.length} instances of <${componentName}> found \u2014 click the specific one you want to remove, or edit the file directly.`
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (idx >= spans.length) {
|
|
53
|
+
return { removed: false, error: `Instance ${idx} not found (${spans.length} instances exist).` };
|
|
54
|
+
}
|
|
55
|
+
const [start, end] = spans[idx];
|
|
56
|
+
lines.splice(start, end - start + 1);
|
|
57
|
+
const cleaned = [];
|
|
58
|
+
let prevBlank = false;
|
|
59
|
+
for (const line of lines) {
|
|
60
|
+
const blank = line.trim() === "";
|
|
61
|
+
if (blank && prevBlank) continue;
|
|
62
|
+
cleaned.push(line);
|
|
63
|
+
prevBlank = blank;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
writeFileSync(filePath, cleaned.join("\n"), "utf-8");
|
|
67
|
+
} catch {
|
|
68
|
+
return { removed: false, error: `Cannot write file: ${filePath}` };
|
|
69
|
+
}
|
|
70
|
+
return { removed: true, file: filePath };
|
|
71
|
+
}
|
|
72
|
+
function removeElement(filePath, tagName, instanceIndex) {
|
|
73
|
+
let source;
|
|
74
|
+
try {
|
|
75
|
+
source = readFileSync(filePath, "utf-8");
|
|
76
|
+
} catch {
|
|
77
|
+
return { removed: false, error: `Cannot read file: ${filePath}` };
|
|
78
|
+
}
|
|
79
|
+
const lines = source.split("\n");
|
|
80
|
+
const span = findFullElementSpan(lines, tagName, instanceIndex);
|
|
81
|
+
if (!span) return { removed: false, error: `No <${tagName}> found at index ${instanceIndex}` };
|
|
82
|
+
const [start, end] = span;
|
|
83
|
+
lines.splice(start, end - start + 1);
|
|
84
|
+
const cleaned = [];
|
|
85
|
+
let prevBlank = false;
|
|
86
|
+
for (const line of lines) {
|
|
87
|
+
const blank = line.trim() === "";
|
|
88
|
+
if (blank && prevBlank) continue;
|
|
89
|
+
cleaned.push(line);
|
|
90
|
+
prevBlank = blank;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
writeFileSync(filePath, cleaned.join("\n"), "utf-8");
|
|
94
|
+
} catch {
|
|
95
|
+
return { removed: false, error: `Cannot write file: ${filePath}` };
|
|
96
|
+
}
|
|
97
|
+
return { removed: true, file: filePath };
|
|
98
|
+
}
|
|
99
|
+
function findElementTagSpan(lines, tagName, instanceIndex) {
|
|
100
|
+
const openRe = new RegExp(`<${tagName}(\\s|>|\\/)`);
|
|
101
|
+
let count = 0;
|
|
102
|
+
for (let i = 0; i < lines.length; i++) {
|
|
103
|
+
if (openRe.test(lines[i])) {
|
|
104
|
+
if (count === instanceIndex) {
|
|
105
|
+
const tagPos = lines[i].search(openRe);
|
|
106
|
+
const rest = lines[i].slice(tagPos);
|
|
107
|
+
if (rest.includes(">")) return [i, i];
|
|
108
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
109
|
+
const t = lines[j].trim();
|
|
110
|
+
if (t === ">" || t === "/>") return [i, j];
|
|
111
|
+
}
|
|
112
|
+
return [i, i];
|
|
113
|
+
}
|
|
114
|
+
count++;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
function buildOpenTag(tagName, props, selfClose) {
|
|
120
|
+
const entries = Object.entries(props).filter(([, v]) => v !== void 0 && v !== null);
|
|
121
|
+
if (!entries.length) return selfClose ? `<${tagName} />` : `<${tagName}>`;
|
|
122
|
+
const attrs = entries.map(([k, v]) => {
|
|
123
|
+
if (v === true) return k;
|
|
124
|
+
if (v === false) return null;
|
|
125
|
+
if (typeof v === "string") return `${k}="${v}"`;
|
|
126
|
+
return `${k}={${JSON.stringify(v)}}`;
|
|
127
|
+
}).filter(Boolean).join(" ");
|
|
128
|
+
return attrs ? selfClose ? `<${tagName} ${attrs} />` : `<${tagName} ${attrs}>` : selfClose ? `<${tagName} />` : `<${tagName}>`;
|
|
129
|
+
}
|
|
130
|
+
function replaceElementAttrs(filePath, tagName, newProps, instanceIndex = 0) {
|
|
131
|
+
let source;
|
|
132
|
+
try {
|
|
133
|
+
source = readFileSync(filePath, "utf-8");
|
|
134
|
+
} catch {
|
|
135
|
+
return { replaced: false, error: `Cannot read file: ${filePath}` };
|
|
136
|
+
}
|
|
137
|
+
const lines = source.split("\n");
|
|
138
|
+
const span = findElementTagSpan(lines, tagName, instanceIndex);
|
|
139
|
+
if (!span) return { replaced: false, error: `No <${tagName}> found at index ${instanceIndex}` };
|
|
140
|
+
const [startLine, endLine] = span;
|
|
141
|
+
const newLines = [...lines];
|
|
142
|
+
const openRe = new RegExp(`<${tagName}(\\s|>|\\/)`);
|
|
143
|
+
if (startLine === endLine) {
|
|
144
|
+
const line = lines[startLine];
|
|
145
|
+
const tagPos = line.search(openRe);
|
|
146
|
+
const before = line.slice(0, tagPos);
|
|
147
|
+
let closePos = -1;
|
|
148
|
+
let selfClose = false;
|
|
149
|
+
for (let i = tagPos + tagName.length + 1; i < line.length; i++) {
|
|
150
|
+
if (line[i] === ">") {
|
|
151
|
+
if (line[i - 1] === "/") {
|
|
152
|
+
selfClose = true;
|
|
153
|
+
closePos = i - 1;
|
|
154
|
+
} else {
|
|
155
|
+
closePos = i;
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (closePos === -1) return { replaced: false, error: `Cannot parse opening tag of <${tagName}>` };
|
|
161
|
+
const after = line.slice(selfClose ? closePos + 2 : closePos + 1);
|
|
162
|
+
newLines[startLine] = before + buildOpenTag(tagName, newProps, selfClose) + after;
|
|
163
|
+
} else {
|
|
164
|
+
const firstLine = lines[startLine];
|
|
165
|
+
const tagPos = firstLine.search(openRe);
|
|
166
|
+
const before = firstLine.slice(0, tagPos);
|
|
167
|
+
const lastLine = lines[endLine];
|
|
168
|
+
const selfClose = lastLine.trim() === "/>";
|
|
169
|
+
const closeIdx = lastLine.indexOf(selfClose ? "/>" : ">");
|
|
170
|
+
const after = lastLine.slice(closeIdx + (selfClose ? 2 : 1));
|
|
171
|
+
newLines.splice(startLine, endLine - startLine + 1, before + buildOpenTag(tagName, newProps, selfClose) + after);
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
175
|
+
} catch {
|
|
176
|
+
return { replaced: false, error: `Cannot write file: ${filePath}` };
|
|
177
|
+
}
|
|
178
|
+
return { replaced: true, file: filePath };
|
|
179
|
+
}
|
|
180
|
+
function replaceTextContent(filePath, tagName, newText, instanceIndex = 0) {
|
|
181
|
+
let source;
|
|
182
|
+
try {
|
|
183
|
+
source = readFileSync(filePath, "utf-8");
|
|
184
|
+
} catch {
|
|
185
|
+
return { replaced: false, error: `Cannot read file: ${filePath}` };
|
|
186
|
+
}
|
|
187
|
+
const lines = source.split("\n");
|
|
188
|
+
const span = findElementTagSpan(lines, tagName, instanceIndex);
|
|
189
|
+
if (!span) return { replaced: false, error: `No <${tagName}> found at index ${instanceIndex}` };
|
|
190
|
+
const [startLine, endLine] = span;
|
|
191
|
+
const contentLine = endLine;
|
|
192
|
+
const line = lines[contentLine];
|
|
193
|
+
const closeTag = `</${tagName}>`;
|
|
194
|
+
const closeIdx = line.indexOf(closeTag);
|
|
195
|
+
if (closeIdx === -1) {
|
|
196
|
+
return { replaced: false, error: `<${tagName}> has multi-line content \u2014 not yet supported` };
|
|
197
|
+
}
|
|
198
|
+
const openRe = new RegExp(`<${tagName}(\\s|>|\\/)`);
|
|
199
|
+
const tagStart = startLine === endLine ? line.search(openRe) : 0;
|
|
200
|
+
let openEnd = -1;
|
|
201
|
+
for (let i = tagStart; i < closeIdx; i++) {
|
|
202
|
+
if (line[i] === ">") {
|
|
203
|
+
openEnd = i;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (openEnd === -1) return { replaced: false, error: `Cannot parse opening tag of <${tagName}>` };
|
|
208
|
+
lines[contentLine] = line.slice(0, openEnd + 1) + newText + line.slice(closeIdx);
|
|
209
|
+
try {
|
|
210
|
+
writeFileSync(filePath, lines.join("\n"), "utf-8");
|
|
211
|
+
} catch {
|
|
212
|
+
return { replaced: false, error: `Cannot write file: ${filePath}` };
|
|
213
|
+
}
|
|
214
|
+
return { replaced: true, file: filePath };
|
|
215
|
+
}
|
|
216
|
+
function replaceJsx(filePath, componentName, newJsx, instanceIndex = 0) {
|
|
217
|
+
let source;
|
|
218
|
+
try {
|
|
219
|
+
source = readFileSync(filePath, "utf-8");
|
|
220
|
+
} catch {
|
|
221
|
+
return { replaced: false, error: `Cannot read file: ${filePath}` };
|
|
222
|
+
}
|
|
223
|
+
const lines = source.split("\n");
|
|
224
|
+
const spans = [];
|
|
225
|
+
let from = 0;
|
|
226
|
+
while (true) {
|
|
227
|
+
const span = findComponentSpan(lines, componentName, from);
|
|
228
|
+
if (!span) break;
|
|
229
|
+
spans.push(span);
|
|
230
|
+
from = span[1] + 1;
|
|
231
|
+
}
|
|
232
|
+
if (spans.length === 0) {
|
|
233
|
+
return { replaced: false, error: `No <${componentName}> found in source.` };
|
|
234
|
+
}
|
|
235
|
+
if (instanceIndex >= spans.length) {
|
|
236
|
+
return {
|
|
237
|
+
replaced: false,
|
|
238
|
+
error: `Instance index ${instanceIndex} out of range (${spans.length} found).`
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
const [start, end] = spans[instanceIndex];
|
|
242
|
+
const existingIndent = (lines[start].match(/^(\s*)/) ?? ["", ""])[1];
|
|
243
|
+
const newLines = newJsx.split("\n").map((l) => l === "" ? "" : existingIndent + l);
|
|
244
|
+
lines.splice(start, end - start + 1, ...newLines);
|
|
245
|
+
try {
|
|
246
|
+
writeFileSync(filePath, lines.join("\n"), "utf-8");
|
|
247
|
+
} catch {
|
|
248
|
+
return { replaced: false, error: `Cannot write file: ${filePath}` };
|
|
249
|
+
}
|
|
250
|
+
return { replaced: true, file: filePath };
|
|
251
|
+
}
|
|
252
|
+
function findFullElementSpan(lines, tagName, instanceIndex) {
|
|
253
|
+
const openRe = new RegExp(`<${tagName}(\\s|>|\\/)`);
|
|
254
|
+
let count = 0;
|
|
255
|
+
for (let i = 0; i < lines.length; i++) {
|
|
256
|
+
if (openRe.test(lines[i])) {
|
|
257
|
+
if (count === instanceIndex) {
|
|
258
|
+
const tagPos = lines[i].search(openRe);
|
|
259
|
+
const openIndent = (lines[i].match(/^(\s*)/) ?? ["", ""])[1];
|
|
260
|
+
const rest = lines[i].slice(tagPos);
|
|
261
|
+
if (/\/>/.test(rest) || new RegExp(`</${tagName}>`).test(rest)) return [i, i];
|
|
262
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
263
|
+
const t = lines[j].trim();
|
|
264
|
+
const ind = (lines[j].match(/^(\s*)/) ?? ["", ""])[1];
|
|
265
|
+
if (t.startsWith(`</${tagName}>`) && ind.length <= openIndent.length) return [i, j];
|
|
266
|
+
if (t && ind.length < openIndent.length) break;
|
|
267
|
+
}
|
|
268
|
+
return [i, i];
|
|
269
|
+
}
|
|
270
|
+
count++;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
function getComponentFragment(filePath, name, instanceIndex) {
|
|
276
|
+
let source;
|
|
277
|
+
try {
|
|
278
|
+
source = readFileSync(filePath, "utf-8");
|
|
279
|
+
} catch {
|
|
280
|
+
return { found: false, error: `Cannot read file: ${filePath}` };
|
|
281
|
+
}
|
|
282
|
+
const lines = source.split("\n");
|
|
283
|
+
const spans = [];
|
|
284
|
+
let from = 0;
|
|
285
|
+
while (true) {
|
|
286
|
+
const span = findComponentSpan(lines, name, from);
|
|
287
|
+
if (!span) break;
|
|
288
|
+
spans.push(span);
|
|
289
|
+
from = span[1] + 1;
|
|
290
|
+
}
|
|
291
|
+
if (instanceIndex >= spans.length)
|
|
292
|
+
return { found: false, error: `Instance ${instanceIndex} not found (${spans.length} instances exist)` };
|
|
293
|
+
const [spanStart, spanEnd] = spans[instanceIndex];
|
|
294
|
+
const startLine = lines[spanStart];
|
|
295
|
+
const tagStart = startLine.indexOf(`<${name}`);
|
|
296
|
+
if (/\/>/.test(startLine.slice(tagStart)))
|
|
297
|
+
return { found: false, error: `<${name}> is self-closing` };
|
|
298
|
+
if (spanStart === spanEnd)
|
|
299
|
+
return { found: false, error: `<${name}> opens and closes on the same line` };
|
|
300
|
+
const { line: openEndLine, col: openEndCol } = findOpenTagEnd(lines, spanStart, name);
|
|
301
|
+
if (openEndCol === -1)
|
|
302
|
+
return { found: false, error: `Cannot find end of opening tag for <${name}>` };
|
|
303
|
+
const contentLines = [];
|
|
304
|
+
const afterOpen = lines[openEndLine].slice(openEndCol + 1);
|
|
305
|
+
if (afterOpen.trim()) contentLines.push(afterOpen);
|
|
306
|
+
for (let i = openEndLine + 1; i < spanEnd; i++) contentLines.push(lines[i]);
|
|
307
|
+
return { found: true, content: contentLines.join("\n"), file: filePath, name, instanceIndex };
|
|
308
|
+
}
|
|
309
|
+
function replaceComponentFragment(filePath, name, instanceIndex, newContent) {
|
|
310
|
+
let source;
|
|
311
|
+
try {
|
|
312
|
+
source = readFileSync(filePath, "utf-8");
|
|
313
|
+
} catch {
|
|
314
|
+
return { replaced: false, error: `Cannot read file: ${filePath}` };
|
|
315
|
+
}
|
|
316
|
+
const lines = source.split("\n");
|
|
317
|
+
const spans = [];
|
|
318
|
+
let from = 0;
|
|
319
|
+
while (true) {
|
|
320
|
+
const span = findComponentSpan(lines, name, from);
|
|
321
|
+
if (!span) break;
|
|
322
|
+
spans.push(span);
|
|
323
|
+
from = span[1] + 1;
|
|
324
|
+
}
|
|
325
|
+
if (instanceIndex >= spans.length)
|
|
326
|
+
return { replaced: false, error: `Instance ${instanceIndex} not found` };
|
|
327
|
+
const [spanStart, spanEnd] = spans[instanceIndex];
|
|
328
|
+
const startLine = lines[spanStart];
|
|
329
|
+
const tagStart = startLine.indexOf(`<${name}`);
|
|
330
|
+
if (/\/>/.test(startLine.slice(tagStart)))
|
|
331
|
+
return { replaced: false, error: `<${name}> is self-closing` };
|
|
332
|
+
if (spanStart === spanEnd)
|
|
333
|
+
return { replaced: false, error: `<${name}> opens and closes on the same line` };
|
|
334
|
+
const { line: openEndLine, col: openEndCol } = findOpenTagEnd(lines, spanStart, name);
|
|
335
|
+
if (openEndCol === -1)
|
|
336
|
+
return { replaced: false, error: `Cannot find end of opening tag for <${name}>` };
|
|
337
|
+
const openingLines = lines.slice(spanStart, openEndLine + 1);
|
|
338
|
+
openingLines[openingLines.length - 1] = openingLines[openingLines.length - 1].slice(0, openEndCol + 1);
|
|
339
|
+
const contentLines = newContent.trim() === "" ? [] : newContent.split("\n");
|
|
340
|
+
const replacement = [...openingLines, ...contentLines, lines[spanEnd]];
|
|
341
|
+
const newLines = [...lines];
|
|
342
|
+
newLines.splice(spanStart, spanEnd - spanStart + 1, ...replacement);
|
|
343
|
+
try {
|
|
344
|
+
writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
345
|
+
} catch {
|
|
346
|
+
return { replaced: false, error: `Cannot write file: ${filePath}` };
|
|
347
|
+
}
|
|
348
|
+
return { replaced: true, file: filePath };
|
|
349
|
+
}
|
|
350
|
+
function findOpenTagEnd(lines, spanStart, name) {
|
|
351
|
+
const firstLine = lines[spanStart];
|
|
352
|
+
const tagStart = firstLine.indexOf(`<${name}`);
|
|
353
|
+
for (let i = tagStart + name.length + 1; i < firstLine.length; i++) {
|
|
354
|
+
if (firstLine[i] === ">") return { line: spanStart, col: i };
|
|
355
|
+
}
|
|
356
|
+
for (let i = spanStart + 1; i < lines.length; i++) {
|
|
357
|
+
const t = lines[i].trim();
|
|
358
|
+
if (t === ">") return { line: i, col: lines[i].indexOf(">") };
|
|
359
|
+
}
|
|
360
|
+
return { line: spanStart, col: -1 };
|
|
361
|
+
}
|
|
362
|
+
function getElementFragment(filePath, tagName, instanceIndex) {
|
|
363
|
+
let source;
|
|
364
|
+
try {
|
|
365
|
+
source = readFileSync(filePath, "utf-8");
|
|
366
|
+
} catch {
|
|
367
|
+
return { found: false, error: `Cannot read file: ${filePath}` };
|
|
368
|
+
}
|
|
369
|
+
const lines = source.split("\n");
|
|
370
|
+
const span = findFullElementSpan(lines, tagName, instanceIndex);
|
|
371
|
+
if (!span) return { found: false, error: `No <${tagName}> found at index ${instanceIndex}` };
|
|
372
|
+
const [spanStart, spanEnd] = span;
|
|
373
|
+
const { line: openEndLine, col: openEndCol } = findOpenTagEnd(lines, spanStart, tagName);
|
|
374
|
+
if (openEndCol === -1) return { found: false, error: `Cannot find end of opening tag for <${tagName}>` };
|
|
375
|
+
const contentLines = [];
|
|
376
|
+
if (spanStart === spanEnd) {
|
|
377
|
+
const line = lines[spanStart];
|
|
378
|
+
const closeIdx = line.lastIndexOf(`</${tagName}>`);
|
|
379
|
+
if (closeIdx === -1) return { found: false, error: `Cannot find closing tag on same line` };
|
|
380
|
+
contentLines.push(line.slice(openEndCol + 1, closeIdx));
|
|
381
|
+
} else {
|
|
382
|
+
const afterOpen = lines[openEndLine].slice(openEndCol + 1);
|
|
383
|
+
if (afterOpen.trim()) contentLines.push(afterOpen);
|
|
384
|
+
for (let i = openEndLine + 1; i < spanEnd; i++) contentLines.push(lines[i]);
|
|
385
|
+
}
|
|
386
|
+
return { found: true, content: contentLines.join("\n"), file: filePath, name: tagName, instanceIndex };
|
|
387
|
+
}
|
|
388
|
+
function replaceElementFragment(filePath, tagName, instanceIndex, newContent) {
|
|
389
|
+
let source;
|
|
390
|
+
try {
|
|
391
|
+
source = readFileSync(filePath, "utf-8");
|
|
392
|
+
} catch {
|
|
393
|
+
return { replaced: false, error: `Cannot read file: ${filePath}` };
|
|
394
|
+
}
|
|
395
|
+
const lines = source.split("\n");
|
|
396
|
+
const span = findFullElementSpan(lines, tagName, instanceIndex);
|
|
397
|
+
if (!span) return { replaced: false, error: `No <${tagName}> found at index ${instanceIndex}` };
|
|
398
|
+
const [spanStart, spanEnd] = span;
|
|
399
|
+
const { line: openEndLine, col: openEndCol } = findOpenTagEnd(lines, spanStart, tagName);
|
|
400
|
+
if (openEndCol === -1) return { replaced: false, error: `Cannot find end of opening tag for <${tagName}>` };
|
|
401
|
+
const newLines = [...lines];
|
|
402
|
+
if (spanStart === spanEnd) {
|
|
403
|
+
const line = lines[spanStart];
|
|
404
|
+
const closeIdx = line.lastIndexOf(`</${tagName}>`);
|
|
405
|
+
if (closeIdx === -1) return { replaced: false, error: `Cannot find closing tag on same line` };
|
|
406
|
+
const before = line.slice(0, openEndCol + 1);
|
|
407
|
+
const after = line.slice(closeIdx);
|
|
408
|
+
const contentLines = newContent.trim() === "" ? [] : newContent.split("\n");
|
|
409
|
+
newLines.splice(spanStart, 1, ...contentLines.length ? [before + contentLines[0], ...contentLines.slice(1), after] : [before + after]);
|
|
410
|
+
} else {
|
|
411
|
+
const openingLines = lines.slice(spanStart, openEndLine + 1);
|
|
412
|
+
openingLines[openingLines.length - 1] = openingLines[openingLines.length - 1].slice(0, openEndCol + 1);
|
|
413
|
+
const contentLines = newContent.trim() === "" ? [] : newContent.split("\n");
|
|
414
|
+
const replacement = [...openingLines, ...contentLines, lines[spanEnd]];
|
|
415
|
+
newLines.splice(spanStart, spanEnd - spanStart + 1, ...replacement);
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
419
|
+
} catch {
|
|
420
|
+
return { replaced: false, error: `Cannot write file: ${filePath}` };
|
|
421
|
+
}
|
|
422
|
+
return { replaced: true, file: filePath };
|
|
423
|
+
}
|
|
424
|
+
function moveNode(filePath, name, isComponent, instanceIndex, direction) {
|
|
425
|
+
let source;
|
|
426
|
+
try {
|
|
427
|
+
source = readFileSync(filePath, "utf-8");
|
|
428
|
+
} catch {
|
|
429
|
+
return { moved: false, error: `Cannot read file: ${filePath}` };
|
|
430
|
+
}
|
|
431
|
+
const lines = source.split("\n");
|
|
432
|
+
let targetSpan = null;
|
|
433
|
+
if (isComponent) {
|
|
434
|
+
let from = 0;
|
|
435
|
+
for (let idx = 0; idx <= instanceIndex; idx++) {
|
|
436
|
+
const s = findComponentSpan(lines, name, from);
|
|
437
|
+
if (!s) break;
|
|
438
|
+
if (idx === instanceIndex) targetSpan = s;
|
|
439
|
+
from = s[1] + 1;
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
targetSpan = findFullElementSpan(lines, name, instanceIndex);
|
|
443
|
+
}
|
|
444
|
+
if (!targetSpan) return { moved: false, error: `No <${name}> found at index ${instanceIndex}` };
|
|
445
|
+
const [startA, endA] = targetSpan;
|
|
446
|
+
const indA = (lines[startA].match(/^(\s*)/) ?? ["", ""])[1].length;
|
|
447
|
+
let siblingSpan = null;
|
|
448
|
+
if (direction === "up") {
|
|
449
|
+
let endB = startA - 1;
|
|
450
|
+
while (endB >= 0 && lines[endB].trim() === "") endB--;
|
|
451
|
+
if (endB < 0) return { moved: false, error: "Already at top" };
|
|
452
|
+
let startB = endB;
|
|
453
|
+
for (let j = endB - 1; j >= 0; j--) {
|
|
454
|
+
const t = lines[j].trim();
|
|
455
|
+
if (!t) continue;
|
|
456
|
+
const ind = (lines[j].match(/^(\s*)/) ?? ["", ""])[1].length;
|
|
457
|
+
if (ind < indA) break;
|
|
458
|
+
if (ind === indA && t.startsWith("<") && !t.startsWith("</") && !t.startsWith("<!--")) {
|
|
459
|
+
startB = j;
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
siblingSpan = [startB, endB];
|
|
464
|
+
} else {
|
|
465
|
+
let startB = endA + 1;
|
|
466
|
+
while (startB < lines.length && lines[startB].trim() === "") startB++;
|
|
467
|
+
if (startB >= lines.length) return { moved: false, error: "Already at bottom" };
|
|
468
|
+
const indB = (lines[startB].match(/^(\s*)/) ?? ["", ""])[1].length;
|
|
469
|
+
const tagMatch = lines[startB].match(/<([A-Za-z][A-Za-z0-9_:-]*)/);
|
|
470
|
+
if (!tagMatch) return { moved: false, error: "Cannot identify next sibling" };
|
|
471
|
+
const tagB = tagMatch[1];
|
|
472
|
+
const tagPos = lines[startB].indexOf(`<${tagB}`);
|
|
473
|
+
const restB = lines[startB].slice(tagPos);
|
|
474
|
+
let endB = startB;
|
|
475
|
+
if (/\/>/.test(restB) || new RegExp(`</${tagB}>`).test(restB)) {
|
|
476
|
+
endB = startB;
|
|
477
|
+
} else {
|
|
478
|
+
for (let j = startB + 1; j < lines.length; j++) {
|
|
479
|
+
const t = lines[j].trim();
|
|
480
|
+
const ind = (lines[j].match(/^(\s*)/) ?? ["", ""])[1].length;
|
|
481
|
+
if ((t.startsWith(`</${tagB}>`) || t === "/>") && ind <= indB) {
|
|
482
|
+
endB = j;
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
if (t && ind < indB) {
|
|
486
|
+
endB = j - 1;
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
siblingSpan = [startB, endB];
|
|
492
|
+
}
|
|
493
|
+
const [first, second] = targetSpan[0] < siblingSpan[0] ? [targetSpan, siblingSpan] : [siblingSpan, targetSpan];
|
|
494
|
+
const linesFirst = lines.slice(first[0], first[1] + 1);
|
|
495
|
+
const linesSecond = lines.slice(second[0], second[1] + 1);
|
|
496
|
+
const newLines = [...lines];
|
|
497
|
+
newLines.splice(second[0], second[1] - second[0] + 1, ...linesFirst);
|
|
498
|
+
newLines.splice(first[0], first[1] - first[0] + 1, ...linesSecond);
|
|
499
|
+
try {
|
|
500
|
+
writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
501
|
+
} catch {
|
|
502
|
+
return { moved: false, error: `Cannot write file: ${filePath}` };
|
|
503
|
+
}
|
|
504
|
+
return { moved: true, file: filePath };
|
|
505
|
+
}
|
|
506
|
+
export {
|
|
507
|
+
getComponentFragment,
|
|
508
|
+
getElementFragment,
|
|
509
|
+
moveNode,
|
|
510
|
+
removeElement,
|
|
511
|
+
removeJsx,
|
|
512
|
+
replaceComponentFragment,
|
|
513
|
+
replaceElementAttrs,
|
|
514
|
+
replaceElementFragment,
|
|
515
|
+
replaceJsx,
|
|
516
|
+
replaceTextContent
|
|
517
|
+
};
|
|
518
|
+
//# sourceMappingURL=remove.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/dev/remove.ts"],
|
|
4
|
+
"sourcesContent": ["import { readFileSync, writeFileSync } from 'node:fs'\n\nexport type RemoveResult = { removed: true; file: string } | { removed: false; error: string }\n\nfunction findComponentSpan(lines: string[], name: string, startFrom = 0): [number, number] | null {\n const openRe = new RegExp(`^\\\\s*<${name}(\\\\s|/>|>|$)`)\n let openIdx = -1\n for (let i = startFrom; i < lines.length; i++) {\n if (openRe.test(lines[i])) {\n openIdx = i\n break\n }\n }\n if (openIdx === -1) return null\n\n const openIndent = (lines[openIdx].match(/^(\\s*)/) ?? ['', ''])[1]\n const tagStart = lines[openIdx].indexOf(`<${name}`)\n const rest = lines[openIdx].slice(tagStart)\n\n // Single-line self-close or same-line children close\n if (/\\/>/.test(rest) || new RegExp(`</${name}>`).test(rest)) return [openIdx, openIdx]\n\n // Multi-line: scan forward for /> or </Name> at same/shallower indent\n for (let i = openIdx + 1; i < lines.length; i++) {\n const t = lines[i].trim()\n const ind = (lines[i].match(/^(\\s*)/) ?? ['', ''])[1]\n if ((t === '/>' || t.startsWith(`</${name}>`)) && ind.length <= openIndent.length + 2) {\n return [openIdx, i]\n }\n // Bail if back to same/shallower indent on a non-close, non-blank line\n if (t && ind.length <= openIndent.length && i > openIdx + 1) break\n }\n\n return [openIdx, openIdx]\n}\n\nexport function removeJsx(filePath: string, componentName: string, instanceIndex?: number): RemoveResult {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return { removed: false, error: `Cannot read file: ${filePath}` }\n }\n\n const lines = source.split('\\n')\n\n // Collect all spans for this component\n const spans: [number, number][] = []\n let from = 0\n while (true) {\n const span = findComponentSpan(lines, componentName, from)\n if (!span) break\n spans.push(span)\n from = span[1] + 1\n }\n\n if (spans.length === 0) {\n return { removed: false, error: `No <${componentName}> found in source.` }\n }\n const idx = instanceIndex ?? (spans.length === 1 ? 0 : -1)\n if (idx === -1) {\n return {\n removed: false,\n error: `${spans.length} instances of <${componentName}> found \u2014 click the specific one you want to remove, or edit the file directly.`,\n }\n }\n if (idx >= spans.length) {\n return { removed: false, error: `Instance ${idx} not found (${spans.length} instances exist).` }\n }\n\n const [start, end] = spans[idx]\n lines.splice(start, end - start + 1)\n\n // Collapse consecutive blank lines left by the removal\n const cleaned: string[] = []\n let prevBlank = false\n for (const line of lines) {\n const blank = line.trim() === ''\n if (blank && prevBlank) continue\n cleaned.push(line)\n prevBlank = blank\n }\n\n try {\n writeFileSync(filePath, cleaned.join('\\n'), 'utf-8')\n } catch {\n return { removed: false, error: `Cannot write file: ${filePath}` }\n }\n\n return { removed: true, file: filePath }\n}\n\nexport function removeElement(filePath: string, tagName: string, instanceIndex: number): RemoveResult {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return { removed: false, error: `Cannot read file: ${filePath}` }\n }\n\n const lines = source.split('\\n')\n const span = findFullElementSpan(lines, tagName, instanceIndex)\n if (!span) return { removed: false, error: `No <${tagName}> found at index ${instanceIndex}` }\n\n const [start, end] = span\n lines.splice(start, end - start + 1)\n\n const cleaned: string[] = []\n let prevBlank = false\n for (const line of lines) {\n const blank = line.trim() === ''\n if (blank && prevBlank) continue\n cleaned.push(line)\n prevBlank = blank\n }\n\n try {\n writeFileSync(filePath, cleaned.join('\\n'), 'utf-8')\n } catch {\n return { removed: false, error: `Cannot write file: ${filePath}` }\n }\n\n return { removed: true, file: filePath }\n}\n\nexport type ReplaceResult = { replaced: true; file: string } | { replaced: false; error: string }\n\nexport type ReplaceElemResult = { replaced: true; file: string } | { replaced: false; error: string }\n\n// Find the span (start line, end line) of the Nth opening tag for `tagName`.\n// Matches <tag>, <tag />, <tag attr>, but NOT </tag>.\nfunction findElementTagSpan(lines: string[], tagName: string, instanceIndex: number): [number, number] | null {\n const openRe = new RegExp(`<${tagName}(\\\\s|>|\\\\/)`)\n let count = 0\n for (let i = 0; i < lines.length; i++) {\n if (openRe.test(lines[i])) {\n if (count === instanceIndex) {\n // If the opening tag closes on the same line, it's a one-liner\n const tagPos = lines[i].search(openRe)\n const rest = lines[i].slice(tagPos)\n if (rest.includes('>')) return [i, i]\n // Multi-line: scan forward for a line that is just > or />\n for (let j = i + 1; j < lines.length; j++) {\n const t = lines[j].trim()\n if (t === '>' || t === '/>') return [i, j]\n }\n return [i, i]\n }\n count++\n }\n }\n return null\n}\n\nfunction buildOpenTag(tagName: string, props: Record<string, unknown>, selfClose: boolean): string {\n const entries = Object.entries(props).filter(([, v]) => v !== undefined && v !== null)\n if (!entries.length) return selfClose ? `<${tagName} />` : `<${tagName}>`\n const attrs = entries\n .map(([k, v]) => {\n if (v === true) return k\n if (v === false) return null\n if (typeof v === 'string') return `${k}=\"${v}\"`\n return `${k}={${JSON.stringify(v)}}`\n })\n .filter(Boolean)\n .join(' ')\n return attrs ? (selfClose ? `<${tagName} ${attrs} />` : `<${tagName} ${attrs}>`) : (selfClose ? `<${tagName} />` : `<${tagName}>`)\n}\n\nexport function replaceElementAttrs(\n filePath: string,\n tagName: string,\n newProps: Record<string, unknown>,\n instanceIndex = 0,\n): ReplaceElemResult {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return { replaced: false, error: `Cannot read file: ${filePath}` }\n }\n\n const lines = source.split('\\n')\n const span = findElementTagSpan(lines, tagName, instanceIndex)\n if (!span) return { replaced: false, error: `No <${tagName}> found at index ${instanceIndex}` }\n\n const [startLine, endLine] = span\n const newLines = [...lines]\n const openRe = new RegExp(`<${tagName}(\\\\s|>|\\\\/)`)\n\n if (startLine === endLine) {\n const line = lines[startLine]\n const tagPos = line.search(openRe)\n const before = line.slice(0, tagPos)\n // Scan for closing > of the opening tag (simple scan \u2014 no nested > expected in common attrs)\n let closePos = -1\n let selfClose = false\n for (let i = tagPos + tagName.length + 1; i < line.length; i++) {\n if (line[i] === '>') {\n if (line[i - 1] === '/') {\n selfClose = true\n closePos = i - 1\n } else {\n closePos = i\n }\n break\n }\n }\n if (closePos === -1) return { replaced: false, error: `Cannot parse opening tag of <${tagName}>` }\n const after = line.slice(selfClose ? closePos + 2 : closePos + 1)\n newLines[startLine] = before + buildOpenTag(tagName, newProps, selfClose) + after\n } else {\n const firstLine = lines[startLine]\n const tagPos = firstLine.search(openRe)\n const before = firstLine.slice(0, tagPos)\n const lastLine = lines[endLine]\n const selfClose = lastLine.trim() === '/>'\n const closeIdx = lastLine.indexOf(selfClose ? '/>' : '>')\n const after = lastLine.slice(closeIdx + (selfClose ? 2 : 1))\n newLines.splice(startLine, endLine - startLine + 1, before + buildOpenTag(tagName, newProps, selfClose) + after)\n }\n\n try {\n writeFileSync(filePath, newLines.join('\\n'), 'utf-8')\n } catch {\n return { replaced: false, error: `Cannot write file: ${filePath}` }\n }\n\n return { replaced: true, file: filePath }\n}\n\n// Replaces the inner text content of an element on a single line.\n// e.g. <h1>Old text</h1> \u2192 <h1>New text</h1>\n// Only works when the opening tag and closing tag are on the same line.\nexport function replaceTextContent(\n filePath: string,\n tagName: string,\n newText: string,\n instanceIndex = 0,\n): ReplaceElemResult {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return { replaced: false, error: `Cannot read file: ${filePath}` }\n }\n\n const lines = source.split('\\n')\n const span = findElementTagSpan(lines, tagName, instanceIndex)\n if (!span) return { replaced: false, error: `No <${tagName}> found at index ${instanceIndex}` }\n\n const [startLine, endLine] = span\n const contentLine = endLine\n const line = lines[contentLine]\n\n const closeTag = `</${tagName}>`\n const closeIdx = line.indexOf(closeTag)\n if (closeIdx === -1) {\n return { replaced: false, error: `<${tagName}> has multi-line content \u2014 not yet supported` }\n }\n\n // Find the end of the opening tag (simple > scan \u2014 no nested > expected in common attrs)\n const openRe = new RegExp(`<${tagName}(\\\\s|>|\\\\/)`)\n const tagStart = startLine === endLine ? line.search(openRe) : 0\n let openEnd = -1\n for (let i = tagStart; i < closeIdx; i++) {\n if (line[i] === '>') {\n openEnd = i\n break\n }\n }\n if (openEnd === -1) return { replaced: false, error: `Cannot parse opening tag of <${tagName}>` }\n\n lines[contentLine] = line.slice(0, openEnd + 1) + newText + line.slice(closeIdx)\n\n try {\n writeFileSync(filePath, lines.join('\\n'), 'utf-8')\n } catch {\n return { replaced: false, error: `Cannot write file: ${filePath}` }\n }\n\n return { replaced: true, file: filePath }\n}\n\nexport function replaceJsx(\n filePath: string,\n componentName: string,\n newJsx: string,\n instanceIndex = 0,\n): ReplaceResult {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return { replaced: false, error: `Cannot read file: ${filePath}` }\n }\n\n const lines = source.split('\\n')\n const spans: [number, number][] = []\n let from = 0\n while (true) {\n const span = findComponentSpan(lines, componentName, from)\n if (!span) break\n spans.push(span)\n from = span[1] + 1\n }\n\n if (spans.length === 0) {\n return { replaced: false, error: `No <${componentName}> found in source.` }\n }\n if (instanceIndex >= spans.length) {\n return {\n replaced: false,\n error: `Instance index ${instanceIndex} out of range (${spans.length} found).`,\n }\n }\n\n const [start, end] = spans[instanceIndex]\n const existingIndent = (lines[start].match(/^(\\s*)/) ?? ['', ''])[1]\n // Prepend existing indent to each line; newJsx lines already carry their own relative indent\n const newLines = newJsx.split('\\n').map((l) => (l === '' ? '' : existingIndent + l))\n\n lines.splice(start, end - start + 1, ...newLines)\n\n try {\n writeFileSync(filePath, lines.join('\\n'), 'utf-8')\n } catch {\n return { replaced: false, error: `Cannot write file: ${filePath}` }\n }\n\n return { replaced: true, file: filePath }\n}\n\n// Full element span: opening <tag through matching </tag> or />, using indent tracking.\nfunction findFullElementSpan(lines: string[], tagName: string, instanceIndex: number): [number, number] | null {\n const openRe = new RegExp(`<${tagName}(\\\\s|>|\\\\/)`)\n let count = 0\n for (let i = 0; i < lines.length; i++) {\n if (openRe.test(lines[i])) {\n if (count === instanceIndex) {\n const tagPos = lines[i].search(openRe)\n const openIndent = (lines[i].match(/^(\\s*)/) ?? ['', ''])[1]\n const rest = lines[i].slice(tagPos)\n if (/\\/>/.test(rest) || new RegExp(`</${tagName}>`).test(rest)) return [i, i]\n for (let j = i + 1; j < lines.length; j++) {\n const t = lines[j].trim()\n const ind = (lines[j].match(/^(\\s*)/) ?? ['', ''])[1]\n if (t.startsWith(`</${tagName}>`) && ind.length <= openIndent.length) return [i, j]\n if (t && ind.length < openIndent.length) break\n }\n return [i, i]\n }\n count++\n }\n }\n return null\n}\n\nexport type FragmentResult =\n | { found: true; content: string; file: string; name: string; instanceIndex: number }\n | { found: false; error: string }\n\n/** Finds the content between a component's opening > and closing </Name>. */\nexport function getComponentFragment(\n filePath: string,\n name: string,\n instanceIndex: number,\n): FragmentResult {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return { found: false, error: `Cannot read file: ${filePath}` }\n }\n const lines = source.split('\\n')\n\n // Collect all spans for this component\n const spans: [number, number][] = []\n let from = 0\n while (true) {\n const span = findComponentSpan(lines, name, from)\n if (!span) break\n spans.push(span)\n from = span[1] + 1\n }\n if (instanceIndex >= spans.length)\n return { found: false, error: `Instance ${instanceIndex} not found (${spans.length} instances exist)` }\n\n const [spanStart, spanEnd] = spans[instanceIndex]\n const startLine = lines[spanStart]\n const tagStart = startLine.indexOf(`<${name}`)\n\n // Self-closing \u2014 no children\n if (/\\/>/.test(startLine.slice(tagStart)))\n return { found: false, error: `<${name}> is self-closing` }\n if (spanStart === spanEnd)\n return { found: false, error: `<${name}> opens and closes on the same line` }\n\n // Find where the opening tag ends (the > that closes it)\n const { line: openEndLine, col: openEndCol } = findOpenTagEnd(lines, spanStart, name)\n if (openEndCol === -1)\n return { found: false, error: `Cannot find end of opening tag for <${name}>` }\n\n // Content = from after > on openEndLine up to (not including) the closing tag line\n const contentLines: string[] = []\n const afterOpen = lines[openEndLine].slice(openEndCol + 1)\n if (afterOpen.trim()) contentLines.push(afterOpen)\n for (let i = openEndLine + 1; i < spanEnd; i++) contentLines.push(lines[i])\n\n return { found: true, content: contentLines.join('\\n'), file: filePath, name, instanceIndex }\n}\n\n/** Replaces the children content of a component, preserving its opening and closing tags. */\nexport function replaceComponentFragment(\n filePath: string,\n name: string,\n instanceIndex: number,\n newContent: string,\n): ReplaceResult {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return { replaced: false, error: `Cannot read file: ${filePath}` }\n }\n const lines = source.split('\\n')\n\n const spans: [number, number][] = []\n let from = 0\n while (true) {\n const span = findComponentSpan(lines, name, from)\n if (!span) break\n spans.push(span)\n from = span[1] + 1\n }\n if (instanceIndex >= spans.length)\n return { replaced: false, error: `Instance ${instanceIndex} not found` }\n\n const [spanStart, spanEnd] = spans[instanceIndex]\n const startLine = lines[spanStart]\n const tagStart = startLine.indexOf(`<${name}`)\n if (/\\/>/.test(startLine.slice(tagStart)))\n return { replaced: false, error: `<${name}> is self-closing` }\n if (spanStart === spanEnd)\n return { replaced: false, error: `<${name}> opens and closes on the same line` }\n\n const { line: openEndLine, col: openEndCol } = findOpenTagEnd(lines, spanStart, name)\n if (openEndCol === -1)\n return { replaced: false, error: `Cannot find end of opening tag for <${name}>` }\n\n // Preserve the opening tag lines (up to and including the >)\n const openingLines = lines.slice(spanStart, openEndLine + 1)\n openingLines[openingLines.length - 1] = openingLines[openingLines.length - 1].slice(0, openEndCol + 1)\n\n const contentLines = newContent.trim() === '' ? [] : newContent.split('\\n')\n const replacement = [...openingLines, ...contentLines, lines[spanEnd]]\n\n const newLines = [...lines]\n newLines.splice(spanStart, spanEnd - spanStart + 1, ...replacement)\n\n try {\n writeFileSync(filePath, newLines.join('\\n'), 'utf-8')\n } catch {\n return { replaced: false, error: `Cannot write file: ${filePath}` }\n }\n return { replaced: true, file: filePath }\n}\n\nfunction findOpenTagEnd(\n lines: string[],\n spanStart: number,\n name: string,\n): { line: number; col: number } {\n const firstLine = lines[spanStart]\n const tagStart = firstLine.indexOf(`<${name}`)\n // Scan the opening line for the closing >\n for (let i = tagStart + name.length + 1; i < firstLine.length; i++) {\n if (firstLine[i] === '>') return { line: spanStart, col: i }\n }\n // Multi-line tag \u2014 scan forward for a line that is just >\n for (let i = spanStart + 1; i < lines.length; i++) {\n const t = lines[i].trim()\n if (t === '>') return { line: i, col: lines[i].indexOf('>') }\n }\n return { line: spanStart, col: -1 }\n}\n\n/** Finds the content between an HTML element's opening > and closing </tag>. */\nexport function getElementFragment(\n filePath: string,\n tagName: string,\n instanceIndex: number,\n): FragmentResult {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return { found: false, error: `Cannot read file: ${filePath}` }\n }\n const lines = source.split('\\n')\n const span = findFullElementSpan(lines, tagName, instanceIndex)\n if (!span) return { found: false, error: `No <${tagName}> found at index ${instanceIndex}` }\n\n const [spanStart, spanEnd] = span\n const { line: openEndLine, col: openEndCol } = findOpenTagEnd(lines, spanStart, tagName)\n if (openEndCol === -1) return { found: false, error: `Cannot find end of opening tag for <${tagName}>` }\n\n const contentLines: string[] = []\n if (spanStart === spanEnd) {\n // Single line: content between > and </tag>\n const line = lines[spanStart]\n const closeIdx = line.lastIndexOf(`</${tagName}>`)\n if (closeIdx === -1) return { found: false, error: `Cannot find closing tag on same line` }\n contentLines.push(line.slice(openEndCol + 1, closeIdx))\n } else {\n const afterOpen = lines[openEndLine].slice(openEndCol + 1)\n if (afterOpen.trim()) contentLines.push(afterOpen)\n for (let i = openEndLine + 1; i < spanEnd; i++) contentLines.push(lines[i])\n }\n\n return { found: true, content: contentLines.join('\\n'), file: filePath, name: tagName, instanceIndex }\n}\n\n/** Replaces the children content of an HTML element, preserving its opening and closing tags. */\nexport function replaceElementFragment(\n filePath: string,\n tagName: string,\n instanceIndex: number,\n newContent: string,\n): ReplaceResult {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return { replaced: false, error: `Cannot read file: ${filePath}` }\n }\n const lines = source.split('\\n')\n const span = findFullElementSpan(lines, tagName, instanceIndex)\n if (!span) return { replaced: false, error: `No <${tagName}> found at index ${instanceIndex}` }\n\n const [spanStart, spanEnd] = span\n const { line: openEndLine, col: openEndCol } = findOpenTagEnd(lines, spanStart, tagName)\n if (openEndCol === -1) return { replaced: false, error: `Cannot find end of opening tag for <${tagName}>` }\n\n const newLines = [...lines]\n if (spanStart === spanEnd) {\n const line = lines[spanStart]\n const closeIdx = line.lastIndexOf(`</${tagName}>`)\n if (closeIdx === -1) return { replaced: false, error: `Cannot find closing tag on same line` }\n const before = line.slice(0, openEndCol + 1)\n const after = line.slice(closeIdx)\n const contentLines = newContent.trim() === '' ? [] : newContent.split('\\n')\n newLines.splice(spanStart, 1, ...(contentLines.length ? [before + contentLines[0], ...contentLines.slice(1), after] : [before + after]))\n } else {\n const openingLines = lines.slice(spanStart, openEndLine + 1)\n openingLines[openingLines.length - 1] = openingLines[openingLines.length - 1].slice(0, openEndCol + 1)\n const contentLines = newContent.trim() === '' ? [] : newContent.split('\\n')\n const replacement = [...openingLines, ...contentLines, lines[spanEnd]]\n newLines.splice(spanStart, spanEnd - spanStart + 1, ...replacement)\n }\n\n try {\n writeFileSync(filePath, newLines.join('\\n'), 'utf-8')\n } catch {\n return { replaced: false, error: `Cannot write file: ${filePath}` }\n }\n return { replaced: true, file: filePath }\n}\n\nexport type MoveResult = { moved: true; file: string } | { moved: false; error: string }\n\n// Moves a component or element up or down past its adjacent sibling in source.\n// Determines the sibling's span by scanning forward/backward using indent level \u2014\n// no OML tree needed on the server side.\nexport function moveNode(\n filePath: string,\n name: string,\n isComponent: boolean,\n instanceIndex: number,\n direction: 'up' | 'down',\n): MoveResult {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return { moved: false, error: `Cannot read file: ${filePath}` }\n }\n\n const lines = source.split('\\n')\n\n // Find the Nth instance of the target node\n let targetSpan: [number, number] | null = null\n if (isComponent) {\n let from = 0\n for (let idx = 0; idx <= instanceIndex; idx++) {\n const s = findComponentSpan(lines, name, from)\n if (!s) break\n if (idx === instanceIndex) targetSpan = s\n from = s[1] + 1\n }\n } else {\n targetSpan = findFullElementSpan(lines, name, instanceIndex)\n }\n\n if (!targetSpan) return { moved: false, error: `No <${name}> found at index ${instanceIndex}` }\n\n const [startA, endA] = targetSpan\n const indA = (lines[startA].match(/^(\\s*)/) ?? ['', ''])[1].length\n\n let siblingSpan: [number, number] | null = null\n\n if (direction === 'up') {\n // Preceding sibling: its end is the first non-blank line before startA\n let endB = startA - 1\n while (endB >= 0 && lines[endB].trim() === '') endB--\n if (endB < 0) return { moved: false, error: 'Already at top' }\n\n // Scan backward from endB to find the sibling's start: first line at indA that opens a tag\n let startB = endB\n for (let j = endB - 1; j >= 0; j--) {\n const t = lines[j].trim()\n if (!t) continue\n const ind = (lines[j].match(/^(\\s*)/) ?? ['', ''])[1].length\n if (ind < indA) break\n if (ind === indA && t.startsWith('<') && !t.startsWith('</') && !t.startsWith('<!--')) {\n startB = j\n break\n }\n }\n siblingSpan = [startB, endB]\n } else {\n // Following sibling: its start is the first non-blank line after endA\n let startB = endA + 1\n while (startB < lines.length && lines[startB].trim() === '') startB++\n if (startB >= lines.length) return { moved: false, error: 'Already at bottom' }\n\n const indB = (lines[startB].match(/^(\\s*)/) ?? ['', ''])[1].length\n const tagMatch = lines[startB].match(/<([A-Za-z][A-Za-z0-9_:-]*)/)\n if (!tagMatch) return { moved: false, error: 'Cannot identify next sibling' }\n\n const tagB = tagMatch[1]\n const tagPos = lines[startB].indexOf(`<${tagB}`)\n const restB = lines[startB].slice(tagPos)\n let endB = startB\n\n if (/\\/>/.test(restB) || new RegExp(`</${tagB}>`).test(restB)) {\n endB = startB\n } else {\n for (let j = startB + 1; j < lines.length; j++) {\n const t = lines[j].trim()\n const ind = (lines[j].match(/^(\\s*)/) ?? ['', ''])[1].length\n if ((t.startsWith(`</${tagB}>`) || t === '/>') && ind <= indB) { endB = j; break }\n if (t && ind < indB) { endB = j - 1; break }\n }\n }\n siblingSpan = [startB, endB]\n }\n\n // Swap the two spans (process in reverse order to preserve line indices)\n const [first, second] =\n targetSpan[0] < siblingSpan[0] ? [targetSpan, siblingSpan] : [siblingSpan, targetSpan]\n\n const linesFirst = lines.slice(first[0], first[1] + 1)\n const linesSecond = lines.slice(second[0], second[1] + 1)\n\n const newLines = [...lines]\n newLines.splice(second[0], second[1] - second[0] + 1, ...linesFirst)\n newLines.splice(first[0], first[1] - first[0] + 1, ...linesSecond)\n\n try {\n writeFileSync(filePath, newLines.join('\\n'), 'utf-8')\n } catch {\n return { moved: false, error: `Cannot write file: ${filePath}` }\n }\n\n return { moved: true, file: filePath }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,cAAc,qBAAqB;AAI5C,SAAS,kBAAkB,OAAiB,MAAc,YAAY,GAA4B;AAChG,QAAM,SAAS,IAAI,OAAO,SAAS,IAAI,cAAc;AACrD,MAAI,UAAU;AACd,WAAS,IAAI,WAAW,IAAI,MAAM,QAAQ,KAAK;AAC7C,QAAI,OAAO,KAAK,MAAM,CAAC,CAAC,GAAG;AACzB,gBAAU;AACV;AAAA,IACF;AAAA,EACF;AACA,MAAI,YAAY,GAAI,QAAO;AAE3B,QAAM,cAAc,MAAM,OAAO,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC;AACjE,QAAM,WAAW,MAAM,OAAO,EAAE,QAAQ,IAAI,IAAI,EAAE;AAClD,QAAM,OAAO,MAAM,OAAO,EAAE,MAAM,QAAQ;AAG1C,MAAI,MAAM,KAAK,IAAI,KAAK,IAAI,OAAO,KAAK,IAAI,GAAG,EAAE,KAAK,IAAI,EAAG,QAAO,CAAC,SAAS,OAAO;AAGrF,WAAS,IAAI,UAAU,GAAG,IAAI,MAAM,QAAQ,KAAK;AAC/C,UAAM,IAAI,MAAM,CAAC,EAAE,KAAK;AACxB,UAAM,OAAO,MAAM,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC;AACpD,SAAK,MAAM,QAAQ,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI,UAAU,WAAW,SAAS,GAAG;AACrF,aAAO,CAAC,SAAS,CAAC;AAAA,IACpB;AAEA,QAAI,KAAK,IAAI,UAAU,WAAW,UAAU,IAAI,UAAU,EAAG;AAAA,EAC/D;AAEA,SAAO,CAAC,SAAS,OAAO;AAC1B;AAEO,SAAS,UAAU,UAAkB,eAAuB,eAAsC;AACvG,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,SAAS,OAAO,OAAO,qBAAqB,QAAQ,GAAG;AAAA,EAClE;AAEA,QAAM,QAAQ,OAAO,MAAM,IAAI;AAG/B,QAAM,QAA4B,CAAC;AACnC,MAAI,OAAO;AACX,SAAO,MAAM;AACX,UAAM,OAAO,kBAAkB,OAAO,eAAe,IAAI;AACzD,QAAI,CAAC,KAAM;AACX,UAAM,KAAK,IAAI;AACf,WAAO,KAAK,CAAC,IAAI;AAAA,EACnB;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,EAAE,SAAS,OAAO,OAAO,OAAO,aAAa,qBAAqB;AAAA,EAC3E;AACA,QAAM,MAAM,kBAAkB,MAAM,WAAW,IAAI,IAAI;AACvD,MAAI,QAAQ,IAAI;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,GAAG,MAAM,MAAM,kBAAkB,aAAa;AAAA,IACvD;AAAA,EACF;AACA,MAAI,OAAO,MAAM,QAAQ;AACvB,WAAO,EAAE,SAAS,OAAO,OAAO,YAAY,GAAG,eAAe,MAAM,MAAM,qBAAqB;AAAA,EACjG;AAEA,QAAM,CAAC,OAAO,GAAG,IAAI,MAAM,GAAG;AAC9B,QAAM,OAAO,OAAO,MAAM,QAAQ,CAAC;AAGnC,QAAM,UAAoB,CAAC;AAC3B,MAAI,YAAY;AAChB,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,KAAK,KAAK,MAAM;AAC9B,QAAI,SAAS,UAAW;AACxB,YAAQ,KAAK,IAAI;AACjB,gBAAY;AAAA,EACd;AAEA,MAAI;AACF,kBAAc,UAAU,QAAQ,KAAK,IAAI,GAAG,OAAO;AAAA,EACrD,QAAQ;AACN,WAAO,EAAE,SAAS,OAAO,OAAO,sBAAsB,QAAQ,GAAG;AAAA,EACnE;AAEA,SAAO,EAAE,SAAS,MAAM,MAAM,SAAS;AACzC;AAEO,SAAS,cAAc,UAAkB,SAAiB,eAAqC;AACpG,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,SAAS,OAAO,OAAO,qBAAqB,QAAQ,GAAG;AAAA,EAClE;AAEA,QAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,QAAM,OAAO,oBAAoB,OAAO,SAAS,aAAa;AAC9D,MAAI,CAAC,KAAM,QAAO,EAAE,SAAS,OAAO,OAAO,OAAO,OAAO,oBAAoB,aAAa,GAAG;AAE7F,QAAM,CAAC,OAAO,GAAG,IAAI;AACrB,QAAM,OAAO,OAAO,MAAM,QAAQ,CAAC;AAEnC,QAAM,UAAoB,CAAC;AAC3B,MAAI,YAAY;AAChB,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,KAAK,KAAK,MAAM;AAC9B,QAAI,SAAS,UAAW;AACxB,YAAQ,KAAK,IAAI;AACjB,gBAAY;AAAA,EACd;AAEA,MAAI;AACF,kBAAc,UAAU,QAAQ,KAAK,IAAI,GAAG,OAAO;AAAA,EACrD,QAAQ;AACN,WAAO,EAAE,SAAS,OAAO,OAAO,sBAAsB,QAAQ,GAAG;AAAA,EACnE;AAEA,SAAO,EAAE,SAAS,MAAM,MAAM,SAAS;AACzC;AAQA,SAAS,mBAAmB,OAAiB,SAAiB,eAAgD;AAC5G,QAAM,SAAS,IAAI,OAAO,IAAI,OAAO,aAAa;AAClD,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,QAAI,OAAO,KAAK,MAAM,CAAC,CAAC,GAAG;AACzB,UAAI,UAAU,eAAe;AAE3B,cAAM,SAAS,MAAM,CAAC,EAAE,OAAO,MAAM;AACrC,cAAM,OAAO,MAAM,CAAC,EAAE,MAAM,MAAM;AAClC,YAAI,KAAK,SAAS,GAAG,EAAG,QAAO,CAAC,GAAG,CAAC;AAEpC,iBAAS,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACzC,gBAAM,IAAI,MAAM,CAAC,EAAE,KAAK;AACxB,cAAI,MAAM,OAAO,MAAM,KAAM,QAAO,CAAC,GAAG,CAAC;AAAA,QAC3C;AACA,eAAO,CAAC,GAAG,CAAC;AAAA,MACd;AACA;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAa,SAAiB,OAAgC,WAA4B;AACjG,QAAM,UAAU,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,UAAa,MAAM,IAAI;AACrF,MAAI,CAAC,QAAQ,OAAQ,QAAO,YAAY,IAAI,OAAO,QAAQ,IAAI,OAAO;AACtE,QAAM,QAAQ,QACX,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM;AACf,QAAI,MAAM,KAAM,QAAO;AACvB,QAAI,MAAM,MAAO,QAAO;AACxB,QAAI,OAAO,MAAM,SAAU,QAAO,GAAG,CAAC,KAAK,CAAC;AAC5C,WAAO,GAAG,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC;AAAA,EACnC,CAAC,EACA,OAAO,OAAO,EACd,KAAK,GAAG;AACX,SAAO,QAAS,YAAY,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,MAAQ,YAAY,IAAI,OAAO,QAAQ,IAAI,OAAO;AAChI;AAEO,SAAS,oBACd,UACA,SACA,UACA,gBAAgB,GACG;AACnB,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,OAAO,qBAAqB,QAAQ,GAAG;AAAA,EACnE;AAEA,QAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,QAAM,OAAO,mBAAmB,OAAO,SAAS,aAAa;AAC7D,MAAI,CAAC,KAAM,QAAO,EAAE,UAAU,OAAO,OAAO,OAAO,OAAO,oBAAoB,aAAa,GAAG;AAE9F,QAAM,CAAC,WAAW,OAAO,IAAI;AAC7B,QAAM,WAAW,CAAC,GAAG,KAAK;AAC1B,QAAM,SAAS,IAAI,OAAO,IAAI,OAAO,aAAa;AAElD,MAAI,cAAc,SAAS;AACzB,UAAM,OAAO,MAAM,SAAS;AAC5B,UAAM,SAAS,KAAK,OAAO,MAAM;AACjC,UAAM,SAAS,KAAK,MAAM,GAAG,MAAM;AAEnC,QAAI,WAAW;AACf,QAAI,YAAY;AAChB,aAAS,IAAI,SAAS,QAAQ,SAAS,GAAG,IAAI,KAAK,QAAQ,KAAK;AAC9D,UAAI,KAAK,CAAC,MAAM,KAAK;AACnB,YAAI,KAAK,IAAI,CAAC,MAAM,KAAK;AACvB,sBAAY;AACZ,qBAAW,IAAI;AAAA,QACjB,OAAO;AACL,qBAAW;AAAA,QACb;AACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,aAAa,GAAI,QAAO,EAAE,UAAU,OAAO,OAAO,gCAAgC,OAAO,IAAI;AACjG,UAAM,QAAQ,KAAK,MAAM,YAAY,WAAW,IAAI,WAAW,CAAC;AAChE,aAAS,SAAS,IAAI,SAAS,aAAa,SAAS,UAAU,SAAS,IAAI;AAAA,EAC9E,OAAO;AACL,UAAM,YAAY,MAAM,SAAS;AACjC,UAAM,SAAS,UAAU,OAAO,MAAM;AACtC,UAAM,SAAS,UAAU,MAAM,GAAG,MAAM;AACxC,UAAM,WAAW,MAAM,OAAO;AAC9B,UAAM,YAAY,SAAS,KAAK,MAAM;AACtC,UAAM,WAAW,SAAS,QAAQ,YAAY,OAAO,GAAG;AACxD,UAAM,QAAQ,SAAS,MAAM,YAAY,YAAY,IAAI,EAAE;AAC3D,aAAS,OAAO,WAAW,UAAU,YAAY,GAAG,SAAS,aAAa,SAAS,UAAU,SAAS,IAAI,KAAK;AAAA,EACjH;AAEA,MAAI;AACF,kBAAc,UAAU,SAAS,KAAK,IAAI,GAAG,OAAO;AAAA,EACtD,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,OAAO,sBAAsB,QAAQ,GAAG;AAAA,EACpE;AAEA,SAAO,EAAE,UAAU,MAAM,MAAM,SAAS;AAC1C;AAKO,SAAS,mBACd,UACA,SACA,SACA,gBAAgB,GACG;AACnB,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,OAAO,qBAAqB,QAAQ,GAAG;AAAA,EACnE;AAEA,QAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,QAAM,OAAO,mBAAmB,OAAO,SAAS,aAAa;AAC7D,MAAI,CAAC,KAAM,QAAO,EAAE,UAAU,OAAO,OAAO,OAAO,OAAO,oBAAoB,aAAa,GAAG;AAE9F,QAAM,CAAC,WAAW,OAAO,IAAI;AAC7B,QAAM,cAAc;AACpB,QAAM,OAAO,MAAM,WAAW;AAE9B,QAAM,WAAW,KAAK,OAAO;AAC7B,QAAM,WAAW,KAAK,QAAQ,QAAQ;AACtC,MAAI,aAAa,IAAI;AACnB,WAAO,EAAE,UAAU,OAAO,OAAO,IAAI,OAAO,oDAA+C;AAAA,EAC7F;AAGA,QAAM,SAAS,IAAI,OAAO,IAAI,OAAO,aAAa;AAClD,QAAM,WAAW,cAAc,UAAU,KAAK,OAAO,MAAM,IAAI;AAC/D,MAAI,UAAU;AACd,WAAS,IAAI,UAAU,IAAI,UAAU,KAAK;AACxC,QAAI,KAAK,CAAC,MAAM,KAAK;AACnB,gBAAU;AACV;AAAA,IACF;AAAA,EACF;AACA,MAAI,YAAY,GAAI,QAAO,EAAE,UAAU,OAAO,OAAO,gCAAgC,OAAO,IAAI;AAEhG,QAAM,WAAW,IAAI,KAAK,MAAM,GAAG,UAAU,CAAC,IAAI,UAAU,KAAK,MAAM,QAAQ;AAE/E,MAAI;AACF,kBAAc,UAAU,MAAM,KAAK,IAAI,GAAG,OAAO;AAAA,EACnD,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,OAAO,sBAAsB,QAAQ,GAAG;AAAA,EACpE;AAEA,SAAO,EAAE,UAAU,MAAM,MAAM,SAAS;AAC1C;AAEO,SAAS,WACd,UACA,eACA,QACA,gBAAgB,GACD;AACf,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,OAAO,qBAAqB,QAAQ,GAAG;AAAA,EACnE;AAEA,QAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,QAAM,QAA4B,CAAC;AACnC,MAAI,OAAO;AACX,SAAO,MAAM;AACX,UAAM,OAAO,kBAAkB,OAAO,eAAe,IAAI;AACzD,QAAI,CAAC,KAAM;AACX,UAAM,KAAK,IAAI;AACf,WAAO,KAAK,CAAC,IAAI;AAAA,EACnB;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,EAAE,UAAU,OAAO,OAAO,OAAO,aAAa,qBAAqB;AAAA,EAC5E;AACA,MAAI,iBAAiB,MAAM,QAAQ;AACjC,WAAO;AAAA,MACL,UAAU;AAAA,MACV,OAAO,kBAAkB,aAAa,kBAAkB,MAAM,MAAM;AAAA,IACtE;AAAA,EACF;AAEA,QAAM,CAAC,OAAO,GAAG,IAAI,MAAM,aAAa;AACxC,QAAM,kBAAkB,MAAM,KAAK,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC;AAEnE,QAAM,WAAW,OAAO,MAAM,IAAI,EAAE,IAAI,CAAC,MAAO,MAAM,KAAK,KAAK,iBAAiB,CAAE;AAEnF,QAAM,OAAO,OAAO,MAAM,QAAQ,GAAG,GAAG,QAAQ;AAEhD,MAAI;AACF,kBAAc,UAAU,MAAM,KAAK,IAAI,GAAG,OAAO;AAAA,EACnD,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,OAAO,sBAAsB,QAAQ,GAAG;AAAA,EACpE;AAEA,SAAO,EAAE,UAAU,MAAM,MAAM,SAAS;AAC1C;AAGA,SAAS,oBAAoB,OAAiB,SAAiB,eAAgD;AAC7G,QAAM,SAAS,IAAI,OAAO,IAAI,OAAO,aAAa;AAClD,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,QAAI,OAAO,KAAK,MAAM,CAAC,CAAC,GAAG;AACzB,UAAI,UAAU,eAAe;AAC3B,cAAM,SAAS,MAAM,CAAC,EAAE,OAAO,MAAM;AACrC,cAAM,cAAc,MAAM,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC;AAC3D,cAAM,OAAO,MAAM,CAAC,EAAE,MAAM,MAAM;AAClC,YAAI,MAAM,KAAK,IAAI,KAAK,IAAI,OAAO,KAAK,OAAO,GAAG,EAAE,KAAK,IAAI,EAAG,QAAO,CAAC,GAAG,CAAC;AAC5E,iBAAS,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACzC,gBAAM,IAAI,MAAM,CAAC,EAAE,KAAK;AACxB,gBAAM,OAAO,MAAM,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC;AACpD,cAAI,EAAE,WAAW,KAAK,OAAO,GAAG,KAAK,IAAI,UAAU,WAAW,OAAQ,QAAO,CAAC,GAAG,CAAC;AAClF,cAAI,KAAK,IAAI,SAAS,WAAW,OAAQ;AAAA,QAC3C;AACA,eAAO,CAAC,GAAG,CAAC;AAAA,MACd;AACA;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,qBACd,UACA,MACA,eACgB;AAChB,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,OAAO,OAAO,OAAO,qBAAqB,QAAQ,GAAG;AAAA,EAChE;AACA,QAAM,QAAQ,OAAO,MAAM,IAAI;AAG/B,QAAM,QAA4B,CAAC;AACnC,MAAI,OAAO;AACX,SAAO,MAAM;AACX,UAAM,OAAO,kBAAkB,OAAO,MAAM,IAAI;AAChD,QAAI,CAAC,KAAM;AACX,UAAM,KAAK,IAAI;AACf,WAAO,KAAK,CAAC,IAAI;AAAA,EACnB;AACA,MAAI,iBAAiB,MAAM;AACzB,WAAO,EAAE,OAAO,OAAO,OAAO,YAAY,aAAa,eAAe,MAAM,MAAM,oBAAoB;AAExG,QAAM,CAAC,WAAW,OAAO,IAAI,MAAM,aAAa;AAChD,QAAM,YAAY,MAAM,SAAS;AACjC,QAAM,WAAW,UAAU,QAAQ,IAAI,IAAI,EAAE;AAG7C,MAAI,MAAM,KAAK,UAAU,MAAM,QAAQ,CAAC;AACtC,WAAO,EAAE,OAAO,OAAO,OAAO,IAAI,IAAI,oBAAoB;AAC5D,MAAI,cAAc;AAChB,WAAO,EAAE,OAAO,OAAO,OAAO,IAAI,IAAI,sCAAsC;AAG9E,QAAM,EAAE,MAAM,aAAa,KAAK,WAAW,IAAI,eAAe,OAAO,WAAW,IAAI;AACpF,MAAI,eAAe;AACjB,WAAO,EAAE,OAAO,OAAO,OAAO,uCAAuC,IAAI,IAAI;AAG/E,QAAM,eAAyB,CAAC;AAChC,QAAM,YAAY,MAAM,WAAW,EAAE,MAAM,aAAa,CAAC;AACzD,MAAI,UAAU,KAAK,EAAG,cAAa,KAAK,SAAS;AACjD,WAAS,IAAI,cAAc,GAAG,IAAI,SAAS,IAAK,cAAa,KAAK,MAAM,CAAC,CAAC;AAE1E,SAAO,EAAE,OAAO,MAAM,SAAS,aAAa,KAAK,IAAI,GAAG,MAAM,UAAU,MAAM,cAAc;AAC9F;AAGO,SAAS,yBACd,UACA,MACA,eACA,YACe;AACf,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,OAAO,qBAAqB,QAAQ,GAAG;AAAA,EACnE;AACA,QAAM,QAAQ,OAAO,MAAM,IAAI;AAE/B,QAAM,QAA4B,CAAC;AACnC,MAAI,OAAO;AACX,SAAO,MAAM;AACX,UAAM,OAAO,kBAAkB,OAAO,MAAM,IAAI;AAChD,QAAI,CAAC,KAAM;AACX,UAAM,KAAK,IAAI;AACf,WAAO,KAAK,CAAC,IAAI;AAAA,EACnB;AACA,MAAI,iBAAiB,MAAM;AACzB,WAAO,EAAE,UAAU,OAAO,OAAO,YAAY,aAAa,aAAa;AAEzE,QAAM,CAAC,WAAW,OAAO,IAAI,MAAM,aAAa;AAChD,QAAM,YAAY,MAAM,SAAS;AACjC,QAAM,WAAW,UAAU,QAAQ,IAAI,IAAI,EAAE;AAC7C,MAAI,MAAM,KAAK,UAAU,MAAM,QAAQ,CAAC;AACtC,WAAO,EAAE,UAAU,OAAO,OAAO,IAAI,IAAI,oBAAoB;AAC/D,MAAI,cAAc;AAChB,WAAO,EAAE,UAAU,OAAO,OAAO,IAAI,IAAI,sCAAsC;AAEjF,QAAM,EAAE,MAAM,aAAa,KAAK,WAAW,IAAI,eAAe,OAAO,WAAW,IAAI;AACpF,MAAI,eAAe;AACjB,WAAO,EAAE,UAAU,OAAO,OAAO,uCAAuC,IAAI,IAAI;AAGlF,QAAM,eAAe,MAAM,MAAM,WAAW,cAAc,CAAC;AAC3D,eAAa,aAAa,SAAS,CAAC,IAAI,aAAa,aAAa,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;AAErG,QAAM,eAAe,WAAW,KAAK,MAAM,KAAK,CAAC,IAAI,WAAW,MAAM,IAAI;AAC1E,QAAM,cAAc,CAAC,GAAG,cAAc,GAAG,cAAc,MAAM,OAAO,CAAC;AAErE,QAAM,WAAW,CAAC,GAAG,KAAK;AAC1B,WAAS,OAAO,WAAW,UAAU,YAAY,GAAG,GAAG,WAAW;AAElE,MAAI;AACF,kBAAc,UAAU,SAAS,KAAK,IAAI,GAAG,OAAO;AAAA,EACtD,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,OAAO,sBAAsB,QAAQ,GAAG;AAAA,EACpE;AACA,SAAO,EAAE,UAAU,MAAM,MAAM,SAAS;AAC1C;AAEA,SAAS,eACP,OACA,WACA,MAC+B;AAC/B,QAAM,YAAY,MAAM,SAAS;AACjC,QAAM,WAAW,UAAU,QAAQ,IAAI,IAAI,EAAE;AAE7C,WAAS,IAAI,WAAW,KAAK,SAAS,GAAG,IAAI,UAAU,QAAQ,KAAK;AAClE,QAAI,UAAU,CAAC,MAAM,IAAK,QAAO,EAAE,MAAM,WAAW,KAAK,EAAE;AAAA,EAC7D;AAEA,WAAS,IAAI,YAAY,GAAG,IAAI,MAAM,QAAQ,KAAK;AACjD,UAAM,IAAI,MAAM,CAAC,EAAE,KAAK;AACxB,QAAI,MAAM,IAAK,QAAO,EAAE,MAAM,GAAG,KAAK,MAAM,CAAC,EAAE,QAAQ,GAAG,EAAE;AAAA,EAC9D;AACA,SAAO,EAAE,MAAM,WAAW,KAAK,GAAG;AACpC;AAGO,SAAS,mBACd,UACA,SACA,eACgB;AAChB,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,OAAO,OAAO,OAAO,qBAAqB,QAAQ,GAAG;AAAA,EAChE;AACA,QAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,QAAM,OAAO,oBAAoB,OAAO,SAAS,aAAa;AAC9D,MAAI,CAAC,KAAM,QAAO,EAAE,OAAO,OAAO,OAAO,OAAO,OAAO,oBAAoB,aAAa,GAAG;AAE3F,QAAM,CAAC,WAAW,OAAO,IAAI;AAC7B,QAAM,EAAE,MAAM,aAAa,KAAK,WAAW,IAAI,eAAe,OAAO,WAAW,OAAO;AACvF,MAAI,eAAe,GAAI,QAAO,EAAE,OAAO,OAAO,OAAO,uCAAuC,OAAO,IAAI;AAEvG,QAAM,eAAyB,CAAC;AAChC,MAAI,cAAc,SAAS;AAEzB,UAAM,OAAO,MAAM,SAAS;AAC5B,UAAM,WAAW,KAAK,YAAY,KAAK,OAAO,GAAG;AACjD,QAAI,aAAa,GAAI,QAAO,EAAE,OAAO,OAAO,OAAO,uCAAuC;AAC1F,iBAAa,KAAK,KAAK,MAAM,aAAa,GAAG,QAAQ,CAAC;AAAA,EACxD,OAAO;AACL,UAAM,YAAY,MAAM,WAAW,EAAE,MAAM,aAAa,CAAC;AACzD,QAAI,UAAU,KAAK,EAAG,cAAa,KAAK,SAAS;AACjD,aAAS,IAAI,cAAc,GAAG,IAAI,SAAS,IAAK,cAAa,KAAK,MAAM,CAAC,CAAC;AAAA,EAC5E;AAEA,SAAO,EAAE,OAAO,MAAM,SAAS,aAAa,KAAK,IAAI,GAAG,MAAM,UAAU,MAAM,SAAS,cAAc;AACvG;AAGO,SAAS,uBACd,UACA,SACA,eACA,YACe;AACf,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,OAAO,qBAAqB,QAAQ,GAAG;AAAA,EACnE;AACA,QAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,QAAM,OAAO,oBAAoB,OAAO,SAAS,aAAa;AAC9D,MAAI,CAAC,KAAM,QAAO,EAAE,UAAU,OAAO,OAAO,OAAO,OAAO,oBAAoB,aAAa,GAAG;AAE9F,QAAM,CAAC,WAAW,OAAO,IAAI;AAC7B,QAAM,EAAE,MAAM,aAAa,KAAK,WAAW,IAAI,eAAe,OAAO,WAAW,OAAO;AACvF,MAAI,eAAe,GAAI,QAAO,EAAE,UAAU,OAAO,OAAO,uCAAuC,OAAO,IAAI;AAE1G,QAAM,WAAW,CAAC,GAAG,KAAK;AAC1B,MAAI,cAAc,SAAS;AACzB,UAAM,OAAO,MAAM,SAAS;AAC5B,UAAM,WAAW,KAAK,YAAY,KAAK,OAAO,GAAG;AACjD,QAAI,aAAa,GAAI,QAAO,EAAE,UAAU,OAAO,OAAO,uCAAuC;AAC7F,UAAM,SAAS,KAAK,MAAM,GAAG,aAAa,CAAC;AAC3C,UAAM,QAAQ,KAAK,MAAM,QAAQ;AACjC,UAAM,eAAe,WAAW,KAAK,MAAM,KAAK,CAAC,IAAI,WAAW,MAAM,IAAI;AAC1E,aAAS,OAAO,WAAW,GAAG,GAAI,aAAa,SAAS,CAAC,SAAS,aAAa,CAAC,GAAG,GAAG,aAAa,MAAM,CAAC,GAAG,KAAK,IAAI,CAAC,SAAS,KAAK,CAAE;AAAA,EACzI,OAAO;AACL,UAAM,eAAe,MAAM,MAAM,WAAW,cAAc,CAAC;AAC3D,iBAAa,aAAa,SAAS,CAAC,IAAI,aAAa,aAAa,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;AACrG,UAAM,eAAe,WAAW,KAAK,MAAM,KAAK,CAAC,IAAI,WAAW,MAAM,IAAI;AAC1E,UAAM,cAAc,CAAC,GAAG,cAAc,GAAG,cAAc,MAAM,OAAO,CAAC;AACrE,aAAS,OAAO,WAAW,UAAU,YAAY,GAAG,GAAG,WAAW;AAAA,EACpE;AAEA,MAAI;AACF,kBAAc,UAAU,SAAS,KAAK,IAAI,GAAG,OAAO;AAAA,EACtD,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,OAAO,sBAAsB,QAAQ,GAAG;AAAA,EACpE;AACA,SAAO,EAAE,UAAU,MAAM,MAAM,SAAS;AAC1C;AAOO,SAAS,SACd,UACA,MACA,aACA,eACA,WACY;AACZ,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,OAAO,OAAO,OAAO,qBAAqB,QAAQ,GAAG;AAAA,EAChE;AAEA,QAAM,QAAQ,OAAO,MAAM,IAAI;AAG/B,MAAI,aAAsC;AAC1C,MAAI,aAAa;AACf,QAAI,OAAO;AACX,aAAS,MAAM,GAAG,OAAO,eAAe,OAAO;AAC7C,YAAM,IAAI,kBAAkB,OAAO,MAAM,IAAI;AAC7C,UAAI,CAAC,EAAG;AACR,UAAI,QAAQ,cAAe,cAAa;AACxC,aAAO,EAAE,CAAC,IAAI;AAAA,IAChB;AAAA,EACF,OAAO;AACL,iBAAa,oBAAoB,OAAO,MAAM,aAAa;AAAA,EAC7D;AAEA,MAAI,CAAC,WAAY,QAAO,EAAE,OAAO,OAAO,OAAO,OAAO,IAAI,oBAAoB,aAAa,GAAG;AAE9F,QAAM,CAAC,QAAQ,IAAI,IAAI;AACvB,QAAM,QAAQ,MAAM,MAAM,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;AAE5D,MAAI,cAAuC;AAE3C,MAAI,cAAc,MAAM;AAEtB,QAAI,OAAO,SAAS;AACpB,WAAO,QAAQ,KAAK,MAAM,IAAI,EAAE,KAAK,MAAM,GAAI;AAC/C,QAAI,OAAO,EAAG,QAAO,EAAE,OAAO,OAAO,OAAO,iBAAiB;AAG7D,QAAI,SAAS;AACb,aAAS,IAAI,OAAO,GAAG,KAAK,GAAG,KAAK;AAClC,YAAM,IAAI,MAAM,CAAC,EAAE,KAAK;AACxB,UAAI,CAAC,EAAG;AACR,YAAM,OAAO,MAAM,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;AACtD,UAAI,MAAM,KAAM;AAChB,UAAI,QAAQ,QAAQ,EAAE,WAAW,GAAG,KAAK,CAAC,EAAE,WAAW,IAAI,KAAK,CAAC,EAAE,WAAW,MAAM,GAAG;AACrF,iBAAS;AACT;AAAA,MACF;AAAA,IACF;AACA,kBAAc,CAAC,QAAQ,IAAI;AAAA,EAC7B,OAAO;AAEL,QAAI,SAAS,OAAO;AACpB,WAAO,SAAS,MAAM,UAAU,MAAM,MAAM,EAAE,KAAK,MAAM,GAAI;AAC7D,QAAI,UAAU,MAAM,OAAQ,QAAO,EAAE,OAAO,OAAO,OAAO,oBAAoB;AAE9E,UAAM,QAAQ,MAAM,MAAM,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;AAC5D,UAAM,WAAW,MAAM,MAAM,EAAE,MAAM,4BAA4B;AACjE,QAAI,CAAC,SAAU,QAAO,EAAE,OAAO,OAAO,OAAO,+BAA+B;AAE5E,UAAM,OAAO,SAAS,CAAC;AACvB,UAAM,SAAS,MAAM,MAAM,EAAE,QAAQ,IAAI,IAAI,EAAE;AAC/C,UAAM,QAAQ,MAAM,MAAM,EAAE,MAAM,MAAM;AACxC,QAAI,OAAO;AAEX,QAAI,MAAM,KAAK,KAAK,KAAK,IAAI,OAAO,KAAK,IAAI,GAAG,EAAE,KAAK,KAAK,GAAG;AAC7D,aAAO;AAAA,IACT,OAAO;AACL,eAAS,IAAI,SAAS,GAAG,IAAI,MAAM,QAAQ,KAAK;AAC9C,cAAM,IAAI,MAAM,CAAC,EAAE,KAAK;AACxB,cAAM,OAAO,MAAM,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;AACtD,aAAK,EAAE,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,OAAO,MAAM;AAAE,iBAAO;AAAG;AAAA,QAAM;AACjF,YAAI,KAAK,MAAM,MAAM;AAAE,iBAAO,IAAI;AAAG;AAAA,QAAM;AAAA,MAC7C;AAAA,IACF;AACA,kBAAc,CAAC,QAAQ,IAAI;AAAA,EAC7B;AAGA,QAAM,CAAC,OAAO,MAAM,IAClB,WAAW,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,YAAY,WAAW,IAAI,CAAC,aAAa,UAAU;AAEvF,QAAM,aAAa,MAAM,MAAM,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;AACrD,QAAM,cAAc,MAAM,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;AAExD,QAAM,WAAW,CAAC,GAAG,KAAK;AAC1B,WAAS,OAAO,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,GAAG,GAAG,UAAU;AACnE,WAAS,OAAO,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,GAAG,WAAW;AAEjE,MAAI;AACF,kBAAc,UAAU,SAAS,KAAK,IAAI,GAAG,OAAO;AAAA,EACtD,QAAQ;AACN,WAAO,EAAE,OAAO,OAAO,OAAO,sBAAsB,QAAQ,GAAG;AAAA,EACjE;AAEA,SAAO,EAAE,OAAO,MAAM,MAAM,SAAS;AACvC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type DavauxPlugin } from '../config.js';
|
|
2
|
+
export interface DevOptions {
|
|
3
|
+
cwd: string;
|
|
4
|
+
port?: number;
|
|
5
|
+
hostname?: string;
|
|
6
|
+
routesDir?: string;
|
|
7
|
+
publicDir?: string;
|
|
8
|
+
islandsDir?: string;
|
|
9
|
+
/** Path to the client-side entry file for custom client code. Default: <cwd>/src/client.ts */
|
|
10
|
+
clientEntry?: string;
|
|
11
|
+
/** Path aliases forwarded to esbuild `alias` in every build context. Same glob syntax as tsconfig `paths`. */
|
|
12
|
+
paths?: Record<string, string>;
|
|
13
|
+
/** Davaux plugins from davaux.config.ts — contribute esbuild transforms and scanner extensions. */
|
|
14
|
+
plugins?: DavauxPlugin[];
|
|
15
|
+
/**
|
|
16
|
+
* Additional packages to exclude from esbuild bundling. Merged with the default
|
|
17
|
+
* `['node:*', 'davaux']` externals. Useful for native or CJS-only packages.
|
|
18
|
+
*/
|
|
19
|
+
external?: string[];
|
|
20
|
+
/** Absolute path to `src/middleware.ts` if it exists — compiled and run before route matching. */
|
|
21
|
+
middlewareSrc?: string;
|
|
22
|
+
/** Visual editor configuration from davaux.config.ts. */
|
|
23
|
+
editor?: import('../config.js').EditorConfig;
|
|
24
|
+
}
|
|
25
|
+
export declare function startDev(options: DevOptions): Promise<void>;
|
|
26
|
+
//# sourceMappingURL=watch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/dev/watch.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,YAAY,EAElB,MAAM,cAAc,CAAA;AAqnErB,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8GAA8G;IAC9G,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,mGAAmG;IACnG,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,kGAAkG;IAClG,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,yDAAyD;IACzD,MAAM,CAAC,EAAE,OAAO,cAAc,EAAE,YAAY,CAAA;CAC7C;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAk3BjE"}
|