@sap/ux-specification 1.136.16 → 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.
Files changed (67) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/documentation/v2/v2-AnalyticalListPage.html +2 -2
  3. package/dist/documentation/v2/v2-ApplicationV2.html +2 -2
  4. package/dist/documentation/v2/v2-ListReport.html +2 -2
  5. package/dist/documentation/v2/v2-ListReportNew.html +2 -2
  6. package/dist/documentation/v2/v2-ObjectPage.html +2 -2
  7. package/dist/documentation/v2/v2-OverviewPage.html +2 -2
  8. package/dist/documentation/v4/v4-ApplicationV4.html +2 -2
  9. package/dist/documentation/v4/v4-BuildingBlocks.html +2 -2
  10. package/dist/documentation/v4/v4-FreestylePage.html +2 -2
  11. package/dist/documentation/v4/v4-ListReport.html +2 -2
  12. package/dist/documentation/v4/v4-ObjectPage.html +2 -2
  13. package/dist/index-min.js +273 -271
  14. package/dist/index-min.js.map +4 -4
  15. package/dist/schemas/v4/BuildingBlocksConfig.json +52 -4
  16. package/dist/specification/package.json +6 -6
  17. package/dist/specification/scripts/macros/corrections.d.ts.map +1 -1
  18. package/dist/specification/scripts/macros/corrections.js +33 -1
  19. package/dist/specification/scripts/macros/corrections.js.map +1 -1
  20. package/dist/specification/scripts/macros/schema.d.ts.map +1 -1
  21. package/dist/specification/scripts/macros/schema.js +13 -0
  22. package/dist/specification/scripts/macros/schema.js.map +1 -1
  23. package/dist/specification/src/i18n/i18n.d.ts.map +1 -1
  24. package/dist/specification/src/i18n/i18n.js +2 -1
  25. package/dist/specification/src/i18n/i18n.js.map +1 -1
  26. package/dist/specification/src/sync/common/ManifestDrivenSchemaProcessor.d.ts +8 -1
  27. package/dist/specification/src/sync/common/ManifestDrivenSchemaProcessor.d.ts.map +1 -1
  28. package/dist/specification/src/sync/common/ManifestDrivenSchemaProcessor.js +10 -6
  29. package/dist/specification/src/sync/common/ManifestDrivenSchemaProcessor.js.map +1 -1
  30. package/dist/specification/src/sync/common/decoration/decorators.d.ts +6 -40
  31. package/dist/specification/src/sync/common/decoration/decorators.d.ts.map +1 -1
  32. package/dist/specification/src/sync/common/decoration/decorators.js +26 -91
  33. package/dist/specification/src/sync/common/decoration/decorators.js.map +1 -1
  34. package/dist/specification/src/sync/common/rules.d.ts +20 -0
  35. package/dist/specification/src/sync/common/rules.d.ts.map +1 -1
  36. package/dist/specification/src/sync/common/rules.js +22 -2
  37. package/dist/specification/src/sync/common/rules.js.map +1 -1
  38. package/dist/specification/src/sync/v2/generate/analyticalListReport.js +7 -7
  39. package/dist/specification/src/sync/v2/generate/analyticalListReport.js.map +1 -1
  40. package/dist/specification/src/sync/v2/generate/objectPage.d.ts.map +1 -1
  41. package/dist/specification/src/sync/v2/generate/objectPage.js +56 -2
  42. package/dist/specification/src/sync/v2/generate/objectPage.js.map +1 -1
  43. package/dist/specification/src/sync/v4/application.d.ts +11 -0
  44. package/dist/specification/src/sync/v4/application.d.ts.map +1 -1
  45. package/dist/specification/src/sync/v4/application.js +18 -3
  46. package/dist/specification/src/sync/v4/application.js.map +1 -1
  47. package/dist/specification/src/sync/v4/export/controls/Table.d.ts +8 -2
  48. package/dist/specification/src/sync/v4/export/controls/Table.d.ts.map +1 -1
  49. package/dist/specification/src/sync/v4/export/controls/Table.js +44 -12
  50. package/dist/specification/src/sync/v4/export/controls/Table.js.map +1 -1
  51. package/dist/specification/src/sync/v4/export/controls/ToolBarAction.d.ts.map +1 -1
  52. package/dist/specification/src/sync/v4/export/controls/ToolBarAction.js +2 -2
  53. package/dist/specification/src/sync/v4/export/controls/ToolBarAction.js.map +1 -1
  54. package/dist/specification/src/sync/v4/generate/fpm-custom-page/annotations.d.ts.map +1 -1
  55. package/dist/specification/src/sync/v4/generate/fpm-custom-page/annotations.js +19 -11
  56. package/dist/specification/src/sync/v4/generate/fpm-custom-page/annotations.js.map +1 -1
  57. package/dist/specification/src/sync/v4/generate/list-report/listReport.d.ts +6 -2
  58. package/dist/specification/src/sync/v4/generate/list-report/listReport.d.ts.map +1 -1
  59. package/dist/specification/src/sync/v4/generate/list-report/listReport.js +79 -95
  60. package/dist/specification/src/sync/v4/generate/list-report/listReport.js.map +1 -1
  61. package/dist/specification/src/sync/v4/generate/objectPage.js +26 -23
  62. package/dist/specification/src/sync/v4/generate/objectPage.js.map +1 -1
  63. package/dist/specification/src/sync/v4/sync-rules/DecoratorClass.d.ts +119 -127
  64. package/dist/specification/src/sync/v4/sync-rules/DecoratorClass.d.ts.map +1 -1
  65. package/dist/specification/src/sync/v4/sync-rules/DecoratorClass.js +168 -168
  66. package/dist/specification/src/sync/v4/sync-rules/DecoratorClass.js.map +1 -1
  67. package/package.json +7 -7
@@ -10,13 +10,13 @@ const i18next_1 = __importDefault(require("i18next"));
10
10
  const jsonpath_plus_1 = require("jsonpath-plus");
11
11
  const utils_1 = require("./utils");
12
12
  /**
13
- * Adds a message to a schema element.
14
- * 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.
15
15
  *
16
- * @param element - The schema element to add the message to
17
- * @param message - The message parameters
18
- * @param message.text - The message text
19
- * @param message.deletable - Whether the message is deletable (default: false)
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)
20
20
  */
21
21
  function addMessageToSchema(element, { text, deletable = false }) {
22
22
  if (!element[ux_specification_types_1.SchemaTag.messages]) {
@@ -26,9 +26,9 @@ function addMessageToSchema(element, { text, deletable = false }) {
26
26
  }
27
27
  class BaseConstruct {
28
28
  /**
29
- * Constructor for BaseConstruct.
29
+ * Creates the base construct with access to the app schema, app/page configuration, and logger.
30
30
  *
31
- * @param settings - General settings including appSchema, app, page, and logger
31
+ * @param settings - Shared context (appSchema, app, page, logger) passed to all decorator classes
32
32
  */
33
33
  constructor(settings) {
34
34
  const { app, appSchema, page, logger } = settings || {};
@@ -59,9 +59,9 @@ class BaseConstruct {
59
59
  });
60
60
  }
61
61
  /**
62
- * Gets the general settings.
62
+ * Returns the shared context (appSchema, app, page, logger) for use by subclasses or callers.
63
63
  *
64
- * @returns The general settings object
64
+ * @returns The current settings object
65
65
  */
66
66
  getSettings() {
67
67
  return {
@@ -75,9 +75,9 @@ class BaseConstruct {
75
75
  exports.BaseConstruct = BaseConstruct;
76
76
  class BaseClass extends BaseConstruct {
77
77
  /**
78
- * Creates an instance of BaseClass.
78
+ * Looks up the matching schema definition by class name and stores it as the base.
79
79
  *
80
- * @param settings - General settings including appSchema, app, page, and logger
80
+ * @param settings - Shared context (appSchema, app, page, logger) passed to all decorator classes
81
81
  */
82
82
  constructor(settings) {
83
83
  super(settings);
@@ -91,36 +91,36 @@ class BaseClass extends BaseConstruct {
91
91
  });
92
92
  }
93
93
  /**
94
- * Gets the class name.
94
+ * Returns the class name used to look up the matching schema definition.
95
95
  *
96
- * @returns The name of the class
96
+ * @returns The constructor name of this class
97
97
  */
98
98
  getClassName() {
99
99
  return this.constructor.name;
100
100
  }
101
101
  /**
102
- * Gets the base name.
102
+ * Returns the name stored at construction time for the schema definition lookup.
103
103
  *
104
- * @returns The base name
104
+ * @returns The base definition name
105
105
  */
106
106
  getBaseName() {
107
107
  return this.base.name;
108
108
  }
109
109
  /**
110
- * Gets the base definition.
110
+ * Returns the schema definition that decorators are applied to.
111
111
  *
112
- * @returns The base definition
112
+ * @returns The JSON schema definition for this class
113
113
  */
114
114
  getBase() {
115
115
  return this.base.definition;
116
116
  }
117
117
  /**
118
- * Creates an annotation path for schema based on entity type, term, and qualifier.
118
+ * Builds an annotation path like `/<EntityType>/@<Term>#<Qualifier>` and stores it on the schema definition.
119
119
  *
120
- * @param entityTypeName - Entity type name.
121
- * @param term - Annotation term.
122
- * @param qualifier - Annotation qualifier (optional).
123
- * @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
124
124
  */
125
125
  createAnnotationPath(entityTypeName, term, qualifier) {
126
126
  if (!entityTypeName) {
@@ -137,9 +137,9 @@ class BaseClass extends BaseConstruct {
137
137
  exports.BaseClass = BaseClass;
138
138
  class Decorator extends BaseClass {
139
139
  /**
140
- * Creates an instance of Decorator.
140
+ * Sets up the decorator context as non-enumerable so it stays hidden from serialization.
141
141
  *
142
- * @param settings - General settings including appSchema, app, page, and logger
142
+ * @param settings - Shared context (appSchema, app, page, logger) passed to all decorator classes
143
143
  */
144
144
  constructor(settings) {
145
145
  super(settings);
@@ -152,17 +152,11 @@ class Decorator extends BaseClass {
152
152
  });
153
153
  }
154
154
  /**
155
- * Initializes the decorator by applying all decorators to the schema definition.
155
+ * Builds the decorator context from app, page, and custom values, then applies all
156
+ * decorators (enums, message, hide, readonly) to the schema definition.
156
157
  *
157
- * The decorator context is structured as:
158
- * - `app`: The App configuration (from `this.app.config`, includes manifest)
159
- * - `page`: The Page configuration (from `this.page.config`)
160
- * - `custom`: Custom context provided by the caller.
161
- *
162
- * @param customContext - Optional custom context for decorator conditions.
163
- * Use this for runtime-specific conditions like table state, section state, etc.
164
- * @param definition - Optional custom definition to apply decorators to.
165
- * If provided, decorators are applied to this definition instead of the one from appSchema.
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())
166
160
  * @example
167
161
  * ```typescript
168
162
  * // Basic initialization (app and page auto-injected)
@@ -188,12 +182,12 @@ class Decorator extends BaseClass {
188
182
  this.applyDecorators(undefined, undefined, definition);
189
183
  }
190
184
  /**
191
- * Gets property value from the decorator context using a property path.
192
- *
193
- * The path must include an explicit source prefix ('app', 'page', or 'custom').
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`).
194
188
  *
195
- * @param propertyPath - The property path with explicit source prefix - supports full jsonpath syntax
196
- * @returns Object containing the final key and its value, or undefined if not found
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
197
191
  * @example
198
192
  * ```typescript
199
193
  * // With decoratorContext = {
@@ -239,14 +233,11 @@ class Decorator extends BaseClass {
239
233
  }
240
234
  }
241
235
  /**
242
- * Evaluates a single dependency condition.
243
- *
244
- * @param condition - The single condition to evaluate
245
- * @param condition.path - The property path to check
246
- * @param condition.dependsOn - Optional custom condition function
247
- * @param condition.expectedValue - Optional expected value for equality check
248
- * @param condition.negate - Optional flag to invert the condition result
249
- * @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
250
241
  */
251
242
  evaluateSingleCondition(condition) {
252
243
  // Handle special __always__ path (from @hide(true))
@@ -276,16 +267,17 @@ class Decorator extends BaseClass {
276
267
  return { passed, value, key };
277
268
  }
278
269
  /**
279
- * Helper method to add a message to the schema property based on value condition.
280
- *
281
- * @param condition - DecoratorMetadata or EnumValueCondition object containing condition details
282
- * @param syncRuleProviderInstance - The instance of the sync rule provider
283
- * @param definition - The schema property definition
284
- * @param i18nProperties - i18n properties for message translation
285
- * @param i18nProperties.propertyName - The property name for the message
286
- * @param i18nProperties.context - The context for the message
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
287
279
  */
288
- addConditionalMessage(condition, syncRuleProviderInstance, definition, i18nProperties) {
280
+ addConditionalMessage(condition, decoratedClass, definition, i18nProperties) {
289
281
  // Handle new MessageConfig format (from msg() helper)
290
282
  const metadata = condition;
291
283
  if (metadata.messageConfig && (0, decoration_1.isMessageConfig)(metadata.messageConfig)) {
@@ -301,7 +293,7 @@ class Decorator extends BaseClass {
301
293
  }
302
294
  let messageText;
303
295
  if (typeof condition.message.text === 'function') {
304
- messageText = condition.message.text(syncRuleProviderInstance);
296
+ messageText = condition.message.text(decoratedClass);
305
297
  }
306
298
  else if (typeof condition.message.text === 'string') {
307
299
  messageText = condition.message.text;
@@ -316,10 +308,10 @@ class Decorator extends BaseClass {
316
308
  addMessageToSchema(definition, { text: messageText, deletable: condition.message.deletable });
317
309
  }
318
310
  /**
319
- * Resolves PathNode values in message params to their actual values from the decorator context.
311
+ * Resolves any `PathNode` values in message params to their actual values from the decorator context.
320
312
  *
321
- * @param params - The message params potentially containing PathNode values
322
- * @returns The params with PathNode values resolved to actual values
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
323
315
  */
324
316
  resolveMessageParams(params) {
325
317
  if (!params) {
@@ -339,10 +331,11 @@ class Decorator extends BaseClass {
339
331
  return resolved;
340
332
  }
341
333
  /**
342
- * Gets the context message from evaluation results.
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.
343
336
  *
344
- * @param results - The evaluation results
345
- * @returns The context message string
337
+ * @param results - The condition evaluation results to summarize
338
+ * @returns A comma-separated string of `key: value` pairs for failed conditions
346
339
  */
347
340
  getContextForMessage(results) {
348
341
  return results
@@ -351,10 +344,10 @@ class Decorator extends BaseClass {
351
344
  .join(', ');
352
345
  }
353
346
  /**
354
- * Evaluates an AND condition item which can be either a single condition or a nested OR group.
347
+ * Evaluates one item inside an AND group either a single condition or a nested OR group.
355
348
  *
356
- * @param conditionItem - The condition item to evaluate
357
- * @returns Object containing whether condition passed and evaluation details
349
+ * @param conditionItem - A single condition or a nested `{ __orConditions }` group
350
+ * @returns Whether the item passed and the detailed evaluation results
358
351
  */
359
352
  evaluateAndConditionItem(conditionItem) {
360
353
  // Check if this is a nested OR group
@@ -367,11 +360,11 @@ class Decorator extends BaseClass {
367
360
  return { passed: result.passed, results: [result] };
368
361
  }
369
362
  /**
370
- * Evaluates OR conditions (at least one condition must match).
371
- * Supports both single conditions and nested AND groups.
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.
372
365
  *
373
- * @param orConditions - Array of condition items (single conditions or AND groups)
374
- * @returns Object containing whether any condition passed and evaluation details
366
+ * @param orConditions - Array of conditions or nested AND groups to evaluate
367
+ * @returns Whether any condition passed and the collected evaluation results
375
368
  */
376
369
  evaluateOrConditions(orConditions) {
377
370
  const allResults = [];
@@ -408,11 +401,11 @@ class Decorator extends BaseClass {
408
401
  return { passed: false, results: allResults };
409
402
  }
410
403
  /**
411
- * Evaluates AND conditions (all conditions must match).
412
- * Supports both single conditions and nested OR groups.
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.
413
406
  *
414
- * @param andConditions - Array of condition items (single conditions or OR groups)
415
- * @returns Object containing whether all conditions passed and evaluation details
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
416
409
  */
417
410
  evaluateAndConditions(andConditions) {
418
411
  const allResults = [];
@@ -428,10 +421,11 @@ class Decorator extends BaseClass {
428
421
  return { passed: allPassed, results: allResults };
429
422
  }
430
423
  /**
431
- * Evaluates condition metadata and returns whether the condition is met and the context.
424
+ * Entry point for condition evaluation. Dispatches to OR, AND, or single evaluation
425
+ * depending on the shape of the condition metadata.
432
426
  *
433
- * @param conditionInfo - The condition metadata
434
- * @returns Object with passed (boolean) and context (string)
427
+ * @param conditionInfo - The decorator condition metadata (single, AND, or OR)
428
+ * @returns Whether the condition passed and a diagnostic context string
435
429
  */
436
430
  evaluateCondition(conditionInfo) {
437
431
  let passed = false;
@@ -458,12 +452,12 @@ class Decorator extends BaseClass {
458
452
  return { passed, context };
459
453
  }
460
454
  /**
461
- * Iterates over schema properties and yields property info for decorator processing.
462
- * Centralizes the guard clause and property iteration logic.
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.
463
457
  *
464
- * @param schemaDefinition - The schema definition to process
465
- * @param target - The target object (used for guard clause validation)
466
- * @yields Property name and definition for each property in the schema
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
467
461
  */
468
462
  *iterateProperties(schemaDefinition, target) {
469
463
  if (!schemaDefinition?.properties || !target) {
@@ -475,42 +469,45 @@ class Decorator extends BaseClass {
475
469
  }
476
470
  }
477
471
  /**
478
- * Applies the hide decorator to the schema definition.
479
- * Hides properties when their condition evaluates to true, but only if
480
- * the message decorator did not add any messages to the property.
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.
481
475
  *
482
- * @param schemaDefinition - The schema definition to apply the decorator to
483
- * @param syncRuleProviderInstance - The sync rule provider instance
476
+ * @param schemaDefinition - The schema definition to process
477
+ * @param decoratedClass - The decorated class instance carrying `@hide` metadata
484
478
  */
485
- applyHideDecorator(schemaDefinition, syncRuleProviderInstance) {
486
- for (const { propertyName, property } of this.iterateProperties(schemaDefinition, syncRuleProviderInstance)) {
487
- const hideInfo = (0, decoration_1.getHideMetadata)(syncRuleProviderInstance, propertyName);
488
- if (hideInfo) {
489
- const { passed } = this.evaluateCondition(hideInfo);
490
- // Hide when condition IS met (passed=true means hide)
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)
491
484
  // But only if no messages were added by the message decorator
492
485
  const hasMessages = Array.isArray(property[ux_specification_types_1.SchemaTag.messages]) && property[ux_specification_types_1.SchemaTag.messages].length > 0;
493
- if (passed && !hasMessages) {
494
- property[ux_specification_types_1.SchemaTag.hidden] = true;
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
+ }
495
492
  }
496
493
  }
497
494
  }
498
495
  }
499
496
  /**
500
- * Applies the message decorator to the schema definition.
501
- * Shows messages when their condition evaluates to true.
497
+ * Shows messages on properties whose `@message` conditions pass.
498
+ * Must run before `applyHideDecorator` so hide can detect existing messages.
502
499
  *
503
- * @param schemaDefinition - The schema definition to apply the decorator to
504
- * @param syncRuleProviderInstance - The sync rule provider instance
500
+ * @param schemaDefinition - The schema definition to process
501
+ * @param decoratedClass - The decorated class instance carrying `@message` metadata
505
502
  */
506
- applyMessageDecorator(schemaDefinition, syncRuleProviderInstance) {
507
- for (const { propertyName, property } of this.iterateProperties(schemaDefinition, syncRuleProviderInstance)) {
508
- const messageInfoList = (0, decoration_1.getMessageMetadata)(syncRuleProviderInstance, propertyName);
509
- if (messageInfoList) {
510
- for (const messageInfo of messageInfoList) {
511
- const { passed, context } = this.evaluateCondition(messageInfo);
512
- if (passed && (messageInfo.message || messageInfo.messageConfig)) {
513
- this.addConditionalMessage(messageInfo, syncRuleProviderInstance, property, {
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, {
514
511
  propertyName,
515
512
  context
516
513
  });
@@ -520,45 +517,48 @@ class Decorator extends BaseClass {
520
517
  }
521
518
  }
522
519
  /**
523
- * Applies the readonly decorator to the schema definition.
524
- * Marks properties as readonly when their condition evaluates to true.
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.
525
522
  *
526
- * @param schemaDefinition - The schema definition to apply the decorator to
527
- * @param syncRuleProviderInstance - The sync rule provider instance
523
+ * @param schemaDefinition - The schema definition to process
524
+ * @param decoratedClass - The decorated class instance carrying `@readonly` metadata
528
525
  */
529
- applyReadonlyDecorator(schemaDefinition, syncRuleProviderInstance) {
530
- for (const { propertyName, property } of this.iterateProperties(schemaDefinition, syncRuleProviderInstance)) {
531
- const readonlyInfo = (0, decoration_1.getReadonlyMetadata)(syncRuleProviderInstance, propertyName);
532
- if (readonlyInfo) {
533
- const { passed } = this.evaluateCondition(readonlyInfo);
534
- if (passed) {
535
- property.readOnly = true;
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
+ }
536
537
  }
537
538
  }
538
539
  }
539
540
  }
540
541
  /**
541
- * Applies the enums decorator to the schema definition.
542
- * Restricts enum values when their condition evaluates to true.
543
- * If multiple @enums decorators exist on the same property, the first matching condition wins.
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
544
  *
545
- * @param schemaDefinition - The schema definition to apply the decorator to
546
- * @param syncRuleProviderInstance - The sync rule provider instance
545
+ * @param schemaDefinition - The schema definition to process
546
+ * @param decoratedClass - The decorated class instance carrying `@enums` metadata
547
547
  */
548
- applyEnumsDecorator(schemaDefinition, syncRuleProviderInstance) {
549
- for (const { propertyName, property } of this.iterateProperties(schemaDefinition, syncRuleProviderInstance)) {
550
- const enumsMetadataList = (0, decoration_1.getEnumsMetadata)(syncRuleProviderInstance, propertyName);
551
- if (!enumsMetadataList?.length) {
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
552
  continue;
553
553
  }
554
554
  // Find first matching condition (first match wins)
555
- for (const enumsMetadata of enumsMetadataList) {
556
- const { passed } = this.evaluateCondition(enumsMetadata);
555
+ for (const condition of enumsConditions) {
556
+ const { passed } = this.evaluateCondition(condition);
557
557
  if (passed) {
558
558
  const currentEnumValues = this.resolveEnumFromProperty(property);
559
559
  if (currentEnumValues) {
560
560
  // Filter to only allowed values that exist in original enum
561
- const filteredValues = enumsMetadata.allowedValues.filter((v) => currentEnumValues.includes(v));
561
+ const filteredValues = condition.allowedValues.filter((v) => currentEnumValues.includes(v));
562
562
  this.applyFilteredEnumToProperty(property, filteredValues);
563
563
  }
564
564
  break; // First match wins, stop processing
@@ -567,11 +567,11 @@ class Decorator extends BaseClass {
567
567
  }
568
568
  }
569
569
  /**
570
- * Gets the validity metadata for a property.
570
+ * Reads the `@validity` metadata stored on a property of the decorated class.
571
571
  *
572
- * @param target - The target object
573
- * @param propertyName - The property name
574
- * @returns The validity metadata or undefined
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
575
575
  */
576
576
  getValidityMetadata(target, propertyName) {
577
577
  let validityInfo;
@@ -581,11 +581,10 @@ class Decorator extends BaseClass {
581
581
  return validityInfo;
582
582
  }
583
583
  /**
584
- * Resolves an enum array from a property definition.
585
- * Handles both inline enums and $ref to enum definitions.
584
+ * Returns the enum values from a property definition, resolving `$ref` to a shared enum definition if needed.
586
585
  *
587
- * @param property - The property definition
588
- * @returns The enum array or undefined if not found
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
589
588
  */
590
589
  resolveEnumFromProperty(property) {
591
590
  // Check for inline enum
@@ -604,12 +603,11 @@ class Decorator extends BaseClass {
604
603
  return undefined;
605
604
  }
606
605
  /**
607
- * Applies filtered enum values to a property.
608
- * For $ref properties, inlines the filtered enum, copies the type from the referenced definition, and removes the $ref.
609
- * For inline enum properties, updates the enum directly.
606
+ * Writes filtered enum values to a property definition.
607
+ * For `$ref` properties, inlines the enum, copies the type, and removes the `$ref`.
610
608
  *
611
- * @param property - The property definition to update
612
- * @param filteredEnum - The filtered enum values
609
+ * @param property - The schema property definition to update
610
+ * @param filteredEnum - The allowed enum values after filtering
613
611
  */
614
612
  applyFilteredEnumToProperty(property, filteredEnum) {
615
613
  if (property.$ref) {
@@ -631,19 +629,19 @@ class Decorator extends BaseClass {
631
629
  }
632
630
  }
633
631
  /**
634
- * Applies the validity decorator to the schema definition based on the sync rule provider instance and minimum UI5 version.
632
+ * Hides properties and filters enum values that require a UI5 version higher than the app's minimum.
635
633
  *
636
- * @param schemaDefinition The schema definition to apply the validity decorator to
637
- * @param syncRuleProviderInstance The instance of the sync rule provider
638
- * @param minUI5Version The minimum UI5 version to consider for validity checks
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
639
637
  */
640
- applyValidityDecorator(schemaDefinition, syncRuleProviderInstance, minUI5Version) {
641
- if (!schemaDefinition?.properties || !syncRuleProviderInstance || !minUI5Version) {
638
+ applyValidityDecorator(schemaDefinition, decoratedClass, minUI5Version) {
639
+ if (!schemaDefinition?.properties || !decoratedClass || !minUI5Version) {
642
640
  return;
643
641
  }
644
642
  for (const propertyName in schemaDefinition.properties) {
645
643
  const property = schemaDefinition.properties[propertyName];
646
- const validityInfo = this.getValidityMetadata(syncRuleProviderInstance, propertyName);
644
+ const validityInfo = this.getValidityMetadata(decoratedClass, propertyName);
647
645
  // Check if property has a 'since' requirement that exceeds the app's minUI5Version
648
646
  if (validityInfo?.since && !(0, utils_1.compareUI5Versions)(minUI5Version, validityInfo.since)) {
649
647
  property[ux_specification_types_1.SchemaTag.hidden] = true;
@@ -664,7 +662,7 @@ class Decorator extends BaseClass {
664
662
  if (condition.since && minUI5Version) {
665
663
  if (!(0, utils_1.compareUI5Versions)(minUI5Version, condition.since)) {
666
664
  if (condition.message) {
667
- this.addConditionalMessage(condition, syncRuleProviderInstance, property, {
665
+ this.addConditionalMessage(condition, decoratedClass, property, {
668
666
  propertyName: enumValueStr
669
667
  });
670
668
  }
@@ -673,9 +671,9 @@ class Decorator extends BaseClass {
673
671
  }
674
672
  // Check property dependency using dependsOn function
675
673
  if (condition.dependsOn) {
676
- if (!condition.dependsOn(syncRuleProviderInstance)) {
674
+ if (!condition.dependsOn(decoratedClass)) {
677
675
  if (condition.message) {
678
- this.addConditionalMessage(condition, syncRuleProviderInstance, property, {
676
+ this.addConditionalMessage(condition, decoratedClass, property, {
679
677
  propertyName: enumValueStr
680
678
  });
681
679
  }
@@ -693,11 +691,11 @@ class Decorator extends BaseClass {
693
691
  }
694
692
  }
695
693
  /**
696
- * Applies the isViewNode decorator to the schema definition based on the target and property name.
694
+ * Marks the schema definition as a view node if the `@isViewNode` decorator is present on the target.
697
695
  *
698
- * @param schemaDefinition The schema definition to apply the isViewNode decorator to
699
- * @param target The target object or function
700
- * @param propertyName The property name (optional)
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
701
699
  */
702
700
  applyIsViewNodeDecorator(schemaDefinition, target, propertyName) {
703
701
  const isViewNode = Reflect.getMetadata(decoration_1.metadataKeys.isViewNode, target, propertyName);
@@ -707,11 +705,11 @@ class Decorator extends BaseClass {
707
705
  }
708
706
  }
709
707
  /**
710
- * Applies the description decorator to the schema definition.
708
+ * Sets the schema `description` field from the `@description` decorator if present on the target.
711
709
  *
712
- * @param schemaDefinition - The schema definition to apply the decorator to
713
- * @param target - The target object or function
714
- * @param propertyName - The property name (optional)
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
715
713
  */
716
714
  applyDescriptionDecorator(schemaDefinition, target, propertyName) {
717
715
  const description = Reflect.getMetadata(decoration_1.metadataKeys.description, target, propertyName);
@@ -720,12 +718,14 @@ class Decorator extends BaseClass {
720
718
  }
721
719
  }
722
720
  /**
723
- * Applies all decorators to the schema definition.
724
- *
725
- * @param minUi5Version - The minimum UI5 version (optional)
726
- * @param propertyName - The property name (optional)
727
- * @param customDefinition - Optional custom definition to apply decorators to (overrides getBase())
728
- * @returns Object containing the 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.
724
+ *
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
729
729
  */
730
730
  applyDecorators(minUi5Version, propertyName, customDefinition) {
731
731
  const definition = customDefinition ?? this.getBase();