jskelet 0.6.3 → 0.6.4
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/AGENTS.md +136 -136
- package/CHANGELOG.md +628 -620
- package/LICENSE +21 -21
- package/README.md +2 -0
- package/bin/jskelet.mjs +130 -130
- package/docs/01-baslangic.md +291 -291
- package/docs/02-mimari.md +310 -310
- package/docs/03-routing.md +515 -515
- package/docs/04-render-ve-sablonlar.md +667 -661
- package/docs/05-islands.md +486 -486
- package/docs/06-cache.md +1467 -1443
- package/docs/07-yapilandirma.md +1208 -1197
- package/docs/08-build.md +429 -429
- package/docs/09-dev-araclari.md +364 -364
- package/docs/10-dagitim.md +348 -338
- package/docs/12-panel-ve-oturum.md +479 -478
- package/docs/README.md +83 -83
- package/docs/en/01-getting-started.md +298 -298
- package/docs/en/02-architecture.md +329 -329
- package/docs/en/03-routing.md +531 -531
- package/docs/en/04-rendering.md +675 -669
- package/docs/en/05-islands.md +497 -497
- package/docs/en/06-caching.md +1476 -1453
- package/docs/en/07-configuration.md +1229 -1219
- package/docs/en/08-build.md +447 -447
- package/docs/en/09-dev-tools.md +373 -373
- package/docs/en/10-deployment.md +351 -340
- package/docs/en/11-migration.md +398 -398
- package/docs/en/12-dashboards-and-sessions.md +489 -488
- package/docs/en/README.md +87 -87
- package/package.json +137 -137
- package/src/build/ensure-build.mjs +19 -19
- package/src/build/paths.mjs +153 -153
- package/src/build/resolve-peer.mjs +36 -36
- package/src/build/tasks/client.mjs +349 -349
- package/src/build/tasks/css.mjs +235 -235
- package/src/build/tasks/fonts.mjs +146 -146
- package/src/build/tasks/icons.mjs +357 -357
- package/src/build/tasks/images.mjs +244 -244
- package/src/build/tasks/precompress.mjs +78 -78
- package/src/build/tasks/templates.mjs +20 -20
- package/src/client/admin/i18n.js +764 -764
- package/src/client/admin/login.html +74 -74
- package/src/client/admin/panel.css +809 -809
- package/src/client/admin/panel.html +495 -495
- package/src/client/admin/panel.js +1251 -1251
- package/src/client/devtools/report.html +185 -185
- package/src/client/devtools/report.js +745 -745
- package/src/client/devtools/seo.js +628 -628
- package/src/client/dom.js +95 -95
- package/src/client/form.js +192 -192
- package/src/client/index.js +45 -45
- package/src/client/registry.js +305 -305
- package/src/client/safe-image.js +91 -91
- package/src/client/shared-cookie.js +225 -225
- package/src/client/store.js +36 -36
- package/src/client/swap.js +188 -188
- package/src/compile/codegen.js +336 -336
- package/src/compile/compile-all.js +149 -149
- package/src/compile/errors.js +66 -66
- package/src/compile/expr.js +409 -409
- package/src/compile/index.js +17 -17
- package/src/compile/parse.js +541 -541
- package/src/compile/resolve.js +211 -211
- package/src/compile/scan-exports.js +51 -51
- package/src/config/defaults.js +541 -534
- package/src/config/index.js +1500 -1469
- package/src/config/pattern.js +107 -107
- package/src/generate.mjs +163 -163
- package/src/http/control-flow.js +71 -71
- package/src/http/cookies-entry.js +21 -21
- package/src/http/cookies.js +277 -277
- package/src/http/request-cache.js +46 -46
- package/src/http/request-context.js +165 -165
- package/src/http/shared-cookie.js +178 -178
- package/src/index.js +101 -101
- package/src/init.mjs +232 -230
- package/src/migrate/apply.mjs +262 -262
- package/src/migrate/babel.mjs +79 -79
- package/src/migrate/classify.mjs +155 -155
- package/src/migrate/config.mjs +126 -126
- package/src/migrate/fs-walk.mjs +191 -191
- package/src/migrate/parse.mjs +26 -26
- package/src/migrate/scan.mjs +177 -177
- package/src/migrate/transform/expr-source.mjs +168 -168
- package/src/migrate/transform/island.mjs +67 -67
- package/src/migrate/transform/jsx-to-component.mjs +302 -302
- package/src/migrate/transform/jsx-to-jsk.mjs +330 -330
- package/src/migrate/transform/page-split.mjs +435 -435
- package/src/migrate/write.mjs +81 -81
- package/src/migrate.mjs +171 -171
- package/src/runtime/alias-hooks.mjs +119 -119
- package/src/runtime/register.mjs +4 -4
- package/src/server/admin/actions.js +229 -229
- package/src/server/admin/auth.js +125 -125
- package/src/server/admin/event-log.js +151 -151
- package/src/server/admin/gate.js +209 -209
- package/src/server/admin/inventory.js +188 -188
- package/src/server/admin/mount.js +56 -56
- package/src/server/admin/router.js +216 -216
- package/src/server/admin/snapshot.js +241 -241
- package/src/server/assets.js +147 -147
- package/src/server/auth/handoff.js +309 -309
- package/src/server/cache-blob.js +70 -70
- package/src/server/cache-control.js +45 -0
- package/src/server/cache-deps.js +42 -42
- package/src/server/cache-vary.js +113 -113
- package/src/server/cloudflare.js +607 -607
- package/src/server/create-app.js +366 -366
- package/src/server/data-cache.js +553 -553
- package/src/server/dev/report.js +485 -485
- package/src/server/dev/socket.js +170 -170
- package/src/server/dev/version-check.mjs +139 -139
- package/src/server/disk-cache.js +233 -233
- package/src/server/ejs-adapter.js +59 -59
- package/src/server/html-cache.js +1196 -1196
- package/src/server/image-optimizer.js +500 -500
- package/src/server/logs/access-middleware.js +66 -66
- package/src/server/logs/file-sink.js +193 -193
- package/src/server/logs/pipeline.js +165 -165
- package/src/server/logs/s3-put.js +214 -214
- package/src/server/logs/s3-sink.js +112 -112
- package/src/server/metadata.js +102 -102
- package/src/server/middleware/compression.js +205 -205
- package/src/server/middleware/csrf.js +134 -134
- package/src/server/middleware/dev-gate.js +75 -75
- package/src/server/middleware/headers.js +37 -37
- package/src/server/middleware/redirects.js +32 -32
- package/src/server/middleware/robots-txt.js +341 -341
- package/src/server/middleware/static-precompressed.js +121 -121
- package/src/server/middleware/trailing-slash.js +53 -53
- package/src/server/middleware/upstream-proxy.js +141 -141
- package/src/server/og-image.js +369 -356
- package/src/server/port-guard.js +255 -255
- package/src/server/prewarm.js +1082 -1082
- package/src/server/redis.js +588 -588
- package/src/server/render.js +910 -910
- package/src/server/router.js +157 -157
- package/src/server/status-page.js +265 -265
- package/src/server/upstream-limiter.js +376 -376
- package/src/server/upstream-tracking.js +166 -166
- package/src/shared/cookie-domain.js +66 -66
- package/src/start.mjs +22 -22
- package/src/templates/layout.ejs +30 -30
- package/src/templates/layout.jsk +30 -30
- package/src/version.mjs +31 -31
- package/src/views/components/loader.js +101 -101
- package/src/views/helpers/html.js +102 -102
- package/src/views/helpers/tags.js +375 -375
- package/types/config/defaults.d.ts +6 -0
- package/types/config/index.d.ts +6 -0
- package/types/server/cache-control.d.ts +28 -0
- package/types/server/og-image.d.ts +5 -0
package/src/migrate/write.mjs
CHANGED
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dry-run / no-overwrite yazıcı.
|
|
3
|
-
*/
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import process from "node:process";
|
|
7
|
-
import * as log from "../log.mjs";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @typedef {{ path: string, contents: string, action: 'create' | 'skip' | 'conflict' }} WritePlan
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @param {string} absPath
|
|
15
|
-
* @param {string} contents
|
|
16
|
-
* @param {{ write?: boolean, cwd?: string }} options
|
|
17
|
-
* @returns {WritePlan}
|
|
18
|
-
*/
|
|
19
|
-
export function planWrite(absPath, contents, options = {}) {
|
|
20
|
-
const cwd = options.cwd ?? process.cwd();
|
|
21
|
-
const rel = path.relative(cwd, absPath).replace(/\\/g, "/");
|
|
22
|
-
if (fs.existsSync(absPath)) {
|
|
23
|
-
return { path: rel, contents, action: "conflict" };
|
|
24
|
-
}
|
|
25
|
-
return { path: rel, contents, action: options.write ? "create" : "create" };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @param {WritePlan[]} plans
|
|
30
|
-
* @param {{ write?: boolean, cwd?: string }} options
|
|
31
|
-
* @returns {WritePlan[]}
|
|
32
|
-
*/
|
|
33
|
-
export function commitWrites(plans, options = {}) {
|
|
34
|
-
const cwd = options.cwd ?? process.cwd();
|
|
35
|
-
/** @type {WritePlan[]} */
|
|
36
|
-
const out = [];
|
|
37
|
-
for (const plan of plans) {
|
|
38
|
-
const abs = path.isAbsolute(plan.path) ? plan.path : path.join(cwd, plan.path);
|
|
39
|
-
if (fs.existsSync(abs)) {
|
|
40
|
-
const conflict = {
|
|
41
|
-
path: path.relative(cwd, abs).replace(/\\/g, "/"),
|
|
42
|
-
contents: plan.contents,
|
|
43
|
-
action: /** @type {const} */ ("conflict"),
|
|
44
|
-
};
|
|
45
|
-
// .migrate soneki dene
|
|
46
|
-
const alt = abs.replace(/(\.\w+)?$/, (m) => `.migrate${m || ""}`);
|
|
47
|
-
if (!fs.existsSync(alt) && options.write) {
|
|
48
|
-
fs.mkdirSync(path.dirname(alt), { recursive: true });
|
|
49
|
-
fs.writeFileSync(alt, plan.contents, "utf8");
|
|
50
|
-
log.line(`create ${path.relative(cwd, alt).replace(/\\/g, "/")} (conflict → .migrate)`);
|
|
51
|
-
out.push({
|
|
52
|
-
path: path.relative(cwd, alt).replace(/\\/g, "/"),
|
|
53
|
-
contents: plan.contents,
|
|
54
|
-
action: "create",
|
|
55
|
-
});
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
log.line(`skip ${conflict.path} (exists)`);
|
|
59
|
-
out.push(conflict);
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
if (options.write) {
|
|
63
|
-
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
64
|
-
fs.writeFileSync(abs, plan.contents, "utf8");
|
|
65
|
-
log.line(`create ${path.relative(cwd, abs).replace(/\\/g, "/")}`);
|
|
66
|
-
out.push({
|
|
67
|
-
path: path.relative(cwd, abs).replace(/\\/g, "/"),
|
|
68
|
-
contents: plan.contents,
|
|
69
|
-
action: "create",
|
|
70
|
-
});
|
|
71
|
-
} else {
|
|
72
|
-
log.line(`would create ${path.relative(cwd, abs).replace(/\\/g, "/")}`);
|
|
73
|
-
out.push({
|
|
74
|
-
path: path.relative(cwd, abs).replace(/\\/g, "/"),
|
|
75
|
-
contents: plan.contents,
|
|
76
|
-
action: "create",
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return out;
|
|
81
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Dry-run / no-overwrite yazıcı.
|
|
3
|
+
*/
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
import * as log from "../log.mjs";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {{ path: string, contents: string, action: 'create' | 'skip' | 'conflict' }} WritePlan
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} absPath
|
|
15
|
+
* @param {string} contents
|
|
16
|
+
* @param {{ write?: boolean, cwd?: string }} options
|
|
17
|
+
* @returns {WritePlan}
|
|
18
|
+
*/
|
|
19
|
+
export function planWrite(absPath, contents, options = {}) {
|
|
20
|
+
const cwd = options.cwd ?? process.cwd();
|
|
21
|
+
const rel = path.relative(cwd, absPath).replace(/\\/g, "/");
|
|
22
|
+
if (fs.existsSync(absPath)) {
|
|
23
|
+
return { path: rel, contents, action: "conflict" };
|
|
24
|
+
}
|
|
25
|
+
return { path: rel, contents, action: options.write ? "create" : "create" };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {WritePlan[]} plans
|
|
30
|
+
* @param {{ write?: boolean, cwd?: string }} options
|
|
31
|
+
* @returns {WritePlan[]}
|
|
32
|
+
*/
|
|
33
|
+
export function commitWrites(plans, options = {}) {
|
|
34
|
+
const cwd = options.cwd ?? process.cwd();
|
|
35
|
+
/** @type {WritePlan[]} */
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const plan of plans) {
|
|
38
|
+
const abs = path.isAbsolute(plan.path) ? plan.path : path.join(cwd, plan.path);
|
|
39
|
+
if (fs.existsSync(abs)) {
|
|
40
|
+
const conflict = {
|
|
41
|
+
path: path.relative(cwd, abs).replace(/\\/g, "/"),
|
|
42
|
+
contents: plan.contents,
|
|
43
|
+
action: /** @type {const} */ ("conflict"),
|
|
44
|
+
};
|
|
45
|
+
// .migrate soneki dene
|
|
46
|
+
const alt = abs.replace(/(\.\w+)?$/, (m) => `.migrate${m || ""}`);
|
|
47
|
+
if (!fs.existsSync(alt) && options.write) {
|
|
48
|
+
fs.mkdirSync(path.dirname(alt), { recursive: true });
|
|
49
|
+
fs.writeFileSync(alt, plan.contents, "utf8");
|
|
50
|
+
log.line(`create ${path.relative(cwd, alt).replace(/\\/g, "/")} (conflict → .migrate)`);
|
|
51
|
+
out.push({
|
|
52
|
+
path: path.relative(cwd, alt).replace(/\\/g, "/"),
|
|
53
|
+
contents: plan.contents,
|
|
54
|
+
action: "create",
|
|
55
|
+
});
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
log.line(`skip ${conflict.path} (exists)`);
|
|
59
|
+
out.push(conflict);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (options.write) {
|
|
63
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
64
|
+
fs.writeFileSync(abs, plan.contents, "utf8");
|
|
65
|
+
log.line(`create ${path.relative(cwd, abs).replace(/\\/g, "/")}`);
|
|
66
|
+
out.push({
|
|
67
|
+
path: path.relative(cwd, abs).replace(/\\/g, "/"),
|
|
68
|
+
contents: plan.contents,
|
|
69
|
+
action: "create",
|
|
70
|
+
});
|
|
71
|
+
} else {
|
|
72
|
+
log.line(`would create ${path.relative(cwd, abs).replace(/\\/g, "/")}`);
|
|
73
|
+
out.push({
|
|
74
|
+
path: path.relative(cwd, abs).replace(/\\/g, "/"),
|
|
75
|
+
contents: plan.contents,
|
|
76
|
+
action: "create",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
package/src/migrate.mjs
CHANGED
|
@@ -1,171 +1,171 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `jskelet migrate` — Next.js App Router → JSkelet codemod.
|
|
3
|
-
*
|
|
4
|
-
* jskelet migrate scan + apply --dry-run özeti
|
|
5
|
-
* jskelet migrate scan [dir]
|
|
6
|
-
* jskelet migrate apply [dir] [--out .] [--write] [--only pages|components|islands] [--strict] [--json]
|
|
7
|
-
* jskelet migrate config [dir] [--out .] [--write] [--json]
|
|
8
|
-
*/
|
|
9
|
-
import fs from "node:fs";
|
|
10
|
-
import path from "node:path";
|
|
11
|
-
import process from "node:process";
|
|
12
|
-
import * as log from "./log.mjs";
|
|
13
|
-
import { scanProject, formatScanReport } from "./migrate/scan.mjs";
|
|
14
|
-
import { draftConfig } from "./migrate/config.mjs";
|
|
15
|
-
import { applyMigrate, formatApplyReport } from "./migrate/apply.mjs";
|
|
16
|
-
import { commitWrites } from "./migrate/write.mjs";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @param {string} cwd
|
|
20
|
-
* @param {string[]} args
|
|
21
|
-
* @returns {Promise<void>}
|
|
22
|
-
*/
|
|
23
|
-
export async function migrate(cwd, args) {
|
|
24
|
-
const { command, positionals, flags } = parseArgs(args);
|
|
25
|
-
|
|
26
|
-
if (command === "help" || flags.help) {
|
|
27
|
-
printUsage();
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const sourceRoot = path.resolve(cwd, positionals[0] ?? ".");
|
|
32
|
-
const outRoot = path.resolve(cwd, flags.out ?? (command === "apply" || command === "config" ? "." : sourceRoot));
|
|
33
|
-
|
|
34
|
-
if (command === "scan" || command === "default") {
|
|
35
|
-
const report = scanProject(sourceRoot);
|
|
36
|
-
if (flags.json) {
|
|
37
|
-
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
38
|
-
} else {
|
|
39
|
-
process.stdout.write(formatScanReport(report) + "\n");
|
|
40
|
-
}
|
|
41
|
-
if (command === "default") {
|
|
42
|
-
process.stdout.write("\n--- apply (dry-run) ---\n");
|
|
43
|
-
const { reports } = await applyMigrate(sourceRoot, outRoot, {
|
|
44
|
-
write: false,
|
|
45
|
-
only: flags.only,
|
|
46
|
-
});
|
|
47
|
-
if (flags.json) {
|
|
48
|
-
process.stdout.write(JSON.stringify({ apply: reports }, null, 2) + "\n");
|
|
49
|
-
} else {
|
|
50
|
-
process.stdout.write(formatApplyReport(reports) + "\n");
|
|
51
|
-
}
|
|
52
|
-
exitStrict(reports, flags.strict);
|
|
53
|
-
}
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (command === "config") {
|
|
58
|
-
const draft = await draftConfig(sourceRoot);
|
|
59
|
-
if (flags.json) {
|
|
60
|
-
process.stdout.write(JSON.stringify(draft, null, 2) + "\n");
|
|
61
|
-
} else {
|
|
62
|
-
for (const n of draft.notes) log.warn(n);
|
|
63
|
-
if (!flags.write) {
|
|
64
|
-
process.stdout.write(draft.code ?? "");
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
if (draft.code) {
|
|
68
|
-
const dest = path.join(outRoot, "jskelet.config.mjs");
|
|
69
|
-
commitWrites([{ path: dest, contents: draft.code, action: "create" }], {
|
|
70
|
-
write: Boolean(flags.write),
|
|
71
|
-
cwd: outRoot,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
if (flags.strict && draft.status !== "ok") process.exitCode = 1;
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (command === "apply") {
|
|
79
|
-
if (!fs.existsSync(sourceRoot)) {
|
|
80
|
-
throw new Error(`source not found: ${sourceRoot}`);
|
|
81
|
-
}
|
|
82
|
-
const { reports } = await applyMigrate(sourceRoot, outRoot, {
|
|
83
|
-
write: Boolean(flags.write),
|
|
84
|
-
only: flags.only,
|
|
85
|
-
strict: flags.strict,
|
|
86
|
-
});
|
|
87
|
-
if (flags.json) {
|
|
88
|
-
process.stdout.write(JSON.stringify({ reports }, null, 2) + "\n");
|
|
89
|
-
} else {
|
|
90
|
-
process.stdout.write(formatApplyReport(reports) + "\n");
|
|
91
|
-
if (!flags.write) {
|
|
92
|
-
log.line("dry-run only — pass --write to create files (never overwrites; conflicts get .migrate suffix)");
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
exitStrict(reports, flags.strict);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
throw new Error(`unknown migrate command: ${command}\n\n${usageText()}`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* @param {string[]} args
|
|
104
|
-
*/
|
|
105
|
-
function parseArgs(args) {
|
|
106
|
-
/** @type {string[]} */
|
|
107
|
-
const positionals = [];
|
|
108
|
-
/** @type {{ write?: boolean, json?: boolean, strict?: boolean, help?: boolean, out?: string, only?: Set<string> }} */
|
|
109
|
-
const flags = {};
|
|
110
|
-
let command = "default";
|
|
111
|
-
let i = 0;
|
|
112
|
-
if (args[0] && !args[0].startsWith("-")) {
|
|
113
|
-
if (["scan", "apply", "config", "help"].includes(args[0])) {
|
|
114
|
-
command = args[0];
|
|
115
|
-
i = 1;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
for (; i < args.length; i++) {
|
|
119
|
-
const a = args[i];
|
|
120
|
-
if (a === "--write") flags.write = true;
|
|
121
|
-
else if (a === "--dry-run") flags.write = false;
|
|
122
|
-
else if (a === "--json") flags.json = true;
|
|
123
|
-
else if (a === "--strict") flags.strict = true;
|
|
124
|
-
else if (a === "--help" || a === "-h") flags.help = true;
|
|
125
|
-
else if (a === "--out") {
|
|
126
|
-
flags.out = args[++i];
|
|
127
|
-
} else if (a.startsWith("--out=")) {
|
|
128
|
-
flags.out = a.slice(6);
|
|
129
|
-
} else if (a === "--only") {
|
|
130
|
-
const raw = args[++i] ?? "";
|
|
131
|
-
flags.only = new Set(raw.split(",").map((s) => s.trim()).filter(Boolean));
|
|
132
|
-
} else if (a.startsWith("--only=")) {
|
|
133
|
-
flags.only = new Set(a.slice(7).split(",").map((s) => s.trim()).filter(Boolean));
|
|
134
|
-
} else if (a.startsWith("-")) {
|
|
135
|
-
throw new Error(`unknown flag: ${a}`);
|
|
136
|
-
} else {
|
|
137
|
-
positionals.push(a);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return { command, positionals, flags };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* @param {{ status: string }[]} reports
|
|
145
|
-
* @param {boolean} [strict]
|
|
146
|
-
*/
|
|
147
|
-
function exitStrict(reports, strict) {
|
|
148
|
-
if (!strict) return;
|
|
149
|
-
if (reports.some((r) => r.status !== "ok")) process.exitCode = 1;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function printUsage() {
|
|
153
|
-
process.stdout.write(usageText() + "\n");
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function usageText() {
|
|
157
|
-
return (
|
|
158
|
-
"usage: jskelet migrate [scan|apply|config] [dir] [options]\n\n" +
|
|
159
|
-
" scan Inventory App Router pages, layouts, blockers\n" +
|
|
160
|
-
" apply Codemod: JSX pages → controller + .jsk, components, islands\n" +
|
|
161
|
-
" config Draft jskelet.config.mjs from next.config\n\n" +
|
|
162
|
-
"Options:\n" +
|
|
163
|
-
" --out <dir> Output root (default: cwd)\n" +
|
|
164
|
-
" --write Write files (default: dry-run)\n" +
|
|
165
|
-
" --only <list> pages,components,islands (comma-separated)\n" +
|
|
166
|
-
" --json Machine-readable report\n" +
|
|
167
|
-
" --strict Exit 1 if any partial/skipped\n\n" +
|
|
168
|
-
"Requires optional peers (install in the project you migrate):\n" +
|
|
169
|
-
" npm i -D @babel/parser @babel/types\n"
|
|
170
|
-
);
|
|
171
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* `jskelet migrate` — Next.js App Router → JSkelet codemod.
|
|
3
|
+
*
|
|
4
|
+
* jskelet migrate scan + apply --dry-run özeti
|
|
5
|
+
* jskelet migrate scan [dir]
|
|
6
|
+
* jskelet migrate apply [dir] [--out .] [--write] [--only pages|components|islands] [--strict] [--json]
|
|
7
|
+
* jskelet migrate config [dir] [--out .] [--write] [--json]
|
|
8
|
+
*/
|
|
9
|
+
import fs from "node:fs";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import process from "node:process";
|
|
12
|
+
import * as log from "./log.mjs";
|
|
13
|
+
import { scanProject, formatScanReport } from "./migrate/scan.mjs";
|
|
14
|
+
import { draftConfig } from "./migrate/config.mjs";
|
|
15
|
+
import { applyMigrate, formatApplyReport } from "./migrate/apply.mjs";
|
|
16
|
+
import { commitWrites } from "./migrate/write.mjs";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} cwd
|
|
20
|
+
* @param {string[]} args
|
|
21
|
+
* @returns {Promise<void>}
|
|
22
|
+
*/
|
|
23
|
+
export async function migrate(cwd, args) {
|
|
24
|
+
const { command, positionals, flags } = parseArgs(args);
|
|
25
|
+
|
|
26
|
+
if (command === "help" || flags.help) {
|
|
27
|
+
printUsage();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const sourceRoot = path.resolve(cwd, positionals[0] ?? ".");
|
|
32
|
+
const outRoot = path.resolve(cwd, flags.out ?? (command === "apply" || command === "config" ? "." : sourceRoot));
|
|
33
|
+
|
|
34
|
+
if (command === "scan" || command === "default") {
|
|
35
|
+
const report = scanProject(sourceRoot);
|
|
36
|
+
if (flags.json) {
|
|
37
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
38
|
+
} else {
|
|
39
|
+
process.stdout.write(formatScanReport(report) + "\n");
|
|
40
|
+
}
|
|
41
|
+
if (command === "default") {
|
|
42
|
+
process.stdout.write("\n--- apply (dry-run) ---\n");
|
|
43
|
+
const { reports } = await applyMigrate(sourceRoot, outRoot, {
|
|
44
|
+
write: false,
|
|
45
|
+
only: flags.only,
|
|
46
|
+
});
|
|
47
|
+
if (flags.json) {
|
|
48
|
+
process.stdout.write(JSON.stringify({ apply: reports }, null, 2) + "\n");
|
|
49
|
+
} else {
|
|
50
|
+
process.stdout.write(formatApplyReport(reports) + "\n");
|
|
51
|
+
}
|
|
52
|
+
exitStrict(reports, flags.strict);
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (command === "config") {
|
|
58
|
+
const draft = await draftConfig(sourceRoot);
|
|
59
|
+
if (flags.json) {
|
|
60
|
+
process.stdout.write(JSON.stringify(draft, null, 2) + "\n");
|
|
61
|
+
} else {
|
|
62
|
+
for (const n of draft.notes) log.warn(n);
|
|
63
|
+
if (!flags.write) {
|
|
64
|
+
process.stdout.write(draft.code ?? "");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (draft.code) {
|
|
68
|
+
const dest = path.join(outRoot, "jskelet.config.mjs");
|
|
69
|
+
commitWrites([{ path: dest, contents: draft.code, action: "create" }], {
|
|
70
|
+
write: Boolean(flags.write),
|
|
71
|
+
cwd: outRoot,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (flags.strict && draft.status !== "ok") process.exitCode = 1;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (command === "apply") {
|
|
79
|
+
if (!fs.existsSync(sourceRoot)) {
|
|
80
|
+
throw new Error(`source not found: ${sourceRoot}`);
|
|
81
|
+
}
|
|
82
|
+
const { reports } = await applyMigrate(sourceRoot, outRoot, {
|
|
83
|
+
write: Boolean(flags.write),
|
|
84
|
+
only: flags.only,
|
|
85
|
+
strict: flags.strict,
|
|
86
|
+
});
|
|
87
|
+
if (flags.json) {
|
|
88
|
+
process.stdout.write(JSON.stringify({ reports }, null, 2) + "\n");
|
|
89
|
+
} else {
|
|
90
|
+
process.stdout.write(formatApplyReport(reports) + "\n");
|
|
91
|
+
if (!flags.write) {
|
|
92
|
+
log.line("dry-run only — pass --write to create files (never overwrites; conflicts get .migrate suffix)");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exitStrict(reports, flags.strict);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
throw new Error(`unknown migrate command: ${command}\n\n${usageText()}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {string[]} args
|
|
104
|
+
*/
|
|
105
|
+
function parseArgs(args) {
|
|
106
|
+
/** @type {string[]} */
|
|
107
|
+
const positionals = [];
|
|
108
|
+
/** @type {{ write?: boolean, json?: boolean, strict?: boolean, help?: boolean, out?: string, only?: Set<string> }} */
|
|
109
|
+
const flags = {};
|
|
110
|
+
let command = "default";
|
|
111
|
+
let i = 0;
|
|
112
|
+
if (args[0] && !args[0].startsWith("-")) {
|
|
113
|
+
if (["scan", "apply", "config", "help"].includes(args[0])) {
|
|
114
|
+
command = args[0];
|
|
115
|
+
i = 1;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (; i < args.length; i++) {
|
|
119
|
+
const a = args[i];
|
|
120
|
+
if (a === "--write") flags.write = true;
|
|
121
|
+
else if (a === "--dry-run") flags.write = false;
|
|
122
|
+
else if (a === "--json") flags.json = true;
|
|
123
|
+
else if (a === "--strict") flags.strict = true;
|
|
124
|
+
else if (a === "--help" || a === "-h") flags.help = true;
|
|
125
|
+
else if (a === "--out") {
|
|
126
|
+
flags.out = args[++i];
|
|
127
|
+
} else if (a.startsWith("--out=")) {
|
|
128
|
+
flags.out = a.slice(6);
|
|
129
|
+
} else if (a === "--only") {
|
|
130
|
+
const raw = args[++i] ?? "";
|
|
131
|
+
flags.only = new Set(raw.split(",").map((s) => s.trim()).filter(Boolean));
|
|
132
|
+
} else if (a.startsWith("--only=")) {
|
|
133
|
+
flags.only = new Set(a.slice(7).split(",").map((s) => s.trim()).filter(Boolean));
|
|
134
|
+
} else if (a.startsWith("-")) {
|
|
135
|
+
throw new Error(`unknown flag: ${a}`);
|
|
136
|
+
} else {
|
|
137
|
+
positionals.push(a);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { command, positionals, flags };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {{ status: string }[]} reports
|
|
145
|
+
* @param {boolean} [strict]
|
|
146
|
+
*/
|
|
147
|
+
function exitStrict(reports, strict) {
|
|
148
|
+
if (!strict) return;
|
|
149
|
+
if (reports.some((r) => r.status !== "ok")) process.exitCode = 1;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function printUsage() {
|
|
153
|
+
process.stdout.write(usageText() + "\n");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function usageText() {
|
|
157
|
+
return (
|
|
158
|
+
"usage: jskelet migrate [scan|apply|config] [dir] [options]\n\n" +
|
|
159
|
+
" scan Inventory App Router pages, layouts, blockers\n" +
|
|
160
|
+
" apply Codemod: JSX pages → controller + .jsk, components, islands\n" +
|
|
161
|
+
" config Draft jskelet.config.mjs from next.config\n\n" +
|
|
162
|
+
"Options:\n" +
|
|
163
|
+
" --out <dir> Output root (default: cwd)\n" +
|
|
164
|
+
" --write Write files (default: dry-run)\n" +
|
|
165
|
+
" --only <list> pages,components,islands (comma-separated)\n" +
|
|
166
|
+
" --json Machine-readable report\n" +
|
|
167
|
+
" --strict Exit 1 if any partial/skipped\n\n" +
|
|
168
|
+
"Requires optional peers (install in the project you migrate):\n" +
|
|
169
|
+
" npm i -D @babel/parser @babel/types\n"
|
|
170
|
+
);
|
|
171
|
+
}
|