mikser-io 9.19.1 → 9.20.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/package.json +1 -1
- package/src/database/index.js +5 -0
- package/src/manifest.js +28 -27
- package/src/plugins/assets.js +10 -2
- package/src/utils.js +23 -0
package/package.json
CHANGED
package/src/database/index.js
CHANGED
|
@@ -331,6 +331,11 @@ export function createSqliteDatabase({
|
|
|
331
331
|
logger: logger ?? null,
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
+
// Published so plugins can tell an everything-was-evaluated cycle
|
|
335
|
+
// from an incremental one without reaching into the db handle. Read
|
|
336
|
+
// through `isFullCycle()` in utils.js rather than directly.
|
|
337
|
+
runtime.options.firstRun = provisioningCtx.firstRun
|
|
338
|
+
|
|
334
339
|
// Fire provisioning callbacks before schema apply, so they can
|
|
335
340
|
// load runtime extensions (sqlite-vec's vec0, etc.) that the
|
|
336
341
|
// schemas about to apply might reference, register custom
|
package/src/manifest.js
CHANGED
|
@@ -190,9 +190,34 @@ function snapToRow(snap) {
|
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
|
|
193
|
+
// Where a `destination` actually is on disk.
|
|
194
|
+
//
|
|
195
|
+
// Two shapes are in circulation and both are legitimate. A page's is
|
|
196
|
+
// output-relative with a leading slash (`/bg/index.html`); an asset's is a
|
|
197
|
+
// real filesystem path, because assets.js builds it from
|
|
198
|
+
// `runtime.options.assetsFolder`, which resolves inside the WORKING folder
|
|
199
|
+
// and can sit outside outputFolder entirely.
|
|
200
|
+
//
|
|
201
|
+
// `path.isAbsolute` cannot separate them — on POSIX `/bg/index.html` is
|
|
202
|
+
// absolute too — so resolve by EXISTENCE, output-relative first since that
|
|
203
|
+
// is the dominant shape. A page destination treated as a filesystem path
|
|
204
|
+
// would otherwise be looked for at the root of the disk.
|
|
205
|
+
//
|
|
206
|
+
// Shared, because the two callers needing it drifted into two separate
|
|
207
|
+
// bugs: verify() reported every asset missing while printing its real
|
|
208
|
+
// path, and hashOutputFile silently recorded no outputHash for one, which
|
|
209
|
+
// left 78% of a real project's snapshots presence-checked only.
|
|
210
|
+
export function resolveOutputPath(destination, outputFolder = runtime.options?.outputFolder) {
|
|
194
211
|
if (!destination) return undefined
|
|
195
|
-
const
|
|
212
|
+
const joined = path.join(outputFolder ?? '', destination)
|
|
213
|
+
if (existsSync(joined)) return joined
|
|
214
|
+
if (path.isAbsolute(destination) && existsSync(destination)) return destination
|
|
215
|
+
return joined
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function hashOutputFile(destination) {
|
|
219
|
+
const filePath = resolveOutputPath(destination)
|
|
220
|
+
if (!filePath) return undefined
|
|
196
221
|
try {
|
|
197
222
|
const buf = await readFile(filePath)
|
|
198
223
|
return sha1(buf)
|
|
@@ -552,31 +577,7 @@ export function createManifest(db) {
|
|
|
552
577
|
for (const row of stmtSelectAll.iterate()) {
|
|
553
578
|
const snap = rowToSnap(row)
|
|
554
579
|
if (!snap.destination) continue
|
|
555
|
-
|
|
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
|
+
const filePath = resolveOutputPath(snap.destination, outputFolder)
|
|
580
581
|
// Orphan detection compares against a globby walk of
|
|
581
582
|
// outputFolder, so `claimed` has to hold exactly the relative
|
|
582
583
|
// form that walk produces. A destination resolving outside
|
package/src/plugins/assets.js
CHANGED
|
@@ -6,6 +6,7 @@ import { globby } from 'globby'
|
|
|
6
6
|
import _ from 'lodash'
|
|
7
7
|
import map from 'p-map'
|
|
8
8
|
import { reportWarning } from '../report.js'
|
|
9
|
+
import { isFullCycle } from '../utils.js'
|
|
9
10
|
|
|
10
11
|
// Normalize a `options.presets[name]` value to a consistent
|
|
11
12
|
// { matches, options } shape so callers don't have to inspect which form
|
|
@@ -120,6 +121,14 @@ export function assets(options = {}) {
|
|
|
120
121
|
if (matchTally.reported) return
|
|
121
122
|
const configured = Object.keys(options.presets || {})
|
|
122
123
|
if (!configured.length || !matchTally.evaluated) return
|
|
124
|
+
// Only when the cycle evaluated everything. On an incremental run the
|
|
125
|
+
// evaluated set is whatever changed, so a healthy preset matches
|
|
126
|
+
// nothing in a run of two and the warning fires on every build —
|
|
127
|
+
// which trains the reader to filter it, and the filtered-out line is
|
|
128
|
+
// the real one. The message already told the reader to use --force to
|
|
129
|
+
// check the whole catalog; that condition gates it now instead of
|
|
130
|
+
// annotating it.
|
|
131
|
+
if (!isFullCycle(runtime)) return
|
|
123
132
|
matchTally.reported = true
|
|
124
133
|
|
|
125
134
|
for (const preset of configured) {
|
|
@@ -129,8 +138,7 @@ export function assets(options = {}) {
|
|
|
129
138
|
logger.warn(
|
|
130
139
|
'Assets preset %j matched none of the %d entities evaluated (patterns: %s). ' +
|
|
131
140
|
'Patterns run against entity.id, which files({ outputFolder }) does NOT prefix — ' +
|
|
132
|
-
'the prefix appears on name and meta.url only.
|
|
133
|
-
'entities are not re-evaluated; use --force to check the whole catalog.',
|
|
141
|
+
'the prefix appears on name and meta.url only.',
|
|
134
142
|
preset, matchTally.evaluated, matches.join(', '))
|
|
135
143
|
}
|
|
136
144
|
}
|
package/src/utils.js
CHANGED
|
@@ -990,6 +990,29 @@ export async function writeOutput(file, bytes) {
|
|
|
990
990
|
return true
|
|
991
991
|
}
|
|
992
992
|
|
|
993
|
+
// Did this cycle evaluate the whole corpus, or only what changed?
|
|
994
|
+
//
|
|
995
|
+
// The distinction is what makes a "declared X matched nothing" warning
|
|
996
|
+
// worth printing. On an incremental cycle only changed entities are
|
|
997
|
+
// re-evaluated, so a pattern or preset legitimately matches nothing in a
|
|
998
|
+
// run of two — printing it there means the warning fires on every healthy
|
|
999
|
+
// build, and a warning that always fires is one people filter out, taking
|
|
1000
|
+
// the real instance with it.
|
|
1001
|
+
//
|
|
1002
|
+
// True for: --force, a first-run or wiped database, and a cache
|
|
1003
|
+
// invalidation. Those are exactly the cases where the import gate is
|
|
1004
|
+
// bypassed and every entity is presented for evaluation.
|
|
1005
|
+
// Takes the runtime rather than reading the singleton, so a plugin passes
|
|
1006
|
+
// the one it was injected with — which is the singleton in a real build and
|
|
1007
|
+
// the harness's stand-in under test.
|
|
1008
|
+
export function isFullCycle(rt = runtime) {
|
|
1009
|
+
return !!(
|
|
1010
|
+
rt?.options?.force
|
|
1011
|
+
|| rt?.options?.firstRun
|
|
1012
|
+
|| rt?.catalog?.cacheInvalidated
|
|
1013
|
+
)
|
|
1014
|
+
}
|
|
1015
|
+
|
|
993
1016
|
// ── operating-system and file-manager litter ────────────────────────────
|
|
994
1017
|
//
|
|
995
1018
|
// Exposing a source folder over a network filesystem (mikser-io-webdav) or
|