@decocms/start 2.0.0 → 2.0.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/package.json +1 -1
- package/src/cms/loader.ts +36 -10
package/package.json
CHANGED
package/src/cms/loader.ts
CHANGED
|
@@ -127,9 +127,25 @@ export function withBlocksOverride<T>(override: Record<string, unknown>, fn: ()
|
|
|
127
127
|
return blocksOverrideStorage.run(override, fn);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
// Higher key wins. Compared lexicographically:
|
|
131
|
+
// [literalSegments, paramSegments, hasNoSplat]
|
|
132
|
+
// So `/foo/bar` > `/foo/:x` > `/foo/*` > `/*`, and `/my-account/*` > `/*`.
|
|
133
|
+
function pathSpecificityKey(path: string): [number, number, number] {
|
|
134
|
+
const parts = path.split("/").filter(Boolean);
|
|
135
|
+
let literals = 0;
|
|
136
|
+
let params = 0;
|
|
137
|
+
let hasSplat = false;
|
|
138
|
+
for (const part of parts) {
|
|
139
|
+
if (part === "*") hasSplat = true;
|
|
140
|
+
else if (part.startsWith(":") || part.startsWith("$")) params++;
|
|
141
|
+
else literals++;
|
|
142
|
+
}
|
|
143
|
+
return [literals, params, hasSplat ? 0 : 1];
|
|
144
|
+
}
|
|
145
|
+
|
|
130
146
|
export function getAllPages(): Array<{ key: string; page: DecoPage }> {
|
|
131
147
|
const blocks = loadBlocks();
|
|
132
|
-
const pages: Array<{ key: string; page: DecoPage;
|
|
148
|
+
const pages: Array<{ key: string; page: DecoPage; key2: [number, number, number] }> = [];
|
|
133
149
|
|
|
134
150
|
for (const [key, block] of Object.entries(blocks)) {
|
|
135
151
|
if (!key.startsWith("pages-")) continue;
|
|
@@ -137,16 +153,16 @@ export function getAllPages(): Array<{ key: string; page: DecoPage }> {
|
|
|
137
153
|
if (!page.sections) continue;
|
|
138
154
|
if (!page.path) continue;
|
|
139
155
|
|
|
140
|
-
|
|
141
|
-
if (page.path === "/*") specificity = 0;
|
|
142
|
-
else if (page.path.includes(":") || page.path.includes("$")) specificity = 1;
|
|
143
|
-
else specificity = 2;
|
|
144
|
-
|
|
145
|
-
pages.push({ key, page, specificity });
|
|
156
|
+
pages.push({ key, page, key2: pathSpecificityKey(page.path) });
|
|
146
157
|
}
|
|
147
158
|
|
|
148
159
|
return pages
|
|
149
|
-
.sort((a, b) =>
|
|
160
|
+
.sort((a, b) => {
|
|
161
|
+
for (let i = 0; i < a.key2.length; i++) {
|
|
162
|
+
if (a.key2[i] !== b.key2[i]) return b.key2[i] - a.key2[i];
|
|
163
|
+
}
|
|
164
|
+
return 0;
|
|
165
|
+
})
|
|
150
166
|
.map(({ key, page }) => ({ key, page }));
|
|
151
167
|
}
|
|
152
168
|
|
|
@@ -156,16 +172,26 @@ function matchPath(pattern: string, urlPath: string): Record<string, string> | n
|
|
|
156
172
|
const patternParts = pattern.split("/").filter(Boolean);
|
|
157
173
|
const urlParts = urlPath.split("/").filter(Boolean);
|
|
158
174
|
|
|
159
|
-
|
|
175
|
+
// Trailing `*` means "match this prefix and any remaining segments".
|
|
176
|
+
const hasSplat = patternParts[patternParts.length - 1] === "*";
|
|
177
|
+
const fixedLen = hasSplat ? patternParts.length - 1 : patternParts.length;
|
|
178
|
+
|
|
179
|
+
if (hasSplat) {
|
|
180
|
+
if (urlParts.length < fixedLen) return null;
|
|
181
|
+
} else if (urlParts.length !== fixedLen) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
160
184
|
|
|
161
185
|
const params: Record<string, string> = {};
|
|
162
|
-
for (let i = 0; i <
|
|
186
|
+
for (let i = 0; i < fixedLen; i++) {
|
|
163
187
|
const pp = patternParts[i];
|
|
164
188
|
const up = urlParts[i];
|
|
165
189
|
if (pp.startsWith(":")) params[pp.slice(1)] = up;
|
|
166
190
|
else if (pp !== up) return null;
|
|
167
191
|
}
|
|
168
192
|
|
|
193
|
+
if (hasSplat) params._splat = urlParts.slice(fixedLen).join("/");
|
|
194
|
+
|
|
169
195
|
return params;
|
|
170
196
|
}
|
|
171
197
|
|