@okf/ootils 1.27.0 → 1.28.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/dist/browser.mjs CHANGED
@@ -1014,6 +1014,7 @@ var buildFilterConfigurations = ({ groups, type, selectedTpls, allTpls, isRollup
1014
1014
  filterKey,
1015
1015
  contentType: element.contentType,
1016
1016
  path: element.valuePath,
1017
+ ...element.comp && { comp: element.comp },
1017
1018
  source: {
1018
1019
  filterType: "tplType",
1019
1020
  contentType: element.contentType,
@@ -1039,6 +1040,7 @@ var buildFilterConfigurations = ({ groups, type, selectedTpls, allTpls, isRollup
1039
1040
  filterKey: valuePathFilterKey,
1040
1041
  contentType: element.contentType,
1041
1042
  path: element.valuePath,
1043
+ ...element.comp && { comp: element.comp },
1042
1044
  source: {
1043
1045
  filterType: "tplType",
1044
1046
  contentType: element.contentType,
@@ -1064,6 +1066,7 @@ var buildFilterConfigurations = ({ groups, type, selectedTpls, allTpls, isRollup
1064
1066
  filterKey: dateFilterKey,
1065
1067
  contentType: element.contentType,
1066
1068
  path: element.valuePath,
1069
+ ...element.comp && { comp: element.comp },
1067
1070
  source: { filterType: "dateRangeType" },
1068
1071
  target: { filterType: "dateRangeType", valuePath: element.valuePath }
1069
1072
  };
@@ -1081,6 +1084,7 @@ var buildFilterConfigurations = ({ groups, type, selectedTpls, allTpls, isRollup
1081
1084
  filterKey: numberFilterKey,
1082
1085
  contentType: element.contentType,
1083
1086
  path: element.valuePath,
1087
+ ...element.comp && { comp: element.comp },
1084
1088
  source: { filterType: "numberRangeType", valuePath: element.valuePath },
1085
1089
  target: { filterType: "numberRangeType", valuePath: element.valuePath }
1086
1090
  };
@@ -1201,6 +1205,7 @@ var buildFilterConfigurations = ({ groups, type, selectedTpls, allTpls, isRollup
1201
1205
  filterKey: tagFilterKey,
1202
1206
  contentType: element.tagType,
1203
1207
  path: `tags.${element.tagType}`,
1208
+ ...element.comp && { comp: element.comp },
1204
1209
  source: allProfileTpls.some(
1205
1210
  (tpl) => tpl.kp_content_type === element.tagType
1206
1211
  ) ? {
@@ -1342,6 +1347,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls) => {
1342
1347
  contentType: tpl.kp_content_type,
1343
1348
  blocks: allBlocks.filter((block) => block.valuePath.startsWith("tags.")).map((block) => ({
1344
1349
  tagType: block.props.tagType,
1350
+ comp: block.comp,
1345
1351
  filterType: "tagType"
1346
1352
  }))
1347
1353
  };
@@ -1369,6 +1375,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls) => {
1369
1375
  value: block.valuePath,
1370
1376
  saveValueAsString: block.props?.saveValueAsString,
1371
1377
  contentType: tpl.kp_content_type,
1378
+ comp: block.comp,
1372
1379
  filterType: "valuePathType"
1373
1380
  }))
1374
1381
  };
@@ -1383,6 +1390,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls) => {
1383
1390
  value: block.valuePath,
1384
1391
  saveValueAsString: block.props?.saveValueAsString,
1385
1392
  contentType: tpl.kp_content_type,
1393
+ comp: block.comp,
1386
1394
  block,
1387
1395
  filterType: "split_valuePathType"
1388
1396
  }))
@@ -1397,6 +1405,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls) => {
1397
1405
  display: block.props?.shortLabel || block.props?.label || block.valuePath,
1398
1406
  value: block.valuePath,
1399
1407
  contentType: tpl.kp_content_type,
1408
+ comp: block.comp,
1400
1409
  filterType: "dateRangeType"
1401
1410
  }))
1402
1411
  };
@@ -1410,6 +1419,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls) => {
1410
1419
  display: block.props?.shortLabel || block.props?.label || block.valuePath,
1411
1420
  value: block.valuePath,
1412
1421
  contentType: tpl.kp_content_type,
1422
+ comp: block.comp,
1413
1423
  filterType: "numberRangeType"
1414
1424
  }))
1415
1425
  };
@@ -1656,6 +1666,240 @@ var _self_managed_buildAnnoHierarchyConfig = ({
1656
1666
  };
1657
1667
  };
1658
1668
 
1669
+ // src/utils/autoGenFilterConfigsFromTpl/utils/buildTagTypeParentMap.ts
1670
+ var buildTagTypeParentMap = (tagTypesInGroup, allTpls) => {
1671
+ const tagTypeSet = new Set(tagTypesInGroup);
1672
+ const parentMap = /* @__PURE__ */ new Map();
1673
+ for (const tagType of tagTypesInGroup) {
1674
+ const tpl = allTpls.find((t) => t.kp_content_type === tagType);
1675
+ if (!tpl) continue;
1676
+ const blocks = extractAllBlocksFromTpl({ tpl });
1677
+ const tagBlocks = blocks.filter(
1678
+ (block) => block.valuePath?.startsWith("tags.") && block.props?.tagType
1679
+ );
1680
+ for (const block of tagBlocks) {
1681
+ const referencedTagType = block.props.tagType;
1682
+ if (tagTypeSet.has(referencedTagType) && referencedTagType !== tagType) {
1683
+ parentMap.set(tagType, referencedTagType);
1684
+ break;
1685
+ }
1686
+ }
1687
+ }
1688
+ for (const child of parentMap.keys()) {
1689
+ const visited = /* @__PURE__ */ new Set();
1690
+ let current = child;
1691
+ while (current && parentMap.has(current)) {
1692
+ if (visited.has(current)) {
1693
+ parentMap.delete(current);
1694
+ break;
1695
+ }
1696
+ visited.add(current);
1697
+ current = parentMap.get(current);
1698
+ }
1699
+ }
1700
+ return parentMap;
1701
+ };
1702
+ var attachParentFields = (filters, allTpls) => {
1703
+ const tagTypeFilters = filters.filter(
1704
+ (f) => f.source?.filterType === "tagType" && f.source?.tagType
1705
+ );
1706
+ if (tagTypeFilters.length === 0) return filters;
1707
+ const tagTypesInGroup = tagTypeFilters.map((f) => f.source.tagType);
1708
+ const parentMap = buildTagTypeParentMap(tagTypesInGroup, allTpls);
1709
+ if (parentMap.size === 0) return filters;
1710
+ const tagTypeToFilterId = /* @__PURE__ */ new Map();
1711
+ for (const f of tagTypeFilters) {
1712
+ tagTypeToFilterId.set(f.source.tagType, f.filterId);
1713
+ }
1714
+ return filters.map((f) => {
1715
+ if (f.source?.filterType !== "tagType" || !f.source?.tagType) return f;
1716
+ const parentTagType = parentMap.get(f.source.tagType);
1717
+ if (!parentTagType) return f;
1718
+ const parentFilterId = tagTypeToFilterId.get(parentTagType);
1719
+ if (!parentFilterId) return f;
1720
+ return { ...f, parentFilterId };
1721
+ });
1722
+ };
1723
+ var sortFiltersHierarchically = (filters) => {
1724
+ if (filters.length <= 1) return filters;
1725
+ const hasHierarchy = filters.some((f) => f.parentFilterId);
1726
+ if (!hasHierarchy) return filters;
1727
+ const childrenOf = /* @__PURE__ */ new Map();
1728
+ const roots = [];
1729
+ for (const f of filters) {
1730
+ if (!f.parentFilterId) {
1731
+ roots.push(f);
1732
+ } else {
1733
+ const siblings = childrenOf.get(f.parentFilterId) || [];
1734
+ siblings.push(f);
1735
+ childrenOf.set(f.parentFilterId, siblings);
1736
+ }
1737
+ }
1738
+ const sorted = [];
1739
+ const visited = /* @__PURE__ */ new Set();
1740
+ const visit = (filter) => {
1741
+ if (visited.has(filter.filterId)) return;
1742
+ visited.add(filter.filterId);
1743
+ sorted.push(filter);
1744
+ const children = childrenOf.get(filter.filterId) || [];
1745
+ for (const child of children) {
1746
+ visit(child);
1747
+ }
1748
+ };
1749
+ for (const root of roots) {
1750
+ visit(root);
1751
+ }
1752
+ for (const f of filters) {
1753
+ if (!visited.has(f.filterId)) {
1754
+ sorted.push(f);
1755
+ }
1756
+ }
1757
+ return sorted;
1758
+ };
1759
+
1760
+ // src/utils/autoGenFilterConfigsFromTpl/utils/_self_managed_buildDocHierarchyConfig.ts
1761
+ var _self_managed_buildDocHierarchyConfig = ({
1762
+ combinedDocumentBlocks,
1763
+ docRollupBlocks,
1764
+ selectedTpls,
1765
+ allTpls,
1766
+ commonDocumentFilters,
1767
+ flatDocFilters = false
1768
+ }) => {
1769
+ const allGroups = compareAndGroupBlocks(combinedDocumentBlocks);
1770
+ const commonGroup = allGroups.find(
1771
+ (g) => g.contentTypes.length === selectedTpls.length
1772
+ );
1773
+ const commonFilterConfigs = commonGroup ? sortFiltersHierarchically(
1774
+ attachParentFields(
1775
+ buildFilterConfigurations({
1776
+ groups: [commonGroup],
1777
+ type: "tags",
1778
+ selectedTpls,
1779
+ allTpls,
1780
+ isRollup: false,
1781
+ isAnno: false
1782
+ }).flatMap((s) => s.configs),
1783
+ allTpls
1784
+ )
1785
+ ) : [];
1786
+ const multiDatasetGroups = selectedTpls.length >= 2 ? allGroups.filter(
1787
+ (g) => g.contentTypes.length > 1 && g.contentTypes.length < selectedTpls.length
1788
+ ) : [];
1789
+ const sharedAcrossMultiple = multiDatasetGroups.map((group) => {
1790
+ const groupFilterConfigs = sortFiltersHierarchically(
1791
+ attachParentFields(
1792
+ buildFilterConfigurations({
1793
+ groups: [group],
1794
+ type: "tags",
1795
+ selectedTpls,
1796
+ allTpls,
1797
+ isRollup: false,
1798
+ isAnno: false
1799
+ }).flatMap((s) => s.configs),
1800
+ allTpls
1801
+ )
1802
+ );
1803
+ const display = group.contentTypes.map((ct) => {
1804
+ const tplData = allTpls.find(
1805
+ (t) => t.kp_content_type === ct
1806
+ );
1807
+ return tplData?.general?.content?.title || ct;
1808
+ }).join(" + ");
1809
+ return {
1810
+ contentTypes: group.contentTypes,
1811
+ display,
1812
+ filters: groupFilterConfigs
1813
+ };
1814
+ }).filter((g) => g.filters.length > 0);
1815
+ const commonFilterIds = new Set(commonFilterConfigs.map((f) => f.filterId));
1816
+ const perDataset = selectedTpls.map((tpl) => {
1817
+ const tplBlocks = combinedDocumentBlocks.find(
1818
+ (b) => b.contentType === tpl.kp_content_type
1819
+ );
1820
+ const singleTplGroup = [
1821
+ {
1822
+ contentTypes: [tpl.kp_content_type],
1823
+ elements: tplBlocks?.blocks || []
1824
+ }
1825
+ ];
1826
+ const filters = buildFilterConfigurations({
1827
+ groups: singleTplGroup,
1828
+ type: "tags",
1829
+ selectedTpls: [tpl],
1830
+ allTpls,
1831
+ isRollup: false,
1832
+ isAnno: false
1833
+ }).flatMap((s) => s.configs);
1834
+ const filtersWithCommonFlag = filters.map((f) => ({
1835
+ ...f,
1836
+ isSharedFilter: commonFilterIds.has(f.filterId)
1837
+ }));
1838
+ const rollupData = docRollupBlocks?.find(
1839
+ (b) => b.contentType === tpl.kp_content_type
1840
+ );
1841
+ const rollupGroups = rollupData?.blocks?.length ? compareAndGroupBlocks([rollupData]) : [];
1842
+ const rollupConfigs = rollupGroups.length ? buildFilterConfigurations({
1843
+ groups: rollupGroups,
1844
+ type: "tags",
1845
+ selectedTpls: [tpl],
1846
+ allTpls,
1847
+ isRollup: true,
1848
+ isAnno: false
1849
+ }).flatMap((s) => s.configs) : [];
1850
+ const tplData = allTpls.find(
1851
+ (t) => t.kp_content_type === tpl.kp_content_type
1852
+ );
1853
+ const rollupSourceKeys = new Set(
1854
+ rollupConfigs.map((r) => JSON.stringify(r.source))
1855
+ );
1856
+ const dedupedFilters = filtersWithCommonFlag.filter(
1857
+ (f) => !rollupSourceKeys.has(JSON.stringify(f.source))
1858
+ );
1859
+ const combined = [...dedupedFilters, ...rollupConfigs];
1860
+ const combinedWithParents = sortFiltersHierarchically(
1861
+ attachParentFields(combined, allTpls)
1862
+ );
1863
+ const rollupFilterIds = new Set(rollupConfigs.map((r) => r.filterId));
1864
+ const filtersWithParents = combinedWithParents.filter(
1865
+ (f) => !rollupFilterIds.has(f.filterId)
1866
+ );
1867
+ const rollupsWithParents = combinedWithParents.filter(
1868
+ (f) => rollupFilterIds.has(f.filterId)
1869
+ );
1870
+ return {
1871
+ contentType: tpl.kp_content_type,
1872
+ display: tplData?.general?.content?.title || tpl.kp_content_type,
1873
+ filters: filtersWithParents,
1874
+ rollups: rollupsWithParents
1875
+ };
1876
+ });
1877
+ const filteredPerDataset = perDataset.filter(
1878
+ (d) => d.filters.length > 0 || d.rollups.length > 0
1879
+ );
1880
+ if (commonFilterConfigs.length === 0 && sharedAcrossMultiple.length === 0 && filteredPerDataset.every((d) => d.filters.length === 0)) {
1881
+ return null;
1882
+ }
1883
+ const flatCommonDocFilters = commonDocumentFilters.flatMap(
1884
+ (s) => s.configs || [s]
1885
+ );
1886
+ const shouldFlatten = flatDocFilters && selectedTpls.length === 1;
1887
+ return {
1888
+ filterId: "docHierarchy_document_filters",
1889
+ display: "Combined Content Filters",
1890
+ filterKey: "docHierarchyType::doc",
1891
+ source: {
1892
+ filterType: "docHierarchyType",
1893
+ flatDocFilters: shouldFlatten,
1894
+ commonFilters: commonFilterConfigs,
1895
+ sharedAcrossMultiple,
1896
+ commonDocumentFilters: flatCommonDocFilters,
1897
+ perDataset: filteredPerDataset
1898
+ },
1899
+ target: { filterType: "docHierarchyType" }
1900
+ };
1901
+ };
1902
+
1659
1903
  // src/utils/autoGenFilterConfigsFromTpl/utils/TEMP_removeDuplicateFilters.ts
1660
1904
  var TEMP_removeDuplicateFilters = (filterGroups) => {
1661
1905
  return filterGroups.map((group) => {
@@ -1792,7 +2036,25 @@ var autoGenFilterConfigsFromTpl = ({
1792
2036
  ...annotationRollupSections
1793
2037
  ].filter((section) => Array.isArray(section.configs) ? section.configs.length > 0 : true)
1794
2038
  };
1795
- const final_documentTagsFilterConfigs = {
2039
+ const isSMTDocFilterUI = isSelfManagedTenant && filterScopes.includes("doc");
2040
+ const final_documentTagsFilterConfigs = isSMTDocFilterUI ? (() => {
2041
+ const docHierarchyConfig = _self_managed_buildDocHierarchyConfig({
2042
+ combinedDocumentBlocks: extractedBlocks.combinedDocumentBlocks,
2043
+ docRollupBlocks: extractedBlocks.docRollupBlocks,
2044
+ selectedTpls,
2045
+ allTpls,
2046
+ commonDocumentFilters
2047
+ });
2048
+ if (!docHierarchyConfig) return { sectionId: "documentTagsSection", sectionTitle: "Document Filters", configs: [] };
2049
+ return {
2050
+ sectionId: "documentTagsSection",
2051
+ // sectionTitle: 'Document Filters',
2052
+ configs: [{
2053
+ sectionId: "self_managed_consolidated_doc_filters",
2054
+ configs: [docHierarchyConfig]
2055
+ }]
2056
+ };
2057
+ })() : {
1796
2058
  sectionId: "documentTagsSection",
1797
2059
  sectionTitle: "Document Filters",
1798
2060
  configs: [
@@ -1808,20 +2070,33 @@ var autoGenFilterConfigsFromTpl = ({
1808
2070
  };
1809
2071
 
1810
2072
  // src/utils/genCleanCamelCaseId.ts
1811
- var genCleanCamelCaseId = (id) => {
2073
+ var genCleanCamelCaseId = (id, options) => {
1812
2074
  if (!id || typeof id !== "string") return id;
1813
- const isAlreadyClean = /^\p{Ll}[\p{L}\p{N}]*$/u.test(id) || /^a\d[\p{L}\p{N}]*$/u.test(id);
1814
- if (isAlreadyClean) return id;
2075
+ const { stripNonAlphanumeric = false, maxLength } = options || {};
2076
+ const baseClean = /^\p{Ll}[\p{L}\p{N}]*$/u.test(id) || /^a\d[\p{L}\p{N}]*$/u.test(id);
2077
+ const withinMaxLength = maxLength ? id.length <= maxLength : true;
2078
+ const hasNoNonAlpha = stripNonAlphanumeric ? /^[a-zA-Z0-9]+$/.test(id) : true;
2079
+ if (baseClean && withinMaxLength && hasNoNonAlpha) return id;
1815
2080
  const words = id.split(/[^\p{L}\p{N}]+/u).filter(Boolean);
1816
2081
  if (words.length === 0) return "a";
1817
- const result = words.map((word, i) => {
2082
+ let result = words.map((word, i) => {
1818
2083
  const lower = word.toLowerCase();
1819
2084
  return i === 0 ? lower : lower.charAt(0).toUpperCase() + lower.slice(1);
1820
2085
  }).join("");
1821
- return /^\d/.test(result) ? "a" + result : result;
2086
+ if (/^\d/.test(result)) result = "a" + result;
2087
+ if (stripNonAlphanumeric) {
2088
+ result = result.replace(/[^a-zA-Z0-9]/g, "");
2089
+ }
2090
+ if (maxLength) {
2091
+ result = result.slice(0, maxLength);
2092
+ }
2093
+ return result;
1822
2094
  };
1823
2095
 
1824
- // src/utils/genCleanIdForContentTypeAndValuePaths.ts
2096
+ // src/utils/genCleanContentTypeId.ts
2097
+ var genCleanContentTypeId = (text) => genCleanCamelCaseId(text, { stripNonAlphanumeric: true, maxLength: 40 });
2098
+
2099
+ // src/utils/genCleanValuePath.ts
1825
2100
  var CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
1826
2101
  function genShortId(length = 4) {
1827
2102
  let result = "";
@@ -1830,11 +2105,15 @@ function genShortId(length = 4) {
1830
2105
  }
1831
2106
  return result;
1832
2107
  }
1833
- var genCleanIdForContentTypeAndValuePaths = (text, maxLength = 10, shortIdLength = 4) => {
2108
+ var genCleanValuePath = (text) => {
2109
+ const maxLength = 10;
2110
+ const shortIdLength = 4;
1834
2111
  if (!text || typeof text !== "string") return text;
2112
+ const idempotencyPattern = new RegExp(`^[a-z][a-z0-9]*_[a-z0-9]{${shortIdLength}}$`);
2113
+ if (idempotencyPattern.test(text)) return text;
1835
2114
  let cleaned = text.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
1836
2115
  if (!cleaned) {
1837
- throw new Error(`[genCleanIdForContentTypeAndValuePaths] Input "${text}" contains no alphanumeric characters`);
2116
+ throw new Error(`[genCleanValuePath] Input "${text}" contains no alphanumeric characters`);
1838
2117
  }
1839
2118
  if (/^\d/.test(cleaned)) cleaned = "a" + cleaned;
1840
2119
  const truncated = cleaned.slice(0, maxLength);
@@ -1846,6 +2125,7 @@ export {
1846
2125
  TEMP_removeDuplicateFilters,
1847
2126
  UI_CONTENT,
1848
2127
  _self_managed_buildAnnoHierarchyConfig,
2128
+ _self_managed_buildDocHierarchyConfig,
1849
2129
  _self_managed_getFixedAnnoRollupBlocks,
1850
2130
  _self_managed_getFixedAnnoTagBlock,
1851
2131
  autoGenFilterConfigsFromTpl,
@@ -1855,7 +2135,8 @@ export {
1855
2135
  extractAllBlocksFromTpl,
1856
2136
  extractAndOrganizeBlocks,
1857
2137
  genCleanCamelCaseId,
1858
- genCleanIdForContentTypeAndValuePaths,
2138
+ genCleanContentTypeId,
2139
+ genCleanValuePath,
1859
2140
  genTagId,
1860
2141
  generateFilterKey,
1861
2142
  getFilterKeyForBlock,
package/dist/node.d.mts CHANGED
@@ -1027,6 +1027,51 @@ declare const _self_managed_buildAnnoHierarchyConfig: ({ annotationTagsCount, }:
1027
1027
  };
1028
1028
  } | null;
1029
1029
 
1030
+ /**
1031
+ * Builds a consolidated docHierarchyType config for self-managed tenants.
1032
+ *
1033
+ * Produces a single filter config that contains:
1034
+ * - commonFilters: filters present in ALL selected templates
1035
+ * - sharedAcrossMultiple: groups of filters shared by 2+ (but not all) templates
1036
+ * - perDataset: each template's complete filter list + rollup configs
1037
+ * - commonDocumentFilters: Author, Published Date, etc.
1038
+ *
1039
+ * This is consumed by DocHierarchyFilter on the frontend to render the
1040
+ * drilldown-based document filter UI.
1041
+ */
1042
+ declare const _self_managed_buildDocHierarchyConfig: ({ combinedDocumentBlocks, docRollupBlocks, selectedTpls, allTpls, commonDocumentFilters, flatDocFilters, }: {
1043
+ combinedDocumentBlocks: any[];
1044
+ docRollupBlocks: any[];
1045
+ selectedTpls: any[];
1046
+ allTpls: any[];
1047
+ commonDocumentFilters: any[];
1048
+ flatDocFilters?: boolean;
1049
+ }) => {
1050
+ filterId: string;
1051
+ display: string;
1052
+ filterKey: string;
1053
+ source: {
1054
+ filterType: string;
1055
+ flatDocFilters: boolean;
1056
+ commonFilters: any[];
1057
+ sharedAcrossMultiple: {
1058
+ contentTypes: any;
1059
+ display: any;
1060
+ filters: any[];
1061
+ }[];
1062
+ commonDocumentFilters: any[];
1063
+ perDataset: {
1064
+ contentType: any;
1065
+ display: any;
1066
+ filters: any[];
1067
+ rollups: any[];
1068
+ }[];
1069
+ };
1070
+ target: {
1071
+ filterType: string;
1072
+ };
1073
+ } | null;
1074
+
1030
1075
  /**
1031
1076
  * TEMP_removeDuplicateFilters - Removes duplicate rollup and tag-type filters
1032
1077
  *
@@ -1121,6 +1166,37 @@ declare const autoGenFilterConfigsFromTpl: ({ selectedTpls, allTpls, filterScope
1121
1166
  sectionId: string;
1122
1167
  configs: any[];
1123
1168
  }[];
1169
+ } | {
1170
+ sectionId: string;
1171
+ configs: {
1172
+ sectionId: string;
1173
+ configs: {
1174
+ filterId: string;
1175
+ display: string;
1176
+ filterKey: string;
1177
+ source: {
1178
+ filterType: string;
1179
+ flatDocFilters: boolean;
1180
+ commonFilters: any[];
1181
+ sharedAcrossMultiple: {
1182
+ contentTypes: any;
1183
+ display: any;
1184
+ filters: any[];
1185
+ }[];
1186
+ commonDocumentFilters: any[];
1187
+ perDataset: {
1188
+ contentType: any;
1189
+ display: any;
1190
+ filters: any[];
1191
+ rollups: any[];
1192
+ }[];
1193
+ };
1194
+ target: {
1195
+ filterType: string;
1196
+ };
1197
+ }[];
1198
+ }[];
1199
+ sectionTitle?: undefined;
1124
1200
  } | {
1125
1201
  sectionId: string;
1126
1202
  sectionTitle: string;
@@ -1191,11 +1267,30 @@ declare const UI_CONTENT: {
1191
1267
  };
1192
1268
  };
1193
1269
 
1194
- declare const genCleanCamelCaseId: (id: string) => string;
1270
+ interface GenCleanCamelCaseIdOptions {
1271
+ /** Strip all non-alphanumeric chars (A-Z, a-z, 0-9 only). Default: false */
1272
+ stripNonAlphanumeric?: boolean;
1273
+ /** Truncate result to this max length. Default: no limit */
1274
+ maxLength?: number;
1275
+ }
1276
+ declare const genCleanCamelCaseId: (id: string, options?: GenCleanCamelCaseIdOptions) => string;
1277
+
1278
+ /**
1279
+ * Generates a clean, deterministic contentType ID from text.
1280
+ * Wraps genCleanCamelCaseId with stripNonAlphanumeric + maxLength 40.
1281
+ *
1282
+ * Idempotent: running twice produces the same output.
1283
+ *
1284
+ * @example
1285
+ * genCleanContentTypeId("My Articles!") => "myArticles"
1286
+ * genCleanContentTypeId("myArticles") => "myArticles" (idempotent)
1287
+ * genCleanContentTypeId("123 Test") => "a123Test"
1288
+ */
1289
+ declare const genCleanContentTypeId: (text: string) => string;
1195
1290
 
1196
1291
  /**
1197
1292
  * Generates a clean, short, unique ID from text input.
1198
- * Used for both contentType IDs and block valuePaths.
1293
+ * Used for block valuePaths in templates.
1199
1294
  *
1200
1295
  * 1. Strips all characters except A-Z, a-z, 0-9
1201
1296
  * 2. Lowercases the result
@@ -1203,16 +1298,19 @@ declare const genCleanCamelCaseId: (id: string) => string;
1203
1298
  * 4. Truncates to maxLength (default 10)
1204
1299
  * 5. Appends _{random id} (default 4 chars)
1205
1300
  *
1301
+ * Idempotent: if input already matches the output pattern
1302
+ * (lowercase alphanumeric + _hash suffix), returns as-is.
1303
+ *
1206
1304
  * @param text - The input text to convert
1207
- * @param maxLength - Max characters before the random suffix (default 10, use 20 for contentType)
1305
+ * @param maxLength - Max characters before the random suffix (default 10)
1208
1306
  * @param shortIdLength - Length of the random suffix (default 4)
1209
1307
  *
1210
1308
  * @example
1211
- * genCleanIdForContentTypeAndValuePaths("Author Name") => "authorname_x7k2"
1212
- * genCleanIdForContentTypeAndValuePaths("My Articles!", 20) => "myarticles_m3p1"
1213
- * genCleanIdForContentTypeAndValuePaths("123 Test") => "a123test_ab4d"
1309
+ * genCleanValuePath("Author Name") => "authorname_x7k2"
1310
+ * genCleanValuePath("authorname_x7k2") => "authorname_x7k2" (idempotent)
1311
+ * genCleanValuePath("123 Test") => "a123test_ab4d"
1214
1312
  */
1215
- declare const genCleanIdForContentTypeAndValuePaths: (text: string, maxLength?: number, shortIdLength?: number) => string;
1313
+ declare const genCleanValuePath: (text: string) => string;
1216
1314
 
1217
1315
  declare class MongoConnector {
1218
1316
  static getInstance(): any;
@@ -1944,4 +2042,4 @@ declare function GET_GLOBAL_BULLMQ_CONFIG({ env, redisCredentials }: {
1944
2042
  };
1945
2043
  }): Object;
1946
2044
 
1947
- export { AIChatSchema, AnnosElasticSyncProducer, AnnotationSchema, BASE_BULLMQ_CONFIG, BaseProducer, BaseWorker, ChunksElasticSyncProducer, ElasticSearchConnector, FILTER_IDS, GET_GLOBAL_BULLMQ_CONFIG, GeneratedEntitiesSchema, GeneratedTopicsSchema, MongoConnector, PlatformConfigsSchema, ProducerManager, RedisCacheConnector, SecretManagerConnector, TEMP_removeDuplicateFilters, TplSchema, UI_CONTENT, WorkerManager, _self_managed_buildAnnoHierarchyConfig, _self_managed_getFixedAnnoRollupBlocks, _self_managed_getFixedAnnoTagBlock, autoGenFilterConfigsFromTpl, buildFilterConfigurations, compareAndGroupBlocks, deleteVal, extractAllBlocksFromTpl, extractAndOrganizeBlocks, genCleanCamelCaseId, genCleanIdForContentTypeAndValuePaths, genTagId, generateFilterKey, getAIChatModelByTenant, getAnnotationsModelByTenant, getDbByTenant, getFilterKeyForBlock, getGeneratedEntitiesModelByTenant, getGeneratedTopicsModelByTenant, getModelByTenant, getPlatformConfigsModelByTenant, getPlatformContextContent, getRollupPossibilities, getRoutePathToEditContent, getRoutePathToModerateContent, getRoutePathToPublishedContent, getTplModelByTenant, getVal, mergeAnnoDataIntoAnnotationsTags, parseSpecialConfigSyntax, processAuthorAndCommonFilters, _recursExtractBlocks as recursivelyExtractBlocks, segrigateDocs, setVal, toArray };
2045
+ export { AIChatSchema, AnnosElasticSyncProducer, AnnotationSchema, BASE_BULLMQ_CONFIG, BaseProducer, BaseWorker, ChunksElasticSyncProducer, ElasticSearchConnector, FILTER_IDS, GET_GLOBAL_BULLMQ_CONFIG, GeneratedEntitiesSchema, GeneratedTopicsSchema, MongoConnector, PlatformConfigsSchema, ProducerManager, RedisCacheConnector, SecretManagerConnector, TEMP_removeDuplicateFilters, TplSchema, UI_CONTENT, WorkerManager, _self_managed_buildAnnoHierarchyConfig, _self_managed_buildDocHierarchyConfig, _self_managed_getFixedAnnoRollupBlocks, _self_managed_getFixedAnnoTagBlock, autoGenFilterConfigsFromTpl, buildFilterConfigurations, compareAndGroupBlocks, deleteVal, extractAllBlocksFromTpl, extractAndOrganizeBlocks, genCleanCamelCaseId, genCleanContentTypeId, genCleanValuePath, genTagId, generateFilterKey, getAIChatModelByTenant, getAnnotationsModelByTenant, getDbByTenant, getFilterKeyForBlock, getGeneratedEntitiesModelByTenant, getGeneratedTopicsModelByTenant, getModelByTenant, getPlatformConfigsModelByTenant, getPlatformContextContent, getRollupPossibilities, getRoutePathToEditContent, getRoutePathToModerateContent, getRoutePathToPublishedContent, getTplModelByTenant, getVal, mergeAnnoDataIntoAnnotationsTags, parseSpecialConfigSyntax, processAuthorAndCommonFilters, _recursExtractBlocks as recursivelyExtractBlocks, segrigateDocs, setVal, toArray };