@roottale/cms-core 0.65.0 → 0.66.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/CHANGELOG.md +15 -0
- package/dist/index.cjs +26 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -4
- package/dist/index.d.ts +22 -4
- package/dist/index.js +25 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @roottale/cms-core
|
|
2
2
|
|
|
3
|
+
## 0.66.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- a58c5d2: 계층형 분류 모델(`category_tree`)에 `entryCategory: "leaf"`를 추가한다. 하위 분류가 없는
|
|
8
|
+
분류면 단계와 무관하게 글을 붙일 수 있고(`categoryDepth`는 최대 단계), 새로 고를 때는
|
|
9
|
+
`resolveCategoryTreeSelection`으로 하위가 없는지 확인한다. 생략하면 기존처럼
|
|
10
|
+
`categoryDepth` 단계 말단에만 붙는다.
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- d5ef48e: `basePath: "/"`인 계층형 분류 모델(`category_tree`)도 허브·상세 주소를 계산합니다. 이전에는 루트를 빈 basePath(주소 없음)와 같게 보아 `resolveCategoryTreeHubPaths`·`resolveCategoryTreeEntryPath`·`resolvePostPublicPath`가 `null`을 돌려주었고, 웹훅에 상세 경로가 빠져 글 상세 캐시가 갱신되지 않았습니다.
|
|
15
|
+
|
|
16
|
+
## 0.65.1
|
|
17
|
+
|
|
3
18
|
## 0.65.0
|
|
4
19
|
|
|
5
20
|
## 0.64.0
|
package/dist/index.cjs
CHANGED
|
@@ -103,6 +103,7 @@ __export(src_exports, {
|
|
|
103
103
|
resolveCategoryTreeChain: () => resolveCategoryTreeChain,
|
|
104
104
|
resolveCategoryTreeEntryPath: () => resolveCategoryTreeEntryPath,
|
|
105
105
|
resolveCategoryTreeHubPaths: () => resolveCategoryTreeHubPaths,
|
|
106
|
+
resolveCategoryTreeSelection: () => resolveCategoryTreeSelection,
|
|
106
107
|
resolvePatternSlots: () => resolvePatternSlots,
|
|
107
108
|
resolvePostCategorySlug: () => resolvePostCategorySlug,
|
|
108
109
|
resolvePostCollection: () => resolvePostCollection,
|
|
@@ -349,39 +350,51 @@ function validateCollections(collections) {
|
|
|
349
350
|
}
|
|
350
351
|
|
|
351
352
|
// src/category-tree.ts
|
|
352
|
-
function
|
|
353
|
+
function basePathPrefix(basePath) {
|
|
354
|
+
if (!basePath.trim()) return null;
|
|
353
355
|
return basePath.replace(/\/+$/, "");
|
|
354
356
|
}
|
|
355
|
-
function
|
|
356
|
-
if (!Number.isInteger(
|
|
357
|
-
return null;
|
|
358
|
-
}
|
|
357
|
+
function categoryTreeAncestry(categoryDepth, termId, terms) {
|
|
358
|
+
if (!Number.isInteger(categoryDepth) || categoryDepth < 1) return null;
|
|
359
359
|
const termsById = new Map(terms.map((term) => [term.id, term]));
|
|
360
360
|
if (termsById.size !== terms.length) return null;
|
|
361
|
-
if (terms.some((term) => term.parentId === leafId)) return null;
|
|
362
361
|
const reversed = [];
|
|
363
362
|
const visited = /* @__PURE__ */ new Set();
|
|
364
|
-
let currentId =
|
|
363
|
+
let currentId = termId;
|
|
365
364
|
while (currentId) {
|
|
366
365
|
if (visited.has(currentId)) return null;
|
|
367
366
|
visited.add(currentId);
|
|
368
367
|
const current = termsById.get(currentId);
|
|
369
368
|
if (!current || !current.slug) return null;
|
|
370
369
|
reversed.push(current);
|
|
370
|
+
if (reversed.length > categoryDepth) return null;
|
|
371
371
|
currentId = current.parentId ?? null;
|
|
372
372
|
}
|
|
373
|
-
if (reversed.length !== presentation.categoryDepth) return null;
|
|
374
373
|
return reversed.reverse();
|
|
375
374
|
}
|
|
375
|
+
function hasChildCategory(termId, terms) {
|
|
376
|
+
return terms.some((term) => term.parentId === termId);
|
|
377
|
+
}
|
|
378
|
+
function resolveCategoryTreeChain(presentation, termId, terms) {
|
|
379
|
+
const chain = categoryTreeAncestry(presentation.categoryDepth, termId, terms);
|
|
380
|
+
if (!chain) return null;
|
|
381
|
+
if (presentation.entryCategory === "leaf") return chain;
|
|
382
|
+
if (hasChildCategory(termId, terms)) return null;
|
|
383
|
+
return chain.length === presentation.categoryDepth ? chain : null;
|
|
384
|
+
}
|
|
385
|
+
function resolveCategoryTreeSelection(presentation, termId, terms) {
|
|
386
|
+
if (hasChildCategory(termId, terms)) return null;
|
|
387
|
+
return resolveCategoryTreeChain(presentation, termId, terms);
|
|
388
|
+
}
|
|
376
389
|
function resolveCategoryTreeHubPaths(presentation, termId, terms) {
|
|
377
390
|
const chain = resolveCategoryTreeChain(presentation, termId, terms);
|
|
378
|
-
const
|
|
379
|
-
if (!chain ||
|
|
380
|
-
const paths = [
|
|
391
|
+
const prefix = basePathPrefix(presentation.basePath);
|
|
392
|
+
if (!chain || prefix === null) return null;
|
|
393
|
+
const paths = [prefix || "/"];
|
|
381
394
|
const segments = [];
|
|
382
395
|
for (const term of chain) {
|
|
383
396
|
segments.push(encodeURIComponent(term.slug));
|
|
384
|
-
paths.push(`${
|
|
397
|
+
paths.push(`${prefix}/${segments.join("/")}`);
|
|
385
398
|
}
|
|
386
399
|
return paths;
|
|
387
400
|
}
|
|
@@ -2037,6 +2050,7 @@ function formatSectionLockViolations(violations) {
|
|
|
2037
2050
|
resolveCategoryTreeChain,
|
|
2038
2051
|
resolveCategoryTreeEntryPath,
|
|
2039
2052
|
resolveCategoryTreeHubPaths,
|
|
2053
|
+
resolveCategoryTreeSelection,
|
|
2040
2054
|
resolvePatternSlots,
|
|
2041
2055
|
resolvePostCategorySlug,
|
|
2042
2056
|
resolvePostCollection,
|