@conduction/nextcloud-vue 2.56.0-beta.34 → 2.56.0-beta.36
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/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue.js +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue2.js +22 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue2.js.map +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue3.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue.js +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js +47 -4
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue.js +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +239 -3
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js +5 -5
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +5 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue.js +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue2.js +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +203 -4
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +38 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +45 -5
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue.js +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue2.js +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js +29 -6
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +126 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +24 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +37 -2
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue.js +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js +135 -2
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js +95 -43
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue.js +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +72 -5
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +33 -8
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue.js +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue.js +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +17 -2
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +33 -3
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue.js +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js +16 -0
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +2 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue.js +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue2.js +68 -6
- package/dist/esm/dialogs/CnTransitionInputDialog.vue2.js.map +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue3.js +133 -105
- package/dist/esm/dialogs/CnTransitionInputDialog.vue3.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +16 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +38 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +525 -318
- package/dist/esm/utils/buildManifest.js +37 -3
- package/dist/esm/utils/buildManifest.js.map +1 -1
- package/dist/esm/utils/detailWidgetVisibility.js +149 -0
- package/dist/esm/utils/detailWidgetVisibility.js.map +1 -0
- package/dist/esm/utils/formatMetric.js +39 -3
- package/dist/esm/utils/formatMetric.js.map +1 -1
- package/dist/esm/utils/gridStack.js +40 -1
- package/dist/esm/utils/gridStack.js.map +1 -1
- package/dist/esm/utils/humaniseKey.js +41 -0
- package/dist/esm/utils/humaniseKey.js.map +1 -0
- package/dist/esm/utils/notificationRuleLabel.js +6 -23
- package/dist/esm/utils/notificationRuleLabel.js.map +1 -1
- package/dist/esm/utils/resolveManifestTokens.js +1 -0
- package/dist/esm/utils/resolveManifestTokens.js.map +1 -1
- package/dist/esm/utils/sentinelTokens.js +9 -0
- package/dist/esm/utils/sentinelTokens.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +2250 -708
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +525 -318
- package/l10n/en.json +16 -1
- package/l10n/nl.json +38 -1
- package/package.json +1 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +1 -1
- package/src/components/CnBodySections/CnBodySections.vue +22 -1
- package/src/components/CnCountdownWidget/CnCountdownWidget.vue +47 -4
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +244 -8
- package/src/components/CnDashboardPage/CnDashboardPage.vue +5 -0
- package/src/components/CnDeltaWidget/CnDeltaWidget.vue +1 -1
- package/src/components/CnDetailPage/CnDetailPage.md +2 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +203 -4
- package/src/components/CnFieldListWidget/CnFieldListWidget.vue +63 -1
- package/src/components/CnGaugeWidget/CnGaugeWidget.vue +1 -1
- package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +29 -6
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +154 -5
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +37 -2
- package/src/components/CnReportsPage/CnReportsPage.vue +179 -1
- package/src/components/CnStagesWidget/CnStagesWidget.vue +103 -6
- package/src/components/CnStatWidget/CnStatWidget.vue +1 -1
- package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +34 -3
- package/src/components/CnTabsWidget/CnTabsWidget.vue +33 -3
- package/src/components/CnWalkthrough/CnWalkthrough.vue +16 -0
- package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +2 -1
- package/src/css/form-field.css +14 -0
- package/src/css/form-widget.css +11 -0
- package/src/css/kpi-card.css +13 -0
- package/src/css/look-board-reports.css +58 -0
- package/src/css/look-board.css +31 -0
- package/src/dialogs/CnTransitionInputDialog.vue +87 -7
- package/src/index.js +2 -0
- package/src/schemas/app-manifest-v2.schema.json +23 -2
- package/src/utils/buildManifest.js +36 -2
- package/src/utils/detailWidgetVisibility.js +145 -0
- package/src/utils/formatMetric.js +38 -2
- package/src/utils/gridStack.js +39 -0
- package/src/utils/humaniseKey.js +38 -0
- package/src/utils/notificationRuleLabel.js +5 -23
- package/src/utils/resolveManifestTokens.js +1 -0
- package/src/utils/sentinelTokens.js +9 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*
|
|
5
|
+
* Make an identifier-shaped key readable for a person. Pure: no Vue.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Split camelCase, snake_case and kebab-case into words, keep acronyms, and
|
|
10
|
+
* capitalise only the first word.
|
|
11
|
+
*
|
|
12
|
+
* `caseAssigned` → "Case assigned", `object_created` → "Object created",
|
|
13
|
+
* `newBRPRecord` → "New BRP record".
|
|
14
|
+
*
|
|
15
|
+
* @param {string} key The key.
|
|
16
|
+
* @return {string} A readable sentence-case label, or the key when it has no words.
|
|
17
|
+
* @spec openspec/changes/data-widget-nested-objects/specs/data-widget-nested-objects/spec.md#requirement-a-nested-object-reads-as-a-list-per-key
|
|
18
|
+
*/
|
|
19
|
+
function humaniseKey(key) {
|
|
20
|
+
const words = String(key || '')
|
|
21
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
22
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
|
|
23
|
+
.split(/[\s_\-.]+/)
|
|
24
|
+
.filter(Boolean);
|
|
25
|
+
if (words.length === 0) {
|
|
26
|
+
return String(key || '')
|
|
27
|
+
}
|
|
28
|
+
return words
|
|
29
|
+
.map((word, index) => {
|
|
30
|
+
const isAcronym = word.length > 1 && word === word.toUpperCase() && /[A-Z]/.test(word);
|
|
31
|
+
if (isAcronym) {
|
|
32
|
+
return word
|
|
33
|
+
}
|
|
34
|
+
const lower = word.toLowerCase();
|
|
35
|
+
return index === 0 ? lower.charAt(0).toUpperCase() + lower.slice(1) : lower
|
|
36
|
+
})
|
|
37
|
+
.join(' ')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { humaniseKey };
|
|
41
|
+
//# sourceMappingURL=humaniseKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"humaniseKey.js","sources":["../../../src/utils/humaniseKey.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: EUPL-1.2\n *\n * Make an identifier-shaped key readable for a person. Pure: no Vue.\n */\n\n/**\n * Split camelCase, snake_case and kebab-case into words, keep acronyms, and\n * capitalise only the first word.\n *\n * `caseAssigned` → \"Case assigned\", `object_created` → \"Object created\",\n * `newBRPRecord` → \"New BRP record\".\n *\n * @param {string} key The key.\n * @return {string} A readable sentence-case label, or the key when it has no words.\n * @spec openspec/changes/data-widget-nested-objects/specs/data-widget-nested-objects/spec.md#requirement-a-nested-object-reads-as-a-list-per-key\n */\nexport function humaniseKey(key) {\n\tconst words = String(key || '')\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n\t\t.split(/[\\s_\\-.]+/)\n\t\t.filter(Boolean)\n\tif (words.length === 0) {\n\t\treturn String(key || '')\n\t}\n\treturn words\n\t\t.map((word, index) => {\n\t\t\tconst isAcronym = word.length > 1 && word === word.toUpperCase() && /[A-Z]/.test(word)\n\t\t\tif (isAcronym) {\n\t\t\t\treturn word\n\t\t\t}\n\t\t\tconst lower = word.toLowerCase()\n\t\t\treturn index === 0 ? lower.charAt(0).toUpperCase() + lower.slice(1) : lower\n\t\t})\n\t\t.join(' ')\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,GAAG,EAAE;AACjC,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;AAChC,GAAG,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;AACzC,GAAG,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC;AAC5C,GAAG,KAAK,CAAC,WAAW,CAAC;AACrB,GAAG,MAAM,CAAC,OAAO,EAAC;AAClB,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;AACzB,EAAE,OAAO,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;AAC1B,EAAE;AACF,CAAC,OAAO,KAAK;AACb,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK;AACxB,GAAG,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,WAAW,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAC;AACzF,GAAG,IAAI,SAAS,EAAE;AAClB,IAAI,OAAO,IAAI;AACf,IAAI;AACJ,GAAG,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,GAAE;AACnC,GAAG,OAAO,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;AAC9E,GAAG,CAAC;AACJ,GAAG,IAAI,CAAC,GAAG,CAAC;AACZ;;;;"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { humaniseKey } from './humaniseKey.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>
|
|
3
5
|
* SPDX-License-Identifier: EUPL-1.2
|
|
@@ -28,6 +30,7 @@
|
|
|
28
30
|
* @spec openspec/changes/notification-rule-labels-and-runtime-version/specs/notification-preferences/spec.md
|
|
29
31
|
*/
|
|
30
32
|
|
|
33
|
+
|
|
31
34
|
/**
|
|
32
35
|
* Pick the string for the current language out of a string or per-locale map.
|
|
33
36
|
*
|
|
@@ -54,34 +57,14 @@ function resolveLocalised(value, language = 'en') {
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
/**
|
|
57
|
-
* Make a rule key readable
|
|
58
|
-
* words, keep acronyms, and capitalise only the first word.
|
|
59
|
-
*
|
|
60
|
-
* `caseAssigned` → "Case assigned", `object_created` → "Object created",
|
|
61
|
-
* `newBRPRecord` → "New BRP record".
|
|
60
|
+
* Make a rule key readable (`caseAssigned` → "Case assigned"); see `humaniseKey`.
|
|
62
61
|
*
|
|
63
62
|
* @param {string} key The rule key.
|
|
64
63
|
* @return {string} A readable sentence-case label, or the key when it has no words.
|
|
64
|
+
* @spec openspec/changes/notification-rule-labels-and-runtime-version/specs/notification-preferences/spec.md#requirement-a-notification-rule-reads-as-a-label
|
|
65
65
|
*/
|
|
66
66
|
function humaniseRuleKey(key) {
|
|
67
|
-
|
|
68
|
-
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
69
|
-
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
|
|
70
|
-
.split(/[\s_\-.]+/)
|
|
71
|
-
.filter(Boolean);
|
|
72
|
-
if (words.length === 0) {
|
|
73
|
-
return String(key || '')
|
|
74
|
-
}
|
|
75
|
-
return words
|
|
76
|
-
.map((word, index) => {
|
|
77
|
-
const isAcronym = word.length > 1 && word === word.toUpperCase() && /[A-Z]/.test(word);
|
|
78
|
-
if (isAcronym) {
|
|
79
|
-
return word
|
|
80
|
-
}
|
|
81
|
-
const lower = word.toLowerCase();
|
|
82
|
-
return index === 0 ? lower.charAt(0).toUpperCase() + lower.slice(1) : lower
|
|
83
|
-
})
|
|
84
|
-
.join(' ')
|
|
67
|
+
return humaniseKey(key)
|
|
85
68
|
}
|
|
86
69
|
|
|
87
70
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notificationRuleLabel.js","sources":["../../../src/utils/notificationRuleLabel.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: EUPL-1.2\n *\n * The label a person reads for one notification rule in their settings.\n *\n * A rule is declared in a schema's `x-openregister-notifications` map under a\n * KEY (`caseAssigned`, `clientUpdated`, `onCreate`). The key is an identifier\n * for a developer. The settings pane used to print it as is, so a person saw\n * \"substitutionRegisteredForSubstitute\" next to a switch and had to guess.\n *\n * The label is taken from the first source that has one, most specific first:\n *\n * 1. the rule's own words, when OpenRegister passes them on the preference\n * entry (`label`, then `title`), as a plain string or a per-locale map\n * like the dialect's `subject` (`{ \"nl\": \"…\", \"en\": \"…\" }`);\n * 2. the app's own label for the rule, from the `labels` map the app hands\n * to CnAppRoot (`notificationLabels`), keyed `<schema>.<key>` or `<key>`;\n * 3. the library's wording for the generic object-event keys;\n * 4. the key made readable: `caseAssigned` becomes \"Case assigned\".\n *\n * The rule's `subject` is used only when it carries no `{{placeholder}}`: it\n * is the notification TITLE template, and \"Case \"{{title}}\" assigned to you\"\n * reads worse as a setting than the readable key does.\n *\n * Pure: no store, no fetch, no Vue.\n *\n * @spec openspec/changes/notification-rule-labels-and-runtime-version/specs/notification-preferences/spec.md\n */\n\n/**\n * Pick the string for the current language out of a string or per-locale map.\n *\n * @param {string|object|null|undefined} value A string, or `{ nl, en, … }`.\n * @param {string} [language] The current language, e.g. `nl` or `de_DE`.\n * @return {string} The resolved text, or '' when there is none.\n */\nexport function resolveLocalised(value, language = 'en') {\n\tif (typeof value === 'string') {\n\t\treturn value.trim()\n\t}\n\tif (!value || typeof value !== 'object' || Array.isArray(value)) {\n\t\treturn ''\n\t}\n\tconst lang = String(language || 'en')\n\tconst base = lang.split(/[-_]/)[0]\n\tfor (const candidate of [lang, base, 'en']) {\n\t\tif (typeof value[candidate] === 'string' && value[candidate].trim() !== '') {\n\t\t\treturn value[candidate].trim()\n\t\t}\n\t}\n\tconst first = Object.values(value).find((text) => typeof text === 'string' && text.trim() !== '')\n\treturn first ? first.trim() : ''\n}\n\n/**\n * Make a rule key readable
|
|
1
|
+
{"version":3,"file":"notificationRuleLabel.js","sources":["../../../src/utils/notificationRuleLabel.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: EUPL-1.2\n *\n * The label a person reads for one notification rule in their settings.\n *\n * A rule is declared in a schema's `x-openregister-notifications` map under a\n * KEY (`caseAssigned`, `clientUpdated`, `onCreate`). The key is an identifier\n * for a developer. The settings pane used to print it as is, so a person saw\n * \"substitutionRegisteredForSubstitute\" next to a switch and had to guess.\n *\n * The label is taken from the first source that has one, most specific first:\n *\n * 1. the rule's own words, when OpenRegister passes them on the preference\n * entry (`label`, then `title`), as a plain string or a per-locale map\n * like the dialect's `subject` (`{ \"nl\": \"…\", \"en\": \"…\" }`);\n * 2. the app's own label for the rule, from the `labels` map the app hands\n * to CnAppRoot (`notificationLabels`), keyed `<schema>.<key>` or `<key>`;\n * 3. the library's wording for the generic object-event keys;\n * 4. the key made readable: `caseAssigned` becomes \"Case assigned\".\n *\n * The rule's `subject` is used only when it carries no `{{placeholder}}`: it\n * is the notification TITLE template, and \"Case \"{{title}}\" assigned to you\"\n * reads worse as a setting than the readable key does.\n *\n * Pure: no store, no fetch, no Vue.\n *\n * @spec openspec/changes/notification-rule-labels-and-runtime-version/specs/notification-preferences/spec.md\n */\n\nimport { humaniseKey } from './humaniseKey.js'\n\n/**\n * Pick the string for the current language out of a string or per-locale map.\n *\n * @param {string|object|null|undefined} value A string, or `{ nl, en, … }`.\n * @param {string} [language] The current language, e.g. `nl` or `de_DE`.\n * @return {string} The resolved text, or '' when there is none.\n */\nexport function resolveLocalised(value, language = 'en') {\n\tif (typeof value === 'string') {\n\t\treturn value.trim()\n\t}\n\tif (!value || typeof value !== 'object' || Array.isArray(value)) {\n\t\treturn ''\n\t}\n\tconst lang = String(language || 'en')\n\tconst base = lang.split(/[-_]/)[0]\n\tfor (const candidate of [lang, base, 'en']) {\n\t\tif (typeof value[candidate] === 'string' && value[candidate].trim() !== '') {\n\t\t\treturn value[candidate].trim()\n\t\t}\n\t}\n\tconst first = Object.values(value).find((text) => typeof text === 'string' && text.trim() !== '')\n\treturn first ? first.trim() : ''\n}\n\n/**\n * Make a rule key readable (`caseAssigned` → \"Case assigned\"); see `humaniseKey`.\n *\n * @param {string} key The rule key.\n * @return {string} A readable sentence-case label, or the key when it has no words.\n * @spec openspec/changes/notification-rule-labels-and-runtime-version/specs/notification-preferences/spec.md#requirement-a-notification-rule-reads-as-a-label\n */\nexport function humaniseRuleKey(key) {\n\treturn humaniseKey(key)\n}\n\n/**\n * The label for one preference entry.\n *\n * @param {object} entry A preference entry: `{ schema, notification, label?, title?, subject? }`.\n * @param {object} [options] Where else a label may come from.\n * @param {object} [options.labels] App-supplied labels keyed `<schema>.<key>` or `<key>`;\n * values are strings or per-locale maps.\n * @param {object} [options.known] Library wording for generic keys, keyed by rule key.\n * @param {string} [options.language] The current language.\n * @return {string} The label to show.\n */\nexport function notificationRuleLabel(entry, { labels = {}, known = {}, language = 'en' } = {}) {\n\tconst key = String(entry?.notification ?? '')\n\tconst schema = String(entry?.schema ?? '')\n\n\tfor (const field of ['label', 'title']) {\n\t\tconst own = resolveLocalised(entry?.[field], language)\n\t\tif (own) {\n\t\t\treturn own\n\t\t}\n\t}\n\n\tconst map = labels && typeof labels === 'object' ? labels : {}\n\tfor (const lookup of [schema ? `${schema}.${key}` : '', key]) {\n\t\tif (lookup && Object.hasOwn(map, lookup)) {\n\t\t\tconst fromApp = resolveLocalised(map[lookup], language)\n\t\t\tif (fromApp) {\n\t\t\t\treturn fromApp\n\t\t\t}\n\t\t}\n\t}\n\n\tif (known && typeof known[key] === 'string' && known[key]) {\n\t\treturn known[key]\n\t}\n\n\tconst subject = resolveLocalised(entry?.subject, language)\n\tif (subject && !subject.includes('{{')) {\n\t\treturn subject\n\t}\n\n\treturn humaniseRuleKey(key)\n}\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gBAAgB,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAE;AACzD,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAChC,EAAE,OAAO,KAAK,CAAC,IAAI,EAAE;AACrB,EAAE;AACF,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AAClE,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,IAAI,IAAI,EAAC;AACtC,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAC;AACnC,CAAC,KAAK,MAAM,SAAS,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;AAC7C,EAAE,IAAI,OAAO,KAAK,CAAC,SAAS,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;AAC9E,GAAG,OAAO,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE;AACjC,GAAG;AACH,EAAE;AACF,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAC;AAClG,CAAC,OAAO,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE;AACjC,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,GAAG,EAAE;AACrC,CAAC,OAAO,WAAW,CAAC,GAAG,CAAC;AACxB,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB,CAAC,KAAK,EAAE,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE;AAChG,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,EAAE,YAAY,IAAI,EAAE,EAAC;AAC9C,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,EAAC;AAC3C;AACA,CAAC,KAAK,MAAM,KAAK,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE;AACzC,EAAE,MAAM,GAAG,GAAG,gBAAgB,CAAC,KAAK,GAAG,KAAK,CAAC,EAAE,QAAQ,EAAC;AACxD,EAAE,IAAI,GAAG,EAAE;AACX,GAAG,OAAO,GAAG;AACb,GAAG;AACH,EAAE;AACF;AACA,CAAC,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,GAAG,MAAM,GAAG,GAAE;AAC/D,CAAC,KAAK,MAAM,MAAM,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,EAAE;AAC/D,EAAE,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE;AAC5C,GAAG,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAC;AAC1D,GAAG,IAAI,OAAO,EAAE;AAChB,IAAI,OAAO,OAAO;AAClB,IAAI;AACJ,GAAG;AACH,EAAE;AACF;AACA,CAAC,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE;AAC5D,EAAE,OAAO,KAAK,CAAC,GAAG,CAAC;AACnB,EAAE;AACF;AACA,CAAC,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAC;AAC3D,CAAC,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AACzC,EAAE,OAAO,OAAO;AAChB,EAAE;AACF;AACA,CAAC,OAAO,eAAe,CAAC,GAAG,CAAC;AAC5B;;;;"}
|
|
@@ -58,6 +58,7 @@ const SENTINEL_RESOLVERS = Object.freeze({
|
|
|
58
58
|
answer: 'resolveAssignValue (utils/formAssign.js)',
|
|
59
59
|
row: 'CnFieldListWidget (rowActions request)',
|
|
60
60
|
subject: 'CnBannerWidget (action route)',
|
|
61
|
+
context: 'detailWidgetVisible (utils/detailWidgetVisibility.js)',
|
|
61
62
|
});
|
|
62
63
|
|
|
63
64
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveManifestTokens.js","sources":["../../../src/utils/resolveManifestTokens.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * Single documented resolver-dispatch entrypoint for the closed sentinel-token\n * vocabulary. Before this module the four resolvers were invoked ad-hoc by\n * callers who had to know which resolver owned which token. This entrypoint\n * routes a token to its owning resolver BY CONTEXT (see\n * {@link module:utils/sentinelTokens}) so the vocabulary cannot drift between\n * the schema, the runtime, and the gate.\n *\n * It does NOT re-implement resolution: it composes the existing resolver\n * functions verbatim —\n *\n * - route context → {@link resolveRouteSentinels} (reference-preserving walk +\n * per-page unresolved warning);\n * - filter / object / workspace / config(@config.<key>) contexts →\n * {@link resolveFilterValue} per leaf (identical behaviour to\n * resolveFilterTokens, which is that function applied over a filter map);\n * - config `@resolve:<key>` context → handled at manifest-LOAD time by\n * `resolveManifestSentinels` (async IAppConfig), so a render-time\n * subtree pass leaves it untouched — matching today's split;\n * - declarative `@self`/`@ref`/`@aggregate` → resolved server-side by\n * OpenRegister, so they pass through the client walk untouched;\n * - visibleWhen `@total` (manifest-form-logic) → resolved by\n * {@link module:utils/visibleWhen}'s own `evaluateVisibleWhen` /\n * `evaluateVisibleWhenLocal`, not by this generic subtree walk, so it\n * likewise passes through untouched.\n *\n * On top it adds the migration-window behaviour the vocabulary requires: a\n * one-time `console.warn` naming the canonical replacement whenever a\n * DEPRECATED token is encountered.\n *\n * @module utils/resolveManifestTokens\n */\n\nimport { isOptionalUnresolved, resolveFilterValue } from './resolveFilterTokens.js'\nimport resolveRouteSentinels from './resolveRouteSentinels.js'\nimport { contextOf, looksLikeSentinel, matchDeprecation, SENTINEL_CONTEXTS } from './sentinelTokens.js'\n\n/**\n * Dispatch table: canonical context → the resolver that owns it. Documentation\n * + programmatic lookup; the actual routing in {@link resolveManifestSubtree}\n * uses the same source-of-truth classifier ({@link contextOf}).\n *\n * @type {Readonly<Record<string, string>>}\n */\nexport const SENTINEL_RESOLVERS = Object.freeze({\n\tfilter: 'resolveFilterTokens',\n\tconfig: 'resolveManifestSentinels / resolveFilterTokens',\n\tobject: 'resolveFilterTokens',\n\tworkspace: 'resolveFilterTokens',\n\troute: 'resolveRouteSentinels',\n\tdeclarative: 'fetchAggregate (OpenRegister server-side)',\n\tvisibleWhen: 'evaluateVisibleWhen (utils/visibleWhen.js)',\n\tanswer: 'resolveAssignValue (utils/formAssign.js)',\n\trow: 'CnFieldListWidget (rowActions request)',\n\tsubject: 'CnBannerWidget (action route)',\n})\n\n/**\n * Process-wide set of deprecated tokens already warned about, so the same\n * deprecated token referenced from many pages warns once. Cleared by\n * {@link clearDeprecationWarnings} (test-only).\n *\n * @type {Set<string>}\n */\nconst _warnedDeprecations = new Set()\n\n/**\n * Reset the one-time deprecation-warning dedup set. Test-only.\n *\n * @return {void}\n */\nexport function clearDeprecationWarnings() {\n\t_warnedDeprecations.clear()\n}\n\n/**\n * Emit a one-time deprecation warning for `token` if it is on the deprecation\n * map. Idempotent per token for the process lifetime.\n *\n * @param {string} token The `@`-prefixed token.\n * @param {(...args: unknown[]) => void} warn console.warn override (tests).\n * @return {boolean} True when the token is deprecated (regardless of whether a\n * warning was emitted this call).\n */\nexport function warnIfDeprecated(token, warn) {\n\tconst dep = matchDeprecation(token)\n\tif (!dep) {\n\t\treturn false\n\t}\n\tif (!_warnedDeprecations.has(token)) {\n\t\t_warnedDeprecations.add(token)\n\t\tconst target = dep.replacement\n\t\t\t? `use '${dep.replacement}' instead`\n\t\t\t: 'it will be removed with no direct replacement'\n\t\twarn(`[resolveManifestTokens] Deprecated sentinel token '${token}' — ${target} `\n\t\t\t+ `(removal ${dep.removal}). ${dep.note}`)\n\t}\n\treturn true\n}\n\n/**\n * Resolve every sentinel token in a manifest subtree through the single\n * dispatch, routing each by context to its existing resolver.\n *\n * Behaviour is the composition of the existing resolvers, so this is a\n * drop-in for a caller that previously ran `resolveRouteSentinels` then a\n * `resolveFilterTokens`-style pass by hand.\n *\n * @param {unknown} value The subtree (typically a `pages[].config` block). Not mutated.\n * @param {object} [opts] Resolution inputs.\n * @param {object} [opts.params] vue-router params for `@route.<param>`.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [opts.ctx]\n * Context forwarded to {@link resolveFilterValue} for filter / object /\n * workspace / `@config.<key>` tokens.\n * @param {string} [opts.pageId] Page id for route-resolver warning dedup.\n * @param {(...args: unknown[]) => void} [opts.warn] console.warn override (tests).\n * @return {{value: unknown, unresolved: string[]}} The resolved subtree plus the\n * list of tokens that stayed unresolved (excluding OPTIONAL `?` tokens, which\n * are meant to be dropped, not waited on).\n */\nexport function resolveManifestSubtree(value, opts = {}) {\n\tconst params = opts.params && typeof opts.params === 'object' ? opts.params : {}\n\tconst ctx = opts.ctx && typeof opts.ctx === 'object' ? opts.ctx : {}\n\tconst pageId = opts.pageId || '<unknown>'\n\tconst warn = opts.warn ?? ((...args) => {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(...args)\n\t})\n\n\t// Pass 1: route context (reuses the reference-preserving route walker,\n\t// including its own per-page unresolved warning).\n\tconst afterRoute = resolveRouteSentinels(value, params, pageId)\n\n\t// Pass 2: filter / object / workspace / @config.<key> contexts, per leaf,\n\t// via the existing resolveFilterValue. Deprecated tokens warn once.\n\tconst unresolved = []\n\tconst walk = (node) => {\n\t\tif (typeof node === 'string') {\n\t\t\tif (!looksLikeSentinel(node)) {\n\t\t\t\treturn node\n\t\t\t}\n\t\t\twarnIfDeprecated(node, warn)\n\t\t\tconst resolved = resolveFilterValue(node, ctx)\n\t\t\tif (resolved === node && !isOptionalUnresolved(node)) {\n\t\t\t\t// Still a raw token: unresolved unless it is a load-time / server-side\n\t\t\t\t// context this render-pass deliberately leaves alone.\n\t\t\t\tconst c = contextOf(node)\n\t\t\t\tif (c !== 'config' && c !== 'declarative' && c !== 'visibleWhen') {\n\t\t\t\t\tunresolved.push(node)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resolved\n\t\t}\n\t\tif (Array.isArray(node)) {\n\t\t\treturn node.map(walk)\n\t\t}\n\t\tif (node && typeof node === 'object') {\n\t\t\tconst out = {}\n\t\t\tfor (const [k, v] of Object.entries(node)) {\n\t\t\t\tout[k] = walk(v)\n\t\t\t}\n\t\t\treturn out\n\t\t}\n\t\treturn node\n\t}\n\n\treturn { value: walk(afterRoute), unresolved }\n}\n\nexport { SENTINEL_CONTEXTS }\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolveManifestTokens.js","sources":["../../../src/utils/resolveManifestTokens.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * Single documented resolver-dispatch entrypoint for the closed sentinel-token\n * vocabulary. Before this module the four resolvers were invoked ad-hoc by\n * callers who had to know which resolver owned which token. This entrypoint\n * routes a token to its owning resolver BY CONTEXT (see\n * {@link module:utils/sentinelTokens}) so the vocabulary cannot drift between\n * the schema, the runtime, and the gate.\n *\n * It does NOT re-implement resolution: it composes the existing resolver\n * functions verbatim —\n *\n * - route context → {@link resolveRouteSentinels} (reference-preserving walk +\n * per-page unresolved warning);\n * - filter / object / workspace / config(@config.<key>) contexts →\n * {@link resolveFilterValue} per leaf (identical behaviour to\n * resolveFilterTokens, which is that function applied over a filter map);\n * - config `@resolve:<key>` context → handled at manifest-LOAD time by\n * `resolveManifestSentinels` (async IAppConfig), so a render-time\n * subtree pass leaves it untouched — matching today's split;\n * - declarative `@self`/`@ref`/`@aggregate` → resolved server-side by\n * OpenRegister, so they pass through the client walk untouched;\n * - visibleWhen `@total` (manifest-form-logic) → resolved by\n * {@link module:utils/visibleWhen}'s own `evaluateVisibleWhen` /\n * `evaluateVisibleWhenLocal`, not by this generic subtree walk, so it\n * likewise passes through untouched.\n *\n * On top it adds the migration-window behaviour the vocabulary requires: a\n * one-time `console.warn` naming the canonical replacement whenever a\n * DEPRECATED token is encountered.\n *\n * @module utils/resolveManifestTokens\n */\n\nimport { isOptionalUnresolved, resolveFilterValue } from './resolveFilterTokens.js'\nimport resolveRouteSentinels from './resolveRouteSentinels.js'\nimport { contextOf, looksLikeSentinel, matchDeprecation, SENTINEL_CONTEXTS } from './sentinelTokens.js'\n\n/**\n * Dispatch table: canonical context → the resolver that owns it. Documentation\n * + programmatic lookup; the actual routing in {@link resolveManifestSubtree}\n * uses the same source-of-truth classifier ({@link contextOf}).\n *\n * @type {Readonly<Record<string, string>>}\n */\nexport const SENTINEL_RESOLVERS = Object.freeze({\n\tfilter: 'resolveFilterTokens',\n\tconfig: 'resolveManifestSentinels / resolveFilterTokens',\n\tobject: 'resolveFilterTokens',\n\tworkspace: 'resolveFilterTokens',\n\troute: 'resolveRouteSentinels',\n\tdeclarative: 'fetchAggregate (OpenRegister server-side)',\n\tvisibleWhen: 'evaluateVisibleWhen (utils/visibleWhen.js)',\n\tanswer: 'resolveAssignValue (utils/formAssign.js)',\n\trow: 'CnFieldListWidget (rowActions request)',\n\tsubject: 'CnBannerWidget (action route)',\n\tcontext: 'detailWidgetVisible (utils/detailWidgetVisibility.js)',\n})\n\n/**\n * Process-wide set of deprecated tokens already warned about, so the same\n * deprecated token referenced from many pages warns once. Cleared by\n * {@link clearDeprecationWarnings} (test-only).\n *\n * @type {Set<string>}\n */\nconst _warnedDeprecations = new Set()\n\n/**\n * Reset the one-time deprecation-warning dedup set. Test-only.\n *\n * @return {void}\n */\nexport function clearDeprecationWarnings() {\n\t_warnedDeprecations.clear()\n}\n\n/**\n * Emit a one-time deprecation warning for `token` if it is on the deprecation\n * map. Idempotent per token for the process lifetime.\n *\n * @param {string} token The `@`-prefixed token.\n * @param {(...args: unknown[]) => void} warn console.warn override (tests).\n * @return {boolean} True when the token is deprecated (regardless of whether a\n * warning was emitted this call).\n */\nexport function warnIfDeprecated(token, warn) {\n\tconst dep = matchDeprecation(token)\n\tif (!dep) {\n\t\treturn false\n\t}\n\tif (!_warnedDeprecations.has(token)) {\n\t\t_warnedDeprecations.add(token)\n\t\tconst target = dep.replacement\n\t\t\t? `use '${dep.replacement}' instead`\n\t\t\t: 'it will be removed with no direct replacement'\n\t\twarn(`[resolveManifestTokens] Deprecated sentinel token '${token}' — ${target} `\n\t\t\t+ `(removal ${dep.removal}). ${dep.note}`)\n\t}\n\treturn true\n}\n\n/**\n * Resolve every sentinel token in a manifest subtree through the single\n * dispatch, routing each by context to its existing resolver.\n *\n * Behaviour is the composition of the existing resolvers, so this is a\n * drop-in for a caller that previously ran `resolveRouteSentinels` then a\n * `resolveFilterTokens`-style pass by hand.\n *\n * @param {unknown} value The subtree (typically a `pages[].config` block). Not mutated.\n * @param {object} [opts] Resolution inputs.\n * @param {object} [opts.params] vue-router params for `@route.<param>`.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [opts.ctx]\n * Context forwarded to {@link resolveFilterValue} for filter / object /\n * workspace / `@config.<key>` tokens.\n * @param {string} [opts.pageId] Page id for route-resolver warning dedup.\n * @param {(...args: unknown[]) => void} [opts.warn] console.warn override (tests).\n * @return {{value: unknown, unresolved: string[]}} The resolved subtree plus the\n * list of tokens that stayed unresolved (excluding OPTIONAL `?` tokens, which\n * are meant to be dropped, not waited on).\n */\nexport function resolveManifestSubtree(value, opts = {}) {\n\tconst params = opts.params && typeof opts.params === 'object' ? opts.params : {}\n\tconst ctx = opts.ctx && typeof opts.ctx === 'object' ? opts.ctx : {}\n\tconst pageId = opts.pageId || '<unknown>'\n\tconst warn = opts.warn ?? ((...args) => {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(...args)\n\t})\n\n\t// Pass 1: route context (reuses the reference-preserving route walker,\n\t// including its own per-page unresolved warning).\n\tconst afterRoute = resolveRouteSentinels(value, params, pageId)\n\n\t// Pass 2: filter / object / workspace / @config.<key> contexts, per leaf,\n\t// via the existing resolveFilterValue. Deprecated tokens warn once.\n\tconst unresolved = []\n\tconst walk = (node) => {\n\t\tif (typeof node === 'string') {\n\t\t\tif (!looksLikeSentinel(node)) {\n\t\t\t\treturn node\n\t\t\t}\n\t\t\twarnIfDeprecated(node, warn)\n\t\t\tconst resolved = resolveFilterValue(node, ctx)\n\t\t\tif (resolved === node && !isOptionalUnresolved(node)) {\n\t\t\t\t// Still a raw token: unresolved unless it is a load-time / server-side\n\t\t\t\t// context this render-pass deliberately leaves alone.\n\t\t\t\tconst c = contextOf(node)\n\t\t\t\tif (c !== 'config' && c !== 'declarative' && c !== 'visibleWhen') {\n\t\t\t\t\tunresolved.push(node)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resolved\n\t\t}\n\t\tif (Array.isArray(node)) {\n\t\t\treturn node.map(walk)\n\t\t}\n\t\tif (node && typeof node === 'object') {\n\t\t\tconst out = {}\n\t\t\tfor (const [k, v] of Object.entries(node)) {\n\t\t\t\tout[k] = walk(v)\n\t\t\t}\n\t\t\treturn out\n\t\t}\n\t\treturn node\n\t}\n\n\treturn { value: walk(afterRoute), unresolved }\n}\n\nexport { SENTINEL_CONTEXTS }\n"],"names":[],"mappings":"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"}
|
|
@@ -89,6 +89,9 @@ const SENTINEL_TOKEN_PATTERNS = Object.freeze({
|
|
|
89
89
|
// A field of the record a start-here attention card names (`@subject.<field>`, dot path),
|
|
90
90
|
// read by the banner widget's action routes.
|
|
91
91
|
subject: '^@subject\\.[A-Za-z][A-Za-z0-9_.]*$',
|
|
92
|
+
// A record a detail page reads beside the loaded one (`visibilityContext`), read by a
|
|
93
|
+
// grid widget's or a tab's `visibleWhen` as `@context.<name>.<field>` (dot path).
|
|
94
|
+
context: '^@context\\.[A-Za-z][A-Za-z0-9_.]*$',
|
|
92
95
|
// Deprecated-but-not-yet-removed tokens. Kept in the schema union so
|
|
93
96
|
// deployed manifests still validate during the migration window; the gate
|
|
94
97
|
// downgrades them to a WARN (see SENTINEL_DEPRECATIONS).
|
|
@@ -112,6 +115,7 @@ const SENTINEL_CONTEXTS = Object.freeze([
|
|
|
112
115
|
'answer',
|
|
113
116
|
'row',
|
|
114
117
|
'subject',
|
|
118
|
+
'context',
|
|
115
119
|
]);
|
|
116
120
|
|
|
117
121
|
/**
|
|
@@ -172,6 +176,11 @@ const SENTINEL_VOCABULARY = Object.freeze({
|
|
|
172
176
|
description: 'A field of the record an attention card names (the first row of its ordered `visibleWhen` source query), read when the card builds an action\'s route. Dot paths are allowed (`@subject.owner.id`).',
|
|
173
177
|
members: ['@subject.<field>'],
|
|
174
178
|
},
|
|
179
|
+
context: {
|
|
180
|
+
resolver: 'CnDetailPage visibilityContext (detailWidgetVisibility), read by a grid widget\'s or a tab\'s visibleWhen',
|
|
181
|
+
description: 'A record the detail page reads beside the loaded one, named in `config.visibilityContext` (a case\'s case type). A `visibleWhen` field reads it as `@context.<name>.<field>`, dot paths allowed (`@context.caseType.category`).',
|
|
182
|
+
members: ['@context.<name>.<field>'],
|
|
183
|
+
},
|
|
175
184
|
});
|
|
176
185
|
|
|
177
186
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sentinelTokens.js","sources":["../../../src/utils/sentinelTokens.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * Closed, context-partitioned manifest **sentinel-token vocabulary** — the\n * single source of truth for every `@`-prefixed dynamic value a manifest may\n * carry under `pages[].config` or a widget `filter`/`dataSource`.\n *\n * Before this module the token surface was scattered across four resolvers\n * (`resolveManifestSentinels`, `resolveFilterTokens`, `resolveRouteSentinels`,\n * `fetchAggregate`) plus ad-hoc single-app inventions (`@currentFiscalYear`,\n * `@page.*`, `@runtime`). This module declares the vocabulary ONCE so:\n *\n * 1. the JSON-Schema `$defs` in `app-manifest-v2.schema.json` reject an\n * out-of-vocabulary token (the pattern strings here are the exact strings\n * mirrored into the schema — a unit test enforces byte-equality);\n * 2. the shared resolver dispatch (`resolveManifestTokens.js`) and the four\n * resolvers import their token patterns from here rather than re-declaring\n * them, so the runtime and the schema cannot drift;\n * 3. a hydra manifest gate can `scanManifestTokens()` an app and FAIL an\n * unknown token / WARN a deprecated one, reusing this export (no hardcoded\n * copy).\n *\n * ## Context partitions\n *\n * A token is valid only in the context whose resolver runs on it:\n *\n * - **filter** — `resolveFilterTokens`, resolved at fetch time:\n * `@me`, `@myGroups`, `@now`, `@today`, `@today±Nd`, `@monthStart`, `@monthEnd`, `@nextMonthStart`,\n * `@quarterStart`, `@yearStart`.\n * - **config** — `IAppConfig`-sourced: `@resolve:<key>`, `@config.<key>`\n * (trailing `?` marks optional).\n * - **object** — detail-page object context: `@objectId`,\n * `@object.<field>`.\n * - **workspace** — page-level workspace state: `@workspace.<key>`\n * (trailing `?` optional).\n * - **route** — `resolveRouteSentinels`: `@route.<param>`.\n * - **declarative** — OpenRegister direction, resolved server-side:\n * `@self.<field>` (the object's own field in a\n * cross-object calc), `@ref:<path>`, `@aggregate:<expr>`.\n * - **visibleWhen** — the shared `visibleWhen` predicate's `source`-mode\n * collection-total marker, resolved client-side by\n * `evaluateVisibleWhen` (`utils/visibleWhen.js`):\n * `@total` (a `field: \"@total\"` — or omitted `field` —\n * compares the collection total rather than the first\n * result). Added for manifest-form-logic:\n * `config.fields[].visibleWhen` is the first\n * `visibleWhen` reachable through the\n * sentinelGuardedValue-guarded `pages[].config` subtree.\n *\n * `@ref`/`@aggregate` are first-class members even though currently unused\n * fleet-wide — they are the OR-declarative direction and belong in the closed\n * vocabulary so a future adopter validates rather than inventing a variant.\n *\n * @module utils/sentinelTokens\n */\n\n/**\n * Pattern STRINGS, one per context — the canonical source mirrored verbatim\n * into `app-manifest-v2.schema.json`'s `$defs`. A unit test asserts each schema\n * `$def`'s `pattern` equals the string here, so the two cannot drift.\n *\n * NOTE: these are JS string literals; a `\\\\.` here is the two-character\n * sequence `\\.` at runtime, which is exactly what the JSON schema stores after\n * its own `\\\\.` is parsed. Compare PARSED values, never raw source.\n *\n * @type {Readonly<Record<string, string>>}\n */\nexport const SENTINEL_TOKEN_PATTERNS = Object.freeze({\n\tfilter: '^@(?:me(?:\\\\.(?:displayName|email))?|myGroups|now|today|monthStart|monthEnd|nextMonthStart|quarterStart|yearStart)$|^@today[+-][0-9]+d$',\n\tconfig: '^@resolve:[a-z][a-z0-9_-]*$|^@config\\\\.[A-Za-z][A-Za-z0-9_.]*\\\\??$',\n\tobject: '^@objectId$|^@object\\\\.[A-Za-z][A-Za-z0-9_]*$',\n\tworkspace: '^@workspace\\\\.[A-Za-z][A-Za-z0-9_]*\\\\??$',\n\troute: '^@route\\\\.[A-Za-z][A-Za-z0-9_-]*$',\n\tdeclarative: '^@self\\\\.[A-Za-z][A-Za-z0-9_]*$|^@ref:[A-Za-z][A-Za-z0-9_./-]*$|^@aggregate:.+$',\n\t// manifest-form-logic: the shared visibleWhen predicate's source-mode\n\t// collection-total marker (`field: \"@total\"`), resolved client-side by\n\t// evaluateVisibleWhen — not one of the four IAppConfig/OpenRegister\n\t// resolvers, but a real pre-existing convention (already documented on\n\t// $defs.visibleWhen and the banner widget) now reachable through the\n\t// sentinelGuardedValue-guarded pages[].config subtree for the first time\n\t// via config.fields[].visibleWhen.\n\tvisibleWhen: '^@total$',\n\t// form-live-values: another answer in the same form, read by a field's `assign` rule.\n\tanswer: '^@answer\\\\.[A-Za-z][A-Za-z0-9_]*$',\n\t// A field of the row a row action is run on (`@row.<field>`, dot path), read by the\n\t// field-list widget's `rowActions` request URL and payload.\n\trow: '^@row\\\\.[A-Za-z][A-Za-z0-9_.@]*$',\n\t// A field of the record a start-here attention card names (`@subject.<field>`, dot path),\n\t// read by the banner widget's action routes.\n\tsubject: '^@subject\\\\.[A-Za-z][A-Za-z0-9_.]*$',\n\t// Deprecated-but-not-yet-removed tokens. Kept in the schema union so\n\t// deployed manifests still validate during the migration window; the gate\n\t// downgrades them to a WARN (see SENTINEL_DEPRECATIONS).\n\tdeprecated: '^@currentFiscalYear$|^@page\\\\.[A-Za-z][A-Za-z0-9_]*$|^@runtime(?:\\\\.[A-Za-z][A-Za-z0-9_]*)?$',\n})\n\n/**\n * The nine canonical context names (excludes `deprecated`, which is a\n * transitional overlay, not a resolution context).\n *\n * @type {string[]}\n */\nexport const SENTINEL_CONTEXTS = Object.freeze([\n\t'filter',\n\t'config',\n\t'object',\n\t'workspace',\n\t'route',\n\t'declarative',\n\t'visibleWhen',\n\t'answer',\n\t'row',\n\t'subject',\n])\n\n/**\n * Human-readable vocabulary: members + context + owning resolver + parameter\n * grammar. Documentation-facing (feeds audit item 16 schema-generated docs);\n * the machine-checkable truth is {@link SENTINEL_TOKEN_PATTERNS}.\n *\n * @type {Readonly<Record<string, {resolver: string, description: string, members: string[]}>>}\n */\nexport const SENTINEL_VOCABULARY = Object.freeze({\n\tfilter: {\n\t\tresolver: 'resolveFilterTokens',\n\t\tdescription: 'Relative fetch-time tokens (current user, the current user\\'s groups as an IN list, relative dates).',\n\t\tmembers: ['@me', '@me.displayName', '@me.email', '@myGroups', '@now', '@today', '@today±Nd', '@monthStart', '@monthEnd', '@nextMonthStart', '@quarterStart', '@yearStart'],\n\t},\n\tconfig: {\n\t\tresolver: 'resolveManifestSentinels / resolveFilterTokens',\n\t\tdescription: 'IAppConfig-sourced values. `@resolve:<key>` at manifest-load time; `@config.<key>` (trailing `?` optional) at fetch time.',\n\t\tmembers: ['@resolve:<key>', '@config.<key>', '@config.<key>?'],\n\t},\n\tobject: {\n\t\tresolver: 'resolveFilterTokens',\n\t\tdescription: 'Detail-page object context. Resolve only when a `{ objectId, object }` ctx is supplied.',\n\t\tmembers: ['@objectId', '@object.<field>'],\n\t},\n\tworkspace: {\n\t\tresolver: 'resolveFilterTokens',\n\t\tdescription: 'Page-level workspace state (e.g. a selected client / period). Trailing `?` marks optional (drop when unset).',\n\t\tmembers: ['@workspace.<key>', '@workspace.<key>?'],\n\t},\n\troute: {\n\t\tresolver: 'resolveRouteSentinels',\n\t\tdescription: 'vue-router param substitution at render time.',\n\t\tmembers: ['@route.<param>'],\n\t},\n\tdeclarative: {\n\t\tresolver: 'fetchAggregate (OpenRegister server-side)',\n\t\tdescription: 'OpenRegister declarative direction — resolved server-side. `@self.<field>` is the object\\'s own field in a cross-object calc; `@ref`/`@aggregate` are reserved (currently unused fleet-wide).',\n\t\tmembers: ['@self.<field>', '@ref:<path>', '@aggregate:<expr>'],\n\t},\n\tvisibleWhen: {\n\t\tresolver: 'evaluateVisibleWhen (utils/visibleWhen.js)',\n\t\tdescription: 'The shared visibleWhen predicate\\'s source-mode collection-total marker. `field: \"@total\"` (or an omitted `field`) compares the collection total instead of the first result.',\n\t\tmembers: ['@total'],\n\t},\n\tanswer: {\n\t\tresolver: 'resolveAssignValue (utils/formAssign.js)',\n\t\tdescription: 'Another answer in the same form, read by a field\\'s `assign` rule.',\n\t\tmembers: ['@answer.<field>'],\n\t},\n\trow: {\n\t\tresolver: 'CnFieldListWidget (rowActions request url and payload)',\n\t\tdescription: 'A field of the row a row action runs on, read by the field-list widget when it sends the action\\'s request. Dot paths are allowed (`@row.owner.id`).',\n\t\tmembers: ['@row.<field>'],\n\t},\n\tsubject: {\n\t\tresolver: 'CnBannerWidget (action route params and query)',\n\t\tdescription: 'A field of the record an attention card names (the first row of its ordered `visibleWhen` source query), read when the card builds an action\\'s route. Dot paths are allowed (`@subject.owner.id`).',\n\t\tmembers: ['@subject.<field>'],\n\t},\n})\n\n/**\n * Machine-readable deprecation map: single-app inventions → canonical\n * replacement (or `null` for removal) + removal date. The shared resolver still\n * resolves a deprecated token during the window (emitting a one-time warn); the\n * gate WARNs (not fails) until `removal`. Each entry carries a `test` RegExp so\n * a parameterised deprecated token (`@page.period`) matches its family.\n *\n * @type {Readonly<Record<string, {test: RegExp, replacement: (string|null), removal: string, note: string}>>}\n */\nexport const SENTINEL_DEPRECATIONS = Object.freeze({\n\t'@currentFiscalYear': {\n\t\ttest: /^@currentFiscalYear$/,\n\t\treplacement: '@config.fiscalYear',\n\t\tremoval: '2026-10-01',\n\t\tnote: 'Single-app invention (shillinq). Source the fiscal year from IAppConfig instead of the calendar year.',\n\t},\n\t'@page.<key>': {\n\t\ttest: /^@page\\.[A-Za-z][A-Za-z0-9_]*$/,\n\t\treplacement: '@workspace.<key>',\n\t\tremoval: '2026-10-01',\n\t\tnote: 'Single-app invention (pipelinq). Page-context state is the workspace context; use @workspace.<key>.',\n\t},\n\t'@runtime': {\n\t\ttest: /^@runtime(?:\\.[A-Za-z][A-Za-z0-9_]*)?$/,\n\t\treplacement: null,\n\t\tremoval: '2026-10-01',\n\t\tnote: 'Single-app invention. No canonical equivalent — resolve via @workspace.<key> / @route.<param> or remove.',\n\t},\n})\n\n// --- Runtime RegExps (the resolvers import these — one source of truth) -----\n\n/** `@resolve:<key>` — full match with a captured key group. */\nexport const RESOLVE_TOKEN_RE = /^@resolve:([a-z][a-z0-9_-]*)$/\n\n/** `@route.<param>` — full match with a captured param group. */\nexport const ROUTE_TOKEN_RE = /^@route\\.([A-Za-z][A-Za-z0-9_-]*)$/\n\n/** `@today±Nd` — full match with a captured signed-day-delta group. */\nexport const TODAY_DELTA_RE = /^@today([+-]\\d+)d$/\n\n/** Compiled per-context matchers (anchored, from SENTINEL_TOKEN_PATTERNS). */\nconst CONTEXT_RE = Object.freeze(Object.fromEntries(Object.entries(SENTINEL_TOKEN_PATTERNS).map(([ctx, pat]) => [ctx, new RegExp(pat)])))\n\n/**\n * True when `value` is a string that begins with `@` (i.e. shaped like a\n * sentinel, regardless of membership).\n *\n * @param {unknown} value Candidate.\n * @return {boolean}\n */\nexport function looksLikeSentinel(value) {\n\treturn typeof value === 'string' && value.charAt(0) === '@'\n}\n\n/**\n * The canonical context a token belongs to, or `null` if it is not a member of\n * any canonical context. Deprecated tokens return `null` here (they are not a\n * canonical context) — use {@link matchDeprecation} to detect those.\n *\n * @param {string} token The `@`-prefixed token.\n * @return {(string|null)} A member of {@link SENTINEL_CONTEXTS} or null.\n */\nexport function contextOf(token) {\n\tif (typeof token !== 'string') {\n\t\treturn null\n\t}\n\tfor (const ctx of SENTINEL_CONTEXTS) {\n\t\tif (CONTEXT_RE[ctx].test(token)) {\n\t\t\treturn ctx\n\t\t}\n\t}\n\treturn null\n}\n\n/**\n * True when `token` is a member of the closed CANONICAL vocabulary (any\n * context). Deprecated tokens are NOT canonical (return false).\n *\n * @param {string} token The `@`-prefixed token.\n * @return {boolean}\n */\nexport function isKnownToken(token) {\n\treturn contextOf(token) !== null\n}\n\n/**\n * The deprecation entry matching `token`, or `null`. A deprecated token is\n * accepted by the schema (its pattern is in the union) but the gate + resolver\n * flag it.\n *\n * @param {string} token The `@`-prefixed token.\n * @return {({key: string, replacement: (string|null), removal: string, note: string}|null)}\n */\nexport function matchDeprecation(token) {\n\tif (typeof token !== 'string') {\n\t\treturn null\n\t}\n\tfor (const [key, entry] of Object.entries(SENTINEL_DEPRECATIONS)) {\n\t\tif (entry.test.test(token)) {\n\t\t\treturn { key, replacement: entry.replacement, removal: entry.removal, note: entry.note }\n\t\t}\n\t}\n\treturn null\n}\n\n/**\n * Classify a token for gate / dispatcher consumption.\n *\n * @param {string} token The `@`-prefixed token.\n * @return {{status: ('known'|'deprecated'|'unknown'), context: (string|null), deprecation: (object|null)}}\n */\nexport function classifyToken(token) {\n\tconst deprecation = matchDeprecation(token)\n\tif (deprecation) {\n\t\treturn { status: 'deprecated', context: null, deprecation }\n\t}\n\tconst context = contextOf(token)\n\tif (context) {\n\t\treturn { status: 'known', context, deprecation: null }\n\t}\n\treturn { status: 'unknown', context: null, deprecation: null }\n}\n\n/**\n * Scan a manifest's `pages[].config` and widget `filter`/`dataSource` string\n * leaves for `@`-prefixed values and bucket them. The reusable CORE of the\n * hydra token-vocabulary gate — the gate wraps this (diff-scope + exit code)\n * and MUST import it rather than hardcode the vocabulary.\n *\n * Only `@`-prefixed strings under `pages[]` are considered (router/registry\n * invariants elsewhere are out of scope, matching the schema `$def` placement).\n *\n * @param {object} manifest A parsed manifest object.\n * @return {{unknown: Array<{token: string, path: string}>,\n * deprecated: Array<{token: string, path: string, replacement: (string|null), removal: string}>,\n * known: number}}\n */\nexport function scanManifestTokens(manifest) {\n\tconst unknown = []\n\tconst deprecated = []\n\tlet known = 0\n\n\tconst visit = (node, path) => {\n\t\tif (typeof node === 'string') {\n\t\t\tif (!looksLikeSentinel(node)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst c = classifyToken(node)\n\t\t\tif (c.status === 'deprecated') {\n\t\t\t\tdeprecated.push({ token: node, path, replacement: c.deprecation.replacement, removal: c.deprecation.removal })\n\t\t\t} else if (c.status === 'unknown') {\n\t\t\t\tunknown.push({ token: node, path })\n\t\t\t} else {\n\t\t\t\tknown += 1\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (Array.isArray(node)) {\n\t\t\tnode.forEach((item, i) => visit(item, `${path}[${i}]`))\n\t\t\treturn\n\t\t}\n\t\tif (node && typeof node === 'object') {\n\t\t\tfor (const [k, v] of Object.entries(node)) {\n\t\t\t\tvisit(v, `${path}.${k}`)\n\t\t\t}\n\t\t}\n\t}\n\n\tconst pages = manifest && Array.isArray(manifest.pages) ? manifest.pages : []\n\tpages.forEach((page, i) => {\n\t\tif (!page || typeof page !== 'object') {\n\t\t\treturn\n\t\t}\n\t\tif (page.config && typeof page.config === 'object') {\n\t\t\tvisit(page.config, `pages[${i}].config`)\n\t\t}\n\t\tif (Array.isArray(page.widgets)) {\n\t\t\tvisit(page.widgets, `pages[${i}].widgets`)\n\t\t}\n\t})\n\n\treturn { unknown, deprecated, known }\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,uBAAuB,GAAG,MAAM,CAAC,MAAM,CAAC;AACrD,CAAC,MAAM,EAAE,yIAAyI;AAClJ,CAAC,MAAM,EAAE,oEAAoE;AAC7E,CAAC,MAAM,EAAE,+CAA+C;AACxD,CAAC,SAAS,EAAE,0CAA0C;AACtD,CAAC,KAAK,EAAE,mCAAmC;AAC3C,CAAC,WAAW,EAAE,iFAAiF;AAC/F;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,WAAW,EAAE,UAAU;AACxB;AACA,CAAC,MAAM,EAAE,mCAAmC;AAC5C;AACA;AACA,CAAC,GAAG,EAAE,kCAAkC;AACxC;AACA;AACA,CAAC,OAAO,EAAE,qCAAqC;AAC/C;AACA;AACA;AACA,CAAC,UAAU,EAAE,8FAA8F;AAC3G,CAAC,EAAC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;AAC/C,CAAC,QAAQ;AACT,CAAC,QAAQ;AACT,CAAC,QAAQ;AACT,CAAC,WAAW;AACZ,CAAC,OAAO;AACR,CAAC,aAAa;AACd,CAAC,aAAa;AACd,CAAC,QAAQ;AACT,CAAC,KAAK;AACN,CAAC,SAAS;AACV,CAAC,EAAC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC;AACjD,CAAC,MAAM,EAAE;AACT,EAAE,QAAQ,EAAE,qBAAqB;AACjC,EAAE,WAAW,EAAE,sGAAsG;AACrH,EAAE,OAAO,EAAE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"}
|
|
1
|
+
{"version":3,"file":"sentinelTokens.js","sources":["../../../src/utils/sentinelTokens.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * Closed, context-partitioned manifest **sentinel-token vocabulary** — the\n * single source of truth for every `@`-prefixed dynamic value a manifest may\n * carry under `pages[].config` or a widget `filter`/`dataSource`.\n *\n * Before this module the token surface was scattered across four resolvers\n * (`resolveManifestSentinels`, `resolveFilterTokens`, `resolveRouteSentinels`,\n * `fetchAggregate`) plus ad-hoc single-app inventions (`@currentFiscalYear`,\n * `@page.*`, `@runtime`). This module declares the vocabulary ONCE so:\n *\n * 1. the JSON-Schema `$defs` in `app-manifest-v2.schema.json` reject an\n * out-of-vocabulary token (the pattern strings here are the exact strings\n * mirrored into the schema — a unit test enforces byte-equality);\n * 2. the shared resolver dispatch (`resolveManifestTokens.js`) and the four\n * resolvers import their token patterns from here rather than re-declaring\n * them, so the runtime and the schema cannot drift;\n * 3. a hydra manifest gate can `scanManifestTokens()` an app and FAIL an\n * unknown token / WARN a deprecated one, reusing this export (no hardcoded\n * copy).\n *\n * ## Context partitions\n *\n * A token is valid only in the context whose resolver runs on it:\n *\n * - **filter** — `resolveFilterTokens`, resolved at fetch time:\n * `@me`, `@myGroups`, `@now`, `@today`, `@today±Nd`, `@monthStart`, `@monthEnd`, `@nextMonthStart`,\n * `@quarterStart`, `@yearStart`.\n * - **config** — `IAppConfig`-sourced: `@resolve:<key>`, `@config.<key>`\n * (trailing `?` marks optional).\n * - **object** — detail-page object context: `@objectId`,\n * `@object.<field>`.\n * - **workspace** — page-level workspace state: `@workspace.<key>`\n * (trailing `?` optional).\n * - **route** — `resolveRouteSentinels`: `@route.<param>`.\n * - **declarative** — OpenRegister direction, resolved server-side:\n * `@self.<field>` (the object's own field in a\n * cross-object calc), `@ref:<path>`, `@aggregate:<expr>`.\n * - **visibleWhen** — the shared `visibleWhen` predicate's `source`-mode\n * collection-total marker, resolved client-side by\n * `evaluateVisibleWhen` (`utils/visibleWhen.js`):\n * `@total` (a `field: \"@total\"` — or omitted `field` —\n * compares the collection total rather than the first\n * result). Added for manifest-form-logic:\n * `config.fields[].visibleWhen` is the first\n * `visibleWhen` reachable through the\n * sentinelGuardedValue-guarded `pages[].config` subtree.\n *\n * `@ref`/`@aggregate` are first-class members even though currently unused\n * fleet-wide — they are the OR-declarative direction and belong in the closed\n * vocabulary so a future adopter validates rather than inventing a variant.\n *\n * @module utils/sentinelTokens\n */\n\n/**\n * Pattern STRINGS, one per context — the canonical source mirrored verbatim\n * into `app-manifest-v2.schema.json`'s `$defs`. A unit test asserts each schema\n * `$def`'s `pattern` equals the string here, so the two cannot drift.\n *\n * NOTE: these are JS string literals; a `\\\\.` here is the two-character\n * sequence `\\.` at runtime, which is exactly what the JSON schema stores after\n * its own `\\\\.` is parsed. Compare PARSED values, never raw source.\n *\n * @type {Readonly<Record<string, string>>}\n */\nexport const SENTINEL_TOKEN_PATTERNS = Object.freeze({\n\tfilter: '^@(?:me(?:\\\\.(?:displayName|email))?|myGroups|now|today|monthStart|monthEnd|nextMonthStart|quarterStart|yearStart)$|^@today[+-][0-9]+d$',\n\tconfig: '^@resolve:[a-z][a-z0-9_-]*$|^@config\\\\.[A-Za-z][A-Za-z0-9_.]*\\\\??$',\n\tobject: '^@objectId$|^@object\\\\.[A-Za-z][A-Za-z0-9_]*$',\n\tworkspace: '^@workspace\\\\.[A-Za-z][A-Za-z0-9_]*\\\\??$',\n\troute: '^@route\\\\.[A-Za-z][A-Za-z0-9_-]*$',\n\tdeclarative: '^@self\\\\.[A-Za-z][A-Za-z0-9_]*$|^@ref:[A-Za-z][A-Za-z0-9_./-]*$|^@aggregate:.+$',\n\t// manifest-form-logic: the shared visibleWhen predicate's source-mode\n\t// collection-total marker (`field: \"@total\"`), resolved client-side by\n\t// evaluateVisibleWhen — not one of the four IAppConfig/OpenRegister\n\t// resolvers, but a real pre-existing convention (already documented on\n\t// $defs.visibleWhen and the banner widget) now reachable through the\n\t// sentinelGuardedValue-guarded pages[].config subtree for the first time\n\t// via config.fields[].visibleWhen.\n\tvisibleWhen: '^@total$',\n\t// form-live-values: another answer in the same form, read by a field's `assign` rule.\n\tanswer: '^@answer\\\\.[A-Za-z][A-Za-z0-9_]*$',\n\t// A field of the row a row action is run on (`@row.<field>`, dot path), read by the\n\t// field-list widget's `rowActions` request URL and payload.\n\trow: '^@row\\\\.[A-Za-z][A-Za-z0-9_.@]*$',\n\t// A field of the record a start-here attention card names (`@subject.<field>`, dot path),\n\t// read by the banner widget's action routes.\n\tsubject: '^@subject\\\\.[A-Za-z][A-Za-z0-9_.]*$',\n\t// A record a detail page reads beside the loaded one (`visibilityContext`), read by a\n\t// grid widget's or a tab's `visibleWhen` as `@context.<name>.<field>` (dot path).\n\tcontext: '^@context\\\\.[A-Za-z][A-Za-z0-9_.]*$',\n\t// Deprecated-but-not-yet-removed tokens. Kept in the schema union so\n\t// deployed manifests still validate during the migration window; the gate\n\t// downgrades them to a WARN (see SENTINEL_DEPRECATIONS).\n\tdeprecated: '^@currentFiscalYear$|^@page\\\\.[A-Za-z][A-Za-z0-9_]*$|^@runtime(?:\\\\.[A-Za-z][A-Za-z0-9_]*)?$',\n})\n\n/**\n * The nine canonical context names (excludes `deprecated`, which is a\n * transitional overlay, not a resolution context).\n *\n * @type {string[]}\n */\nexport const SENTINEL_CONTEXTS = Object.freeze([\n\t'filter',\n\t'config',\n\t'object',\n\t'workspace',\n\t'route',\n\t'declarative',\n\t'visibleWhen',\n\t'answer',\n\t'row',\n\t'subject',\n\t'context',\n])\n\n/**\n * Human-readable vocabulary: members + context + owning resolver + parameter\n * grammar. Documentation-facing (feeds audit item 16 schema-generated docs);\n * the machine-checkable truth is {@link SENTINEL_TOKEN_PATTERNS}.\n *\n * @type {Readonly<Record<string, {resolver: string, description: string, members: string[]}>>}\n */\nexport const SENTINEL_VOCABULARY = Object.freeze({\n\tfilter: {\n\t\tresolver: 'resolveFilterTokens',\n\t\tdescription: 'Relative fetch-time tokens (current user, the current user\\'s groups as an IN list, relative dates).',\n\t\tmembers: ['@me', '@me.displayName', '@me.email', '@myGroups', '@now', '@today', '@today±Nd', '@monthStart', '@monthEnd', '@nextMonthStart', '@quarterStart', '@yearStart'],\n\t},\n\tconfig: {\n\t\tresolver: 'resolveManifestSentinels / resolveFilterTokens',\n\t\tdescription: 'IAppConfig-sourced values. `@resolve:<key>` at manifest-load time; `@config.<key>` (trailing `?` optional) at fetch time.',\n\t\tmembers: ['@resolve:<key>', '@config.<key>', '@config.<key>?'],\n\t},\n\tobject: {\n\t\tresolver: 'resolveFilterTokens',\n\t\tdescription: 'Detail-page object context. Resolve only when a `{ objectId, object }` ctx is supplied.',\n\t\tmembers: ['@objectId', '@object.<field>'],\n\t},\n\tworkspace: {\n\t\tresolver: 'resolveFilterTokens',\n\t\tdescription: 'Page-level workspace state (e.g. a selected client / period). Trailing `?` marks optional (drop when unset).',\n\t\tmembers: ['@workspace.<key>', '@workspace.<key>?'],\n\t},\n\troute: {\n\t\tresolver: 'resolveRouteSentinels',\n\t\tdescription: 'vue-router param substitution at render time.',\n\t\tmembers: ['@route.<param>'],\n\t},\n\tdeclarative: {\n\t\tresolver: 'fetchAggregate (OpenRegister server-side)',\n\t\tdescription: 'OpenRegister declarative direction — resolved server-side. `@self.<field>` is the object\\'s own field in a cross-object calc; `@ref`/`@aggregate` are reserved (currently unused fleet-wide).',\n\t\tmembers: ['@self.<field>', '@ref:<path>', '@aggregate:<expr>'],\n\t},\n\tvisibleWhen: {\n\t\tresolver: 'evaluateVisibleWhen (utils/visibleWhen.js)',\n\t\tdescription: 'The shared visibleWhen predicate\\'s source-mode collection-total marker. `field: \"@total\"` (or an omitted `field`) compares the collection total instead of the first result.',\n\t\tmembers: ['@total'],\n\t},\n\tanswer: {\n\t\tresolver: 'resolveAssignValue (utils/formAssign.js)',\n\t\tdescription: 'Another answer in the same form, read by a field\\'s `assign` rule.',\n\t\tmembers: ['@answer.<field>'],\n\t},\n\trow: {\n\t\tresolver: 'CnFieldListWidget (rowActions request url and payload)',\n\t\tdescription: 'A field of the row a row action runs on, read by the field-list widget when it sends the action\\'s request. Dot paths are allowed (`@row.owner.id`).',\n\t\tmembers: ['@row.<field>'],\n\t},\n\tsubject: {\n\t\tresolver: 'CnBannerWidget (action route params and query)',\n\t\tdescription: 'A field of the record an attention card names (the first row of its ordered `visibleWhen` source query), read when the card builds an action\\'s route. Dot paths are allowed (`@subject.owner.id`).',\n\t\tmembers: ['@subject.<field>'],\n\t},\n\tcontext: {\n\t\tresolver: 'CnDetailPage visibilityContext (detailWidgetVisibility), read by a grid widget\\'s or a tab\\'s visibleWhen',\n\t\tdescription: 'A record the detail page reads beside the loaded one, named in `config.visibilityContext` (a case\\'s case type). A `visibleWhen` field reads it as `@context.<name>.<field>`, dot paths allowed (`@context.caseType.category`).',\n\t\tmembers: ['@context.<name>.<field>'],\n\t},\n})\n\n/**\n * Machine-readable deprecation map: single-app inventions → canonical\n * replacement (or `null` for removal) + removal date. The shared resolver still\n * resolves a deprecated token during the window (emitting a one-time warn); the\n * gate WARNs (not fails) until `removal`. Each entry carries a `test` RegExp so\n * a parameterised deprecated token (`@page.period`) matches its family.\n *\n * @type {Readonly<Record<string, {test: RegExp, replacement: (string|null), removal: string, note: string}>>}\n */\nexport const SENTINEL_DEPRECATIONS = Object.freeze({\n\t'@currentFiscalYear': {\n\t\ttest: /^@currentFiscalYear$/,\n\t\treplacement: '@config.fiscalYear',\n\t\tremoval: '2026-10-01',\n\t\tnote: 'Single-app invention (shillinq). Source the fiscal year from IAppConfig instead of the calendar year.',\n\t},\n\t'@page.<key>': {\n\t\ttest: /^@page\\.[A-Za-z][A-Za-z0-9_]*$/,\n\t\treplacement: '@workspace.<key>',\n\t\tremoval: '2026-10-01',\n\t\tnote: 'Single-app invention (pipelinq). Page-context state is the workspace context; use @workspace.<key>.',\n\t},\n\t'@runtime': {\n\t\ttest: /^@runtime(?:\\.[A-Za-z][A-Za-z0-9_]*)?$/,\n\t\treplacement: null,\n\t\tremoval: '2026-10-01',\n\t\tnote: 'Single-app invention. No canonical equivalent — resolve via @workspace.<key> / @route.<param> or remove.',\n\t},\n})\n\n// --- Runtime RegExps (the resolvers import these — one source of truth) -----\n\n/** `@resolve:<key>` — full match with a captured key group. */\nexport const RESOLVE_TOKEN_RE = /^@resolve:([a-z][a-z0-9_-]*)$/\n\n/** `@route.<param>` — full match with a captured param group. */\nexport const ROUTE_TOKEN_RE = /^@route\\.([A-Za-z][A-Za-z0-9_-]*)$/\n\n/** `@today±Nd` — full match with a captured signed-day-delta group. */\nexport const TODAY_DELTA_RE = /^@today([+-]\\d+)d$/\n\n/** Compiled per-context matchers (anchored, from SENTINEL_TOKEN_PATTERNS). */\nconst CONTEXT_RE = Object.freeze(Object.fromEntries(Object.entries(SENTINEL_TOKEN_PATTERNS).map(([ctx, pat]) => [ctx, new RegExp(pat)])))\n\n/**\n * True when `value` is a string that begins with `@` (i.e. shaped like a\n * sentinel, regardless of membership).\n *\n * @param {unknown} value Candidate.\n * @return {boolean}\n */\nexport function looksLikeSentinel(value) {\n\treturn typeof value === 'string' && value.charAt(0) === '@'\n}\n\n/**\n * The canonical context a token belongs to, or `null` if it is not a member of\n * any canonical context. Deprecated tokens return `null` here (they are not a\n * canonical context) — use {@link matchDeprecation} to detect those.\n *\n * @param {string} token The `@`-prefixed token.\n * @return {(string|null)} A member of {@link SENTINEL_CONTEXTS} or null.\n */\nexport function contextOf(token) {\n\tif (typeof token !== 'string') {\n\t\treturn null\n\t}\n\tfor (const ctx of SENTINEL_CONTEXTS) {\n\t\tif (CONTEXT_RE[ctx].test(token)) {\n\t\t\treturn ctx\n\t\t}\n\t}\n\treturn null\n}\n\n/**\n * True when `token` is a member of the closed CANONICAL vocabulary (any\n * context). Deprecated tokens are NOT canonical (return false).\n *\n * @param {string} token The `@`-prefixed token.\n * @return {boolean}\n */\nexport function isKnownToken(token) {\n\treturn contextOf(token) !== null\n}\n\n/**\n * The deprecation entry matching `token`, or `null`. A deprecated token is\n * accepted by the schema (its pattern is in the union) but the gate + resolver\n * flag it.\n *\n * @param {string} token The `@`-prefixed token.\n * @return {({key: string, replacement: (string|null), removal: string, note: string}|null)}\n */\nexport function matchDeprecation(token) {\n\tif (typeof token !== 'string') {\n\t\treturn null\n\t}\n\tfor (const [key, entry] of Object.entries(SENTINEL_DEPRECATIONS)) {\n\t\tif (entry.test.test(token)) {\n\t\t\treturn { key, replacement: entry.replacement, removal: entry.removal, note: entry.note }\n\t\t}\n\t}\n\treturn null\n}\n\n/**\n * Classify a token for gate / dispatcher consumption.\n *\n * @param {string} token The `@`-prefixed token.\n * @return {{status: ('known'|'deprecated'|'unknown'), context: (string|null), deprecation: (object|null)}}\n */\nexport function classifyToken(token) {\n\tconst deprecation = matchDeprecation(token)\n\tif (deprecation) {\n\t\treturn { status: 'deprecated', context: null, deprecation }\n\t}\n\tconst context = contextOf(token)\n\tif (context) {\n\t\treturn { status: 'known', context, deprecation: null }\n\t}\n\treturn { status: 'unknown', context: null, deprecation: null }\n}\n\n/**\n * Scan a manifest's `pages[].config` and widget `filter`/`dataSource` string\n * leaves for `@`-prefixed values and bucket them. The reusable CORE of the\n * hydra token-vocabulary gate — the gate wraps this (diff-scope + exit code)\n * and MUST import it rather than hardcode the vocabulary.\n *\n * Only `@`-prefixed strings under `pages[]` are considered (router/registry\n * invariants elsewhere are out of scope, matching the schema `$def` placement).\n *\n * @param {object} manifest A parsed manifest object.\n * @return {{unknown: Array<{token: string, path: string}>,\n * deprecated: Array<{token: string, path: string, replacement: (string|null), removal: string}>,\n * known: number}}\n */\nexport function scanManifestTokens(manifest) {\n\tconst unknown = []\n\tconst deprecated = []\n\tlet known = 0\n\n\tconst visit = (node, path) => {\n\t\tif (typeof node === 'string') {\n\t\t\tif (!looksLikeSentinel(node)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst c = classifyToken(node)\n\t\t\tif (c.status === 'deprecated') {\n\t\t\t\tdeprecated.push({ token: node, path, replacement: c.deprecation.replacement, removal: c.deprecation.removal })\n\t\t\t} else if (c.status === 'unknown') {\n\t\t\t\tunknown.push({ token: node, path })\n\t\t\t} else {\n\t\t\t\tknown += 1\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (Array.isArray(node)) {\n\t\t\tnode.forEach((item, i) => visit(item, `${path}[${i}]`))\n\t\t\treturn\n\t\t}\n\t\tif (node && typeof node === 'object') {\n\t\t\tfor (const [k, v] of Object.entries(node)) {\n\t\t\t\tvisit(v, `${path}.${k}`)\n\t\t\t}\n\t\t}\n\t}\n\n\tconst pages = manifest && Array.isArray(manifest.pages) ? manifest.pages : []\n\tpages.forEach((page, i) => {\n\t\tif (!page || typeof page !== 'object') {\n\t\t\treturn\n\t\t}\n\t\tif (page.config && typeof page.config === 'object') {\n\t\t\tvisit(page.config, `pages[${i}].config`)\n\t\t}\n\t\tif (Array.isArray(page.widgets)) {\n\t\t\tvisit(page.widgets, `pages[${i}].widgets`)\n\t\t}\n\t})\n\n\treturn { unknown, deprecated, known }\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,uBAAuB,GAAG,MAAM,CAAC,MAAM,CAAC;AACrD,CAAC,MAAM,EAAE,yIAAyI;AAClJ,CAAC,MAAM,EAAE,oEAAoE;AAC7E,CAAC,MAAM,EAAE,+CAA+C;AACxD,CAAC,SAAS,EAAE,0CAA0C;AACtD,CAAC,KAAK,EAAE,mCAAmC;AAC3C,CAAC,WAAW,EAAE,iFAAiF;AAC/F;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,WAAW,EAAE,UAAU;AACxB;AACA,CAAC,MAAM,EAAE,mCAAmC;AAC5C;AACA;AACA,CAAC,GAAG,EAAE,kCAAkC;AACxC;AACA;AACA,CAAC,OAAO,EAAE,qCAAqC;AAC/C;AACA;AACA,CAAC,OAAO,EAAE,qCAAqC;AAC/C;AACA;AACA;AACA,CAAC,UAAU,EAAE,8FAA8F;AAC3G,CAAC,EAAC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;AAC/C,CAAC,QAAQ;AACT,CAAC,QAAQ;AACT,CAAC,QAAQ;AACT,CAAC,WAAW;AACZ,CAAC,OAAO;AACR,CAAC,aAAa;AACd,CAAC,aAAa;AACd,CAAC,QAAQ;AACT,CAAC,KAAK;AACN,CAAC,SAAS;AACV,CAAC,SAAS;AACV,CAAC,EAAC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC;AACjD,CAAC,MAAM,EAAE;AACT,EAAE,QAAQ,EAAE,qB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"}
|