@conduction/nextcloud-vue 2.82.0 → 2.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +2 -2
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +24 -0
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +9 -4
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- 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 +125 -3
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js +3 -3
- 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 +14 -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/CnIndexPage/CnIndexPage.vue2.js +96 -12
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +95 -50
- package/dist/esm/components/CnIndexPage/CnIndexPage.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/CnMassActionBar/CnMassActionBar.vue2.js +2 -2
- package/dist/esm/components/CnMassActionBar/CnMassActionBar.vue2.js.map +1 -1
- package/dist/esm/components/CnMassImportDialog/CnMassImportDialog.vue2.js +2 -2
- package/dist/esm/components/CnMassImportDialog/CnMassImportDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +31 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js +1 -1
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js +16 -2
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js +3 -3
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.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 +176 -0
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js +181 -52
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js +1 -1
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js +70 -5
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js +61 -35
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.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 +4 -2
- 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 +72 -5
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +88 -71
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js +1 -1
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js +18 -4
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.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/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/l10n/en.json.js +16 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +41 -4
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +900 -537
- 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/fetchAggregate.js +25 -2
- package/dist/esm/utils/fetchAggregate.js.map +1 -1
- package/dist/esm/utils/formatMetric.js +39 -3
- package/dist/esm/utils/formatMetric.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/switchValues.js +62 -0
- package/dist/esm/utils/switchValues.js.map +1 -0
- 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 +36711 -34909
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +900 -537
- package/l10n/en.json +16 -1
- package/l10n/nl.json +41 -4
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +31 -2
- 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 +128 -6
- package/src/components/CnDashboardPage/CnDashboardPage.vue +14 -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/CnIndexPage/CnIndexPage.vue +125 -15
- package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +29 -6
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +31 -2
- package/src/components/CnRadioCardsWidget/CnRadioCardsWidget.vue +54 -3
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +37 -2
- package/src/components/CnReportsPage/CnReportsPage.vue +263 -5
- package/src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue +110 -18
- package/src/components/CnStagesWidget/CnStagesWidget.vue +103 -6
- package/src/components/CnStatWidget/CnStatWidget.vue +4 -2
- package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +125 -7
- package/src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue +18 -4
- package/src/components/CnTabsWidget/CnTabsWidget.vue +33 -3
- package/src/components/CnWalkthrough/CnWalkthrough.vue +16 -0
- package/src/css/form-field.css +14 -0
- package/src/css/form-widget.css +11 -0
- package/src/css/index-page.css +11 -0
- package/src/css/index.css +1 -0
- package/src/css/look-board-reports.css +175 -0
- package/src/css/look-board.css +44 -1
- package/src/dialogs/CnTransitionInputDialog.vue +87 -7
- package/src/schemas/app-manifest-v2.schema.json +24 -3
- package/src/utils/buildManifest.js +36 -2
- package/src/utils/detailWidgetVisibility.js +145 -0
- package/src/utils/fetchAggregate.js +24 -1
- package/src/utils/formatMetric.js +38 -2
- package/src/utils/resolveManifestTokens.js +1 -0
- package/src/utils/sentinelTokens.js +9 -0
- package/src/utils/switchValues.js +59 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -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":";;;;;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;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC;AAChD,CAAC,MAAM,EAAE,qBAAqB;AAC9B,CAAC,MAAM,EAAE,gDAAgD;AACzD,CAAC,MAAM,EAAE,qBAAqB;AAC9B,CAAC,SAAS,EAAE,qBAAqB;AACjC,CAAC,KAAK,EAAE,uBAAuB;AAC/B,CAAC,WAAW,EAAE,2CAA2C;AACzD,CAAC,WAAW,EAAE,4CAA4C;AAC1D,CAAC,MAAM,EAAE,0CAA0C;AACnD,CAAC,GAAG,EAAE,wCAAwC;AAC9C,CAAC,OAAO,EAAE,+BAA+B;AACzC,CAAC,EAAC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,mBAAmB,GAAG,IAAI,GAAG,GAAE;AACrC;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,wBAAwB,GAAG;AAC3C,CAAC,mBAAmB,CAAC,KAAK,GAAE;AAC5B,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE;AAC9C,CAAC,MAAM,GAAG,GAAG,gBAAgB,CAAC,KAAK,EAAC;AACpC,CAAC,IAAI,CAAC,GAAG,EAAE;AACX,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACtC,EAAE,mBAAmB,CAAC,GAAG,CAAC,KAAK,EAAC;AAChC,EAAE,MAAM,MAAM,GAAG,GAAG,CAAC,WAAW;AAChC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC;AACvC,KAAK,gDAA+C;AACpD,EAAE,IAAI,CAAC,CAAC,mDAAmD,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AAClF,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,EAAC;AAC7C,EAAE;AACF,CAAC,OAAO,IAAI;AACZ,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,sBAAsB,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE;AACzD,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,GAAG,IAAI,CAAC,MAAM,GAAG,GAAE;AACjF,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,GAAG,IAAI,CAAC,GAAG,GAAG,GAAE;AACrE,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,YAAW;AAC1C,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,KAAK;AACzC;AACA,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,EAAC;AACvB,EAAE,EAAC;AACH;AACA;AACA;AACA,CAAC,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAC;AAChE;AACA;AACA;AACA,CAAC,MAAM,UAAU,GAAG,GAAE;AACtB,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK;AACxB,EAAE,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;AAChC,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE;AACjC,IAAI,OAAO,IAAI;AACf,IAAI;AACJ,GAAG,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAC;AAC/B,GAAG,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,EAAE,GAAG,EAAC;AACjD,GAAG,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE;AACzD;AACA;AACA,IAAI,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,EAAC;AAC7B,IAAI,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,aAAa,IAAI,CAAC,KAAK,aAAa,EAAE;AACtE,KAAK,UAAU,CAAC,IAAI,CAAC,IAAI,EAAC;AAC1B,KAAK;AACL,IAAI;AACJ,GAAG,OAAO,QAAQ;AAClB,GAAG;AACH,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAC3B,GAAG,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,GAAG;AACH,EAAE,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;AACxC,GAAG,MAAM,GAAG,GAAG,GAAE;AACjB,GAAG,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAC9C,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAC;AACpB,IAAI;AACJ,GAAG,OAAO,GAAG;AACb,GAAG;AACH,EAAE,OAAO,IAAI;AACb,GAAE;AACF;AACA,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE;AAC/C;;;;"}
|
|
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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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*
|
|
5
|
+
* A switch's value map: what a switch reads as "on" and what it writes for on
|
|
6
|
+
* and off. Without a map a switch is a boolean, as before. With `values:
|
|
7
|
+
* { on, off }` it reads a field stored as `"1"`/`"0"` or `"true"`/`"false"`
|
|
8
|
+
* (an app config flag) and writes those values back.
|
|
9
|
+
*
|
|
10
|
+
* @module utils/switchValues
|
|
11
|
+
* @spec openspec/changes/screens-switch-value-map/specs/switch-rows/spec.md#requirement-a-switch-can-read-and-write-a-value-map
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The value map of a switch, or null when it has none (a boolean switch).
|
|
16
|
+
*
|
|
17
|
+
* @param {unknown} values The declared `values`.
|
|
18
|
+
* @return {{on: unknown, off: unknown}|null} The map.
|
|
19
|
+
*/
|
|
20
|
+
function switchValueMap(values) {
|
|
21
|
+
if (!values || typeof values !== 'object' || Array.isArray(values) || values.on === undefined) {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
return { on: values.on, off: values.off === undefined ? null : values.off }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Whether a stored value reads as "on". Without a map only `true` does; with
|
|
29
|
+
* one, the `on` value does, compared as text so `1` and `"1"` are the same.
|
|
30
|
+
*
|
|
31
|
+
* @param {unknown} stored The stored value.
|
|
32
|
+
* @param {unknown} values The declared `values`.
|
|
33
|
+
* @return {boolean} True when the switch shows on.
|
|
34
|
+
*/
|
|
35
|
+
function switchIsOn(stored, values) {
|
|
36
|
+
const map = switchValueMap(values);
|
|
37
|
+
if (!map) {
|
|
38
|
+
return stored === true
|
|
39
|
+
}
|
|
40
|
+
if (stored === undefined || stored === null) {
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
return stored === map.on || String(stored) === String(map.on)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The value a switch writes for a state.
|
|
48
|
+
*
|
|
49
|
+
* @param {boolean} on The switch state.
|
|
50
|
+
* @param {unknown} values The declared `values`.
|
|
51
|
+
* @return {unknown} `true`/`false` without a map, else the map's `on` / `off`.
|
|
52
|
+
*/
|
|
53
|
+
function switchStoredValue(on, values) {
|
|
54
|
+
const map = switchValueMap(values);
|
|
55
|
+
if (!map) {
|
|
56
|
+
return on === true
|
|
57
|
+
}
|
|
58
|
+
return on ? map.on : map.off
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { switchIsOn, switchStoredValue, switchValueMap };
|
|
62
|
+
//# sourceMappingURL=switchValues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"switchValues.js","sources":["../../../src/utils/switchValues.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * A switch's value map: what a switch reads as \"on\" and what it writes for on\n * and off. Without a map a switch is a boolean, as before. With `values:\n * { on, off }` it reads a field stored as `\"1\"`/`\"0\"` or `\"true\"`/`\"false\"`\n * (an app config flag) and writes those values back.\n *\n * @module utils/switchValues\n * @spec openspec/changes/screens-switch-value-map/specs/switch-rows/spec.md#requirement-a-switch-can-read-and-write-a-value-map\n */\n\n/**\n * The value map of a switch, or null when it has none (a boolean switch).\n *\n * @param {unknown} values The declared `values`.\n * @return {{on: unknown, off: unknown}|null} The map.\n */\nexport function switchValueMap(values) {\n\tif (!values || typeof values !== 'object' || Array.isArray(values) || values.on === undefined) {\n\t\treturn null\n\t}\n\treturn { on: values.on, off: values.off === undefined ? null : values.off }\n}\n\n/**\n * Whether a stored value reads as \"on\". Without a map only `true` does; with\n * one, the `on` value does, compared as text so `1` and `\"1\"` are the same.\n *\n * @param {unknown} stored The stored value.\n * @param {unknown} values The declared `values`.\n * @return {boolean} True when the switch shows on.\n */\nexport function switchIsOn(stored, values) {\n\tconst map = switchValueMap(values)\n\tif (!map) {\n\t\treturn stored === true\n\t}\n\tif (stored === undefined || stored === null) {\n\t\treturn false\n\t}\n\treturn stored === map.on || String(stored) === String(map.on)\n}\n\n/**\n * The value a switch writes for a state.\n *\n * @param {boolean} on The switch state.\n * @param {unknown} values The declared `values`.\n * @return {unknown} `true`/`false` without a map, else the map's `on` / `off`.\n */\nexport function switchStoredValue(on, values) {\n\tconst map = switchValueMap(values)\n\tif (!map) {\n\t\treturn on === true\n\t}\n\treturn on ? map.on : map.off\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,MAAM,EAAE;AACvC,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,KAAK,SAAS,EAAE;AAChG,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,KAAK,SAAS,GAAG,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE;AAC5E,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE;AAC3C,CAAC,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,EAAC;AACnC,CAAC,IAAI,CAAC,GAAG,EAAE;AACX,EAAE,OAAO,MAAM,KAAK,IAAI;AACxB,EAAE;AACF,CAAC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,EAAE;AAC9C,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,OAAO,MAAM,KAAK,GAAG,CAAC,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AAC9D,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE;AAC9C,CAAC,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,EAAC;AACnC,CAAC,IAAI,CAAC,GAAG,EAAE;AACX,EAAE,OAAO,EAAE,KAAK,IAAI;AACpB,EAAE;AACF,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG;AAC7B;;;;"}
|