@drzl/cli 4.38.0 → 4.40.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/dist/cli.cjs +177 -43
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +170 -36
- package/dist/cli.js.map +1 -1
- package/dist/config.d.cts +2 -2
- package/dist/config.d.ts +2 -2
- package/package.json +7 -7
package/dist/cli.cjs
CHANGED
|
@@ -28,7 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var import_analyzer3 = require("@drzl/analyzer");
|
|
29
29
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
30
30
|
var import_commander = require("commander");
|
|
31
|
-
var
|
|
31
|
+
var path9 = __toESM(require("path"), 1);
|
|
32
32
|
|
|
33
33
|
// src/output.ts
|
|
34
34
|
var import_chalk = require("chalk");
|
|
@@ -2512,11 +2512,11 @@ function authTableWarnings(analysis) {
|
|
|
2512
2512
|
var import_chalk2 = require("chalk");
|
|
2513
2513
|
var PLAIN = new import_chalk2.Chalk({ level: 0 });
|
|
2514
2514
|
var HANDLED_CODES = /* @__PURE__ */ new Set(["DRZL_ANL_UNKNOWN_COLUMN"]);
|
|
2515
|
-
function splitPath(
|
|
2516
|
-
if (!
|
|
2517
|
-
const dot =
|
|
2518
|
-
if (dot <= 0) return { table:
|
|
2519
|
-
return { table:
|
|
2515
|
+
function splitPath(path10) {
|
|
2516
|
+
if (!path10) return {};
|
|
2517
|
+
const dot = path10.lastIndexOf(".");
|
|
2518
|
+
if (dot <= 0) return { table: path10 };
|
|
2519
|
+
return { table: path10.slice(0, dot), column: path10.slice(dot + 1) };
|
|
2520
2520
|
}
|
|
2521
2521
|
function namedColumns(parsed) {
|
|
2522
2522
|
const out = [];
|
|
@@ -3068,11 +3068,11 @@ function issueTouches(issue, table) {
|
|
|
3068
3068
|
return dot > 0 && own.includes(issue.path.slice(0, dot));
|
|
3069
3069
|
}
|
|
3070
3070
|
function issueColumn(issue, table) {
|
|
3071
|
-
const
|
|
3071
|
+
const path10 = issue.path ?? "";
|
|
3072
3072
|
const names = namesOf(table);
|
|
3073
3073
|
for (const prefix of [names.qualified, names.tsName, names.name, table.name]) {
|
|
3074
|
-
if (
|
|
3075
|
-
const rest =
|
|
3074
|
+
if (path10.startsWith(`${prefix}.`)) {
|
|
3075
|
+
const rest = path10.slice(prefix.length + 1);
|
|
3076
3076
|
if (table.columns.some((c) => c.name === rest)) return rest;
|
|
3077
3077
|
}
|
|
3078
3078
|
}
|
|
@@ -4231,6 +4231,107 @@ function displayPath(file, cwd = process.cwd()) {
|
|
|
4231
4231
|
return rel && !rel.startsWith("..") ? rel : file;
|
|
4232
4232
|
}
|
|
4233
4233
|
|
|
4234
|
+
// src/manifest.ts
|
|
4235
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
4236
|
+
var import_node_fs3 = require("fs");
|
|
4237
|
+
var MANIFEST_VERSION = 1;
|
|
4238
|
+
var MANIFEST_PATH = import_node_path3.default.join(".drzl", "manifest.json");
|
|
4239
|
+
function toPosix(p) {
|
|
4240
|
+
return p.split(import_node_path3.default.sep).join("/");
|
|
4241
|
+
}
|
|
4242
|
+
function manifestEntries(files, root) {
|
|
4243
|
+
const rel = files.map((f) => toPosix(import_node_path3.default.relative(root, f)));
|
|
4244
|
+
return [...new Set(rel)].sort();
|
|
4245
|
+
}
|
|
4246
|
+
async function readManifest(root) {
|
|
4247
|
+
try {
|
|
4248
|
+
const raw = await import_node_fs3.promises.readFile(import_node_path3.default.join(root, MANIFEST_PATH), "utf8");
|
|
4249
|
+
const parsed = JSON.parse(raw);
|
|
4250
|
+
if (!parsed || typeof parsed !== "object" || parsed.version !== MANIFEST_VERSION || !Array.isArray(parsed.files) || !parsed.files.every((f) => typeof f === "string")) {
|
|
4251
|
+
return void 0;
|
|
4252
|
+
}
|
|
4253
|
+
return { version: MANIFEST_VERSION, files: parsed.files };
|
|
4254
|
+
} catch {
|
|
4255
|
+
return void 0;
|
|
4256
|
+
}
|
|
4257
|
+
}
|
|
4258
|
+
async function writeManifest(root, files) {
|
|
4259
|
+
const manifest = { version: MANIFEST_VERSION, files: manifestEntries(files, root) };
|
|
4260
|
+
const target = import_node_path3.default.join(root, MANIFEST_PATH);
|
|
4261
|
+
await import_node_fs3.promises.mkdir(import_node_path3.default.dirname(target), { recursive: true });
|
|
4262
|
+
await import_node_fs3.promises.writeFile(target, `${JSON.stringify(manifest, null, 2)}
|
|
4263
|
+
`, "utf8");
|
|
4264
|
+
}
|
|
4265
|
+
async function staleFiles(previous, writtenNow, root) {
|
|
4266
|
+
if (!previous) return [];
|
|
4267
|
+
const current = new Set(manifestEntries(writtenNow, root));
|
|
4268
|
+
const gone = previous.files.filter((f) => !current.has(f));
|
|
4269
|
+
const out = [];
|
|
4270
|
+
for (const file of gone) {
|
|
4271
|
+
let present = true;
|
|
4272
|
+
try {
|
|
4273
|
+
await import_node_fs3.promises.access(import_node_path3.default.join(root, file));
|
|
4274
|
+
} catch {
|
|
4275
|
+
present = false;
|
|
4276
|
+
}
|
|
4277
|
+
out.push({ file, present });
|
|
4278
|
+
}
|
|
4279
|
+
return out;
|
|
4280
|
+
}
|
|
4281
|
+
async function pruneStale(root, stale) {
|
|
4282
|
+
const deleted = [];
|
|
4283
|
+
for (const entry of stale) {
|
|
4284
|
+
if (!entry.present) continue;
|
|
4285
|
+
const target = import_node_path3.default.resolve(root, entry.file);
|
|
4286
|
+
const inside = target === root || target.startsWith(root + import_node_path3.default.sep);
|
|
4287
|
+
if (!inside) continue;
|
|
4288
|
+
try {
|
|
4289
|
+
await import_node_fs3.promises.rm(target);
|
|
4290
|
+
deleted.push(entry.file);
|
|
4291
|
+
} catch {
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
return deleted;
|
|
4295
|
+
}
|
|
4296
|
+
function staleWarning(stale) {
|
|
4297
|
+
const present = stale.filter((s) => s.present);
|
|
4298
|
+
if (!present.length) return void 0;
|
|
4299
|
+
const list = present.map((s) => s.file).join(", ");
|
|
4300
|
+
return `drzl generate: ${present.length} file(s) written by a previous run were not written by this one, and are still on disk: ${list}. That usually means a table was renamed or removed. Delete them with \`drzl generate --prune\`, which removes only files a previous run recorded writing.`;
|
|
4301
|
+
}
|
|
4302
|
+
function nextManifestFiles(writtenNow, stale, root) {
|
|
4303
|
+
const kept = stale.filter((s) => s.present).map((s) => import_node_path3.default.resolve(root, s.file));
|
|
4304
|
+
return manifestEntries([...writtenNow, ...kept], root);
|
|
4305
|
+
}
|
|
4306
|
+
|
|
4307
|
+
// src/rebuild-fingerprint.ts
|
|
4308
|
+
var import_node_crypto = require("crypto");
|
|
4309
|
+
function analysisFingerprint(analysis) {
|
|
4310
|
+
const material = {
|
|
4311
|
+
dialect: analysis.dialect,
|
|
4312
|
+
tables: analysis.tables,
|
|
4313
|
+
enums: analysis.enums,
|
|
4314
|
+
relations: analysis.relations
|
|
4315
|
+
};
|
|
4316
|
+
return (0, import_node_crypto.createHash)("sha256").update(stableStringify(material)).digest("hex");
|
|
4317
|
+
}
|
|
4318
|
+
function configFingerprint(generators) {
|
|
4319
|
+
return (0, import_node_crypto.createHash)("sha256").update(stableStringify(generators)).digest("hex");
|
|
4320
|
+
}
|
|
4321
|
+
function stableStringify(value) {
|
|
4322
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
|
|
4323
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
4324
|
+
const entries = Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
4325
|
+
return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
|
|
4326
|
+
}
|
|
4327
|
+
function rebuildSignature(analysis, generators) {
|
|
4328
|
+
return { analysis: analysisFingerprint(analysis), config: configFingerprint(generators) };
|
|
4329
|
+
}
|
|
4330
|
+
function sameAsLast(previous, next) {
|
|
4331
|
+
if (!previous) return false;
|
|
4332
|
+
return previous.analysis === next.analysis && previous.config === next.config;
|
|
4333
|
+
}
|
|
4334
|
+
|
|
4234
4335
|
// src/unified-diff.ts
|
|
4235
4336
|
var DEFAULT_DIFF_LIMITS = {
|
|
4236
4337
|
maxLines: 4e3,
|
|
@@ -4473,8 +4574,8 @@ function createRebuildScheduler(options) {
|
|
|
4473
4574
|
|
|
4474
4575
|
// src/init.ts
|
|
4475
4576
|
var import_analyzer2 = require("@drzl/analyzer");
|
|
4476
|
-
var
|
|
4477
|
-
var
|
|
4577
|
+
var fs6 = __toESM(require("fs"), 1);
|
|
4578
|
+
var path6 = __toESM(require("path"), 1);
|
|
4478
4579
|
var INIT_GENERATOR_CHOICES = [
|
|
4479
4580
|
{ kind: "zod", packageName: "@drzl/generator-zod", label: "Zod validators" },
|
|
4480
4581
|
{ kind: "valibot", packageName: "@drzl/generator-valibot", label: "Valibot validators" },
|
|
@@ -4545,7 +4646,7 @@ async function detectSchema(cwd) {
|
|
|
4545
4646
|
kitFiles = null;
|
|
4546
4647
|
}
|
|
4547
4648
|
if (kitFiles && kitPath) {
|
|
4548
|
-
const rel =
|
|
4649
|
+
const rel = path6.relative(cwd, kitPath) || path6.basename(kitPath);
|
|
4549
4650
|
const report = await classifySchemaCandidate(kitFiles);
|
|
4550
4651
|
if (report.verdict === "confirmed" || report.verdict === "unverified") {
|
|
4551
4652
|
notes.push(
|
|
@@ -4561,10 +4662,10 @@ async function detectSchema(cwd) {
|
|
|
4561
4662
|
}
|
|
4562
4663
|
notes.push(`${rel} names schema files that declare no Drizzle tables; looking elsewhere.`);
|
|
4563
4664
|
}
|
|
4564
|
-
const present = schemaCandidates().filter((c) =>
|
|
4665
|
+
const present = schemaCandidates().filter((c) => fs6.existsSync(path6.resolve(cwd, c)));
|
|
4565
4666
|
const unverified = [];
|
|
4566
4667
|
for (const file of present) {
|
|
4567
|
-
const report = await classifySchemaCandidate(
|
|
4668
|
+
const report = await classifySchemaCandidate(path6.resolve(cwd, file));
|
|
4568
4669
|
if (report.verdict === "confirmed") {
|
|
4569
4670
|
notes.push(
|
|
4570
4671
|
`Schema found at ${file} (${report.tables} table${report.tables === 1 ? "" : "s"})`
|
|
@@ -4666,7 +4767,7 @@ async function promptForPlan(args) {
|
|
|
4666
4767
|
if (answer === null) endedEarly = true;
|
|
4667
4768
|
else if (answer.trim()) {
|
|
4668
4769
|
const typed = answer.trim();
|
|
4669
|
-
const report = await classifySchemaCandidate(
|
|
4770
|
+
const report = await classifySchemaCandidate(path6.resolve(cwd, typed));
|
|
4670
4771
|
if (report.verdict === "confirmed") {
|
|
4671
4772
|
write(` ${typed}: ${report.tables} table${report.tables === 1 ? "" : "s"}`);
|
|
4672
4773
|
} else if (report.verdict === "unverified") {
|
|
@@ -4728,8 +4829,8 @@ function parseGeneratorsFlag(value) {
|
|
|
4728
4829
|
return parts;
|
|
4729
4830
|
}
|
|
4730
4831
|
async function runInit(args) {
|
|
4731
|
-
const target =
|
|
4732
|
-
const existing = CONFIG_FILE_NAMES.find((name) =>
|
|
4832
|
+
const target = path6.resolve(args.cwd, "drzl.config.ts");
|
|
4833
|
+
const existing = CONFIG_FILE_NAMES.find((name) => fs6.existsSync(path6.resolve(args.cwd, name)));
|
|
4733
4834
|
if (existing) {
|
|
4734
4835
|
args.error(
|
|
4735
4836
|
`drzl init: ${existing} already exists, so nothing was written. Delete it, or edit it by hand; init never overwrites a config, and will not write one that shadows it either.`
|
|
@@ -4768,8 +4869,8 @@ async function runInit(args) {
|
|
|
4768
4869
|
generators: fromFlag ?? [DEFAULT_GENERATOR_KIND]
|
|
4769
4870
|
};
|
|
4770
4871
|
if (args.schemaFlag) {
|
|
4771
|
-
const full =
|
|
4772
|
-
if (!
|
|
4872
|
+
const full = path6.resolve(args.cwd, args.schemaFlag);
|
|
4873
|
+
if (!fs6.existsSync(full)) {
|
|
4773
4874
|
args.log(`--schema ${args.schemaFlag} is not there yet. Writing it anyway.`);
|
|
4774
4875
|
} else if ((await classifySchemaCandidate(full)).verdict === "rejected") {
|
|
4775
4876
|
args.log(`--schema ${args.schemaFlag} declares no Drizzle tables. Writing it anyway.`);
|
|
@@ -4777,7 +4878,7 @@ async function runInit(args) {
|
|
|
4777
4878
|
}
|
|
4778
4879
|
}
|
|
4779
4880
|
try {
|
|
4780
|
-
|
|
4881
|
+
fs6.writeFileSync(target, renderInitConfig(plan), { flag: "wx" });
|
|
4781
4882
|
} catch (e) {
|
|
4782
4883
|
if (e?.code === "EEXIST") {
|
|
4783
4884
|
args.error(
|
|
@@ -4800,10 +4901,10 @@ async function runInit(args) {
|
|
|
4800
4901
|
}
|
|
4801
4902
|
|
|
4802
4903
|
// src/sponsor.ts
|
|
4803
|
-
var
|
|
4804
|
-
var
|
|
4805
|
-
var CACHE_DIR =
|
|
4806
|
-
var CACHE_FILE =
|
|
4904
|
+
var import_node_fs4 = require("fs");
|
|
4905
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
4906
|
+
var CACHE_DIR = import_node_path4.default.join(process.cwd(), "node_modules", ".cache", "@drzl");
|
|
4907
|
+
var CACHE_FILE = import_node_path4.default.join(CACHE_DIR, "sponsor-message.json");
|
|
4807
4908
|
var DEFAULT_INTERVAL_MS = 1e3 * 60 * 15;
|
|
4808
4909
|
var shownThisProcess = false;
|
|
4809
4910
|
var tips = [
|
|
@@ -4827,7 +4928,7 @@ function maybeShowSponsorMessage({
|
|
|
4827
4928
|
if (hideRequested || process.env.CI && !force || shownThisProcess && !force) return;
|
|
4828
4929
|
if (!out.wantsAsides && !force) return;
|
|
4829
4930
|
try {
|
|
4830
|
-
(0,
|
|
4931
|
+
(0, import_node_fs4.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
4831
4932
|
const payload = readCache();
|
|
4832
4933
|
payload.runs += 1;
|
|
4833
4934
|
const now = Date.now();
|
|
@@ -4855,11 +4956,11 @@ ${green("Pro tip:")} ${tip}
|
|
|
4855
4956
|
}
|
|
4856
4957
|
}
|
|
4857
4958
|
function readCache() {
|
|
4858
|
-
if (!(0,
|
|
4959
|
+
if (!(0, import_node_fs4.existsSync)(CACHE_FILE)) {
|
|
4859
4960
|
return { runs: 0 };
|
|
4860
4961
|
}
|
|
4861
4962
|
try {
|
|
4862
|
-
const data = JSON.parse((0,
|
|
4963
|
+
const data = JSON.parse((0, import_node_fs4.readFileSync)(CACHE_FILE, "utf8"));
|
|
4863
4964
|
if (typeof data.runs !== "number") return { runs: 0 };
|
|
4864
4965
|
return data;
|
|
4865
4966
|
} catch {
|
|
@@ -4867,21 +4968,21 @@ function readCache() {
|
|
|
4867
4968
|
}
|
|
4868
4969
|
}
|
|
4869
4970
|
function writeCache(payload) {
|
|
4870
|
-
(0,
|
|
4971
|
+
(0, import_node_fs4.writeFileSync)(CACHE_FILE, JSON.stringify(payload, null, 2), "utf8");
|
|
4871
4972
|
}
|
|
4872
4973
|
|
|
4873
4974
|
// src/version.ts
|
|
4874
|
-
var
|
|
4875
|
-
var
|
|
4975
|
+
var import_node_fs5 = require("fs");
|
|
4976
|
+
var path8 = __toESM(require("path"), 1);
|
|
4876
4977
|
var import_node_url = require("url");
|
|
4877
4978
|
var PACKAGE_NAME = "@drzl/cli";
|
|
4878
4979
|
function moduleDir() {
|
|
4879
|
-
return
|
|
4980
|
+
return path8.dirname((0, import_node_url.fileURLToPath)(__drzlModuleUrl));
|
|
4880
4981
|
}
|
|
4881
4982
|
function readVersionFrom(manifestPath) {
|
|
4882
4983
|
let raw;
|
|
4883
4984
|
try {
|
|
4884
|
-
raw = (0,
|
|
4985
|
+
raw = (0, import_node_fs5.readFileSync)(manifestPath, "utf8");
|
|
4885
4986
|
} catch (e) {
|
|
4886
4987
|
throw new Error(
|
|
4887
4988
|
`${PACKAGE_NAME} cannot read its own version: no manifest at ${manifestPath} (${e?.message ?? String(e)}).`
|
|
@@ -4899,7 +5000,7 @@ function readVersionFrom(manifestPath) {
|
|
|
4899
5000
|
return manifest.version;
|
|
4900
5001
|
}
|
|
4901
5002
|
function readCliVersion() {
|
|
4902
|
-
return readVersionFrom(
|
|
5003
|
+
return readVersionFrom(path8.join(moduleDir(), "..", "package.json"));
|
|
4903
5004
|
}
|
|
4904
5005
|
var CLI_VERSION = readCliVersion();
|
|
4905
5006
|
|
|
@@ -4988,8 +5089,8 @@ withOutputFlags(
|
|
|
4988
5089
|
const errors = res.issues.some((i) => i.level === "error");
|
|
4989
5090
|
const code = unreadable ? EXIT_FAILED : errors ? EXIT_FINDINGS : EXIT_OK;
|
|
4990
5091
|
if (opts.out && !opts.json) {
|
|
4991
|
-
const
|
|
4992
|
-
await
|
|
5092
|
+
const fs7 = await import("fs/promises");
|
|
5093
|
+
await fs7.writeFile(opts.out, JSON.stringify(res, null, 2), "utf8");
|
|
4993
5094
|
spinner.succeed(`Analysis written to ${opts.out} in ${ms}ms`);
|
|
4994
5095
|
} else {
|
|
4995
5096
|
spinner.succeed(`Analyzed in ${ms}ms`);
|
|
@@ -5126,7 +5227,7 @@ async function explainSchemaSource(opts, out) {
|
|
|
5126
5227
|
schema: source.schema,
|
|
5127
5228
|
label: describeSchemaTarget(source.schema),
|
|
5128
5229
|
config: cfg,
|
|
5129
|
-
...source.source === "drizzle-kit" && source.drizzleKitConfigPath ? { note: `Schema from ${
|
|
5230
|
+
...source.source === "drizzle-kit" && source.drizzleKitConfigPath ? { note: `Schema from ${path9.relative(process.cwd(), source.drizzleKitConfigPath)}` } : {}
|
|
5130
5231
|
};
|
|
5131
5232
|
}
|
|
5132
5233
|
const detected = await detectSchema(process.cwd());
|
|
@@ -5236,7 +5337,11 @@ withOutputFlags(
|
|
|
5236
5337
|
).option(
|
|
5237
5338
|
"--check",
|
|
5238
5339
|
"regenerate and fail if the result differs from what is on disk, without changing it"
|
|
5239
|
-
).option("--dry-run", "report what would be written, and write nothing", false)
|
|
5340
|
+
).option("--dry-run", "report what would be written, and write nothing", false).option(
|
|
5341
|
+
"--prune",
|
|
5342
|
+
"delete files a previous run wrote that this one did not, and nothing else",
|
|
5343
|
+
false
|
|
5344
|
+
)
|
|
5240
5345
|
).action(async (opts) => {
|
|
5241
5346
|
const out = outputFor(opts);
|
|
5242
5347
|
const planning = !!opts.check || !!opts.dryRun;
|
|
@@ -5286,7 +5391,7 @@ withOutputFlags(
|
|
|
5286
5391
|
const n = source.schema.length;
|
|
5287
5392
|
out.note(
|
|
5288
5393
|
out.errStyle.gray(
|
|
5289
|
-
`Schema from ${
|
|
5394
|
+
`Schema from ${path9.relative(process.cwd(), source.drizzleKitConfigPath)} (${n} file${n === 1 ? "" : "s"})`
|
|
5290
5395
|
)
|
|
5291
5396
|
);
|
|
5292
5397
|
}
|
|
@@ -5385,6 +5490,19 @@ withOutputFlags(
|
|
|
5385
5490
|
files: e.files,
|
|
5386
5491
|
changes: e.changes.map((c) => ({ file: displayPath(c.file), status: c.status }))
|
|
5387
5492
|
}));
|
|
5493
|
+
const previousManifest = await readManifest(process.cwd());
|
|
5494
|
+
const writtenNow = plan.files.map((f) => f.file);
|
|
5495
|
+
const stale = await staleFiles(previousManifest, writtenNow, process.cwd());
|
|
5496
|
+
let stillStale = stale;
|
|
5497
|
+
if (opts.prune && !planning) {
|
|
5498
|
+
const removed = await pruneStale(process.cwd(), stale);
|
|
5499
|
+
for (const file of removed) out.warn(`drzl generate: removed stale ${file}`);
|
|
5500
|
+
const gone = new Set(removed);
|
|
5501
|
+
stillStale = stale.filter((s) => !gone.has(s.file));
|
|
5502
|
+
} else {
|
|
5503
|
+
const warning = staleWarning(stale);
|
|
5504
|
+
if (warning) warn(warning);
|
|
5505
|
+
}
|
|
5388
5506
|
if (planning) {
|
|
5389
5507
|
const wrote = await verifyNothingWasWritten(outputDirs, existing);
|
|
5390
5508
|
if (wrote.length) {
|
|
@@ -5394,6 +5512,14 @@ withOutputFlags(
|
|
|
5394
5512
|
process.exit(EXIT_FAILED);
|
|
5395
5513
|
}
|
|
5396
5514
|
}
|
|
5515
|
+
if (!planning) {
|
|
5516
|
+
await writeManifest(
|
|
5517
|
+
process.cwd(),
|
|
5518
|
+
nextManifestFiles(writtenNow, stillStale, process.cwd()).map(
|
|
5519
|
+
(f) => path9.resolve(process.cwd(), f)
|
|
5520
|
+
)
|
|
5521
|
+
);
|
|
5522
|
+
}
|
|
5397
5523
|
if (opts.check) {
|
|
5398
5524
|
const drift = pendingChanges(plan);
|
|
5399
5525
|
const upToDate = drift.length === 0;
|
|
@@ -5635,10 +5761,10 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
5635
5761
|
return;
|
|
5636
5762
|
}
|
|
5637
5763
|
let cfg = loaded;
|
|
5638
|
-
const abs = (p) =>
|
|
5764
|
+
const abs = (p) => path9.resolve(process.cwd(), p);
|
|
5639
5765
|
const isInside = (child, parent) => {
|
|
5640
|
-
const rel =
|
|
5641
|
-
return !!rel && !rel.startsWith("..") && !
|
|
5766
|
+
const rel = path9.relative(parent, child);
|
|
5767
|
+
return !!rel && !rel.startsWith("..") && !path9.isAbsolute(rel);
|
|
5642
5768
|
};
|
|
5643
5769
|
let source;
|
|
5644
5770
|
try {
|
|
@@ -5674,7 +5800,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
5674
5800
|
if (full === dir || isInside(full, dir)) return true;
|
|
5675
5801
|
}
|
|
5676
5802
|
if (stats?.isDirectory()) return false;
|
|
5677
|
-
const ext =
|
|
5803
|
+
const ext = path9.extname(full);
|
|
5678
5804
|
if (!ext) return false;
|
|
5679
5805
|
return !WATCHED_EXTENSIONS.has(ext);
|
|
5680
5806
|
};
|
|
@@ -5698,6 +5824,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
5698
5824
|
trigger(p);
|
|
5699
5825
|
});
|
|
5700
5826
|
let lastFiles = [];
|
|
5827
|
+
let lastSignature;
|
|
5701
5828
|
const watchGenerated = (kind, files) => {
|
|
5702
5829
|
if (opts.json) {
|
|
5703
5830
|
out.jsonData({ event: "generate_complete", kind, files });
|
|
@@ -5784,6 +5911,13 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
5784
5911
|
}
|
|
5785
5912
|
return;
|
|
5786
5913
|
}
|
|
5914
|
+
const signature = rebuildSignature(analysis, cfg.generators);
|
|
5915
|
+
if (sameAsLast(lastSignature, signature)) {
|
|
5916
|
+
if (opts.json) out.jsonData({ event: "generate_skipped", reason: "no change" });
|
|
5917
|
+
else out.note(out.errStyle.gray("No change to anything a generator reads. Skipped."));
|
|
5918
|
+
return;
|
|
5919
|
+
}
|
|
5920
|
+
lastSignature = signature;
|
|
5787
5921
|
for (const g of selectGenerators(cfg.generators, selection.kinds)) {
|
|
5788
5922
|
const entry = GENERATOR_BY_KIND.get(g.kind);
|
|
5789
5923
|
if (!entry) continue;
|
|
@@ -5837,7 +5971,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
5837
5971
|
} else {
|
|
5838
5972
|
out.note(
|
|
5839
5973
|
out.errStyle.gray(
|
|
5840
|
-
"Watching:\n " + Array.from(currentTargets).map((p) =>
|
|
5974
|
+
"Watching:\n " + Array.from(currentTargets).map((p) => path9.relative(process.cwd(), p)).join("\n ")
|
|
5841
5975
|
)
|
|
5842
5976
|
);
|
|
5843
5977
|
}
|