dotmd-cli 0.86.0 → 0.87.1

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/src/validate.mjs CHANGED
@@ -254,52 +254,45 @@ export function validateDoc(doc, frontmatter, headingTitle, config) {
254
254
  }
255
255
  }
256
256
 
257
- // Validate reference fields resolve to existing files. Terminal statuses
258
- // (archived, deprecated, etc.) document historical state — their refs may
259
- // legitimately point at moved/deleted targets and shouldn't gate the
260
- // exit code with a hard error.
257
+ // Historical documents still need navigable references. Their prose is a
258
+ // dated record, but links to moved or deleted files cannot be followed.
261
259
  const docDir = path.dirname(path.join(config.repoRoot, doc.path));
262
260
  const allRefFields = [...(config.referenceFields.bidirectional || []), ...(config.referenceFields.unidirectional || [])];
263
- const skipRefValidation = config.lifecycle.isTerminal?.(doc.status, doc.type)
264
- ?? config.lifecycle.terminalStatuses.has(doc.status);
265
- if (!skipRefValidation) {
266
- for (const field of allRefFields) {
267
- for (const relPath of (doc.refFields[field] || [])) {
268
- if (!resolveRefPath(relPath, docDir, config.repoRoot)) {
269
- doc.errors.push({
270
- path: doc.path,
271
- level: 'error',
272
- message: `${field} entry \`${relPath}\` does not resolve to an existing file.`,
273
- meta: { kind: 'ref-resolution', field, relPath },
274
- });
275
- }
276
- }
277
- }
278
-
279
- // Validate body links resolve to existing files
280
- for (const link of (doc.bodyLinks || [])) {
281
- const resolution = resolveBodyLinkTarget(link.href, docDir, config.repoRoot);
282
- if (!resolution.ok) {
283
- const shownHref = link.rawHref ?? link.href;
284
- doc.warnings.push({
261
+ for (const field of allRefFields) {
262
+ for (const relPath of (doc.refFields[field] || [])) {
263
+ if (!resolveRefPath(relPath, docDir, config.repoRoot)) {
264
+ doc.errors.push({
285
265
  path: doc.path,
286
- level: 'warning',
287
- message: resolution.reason === 'outside-repo'
288
- ? `body link \`${shownHref}\` escapes the repository.`
289
- : `body link \`${shownHref}\` does not resolve to an existing file or directory.`,
290
- meta: {
291
- kind: 'body-link-resolution',
292
- field: 'body-link',
293
- relPath: link.href,
294
- rawHref: shownHref,
295
- targetKind: link.targetKind ?? 'document',
296
- angle: link.angle === true,
297
- reason: resolution.reason,
298
- },
266
+ level: 'error',
267
+ message: `${field} entry \`${relPath}\` does not resolve to an existing file.`,
268
+ meta: { kind: 'ref-resolution', field, relPath },
299
269
  });
300
270
  }
301
271
  }
302
272
  }
273
+
274
+ for (const link of (doc.bodyLinks || [])) {
275
+ const resolution = resolveBodyLinkTarget(link.href, docDir, config.repoRoot, config.externalBodyLinkRoots);
276
+ if (!resolution.ok) {
277
+ const shownHref = link.rawHref ?? link.href;
278
+ doc.errors.push({
279
+ path: doc.path,
280
+ level: 'error',
281
+ message: resolution.reason === 'outside-repo'
282
+ ? `body link \`${shownHref}\` escapes the repository.`
283
+ : `body link \`${shownHref}\` does not resolve to an existing file or directory.`,
284
+ meta: {
285
+ kind: 'body-link-resolution',
286
+ field: 'body-link',
287
+ relPath: link.href,
288
+ rawHref: shownHref,
289
+ targetKind: link.targetKind ?? 'document',
290
+ angle: link.angle === true,
291
+ reason: resolution.reason,
292
+ },
293
+ });
294
+ }
295
+ }
303
296
  }
304
297
 
305
298
  // Guess which doc type a ref field expects so suggestions don't propose