@nuasite/cms 0.46.3 → 0.46.4
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/editor.js
CHANGED
|
@@ -386,7 +386,7 @@ function IC(t, e) {
|
|
|
386
386
|
function _C(t, e) {
|
|
387
387
|
return typeof e == "function" ? e(t) : e;
|
|
388
388
|
}
|
|
389
|
-
const u5 = "0.46.
|
|
389
|
+
const u5 = "0.46.4", h5 = u5, ct = {
|
|
390
390
|
/** Highlight overlay for hovered elements */
|
|
391
391
|
HIGHLIGHT: 2147483644,
|
|
392
392
|
/** Hover outline for elements/components */
|
package/package.json
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"directory": "packages/astro-cms"
|
|
15
15
|
},
|
|
16
16
|
"license": "Apache-2.0",
|
|
17
|
-
"version": "0.46.
|
|
17
|
+
"version": "0.46.4",
|
|
18
18
|
"module": "src/index.ts",
|
|
19
19
|
"types": "src/index.ts",
|
|
20
20
|
"type": "module",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@nuasite/cms-core": "0.46.
|
|
30
|
-
"@nuasite/cms-types": "0.46.
|
|
29
|
+
"@nuasite/cms-core": "0.46.4",
|
|
30
|
+
"@nuasite/cms-types": "0.46.4",
|
|
31
31
|
"@astrojs/compiler": "^3.0.1",
|
|
32
32
|
"@babel/parser": "^7.29.2",
|
|
33
33
|
"node-html-parser": "^7.1.0",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"yaml": "^2.8.3"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@nuasite/cms-sidecar": "0.46.
|
|
39
|
-
"@nuasite/collections-admin": "0.46.
|
|
38
|
+
"@nuasite/cms-sidecar": "0.46.4",
|
|
39
|
+
"@nuasite/collections-admin": "0.46.4",
|
|
40
40
|
"@babel/types": "^7.29.0",
|
|
41
41
|
"@types/react": "^19.2.7",
|
|
42
42
|
"@types/react-dom": "^19.2.3",
|
|
@@ -76,8 +76,8 @@
|
|
|
76
76
|
"typescript": "^6.0.2",
|
|
77
77
|
"vite": "^7.0.0",
|
|
78
78
|
"@aws-sdk/client-s3": "^3.0.0",
|
|
79
|
-
"@nuasite/cms-sidecar": "0.46.
|
|
80
|
-
"@nuasite/collections-admin": "0.46.
|
|
79
|
+
"@nuasite/cms-sidecar": "0.46.4",
|
|
80
|
+
"@nuasite/collections-admin": "0.46.4",
|
|
81
81
|
"react": "^19.0.0",
|
|
82
82
|
"react-dom": "^19.0.0"
|
|
83
83
|
},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
1
2
|
import type { CachedParsedFile, ImageIndexEntry, SearchIndexEntry, SourceLocation } from './types'
|
|
2
3
|
|
|
3
4
|
// ============================================================================
|
|
@@ -113,10 +114,16 @@ export function markFileDirty(absPath: string): void {
|
|
|
113
114
|
dirtyFiles.add(absPath)
|
|
114
115
|
// Also evict the parsed file cache so it's re-read from disk
|
|
115
116
|
parsedFileCache.delete(absPath)
|
|
116
|
-
// A changed file may add/remove/alter
|
|
117
|
-
// collection directory
|
|
118
|
-
//
|
|
119
|
-
|
|
117
|
+
// A changed file may add/remove/alter its declared URL, so drop the URL→file
|
|
118
|
+
// index for its collection directory. The index is keyed by collection dir:
|
|
119
|
+
// for a flat `<dir>/<slug>.md` that's the file's directory; for Hugo-style
|
|
120
|
+
// `<dir>/<slug>/index.md` it's the parent of the file's directory. Evict both
|
|
121
|
+
// candidates (deleting a non-existent key is a no-op) instead of clearing the
|
|
122
|
+
// whole cache, which would rebuild every collection's index on the next
|
|
123
|
+
// unmatched-page lookup.
|
|
124
|
+
const fileDir = path.dirname(absPath)
|
|
125
|
+
declaredUrlIndexCache.delete(fileDir)
|
|
126
|
+
declaredUrlIndexCache.delete(path.dirname(fileDir))
|
|
120
127
|
}
|
|
121
128
|
|
|
122
129
|
export function getDirtyFiles(): Set<string> {
|
|
@@ -300,7 +300,7 @@ export async function findCollectionSource(
|
|
|
300
300
|
// Prefer the entry whose declared canonical URL equals the requested
|
|
301
301
|
// path. Only kicks in when an entry actually declares a URL, so
|
|
302
302
|
// URL-less projects fall through to the filename logic unchanged.
|
|
303
|
-
const byUrl = await resolveByDeclaredUrl(matches, requestedUrl, contentPath)
|
|
303
|
+
const byUrl = await resolveByDeclaredUrl(matches, requestedUrl, contentPath, pathParts[0])
|
|
304
304
|
if (byUrl) {
|
|
305
305
|
// byUrl.file may differ from the file the filename match found
|
|
306
306
|
// (that's the whole point of this fallback) — its slug must be
|
|
@@ -331,6 +331,29 @@ export async function findCollectionSource(
|
|
|
331
331
|
}
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
+
// No filename-based candidate matched any tail slug. The source file may be
|
|
335
|
+
// named unlike its URL entirely — e.g. people entries stored as
|
|
336
|
+
// `<role>__<slug>.md` but served at `/<family>/<slug>`, so no tail segment
|
|
337
|
+
// ever hits a `<slug>.md` file. Fall back to resolving by declared canonical
|
|
338
|
+
// URL across every collection.
|
|
339
|
+
//
|
|
340
|
+
// Guarded to multi-segment paths: the tail-slug loop above only ran for
|
|
341
|
+
// `pathParts.length >= 2`, so single-segment paths (bare static pages like
|
|
342
|
+
// `/about`) were never treated as collection pages. Keeping that boundary
|
|
343
|
+
// avoids both a full declared-URL scan on every such page and the risk of
|
|
344
|
+
// mis-attributing a static page to a collection entry that happens to
|
|
345
|
+
// declare the same URL.
|
|
346
|
+
if (pathParts.length >= 2) {
|
|
347
|
+
const byDeclaredUrl = await findByDeclaredUrlAcross(collectionDirs, contentPath, requestedUrl, pathParts[0])
|
|
348
|
+
if (byDeclaredUrl) {
|
|
349
|
+
return {
|
|
350
|
+
name: byDeclaredUrl.name,
|
|
351
|
+
slug: slugFromFilePath(byDeclaredUrl.file),
|
|
352
|
+
file: path.relative(getProjectRoot(), byDeclaredUrl.file),
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
334
357
|
return undefined
|
|
335
358
|
}
|
|
336
359
|
|
|
@@ -428,6 +451,7 @@ async function resolveByDeclaredUrl(
|
|
|
428
451
|
matches: { name: string; file: string }[],
|
|
429
452
|
requestedUrl: string,
|
|
430
453
|
contentPath: string,
|
|
454
|
+
urlPrefix: string | undefined,
|
|
431
455
|
): Promise<{ name: string; file: string } | undefined> {
|
|
432
456
|
let sawDeclaredUrl = false
|
|
433
457
|
for (const m of matches) {
|
|
@@ -441,13 +465,30 @@ async function resolveByDeclaredUrl(
|
|
|
441
465
|
|
|
442
466
|
// Contradiction: the right entry is named differently from its slug. Scan
|
|
443
467
|
// the collection(s) that produced filename matches for a declared-URL hit.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
468
|
+
return findByDeclaredUrlAcross([...new Set(matches.map(m => m.name))], contentPath, requestedUrl, urlPrefix)
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Resolve `requestedUrl` to a source file by its declared canonical URL across
|
|
473
|
+
* the given collection directories, using the cached per-directory URL→file
|
|
474
|
+
* index. When more than one collection declares the same URL, a directory whose
|
|
475
|
+
* name equals the URL's first path segment wins; otherwise the sorted-first
|
|
476
|
+
* match is returned so the result is deterministic regardless of readdir order.
|
|
477
|
+
*/
|
|
478
|
+
async function findByDeclaredUrlAcross(
|
|
479
|
+
dirs: string[],
|
|
480
|
+
contentPath: string,
|
|
481
|
+
requestedUrl: string,
|
|
482
|
+
urlPrefix: string | undefined,
|
|
483
|
+
): Promise<{ name: string; file: string } | undefined> {
|
|
484
|
+
let firstHit: { name: string; file: string } | undefined
|
|
485
|
+
for (const dir of [...dirs].sort()) {
|
|
447
486
|
const hit = await findFileByDeclaredUrl(path.join(contentPath, dir), requestedUrl)
|
|
448
|
-
if (hit)
|
|
487
|
+
if (!hit) continue
|
|
488
|
+
if (dir === urlPrefix) return { name: dir, file: hit }
|
|
489
|
+
firstHit ??= { name: dir, file: hit }
|
|
449
490
|
}
|
|
450
|
-
return
|
|
491
|
+
return firstHit
|
|
451
492
|
}
|
|
452
493
|
|
|
453
494
|
/**
|