mikser-io 9.19.0 → 9.19.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.
@@ -106,9 +106,16 @@ there is no manifest to check against.
106
106
  npx mikser --verify || echo "output folder has drifted"
107
107
  ```
108
108
 
109
- `Orphan` is the one to read carefully — it is normal for files that
110
- another plugin writes (assets, files, data), and a real signal for a page
111
- whose layout stopped producing it.
109
+ A destination is resolved against the output folder first and, when that
110
+ finds nothing, treated as a filesystem path — assets carry an absolute
111
+ destination built from `assetsFolder`, which may sit outside the output
112
+ folder entirely.
113
+
114
+ `Orphan` still needs reading with that in mind: only files under the
115
+ output folder are walked, and a file is an orphan when no snapshot claims
116
+ it. That is normal for anything written without a render snapshot (the
117
+ `files` and `data` plugins), and a real signal for a page whose layout
118
+ stopped producing it.
112
119
 
113
120
  ### The rest, briefly
114
121
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mikser-io",
3
- "version": "9.19.0",
3
+ "version": "9.19.1",
4
4
  "description": "<p align=\"center\"> <img src=\"mikser-lockup-stacked.svg\" alt=\"mikser\" width=\"198\" /> </p>",
5
5
  "main": "index.js",
6
6
  "exports": {
package/src/engine.js CHANGED
@@ -265,8 +265,15 @@ export async function setup(options) {
265
265
  for (const e of unverifiable) logger.warn('No hash: %s (entity %s)', e.destination, e.id)
266
266
  for (const e of orphaned) logger.warn('Orphan: %s', e.path)
267
267
 
268
+ // Level picked from the verdict, because the level IS the marker
269
+ // in pino-pretty's messageFormat: notice renders 🟢, warn 🟡,
270
+ // error 🔴. A fixed `notice` prints a green tick next to the word
271
+ // FAIL, which reads as success at a glance even though the exit
272
+ // code is right.
268
273
  const verdict = errors > 0 ? 'FAIL' : (warnings > 0 ? 'WARN' : 'OK')
269
- logger.notice('Verify %s: %d snapshots, %d missing, %d mismatched, %d unverifiable, %d orphaned',
274
+ const report = errors > 0 ? logger.error : (warnings > 0 ? logger.warn : logger.notice)
275
+ report.call(logger,
276
+ 'Verify %s: %d snapshots, %d missing, %d mismatched, %d unverifiable, %d orphaned',
270
277
  verdict, total, missing.length, mismatched.length, unverifiable.length, orphaned.length)
271
278
  process.exit(errors > 0 ? 2 : (warnings > 0 ? 1 : 0))
272
279
  }
package/src/manifest.js CHANGED
@@ -66,7 +66,10 @@ import { useDatabase, registerSchema } from './database/index.js'
66
66
  // PK index, no separate id index needed. Parent index is for pagination
67
67
  // cleanup (drop all children of X). WITHOUT ROWID keeps the file
68
68
  // smaller.
69
- registerSchema('mikser_snapshots', `
69
+ // Exported so tests build against the real schema rather than a copy. A
70
+ // copy drifts the moment a column is added, and the failure is a bare
71
+ // SQLITE_ERROR that names nothing.
72
+ export const SNAPSHOTS_SCHEMA = `
70
73
  CREATE TABLE IF NOT EXISTS mikser_snapshots (
71
74
  id TEXT NOT NULL,
72
75
  destination TEXT NOT NULL,
@@ -78,7 +81,8 @@ registerSchema('mikser_snapshots', `
78
81
  PRIMARY KEY (id, destination)
79
82
  ) WITHOUT ROWID;
80
83
  CREATE INDEX IF NOT EXISTS idx_mikser_snapshots_parent ON mikser_snapshots(parent) WHERE parent IS NOT NULL;
81
- `)
84
+ `
85
+ registerSchema('mikser_snapshots', SNAPSHOTS_SCHEMA)
82
86
 
83
87
  // Module-level DB handle + prepared statements for the lifecycle
84
88
  // integration. Tests build their own via `createManifest(db)` —
@@ -548,8 +552,41 @@ export function createManifest(db) {
548
552
  for (const row of stmtSelectAll.iterate()) {
549
553
  const snap = rowToSnap(row)
550
554
  if (!snap.destination) continue
551
- claimed.add(snap.destination.replace(/^\/+/, ''))
552
- const filePath = path.join(outputFolder, snap.destination)
555
+ // `destination` arrives in two shapes and both are legitimate.
556
+ // A page's is output-relative with a leading slash
557
+ // (`/bg/index.html`); an asset's is a real filesystem path,
558
+ // because assets.js builds it from
559
+ // `runtime.options.assetsFolder` — which resolves inside the
560
+ // WORKING folder and may sit outside outputFolder entirely
561
+ // (a `derived/` tree that `shares` symlinks into each language
562
+ // root is the case that proves it).
563
+ //
564
+ // `path.isAbsolute` cannot tell them apart: on POSIX
565
+ // `/bg/index.html` is absolute too. So resolve by EXISTENCE,
566
+ // output-relative first — that is the dominant shape, and a
567
+ // page destination interpreted as a filesystem path would
568
+ // otherwise be looked for at the root of the disk.
569
+ //
570
+ // Only the fallback path is a filesystem path, so it is only
571
+ // tried when the destination is absolute and joining changed
572
+ // nothing that resolves.
573
+ const joined = path.join(outputFolder, snap.destination)
574
+ let filePath = joined
575
+ if (!existsSync(joined)
576
+ && path.isAbsolute(snap.destination)
577
+ && existsSync(snap.destination)) {
578
+ filePath = snap.destination
579
+ }
580
+ // Orphan detection compares against a globby walk of
581
+ // outputFolder, so `claimed` has to hold exactly the relative
582
+ // form that walk produces. A destination resolving outside
583
+ // outputFolder can never appear in it and is not claimable;
584
+ // one inside it must be claimed by its relative path, not by
585
+ // the raw string with its leading slashes stripped.
586
+ const relative = path.relative(outputFolder, filePath)
587
+ if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) {
588
+ claimed.add(relative)
589
+ }
553
590
  if (!existsSync(filePath)) {
554
591
  missing.push({ id: snap.id, destination: snap.destination })
555
592
  continue