@decocms/blocks 7.66.6 → 7.66.7
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/cms/loader.test.ts +73 -0
- package/src/cms/loader.ts +31 -1
package/package.json
CHANGED
package/src/cms/loader.test.ts
CHANGED
|
@@ -222,6 +222,79 @@ describe("findPageByPath specificity", () => {
|
|
|
222
222
|
});
|
|
223
223
|
});
|
|
224
224
|
|
|
225
|
+
describe("getAllPages — page blocks without the `pages-` prefix", () => {
|
|
226
|
+
afterEach(() => {
|
|
227
|
+
setBlocks({});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("routes a page block whose key lacks the prefix", () => {
|
|
231
|
+
// Decofiles carried over from Deco on Fresh hold page blocks under
|
|
232
|
+
// arbitrary keys: renaming a page in the CMS renames its snapshot file,
|
|
233
|
+
// and the key follows the filename. Fresh enumerated pages by
|
|
234
|
+
// __resolveType, so these routed fine there.
|
|
235
|
+
setBlocks({
|
|
236
|
+
"plp-verao": {
|
|
237
|
+
name: "Verão",
|
|
238
|
+
path: "/verao",
|
|
239
|
+
sections: [],
|
|
240
|
+
__resolveType: "website/pages/Page.tsx",
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const match = findPageByPath("/verao");
|
|
245
|
+
expect(match?.blockKey).toBe("plp-verao");
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("still ranks by path specificity across both key shapes", () => {
|
|
249
|
+
setBlocks({
|
|
250
|
+
"pages-catch-all": {
|
|
251
|
+
name: "Catch all",
|
|
252
|
+
path: "/*",
|
|
253
|
+
sections: [],
|
|
254
|
+
},
|
|
255
|
+
"plp-inverno": {
|
|
256
|
+
name: "Inverno",
|
|
257
|
+
path: "/inverno",
|
|
258
|
+
sections: [],
|
|
259
|
+
__resolveType: "website/pages/Page.tsx",
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// The literal must win over the catch-all regardless of which one
|
|
264
|
+
// carries the prefix.
|
|
265
|
+
expect(findPageByPath("/inverno")?.blockKey).toBe("plp-inverno");
|
|
266
|
+
expect(findPageByPath("/qualquer-outra")?.blockKey).toBe("pages-catch-all");
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("ignores non-page blocks that happen to carry a path", () => {
|
|
270
|
+
// A loader block is not a page: no __resolveType match, no prefix.
|
|
271
|
+
setBlocks({
|
|
272
|
+
"some-loader": {
|
|
273
|
+
name: "Not a page",
|
|
274
|
+
path: "/not-a-page",
|
|
275
|
+
sections: [],
|
|
276
|
+
__resolveType: "site/loaders/whatever.ts",
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
expect(findPageByPath("/not-a-page")).toBeNull();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it("keeps honouring the prefix when there is no __resolveType", () => {
|
|
284
|
+
// The admin emits prefixed keys and does not always write a
|
|
285
|
+
// __resolveType onto the snapshot — the fast path must still apply.
|
|
286
|
+
setBlocks({
|
|
287
|
+
"pages-sem-tipo": {
|
|
288
|
+
name: "Sem tipo",
|
|
289
|
+
path: "/sem-tipo",
|
|
290
|
+
sections: [],
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
expect(findPageByPath("/sem-tipo")?.blockKey).toBe("pages-sem-tipo");
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
225
298
|
describe("loadBlocks draft override — key percent-encoding", () => {
|
|
226
299
|
// The published decofile encodes special characters in block keys
|
|
227
300
|
// (`pages-Home%20(principal)-1`); the Studio draft emits them raw
|
package/src/cms/loader.ts
CHANGED
|
@@ -282,6 +282,36 @@ function pathSpecificityKey(path: string): [number, number, number] {
|
|
|
282
282
|
return [hasWildcard ? 0 : 1, literals, params];
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
// Literal rather than WELL_KNOWN_TYPES.PAGE: resolve.ts already imports from
|
|
286
|
+
// this module, so importing back would close a cycle.
|
|
287
|
+
const PAGE_RESOLVE_TYPE = "website/pages/Page.tsx";
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Is this block a page?
|
|
291
|
+
*
|
|
292
|
+
* The `pages-` prefix is kept as a fast path because it is what the admin
|
|
293
|
+
* emits and it short-circuits the vast majority of blocks without a property
|
|
294
|
+
* read. But it cannot be the *only* test: a decofile carried over from Deco on
|
|
295
|
+
* Fresh can hold page blocks under any key — renaming one in the CMS renames
|
|
296
|
+
* its snapshot file, and `loadDecofileDirectory` preserves whatever key the
|
|
297
|
+
* filename already had.
|
|
298
|
+
*
|
|
299
|
+
* Those blocks are pages in every way that matters (`website/pages/Page.tsx`,
|
|
300
|
+
* a `path`, `sections`), and on Fresh they routed fine: `website/loaders/pages.ts`
|
|
301
|
+
* enumerated by `__resolveType`, not by key. Filtering on the prefix alone makes
|
|
302
|
+
* them invisible, so every one of their URLs falls through to whatever catch-all
|
|
303
|
+
* the site has — usually a 404 — and they disappear from the CMS sitemap too.
|
|
304
|
+
* One storefront in this state has 205 such blocks against 107 prefixed ones.
|
|
305
|
+
*/
|
|
306
|
+
function isPageBlock(key: string, block: unknown): boolean {
|
|
307
|
+
if (key.startsWith("pages-")) return true;
|
|
308
|
+
return (
|
|
309
|
+
typeof block === "object" &&
|
|
310
|
+
block !== null &&
|
|
311
|
+
(block as Resolvable).__resolveType === PAGE_RESOLVE_TYPE
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
285
315
|
export function getAllPages(): Array<{ key: string; page: DecoPage }> {
|
|
286
316
|
const blocks = loadBlocks();
|
|
287
317
|
const pages: Array<{
|
|
@@ -291,7 +321,7 @@ export function getAllPages(): Array<{ key: string; page: DecoPage }> {
|
|
|
291
321
|
}> = [];
|
|
292
322
|
|
|
293
323
|
for (const [key, block] of Object.entries(blocks)) {
|
|
294
|
-
if (!key
|
|
324
|
+
if (!isPageBlock(key, block)) continue;
|
|
295
325
|
const page = block as DecoPage;
|
|
296
326
|
if (!page.sections) continue;
|
|
297
327
|
if (!page.path) continue;
|