@roottale/cms-core 0.65.1 → 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 +13 -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/dist/index.d.cts
CHANGED
|
@@ -207,9 +207,17 @@ declare function validateCollections(collections: readonly RouteCollection[]): s
|
|
|
207
207
|
* FAQ·도움말·문서처럼 하나의 모델이 여러 단계 분류 허브를 가지는 경우에 쓴다.
|
|
208
208
|
* 저장소나 프레임워크를 모르며, 공개 API와 ROOT-ADMIN이 같은 계산을 재사용한다.
|
|
209
209
|
*/
|
|
210
|
+
/**
|
|
211
|
+
* 글을 붙일 수 있는 분류.
|
|
212
|
+
* - `deepest`(기본): `categoryDepth` 단계의 말단 분류에만 붙는다.
|
|
213
|
+
* - `leaf`: 하위 분류가 없는 분류면 단계와 무관하게 붙는다(`categoryDepth`는 최대 단계).
|
|
214
|
+
* 하위가 필요한 영역만 나누고 나머지는 상위 분류에 바로 글을 쓸 때 쓴다.
|
|
215
|
+
*/
|
|
216
|
+
type CategoryTreeEntryCategory = "deepest" | "leaf";
|
|
210
217
|
interface CategoryTreePresentation {
|
|
211
218
|
readonly basePath: string;
|
|
212
219
|
readonly categoryDepth: number;
|
|
220
|
+
readonly entryCategory?: CategoryTreeEntryCategory;
|
|
213
221
|
}
|
|
214
222
|
interface CategoryTreeTerm {
|
|
215
223
|
readonly id: string;
|
|
@@ -224,10 +232,19 @@ interface CategoryTreeEntry {
|
|
|
224
232
|
}>;
|
|
225
233
|
}
|
|
226
234
|
/**
|
|
227
|
-
*
|
|
228
|
-
*
|
|
235
|
+
* 글 주소에 쓰는 분류의 루트→분류 사슬. 주소를 만들 수 없으면 null.
|
|
236
|
+
*
|
|
237
|
+
* - `deepest`: 정확히 `categoryDepth` 단계의 말단이어야 한다.
|
|
238
|
+
* - `leaf`: `categoryDepth` 이하면 된다. 하위가 없는지는 *새로 고를 때*만 본다
|
|
239
|
+
* (`resolveCategoryTreeSelection`) — 글이 붙은 뒤 하위 분류가 생겨도 이미 발행한
|
|
240
|
+
* 글의 주소는 그대로 살아 있어야 한다.
|
|
241
|
+
*/
|
|
242
|
+
declare function resolveCategoryTreeChain(presentation: CategoryTreePresentation, termId: string, terms: readonly CategoryTreeTerm[]): CategoryTreeTerm[] | null;
|
|
243
|
+
/**
|
|
244
|
+
* 글에 새로 고를 수 있는 분류의 사슬 — 주소를 만들 수 있고 지금 하위 분류가 없어야
|
|
245
|
+
* 한다. 편집기 선택지와 발행 검사가 같은 규칙을 쓴다.
|
|
229
246
|
*/
|
|
230
|
-
declare function
|
|
247
|
+
declare function resolveCategoryTreeSelection(presentation: CategoryTreePresentation, termId: string, terms: readonly CategoryTreeTerm[]): CategoryTreeTerm[] | null;
|
|
231
248
|
/** 루트부터 선택 분류까지 모든 허브 주소. */
|
|
232
249
|
declare function resolveCategoryTreeHubPaths(presentation: CategoryTreePresentation, termId: string, terms: readonly CategoryTreeTerm[]): string[] | null;
|
|
233
250
|
/** 계층형 분류 모델 항목의 정규 상세 주소. */
|
|
@@ -258,6 +275,7 @@ type PublicPathPresentation = {
|
|
|
258
275
|
readonly kind: "category_tree";
|
|
259
276
|
readonly basePath: string;
|
|
260
277
|
readonly categoryDepth: number;
|
|
278
|
+
readonly entryCategory?: CategoryTreeEntryCategory;
|
|
261
279
|
};
|
|
262
280
|
interface PublicPathPost {
|
|
263
281
|
readonly slug: string;
|
|
@@ -612,4 +630,4 @@ declare function isSectionContentPropPath(sectionType: string, path: readonly (s
|
|
|
612
630
|
declare function findSectionLockViolations(beforeDoc: unknown, afterDoc: unknown): SectionLockViolation[];
|
|
613
631
|
declare function formatSectionLockViolations(violations: readonly SectionLockViolation[]): string;
|
|
614
632
|
|
|
615
|
-
export { BLOCK_NAME_PATTERN, type BindingResolver, type Block, type BlockBinding, type BlockDefinition, type BlockRegistry, CMS_FONT_SIZES, CMS_IMAGE_WIDTHS, CMS_LINE_HEIGHTS, CMS_PARAGRAPH_SPACINGS, type CategoryTreeEntry, type CategoryTreePresentation, type CategoryTreeTerm, type ClientHydrationSpec, DEFAULT_SITE_PATTERN_PRESENTATION, EMPTY_SITE_PATTERN_PLACEMENTS, type EmbedProvider, FIELD_BINDING_SOURCE, FIELD_BINDING_SOURCE_ALIAS, type FaqEntry, IMAGE_ALT_MAX_LENGTH, INTERNAL_CONTENT_LINK_CLASS, INTERNAL_CONTENT_LINK_PENDING_ATTR, INTERNAL_CONTENT_LINK_PENDING_CLASS, INTERNAL_CONTENT_LINK_TOKEN_SOURCE, type InternalContentLinkResolver, type InternalContentLinkToken, LEGACY_BLOG_DETAIL_PATH, type NormalizedEmbed, PHASE_1_CORE_BLOCKS, PHASE_1_CSP, POST_FOOTER_SLOT, type PatternSlots, type Phase1CoreBlockName, type PreviewTokenPayload, type PublicPathContext, type PublicPathPost, type PublicPathPresentation, type RoutablePost, type RouteCollection, SITE_PATTERN_BUTTON_COLORS_MAX, SITE_PATTERN_KEY_PATTERN, SITE_PATTERN_PLACEMENTS_KEY, SITE_PATTERN_SLOTS, type SectionLock, type SectionLockViolation, type SectionLockViolationCode, type SitePatternLayout, type SitePatternLinkStyle, type SitePatternPlacementRule, type SitePatternPlacements, type SitePatternPresentation, type SitePatternSlotKey, applyBlockBindings, bindingSrcValue, bindingTextValue, blockSchema, boundFieldValue, chainResolvers, cmsFontSize, cmsImageAlign, cmsImageStyle, cmsImageWidth, cmsLineHeight, cmsParagraphSpacing, createFieldBindingResolver, emptyPatternSlots, ensureImportedHtmlDocumentRoots, ensureStableIds, extractFaqEntries, faqPageJsonLd, findInternalContentLinkTokens, findSectionLockViolations, findSitePatternPlacementRule, formatSectionLockViolations, htmlToPlainText, injectStableIdsTree, internalContentKeyFromPath, internalContentLinkResolverFrom, internalContentPathIndex, isAllowedEmbedSrc, isAllowedMapEmbedSrc, isInCollectionMode, isSectionContentPropPath, isSitePatternSlotKey, isValidBlock, isValidSitePatternKey, issuePreviewToken, normalizeEmbed, normalizeHexColor, normalizeImageAlt, parseBlock, postsForCollection, postsInAnyCollection, postsNotInAnyCollection, readSitePatternPlacements, readSitePatternPresentation, referencedSitePatternKeys, renderInternalContentLinksInHtml, renderInternalContentLinksInText, resolveCategoryPath, resolveCategoryTreeChain, resolveCategoryTreeEntryPath, resolveCategoryTreeHubPaths, resolvePatternSlots, resolvePostCategorySlug, resolvePostCollection, resolvePostPath, resolvePostPublicPath, resolvePostUrl, sanitizeHtml, sanitizeImportedCss, sanitizeImportedHtml, scopeImportedCss, serializeBlock, setSitePatternPlacementRule, sitePatternButtonColor, sitePatternPresentationAttributes, validateCollections, verifyPreviewToken };
|
|
633
|
+
export { BLOCK_NAME_PATTERN, type BindingResolver, type Block, type BlockBinding, type BlockDefinition, type BlockRegistry, CMS_FONT_SIZES, CMS_IMAGE_WIDTHS, CMS_LINE_HEIGHTS, CMS_PARAGRAPH_SPACINGS, type CategoryTreeEntry, type CategoryTreeEntryCategory, type CategoryTreePresentation, type CategoryTreeTerm, type ClientHydrationSpec, DEFAULT_SITE_PATTERN_PRESENTATION, EMPTY_SITE_PATTERN_PLACEMENTS, type EmbedProvider, FIELD_BINDING_SOURCE, FIELD_BINDING_SOURCE_ALIAS, type FaqEntry, IMAGE_ALT_MAX_LENGTH, INTERNAL_CONTENT_LINK_CLASS, INTERNAL_CONTENT_LINK_PENDING_ATTR, INTERNAL_CONTENT_LINK_PENDING_CLASS, INTERNAL_CONTENT_LINK_TOKEN_SOURCE, type InternalContentLinkResolver, type InternalContentLinkToken, LEGACY_BLOG_DETAIL_PATH, type NormalizedEmbed, PHASE_1_CORE_BLOCKS, PHASE_1_CSP, POST_FOOTER_SLOT, type PatternSlots, type Phase1CoreBlockName, type PreviewTokenPayload, type PublicPathContext, type PublicPathPost, type PublicPathPresentation, type RoutablePost, type RouteCollection, SITE_PATTERN_BUTTON_COLORS_MAX, SITE_PATTERN_KEY_PATTERN, SITE_PATTERN_PLACEMENTS_KEY, SITE_PATTERN_SLOTS, type SectionLock, type SectionLockViolation, type SectionLockViolationCode, type SitePatternLayout, type SitePatternLinkStyle, type SitePatternPlacementRule, type SitePatternPlacements, type SitePatternPresentation, type SitePatternSlotKey, applyBlockBindings, bindingSrcValue, bindingTextValue, blockSchema, boundFieldValue, chainResolvers, cmsFontSize, cmsImageAlign, cmsImageStyle, cmsImageWidth, cmsLineHeight, cmsParagraphSpacing, createFieldBindingResolver, emptyPatternSlots, ensureImportedHtmlDocumentRoots, ensureStableIds, extractFaqEntries, faqPageJsonLd, findInternalContentLinkTokens, findSectionLockViolations, findSitePatternPlacementRule, formatSectionLockViolations, htmlToPlainText, injectStableIdsTree, internalContentKeyFromPath, internalContentLinkResolverFrom, internalContentPathIndex, isAllowedEmbedSrc, isAllowedMapEmbedSrc, isInCollectionMode, isSectionContentPropPath, isSitePatternSlotKey, isValidBlock, isValidSitePatternKey, issuePreviewToken, normalizeEmbed, normalizeHexColor, normalizeImageAlt, parseBlock, postsForCollection, postsInAnyCollection, postsNotInAnyCollection, readSitePatternPlacements, readSitePatternPresentation, referencedSitePatternKeys, renderInternalContentLinksInHtml, renderInternalContentLinksInText, resolveCategoryPath, resolveCategoryTreeChain, resolveCategoryTreeEntryPath, resolveCategoryTreeHubPaths, resolveCategoryTreeSelection, resolvePatternSlots, resolvePostCategorySlug, resolvePostCollection, resolvePostPath, resolvePostPublicPath, resolvePostUrl, sanitizeHtml, sanitizeImportedCss, sanitizeImportedHtml, scopeImportedCss, serializeBlock, setSitePatternPlacementRule, sitePatternButtonColor, sitePatternPresentationAttributes, validateCollections, verifyPreviewToken };
|
package/dist/index.d.ts
CHANGED
|
@@ -207,9 +207,17 @@ declare function validateCollections(collections: readonly RouteCollection[]): s
|
|
|
207
207
|
* FAQ·도움말·문서처럼 하나의 모델이 여러 단계 분류 허브를 가지는 경우에 쓴다.
|
|
208
208
|
* 저장소나 프레임워크를 모르며, 공개 API와 ROOT-ADMIN이 같은 계산을 재사용한다.
|
|
209
209
|
*/
|
|
210
|
+
/**
|
|
211
|
+
* 글을 붙일 수 있는 분류.
|
|
212
|
+
* - `deepest`(기본): `categoryDepth` 단계의 말단 분류에만 붙는다.
|
|
213
|
+
* - `leaf`: 하위 분류가 없는 분류면 단계와 무관하게 붙는다(`categoryDepth`는 최대 단계).
|
|
214
|
+
* 하위가 필요한 영역만 나누고 나머지는 상위 분류에 바로 글을 쓸 때 쓴다.
|
|
215
|
+
*/
|
|
216
|
+
type CategoryTreeEntryCategory = "deepest" | "leaf";
|
|
210
217
|
interface CategoryTreePresentation {
|
|
211
218
|
readonly basePath: string;
|
|
212
219
|
readonly categoryDepth: number;
|
|
220
|
+
readonly entryCategory?: CategoryTreeEntryCategory;
|
|
213
221
|
}
|
|
214
222
|
interface CategoryTreeTerm {
|
|
215
223
|
readonly id: string;
|
|
@@ -224,10 +232,19 @@ interface CategoryTreeEntry {
|
|
|
224
232
|
}>;
|
|
225
233
|
}
|
|
226
234
|
/**
|
|
227
|
-
*
|
|
228
|
-
*
|
|
235
|
+
* 글 주소에 쓰는 분류의 루트→분류 사슬. 주소를 만들 수 없으면 null.
|
|
236
|
+
*
|
|
237
|
+
* - `deepest`: 정확히 `categoryDepth` 단계의 말단이어야 한다.
|
|
238
|
+
* - `leaf`: `categoryDepth` 이하면 된다. 하위가 없는지는 *새로 고를 때*만 본다
|
|
239
|
+
* (`resolveCategoryTreeSelection`) — 글이 붙은 뒤 하위 분류가 생겨도 이미 발행한
|
|
240
|
+
* 글의 주소는 그대로 살아 있어야 한다.
|
|
241
|
+
*/
|
|
242
|
+
declare function resolveCategoryTreeChain(presentation: CategoryTreePresentation, termId: string, terms: readonly CategoryTreeTerm[]): CategoryTreeTerm[] | null;
|
|
243
|
+
/**
|
|
244
|
+
* 글에 새로 고를 수 있는 분류의 사슬 — 주소를 만들 수 있고 지금 하위 분류가 없어야
|
|
245
|
+
* 한다. 편집기 선택지와 발행 검사가 같은 규칙을 쓴다.
|
|
229
246
|
*/
|
|
230
|
-
declare function
|
|
247
|
+
declare function resolveCategoryTreeSelection(presentation: CategoryTreePresentation, termId: string, terms: readonly CategoryTreeTerm[]): CategoryTreeTerm[] | null;
|
|
231
248
|
/** 루트부터 선택 분류까지 모든 허브 주소. */
|
|
232
249
|
declare function resolveCategoryTreeHubPaths(presentation: CategoryTreePresentation, termId: string, terms: readonly CategoryTreeTerm[]): string[] | null;
|
|
233
250
|
/** 계층형 분류 모델 항목의 정규 상세 주소. */
|
|
@@ -258,6 +275,7 @@ type PublicPathPresentation = {
|
|
|
258
275
|
readonly kind: "category_tree";
|
|
259
276
|
readonly basePath: string;
|
|
260
277
|
readonly categoryDepth: number;
|
|
278
|
+
readonly entryCategory?: CategoryTreeEntryCategory;
|
|
261
279
|
};
|
|
262
280
|
interface PublicPathPost {
|
|
263
281
|
readonly slug: string;
|
|
@@ -612,4 +630,4 @@ declare function isSectionContentPropPath(sectionType: string, path: readonly (s
|
|
|
612
630
|
declare function findSectionLockViolations(beforeDoc: unknown, afterDoc: unknown): SectionLockViolation[];
|
|
613
631
|
declare function formatSectionLockViolations(violations: readonly SectionLockViolation[]): string;
|
|
614
632
|
|
|
615
|
-
export { BLOCK_NAME_PATTERN, type BindingResolver, type Block, type BlockBinding, type BlockDefinition, type BlockRegistry, CMS_FONT_SIZES, CMS_IMAGE_WIDTHS, CMS_LINE_HEIGHTS, CMS_PARAGRAPH_SPACINGS, type CategoryTreeEntry, type CategoryTreePresentation, type CategoryTreeTerm, type ClientHydrationSpec, DEFAULT_SITE_PATTERN_PRESENTATION, EMPTY_SITE_PATTERN_PLACEMENTS, type EmbedProvider, FIELD_BINDING_SOURCE, FIELD_BINDING_SOURCE_ALIAS, type FaqEntry, IMAGE_ALT_MAX_LENGTH, INTERNAL_CONTENT_LINK_CLASS, INTERNAL_CONTENT_LINK_PENDING_ATTR, INTERNAL_CONTENT_LINK_PENDING_CLASS, INTERNAL_CONTENT_LINK_TOKEN_SOURCE, type InternalContentLinkResolver, type InternalContentLinkToken, LEGACY_BLOG_DETAIL_PATH, type NormalizedEmbed, PHASE_1_CORE_BLOCKS, PHASE_1_CSP, POST_FOOTER_SLOT, type PatternSlots, type Phase1CoreBlockName, type PreviewTokenPayload, type PublicPathContext, type PublicPathPost, type PublicPathPresentation, type RoutablePost, type RouteCollection, SITE_PATTERN_BUTTON_COLORS_MAX, SITE_PATTERN_KEY_PATTERN, SITE_PATTERN_PLACEMENTS_KEY, SITE_PATTERN_SLOTS, type SectionLock, type SectionLockViolation, type SectionLockViolationCode, type SitePatternLayout, type SitePatternLinkStyle, type SitePatternPlacementRule, type SitePatternPlacements, type SitePatternPresentation, type SitePatternSlotKey, applyBlockBindings, bindingSrcValue, bindingTextValue, blockSchema, boundFieldValue, chainResolvers, cmsFontSize, cmsImageAlign, cmsImageStyle, cmsImageWidth, cmsLineHeight, cmsParagraphSpacing, createFieldBindingResolver, emptyPatternSlots, ensureImportedHtmlDocumentRoots, ensureStableIds, extractFaqEntries, faqPageJsonLd, findInternalContentLinkTokens, findSectionLockViolations, findSitePatternPlacementRule, formatSectionLockViolations, htmlToPlainText, injectStableIdsTree, internalContentKeyFromPath, internalContentLinkResolverFrom, internalContentPathIndex, isAllowedEmbedSrc, isAllowedMapEmbedSrc, isInCollectionMode, isSectionContentPropPath, isSitePatternSlotKey, isValidBlock, isValidSitePatternKey, issuePreviewToken, normalizeEmbed, normalizeHexColor, normalizeImageAlt, parseBlock, postsForCollection, postsInAnyCollection, postsNotInAnyCollection, readSitePatternPlacements, readSitePatternPresentation, referencedSitePatternKeys, renderInternalContentLinksInHtml, renderInternalContentLinksInText, resolveCategoryPath, resolveCategoryTreeChain, resolveCategoryTreeEntryPath, resolveCategoryTreeHubPaths, resolvePatternSlots, resolvePostCategorySlug, resolvePostCollection, resolvePostPath, resolvePostPublicPath, resolvePostUrl, sanitizeHtml, sanitizeImportedCss, sanitizeImportedHtml, scopeImportedCss, serializeBlock, setSitePatternPlacementRule, sitePatternButtonColor, sitePatternPresentationAttributes, validateCollections, verifyPreviewToken };
|
|
633
|
+
export { BLOCK_NAME_PATTERN, type BindingResolver, type Block, type BlockBinding, type BlockDefinition, type BlockRegistry, CMS_FONT_SIZES, CMS_IMAGE_WIDTHS, CMS_LINE_HEIGHTS, CMS_PARAGRAPH_SPACINGS, type CategoryTreeEntry, type CategoryTreeEntryCategory, type CategoryTreePresentation, type CategoryTreeTerm, type ClientHydrationSpec, DEFAULT_SITE_PATTERN_PRESENTATION, EMPTY_SITE_PATTERN_PLACEMENTS, type EmbedProvider, FIELD_BINDING_SOURCE, FIELD_BINDING_SOURCE_ALIAS, type FaqEntry, IMAGE_ALT_MAX_LENGTH, INTERNAL_CONTENT_LINK_CLASS, INTERNAL_CONTENT_LINK_PENDING_ATTR, INTERNAL_CONTENT_LINK_PENDING_CLASS, INTERNAL_CONTENT_LINK_TOKEN_SOURCE, type InternalContentLinkResolver, type InternalContentLinkToken, LEGACY_BLOG_DETAIL_PATH, type NormalizedEmbed, PHASE_1_CORE_BLOCKS, PHASE_1_CSP, POST_FOOTER_SLOT, type PatternSlots, type Phase1CoreBlockName, type PreviewTokenPayload, type PublicPathContext, type PublicPathPost, type PublicPathPresentation, type RoutablePost, type RouteCollection, SITE_PATTERN_BUTTON_COLORS_MAX, SITE_PATTERN_KEY_PATTERN, SITE_PATTERN_PLACEMENTS_KEY, SITE_PATTERN_SLOTS, type SectionLock, type SectionLockViolation, type SectionLockViolationCode, type SitePatternLayout, type SitePatternLinkStyle, type SitePatternPlacementRule, type SitePatternPlacements, type SitePatternPresentation, type SitePatternSlotKey, applyBlockBindings, bindingSrcValue, bindingTextValue, blockSchema, boundFieldValue, chainResolvers, cmsFontSize, cmsImageAlign, cmsImageStyle, cmsImageWidth, cmsLineHeight, cmsParagraphSpacing, createFieldBindingResolver, emptyPatternSlots, ensureImportedHtmlDocumentRoots, ensureStableIds, extractFaqEntries, faqPageJsonLd, findInternalContentLinkTokens, findSectionLockViolations, findSitePatternPlacementRule, formatSectionLockViolations, htmlToPlainText, injectStableIdsTree, internalContentKeyFromPath, internalContentLinkResolverFrom, internalContentPathIndex, isAllowedEmbedSrc, isAllowedMapEmbedSrc, isInCollectionMode, isSectionContentPropPath, isSitePatternSlotKey, isValidBlock, isValidSitePatternKey, issuePreviewToken, normalizeEmbed, normalizeHexColor, normalizeImageAlt, parseBlock, postsForCollection, postsInAnyCollection, postsNotInAnyCollection, readSitePatternPlacements, readSitePatternPresentation, referencedSitePatternKeys, renderInternalContentLinksInHtml, renderInternalContentLinksInText, resolveCategoryPath, resolveCategoryTreeChain, resolveCategoryTreeEntryPath, resolveCategoryTreeHubPaths, resolveCategoryTreeSelection, resolvePatternSlots, resolvePostCategorySlug, resolvePostCollection, resolvePostPath, resolvePostPublicPath, resolvePostUrl, sanitizeHtml, sanitizeImportedCss, sanitizeImportedHtml, scopeImportedCss, serializeBlock, setSitePatternPlacementRule, sitePatternButtonColor, sitePatternPresentationAttributes, validateCollections, verifyPreviewToken };
|
package/dist/index.js
CHANGED
|
@@ -225,39 +225,51 @@ function validateCollections(collections) {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
// src/category-tree.ts
|
|
228
|
-
function
|
|
228
|
+
function basePathPrefix(basePath) {
|
|
229
|
+
if (!basePath.trim()) return null;
|
|
229
230
|
return basePath.replace(/\/+$/, "");
|
|
230
231
|
}
|
|
231
|
-
function
|
|
232
|
-
if (!Number.isInteger(
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
232
|
+
function categoryTreeAncestry(categoryDepth, termId, terms) {
|
|
233
|
+
if (!Number.isInteger(categoryDepth) || categoryDepth < 1) return null;
|
|
235
234
|
const termsById = new Map(terms.map((term) => [term.id, term]));
|
|
236
235
|
if (termsById.size !== terms.length) return null;
|
|
237
|
-
if (terms.some((term) => term.parentId === leafId)) return null;
|
|
238
236
|
const reversed = [];
|
|
239
237
|
const visited = /* @__PURE__ */ new Set();
|
|
240
|
-
let currentId =
|
|
238
|
+
let currentId = termId;
|
|
241
239
|
while (currentId) {
|
|
242
240
|
if (visited.has(currentId)) return null;
|
|
243
241
|
visited.add(currentId);
|
|
244
242
|
const current = termsById.get(currentId);
|
|
245
243
|
if (!current || !current.slug) return null;
|
|
246
244
|
reversed.push(current);
|
|
245
|
+
if (reversed.length > categoryDepth) return null;
|
|
247
246
|
currentId = current.parentId ?? null;
|
|
248
247
|
}
|
|
249
|
-
if (reversed.length !== presentation.categoryDepth) return null;
|
|
250
248
|
return reversed.reverse();
|
|
251
249
|
}
|
|
250
|
+
function hasChildCategory(termId, terms) {
|
|
251
|
+
return terms.some((term) => term.parentId === termId);
|
|
252
|
+
}
|
|
253
|
+
function resolveCategoryTreeChain(presentation, termId, terms) {
|
|
254
|
+
const chain = categoryTreeAncestry(presentation.categoryDepth, termId, terms);
|
|
255
|
+
if (!chain) return null;
|
|
256
|
+
if (presentation.entryCategory === "leaf") return chain;
|
|
257
|
+
if (hasChildCategory(termId, terms)) return null;
|
|
258
|
+
return chain.length === presentation.categoryDepth ? chain : null;
|
|
259
|
+
}
|
|
260
|
+
function resolveCategoryTreeSelection(presentation, termId, terms) {
|
|
261
|
+
if (hasChildCategory(termId, terms)) return null;
|
|
262
|
+
return resolveCategoryTreeChain(presentation, termId, terms);
|
|
263
|
+
}
|
|
252
264
|
function resolveCategoryTreeHubPaths(presentation, termId, terms) {
|
|
253
265
|
const chain = resolveCategoryTreeChain(presentation, termId, terms);
|
|
254
|
-
const
|
|
255
|
-
if (!chain ||
|
|
256
|
-
const paths = [
|
|
266
|
+
const prefix = basePathPrefix(presentation.basePath);
|
|
267
|
+
if (!chain || prefix === null) return null;
|
|
268
|
+
const paths = [prefix || "/"];
|
|
257
269
|
const segments = [];
|
|
258
270
|
for (const term of chain) {
|
|
259
271
|
segments.push(encodeURIComponent(term.slug));
|
|
260
|
-
paths.push(`${
|
|
272
|
+
paths.push(`${prefix}/${segments.join("/")}`);
|
|
261
273
|
}
|
|
262
274
|
return paths;
|
|
263
275
|
}
|
|
@@ -1912,6 +1924,7 @@ export {
|
|
|
1912
1924
|
resolveCategoryTreeChain,
|
|
1913
1925
|
resolveCategoryTreeEntryPath,
|
|
1914
1926
|
resolveCategoryTreeHubPaths,
|
|
1927
|
+
resolveCategoryTreeSelection,
|
|
1915
1928
|
resolvePatternSlots,
|
|
1916
1929
|
resolvePostCategorySlug,
|
|
1917
1930
|
resolvePostCollection,
|