@sap/ux-specification 1.136.15 → 1.136.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +258 -165
- package/dist/documentation/v2/v2-AnalyticalListPage.html +2 -2
- package/dist/documentation/v2/v2-ApplicationV2.html +2 -2
- package/dist/documentation/v2/v2-ListReport.html +2 -2
- package/dist/documentation/v2/v2-ListReportNew.html +2 -2
- package/dist/documentation/v2/v2-ObjectPage.html +2 -2
- package/dist/documentation/v2/v2-OverviewPage.html +2 -2
- package/dist/documentation/v4/v4-ApplicationV4.html +2 -2
- package/dist/documentation/v4/v4-BuildingBlocks.html +2 -2
- package/dist/documentation/v4/v4-FreestylePage.html +2 -2
- package/dist/documentation/v4/v4-ListReport.html +2 -2
- package/dist/documentation/v4/v4-ObjectPage.html +2 -2
- package/dist/index-min.js +280 -274
- package/dist/index-min.js.map +4 -4
- package/dist/schemas/v2/AnalyticalListPageConfig.json +3 -3
- package/dist/schemas/v2/ListReportConfig.json +5 -5
- package/dist/schemas/v2/ListReportNewConfig.json +1 -1
- package/dist/schemas/v2/ObjectPageConfig.json +5 -5
- package/dist/schemas/v4/ApplicationV4.json +1 -1
- package/dist/schemas/v4/BuildingBlocksConfig.json +100 -10
- package/dist/schemas/v4/ListReportConfig.json +24 -6
- package/dist/schemas/v4/ObjectPageConfig.json +32 -8
- package/dist/specification/package.json +14 -12
- package/dist/specification/scripts/extractDocu.js +18 -1
- package/dist/specification/scripts/extractDocu.js.map +1 -1
- package/dist/specification/scripts/generate-validity-report.d.ts +15 -0
- package/dist/specification/scripts/generate-validity-report.d.ts.map +1 -0
- package/dist/specification/scripts/generate-validity-report.js +367 -0
- package/dist/specification/scripts/generate-validity-report.js.map +1 -0
- package/dist/specification/scripts/macros/corrections.d.ts +40 -0
- package/dist/specification/scripts/macros/corrections.d.ts.map +1 -1
- package/dist/specification/scripts/macros/corrections.js +114 -7
- package/dist/specification/scripts/macros/corrections.js.map +1 -1
- package/dist/specification/scripts/macros/schema.d.ts.map +1 -1
- package/dist/specification/scripts/macros/schema.js +14 -1
- package/dist/specification/scripts/macros/schema.js.map +1 -1
- package/dist/specification/scripts/macros/types.d.ts +1 -0
- package/dist/specification/scripts/macros/types.d.ts.map +1 -1
- package/dist/specification/scripts/schema/to-json-schema.d.ts.map +1 -1
- package/dist/specification/scripts/schema/to-json-schema.js +2 -13
- package/dist/specification/scripts/schema/to-json-schema.js.map +1 -1
- package/dist/specification/src/api.js +1 -1
- package/dist/specification/src/i18n/i18n.d.ts.map +1 -1
- package/dist/specification/src/i18n/i18n.js +2 -1
- package/dist/specification/src/i18n/i18n.js.map +1 -1
- package/dist/specification/src/sync/common/ManifestDrivenSchemaProcessor.d.ts +8 -1
- package/dist/specification/src/sync/common/ManifestDrivenSchemaProcessor.d.ts.map +1 -1
- package/dist/specification/src/sync/common/ManifestDrivenSchemaProcessor.js +10 -6
- package/dist/specification/src/sync/common/ManifestDrivenSchemaProcessor.js.map +1 -1
- package/dist/specification/src/sync/common/decoration/decorator-paths.d.ts +503 -0
- package/dist/specification/src/sync/common/decoration/decorator-paths.d.ts.map +1 -0
- package/dist/specification/src/sync/common/decoration/decorator-paths.js +497 -0
- package/dist/specification/src/sync/common/decoration/decorator-paths.js.map +1 -0
- package/dist/specification/src/sync/common/decoration/decorators.d.ts +116 -24
- package/dist/specification/src/sync/common/decoration/decorators.d.ts.map +1 -1
- package/dist/specification/src/sync/common/decoration/decorators.js +308 -78
- package/dist/specification/src/sync/common/decoration/decorators.js.map +1 -1
- package/dist/specification/src/sync/common/decoration/index.d.ts +1 -0
- package/dist/specification/src/sync/common/decoration/index.d.ts.map +1 -1
- package/dist/specification/src/sync/common/decoration/index.js +1 -0
- package/dist/specification/src/sync/common/decoration/index.js.map +1 -1
- package/dist/specification/src/sync/common/dist_tag.json +8 -3
- package/dist/specification/src/sync/common/generate/utils.d.ts +2 -1
- package/dist/specification/src/sync/common/generate/utils.d.ts.map +1 -1
- package/dist/specification/src/sync/common/generate/utils.js +5 -1
- package/dist/specification/src/sync/common/generate/utils.js.map +1 -1
- package/dist/specification/src/sync/common/i18n.json +2 -1
- package/dist/specification/src/sync/common/rules.d.ts +20 -0
- package/dist/specification/src/sync/common/rules.d.ts.map +1 -1
- package/dist/specification/src/sync/common/rules.js +22 -2
- package/dist/specification/src/sync/common/rules.js.map +1 -1
- package/dist/specification/src/sync/common/utils.d.ts +22 -6
- package/dist/specification/src/sync/common/utils.d.ts.map +1 -1
- package/dist/specification/src/sync/common/utils.js +122 -18
- package/dist/specification/src/sync/common/utils.js.map +1 -1
- package/dist/specification/src/sync/v2/generate/analyticalListReport.d.ts.map +1 -1
- package/dist/specification/src/sync/v2/generate/analyticalListReport.js +9 -7
- package/dist/specification/src/sync/v2/generate/analyticalListReport.js.map +1 -1
- package/dist/specification/src/sync/v2/generate/listReport.d.ts.map +1 -1
- package/dist/specification/src/sync/v2/generate/listReport.js +3 -1
- package/dist/specification/src/sync/v2/generate/listReport.js.map +1 -1
- package/dist/specification/src/sync/v2/generate/objectPage.d.ts.map +1 -1
- package/dist/specification/src/sync/v2/generate/objectPage.js +58 -2
- package/dist/specification/src/sync/v2/generate/objectPage.js.map +1 -1
- package/dist/specification/src/sync/v2/generate/overviewPage.d.ts +1 -9
- package/dist/specification/src/sync/v2/generate/overviewPage.d.ts.map +1 -1
- package/dist/specification/src/sync/v2/generate/overviewPage.js +30 -1
- package/dist/specification/src/sync/v2/generate/overviewPage.js.map +1 -1
- package/dist/specification/src/sync/v2/import/app/appProvider.d.ts.map +1 -1
- package/dist/specification/src/sync/v2/import/app/appProvider.js +2 -0
- package/dist/specification/src/sync/v2/import/app/appProvider.js.map +1 -1
- package/dist/specification/src/sync/v2/import/pages/analyticalListPage.d.ts +2 -1
- package/dist/specification/src/sync/v2/import/pages/analyticalListPage.d.ts.map +1 -1
- package/dist/specification/src/sync/v2/import/pages/analyticalListPage.js +5 -0
- package/dist/specification/src/sync/v2/import/pages/analyticalListPage.js.map +1 -1
- package/dist/specification/src/sync/v2/import/pages/listReport.d.ts +2 -1
- package/dist/specification/src/sync/v2/import/pages/listReport.d.ts.map +1 -1
- package/dist/specification/src/sync/v2/import/pages/listReport.js +5 -0
- package/dist/specification/src/sync/v2/import/pages/listReport.js.map +1 -1
- package/dist/specification/src/sync/v2/import/pages/objectPage.d.ts.map +1 -1
- package/dist/specification/src/sync/v2/import/pages/objectPage.js +2 -1
- package/dist/specification/src/sync/v2/import/pages/objectPage.js.map +1 -1
- package/dist/specification/src/sync/v2/import/utils.d.ts +28 -1
- package/dist/specification/src/sync/v2/import/utils.d.ts.map +1 -1
- package/dist/specification/src/sync/v2/import/utils.js +37 -0
- package/dist/specification/src/sync/v2/import/utils.js.map +1 -1
- package/dist/specification/src/sync/v2/utils.d.ts +12 -2
- package/dist/specification/src/sync/v2/utils.d.ts.map +1 -1
- package/dist/specification/src/sync/v2/utils.js +19 -2
- package/dist/specification/src/sync/v2/utils.js.map +1 -1
- package/dist/specification/src/sync/v4/application.d.ts +31 -2
- package/dist/specification/src/sync/v4/application.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/application.js +44 -4
- package/dist/specification/src/sync/v4/application.js.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/FilterBar.d.ts +2 -1
- package/dist/specification/src/sync/v4/export/controls/FilterBar.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/FilterBar.js +2 -1
- package/dist/specification/src/sync/v4/export/controls/FilterBar.js.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/Header.d.ts +4 -3
- package/dist/specification/src/sync/v4/export/controls/Header.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/Header.js +7 -3
- package/dist/specification/src/sync/v4/export/controls/Header.js.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/HeaderAction.d.ts +2 -1
- package/dist/specification/src/sync/v4/export/controls/HeaderAction.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/HeaderAction.js +7 -0
- package/dist/specification/src/sync/v4/export/controls/HeaderAction.js.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/ObjectPageCustomSection.d.ts +2 -1
- package/dist/specification/src/sync/v4/export/controls/ObjectPageCustomSection.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/ObjectPageCustomSection.js +2 -1
- package/dist/specification/src/sync/v4/export/controls/ObjectPageCustomSection.js.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/ObjectPageTable.d.ts +1 -1
- package/dist/specification/src/sync/v4/export/controls/ObjectPageTable.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/ObjectPageTable.js +0 -13
- package/dist/specification/src/sync/v4/export/controls/ObjectPageTable.js.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/Table.d.ts +32 -17
- package/dist/specification/src/sync/v4/export/controls/Table.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/Table.js +84 -58
- package/dist/specification/src/sync/v4/export/controls/Table.js.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/TableColumn.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/TableColumn.js +2 -2
- package/dist/specification/src/sync/v4/export/controls/TableColumn.js.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/ToolBarAction.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/export/controls/ToolBarAction.js +2 -2
- package/dist/specification/src/sync/v4/export/controls/ToolBarAction.js.map +1 -1
- package/dist/specification/src/sync/v4/export/export.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/export/export.js +25 -3
- package/dist/specification/src/sync/v4/export/export.js.map +1 -1
- package/dist/specification/src/sync/v4/export/pages/ListReport.js +1 -1
- package/dist/specification/src/sync/v4/export/pages/ListReport.js.map +1 -1
- package/dist/specification/src/sync/v4/generate/actions.d.ts +1 -1
- package/dist/specification/src/sync/v4/generate/actions.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/generate/fpm-custom-page/annotations.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/generate/fpm-custom-page/annotations.js +20 -12
- package/dist/specification/src/sync/v4/generate/fpm-custom-page/annotations.js.map +1 -1
- package/dist/specification/src/sync/v4/generate/fpm-custom-page/generator.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/generate/fpm-custom-page/generator.js +16 -1
- package/dist/specification/src/sync/v4/generate/fpm-custom-page/generator.js.map +1 -1
- package/dist/specification/src/sync/v4/generate/fpm-custom-page/utils.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/generate/fpm-custom-page/utils.js +10 -1
- package/dist/specification/src/sync/v4/generate/fpm-custom-page/utils.js.map +1 -1
- package/dist/specification/src/sync/v4/generate/index.d.ts +1 -1
- package/dist/specification/src/sync/v4/generate/index.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/generate/index.js +1 -1
- package/dist/specification/src/sync/v4/generate/index.js.map +1 -1
- package/dist/specification/src/sync/v4/generate/list-report/ListReportUtils.d.ts +73 -0
- package/dist/specification/src/sync/v4/generate/list-report/ListReportUtils.d.ts.map +1 -0
- package/dist/specification/src/sync/v4/generate/list-report/ListReportUtils.js +354 -0
- package/dist/specification/src/sync/v4/generate/list-report/ListReportUtils.js.map +1 -0
- package/dist/specification/src/sync/v4/generate/{listReport.d.ts → list-report/listReport.d.ts} +27 -16
- package/dist/specification/src/sync/v4/generate/list-report/listReport.d.ts.map +1 -0
- package/dist/specification/src/sync/v4/generate/{listReport.js → list-report/listReport.js} +191 -163
- package/dist/specification/src/sync/v4/generate/list-report/listReport.js.map +1 -0
- package/dist/specification/src/sync/v4/generate/objectPage.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/generate/objectPage.js +145 -44
- package/dist/specification/src/sync/v4/generate/objectPage.js.map +1 -1
- package/dist/specification/src/sync/v4/import/pages/listReport.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/import/pages/listReport.js +2 -1
- package/dist/specification/src/sync/v4/import/pages/listReport.js.map +1 -1
- package/dist/specification/src/sync/v4/import/utils.js +5 -3
- package/dist/specification/src/sync/v4/import/utils.js.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/App.d.ts +9 -7
- package/dist/specification/src/sync/v4/sync-rules/App.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/App.js +4 -8
- package/dist/specification/src/sync/v4/sync-rules/App.js.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/AppSchema.d.ts +2 -9
- package/dist/specification/src/sync/v4/sync-rules/AppSchema.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/AppSchema.js +2 -11
- package/dist/specification/src/sync/v4/sync-rules/AppSchema.js.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/DecoratorClass.d.ts +219 -96
- package/dist/specification/src/sync/v4/sync-rules/DecoratorClass.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/DecoratorClass.js +557 -211
- package/dist/specification/src/sync/v4/sync-rules/DecoratorClass.js.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/Page.d.ts +17 -22
- package/dist/specification/src/sync/v4/sync-rules/Page.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/Page.js +15 -22
- package/dist/specification/src/sync/v4/sync-rules/Page.js.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/controllerExtensions.d.ts +1 -0
- package/dist/specification/src/sync/v4/sync-rules/controllerExtensions.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/controllerExtensions.js +17 -9
- package/dist/specification/src/sync/v4/sync-rules/controllerExtensions.js.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/index.d.ts +5 -0
- package/dist/specification/src/sync/v4/sync-rules/index.d.ts.map +1 -0
- package/dist/specification/src/sync/v4/sync-rules/index.js +21 -0
- package/dist/specification/src/sync/v4/sync-rules/index.js.map +1 -0
- package/dist/specification/src/sync/v4/sync-rules/utils.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/sync-rules/utils.js +4 -0
- package/dist/specification/src/sync/v4/sync-rules/utils.js.map +1 -1
- package/dist/specification/src/sync/v4/utils/index.d.ts +2 -0
- package/dist/specification/src/sync/v4/utils/index.d.ts.map +1 -0
- package/dist/specification/src/sync/v4/utils/index.js +18 -0
- package/dist/specification/src/sync/v4/utils/index.js.map +1 -0
- package/dist/specification/src/sync/v4/utils/utils.d.ts +9 -1
- package/dist/specification/src/sync/v4/utils/utils.d.ts.map +1 -1
- package/dist/specification/src/sync/v4/utils/utils.js +17 -2
- package/dist/specification/src/sync/v4/utils/utils.js.map +1 -1
- package/dist/specification/test/test-projects/v2sttaProdMan2/webapp/manifest.json +550 -0
- package/dist/specification/test/test-projects/v4new/webapp/manifest.json +147 -0
- package/dist/specification/test/test-utils/utils.d.ts +71 -0
- package/dist/specification/test/test-utils/utils.d.ts.map +1 -0
- package/dist/specification/test/test-utils/utils.js +400 -0
- package/dist/specification/test/test-utils/utils.js.map +1 -0
- package/dist/specification/test/unit/decorators/validity-test-utils.d.ts +131 -0
- package/dist/specification/test/unit/decorators/validity-test-utils.d.ts.map +1 -0
- package/dist/specification/test/unit/decorators/validity-test-utils.js +661 -0
- package/dist/specification/test/unit/decorators/validity-test-utils.js.map +1 -0
- package/dist/types/src/apiTypes.d.ts +2 -3
- package/dist/types/src/apiTypes.d.ts.map +1 -1
- package/dist/types/src/apiTypes.js.map +1 -1
- package/dist/types/src/common/types.d.ts +119 -13
- package/dist/types/src/common/types.d.ts.map +1 -1
- package/dist/types/src/common/types.js.map +1 -1
- package/dist/types/src/v2/controls/ObjectPageTable.d.ts +1 -1
- package/dist/types/src/v2/controls/Table.d.ts +1 -1
- package/dist/types/src/v4/controls/ObjectPageTable.d.ts +1 -1
- package/dist/types/src/v4/controls/ObjectPageTable.d.ts.map +1 -1
- package/dist/types/src/v4/controls/Table.d.ts +3 -3
- package/dist/types/src/v4/controls/Table.d.ts.map +1 -1
- package/package.json +14 -12
- package/dist/specification/src/sync/v4/generate/ListReportUtils.d.ts +0 -107
- package/dist/specification/src/sync/v4/generate/ListReportUtils.d.ts.map +0 -1
- package/dist/specification/src/sync/v4/generate/ListReportUtils.js +0 -394
- package/dist/specification/src/sync/v4/generate/ListReportUtils.js.map +0 -1
- package/dist/specification/src/sync/v4/generate/listReport.d.ts.map +0 -1
- package/dist/specification/src/sync/v4/generate/listReport.js.map +0 -1
|
@@ -3,19 +3,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.Decorator = exports.BaseClass = void 0;
|
|
6
|
+
exports.Decorator = exports.BaseClass = exports.BaseConstruct = void 0;
|
|
7
7
|
const ux_specification_types_1 = require("@sap/ux-specification-types");
|
|
8
8
|
const decoration_1 = require("../../common/decoration");
|
|
9
9
|
const i18next_1 = __importDefault(require("i18next"));
|
|
10
|
+
const jsonpath_plus_1 = require("jsonpath-plus");
|
|
10
11
|
const utils_1 = require("./utils");
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
-
* Inlined to avoid circular dependency issues.
|
|
13
|
+
* Appends a message to a schema element's message array.
|
|
14
|
+
* Inlined here to avoid circular dependency issues.
|
|
14
15
|
*
|
|
15
|
-
* @param element - The schema element
|
|
16
|
-
* @param message - The message
|
|
17
|
-
* @param message.text - The message text
|
|
18
|
-
* @param message.deletable - Whether the
|
|
16
|
+
* @param element - The schema element that will receive the message
|
|
17
|
+
* @param message - The message content and options
|
|
18
|
+
* @param message.text - The translated message text to display
|
|
19
|
+
* @param message.deletable - Whether the user can dismiss the message (default: false)
|
|
19
20
|
*/
|
|
20
21
|
function addMessageToSchema(element, { text, deletable = false }) {
|
|
21
22
|
if (!element[ux_specification_types_1.SchemaTag.messages]) {
|
|
@@ -23,77 +24,103 @@ function addMessageToSchema(element, { text, deletable = false }) {
|
|
|
23
24
|
}
|
|
24
25
|
element[ux_specification_types_1.SchemaTag.messages].push({ text, deletable });
|
|
25
26
|
}
|
|
26
|
-
class
|
|
27
|
+
class BaseConstruct {
|
|
27
28
|
/**
|
|
28
|
-
* Creates
|
|
29
|
+
* Creates the base construct with access to the app schema, app/page configuration, and logger.
|
|
29
30
|
*
|
|
30
|
-
* @param
|
|
31
|
+
* @param settings - Shared context (appSchema, app, page, logger) passed to all decorator classes
|
|
31
32
|
*/
|
|
32
|
-
constructor(
|
|
33
|
-
|
|
33
|
+
constructor(settings) {
|
|
34
|
+
const { app, appSchema, page, logger } = settings || {};
|
|
35
|
+
// Define properties as non-enumerable to hide them from serialization and Object.keys()
|
|
34
36
|
Object.defineProperty(this, 'appSchema', {
|
|
35
37
|
value: appSchema,
|
|
36
|
-
writable:
|
|
38
|
+
writable: false,
|
|
39
|
+
enumerable: false,
|
|
40
|
+
configurable: true
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(this, 'app', {
|
|
43
|
+
value: app,
|
|
44
|
+
writable: false,
|
|
45
|
+
enumerable: false,
|
|
46
|
+
configurable: true
|
|
47
|
+
});
|
|
48
|
+
Object.defineProperty(this, 'page', {
|
|
49
|
+
value: page,
|
|
50
|
+
writable: false,
|
|
51
|
+
enumerable: false,
|
|
52
|
+
configurable: true
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(this, 'logger', {
|
|
55
|
+
value: logger,
|
|
56
|
+
writable: false,
|
|
37
57
|
enumerable: false,
|
|
38
58
|
configurable: true
|
|
39
59
|
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Returns the shared context (appSchema, app, page, logger) for use by subclasses or callers.
|
|
63
|
+
*
|
|
64
|
+
* @returns The current settings object
|
|
65
|
+
*/
|
|
66
|
+
getSettings() {
|
|
67
|
+
return {
|
|
68
|
+
appSchema: this.appSchema,
|
|
69
|
+
app: this.app,
|
|
70
|
+
page: this.page,
|
|
71
|
+
logger: this.logger
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.BaseConstruct = BaseConstruct;
|
|
76
|
+
class BaseClass extends BaseConstruct {
|
|
77
|
+
/**
|
|
78
|
+
* Looks up the matching schema definition by class name and stores it as the base.
|
|
79
|
+
*
|
|
80
|
+
* @param settings - Shared context (appSchema, app, page, logger) passed to all decorator classes
|
|
81
|
+
*/
|
|
82
|
+
constructor(settings) {
|
|
83
|
+
super(settings);
|
|
40
84
|
const name = this.getClassName();
|
|
41
|
-
const definitions = appSchema?.definitions;
|
|
42
85
|
// Define base as non-enumerable to hide it from serialization and Object.keys()
|
|
43
86
|
Object.defineProperty(this, 'base', {
|
|
44
|
-
value: { name, definition: definitions?.[name] },
|
|
87
|
+
value: { name, definition: this.appSchema?.get().definitions?.[name] },
|
|
45
88
|
writable: true,
|
|
46
89
|
enumerable: false,
|
|
47
90
|
configurable: true
|
|
48
91
|
});
|
|
49
92
|
}
|
|
50
93
|
/**
|
|
51
|
-
*
|
|
94
|
+
* Returns the class name used to look up the matching schema definition.
|
|
52
95
|
*
|
|
53
|
-
* @returns The name of
|
|
96
|
+
* @returns The constructor name of this class
|
|
54
97
|
*/
|
|
55
98
|
getClassName() {
|
|
56
99
|
return this.constructor.name;
|
|
57
100
|
}
|
|
58
101
|
/**
|
|
59
|
-
*
|
|
102
|
+
* Returns the name stored at construction time for the schema definition lookup.
|
|
60
103
|
*
|
|
61
|
-
* @returns The base name
|
|
104
|
+
* @returns The base definition name
|
|
62
105
|
*/
|
|
63
106
|
getBaseName() {
|
|
64
107
|
return this.base.name;
|
|
65
108
|
}
|
|
66
109
|
/**
|
|
67
|
-
*
|
|
110
|
+
* Returns the schema definition that decorators are applied to.
|
|
68
111
|
*
|
|
69
|
-
* @returns The
|
|
112
|
+
* @returns The JSON schema definition for this class
|
|
70
113
|
*/
|
|
71
114
|
getBase() {
|
|
72
115
|
return this.base.definition;
|
|
73
116
|
}
|
|
74
117
|
/**
|
|
75
|
-
*
|
|
118
|
+
* Builds an annotation path like `/<EntityType>/@<Term>#<Qualifier>` and stores it on the schema definition.
|
|
76
119
|
*
|
|
77
|
-
* @param
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Gets the definitions from the app schema.
|
|
84
|
-
*
|
|
85
|
-
* @returns The definitions object or undefined
|
|
86
|
-
*/
|
|
87
|
-
getDefinitions() {
|
|
88
|
-
return this.appSchema?.definitions;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Creates an annotation path for schema based on entity type, term, and qualifier.
|
|
92
|
-
*
|
|
93
|
-
* @param entityTypeName - Entity type name.
|
|
94
|
-
* @param term - Annotation term.
|
|
95
|
-
* @param qualifier - Annotation qualifier (optional).
|
|
96
|
-
* @returns Annotation path based on received params
|
|
120
|
+
* @param entityTypeName - The OData entity type name (e.g. "SalesOrderItem")
|
|
121
|
+
* @param term - The annotation term (e.g. "com.sap.vocabularies.UI.v1.LineItem")
|
|
122
|
+
* @param qualifier - Optional qualifier to disambiguate multiple annotations of the same term
|
|
123
|
+
* @returns The built annotation path, or undefined if entityTypeName is empty
|
|
97
124
|
*/
|
|
98
125
|
createAnnotationPath(entityTypeName, term, qualifier) {
|
|
99
126
|
if (!entityTypeName) {
|
|
@@ -110,70 +137,116 @@ class BaseClass {
|
|
|
110
137
|
exports.BaseClass = BaseClass;
|
|
111
138
|
class Decorator extends BaseClass {
|
|
112
139
|
/**
|
|
113
|
-
* Sets the
|
|
114
|
-
* This enables nested decorators to access parent properties using the '../' prefix in @dependsOn.
|
|
140
|
+
* Sets up the decorator context as non-enumerable so it stays hidden from serialization.
|
|
115
141
|
*
|
|
116
|
-
* @param
|
|
117
|
-
* @returns this (for method chaining)
|
|
142
|
+
* @param settings - Shared context (appSchema, app, page, logger) passed to all decorator classes
|
|
118
143
|
*/
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
144
|
+
constructor(settings) {
|
|
145
|
+
super(settings);
|
|
146
|
+
// Define decoratorContext as non-enumerable to hide from serialization
|
|
147
|
+
Object.defineProperty(this, 'decoratorContext', {
|
|
148
|
+
value: {},
|
|
149
|
+
writable: true,
|
|
150
|
+
enumerable: false,
|
|
151
|
+
configurable: true
|
|
152
|
+
});
|
|
122
153
|
}
|
|
123
154
|
/**
|
|
124
|
-
*
|
|
155
|
+
* Builds the decorator context from app, page, and custom values, then applies all
|
|
156
|
+
* decorators (enums, message, hide, readonly) to the schema definition.
|
|
157
|
+
*
|
|
158
|
+
* @param customContext - Specific values (e.g. table state, section state) used for condition evaluation
|
|
159
|
+
* @param definition - Override the schema definition to decorate (defaults to getBase())
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* // Basic initialization (app and page auto-injected)
|
|
163
|
+
* decorator.init();
|
|
164
|
+
*
|
|
165
|
+
* // With custom context for table-specific conditions
|
|
166
|
+
* decorator.init({
|
|
167
|
+
* table: { type: 'GridTable', views: [] }
|
|
168
|
+
* });
|
|
125
169
|
*
|
|
126
|
-
*
|
|
170
|
+
* // With custom definition (for dynamically created definitions)
|
|
171
|
+
* decorator.init({ table: { type: 'GridTable' } }, customTableDefinition);
|
|
172
|
+
* ```
|
|
127
173
|
*/
|
|
128
|
-
|
|
129
|
-
|
|
174
|
+
init(customContext, definition) {
|
|
175
|
+
this.decoratorContext = {
|
|
176
|
+
app: this.app?.config,
|
|
177
|
+
page: this.page?.config,
|
|
178
|
+
custom: customContext
|
|
179
|
+
};
|
|
180
|
+
// @ToDo activate for actual use of minUI5Version.
|
|
181
|
+
// const minUi5Version = this.app?.getMinUI5Version();
|
|
182
|
+
this.applyDecorators(undefined, undefined, definition);
|
|
130
183
|
}
|
|
131
184
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
185
|
+
* Resolves a dotted property path (e.g. `page.isALP`, `custom.items[0].name`) against
|
|
186
|
+
* the decorator context using JSONPath. The path must start with a known source prefix
|
|
187
|
+
* (`app`, `page`, or `custom`).
|
|
135
188
|
*
|
|
136
|
-
* @param
|
|
137
|
-
* @
|
|
138
|
-
* @
|
|
189
|
+
* @param propertyPath - Dotted path with source prefix, supports full JSONPath syntax
|
|
190
|
+
* @returns The resolved `{ key, value }` pair, or undefined if the path does not resolve
|
|
191
|
+
* @example
|
|
192
|
+
* ```typescript
|
|
193
|
+
* // With decoratorContext = {
|
|
194
|
+
* // app: { manifest: { 'sap.ui5': { routing: {...} } } },
|
|
195
|
+
* // page: { isALP: true },
|
|
196
|
+
* // custom: { type: 'GridTable', items: [{ name: 'Item1' }, { name: 'Item2' }] }
|
|
197
|
+
* // }
|
|
198
|
+
* getPropertyKeyValue('page.isALP') // { key: 'isALP', value: true }
|
|
199
|
+
* getPropertyKeyValue('custom.items[0]') // { key: '0', value: { name: 'Item1' } }
|
|
200
|
+
* getPropertyKeyValue('custom.items[1].name') // { key: 'name', value: 'Item2' }
|
|
201
|
+
* getPropertyKeyValue('app.manifest["sap.ui5"]') // Access property with dot in name
|
|
202
|
+
* getPropertyKeyValue('$.app.manifest["sap.ui5"].routing') // JSONPath with root reference
|
|
203
|
+
* getPropertyKeyValue('$app["manifest"]["sap.ui5"]') // Alternative JSONPath format
|
|
204
|
+
* ```
|
|
139
205
|
*/
|
|
140
|
-
getPropertyKeyValue(
|
|
141
|
-
if (!
|
|
206
|
+
getPropertyKeyValue(propertyPath) {
|
|
207
|
+
if (!propertyPath || !this.decoratorContext) {
|
|
142
208
|
return undefined;
|
|
143
209
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
210
|
+
try {
|
|
211
|
+
// Ensure path starts with $ for JSONPath
|
|
212
|
+
const jsonPath = propertyPath.startsWith('$') ? propertyPath : `$.${propertyPath}`;
|
|
213
|
+
// Use JSONPath to query with resultType 'all' to get both value and metadata
|
|
214
|
+
const results = (0, jsonpath_plus_1.JSONPath)({
|
|
215
|
+
path: jsonPath,
|
|
216
|
+
json: this.decoratorContext,
|
|
217
|
+
resultType: 'all'
|
|
218
|
+
});
|
|
219
|
+
// JSONPath with resultType 'all' returns an array of result objects
|
|
220
|
+
if (!results || results.length === 0) {
|
|
148
221
|
return undefined;
|
|
149
222
|
}
|
|
150
|
-
//
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
value = value[key];
|
|
223
|
+
// Get the first result (wrap: false behavior)
|
|
224
|
+
const result = results[0];
|
|
225
|
+
// parentProperty contains the last key in the path
|
|
226
|
+
const key = String(result.parentProperty);
|
|
227
|
+
const value = result.value;
|
|
228
|
+
return { key, value };
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// If JSONPath fails, return undefined
|
|
232
|
+
return undefined;
|
|
161
233
|
}
|
|
162
|
-
const key = keys[keys.length - 1];
|
|
163
|
-
return { key, value };
|
|
164
234
|
}
|
|
165
235
|
/**
|
|
166
|
-
* Evaluates
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* @param condition
|
|
170
|
-
* @
|
|
171
|
-
* @param condition.expectedValue - Optional expected value for equality check
|
|
172
|
-
* @param syncRuleProviderInstance - The sync rule provider instance
|
|
173
|
-
* @returns Object containing whether condition passed and the dependency value
|
|
236
|
+
* Evaluates one condition: resolves the path, applies the check (custom function,
|
|
237
|
+
* equality, or truthy), and optionally negates the result (for `not()` conditions).
|
|
238
|
+
*
|
|
239
|
+
* @param condition - A single condition with path, expected value, and optional negate flag
|
|
240
|
+
* @returns Whether the condition passed along with the resolved value and key
|
|
174
241
|
*/
|
|
175
|
-
evaluateSingleCondition(condition
|
|
176
|
-
|
|
242
|
+
evaluateSingleCondition(condition) {
|
|
243
|
+
// Handle special __always__ path (from @hide(true))
|
|
244
|
+
if (condition.path === '__always__') {
|
|
245
|
+
return { passed: true, value: true, key: '__always__' };
|
|
246
|
+
}
|
|
247
|
+
const result = this.getPropertyKeyValue(condition.path);
|
|
248
|
+
const key = result?.key ?? condition.path;
|
|
249
|
+
const value = result?.value;
|
|
177
250
|
let passed = false;
|
|
178
251
|
if (condition.dependsOn) {
|
|
179
252
|
// Use custom condition function
|
|
@@ -187,29 +260,82 @@ class Decorator extends BaseClass {
|
|
|
187
260
|
// Default: truthy check
|
|
188
261
|
passed = !!value;
|
|
189
262
|
}
|
|
263
|
+
// Apply negation if negate flag is set (from not() helper)
|
|
264
|
+
if (condition.negate) {
|
|
265
|
+
passed = !passed;
|
|
266
|
+
}
|
|
190
267
|
return { passed, value, key };
|
|
191
268
|
}
|
|
192
269
|
/**
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
* @param
|
|
197
|
-
* @param
|
|
198
|
-
* @param
|
|
199
|
-
* @param i18nProperties
|
|
200
|
-
* @param i18nProperties.
|
|
270
|
+
* Translates and attaches a message to a schema property.
|
|
271
|
+
* Supports both the new `MessageConfig` format (from `msg()` helper) and the legacy `DependsOnMessage` format.
|
|
272
|
+
*
|
|
273
|
+
* @param condition - The decorator metadata or enum value condition containing the message definition
|
|
274
|
+
* @param decoratedClass - The decorated class instance, used for legacy function-based message text
|
|
275
|
+
* @param definition - The schema property definition to attach the message to
|
|
276
|
+
* @param i18nProperties - Context for i18n translation (propertyName, evaluation context)
|
|
277
|
+
* @param i18nProperties.propertyName - The property name used as i18n parameter
|
|
278
|
+
* @param i18nProperties.context - The evaluation context string used as i18n parameter
|
|
201
279
|
*/
|
|
202
|
-
addConditionalMessage(condition,
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
280
|
+
addConditionalMessage(condition, decoratedClass, definition, i18nProperties) {
|
|
281
|
+
// Handle new MessageConfig format (from msg() helper)
|
|
282
|
+
const metadata = condition;
|
|
283
|
+
if (metadata.messageConfig && (0, decoration_1.isMessageConfig)(metadata.messageConfig)) {
|
|
284
|
+
// Resolve any PathNode values in the params
|
|
285
|
+
const resolvedParams = this.resolveMessageParams(metadata.messageConfig.params);
|
|
286
|
+
const messageText = i18next_1.default.t(metadata.messageConfig.i18nKey, resolvedParams);
|
|
287
|
+
addMessageToSchema(definition, { text: messageText, deletable: metadata.messageConfig.deletable });
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
// Handle legacy DependsOnMessage format
|
|
291
|
+
if (!condition.message) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
let messageText;
|
|
295
|
+
if (typeof condition.message.text === 'function') {
|
|
296
|
+
messageText = condition.message.text(decoratedClass);
|
|
297
|
+
}
|
|
298
|
+
else if (typeof condition.message.text === 'string') {
|
|
299
|
+
messageText = condition.message.text;
|
|
300
|
+
}
|
|
301
|
+
else if (condition.message.text === true) {
|
|
302
|
+
// true means use default i18n translation
|
|
303
|
+
messageText = i18next_1.default.t('PROPERTY_NOT_ALLOWED', { ...i18nProperties });
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
messageText = i18next_1.default.t('PROPERTY_NOT_ALLOWED', { ...i18nProperties });
|
|
307
|
+
}
|
|
206
308
|
addMessageToSchema(definition, { text: messageText, deletable: condition.message.deletable });
|
|
207
309
|
}
|
|
208
310
|
/**
|
|
209
|
-
*
|
|
311
|
+
* Resolves any `PathNode` values in message params to their actual values from the decorator context.
|
|
210
312
|
*
|
|
211
|
-
* @param
|
|
212
|
-
* @returns
|
|
313
|
+
* @param params - Message parameters that may contain PathNode references
|
|
314
|
+
* @returns A new params object with PathNode values replaced by their resolved context values
|
|
315
|
+
*/
|
|
316
|
+
resolveMessageParams(params) {
|
|
317
|
+
if (!params) {
|
|
318
|
+
return params;
|
|
319
|
+
}
|
|
320
|
+
const resolved = {};
|
|
321
|
+
for (const [key, value] of Object.entries(params)) {
|
|
322
|
+
if ((0, decoration_1.isPathNode)(value)) {
|
|
323
|
+
// Resolve PathNode to actual value
|
|
324
|
+
const result = this.getPropertyKeyValue((0, decoration_1.getPath)(value));
|
|
325
|
+
resolved[key] = result?.value ?? '';
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
resolved[key] = value;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return resolved;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Builds a human-readable context string from the evaluation results that did not pass.
|
|
335
|
+
* Used for diagnostic messages showing which conditions were unmet.
|
|
336
|
+
*
|
|
337
|
+
* @param results - The condition evaluation results to summarize
|
|
338
|
+
* @returns A comma-separated string of `key: value` pairs for failed conditions
|
|
213
339
|
*/
|
|
214
340
|
getContextForMessage(results) {
|
|
215
341
|
return results
|
|
@@ -218,53 +344,234 @@ class Decorator extends BaseClass {
|
|
|
218
344
|
.join(', ');
|
|
219
345
|
}
|
|
220
346
|
/**
|
|
221
|
-
*
|
|
347
|
+
* Evaluates one item inside an AND group — either a single condition or a nested OR group.
|
|
348
|
+
*
|
|
349
|
+
* @param conditionItem - A single condition or a nested `{ __orConditions }` group
|
|
350
|
+
* @returns Whether the item passed and the detailed evaluation results
|
|
351
|
+
*/
|
|
352
|
+
evaluateAndConditionItem(conditionItem) {
|
|
353
|
+
// Check if this is a nested OR group
|
|
354
|
+
if ((0, decoration_1.isOrConditionGroup)(conditionItem)) {
|
|
355
|
+
// Evaluate the nested OR - at least one must pass
|
|
356
|
+
return this.evaluateOrConditions(conditionItem.__orConditions);
|
|
357
|
+
}
|
|
358
|
+
// It's a single condition
|
|
359
|
+
const result = this.evaluateSingleCondition(conditionItem);
|
|
360
|
+
return { passed: result.passed, results: [result] };
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Evaluates OR conditions — passes when at least one item (single condition or nested AND group) matches.
|
|
364
|
+
* Short-circuits on the first passing item.
|
|
365
|
+
*
|
|
366
|
+
* @param orConditions - Array of conditions or nested AND groups to evaluate
|
|
367
|
+
* @returns Whether any condition passed and the collected evaluation results
|
|
368
|
+
*/
|
|
369
|
+
evaluateOrConditions(orConditions) {
|
|
370
|
+
const allResults = [];
|
|
371
|
+
for (const conditionItem of orConditions) {
|
|
372
|
+
// Check if this is a nested AND group
|
|
373
|
+
if ((0, decoration_1.isAndConditionGroup)(conditionItem)) {
|
|
374
|
+
// Evaluate all conditions in the AND group - all must pass
|
|
375
|
+
const andResults = [];
|
|
376
|
+
let allAndPassed = true;
|
|
377
|
+
for (const andItem of conditionItem.__andConditions) {
|
|
378
|
+
const { passed, results } = this.evaluateAndConditionItem(andItem);
|
|
379
|
+
andResults.push(...results);
|
|
380
|
+
if (!passed) {
|
|
381
|
+
allAndPassed = false;
|
|
382
|
+
// Don't break - we want all results for context
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
allResults.push(...andResults);
|
|
386
|
+
if (allAndPassed) {
|
|
387
|
+
// Short-circuit: if this AND group passes, the OR passes
|
|
388
|
+
return { passed: true, results: allResults };
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
// Single condition (symmetric with AND handling)
|
|
393
|
+
const result = this.evaluateSingleCondition(conditionItem);
|
|
394
|
+
allResults.push(result);
|
|
395
|
+
if (result.passed) {
|
|
396
|
+
// Short-circuit: if any condition passes, the OR passes
|
|
397
|
+
return { passed: true, results: allResults };
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return { passed: false, results: allResults };
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Evaluates AND conditions — passes only when every item (single condition or nested OR group) matches.
|
|
405
|
+
* Continues even after a failure to collect all results for diagnostic context.
|
|
222
406
|
*
|
|
223
|
-
* @param
|
|
224
|
-
* @
|
|
407
|
+
* @param andConditions - Array of conditions or nested OR groups that must all pass
|
|
408
|
+
* @returns Whether all conditions passed and the collected evaluation results
|
|
225
409
|
*/
|
|
226
|
-
|
|
227
|
-
|
|
410
|
+
evaluateAndConditions(andConditions) {
|
|
411
|
+
const allResults = [];
|
|
412
|
+
let allPassed = true;
|
|
413
|
+
for (const conditionItem of andConditions) {
|
|
414
|
+
const { passed, results } = this.evaluateAndConditionItem(conditionItem);
|
|
415
|
+
allResults.push(...results);
|
|
416
|
+
if (!passed) {
|
|
417
|
+
allPassed = false;
|
|
418
|
+
// Continue to collect all results for context
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return { passed: allPassed, results: allResults };
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Entry point for condition evaluation. Dispatches to OR, AND, or single evaluation
|
|
425
|
+
* depending on the shape of the condition metadata.
|
|
426
|
+
*
|
|
427
|
+
* @param conditionInfo - The decorator condition metadata (single, AND, or OR)
|
|
428
|
+
* @returns Whether the condition passed and a diagnostic context string
|
|
429
|
+
*/
|
|
430
|
+
evaluateCondition(conditionInfo) {
|
|
431
|
+
let passed = false;
|
|
432
|
+
let context = '';
|
|
433
|
+
if (conditionInfo.orConditions && Array.isArray(conditionInfo.orConditions)) {
|
|
434
|
+
// OR logic: At least one condition object must match
|
|
435
|
+
const result = this.evaluateOrConditions(conditionInfo.orConditions);
|
|
436
|
+
passed = result.passed;
|
|
437
|
+
context = this.getContextForMessage(result.results);
|
|
438
|
+
}
|
|
439
|
+
else if (conditionInfo.conditions && Array.isArray(conditionInfo.conditions)) {
|
|
440
|
+
// Multi-condition: ALL must be met (AND logic)
|
|
441
|
+
// Now supports nested OR groups via evaluateAndConditions
|
|
442
|
+
const result = this.evaluateAndConditions(conditionInfo.conditions);
|
|
443
|
+
passed = result.passed;
|
|
444
|
+
context = this.getContextForMessage(result.results);
|
|
445
|
+
}
|
|
446
|
+
else if (conditionInfo.path) {
|
|
447
|
+
// Single condition
|
|
448
|
+
const result = this.evaluateSingleCondition(conditionInfo);
|
|
449
|
+
passed = result.passed;
|
|
450
|
+
context = this.getContextForMessage([result]);
|
|
451
|
+
}
|
|
452
|
+
return { passed, context };
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Yields each property from a schema definition for decorator processing.
|
|
456
|
+
* Returns early if the definition has no properties or the target is falsy.
|
|
457
|
+
*
|
|
458
|
+
* @param schemaDefinition - The schema definition whose properties to iterate
|
|
459
|
+
* @param target - Guard object — iteration is skipped if falsy
|
|
460
|
+
* @yields Property name and its definition for each property in the schema
|
|
461
|
+
*/
|
|
462
|
+
*iterateProperties(schemaDefinition, target) {
|
|
463
|
+
if (!schemaDefinition?.properties || !target) {
|
|
228
464
|
return;
|
|
229
465
|
}
|
|
230
466
|
for (const propertyName in schemaDefinition.properties) {
|
|
231
467
|
const property = schemaDefinition.properties[propertyName];
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
468
|
+
yield { propertyName, property };
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Hides properties whose `@hide` conditions pass.
|
|
473
|
+
* Multiple `@hide` decorators use OR semantics — any passing condition hides the property.
|
|
474
|
+
* Skipped when the `@message` decorator already added messages to the property.
|
|
475
|
+
*
|
|
476
|
+
* @param schemaDefinition - The schema definition to process
|
|
477
|
+
* @param decoratedClass - The decorated class instance carrying `@hide` metadata
|
|
478
|
+
*/
|
|
479
|
+
applyHideDecorator(schemaDefinition, decoratedClass) {
|
|
480
|
+
for (const { propertyName, property } of this.iterateProperties(schemaDefinition, decoratedClass)) {
|
|
481
|
+
const hideConditions = Reflect.getMetadata(decoration_1.metadataKeys.hide, decoratedClass, propertyName);
|
|
482
|
+
if (hideConditions) {
|
|
483
|
+
// Hide when ANY condition IS met (OR semantics across multiple @hide decorators)
|
|
484
|
+
// But only if no messages were added by the message decorator
|
|
485
|
+
const hasMessages = Array.isArray(property[ux_specification_types_1.SchemaTag.messages]) && property[ux_specification_types_1.SchemaTag.messages].length > 0;
|
|
486
|
+
for (const condition of hideConditions) {
|
|
487
|
+
const { passed } = this.evaluateCondition(condition);
|
|
488
|
+
if (passed && !hasMessages) {
|
|
489
|
+
property[ux_specification_types_1.SchemaTag.hidden] = true;
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
248
492
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Shows messages on properties whose `@message` conditions pass.
|
|
498
|
+
* Must run before `applyHideDecorator` so hide can detect existing messages.
|
|
499
|
+
*
|
|
500
|
+
* @param schemaDefinition - The schema definition to process
|
|
501
|
+
* @param decoratedClass - The decorated class instance carrying `@message` metadata
|
|
502
|
+
*/
|
|
503
|
+
applyMessageDecorator(schemaDefinition, decoratedClass) {
|
|
504
|
+
for (const { propertyName, property } of this.iterateProperties(schemaDefinition, decoratedClass)) {
|
|
505
|
+
const messageConditions = Reflect.getMetadata(decoration_1.metadataKeys.message, decoratedClass, propertyName);
|
|
506
|
+
if (messageConditions) {
|
|
507
|
+
for (const condition of messageConditions) {
|
|
508
|
+
const { passed, context } = this.evaluateCondition(condition);
|
|
509
|
+
if (passed && (condition.message || condition.messageConfig)) {
|
|
510
|
+
this.addConditionalMessage(condition, decoratedClass, property, {
|
|
252
511
|
propertyName,
|
|
253
512
|
context
|
|
254
513
|
});
|
|
255
514
|
}
|
|
256
|
-
// Alternative to hide: delete schemaDefinition.properties[propertyName];
|
|
257
|
-
property[ux_specification_types_1.SchemaTag.hidden] = true;
|
|
258
515
|
}
|
|
259
516
|
}
|
|
260
517
|
}
|
|
261
518
|
}
|
|
262
519
|
/**
|
|
263
|
-
*
|
|
520
|
+
* Marks properties as read-only whose `@readonly` conditions pass.
|
|
521
|
+
* Multiple `@readonly` decorators use OR semantics — any passing condition makes the property read-only.
|
|
522
|
+
*
|
|
523
|
+
* @param schemaDefinition - The schema definition to process
|
|
524
|
+
* @param decoratedClass - The decorated class instance carrying `@readonly` metadata
|
|
525
|
+
*/
|
|
526
|
+
applyReadonlyDecorator(schemaDefinition, decoratedClass) {
|
|
527
|
+
for (const { propertyName, property } of this.iterateProperties(schemaDefinition, decoratedClass)) {
|
|
528
|
+
const readonlyConditions = Reflect.getMetadata(decoration_1.metadataKeys.readonly, decoratedClass, propertyName);
|
|
529
|
+
if (readonlyConditions) {
|
|
530
|
+
// Readonly when ANY condition IS met (OR semantics across multiple @readonly decorators)
|
|
531
|
+
for (const condition of readonlyConditions) {
|
|
532
|
+
const { passed } = this.evaluateCondition(condition);
|
|
533
|
+
if (passed) {
|
|
534
|
+
property.readOnly = true;
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Restricts enum values on properties whose `@enums` conditions pass.
|
|
543
|
+
* When multiple `@enums` decorators exist on the same property, the first matching condition wins.
|
|
544
|
+
*
|
|
545
|
+
* @param schemaDefinition - The schema definition to process
|
|
546
|
+
* @param decoratedClass - The decorated class instance carrying `@enums` metadata
|
|
547
|
+
*/
|
|
548
|
+
applyEnumsDecorator(schemaDefinition, decoratedClass) {
|
|
549
|
+
for (const { propertyName, property } of this.iterateProperties(schemaDefinition, decoratedClass)) {
|
|
550
|
+
const enumsConditions = Reflect.getMetadata(decoration_1.metadataKeys.enums, decoratedClass, propertyName);
|
|
551
|
+
if (!enumsConditions?.length) {
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
// Find first matching condition (first match wins)
|
|
555
|
+
for (const condition of enumsConditions) {
|
|
556
|
+
const { passed } = this.evaluateCondition(condition);
|
|
557
|
+
if (passed) {
|
|
558
|
+
const currentEnumValues = this.resolveEnumFromProperty(property);
|
|
559
|
+
if (currentEnumValues) {
|
|
560
|
+
// Filter to only allowed values that exist in original enum
|
|
561
|
+
const filteredValues = condition.allowedValues.filter((v) => currentEnumValues.includes(v));
|
|
562
|
+
this.applyFilteredEnumToProperty(property, filteredValues);
|
|
563
|
+
}
|
|
564
|
+
break; // First match wins, stop processing
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Reads the `@validity` metadata stored on a property of the decorated class.
|
|
264
571
|
*
|
|
265
|
-
* @param target - The
|
|
266
|
-
* @param propertyName - The property
|
|
267
|
-
* @returns The validity
|
|
572
|
+
* @param target - The decorated class instance
|
|
573
|
+
* @param propertyName - The property to read validity metadata from
|
|
574
|
+
* @returns The validity constraints (since, enum restrictions), or undefined if none
|
|
268
575
|
*/
|
|
269
576
|
getValidityMetadata(target, propertyName) {
|
|
270
577
|
let validityInfo;
|
|
@@ -274,66 +581,121 @@ class Decorator extends BaseClass {
|
|
|
274
581
|
return validityInfo;
|
|
275
582
|
}
|
|
276
583
|
/**
|
|
277
|
-
*
|
|
584
|
+
* Returns the enum values from a property definition, resolving `$ref` to a shared enum definition if needed.
|
|
278
585
|
*
|
|
279
|
-
* @param
|
|
280
|
-
* @
|
|
281
|
-
* @param minUI5Version The minimum UI5 version to consider for validity checks
|
|
586
|
+
* @param property - The schema property definition (may have inline `enum` or a `$ref`)
|
|
587
|
+
* @returns The enum values array, or undefined if the property is not an enum
|
|
282
588
|
*/
|
|
283
|
-
|
|
284
|
-
|
|
589
|
+
resolveEnumFromProperty(property) {
|
|
590
|
+
// Check for inline enum
|
|
591
|
+
if (property?.enum && Array.isArray(property.enum)) {
|
|
592
|
+
return property.enum;
|
|
593
|
+
}
|
|
594
|
+
// Check for $ref to an enum definition
|
|
595
|
+
if (property?.$ref) {
|
|
596
|
+
const refName = property.$ref.replace('#/definitions/', '');
|
|
597
|
+
const schema = this.appSchema?.get();
|
|
598
|
+
const refDef = schema?.definitions?.[refName];
|
|
599
|
+
if (refDef?.enum && Array.isArray(refDef.enum)) {
|
|
600
|
+
return refDef.enum;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return undefined;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Writes filtered enum values to a property definition.
|
|
607
|
+
* For `$ref` properties, inlines the enum, copies the type, and removes the `$ref`.
|
|
608
|
+
*
|
|
609
|
+
* @param property - The schema property definition to update
|
|
610
|
+
* @param filteredEnum - The allowed enum values after filtering
|
|
611
|
+
*/
|
|
612
|
+
applyFilteredEnumToProperty(property, filteredEnum) {
|
|
613
|
+
if (property.$ref) {
|
|
614
|
+
// For $ref properties, resolve the referenced definition to get the type
|
|
615
|
+
const refName = property.$ref.replace('#/definitions/', '');
|
|
616
|
+
const schema = this.appSchema?.get();
|
|
617
|
+
const refDef = schema?.definitions?.[refName];
|
|
618
|
+
// Copy the type from the referenced definition if it exists
|
|
619
|
+
if (refDef?.type) {
|
|
620
|
+
property.type = refDef.type;
|
|
621
|
+
}
|
|
622
|
+
// Remove the $ref and inline the filtered enum
|
|
623
|
+
delete property.$ref;
|
|
624
|
+
property.enum = filteredEnum;
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
// For inline enum properties, update directly
|
|
628
|
+
property.enum = filteredEnum;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Hides properties and filters enum values that require a UI5 version higher than the app's minimum.
|
|
633
|
+
*
|
|
634
|
+
* @param schemaDefinition - The schema definition to process
|
|
635
|
+
* @param decoratedClass - The decorated class instance carrying `@validity` metadata
|
|
636
|
+
* @param minUI5Version - The app's minimum UI5 version to check against
|
|
637
|
+
*/
|
|
638
|
+
applyValidityDecorator(schemaDefinition, decoratedClass, minUI5Version) {
|
|
639
|
+
if (!schemaDefinition?.properties || !decoratedClass || !minUI5Version) {
|
|
285
640
|
return;
|
|
286
641
|
}
|
|
287
642
|
for (const propertyName in schemaDefinition.properties) {
|
|
288
643
|
const property = schemaDefinition.properties[propertyName];
|
|
289
|
-
const validityInfo = this.getValidityMetadata(
|
|
644
|
+
const validityInfo = this.getValidityMetadata(decoratedClass, propertyName);
|
|
290
645
|
// Check if property has a 'since' requirement that exceeds the app's minUI5Version
|
|
291
646
|
if (validityInfo?.since && !(0, utils_1.compareUI5Versions)(minUI5Version, validityInfo.since)) {
|
|
292
647
|
property[ux_specification_types_1.SchemaTag.hidden] = true;
|
|
293
648
|
// possible message?
|
|
294
649
|
}
|
|
295
|
-
// Process
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
650
|
+
// Process enum validity configuration from @validity decorator
|
|
651
|
+
// Supports both inline enums and $ref to enum definitions
|
|
652
|
+
if (validityInfo?.enum) {
|
|
653
|
+
const enumValues = this.resolveEnumFromProperty(property);
|
|
654
|
+
if (enumValues) {
|
|
655
|
+
const filteredEnum = enumValues.filter((enumValue) => {
|
|
656
|
+
const enumValueStr = String(enumValue);
|
|
657
|
+
const condition = validityInfo.enum[enumValueStr];
|
|
658
|
+
if (!condition) {
|
|
659
|
+
return true; // Keep values without conditions
|
|
660
|
+
}
|
|
661
|
+
// Check UI5 version requirement (if specified)
|
|
662
|
+
if (condition.since && minUI5Version) {
|
|
663
|
+
if (!(0, utils_1.compareUI5Versions)(minUI5Version, condition.since)) {
|
|
664
|
+
if (condition.message) {
|
|
665
|
+
this.addConditionalMessage(condition, decoratedClass, property, {
|
|
666
|
+
propertyName: enumValueStr
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
return false; // Version requirement not met
|
|
310
670
|
}
|
|
311
|
-
return false; // Version requirement not met
|
|
312
671
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
672
|
+
// Check property dependency using dependsOn function
|
|
673
|
+
if (condition.dependsOn) {
|
|
674
|
+
if (!condition.dependsOn(decoratedClass)) {
|
|
675
|
+
if (condition.message) {
|
|
676
|
+
this.addConditionalMessage(condition, decoratedClass, property, {
|
|
677
|
+
propertyName: enumValueStr
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
return false; // Dependency condition not met
|
|
321
681
|
}
|
|
322
|
-
return false; // Dependency condition not met
|
|
323
682
|
}
|
|
683
|
+
return true;
|
|
684
|
+
});
|
|
685
|
+
// Only update if enum was actually filtered
|
|
686
|
+
if (filteredEnum.length !== enumValues.length) {
|
|
687
|
+
this.applyFilteredEnumToProperty(property, filteredEnum);
|
|
324
688
|
}
|
|
325
|
-
|
|
326
|
-
});
|
|
327
|
-
property.enum = filteredEnum;
|
|
689
|
+
}
|
|
328
690
|
}
|
|
329
691
|
}
|
|
330
692
|
}
|
|
331
693
|
/**
|
|
332
|
-
*
|
|
694
|
+
* Marks the schema definition as a view node if the `@isViewNode` decorator is present on the target.
|
|
333
695
|
*
|
|
334
|
-
* @param schemaDefinition The schema definition to
|
|
335
|
-
* @param target The
|
|
336
|
-
* @param propertyName
|
|
696
|
+
* @param schemaDefinition - The schema definition to tag
|
|
697
|
+
* @param target - The class constructor or prototype carrying the decorator
|
|
698
|
+
* @param propertyName - Optional property name for property-level decorators
|
|
337
699
|
*/
|
|
338
700
|
applyIsViewNodeDecorator(schemaDefinition, target, propertyName) {
|
|
339
701
|
const isViewNode = Reflect.getMetadata(decoration_1.metadataKeys.isViewNode, target, propertyName);
|
|
@@ -343,11 +705,11 @@ class Decorator extends BaseClass {
|
|
|
343
705
|
}
|
|
344
706
|
}
|
|
345
707
|
/**
|
|
346
|
-
*
|
|
708
|
+
* Sets the schema `description` field from the `@description` decorator if present on the target.
|
|
347
709
|
*
|
|
348
|
-
* @param schemaDefinition - The schema definition to
|
|
349
|
-
* @param target - The
|
|
350
|
-
* @param propertyName -
|
|
710
|
+
* @param schemaDefinition - The schema definition to update
|
|
711
|
+
* @param target - The class constructor or prototype carrying the decorator
|
|
712
|
+
* @param propertyName - Optional property name for property-level decorators
|
|
351
713
|
*/
|
|
352
714
|
applyDescriptionDecorator(schemaDefinition, target, propertyName) {
|
|
353
715
|
const description = Reflect.getMetadata(decoration_1.metadataKeys.description, target, propertyName);
|
|
@@ -356,39 +718,17 @@ class Decorator extends BaseClass {
|
|
|
356
718
|
}
|
|
357
719
|
}
|
|
358
720
|
/**
|
|
359
|
-
* Applies
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
* @param target - The target object or function
|
|
363
|
-
* @param propertyName - The property name (optional)
|
|
364
|
-
*/
|
|
365
|
-
applyHiddenDecorator(schemaDefinition, target, propertyName) {
|
|
366
|
-
const hiddenCondition = Reflect.getMetadata(decoration_1.metadataKeys.hidden, target, propertyName);
|
|
367
|
-
if (typeof hiddenCondition === 'function') {
|
|
368
|
-
const shouldHide = hiddenCondition(this);
|
|
369
|
-
if (shouldHide) {
|
|
370
|
-
schemaDefinition[ux_specification_types_1.SchemaTag.hidden] = true;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
else if (hiddenCondition === true) {
|
|
374
|
-
schemaDefinition[ux_specification_types_1.SchemaTag.hidden] = true;
|
|
375
|
-
}
|
|
376
|
-
if (!schemaDefinition?.properties) {
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
for (const propertyName in schemaDefinition.properties) {
|
|
380
|
-
this.applyHiddenDecorator(schemaDefinition.properties[propertyName], target, propertyName);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Applies all decorators to the schema definition.
|
|
721
|
+
* Applies all decorators to the schema in the correct order:
|
|
722
|
+
* description → isViewNode → validity → enums → message → hide → readonly.
|
|
723
|
+
* Message runs before hide so that hide can skip properties that already have messages.
|
|
385
724
|
*
|
|
386
|
-
* @param minUi5Version - The minimum UI5 version
|
|
387
|
-
* @param propertyName -
|
|
388
|
-
* @
|
|
725
|
+
* @param minUi5Version - The app's minimum UI5 version for validity checks
|
|
726
|
+
* @param propertyName - Optional property name when decorating a single property
|
|
727
|
+
* @param customDefinition - Override the schema definition (defaults to `getBase()`)
|
|
728
|
+
* @returns The decorated schema definition
|
|
389
729
|
*/
|
|
390
|
-
applyDecorators(minUi5Version, propertyName) {
|
|
391
|
-
const definition = this.
|
|
730
|
+
applyDecorators(minUi5Version, propertyName, customDefinition) {
|
|
731
|
+
const definition = customDefinition ?? this.getBase();
|
|
392
732
|
if (!definition) {
|
|
393
733
|
return;
|
|
394
734
|
}
|
|
@@ -399,10 +739,16 @@ class Decorator extends BaseClass {
|
|
|
399
739
|
this.applyIsViewNodeDecorator(definition, target, propertyName);
|
|
400
740
|
// Apply validity decorator (for properties)
|
|
401
741
|
this.applyValidityDecorator(definition, this, minUi5Version);
|
|
402
|
-
// Apply
|
|
403
|
-
this.
|
|
404
|
-
// Apply
|
|
405
|
-
|
|
742
|
+
// Apply enums decorator - filter enum values based on conditions
|
|
743
|
+
this.applyEnumsDecorator(definition, this);
|
|
744
|
+
// Apply message decorator - show messages based on conditions
|
|
745
|
+
// NOTE: Message decorator must run before hide decorator so hide can check for messages
|
|
746
|
+
this.applyMessageDecorator(definition, this);
|
|
747
|
+
// Apply hide decorator - hide properties based on conditions
|
|
748
|
+
// NOTE: Only hides if message decorator did not add any messages
|
|
749
|
+
this.applyHideDecorator(definition, this);
|
|
750
|
+
// Apply readonly decorator - mark properties as readonly based on conditions
|
|
751
|
+
this.applyReadonlyDecorator(definition, this);
|
|
406
752
|
return { definition };
|
|
407
753
|
}
|
|
408
754
|
}
|