@hawkeyexl/manni 2.8.2 → 2.8.3

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.
@@ -8,7 +8,7 @@ var __export = (target, all) => {
8
8
  // package.json
9
9
  var package_default = {
10
10
  name: "@hawkeyexl/manni",
11
- version: "2.8.2",
11
+ version: "2.8.3",
12
12
  description: "One command line for documentation that is meant to be checked. `manni meta` validates the presence and format of document metadata (Markdown frontmatter and more) against JSON Schema, built for CI. Formerly docmeta.",
13
13
  type: "module",
14
14
  bin: {
@@ -393,8 +393,8 @@ function isMember(collection, relPath) {
393
393
  return !collection.exclude.some((glob) => matchesFileGlob(relPath, glob));
394
394
  }
395
395
  function normalizeEntry(entry) {
396
- const posix4 = entry.replace(/\\/g, "/").replace(/^\.\//, "");
397
- return posix4.endsWith("/") ? posix4.slice(0, -1) : posix4;
396
+ const posix5 = entry.replace(/\\/g, "/").replace(/^\.\//, "");
397
+ return posix5.endsWith("/") ? posix5.slice(0, -1) : posix5;
398
398
  }
399
399
  function isGlob(entry) {
400
400
  return picomatch2.scan(entry).isGlob;
@@ -5569,11 +5569,11 @@ function collectSchemaPins(config) {
5569
5569
  }
5570
5570
  function rebaseConfigSchemaRefs(config, configDir, cwd) {
5571
5571
  if (resolve(configDir) === resolve(cwd)) return config;
5572
- const rebase = (ref) => classifyRef(ref).kind === "file" && !isAbsolute(ref) ? resolve(configDir, ref) : ref;
5573
- const rebaseEntry = (entry) => typeof entry === "string" ? rebase(entry) : {
5572
+ const rebase2 = (ref) => classifyRef(ref).kind === "file" && !isAbsolute(ref) ? resolve(configDir, ref) : ref;
5573
+ const rebaseEntry = (entry) => typeof entry === "string" ? rebase2(entry) : {
5574
5574
  ...entry,
5575
- ref: rebase(entry.ref),
5576
- ...entry.source !== void 0 ? { source: rebase(entry.source) } : {}
5575
+ ref: rebase2(entry.ref),
5576
+ ...entry.source !== void 0 ? { source: rebase2(entry.source) } : {}
5577
5577
  };
5578
5578
  return {
5579
5579
  ...config,
@@ -5581,7 +5581,7 @@ function rebaseConfigSchemaRefs(config, configDir, cwd) {
5581
5581
  ...config.overrides ? {
5582
5582
  overrides: config.overrides.map((o) => ({
5583
5583
  ...o,
5584
- schemas: o.schemas.map(rebase)
5584
+ schemas: o.schemas.map(rebase2)
5585
5585
  }))
5586
5586
  } : {}
5587
5587
  };
@@ -7012,12 +7012,12 @@ async function gitIgnored(paths, cwd) {
7012
7012
  return answered > 0 ? { ignored, available: true } : unavailable();
7013
7013
  }
7014
7014
  function checkIgnore(paths, cwd) {
7015
- return new Promise((settle) => {
7015
+ return new Promise((settle2) => {
7016
7016
  let done = false;
7017
7017
  const finish2 = (answer) => {
7018
7018
  if (done) return;
7019
7019
  done = true;
7020
- settle(answer);
7020
+ settle2(answer);
7021
7021
  };
7022
7022
  let child;
7023
7023
  try {
@@ -9323,12 +9323,12 @@ var MAX_OUTPUT_BYTES = 8 * 1024 * 1024;
9323
9323
  var BinMissing = class extends Error {
9324
9324
  };
9325
9325
  function run(bin, args, opts) {
9326
- return new Promise((settle, reject) => {
9326
+ return new Promise((settle2, reject) => {
9327
9327
  let done = false;
9328
9328
  const finish2 = (r) => {
9329
9329
  if (done) return;
9330
9330
  done = true;
9331
- settle(r);
9331
+ settle2(r);
9332
9332
  };
9333
9333
  const fail2 = (err) => {
9334
9334
  if (done) return;
@@ -11226,12 +11226,12 @@ function text(out) {
11226
11226
  }
11227
11227
  }
11228
11228
  function runGit(args, cwd, stdin, maxBytes) {
11229
- return new Promise((settle, reject) => {
11229
+ return new Promise((settle2, reject) => {
11230
11230
  let done = false;
11231
11231
  const finish2 = (out) => {
11232
11232
  if (done) return;
11233
11233
  done = true;
11234
- settle(out);
11234
+ settle2(out);
11235
11235
  };
11236
11236
  const fail2 = (err) => {
11237
11237
  if (done) return;
@@ -12363,17 +12363,17 @@ function bare(path) {
12363
12363
  }
12364
12364
  async function collectionPath(target, cwd, configDir) {
12365
12365
  if (target === STDIN_TOKEN) return void 0;
12366
- const posix4 = target.replace(/\\/g, "/");
12367
- const scanned = picomatch6.scan(posix4);
12366
+ const posix5 = target.replace(/\\/g, "/");
12367
+ const scanned = picomatch6.scan(posix5);
12368
12368
  if (scanned.isGlob) {
12369
12369
  const rel2 = toPosix3(relative11(configDir, resolve13(cwd, scanned.base === "" ? "." : scanned.base)));
12370
12370
  if (isAbsolute7(rel2) || rel2 === ".." || rel2.startsWith("../")) return void 0;
12371
12371
  return rel2 === "" ? scanned.glob : `${rel2}/${scanned.glob}`;
12372
12372
  }
12373
- const abs = resolve13(cwd, posix4);
12373
+ const abs = resolve13(cwd, posix5);
12374
12374
  const rel = toPosix3(relative11(configDir, abs));
12375
12375
  if (isAbsolute7(rel) || rel.startsWith("..")) return void 0;
12376
- let directory = posix4.endsWith("/");
12376
+ let directory = posix5.endsWith("/");
12377
12377
  if (!directory) {
12378
12378
  try {
12379
12379
  directory = (await stat5(abs)).isDirectory();
@@ -17130,7 +17130,7 @@ function skipExpression(sql, from) {
17130
17130
  }
17131
17131
 
17132
17132
  // src/meta/commands/fill.ts
17133
- import { readFile as readFile13 } from "node:fs/promises";
17133
+ import { readFile as readFile14 } from "node:fs/promises";
17134
17134
  import { resolve as resolve19, extname as extname8, join as join10 } from "node:path";
17135
17135
  import {
17136
17136
  completeValidatedJSON,
@@ -17145,6 +17145,107 @@ import {
17145
17145
  InferenceError
17146
17146
  } from "@hawkeyexl/inference";
17147
17147
 
17148
+ // src/meta/core/manifest-writes.ts
17149
+ import { readFile as readFile13 } from "node:fs/promises";
17150
+
17151
+ // src/shared/manifest-cas.ts
17152
+ import { posix as posix4 } from "node:path";
17153
+ var COMMIT_ATTEMPTS = 5;
17154
+ function conflictRefusal(file) {
17155
+ return `${file} changed under the command while it was being written. Nothing was written to it. Re-run the command.`;
17156
+ }
17157
+ function heldManifest(path, file, before) {
17158
+ return { path, file, before, text: before, ops: [], bases: /* @__PURE__ */ new Map() };
17159
+ }
17160
+ function encodeValue(value) {
17161
+ return value === void 0 ? "absent" : JSON.stringify(value);
17162
+ }
17163
+ function baseKey(at2) {
17164
+ const entry = at2.join === "path" ? posix4.normalize(at2.entry) : at2.entry;
17165
+ return `${entry}\0${at2.key}`;
17166
+ }
17167
+ function rebaseable(held, op, codec) {
17168
+ const at2 = baseKey(op);
17169
+ if (held.bases.has(at2)) return;
17170
+ held.bases.set(at2, {
17171
+ entry: op.entry,
17172
+ key: op.key,
17173
+ join: op.join,
17174
+ value: encodeValue(codec.read(held.before, op))
17175
+ });
17176
+ }
17177
+ function rebase(held, current, codec) {
17178
+ for (const base of held.bases.values()) {
17179
+ if (encodeValue(codec.read(current, base)) !== base.value) return void 0;
17180
+ }
17181
+ let text2 = current;
17182
+ for (const op of held.ops) text2 = codec.apply(text2, op);
17183
+ return text2;
17184
+ }
17185
+ function rebaseline(held) {
17186
+ held.before = held.text;
17187
+ held.ops = [];
17188
+ held.bases.clear();
17189
+ }
17190
+ async function settle(held, io) {
17191
+ for (let attempt = 1; attempt <= COMMIT_ATTEMPTS; attempt++) {
17192
+ let current;
17193
+ try {
17194
+ current = await io.read(held.path);
17195
+ } catch (error) {
17196
+ const reason = error instanceof Error ? error.message : String(error);
17197
+ throw io.toError(`Manifest ${held.file} could not be read: ${reason}`);
17198
+ }
17199
+ if (current === held.before) {
17200
+ await io.write(held.path, held.text);
17201
+ return;
17202
+ }
17203
+ const replayed = rebase(held, current, io.codec);
17204
+ if (replayed === void 0) throw io.toError(conflictRefusal(held.file));
17205
+ held.before = current;
17206
+ held.text = replayed;
17207
+ }
17208
+ throw io.toError(conflictRefusal(held.file));
17209
+ }
17210
+
17211
+ // src/meta/core/manifest-writes.ts
17212
+ var manifestCodec = {
17213
+ apply(text2, op) {
17214
+ const where = { entry: op.entry, key: op.key, join: op.join, file: op.file };
17215
+ return op.kind === "remove" ? removeManifestKey(text2, where).text : spliceManifestValue(text2, { ...where, value: op.value }).text;
17216
+ },
17217
+ read(text2, at2) {
17218
+ return readManifestValue(text2, at2);
17219
+ }
17220
+ };
17221
+ function applyManifestOp(text2, op) {
17222
+ return manifestCodec.apply(text2, op);
17223
+ }
17224
+ async function holdManifestFile(path, file) {
17225
+ let before;
17226
+ try {
17227
+ before = await readFile13(path, "utf8");
17228
+ } catch (err) {
17229
+ throw new DocmetaError(`Manifest ${file} could not be read: ${errorMessage(err)}`);
17230
+ }
17231
+ return heldManifest(path, file, before);
17232
+ }
17233
+ function recordManifestOp(held, op) {
17234
+ rebaseable(held, op, manifestCodec);
17235
+ held.ops.push(op);
17236
+ }
17237
+ async function settleManifest(held, io = {}) {
17238
+ if (held.text === held.before) return false;
17239
+ await settle(held, {
17240
+ codec: manifestCodec,
17241
+ write: io.write ?? writeFileAtomic,
17242
+ read: io.read ?? ((at2) => readFile13(at2, "utf8")),
17243
+ toError: (message) => new DocmetaError(message)
17244
+ });
17245
+ rebaseline(held);
17246
+ return true;
17247
+ }
17248
+
17148
17249
  // src/meta/commands/fill-prompt.ts
17149
17250
  var FILL_PROMPT_VERSION = 4;
17150
17251
  var DEFAULT_CHUNK_CHARS = 12e3;
@@ -17444,28 +17545,34 @@ async function runFill(opts) {
17444
17545
  });
17445
17546
  const heldManifests = /* @__PURE__ */ new Map();
17446
17547
  const holding = /* @__PURE__ */ new Map();
17447
- const saveManifest = (held) => {
17448
- held.saving = held.saving.then(async () => {
17449
- const text2 = held.text;
17450
- if (text2 === held.written) return;
17451
- await writeFileAtomic(held.path, text2);
17452
- held.written = text2;
17548
+ const saveManifest = (h, ops) => {
17549
+ h.saving = h.saving.then(async () => {
17550
+ for (const op of ops) {
17551
+ const after = applyManifestOp(h.held.text, op);
17552
+ if (after === h.held.text) continue;
17553
+ recordManifestOp(h.held, op);
17554
+ h.held.text = after;
17555
+ }
17556
+ if (!dryRun) await settleManifest(h.held);
17453
17557
  });
17454
- return held.saving;
17558
+ return h.saving;
17559
+ };
17560
+ const restorePage = async (label, before) => {
17561
+ try {
17562
+ await writeFileAtomic(resolve19(base, label), before);
17563
+ return `${label} was restored.`;
17564
+ } catch (err) {
17565
+ return `${label} could not be restored: ${errorMessage(err)}. Restore it from version control.`;
17566
+ }
17455
17567
  };
17456
17568
  const holdManifest = (home) => {
17457
17569
  let held = holding.get(home.absPath);
17458
17570
  if (held === void 0) {
17459
- held = readFile13(home.absPath, "utf8").then(
17460
- (before) => {
17461
- const h = { path: home.absPath, text: before, written: before, saving: Promise.resolve() };
17462
- heldManifests.set(home.absPath, h);
17463
- return h;
17464
- },
17465
- (err) => {
17466
- throw new DocmetaError(`Manifest ${home.file} could not be read: ${errorMessage(err)}`);
17467
- }
17468
- );
17571
+ held = holdManifestFile(home.absPath, home.file).then((m) => {
17572
+ const h = { held: m, saving: Promise.resolve() };
17573
+ heldManifests.set(home.absPath, h);
17574
+ return h;
17575
+ });
17469
17576
  holding.set(home.absPath, held);
17470
17577
  }
17471
17578
  return held;
@@ -17967,52 +18074,54 @@ async function runFill(opts) {
17967
18074
  metaProvenance = { written: false, skipReason: "unwritable" };
17968
18075
  }
17969
18076
  const helds = await Promise.all(entryWrites.map((w) => holdManifest(w.home)));
17970
- const splice = () => {
17971
- const texts = /* @__PURE__ */ new Map();
17972
- for (const [i, w] of entryWrites.entries()) {
17973
- const held = helds[i];
17974
- if (held === void 0) continue;
17975
- const text2 = texts.get(held.path) ?? held.text;
17976
- texts.set(
17977
- held.path,
17978
- spliceManifestValue(text2, {
17979
- entry: w.home.entry,
17980
- key: w.key,
17981
- value: w.value,
17982
- join: w.home.join,
17983
- file: w.home.file
17984
- }).text
17985
- );
17986
- }
17987
- return texts;
17988
- };
18077
+ const ops = [];
18078
+ for (const [i, w] of entryWrites.entries()) {
18079
+ const at2 = helds[i];
18080
+ if (at2 === void 0) continue;
18081
+ ops.push({
18082
+ at: at2,
18083
+ op: {
18084
+ kind: "splice",
18085
+ entry: w.home.entry,
18086
+ key: w.key,
18087
+ value: w.value,
18088
+ join: w.home.join,
18089
+ file: w.home.file
18090
+ }
18091
+ });
18092
+ }
17989
18093
  let manifestChanged = false;
17990
18094
  try {
17991
- manifestChanged = [...splice()].some(([path, text2]) => heldManifests.get(path)?.text !== text2);
18095
+ const texts = /* @__PURE__ */ new Map();
18096
+ for (const { at: at2, op } of ops) {
18097
+ texts.set(at2.held.path, applyManifestOp(texts.get(at2.held.path) ?? at2.held.text, op));
18098
+ }
18099
+ manifestChanged = [...texts].some(([path, text2]) => heldManifests.get(path)?.held.text !== text2);
17992
18100
  } catch (err) {
17993
18101
  if (!(err instanceof DocmetaError)) throw err;
17994
18102
  return errorResult(label, extractor.name, err.message, schemaSet, fields);
17995
18103
  }
17996
18104
  const changed = next !== content || manifestChanged;
17997
- if (next !== content && !dryRun && label !== "<stdin>") {
18105
+ const pageWritten = next !== content && !dryRun && label !== "<stdin>";
18106
+ if (pageWritten) {
17998
18107
  await writeFileAtomic(resolve19(base, label), next);
17999
18108
  }
18000
18109
  if (manifestChanged) {
18001
- let texts;
18110
+ const perManifest = /* @__PURE__ */ new Map();
18111
+ for (const { at: at2, op } of ops) {
18112
+ const list2 = perManifest.get(at2);
18113
+ if (list2 === void 0) perManifest.set(at2, [op]);
18114
+ else list2.push(op);
18115
+ }
18116
+ const saves = [...perManifest].map(([at2, list2]) => saveManifest(at2, list2));
18002
18117
  try {
18003
- texts = splice();
18118
+ await Promise.all(saves);
18004
18119
  } catch (err) {
18005
- if (!(err instanceof DocmetaError)) throw err;
18006
- return errorResult(label, extractor.name, err.message, schemaSet, fields);
18007
- }
18008
- const saves = [];
18009
- for (const [path, text2] of texts) {
18010
- const held = heldManifests.get(path);
18011
- if (held === void 0 || held.text === text2) continue;
18012
- held.text = text2;
18013
- if (!dryRun) saves.push(saveManifest(held));
18120
+ if (!pageWritten) throw err;
18121
+ const note = await restorePage(label, content);
18122
+ if (err instanceof DocmetaError) throw new DocmetaError(`${err.message} ${note}`);
18123
+ throw err;
18014
18124
  }
18015
- await Promise.all(saves);
18016
18125
  }
18017
18126
  return {
18018
18127
  file: label,
@@ -18027,7 +18136,7 @@ async function runFill(opts) {
18027
18136
  const prepareAll = async () => ({
18028
18137
  stdin: usingStdin ? await prepareOne("<stdin>", opts.stdinContent ?? "", forcedExtractor?.extensions[0] ?? "") : void 0,
18029
18138
  files: await mapConcurrent(files, concurrency, async (file) => {
18030
- const content = await readFile13(resolve19(base, file), "utf8");
18139
+ const content = await readFile14(resolve19(base, file), "utf8");
18031
18140
  return prepareOne(file, content, extname8(file));
18032
18141
  })
18033
18142
  });
@@ -18051,7 +18160,7 @@ async function runFill(opts) {
18051
18160
  const results = [];
18052
18161
  if (prepared.stdin !== void 0) results.push(await finish2(prepared.stdin));
18053
18162
  results.push(...await mapConcurrent(prepared.files, concurrency, finish2));
18054
- await Promise.all([...heldManifests.values()].map((held) => held.saving));
18163
+ await Promise.all([...heldManifests.values()].map((h) => h.saving));
18055
18164
  if (flagged.length > 0) {
18056
18165
  const landed = flagged.filter((w) => {
18057
18166
  const r = results.find((x) => x.file === w.label);
@@ -18456,7 +18565,7 @@ async function mapConcurrent(items2, limit, fn) {
18456
18565
  }
18457
18566
 
18458
18567
  // src/meta/commands/derive.ts
18459
- import { readFile as readFile14 } from "node:fs/promises";
18568
+ import { readFile as readFile15 } from "node:fs/promises";
18460
18569
  import { extname as extname9, relative as relative14, resolve as resolve20, sep as sep10 } from "node:path";
18461
18570
  var GENERATED_BY_ENV = "MANNI_GENERATED_BY";
18462
18571
  var SOURCE_HINT = "narrow --sources or --fields";
@@ -18602,7 +18711,7 @@ async function runDerive(opts) {
18602
18711
  });
18603
18712
  continue;
18604
18713
  }
18605
- const content = await readFile14(absPath, "utf8");
18714
+ const content = await readFile15(absPath, "utf8");
18606
18715
  const elements = resolveElements(label, config, membersFor(label));
18607
18716
  try {
18608
18717
  loaded2.set(label, {
@@ -18823,24 +18932,13 @@ async function runDerive(opts) {
18823
18932
  const holdManifest = async (manifest) => {
18824
18933
  const already = heldManifests.get(manifest.absPath);
18825
18934
  if (already !== void 0) return already;
18826
- let before;
18827
- try {
18828
- before = await readFile14(manifest.absPath, "utf8");
18829
- } catch (err) {
18830
- throw new DocmetaError(`Manifest ${manifest.file} could not be read: ${errorMessage(err)}`);
18831
- }
18832
- const held = { path: manifest.absPath, written: before, text: before };
18935
+ const held = await holdManifestFile(manifest.absPath, manifest.file);
18833
18936
  heldManifests.set(manifest.absPath, held);
18834
18937
  return held;
18835
18938
  };
18836
18939
  const results = [];
18837
18940
  const saveManifests = async () => {
18838
- for (const held of heldManifests.values()) {
18839
- if (held.text !== held.written) {
18840
- await writeFileAtomic(held.path, held.text);
18841
- held.written = held.text;
18842
- }
18843
- }
18941
+ for (const held of heldManifests.values()) await settleManifest(held);
18844
18942
  };
18845
18943
  let settled = false;
18846
18944
  try {
@@ -18917,12 +19015,15 @@ async function runDerive(opts) {
18917
19015
  }
18918
19016
  let changed = false;
18919
19017
  const staged = /* @__PURE__ */ new Map();
18920
- const stage = async (manifest, edit) => {
19018
+ const stagedOps = [];
19019
+ const stage = async (manifest, op) => {
18921
19020
  const held = await holdManifest(manifest);
18922
19021
  const before = staged.get(held.path) ?? held.text;
18923
- const after = edit(before);
19022
+ const after = applyManifestOp(before, op);
18924
19023
  staged.set(held.path, after);
18925
- return after !== before;
19024
+ if (after === before) return false;
19025
+ stagedOps.push({ held, op });
19026
+ return true;
18926
19027
  };
18927
19028
  const manifestWritten = [];
18928
19029
  const entryWritten = [];
@@ -18931,7 +19032,7 @@ async function runDerive(opts) {
18931
19032
  const plan = toManifest.judged.plan;
18932
19033
  const edited = await stage(
18933
19034
  place.manifest,
18934
- (text2) => plan.length === 0 ? removeManifestKey(text2, where).text : spliceManifestValue(text2, { ...where, value: plan }).text
19035
+ plan.length === 0 ? { ...where, kind: "remove" } : { ...where, kind: "splice", value: plan }
18935
19036
  );
18936
19037
  if (edited) {
18937
19038
  changed = true;
@@ -18941,16 +19042,14 @@ async function runDerive(opts) {
18941
19042
  try {
18942
19043
  for (const { f, home, entry } of toEntries) {
18943
19044
  const value = isMarked(f.field) ? await sealField(f.field, f.derived, marks.marked) : f.derived;
18944
- const edited = await stage(
18945
- home,
18946
- (text2) => spliceManifestValue(text2, {
18947
- entry,
18948
- key: f.field,
18949
- value,
18950
- join: home.join,
18951
- file: home.file
18952
- }).text
18953
- );
19045
+ const edited = await stage(home, {
19046
+ kind: "splice",
19047
+ entry,
19048
+ key: f.field,
19049
+ value,
19050
+ join: home.join,
19051
+ file: home.file
19052
+ });
18954
19053
  if (edited) {
18955
19054
  changed = true;
18956
19055
  manifestWritten.push(f);
@@ -19013,6 +19112,7 @@ async function runDerive(opts) {
19013
19112
  }
19014
19113
  }
19015
19114
  }
19115
+ for (const { held, op } of stagedOps) recordManifestOp(held, op);
19016
19116
  for (const [path, text2] of staged) {
19017
19117
  const held = heldManifests.get(path);
19018
19118
  if (held !== void 0) held.text = text2;
@@ -19944,6 +20044,9 @@ export {
19944
20044
  runVendorSchema,
19945
20045
  runInferSchema,
19946
20046
  runQuery,
20047
+ heldManifest,
20048
+ rebaseable,
20049
+ settle,
19947
20050
  runFill,
19948
20051
  runDerive,
19949
20052
  deriveFailed,
@@ -19962,4 +20065,4 @@ export {
19962
20065
  renderQuery,
19963
20066
  renderQueryCsv
19964
20067
  };
19965
- //# sourceMappingURL=chunk-KEW557TN.js.map
20068
+ //# sourceMappingURL=chunk-KGI7B6DD.js.map