@siliconst/metaui 1.4.20 → 1.4.21

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 (64) hide show
  1. package/package.json +1 -1
  2. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost-dbg.js +8 -3
  3. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost-dbg.js.map +1 -1
  4. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.d.ts +8 -0
  5. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.d.ts.map +1 -1
  6. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.js +1 -1
  7. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.js.map +1 -1
  8. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.ts +2 -3
  9. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost-dbg.js +13 -3
  10. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost-dbg.js.map +1 -1
  11. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost.d.ts +8 -0
  12. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost.d.ts.map +1 -1
  13. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost.js +1 -1
  14. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost.js.map +1 -1
  15. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost.ts +9 -4
  16. package/src/nz/co/siliconst/ui5/metaui/controls/host/delegates/ODataDelegate-dbg.js +13 -0
  17. package/src/nz/co/siliconst/ui5/metaui/controls/host/delegates/ODataDelegate-dbg.js.map +1 -1
  18. package/src/nz/co/siliconst/ui5/metaui/controls/host/delegates/ODataDelegate.d.ts +4 -0
  19. package/src/nz/co/siliconst/ui5/metaui/controls/host/delegates/ODataDelegate.d.ts.map +1 -1
  20. package/src/nz/co/siliconst/ui5/metaui/controls/host/delegates/ODataDelegate.js +1 -1
  21. package/src/nz/co/siliconst/ui5/metaui/controls/host/delegates/ODataDelegate.js.map +1 -1
  22. package/src/nz/co/siliconst/ui5/metaui/controls/host/delegates/ODataDelegate.ts +13 -0
  23. package/src/nz/co/siliconst/ui5/metaui/core/Engine-dbg.js +8 -4
  24. package/src/nz/co/siliconst/ui5/metaui/core/Engine-dbg.js.map +1 -1
  25. package/src/nz/co/siliconst/ui5/metaui/core/Engine.d.ts +5 -1
  26. package/src/nz/co/siliconst/ui5/metaui/core/Engine.d.ts.map +1 -1
  27. package/src/nz/co/siliconst/ui5/metaui/core/Engine.js +1 -1
  28. package/src/nz/co/siliconst/ui5/metaui/core/Engine.js.map +1 -1
  29. package/src/nz/co/siliconst/ui5/metaui/core/Engine.ts +9 -4
  30. package/src/nz/co/siliconst/ui5/metaui/core/PluginRegistry-dbg.js +3 -0
  31. package/src/nz/co/siliconst/ui5/metaui/core/PluginRegistry-dbg.js.map +1 -1
  32. package/src/nz/co/siliconst/ui5/metaui/core/PluginRegistry.d.ts.map +1 -1
  33. package/src/nz/co/siliconst/ui5/metaui/core/PluginRegistry.js +1 -1
  34. package/src/nz/co/siliconst/ui5/metaui/core/PluginRegistry.js.map +1 -1
  35. package/src/nz/co/siliconst/ui5/metaui/core/PluginRegistry.ts +3 -0
  36. package/src/nz/co/siliconst/ui5/metaui/library-preload.js +9 -6
  37. package/src/nz/co/siliconst/ui5/metaui/library-preload.js.map +1 -1
  38. package/src/nz/co/siliconst/ui5/metaui/openapi/OpenApiUIMapper-dbg.js +6 -3
  39. package/src/nz/co/siliconst/ui5/metaui/openapi/OpenApiUIMapper-dbg.js.map +1 -1
  40. package/src/nz/co/siliconst/ui5/metaui/openapi/OpenApiUIMapper.d.ts.map +1 -1
  41. package/src/nz/co/siliconst/ui5/metaui/openapi/OpenApiUIMapper.js +1 -1
  42. package/src/nz/co/siliconst/ui5/metaui/openapi/OpenApiUIMapper.js.map +1 -1
  43. package/src/nz/co/siliconst/ui5/metaui/openapi/OpenApiUIMapper.ts +6 -3
  44. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/EmailPlugin-dbg.js +48 -0
  45. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/EmailPlugin-dbg.js.map +1 -0
  46. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/EmailPlugin.d.ts +11 -0
  47. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/EmailPlugin.d.ts.map +1 -0
  48. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/EmailPlugin.js +2 -0
  49. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/EmailPlugin.js.map +1 -0
  50. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/EmailPlugin.ts +48 -0
  51. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/LinkPlugin-dbg.js +58 -0
  52. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/LinkPlugin-dbg.js.map +1 -0
  53. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/LinkPlugin.d.ts +11 -0
  54. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/LinkPlugin.d.ts.map +1 -0
  55. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/LinkPlugin.js +2 -0
  56. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/LinkPlugin.js.map +1 -0
  57. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/LinkPlugin.ts +57 -0
  58. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/PasswordPlugin-dbg.js +49 -0
  59. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/PasswordPlugin-dbg.js.map +1 -0
  60. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/PasswordPlugin.d.ts +11 -0
  61. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/PasswordPlugin.d.ts.map +1 -0
  62. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/PasswordPlugin.js +2 -0
  63. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/PasswordPlugin.js.map +1 -0
  64. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/PasswordPlugin.ts +49 -0
@@ -39,6 +39,8 @@ export default class GeneratorHost extends Control {
39
39
  schemaDefinition: { type: "any", defaultValue: null },
40
40
  schemaDefinitions: { type: "object", defaultValue: {} },
41
41
  schemaTarget: { type: "string", defaultValue: null },
42
+ pluginRegistry: { type: "object", defaultValue: null },
43
+ schemaBuilderRegistry: { type: "object", defaultValue: null },
42
44
  data: { type: "object", defaultValue: null, bindable: "bindable" },
43
45
  dataJson: { type: "string", defaultValue: null, bindable: "bindable" },
44
46
  liveUpdate: { type: "boolean", defaultValue: false },
@@ -489,12 +491,14 @@ export default class GeneratorHost extends Control {
489
491
  }
490
492
  }
491
493
 
492
- const pathsToLoad = PluginRegistry.getInstance().getPathsToLoad(normalizedSchema as ISchema);
493
- const needsNetworkLoad = Array.from(pathsToLoad).some(path => !sap.ui.require(path));
494
+ const activePluginRegistry = this.getProperty("pluginRegistry") || PluginRegistry.getInstance();
495
+
496
+ const pathsToLoad = activePluginRegistry.getPathsToLoad(normalizedSchema as ISchema);
497
+ const needsNetworkLoad = Array.from(pathsToLoad).some((path: string) => !sap.ui.require(path));
494
498
 
495
499
  if (needsNetworkLoad) {
496
500
  this.setBusy(true);
497
- await PluginRegistry.getInstance().preloadDependencies(normalizedSchema as ISchema);
501
+ await activePluginRegistry.preloadDependencies(normalizedSchema as ISchema);
498
502
  this.setBusy(false);
499
503
  }
500
504
 
@@ -511,7 +515,8 @@ export default class GeneratorHost extends Control {
511
515
  if (!this.engine) {
512
516
  const isEditable = this.getProperty("editable") !== false;
513
517
  const useMessageManager = this.getProperty("useMessageManager") === true;
514
- this.engine = new Engine(isEditable, useMessageManager);
518
+ const activePluginRegistry = this.getProperty("pluginRegistry") || PluginRegistry.getInstance();
519
+ this.engine = new Engine(isEditable, useMessageManager, activePluginRegistry);
515
520
  this.engine.host = this;
516
521
  }
517
522
 
@@ -21,6 +21,19 @@ sap.ui.define(["../../../utils/Logger"], function (_____utils_Logger) {
21
21
  this.host = host;
22
22
  this.context = context;
23
23
  this.detectODataType();
24
+
25
+ // Natively subscribe to the host's field changes to decouple from DynamicHost internals
26
+ this.host.attachEvent("fieldChange", this.onFieldChange, this);
27
+ }
28
+
29
+ /**
30
+ * Event listener wrapper for field changes emitted by the host.
31
+ */
32
+ onFieldChange(oEvent) {
33
+ const params = oEvent.getParameters();
34
+ if (params.fieldPath && params.value !== undefined) {
35
+ this.handleFieldChange(params.fieldPath, params.value);
36
+ }
24
37
  }
25
38
 
26
39
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ODataDelegate-dbg.js","names":["Logger","_____utils_Logger","ODataDelegate","odataType","isSyncing","constructor","host","context","detectODataType","model","getModel","sClassName","getMetadata","getName","indexOf","syncToEngine","requestObject","then","oData","pushPayload","catch","err","error","message","getObject","cleanData","key","Object","keys","startsWith","setProperty","handleFieldChange","fieldPath","value","getProperty","debug","e","__exports","__esModule"],"sources":["ODataDelegate.ts"],"sourcesContent":["import { DynamicHost } from \"../DynamicHost\";\nimport { Logger } from \"../../../utils/Logger\";\nimport ODataV4Context from \"sap/ui/model/odata/v4/Context\";\nimport Context from \"sap/ui/model/Context\";\n\n/**\n * Universal OData Delegate.\n * Natively detects and manages two-way synchronization for both OData V2 and V4 contexts\n * without requiring controller-level mappings.\n */\nexport class ODataDelegate {\n private host: DynamicHost;\n private context: ODataV4Context | Context;\n private odataType: \"V2\" | \"V4\" | null = null;\n private isSyncing: boolean = false;\n\n /**\n * Initializes a new instance of the ODataDelegate.\n * \n * @param {DynamicHost} host The parent MetaUI DynamicHost instance managing the UI generation.\n * @param {Context} context The active UI5 Model Context bound to the host.\n */\n constructor(host: DynamicHost, context: ODataV4Context | Context) {\n this.host = host;\n this.context = context;\n this.detectODataType();\n }\n\n /**\n * Evaluates the underlying UI5 Model bound to the context to determine if it is an\n * OData V2 or OData V4 model. This determination drives the synchronization strategy.\n * \n * @private\n */\n private detectODataType(): void {\n const model = this.context.getModel();\n // sap.ui.model.odata.v4.ODataModel\n // sap.ui.model.odata.v2.ODataModel\n const sClassName = model.getMetadata().getName();\n if (sClassName.indexOf(\"v4\") > -1) {\n this.odataType = \"V4\";\n } else if (sClassName.indexOf(\"v2\") > -1 || sClassName.indexOf(\"ODataModel\") > -1) {\n this.odataType = \"V2\";\n }\n }\n\n /**\n * Extracts the full entity payload from the bound OData context and pushes it to the Engine.\n * V4 uses an asynchronous requestObject(), while V2 retrieves it synchronously.\n * \n * @public\n */\n public syncToEngine(): void {\n if (!this.odataType) return;\n\n if (this.odataType === \"V4\") {\n // V4 uses async requestObject()\n if (typeof this.context.requestObject === \"function\") {\n this.context.requestObject().then((oData: unknown) => {\n this.pushPayload(oData);\n }).catch((err: Error) => {\n Logger.error(\"[MetaUI]\", \"Failed to extract V4 Context payload: \" + err.message, \"ODataDelegate\");\n });\n }\n } else if (this.odataType === \"V2\") {\n // V2 uses sync getObject()\n const oData = this.context.getObject();\n if (oData) {\n this.pushPayload(oData);\n }\n }\n }\n\n /**\n * Cleans the raw OData payload by stripping framework metadata properties (keys starting with '@' or '__')\n * and pushes the sanitized business data into the MetaUI DynamicHost state manager.\n * \n * @param {unknown} oData The raw JSON object extracted from the OData model context.\n * @private\n */\n private pushPayload(oData: unknown): void {\n if (!oData) return;\n \n // Remove OData metadata properties before pushing to MetaUI\n const cleanData = { ...(oData as Record<string, unknown>) };\n for (const key of Object.keys(cleanData)) {\n if (key.startsWith(\"@\") || key.startsWith(\"__\")) {\n delete cleanData[key];\n }\n }\n\n this.isSyncing = true;\n this.host.setProperty(\"data\", cleanData);\n this.isSyncing = false;\n }\n\n /**\n * Intercepts a field change from the MetaUI Engine and translates it into an OData PATCH.\n */\n public handleFieldChange(fieldPath: string, value: unknown): void {\n if (this.isSyncing || !this.odataType) return;\n\n try {\n if (this.odataType === \"V4\") {\n // V4 sets property directly on context\n this.context.setProperty(fieldPath, value);\n } else if (this.odataType === \"V2\") {\n // V2 sets property on model, specifying the context path\n const model = this.context.getModel();\n model.setProperty(fieldPath, value, this.context);\n }\n if (this.host.getProperty(\"debugMode\")) {\n Logger.debug(\"[MetaUI]\", `ODataDelegate Patched ${fieldPath} = ${value} via ${this.odataType}`, \"ODataDelegate\");\n }\n } catch (e) {\n Logger.error(\"[MetaUI]\", `Failed to patch OData context: ${(e as Error).message}`, \"ODataDelegate\");\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"ODataDelegate-dbg.js","names":["Logger","_____utils_Logger","ODataDelegate","odataType","isSyncing","constructor","host","context","detectODataType","attachEvent","onFieldChange","oEvent","params","getParameters","fieldPath","value","undefined","handleFieldChange","model","getModel","sClassName","getMetadata","getName","indexOf","syncToEngine","requestObject","then","oData","pushPayload","catch","err","error","message","getObject","cleanData","key","Object","keys","startsWith","setProperty","getProperty","debug","e","__exports","__esModule"],"sources":["ODataDelegate.ts"],"sourcesContent":["import { DynamicHost } from \"../DynamicHost\";\nimport { Logger } from \"../../../utils/Logger\";\nimport ODataV4Context from \"sap/ui/model/odata/v4/Context\";\nimport Context from \"sap/ui/model/Context\";\n\n/**\n * Universal OData Delegate.\n * Natively detects and manages two-way synchronization for both OData V2 and V4 contexts\n * without requiring controller-level mappings.\n */\nexport class ODataDelegate {\n private host: DynamicHost;\n private context: ODataV4Context | Context;\n private odataType: \"V2\" | \"V4\" | null = null;\n private isSyncing: boolean = false;\n\n /**\n * Initializes a new instance of the ODataDelegate.\n * \n * @param {DynamicHost} host The parent MetaUI DynamicHost instance managing the UI generation.\n * @param {Context} context The active UI5 Model Context bound to the host.\n */\n constructor(host: DynamicHost, context: ODataV4Context | Context) {\n this.host = host;\n this.context = context;\n this.detectODataType();\n \n // Natively subscribe to the host's field changes to decouple from DynamicHost internals\n this.host.attachEvent(\"fieldChange\", this.onFieldChange, this);\n }\n\n /**\n * Event listener wrapper for field changes emitted by the host.\n */\n private onFieldChange(oEvent: sap.ui.base.Event): void {\n const params = oEvent.getParameters();\n if (params.fieldPath && params.value !== undefined) {\n this.handleFieldChange(params.fieldPath, params.value);\n }\n }\n\n /**\n * Evaluates the underlying UI5 Model bound to the context to determine if it is an\n * OData V2 or OData V4 model. This determination drives the synchronization strategy.\n * \n * @private\n */\n private detectODataType(): void {\n const model = this.context.getModel();\n // sap.ui.model.odata.v4.ODataModel\n // sap.ui.model.odata.v2.ODataModel\n const sClassName = model.getMetadata().getName();\n if (sClassName.indexOf(\"v4\") > -1) {\n this.odataType = \"V4\";\n } else if (sClassName.indexOf(\"v2\") > -1 || sClassName.indexOf(\"ODataModel\") > -1) {\n this.odataType = \"V2\";\n }\n }\n\n /**\n * Extracts the full entity payload from the bound OData context and pushes it to the Engine.\n * V4 uses an asynchronous requestObject(), while V2 retrieves it synchronously.\n * \n * @public\n */\n public syncToEngine(): void {\n if (!this.odataType) return;\n\n if (this.odataType === \"V4\") {\n // V4 uses async requestObject()\n if (typeof this.context.requestObject === \"function\") {\n this.context.requestObject().then((oData: unknown) => {\n this.pushPayload(oData);\n }).catch((err: Error) => {\n Logger.error(\"[MetaUI]\", \"Failed to extract V4 Context payload: \" + err.message, \"ODataDelegate\");\n });\n }\n } else if (this.odataType === \"V2\") {\n // V2 uses sync getObject()\n const oData = this.context.getObject();\n if (oData) {\n this.pushPayload(oData);\n }\n }\n }\n\n /**\n * Cleans the raw OData payload by stripping framework metadata properties (keys starting with '@' or '__')\n * and pushes the sanitized business data into the MetaUI DynamicHost state manager.\n * \n * @param {unknown} oData The raw JSON object extracted from the OData model context.\n * @private\n */\n private pushPayload(oData: unknown): void {\n if (!oData) return;\n \n // Remove OData metadata properties before pushing to MetaUI\n const cleanData = { ...(oData as Record<string, unknown>) };\n for (const key of Object.keys(cleanData)) {\n if (key.startsWith(\"@\") || key.startsWith(\"__\")) {\n delete cleanData[key];\n }\n }\n\n this.isSyncing = true;\n this.host.setProperty(\"data\", cleanData);\n this.isSyncing = false;\n }\n\n /**\n * Intercepts a field change from the MetaUI Engine and translates it into an OData PATCH.\n */\n public handleFieldChange(fieldPath: string, value: unknown): void {\n if (this.isSyncing || !this.odataType) return;\n\n try {\n if (this.odataType === \"V4\") {\n // V4 sets property directly on context\n this.context.setProperty(fieldPath, value);\n } else if (this.odataType === \"V2\") {\n // V2 sets property on model, specifying the context path\n const model = this.context.getModel();\n model.setProperty(fieldPath, value, this.context);\n }\n if (this.host.getProperty(\"debugMode\")) {\n Logger.debug(\"[MetaUI]\", `ODataDelegate Patched ${fieldPath} = ${value} via ${this.odataType}`, \"ODataDelegate\");\n }\n } catch (e) {\n Logger.error(\"[MetaUI]\", `Failed to patch OData context: ${(e as Error).message}`, \"ODataDelegate\");\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -19,6 +19,10 @@ declare module "nz/co/siliconst/ui5/metaui/controls/host/delegates/ODataDelegate
19
19
  * @param {Context} context The active UI5 Model Context bound to the host.
20
20
  */
21
21
  constructor(host: DynamicHost, context: ODataV4Context | Context);
22
+ /**
23
+ * Event listener wrapper for field changes emitted by the host.
24
+ */
25
+ private onFieldChange;
22
26
  /**
23
27
  * Evaluates the underlying UI5 Model bound to the context to determine if it is an
24
28
  * OData V2 or OData V4 model. This determination drives the synchronization strategy.
@@ -1 +1 @@
1
- {"version":3,"file":"ODataDelegate.d.ts","sourceRoot":"../../../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/controls/host/delegates/ODataDelegate.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,kEAAkE,CAAC;IAClF,OAAO,EAAE,WAAW,EAAE,MAAM,sDAAsD,CAAC;IAEnF,OAAO,cAAc,MAAM,+BAA+B,CAAC;IAC3D,OAAO,OAAO,MAAM,sBAAsB,CAAC;IAE3C;;;;OAIG;IACH,MAAa,aAAa;QACtB,OAAO,CAAC,IAAI,CAAc;QAC1B,OAAO,CAAC,OAAO,CAA2B;QAC1C,OAAO,CAAC,SAAS,CAA4B;QAC7C,OAAO,CAAC,SAAS,CAAkB;QAEnC;;;;;WAKG;oBACS,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO;QAMhE;;;;;WAKG;QACH,OAAO,CAAC,eAAe;QAYvB;;;;;WAKG;QACI,YAAY,IAAI,IAAI;QAqB3B;;;;;;WAMG;QACH,OAAO,CAAC,WAAW;QAgBnB;;WAEG;QACI,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;KAmBpE;CAEA"}
1
+ {"version":3,"file":"ODataDelegate.d.ts","sourceRoot":"../../../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/controls/host/delegates/ODataDelegate.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,kEAAkE,CAAC;IAClF,OAAO,EAAE,WAAW,EAAE,MAAM,sDAAsD,CAAC;IAEnF,OAAO,cAAc,MAAM,+BAA+B,CAAC;IAC3D,OAAO,OAAO,MAAM,sBAAsB,CAAC;IAE3C;;;;OAIG;IACH,MAAa,aAAa;QACtB,OAAO,CAAC,IAAI,CAAc;QAC1B,OAAO,CAAC,OAAO,CAA2B;QAC1C,OAAO,CAAC,SAAS,CAA4B;QAC7C,OAAO,CAAC,SAAS,CAAkB;QAEnC;;;;;WAKG;oBACS,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO;QAShE;;WAEG;QACH,OAAO,CAAC,aAAa;QAOrB;;;;;WAKG;QACH,OAAO,CAAC,eAAe;QAYvB;;;;;WAKG;QACI,YAAY,IAAI,IAAI;QAqB3B;;;;;;WAMG;QACH,OAAO,CAAC,WAAW;QAgBnB;;WAEG;QACI,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;KAmBpE;CAEA"}
@@ -1,2 +1,2 @@
1
- sap.ui.define(["../../../utils/Logger"],function(t){"use strict";const e=t["Logger"];class a{odataType=null;isSyncing=false;constructor(t,e){this.host=t;this.context=e;this.detectODataType()}detectODataType(){const t=this.context.getModel();const e=t.getMetadata().getName();if(e.indexOf("v4")>-1){this.odataType="V4"}else if(e.indexOf("v2")>-1||e.indexOf("ODataModel")>-1){this.odataType="V2"}}syncToEngine(){if(!this.odataType)return;if(this.odataType==="V4"){if(typeof this.context.requestObject==="function"){this.context.requestObject().then(t=>{this.pushPayload(t)}).catch(t=>{e.error("[MetaUI]","Failed to extract V4 Context payload: "+t.message,"ODataDelegate")})}}else if(this.odataType==="V2"){const t=this.context.getObject();if(t){this.pushPayload(t)}}}pushPayload(t){if(!t)return;const e={...t};for(const t of Object.keys(e)){if(t.startsWith("@")||t.startsWith("__")){delete e[t]}}this.isSyncing=true;this.host.setProperty("data",e);this.isSyncing=false}handleFieldChange(t,a){if(this.isSyncing||!this.odataType)return;try{if(this.odataType==="V4"){this.context.setProperty(t,a)}else if(this.odataType==="V2"){const e=this.context.getModel();e.setProperty(t,a,this.context)}if(this.host.getProperty("debugMode")){e.debug("[MetaUI]",`ODataDelegate Patched ${t} = ${a} via ${this.odataType}`,"ODataDelegate")}}catch(t){e.error("[MetaUI]",`Failed to patch OData context: ${t.message}`,"ODataDelegate")}}}var s={__esModule:true};s.ODataDelegate=a;return s});
1
+ sap.ui.define(["../../../utils/Logger"],function(t){"use strict";const e=t["Logger"];class a{odataType=null;isSyncing=false;constructor(t,e){this.host=t;this.context=e;this.detectODataType();this.host.attachEvent("fieldChange",this.onFieldChange,this)}onFieldChange(t){const e=t.getParameters();if(e.fieldPath&&e.value!==undefined){this.handleFieldChange(e.fieldPath,e.value)}}detectODataType(){const t=this.context.getModel();const e=t.getMetadata().getName();if(e.indexOf("v4")>-1){this.odataType="V4"}else if(e.indexOf("v2")>-1||e.indexOf("ODataModel")>-1){this.odataType="V2"}}syncToEngine(){if(!this.odataType)return;if(this.odataType==="V4"){if(typeof this.context.requestObject==="function"){this.context.requestObject().then(t=>{this.pushPayload(t)}).catch(t=>{e.error("[MetaUI]","Failed to extract V4 Context payload: "+t.message,"ODataDelegate")})}}else if(this.odataType==="V2"){const t=this.context.getObject();if(t){this.pushPayload(t)}}}pushPayload(t){if(!t)return;const e={...t};for(const t of Object.keys(e)){if(t.startsWith("@")||t.startsWith("__")){delete e[t]}}this.isSyncing=true;this.host.setProperty("data",e);this.isSyncing=false}handleFieldChange(t,a){if(this.isSyncing||!this.odataType)return;try{if(this.odataType==="V4"){this.context.setProperty(t,a)}else if(this.odataType==="V2"){const e=this.context.getModel();e.setProperty(t,a,this.context)}if(this.host.getProperty("debugMode")){e.debug("[MetaUI]",`ODataDelegate Patched ${t} = ${a} via ${this.odataType}`,"ODataDelegate")}}catch(t){e.error("[MetaUI]",`Failed to patch OData context: ${t.message}`,"ODataDelegate")}}}var s={__esModule:true};s.ODataDelegate=a;return s});
2
2
  //# sourceMappingURL=ODataDelegate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ODataDelegate.js","names":["Logger","_____utils_Logger","ODataDelegate","odataType","isSyncing","constructor","host","context","this","detectODataType","model","getModel","sClassName","getMetadata","getName","indexOf","syncToEngine","requestObject","then","oData","pushPayload","catch","err","error","message","getObject","cleanData","key","Object","keys","startsWith","setProperty","handleFieldChange","fieldPath","value","getProperty","debug","e","__exports","__esModule"],"sources":["ODataDelegate.ts"],"sourcesContent":["import { DynamicHost } from \"../DynamicHost\";\nimport { Logger } from \"../../../utils/Logger\";\nimport ODataV4Context from \"sap/ui/model/odata/v4/Context\";\nimport Context from \"sap/ui/model/Context\";\n\n/**\n * Universal OData Delegate.\n * Natively detects and manages two-way synchronization for both OData V2 and V4 contexts\n * without requiring controller-level mappings.\n */\nexport class ODataDelegate {\n private host: DynamicHost;\n private context: ODataV4Context | Context;\n private odataType: \"V2\" | \"V4\" | null = null;\n private isSyncing: boolean = false;\n\n /**\n * Initializes a new instance of the ODataDelegate.\n * \n * @param {DynamicHost} host The parent MetaUI DynamicHost instance managing the UI generation.\n * @param {Context} context The active UI5 Model Context bound to the host.\n */\n constructor(host: DynamicHost, context: ODataV4Context | Context) {\n this.host = host;\n this.context = context;\n this.detectODataType();\n }\n\n /**\n * Evaluates the underlying UI5 Model bound to the context to determine if it is an\n * OData V2 or OData V4 model. This determination drives the synchronization strategy.\n * \n * @private\n */\n private detectODataType(): void {\n const model = this.context.getModel();\n // sap.ui.model.odata.v4.ODataModel\n // sap.ui.model.odata.v2.ODataModel\n const sClassName = model.getMetadata().getName();\n if (sClassName.indexOf(\"v4\") > -1) {\n this.odataType = \"V4\";\n } else if (sClassName.indexOf(\"v2\") > -1 || sClassName.indexOf(\"ODataModel\") > -1) {\n this.odataType = \"V2\";\n }\n }\n\n /**\n * Extracts the full entity payload from the bound OData context and pushes it to the Engine.\n * V4 uses an asynchronous requestObject(), while V2 retrieves it synchronously.\n * \n * @public\n */\n public syncToEngine(): void {\n if (!this.odataType) return;\n\n if (this.odataType === \"V4\") {\n // V4 uses async requestObject()\n if (typeof this.context.requestObject === \"function\") {\n this.context.requestObject().then((oData: unknown) => {\n this.pushPayload(oData);\n }).catch((err: Error) => {\n Logger.error(\"[MetaUI]\", \"Failed to extract V4 Context payload: \" + err.message, \"ODataDelegate\");\n });\n }\n } else if (this.odataType === \"V2\") {\n // V2 uses sync getObject()\n const oData = this.context.getObject();\n if (oData) {\n this.pushPayload(oData);\n }\n }\n }\n\n /**\n * Cleans the raw OData payload by stripping framework metadata properties (keys starting with '@' or '__')\n * and pushes the sanitized business data into the MetaUI DynamicHost state manager.\n * \n * @param {unknown} oData The raw JSON object extracted from the OData model context.\n * @private\n */\n private pushPayload(oData: unknown): void {\n if (!oData) return;\n \n // Remove OData metadata properties before pushing to MetaUI\n const cleanData = { ...(oData as Record<string, unknown>) };\n for (const key of Object.keys(cleanData)) {\n if (key.startsWith(\"@\") || key.startsWith(\"__\")) {\n delete cleanData[key];\n }\n }\n\n this.isSyncing = true;\n this.host.setProperty(\"data\", cleanData);\n this.isSyncing = false;\n }\n\n /**\n * Intercepts a field change from the MetaUI Engine and translates it into an OData PATCH.\n */\n public handleFieldChange(fieldPath: string, value: unknown): void {\n if (this.isSyncing || !this.odataType) return;\n\n try {\n if (this.odataType === \"V4\") {\n // V4 sets property directly on context\n this.context.setProperty(fieldPath, value);\n } else if (this.odataType === \"V2\") {\n // V2 sets property on model, specifying the context path\n const model = this.context.getModel();\n model.setProperty(fieldPath, value, this.context);\n }\n if (this.host.getProperty(\"debugMode\")) {\n Logger.debug(\"[MetaUI]\", `ODataDelegate Patched ${fieldPath} = ${value} via ${this.odataType}`, \"ODataDelegate\");\n }\n } catch (e) {\n Logger.error(\"[MetaUI]\", `Failed to patch OData context: ${(e as Error).message}`, \"ODataDelegate\");\n }\n }\n}\n"],"mappings":"uEACSA,EAAMC,EAAA,UASR,MAAMC,EAGDC,UAAgC,KAChCC,UAAqB,MAQ7BC,YAAYC,EAAmBC,GAC3BC,KAAKF,KAAOA,EACZE,KAAKD,QAAUA,EACfC,KAAKC,iBACT,CAQQA,kBACJ,MAAMC,EAAQF,KAAKD,QAAQI,WAG3B,MAAMC,EAAaF,EAAMG,cAAcC,UACvC,GAAIF,EAAWG,QAAQ,OAAS,EAAG,CAC/BP,KAAKL,UAAY,IACrB,MAAO,GAAIS,EAAWG,QAAQ,OAAS,GAAKH,EAAWG,QAAQ,eAAiB,EAAG,CAC/EP,KAAKL,UAAY,IACrB,CACJ,CAQOa,eACH,IAAKR,KAAKL,UAAW,OAErB,GAAIK,KAAKL,YAAc,KAAM,CAEzB,UAAWK,KAAKD,QAAQU,gBAAkB,WAAY,CAClDT,KAAKD,QAAQU,gBAAgBC,KAAMC,IAC/BX,KAAKY,YAAYD,KAClBE,MAAOC,IACNtB,EAAOuB,MAAM,WAAY,yCAA2CD,EAAIE,QAAS,kBAEzF,CACJ,MAAO,GAAIhB,KAAKL,YAAc,KAAM,CAEhC,MAAMgB,EAAQX,KAAKD,QAAQkB,YAC3B,GAAIN,EAAO,CACPX,KAAKY,YAAYD,EACrB,CACJ,CACJ,CASQC,YAAYD,GAChB,IAAKA,EAAO,OAGZ,MAAMO,EAAY,IAAMP,GACxB,IAAK,MAAMQ,KAAOC,OAAOC,KAAKH,GAAY,CACtC,GAAIC,EAAIG,WAAW,MAAQH,EAAIG,WAAW,MAAO,QACtCJ,EAAUC,EACrB,CACJ,CAEAnB,KAAKJ,UAAY,KACjBI,KAAKF,KAAKyB,YAAY,OAAQL,GAC9BlB,KAAKJ,UAAY,KACrB,CAKO4B,kBAAkBC,EAAmBC,GACxC,GAAI1B,KAAKJ,YAAcI,KAAKL,UAAW,OAEvC,IACI,GAAIK,KAAKL,YAAc,KAAM,CAEzBK,KAAKD,QAAQwB,YAAYE,EAAWC,EACxC,MAAO,GAAI1B,KAAKL,YAAc,KAAM,CAEhC,MAAMO,EAAQF,KAAKD,QAAQI,WAC3BD,EAAMqB,YAAYE,EAAWC,EAAO1B,KAAKD,QAC7C,CACA,GAAIC,KAAKF,KAAK6B,YAAY,aAAc,CACpCnC,EAAOoC,MAAM,WAAY,yBAAyBH,OAAeC,SAAa1B,KAAKL,YAAa,gBACpG,CACJ,CAAE,MAAOkC,GACLrC,EAAOuB,MAAM,WAAY,kCAAmCc,EAAYb,UAAW,gBACvF,CACJ,EACH,IAAAc,EAAA,CAAAC,WAAA,MAAAD,EAAApC,gBAAA,OAAAoC,CAAA","ignoreList":[]}
1
+ {"version":3,"file":"ODataDelegate.js","names":["Logger","_____utils_Logger","ODataDelegate","odataType","isSyncing","constructor","host","context","this","detectODataType","attachEvent","onFieldChange","oEvent","params","getParameters","fieldPath","value","undefined","handleFieldChange","model","getModel","sClassName","getMetadata","getName","indexOf","syncToEngine","requestObject","then","oData","pushPayload","catch","err","error","message","getObject","cleanData","key","Object","keys","startsWith","setProperty","getProperty","debug","e","__exports","__esModule"],"sources":["ODataDelegate.ts"],"sourcesContent":["import { DynamicHost } from \"../DynamicHost\";\nimport { Logger } from \"../../../utils/Logger\";\nimport ODataV4Context from \"sap/ui/model/odata/v4/Context\";\nimport Context from \"sap/ui/model/Context\";\n\n/**\n * Universal OData Delegate.\n * Natively detects and manages two-way synchronization for both OData V2 and V4 contexts\n * without requiring controller-level mappings.\n */\nexport class ODataDelegate {\n private host: DynamicHost;\n private context: ODataV4Context | Context;\n private odataType: \"V2\" | \"V4\" | null = null;\n private isSyncing: boolean = false;\n\n /**\n * Initializes a new instance of the ODataDelegate.\n * \n * @param {DynamicHost} host The parent MetaUI DynamicHost instance managing the UI generation.\n * @param {Context} context The active UI5 Model Context bound to the host.\n */\n constructor(host: DynamicHost, context: ODataV4Context | Context) {\n this.host = host;\n this.context = context;\n this.detectODataType();\n \n // Natively subscribe to the host's field changes to decouple from DynamicHost internals\n this.host.attachEvent(\"fieldChange\", this.onFieldChange, this);\n }\n\n /**\n * Event listener wrapper for field changes emitted by the host.\n */\n private onFieldChange(oEvent: sap.ui.base.Event): void {\n const params = oEvent.getParameters();\n if (params.fieldPath && params.value !== undefined) {\n this.handleFieldChange(params.fieldPath, params.value);\n }\n }\n\n /**\n * Evaluates the underlying UI5 Model bound to the context to determine if it is an\n * OData V2 or OData V4 model. This determination drives the synchronization strategy.\n * \n * @private\n */\n private detectODataType(): void {\n const model = this.context.getModel();\n // sap.ui.model.odata.v4.ODataModel\n // sap.ui.model.odata.v2.ODataModel\n const sClassName = model.getMetadata().getName();\n if (sClassName.indexOf(\"v4\") > -1) {\n this.odataType = \"V4\";\n } else if (sClassName.indexOf(\"v2\") > -1 || sClassName.indexOf(\"ODataModel\") > -1) {\n this.odataType = \"V2\";\n }\n }\n\n /**\n * Extracts the full entity payload from the bound OData context and pushes it to the Engine.\n * V4 uses an asynchronous requestObject(), while V2 retrieves it synchronously.\n * \n * @public\n */\n public syncToEngine(): void {\n if (!this.odataType) return;\n\n if (this.odataType === \"V4\") {\n // V4 uses async requestObject()\n if (typeof this.context.requestObject === \"function\") {\n this.context.requestObject().then((oData: unknown) => {\n this.pushPayload(oData);\n }).catch((err: Error) => {\n Logger.error(\"[MetaUI]\", \"Failed to extract V4 Context payload: \" + err.message, \"ODataDelegate\");\n });\n }\n } else if (this.odataType === \"V2\") {\n // V2 uses sync getObject()\n const oData = this.context.getObject();\n if (oData) {\n this.pushPayload(oData);\n }\n }\n }\n\n /**\n * Cleans the raw OData payload by stripping framework metadata properties (keys starting with '@' or '__')\n * and pushes the sanitized business data into the MetaUI DynamicHost state manager.\n * \n * @param {unknown} oData The raw JSON object extracted from the OData model context.\n * @private\n */\n private pushPayload(oData: unknown): void {\n if (!oData) return;\n \n // Remove OData metadata properties before pushing to MetaUI\n const cleanData = { ...(oData as Record<string, unknown>) };\n for (const key of Object.keys(cleanData)) {\n if (key.startsWith(\"@\") || key.startsWith(\"__\")) {\n delete cleanData[key];\n }\n }\n\n this.isSyncing = true;\n this.host.setProperty(\"data\", cleanData);\n this.isSyncing = false;\n }\n\n /**\n * Intercepts a field change from the MetaUI Engine and translates it into an OData PATCH.\n */\n public handleFieldChange(fieldPath: string, value: unknown): void {\n if (this.isSyncing || !this.odataType) return;\n\n try {\n if (this.odataType === \"V4\") {\n // V4 sets property directly on context\n this.context.setProperty(fieldPath, value);\n } else if (this.odataType === \"V2\") {\n // V2 sets property on model, specifying the context path\n const model = this.context.getModel();\n model.setProperty(fieldPath, value, this.context);\n }\n if (this.host.getProperty(\"debugMode\")) {\n Logger.debug(\"[MetaUI]\", `ODataDelegate Patched ${fieldPath} = ${value} via ${this.odataType}`, \"ODataDelegate\");\n }\n } catch (e) {\n Logger.error(\"[MetaUI]\", `Failed to patch OData context: ${(e as Error).message}`, \"ODataDelegate\");\n }\n }\n}\n"],"mappings":"uEACSA,EAAMC,EAAA,UASR,MAAMC,EAGDC,UAAgC,KAChCC,UAAqB,MAQ7BC,YAAYC,EAAmBC,GAC3BC,KAAKF,KAAOA,EACZE,KAAKD,QAAUA,EACfC,KAAKC,kBAGLD,KAAKF,KAAKI,YAAY,cAAeF,KAAKG,cAAeH,KAC7D,CAKQG,cAAcC,GAClB,MAAMC,EAASD,EAAOE,gBACtB,GAAID,EAAOE,WAAaF,EAAOG,QAAUC,UAAW,CAChDT,KAAKU,kBAAkBL,EAAOE,UAAWF,EAAOG,MACpD,CACJ,CAQQP,kBACJ,MAAMU,EAAQX,KAAKD,QAAQa,WAG3B,MAAMC,EAAaF,EAAMG,cAAcC,UACvC,GAAIF,EAAWG,QAAQ,OAAS,EAAG,CAC/BhB,KAAKL,UAAY,IACrB,MAAO,GAAIkB,EAAWG,QAAQ,OAAS,GAAKH,EAAWG,QAAQ,eAAiB,EAAG,CAC/EhB,KAAKL,UAAY,IACrB,CACJ,CAQOsB,eACH,IAAKjB,KAAKL,UAAW,OAErB,GAAIK,KAAKL,YAAc,KAAM,CAEzB,UAAWK,KAAKD,QAAQmB,gBAAkB,WAAY,CAClDlB,KAAKD,QAAQmB,gBAAgBC,KAAMC,IAC/BpB,KAAKqB,YAAYD,KAClBE,MAAOC,IACN/B,EAAOgC,MAAM,WAAY,yCAA2CD,EAAIE,QAAS,kBAEzF,CACJ,MAAO,GAAIzB,KAAKL,YAAc,KAAM,CAEhC,MAAMyB,EAAQpB,KAAKD,QAAQ2B,YAC3B,GAAIN,EAAO,CACPpB,KAAKqB,YAAYD,EACrB,CACJ,CACJ,CASQC,YAAYD,GAChB,IAAKA,EAAO,OAGZ,MAAMO,EAAY,IAAMP,GACxB,IAAK,MAAMQ,KAAOC,OAAOC,KAAKH,GAAY,CACtC,GAAIC,EAAIG,WAAW,MAAQH,EAAIG,WAAW,MAAO,QACtCJ,EAAUC,EACrB,CACJ,CAEA5B,KAAKJ,UAAY,KACjBI,KAAKF,KAAKkC,YAAY,OAAQL,GAC9B3B,KAAKJ,UAAY,KACrB,CAKOc,kBAAkBH,EAAmBC,GACxC,GAAIR,KAAKJ,YAAcI,KAAKL,UAAW,OAEvC,IACI,GAAIK,KAAKL,YAAc,KAAM,CAEzBK,KAAKD,QAAQiC,YAAYzB,EAAWC,EACxC,MAAO,GAAIR,KAAKL,YAAc,KAAM,CAEhC,MAAMgB,EAAQX,KAAKD,QAAQa,WAC3BD,EAAMqB,YAAYzB,EAAWC,EAAOR,KAAKD,QAC7C,CACA,GAAIC,KAAKF,KAAKmC,YAAY,aAAc,CACpCzC,EAAO0C,MAAM,WAAY,yBAAyB3B,OAAeC,SAAaR,KAAKL,YAAa,gBACpG,CACJ,CAAE,MAAOwC,GACL3C,EAAOgC,MAAM,WAAY,kCAAmCW,EAAYV,UAAW,gBACvF,CACJ,EACH,IAAAW,EAAA,CAAAC,WAAA,MAAAD,EAAA1C,gBAAA,OAAA0C,CAAA","ignoreList":[]}
@@ -24,6 +24,19 @@ export class ODataDelegate {
24
24
  this.host = host;
25
25
  this.context = context;
26
26
  this.detectODataType();
27
+
28
+ // Natively subscribe to the host's field changes to decouple from DynamicHost internals
29
+ this.host.attachEvent("fieldChange", this.onFieldChange, this);
30
+ }
31
+
32
+ /**
33
+ * Event listener wrapper for field changes emitted by the host.
34
+ */
35
+ private onFieldChange(oEvent: sap.ui.base.Event): void {
36
+ const params = oEvent.getParameters();
37
+ if (params.fieldPath && params.value !== undefined) {
38
+ this.handleFieldChange(params.fieldPath, params.value);
39
+ }
27
40
  }
28
41
 
29
42
  /**
@@ -41,14 +41,18 @@ sap.ui.define(["./ConditionEngine", "./PluginRegistry", "sap/m/Text", "../utils/
41
41
  /** Tracks whether the engine should delegate visual state to the global MessageManager. */
42
42
  useMessageManager = false;
43
43
 
44
+ /** The injected PluginRegistry instance */
45
+
44
46
  /**
45
47
  * Initializes a new Engine instance.
46
48
  * @param editable Whether the engine should render form fields as editable or read-only.
47
49
  * @param useMessageManager Whether to delegate visual state to UI5 MessageManager.
50
+ * @param pluginRegistry Optional injected plugin registry. Defaults to singleton.
48
51
  */
49
- constructor(editable = true, useMessageManager = false) {
52
+ constructor(editable = true, useMessageManager = false, pluginRegistry) {
50
53
  this.isEditable = editable;
51
54
  this.useMessageManager = useMessageManager;
55
+ this.pluginRegistry = pluginRegistry || PluginRegistry.getInstance();
52
56
  }
53
57
 
54
58
  /**
@@ -81,7 +85,7 @@ sap.ui.define(["./ConditionEngine", "./PluginRegistry", "sap/m/Text", "../utils/
81
85
  Logger.warn("[MetaUI Engine] Missing 'uiLayout' array in schema. Synthesized a default layout mapping to prevent a blank render.");
82
86
  }
83
87
  const layoutStrategy = schema.layoutStrategy || (schema.type === "array" ? "table" : "form");
84
- const layoutManager = PluginRegistry.getInstance().getLayout(layoutStrategy);
88
+ const layoutManager = this.pluginRegistry.getLayout(layoutStrategy);
85
89
  return layoutManager.render(schema, modelName, this, onSubmit);
86
90
  } catch (error) {
87
91
  this.hasPartialRenderingErrors = true;
@@ -105,7 +109,7 @@ sap.ui.define(["./ConditionEngine", "./PluginRegistry", "sap/m/Text", "../utils/
105
109
  */
106
110
  generateField(fieldMeta, bindingPath, modelName, isTemplate = false) {
107
111
  try {
108
- const plugin = PluginRegistry.getInstance().getPlugin(fieldMeta.type || "string", fieldMeta.ui?.widget);
112
+ const plugin = this.pluginRegistry.getPlugin(fieldMeta.type || "string", fieldMeta.ui?.widget);
109
113
  if (typeof plugin.setEditable === "function") {
110
114
  plugin.setEditable(this.isEditable);
111
115
  }
@@ -147,7 +151,7 @@ sap.ui.define(["./ConditionEngine", "./PluginRegistry", "sap/m/Text", "../utils/
147
151
  generateLayout(schema, modelName, bindingPath) {
148
152
  try {
149
153
  const layoutStrategy = schema.layoutStrategy || (schema.type === "array" ? "table" : "form");
150
- const layoutManager = PluginRegistry.getInstance().getLayout(layoutStrategy);
154
+ const layoutManager = this.pluginRegistry.getLayout(layoutStrategy);
151
155
  return layoutManager.render(schema, modelName, this, undefined, bindingPath);
152
156
  } catch (error) {
153
157
  this.hasPartialRenderingErrors = true;
@@ -1 +1 @@
1
- {"version":3,"file":"Engine-dbg.js","names":["ConditionEngine","___ConditionEngine","PluginRegistry","___PluginRegistry","Logger","___utils_Logger","DefaultLayoutGenerator","___DefaultLayoutGenerator","Engine","conditionEngine","activePlugins","isEditable","hasPartialRenderingErrors","useMessageManager","constructor","editable","build","schema","model","modelName","onSubmit","engineScopeId","onChange","activeModel","isValid","fieldKey","errorMessage","controlId","handleEvent","ensureLayout","warn","layoutStrategy","type","layoutManager","getInstance","getLayout","render","error","msg","message","showErrorPopup","Text","text","generateField","fieldMeta","bindingPath","isTemplate","plugin","getPlugin","ui","widget","setEditable","setUseMessageManager","push","path","scopeId","undefined","control","registerPlugin","generateLayout","validateAll","applyVisualState","errors","item","result","validate","setVisualValidationState","replace","name","getPluginByPath","cleanPath","startsWith","match","find","p","destroy","messageManager","Messaging","existingMessages","getMessageModel","getData","messagesToRemove","targetPath","matched","filter","getTarget","getMessageProcessor","getId","length","removeMessages","__exports","__esModule"],"sources":["Engine.ts"],"sourcesContent":["/**\n * @file Engine.ts\n * @description The central orchestrator that routes data between the Layout Factory and Plugin Registry (v2).\n */\n\nimport { ISchema, IPropertyMetadata } from \"../interfaces/ISchema\";\nimport { ILayoutManager } from \"../interfaces/ILayoutManager\";\nimport { IPlugin, IPluginValidationResult } from \"../interfaces/IPlugin\";\nimport { ConditionEngine } from \"./ConditionEngine\";\nimport { PluginRegistry } from \"./PluginRegistry\";\nimport Control from \"sap/ui/core/Control\";\nimport VBox from \"sap/m/VBox\";\nimport Text from \"sap/m/Text\";\nimport { Logger } from \"../utils/Logger\";\nimport { DefaultLayoutGenerator } from \"./DefaultLayoutGenerator\";\nimport Core from \"sap/ui/core/Core\";\nimport Messaging from \"sap/ui/core/Messaging\";\n\n/**\n * The Engine is responsible for translating a normalized schema into a physical UI5 layout.\n * It delegates layout generation to the configured `LayoutManager` and field generation to the `PluginRegistry`.\n * It strictly routes execution flow and tracks active plugins for validation.\n * It embodies the \"Plugin-First Philosophy\" by routing all complex field and layout rendering\n * through discrete, decoupled plugins rather than handling native overrides.\n * \n * @namespace nz.co.siliconst.ui5.metaui.core\n * @public\n */\nexport class Engine {\n /** Handles dynamic conditional logic across the active form. */\n private conditionEngine: ConditionEngine | null = null;\n\n /** Array of all instantiated plugins generated during the current build. */\n private activePlugins: { plugin: IPlugin, path: string }[] = [];\n\n /** Deterministic scope ID injected by the host control to prevent clone collisions. */\n public engineScopeId?: string;\n\n private activeModel?: sap.ui.model.Model;\n\n /** Reference to the GeneratorHost that instantiated this engine, for retrieving global definitions. */\n public host?: unknown;\n\n /** Callback to notify the host that an internal field changed. */\n public onChange?: (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => void;\n\n /** Tracks whether the entire engine is running in Editable mode. */\n public readonly isEditable: boolean = true;\n\n /** Tracks if any fields or sub-layouts failed to render, requiring a warning strip. */\n public hasPartialRenderingErrors: boolean = false;\n\n /** Tracks whether the engine should delegate visual state to the global MessageManager. */\n public readonly useMessageManager: boolean = false;\n\n /**\n * Initializes a new Engine instance.\n * @param editable Whether the engine should render form fields as editable or read-only.\n * @param useMessageManager Whether to delegate visual state to UI5 MessageManager.\n */\n constructor(editable: boolean = true, useMessageManager: boolean = false) {\n this.isEditable = editable;\n this.useMessageManager = useMessageManager;\n }\n\n /**\n * Bootstraps the layout generation process by resolving the correct layout strategy.\n * \n * @param schema The normalized JSON schema representing the view.\n * @param model The active StateManager JSONModel instance.\n * @param modelName The UI5 model alias used for isolation.\n * @param onSubmit Callback fired when form is submitted.\n * @param engineScopeId Deterministic scope ID for this engine instance.\n * @param onChange Callback fired when field values change.\n * @returns The generated root UI5 Control container.\n */\n public build(schema: ISchema, model: sap.ui.model.Model, modelName: string = \"meta\", onSubmit?: () => void, engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => void): Control {\n this.conditionEngine = new ConditionEngine(schema);\n this.activePlugins = [];\n this.activeModel = model;\n this.engineScopeId = engineScopeId;\n this.onChange = (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => {\n if (this.conditionEngine && fieldKey) {\n this.conditionEngine.handleEvent(fieldKey, isValid);\n }\n if (onChange) {\n onChange(isValid, fieldKey, errorMessage, controlId);\n }\n };\n\n try {\n // Intercept and synthesize a default layout if the developer/backend failed to provide one\n if (DefaultLayoutGenerator.ensureLayout(schema)) {\n Logger.warn(\"[MetaUI Engine] Missing 'uiLayout' array in schema. Synthesized a default layout mapping to prevent a blank render.\");\n }\n\n const layoutStrategy = schema.layoutStrategy || (schema.type === \"array\" ? \"table\" : \"form\");\n const layoutManager = PluginRegistry.getInstance().getLayout(layoutStrategy);\n\n return layoutManager.render(schema, modelName, this, onSubmit);\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(\"[MetaUI Engine] Critical error during layout generation\", msg);\n Logger.showErrorPopup(`Engine failed to generate the layout.\\n\\nDetails: ${msg}`);\n return new Text({ text: \"Critical Layout Error\" });\n }\n }\n\n /**\n * Instantiates the correct plugin for a specific field based on type and widget hints,\n * and tracks the plugin for global validation.\n * \n * @param fieldMeta The metadata schema specific to the field.\n * @param bindingPath The JSON path representing the field within the payload.\n * @param modelName The UI5 JSONModel name used for data binding.\n * @returns The generated UI5 Control for the field.\n */\n public generateField(fieldMeta: IPropertyMetadata, bindingPath: string, modelName: string, isTemplate: boolean = false): Control {\n try {\n const plugin = PluginRegistry.getInstance().getPlugin(fieldMeta.type || \"string\", fieldMeta.ui?.widget);\n if (typeof plugin.setEditable === \"function\") {\n plugin.setEditable(this.isEditable);\n }\n\n if (typeof plugin.setUseMessageManager === \"function\") {\n plugin.setUseMessageManager(this.useMessageManager);\n }\n\n if (!isTemplate) {\n this.activePlugins.push({ plugin, path: bindingPath });\n }\n const scopeId = isTemplate ? undefined : this.engineScopeId;\n const control = plugin.render(fieldMeta, bindingPath, modelName, scopeId, this.onChange, this.activeModel);\n\n if (this.conditionEngine) {\n this.conditionEngine.registerPlugin(bindingPath, plugin);\n }\n\n return control;\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(`[MetaUI Engine] Failed to generate field at ${bindingPath}`, msg);\n Logger.showErrorPopup(`Failed to generate field '${bindingPath}'.\\n\\nDetails: ${msg}`);\n return new Text({ text: `[Error generating field ${bindingPath}]` });\n }\n }\n\n /**\n * Generates a sub-layout (like an embedded table or nested form) without \n * destroying the current Engine state or Condition tracking.\n * \n * @param schema The normalized JSON schema representing the view.\n * @param modelName The UI5 JSONModel name used for data binding (defaults to \"meta\").\n * @param bindingPath Optional path to bind the sub-layout to a specific array/object property.\n * @returns The generated root UI5 Control container.\n */\n public generateLayout(schema: ISchema, modelName: string, bindingPath?: string): Control {\n try {\n const layoutStrategy = schema.layoutStrategy || (schema.type === \"array\" ? \"table\" : \"form\");\n const layoutManager = PluginRegistry.getInstance().getLayout(layoutStrategy);\n return layoutManager.render(schema, modelName, this, undefined, bindingPath);\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(`[MetaUI Engine] Critical error generating sub-layout for ${bindingPath}`, msg);\n Logger.showErrorPopup(`Engine failed to generate a sub-layout.\\n\\nDetails: ${msg}`);\n return new Text({ text: \"Critical Sub-Layout Error\" });\n }\n }\n\n /**\n * Iterates through all active plugins and triggers their internal validation pipelines.\n * \n * @param applyVisualState If true, explicitly instructs the plugin to natively paint its own ValueState.\n * @returns {IPluginValidationResult[]} Array of validation error objects. Empty array if valid.\n */\n public validateAll(applyVisualState: boolean = false): IPluginValidationResult[] {\n const errors: IPluginValidationResult[] = [];\n for (const item of this.activePlugins) {\n try {\n const result = item.plugin.validate();\n if (applyVisualState && typeof item.plugin.setVisualValidationState === \"function\") {\n item.plugin.setVisualValidationState(result.isValid, result.errorMessage);\n }\n\n if (!result.isValid) {\n // Ensure the path is bound to the error so GeneratorHost knows where to target it\n result.fieldKey = result.fieldKey || item.path.replace(/^\\//, \"\");\n errors.push(result);\n // Add console log to find which plugin fails silently\n Logger.error(\"[MetaUI Validation] Plugin failed validation silently:\", item.path || item.plugin.constructor.name);\n }\n } catch (error) {\n Logger.error(`[MetaUI Engine] Error validating plugin at ${item.path}`, (error as Error).message);\n }\n }\n return errors;\n }\n\n /**\n * Retrieves an active plugin instance by its absolute binding path.\n * Useful for programmatic field manipulation (e.g., custom error injection).\n * \n * @param path The binding path (e.g. \"/General/CustomerName\").\n * @returns {IPlugin | undefined} The plugin instance, or undefined if not found.\n */\n public getPluginByPath(path: string): import(\"../interfaces/IPlugin\").IPlugin | undefined {\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n const match = this.activePlugins.find(p => p.path === cleanPath || p.path === `/${cleanPath}`);\n return match ? match.plugin : undefined;\n }\n\n /**\n * Cleans up internal state and destroys the condition engine to prevent memory leaks.\n */\n public destroy(): void {\n if (this.conditionEngine) {\n this.conditionEngine.destroy();\n this.conditionEngine = null;\n }\n\n // ------------------------------------------------------------------------\n // Ghost Error Prevention\n // Flush MessageManager for active plugins before destroying their controls\n // ------------------------------------------------------------------------\n const messageManager = Messaging;\n const existingMessages = messageManager.getMessageModel().getData();\n const messagesToRemove: unknown[] = [];\n\n for (const item of this.activePlugins) {\n if (this.activeModel) {\n const targetPath = `/${item.path.replace(/^\\//, \"\")}`;\n const matched = (existingMessages as { getTarget: () => string, getMessageProcessor: () => { getId: () => string } }[]).filter(msg =>\n msg.getTarget() === targetPath && msg.getMessageProcessor() && msg.getMessageProcessor().getId() === this.activeModel!.getId()\n );\n messagesToRemove.push(...matched);\n }\n if (typeof item.plugin.destroy === \"function\") {\n item.plugin.destroy();\n }\n }\n\n if (messagesToRemove.length > 0) {\n messageManager.removeMessages(messagesToRemove);\n }\n\n this.activePlugins = [];\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"Engine-dbg.js","names":["ConditionEngine","___ConditionEngine","PluginRegistry","___PluginRegistry","Logger","___utils_Logger","DefaultLayoutGenerator","___DefaultLayoutGenerator","Engine","conditionEngine","activePlugins","isEditable","hasPartialRenderingErrors","useMessageManager","constructor","editable","pluginRegistry","getInstance","build","schema","model","modelName","onSubmit","engineScopeId","onChange","activeModel","isValid","fieldKey","errorMessage","controlId","handleEvent","ensureLayout","warn","layoutStrategy","type","layoutManager","getLayout","render","error","msg","message","showErrorPopup","Text","text","generateField","fieldMeta","bindingPath","isTemplate","plugin","getPlugin","ui","widget","setEditable","setUseMessageManager","push","path","scopeId","undefined","control","registerPlugin","generateLayout","validateAll","applyVisualState","errors","item","result","validate","setVisualValidationState","replace","name","getPluginByPath","cleanPath","startsWith","match","find","p","destroy","messageManager","Messaging","existingMessages","getMessageModel","getData","messagesToRemove","targetPath","matched","filter","getTarget","getMessageProcessor","getId","length","removeMessages","__exports","__esModule"],"sources":["Engine.ts"],"sourcesContent":["/**\n * @file Engine.ts\n * @description The central orchestrator that routes data between the Layout Factory and Plugin Registry (v2).\n */\n\nimport { ISchema, IPropertyMetadata } from \"../interfaces/ISchema\";\nimport { ILayoutManager } from \"../interfaces/ILayoutManager\";\nimport { IPlugin, IPluginValidationResult } from \"../interfaces/IPlugin\";\nimport { ConditionEngine } from \"./ConditionEngine\";\nimport { PluginRegistry } from \"./PluginRegistry\";\nimport Control from \"sap/ui/core/Control\";\nimport VBox from \"sap/m/VBox\";\nimport Text from \"sap/m/Text\";\nimport { Logger } from \"../utils/Logger\";\nimport { DefaultLayoutGenerator } from \"./DefaultLayoutGenerator\";\nimport Core from \"sap/ui/core/Core\";\nimport Messaging from \"sap/ui/core/Messaging\";\n\n/**\n * The Engine is responsible for translating a normalized schema into a physical UI5 layout.\n * It delegates layout generation to the configured `LayoutManager` and field generation to the `PluginRegistry`.\n * It strictly routes execution flow and tracks active plugins for validation.\n * It embodies the \"Plugin-First Philosophy\" by routing all complex field and layout rendering\n * through discrete, decoupled plugins rather than handling native overrides.\n * \n * @namespace nz.co.siliconst.ui5.metaui.core\n * @public\n */\nexport class Engine {\n /** Handles dynamic conditional logic across the active form. */\n private conditionEngine: ConditionEngine | null = null;\n\n /** Array of all instantiated plugins generated during the current build. */\n private activePlugins: { plugin: IPlugin, path: string }[] = [];\n\n /** Deterministic scope ID injected by the host control to prevent clone collisions. */\n public engineScopeId?: string;\n\n private activeModel?: sap.ui.model.Model;\n\n /** Reference to the GeneratorHost that instantiated this engine, for retrieving global definitions. */\n public host?: unknown;\n\n /** Callback to notify the host that an internal field changed. */\n public onChange?: (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => void;\n\n /** Tracks whether the entire engine is running in Editable mode. */\n public readonly isEditable: boolean = true;\n\n /** Tracks if any fields or sub-layouts failed to render, requiring a warning strip. */\n public hasPartialRenderingErrors: boolean = false;\n\n /** Tracks whether the engine should delegate visual state to the global MessageManager. */\n public readonly useMessageManager: boolean = false;\n\n /** The injected PluginRegistry instance */\n public readonly pluginRegistry: PluginRegistry;\n\n /**\n * Initializes a new Engine instance.\n * @param editable Whether the engine should render form fields as editable or read-only.\n * @param useMessageManager Whether to delegate visual state to UI5 MessageManager.\n * @param pluginRegistry Optional injected plugin registry. Defaults to singleton.\n */\n constructor(editable: boolean = true, useMessageManager: boolean = false, pluginRegistry?: PluginRegistry) {\n this.isEditable = editable;\n this.useMessageManager = useMessageManager;\n this.pluginRegistry = pluginRegistry || PluginRegistry.getInstance();\n }\n\n /**\n * Bootstraps the layout generation process by resolving the correct layout strategy.\n * \n * @param schema The normalized JSON schema representing the view.\n * @param model The active StateManager JSONModel instance.\n * @param modelName The UI5 model alias used for isolation.\n * @param onSubmit Callback fired when form is submitted.\n * @param engineScopeId Deterministic scope ID for this engine instance.\n * @param onChange Callback fired when field values change.\n * @returns The generated root UI5 Control container.\n */\n public build(schema: ISchema, model: sap.ui.model.Model, modelName: string = \"meta\", onSubmit?: () => void, engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => void): Control {\n this.conditionEngine = new ConditionEngine(schema);\n this.activePlugins = [];\n this.activeModel = model;\n this.engineScopeId = engineScopeId;\n this.onChange = (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => {\n if (this.conditionEngine && fieldKey) {\n this.conditionEngine.handleEvent(fieldKey, isValid);\n }\n if (onChange) {\n onChange(isValid, fieldKey, errorMessage, controlId);\n }\n };\n\n try {\n // Intercept and synthesize a default layout if the developer/backend failed to provide one\n if (DefaultLayoutGenerator.ensureLayout(schema)) {\n Logger.warn(\"[MetaUI Engine] Missing 'uiLayout' array in schema. Synthesized a default layout mapping to prevent a blank render.\");\n }\n\n const layoutStrategy = schema.layoutStrategy || (schema.type === \"array\" ? \"table\" : \"form\");\n const layoutManager = this.pluginRegistry.getLayout(layoutStrategy);\n\n return layoutManager.render(schema, modelName, this, onSubmit);\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(\"[MetaUI Engine] Critical error during layout generation\", msg);\n Logger.showErrorPopup(`Engine failed to generate the layout.\\n\\nDetails: ${msg}`);\n return new Text({ text: \"Critical Layout Error\" });\n }\n }\n\n /**\n * Instantiates the correct plugin for a specific field based on type and widget hints,\n * and tracks the plugin for global validation.\n * \n * @param fieldMeta The metadata schema specific to the field.\n * @param bindingPath The JSON path representing the field within the payload.\n * @param modelName The UI5 JSONModel name used for data binding.\n * @returns The generated UI5 Control for the field.\n */\n public generateField(fieldMeta: IPropertyMetadata, bindingPath: string, modelName: string, isTemplate: boolean = false): Control {\n try {\n const plugin = this.pluginRegistry.getPlugin(fieldMeta.type || \"string\", fieldMeta.ui?.widget);\n if (typeof plugin.setEditable === \"function\") {\n plugin.setEditable(this.isEditable);\n }\n\n if (typeof plugin.setUseMessageManager === \"function\") {\n plugin.setUseMessageManager(this.useMessageManager);\n }\n\n if (!isTemplate) {\n this.activePlugins.push({ plugin, path: bindingPath });\n }\n const scopeId = isTemplate ? undefined : this.engineScopeId;\n const control = plugin.render(fieldMeta, bindingPath, modelName, scopeId, this.onChange, this.activeModel);\n\n if (this.conditionEngine) {\n this.conditionEngine.registerPlugin(bindingPath, plugin);\n }\n\n return control;\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(`[MetaUI Engine] Failed to generate field at ${bindingPath}`, msg);\n Logger.showErrorPopup(`Failed to generate field '${bindingPath}'.\\n\\nDetails: ${msg}`);\n return new Text({ text: `[Error generating field ${bindingPath}]` });\n }\n }\n\n /**\n * Generates a sub-layout (like an embedded table or nested form) without \n * destroying the current Engine state or Condition tracking.\n * \n * @param schema The normalized JSON schema representing the view.\n * @param modelName The UI5 JSONModel name used for data binding (defaults to \"meta\").\n * @param bindingPath Optional path to bind the sub-layout to a specific array/object property.\n * @returns The generated root UI5 Control container.\n */\n public generateLayout(schema: ISchema, modelName: string, bindingPath?: string): Control {\n try {\n const layoutStrategy = schema.layoutStrategy || (schema.type === \"array\" ? \"table\" : \"form\");\n const layoutManager = this.pluginRegistry.getLayout(layoutStrategy);\n return layoutManager.render(schema, modelName, this, undefined, bindingPath);\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(`[MetaUI Engine] Critical error generating sub-layout for ${bindingPath}`, msg);\n Logger.showErrorPopup(`Engine failed to generate a sub-layout.\\n\\nDetails: ${msg}`);\n return new Text({ text: \"Critical Sub-Layout Error\" });\n }\n }\n\n /**\n * Iterates through all active plugins and triggers their internal validation pipelines.\n * \n * @param applyVisualState If true, explicitly instructs the plugin to natively paint its own ValueState.\n * @returns {IPluginValidationResult[]} Array of validation error objects. Empty array if valid.\n */\n public validateAll(applyVisualState: boolean = false): IPluginValidationResult[] {\n const errors: IPluginValidationResult[] = [];\n for (const item of this.activePlugins) {\n try {\n const result = item.plugin.validate();\n if (applyVisualState && typeof item.plugin.setVisualValidationState === \"function\") {\n item.plugin.setVisualValidationState(result.isValid, result.errorMessage);\n }\n\n if (!result.isValid) {\n // Ensure the path is bound to the error so GeneratorHost knows where to target it\n result.fieldKey = result.fieldKey || item.path.replace(/^\\//, \"\");\n errors.push(result);\n // Add console log to find which plugin fails silently\n Logger.error(\"[MetaUI Validation] Plugin failed validation silently:\", item.path || item.plugin.constructor.name);\n }\n } catch (error) {\n Logger.error(`[MetaUI Engine] Error validating plugin at ${item.path}`, (error as Error).message);\n }\n }\n return errors;\n }\n\n /**\n * Retrieves an active plugin instance by its absolute binding path.\n * Useful for programmatic field manipulation (e.g., custom error injection).\n * \n * @param path The binding path (e.g. \"/General/CustomerName\").\n * @returns {IPlugin | undefined} The plugin instance, or undefined if not found.\n */\n public getPluginByPath(path: string): import(\"../interfaces/IPlugin\").IPlugin | undefined {\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n const match = this.activePlugins.find(p => p.path === cleanPath || p.path === `/${cleanPath}`);\n return match ? match.plugin : undefined;\n }\n\n /**\n * Cleans up internal state and destroys the condition engine to prevent memory leaks.\n */\n public destroy(): void {\n if (this.conditionEngine) {\n this.conditionEngine.destroy();\n this.conditionEngine = null;\n }\n\n // ------------------------------------------------------------------------\n // Ghost Error Prevention\n // Flush MessageManager for active plugins before destroying their controls\n // ------------------------------------------------------------------------\n const messageManager = Messaging;\n const existingMessages = messageManager.getMessageModel().getData();\n const messagesToRemove: unknown[] = [];\n\n for (const item of this.activePlugins) {\n if (this.activeModel) {\n const targetPath = `/${item.path.replace(/^\\//, \"\")}`;\n const matched = (existingMessages as { getTarget: () => string, getMessageProcessor: () => { getId: () => string } }[]).filter(msg =>\n msg.getTarget() === targetPath && msg.getMessageProcessor() && msg.getMessageProcessor().getId() === this.activeModel!.getId()\n );\n messagesToRemove.push(...matched);\n }\n if (typeof item.plugin.destroy === \"function\") {\n item.plugin.destroy();\n }\n }\n\n if (messagesToRemove.length > 0) {\n messageManager.removeMessages(messagesToRemove);\n }\n\n this.activePlugins = [];\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -5,6 +5,7 @@ declare module "nz/co/siliconst/ui5/metaui/core/Engine" {
5
5
  */
6
6
  import { ISchema, IPropertyMetadata } from "nz/co/siliconst/ui5/metaui/interfaces/ISchema";
7
7
  import { IPluginValidationResult } from "nz/co/siliconst/ui5/metaui/interfaces/IPlugin";
8
+ import { PluginRegistry } from "nz/co/siliconst/ui5/metaui/core/PluginRegistry";
8
9
  import Control from "sap/ui/core/Control";
9
10
  /**
10
11
  * The Engine is responsible for translating a normalized schema into a physical UI5 layout.
@@ -34,12 +35,15 @@ declare module "nz/co/siliconst/ui5/metaui/core/Engine" {
34
35
  hasPartialRenderingErrors: boolean;
35
36
  /** Tracks whether the engine should delegate visual state to the global MessageManager. */
36
37
  readonly useMessageManager: boolean;
38
+ /** The injected PluginRegistry instance */
39
+ readonly pluginRegistry: PluginRegistry;
37
40
  /**
38
41
  * Initializes a new Engine instance.
39
42
  * @param editable Whether the engine should render form fields as editable or read-only.
40
43
  * @param useMessageManager Whether to delegate visual state to UI5 MessageManager.
44
+ * @param pluginRegistry Optional injected plugin registry. Defaults to singleton.
41
45
  */
42
- constructor(editable?: boolean, useMessageManager?: boolean);
46
+ constructor(editable?: boolean, useMessageManager?: boolean, pluginRegistry?: PluginRegistry);
43
47
  /**
44
48
  * Bootstraps the layout generation process by resolving the correct layout strategy.
45
49
  *
@@ -1 +1 @@
1
- {"version":3,"file":"Engine.d.ts","sourceRoot":"../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/core/Engine.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,wCAAwC,CAAC;IACxD;;;OAGG;IAEH,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;IAE3F,OAAO,EAAW,uBAAuB,EAAE,MAAM,+CAA+C,CAAC;IAGjG,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAQ1C;;;;;;;;;OASG;IACH,MAAa,MAAM;QACf,gEAAgE;QAChE,OAAO,CAAC,eAAe,CAAgC;QAEvD,4EAA4E;QAC5E,OAAO,CAAC,aAAa,CAA2C;QAEhE,uFAAuF;QAChF,aAAa,CAAC,EAAE,MAAM,CAAC;QAE9B,OAAO,CAAC,WAAW,CAAC,CAAqB;QAEzC,uGAAuG;QAChG,IAAI,CAAC,EAAE,OAAO,CAAC;QAEtB,kEAAkE;QAC3D,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;QAE3G,oEAAoE;QACpE,SAAgB,UAAU,EAAE,OAAO,CAAQ;QAE3C,uFAAuF;QAChF,yBAAyB,EAAE,OAAO,CAAS;QAElD,2FAA2F;QAC3F,SAAgB,iBAAiB,EAAE,OAAO,CAAS;QAEnD;;;;WAIG;oBACS,QAAQ,GAAE,OAAc,EAAE,iBAAiB,GAAE,OAAe;QAKxE;;;;;;;;;;WAUG;QACI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,GAAE,MAAe,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;QAiCjP;;;;;;;;WAQG;QACI,aAAa,CAAC,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,OAAe,GAAG,OAAO;QA+BhI;;;;;;;;WAQG;QACI,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO;QAcxF;;;;;WAKG;QACI,WAAW,CAAC,gBAAgB,GAAE,OAAe,GAAG,uBAAuB,EAAE;QAuBhF;;;;;;WAMG;QACI,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,+CAA+C,EAAE,OAAO,GAAG,SAAS;QAMjH;;WAEG;QACI,OAAO,IAAI,IAAI;KAiCzB;CAEA"}
1
+ {"version":3,"file":"Engine.d.ts","sourceRoot":"../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/core/Engine.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,wCAAwC,CAAC;IACxD;;;OAGG;IAEH,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;IAE3F,OAAO,EAAW,uBAAuB,EAAE,MAAM,+CAA+C,CAAC;IAEjG,OAAO,EAAE,cAAc,EAAE,MAAM,gDAAgD,CAAC;IAChF,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAQ1C;;;;;;;;;OASG;IACH,MAAa,MAAM;QACf,gEAAgE;QAChE,OAAO,CAAC,eAAe,CAAgC;QAEvD,4EAA4E;QAC5E,OAAO,CAAC,aAAa,CAA2C;QAEhE,uFAAuF;QAChF,aAAa,CAAC,EAAE,MAAM,CAAC;QAE9B,OAAO,CAAC,WAAW,CAAC,CAAqB;QAEzC,uGAAuG;QAChG,IAAI,CAAC,EAAE,OAAO,CAAC;QAEtB,kEAAkE;QAC3D,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;QAE3G,oEAAoE;QACpE,SAAgB,UAAU,EAAE,OAAO,CAAQ;QAE3C,uFAAuF;QAChF,yBAAyB,EAAE,OAAO,CAAS;QAElD,2FAA2F;QAC3F,SAAgB,iBAAiB,EAAE,OAAO,CAAS;QAEnD,2CAA2C;QAC3C,SAAgB,cAAc,EAAE,cAAc,CAAC;QAE/C;;;;;WAKG;oBACS,QAAQ,GAAE,OAAc,EAAE,iBAAiB,GAAE,OAAe,EAAE,cAAc,CAAC,EAAE,cAAc;QAMzG;;;;;;;;;;WAUG;QACI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,GAAE,MAAe,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;QAiCjP;;;;;;;;WAQG;QACI,aAAa,CAAC,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,OAAe,GAAG,OAAO;QA+BhI;;;;;;;;WAQG;QACI,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO;QAcxF;;;;;WAKG;QACI,WAAW,CAAC,gBAAgB,GAAE,OAAe,GAAG,uBAAuB,EAAE;QAuBhF;;;;;;WAMG;QACI,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,+CAA+C,EAAE,OAAO,GAAG,SAAS;QAMjH;;WAEG;QACI,OAAO,IAAI,IAAI;KAiCzB;CAEA"}
@@ -1,2 +1,2 @@
1
- sap.ui.define(["./ConditionEngine","./PluginRegistry","sap/m/Text","../utils/Logger","./DefaultLayoutGenerator","sap/ui/core/Messaging"],function(e,t,n,i,a,s){"use strict";const r=e["ConditionEngine"];const o=t["PluginRegistry"];const g=i["Logger"];const l=a["DefaultLayoutGenerator"];class u{conditionEngine=null;activePlugins=[];isEditable=true;hasPartialRenderingErrors=false;useMessageManager=false;constructor(e=true,t=false){this.isEditable=e;this.useMessageManager=t}build(e,t,i="meta",a,s,u){this.conditionEngine=new r(e);this.activePlugins=[];this.activeModel=t;this.engineScopeId=s;this.onChange=(e,t,n,i)=>{if(this.conditionEngine&&t){this.conditionEngine.handleEvent(t,e)}if(u){u(e,t,n,i)}};try{if(l.ensureLayout(e)){g.warn("[MetaUI Engine] Missing 'uiLayout' array in schema. Synthesized a default layout mapping to prevent a blank render.")}const t=e.layoutStrategy||(e.type==="array"?"table":"form");const n=o.getInstance().getLayout(t);return n.render(e,i,this,a)}catch(e){this.hasPartialRenderingErrors=true;const t=e.message;g.error("[MetaUI Engine] Critical error during layout generation",t);g.showErrorPopup(`Engine failed to generate the layout.\n\nDetails: ${t}`);return new n({text:"Critical Layout Error"})}}generateField(e,t,i,a=false){try{const n=o.getInstance().getPlugin(e.type||"string",e.ui?.widget);if(typeof n.setEditable==="function"){n.setEditable(this.isEditable)}if(typeof n.setUseMessageManager==="function"){n.setUseMessageManager(this.useMessageManager)}if(!a){this.activePlugins.push({plugin:n,path:t})}const s=a?undefined:this.engineScopeId;const r=n.render(e,t,i,s,this.onChange,this.activeModel);if(this.conditionEngine){this.conditionEngine.registerPlugin(t,n)}return r}catch(e){this.hasPartialRenderingErrors=true;const i=e.message;g.error(`[MetaUI Engine] Failed to generate field at ${t}`,i);g.showErrorPopup(`Failed to generate field '${t}'.\n\nDetails: ${i}`);return new n({text:`[Error generating field ${t}]`})}}generateLayout(e,t,i){try{const n=e.layoutStrategy||(e.type==="array"?"table":"form");const a=o.getInstance().getLayout(n);return a.render(e,t,this,undefined,i)}catch(e){this.hasPartialRenderingErrors=true;const t=e.message;g.error(`[MetaUI Engine] Critical error generating sub-layout for ${i}`,t);g.showErrorPopup(`Engine failed to generate a sub-layout.\n\nDetails: ${t}`);return new n({text:"Critical Sub-Layout Error"})}}validateAll(e=false){const t=[];for(const n of this.activePlugins){try{const i=n.plugin.validate();if(e&&typeof n.plugin.setVisualValidationState==="function"){n.plugin.setVisualValidationState(i.isValid,i.errorMessage)}if(!i.isValid){i.fieldKey=i.fieldKey||n.path.replace(/^\//,"");t.push(i);g.error("[MetaUI Validation] Plugin failed validation silently:",n.path||n.plugin.constructor.name)}}catch(e){g.error(`[MetaUI Engine] Error validating plugin at ${n.path}`,e.message)}}return t}getPluginByPath(e){const t=e.startsWith("/")?e:`/${e}`;const n=this.activePlugins.find(e=>e.path===t||e.path===`/${t}`);return n?n.plugin:undefined}destroy(){if(this.conditionEngine){this.conditionEngine.destroy();this.conditionEngine=null}const e=s;const t=e.getMessageModel().getData();const n=[];for(const e of this.activePlugins){if(this.activeModel){const i=`/${e.path.replace(/^\//,"")}`;const a=t.filter(e=>e.getTarget()===i&&e.getMessageProcessor()&&e.getMessageProcessor().getId()===this.activeModel.getId());n.push(...a)}if(typeof e.plugin.destroy==="function"){e.plugin.destroy()}}if(n.length>0){e.removeMessages(n)}this.activePlugins=[]}}var c={__esModule:true};c.Engine=u;return c});
1
+ sap.ui.define(["./ConditionEngine","./PluginRegistry","sap/m/Text","../utils/Logger","./DefaultLayoutGenerator","sap/ui/core/Messaging"],function(e,t,i,n,s,a){"use strict";const r=e["ConditionEngine"];const o=t["PluginRegistry"];const g=n["Logger"];const l=s["DefaultLayoutGenerator"];class u{conditionEngine=null;activePlugins=[];isEditable=true;hasPartialRenderingErrors=false;useMessageManager=false;constructor(e=true,t=false,i){this.isEditable=e;this.useMessageManager=t;this.pluginRegistry=i||o.getInstance()}build(e,t,n="meta",s,a,o){this.conditionEngine=new r(e);this.activePlugins=[];this.activeModel=t;this.engineScopeId=a;this.onChange=(e,t,i,n)=>{if(this.conditionEngine&&t){this.conditionEngine.handleEvent(t,e)}if(o){o(e,t,i,n)}};try{if(l.ensureLayout(e)){g.warn("[MetaUI Engine] Missing 'uiLayout' array in schema. Synthesized a default layout mapping to prevent a blank render.")}const t=e.layoutStrategy||(e.type==="array"?"table":"form");const i=this.pluginRegistry.getLayout(t);return i.render(e,n,this,s)}catch(e){this.hasPartialRenderingErrors=true;const t=e.message;g.error("[MetaUI Engine] Critical error during layout generation",t);g.showErrorPopup(`Engine failed to generate the layout.\n\nDetails: ${t}`);return new i({text:"Critical Layout Error"})}}generateField(e,t,n,s=false){try{const i=this.pluginRegistry.getPlugin(e.type||"string",e.ui?.widget);if(typeof i.setEditable==="function"){i.setEditable(this.isEditable)}if(typeof i.setUseMessageManager==="function"){i.setUseMessageManager(this.useMessageManager)}if(!s){this.activePlugins.push({plugin:i,path:t})}const a=s?undefined:this.engineScopeId;const r=i.render(e,t,n,a,this.onChange,this.activeModel);if(this.conditionEngine){this.conditionEngine.registerPlugin(t,i)}return r}catch(e){this.hasPartialRenderingErrors=true;const n=e.message;g.error(`[MetaUI Engine] Failed to generate field at ${t}`,n);g.showErrorPopup(`Failed to generate field '${t}'.\n\nDetails: ${n}`);return new i({text:`[Error generating field ${t}]`})}}generateLayout(e,t,n){try{const i=e.layoutStrategy||(e.type==="array"?"table":"form");const s=this.pluginRegistry.getLayout(i);return s.render(e,t,this,undefined,n)}catch(e){this.hasPartialRenderingErrors=true;const t=e.message;g.error(`[MetaUI Engine] Critical error generating sub-layout for ${n}`,t);g.showErrorPopup(`Engine failed to generate a sub-layout.\n\nDetails: ${t}`);return new i({text:"Critical Sub-Layout Error"})}}validateAll(e=false){const t=[];for(const i of this.activePlugins){try{const n=i.plugin.validate();if(e&&typeof i.plugin.setVisualValidationState==="function"){i.plugin.setVisualValidationState(n.isValid,n.errorMessage)}if(!n.isValid){n.fieldKey=n.fieldKey||i.path.replace(/^\//,"");t.push(n);g.error("[MetaUI Validation] Plugin failed validation silently:",i.path||i.plugin.constructor.name)}}catch(e){g.error(`[MetaUI Engine] Error validating plugin at ${i.path}`,e.message)}}return t}getPluginByPath(e){const t=e.startsWith("/")?e:`/${e}`;const i=this.activePlugins.find(e=>e.path===t||e.path===`/${t}`);return i?i.plugin:undefined}destroy(){if(this.conditionEngine){this.conditionEngine.destroy();this.conditionEngine=null}const e=a;const t=e.getMessageModel().getData();const i=[];for(const e of this.activePlugins){if(this.activeModel){const n=`/${e.path.replace(/^\//,"")}`;const s=t.filter(e=>e.getTarget()===n&&e.getMessageProcessor()&&e.getMessageProcessor().getId()===this.activeModel.getId());i.push(...s)}if(typeof e.plugin.destroy==="function"){e.plugin.destroy()}}if(i.length>0){e.removeMessages(i)}this.activePlugins=[]}}var c={__esModule:true};c.Engine=u;return c});
2
2
  //# sourceMappingURL=Engine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Engine.js","names":["ConditionEngine","___ConditionEngine","PluginRegistry","___PluginRegistry","Logger","___utils_Logger","DefaultLayoutGenerator","___DefaultLayoutGenerator","Engine","conditionEngine","activePlugins","isEditable","hasPartialRenderingErrors","useMessageManager","constructor","editable","this","build","schema","model","modelName","onSubmit","engineScopeId","onChange","activeModel","isValid","fieldKey","errorMessage","controlId","handleEvent","ensureLayout","warn","layoutStrategy","type","layoutManager","getInstance","getLayout","render","error","msg","message","showErrorPopup","Text","text","generateField","fieldMeta","bindingPath","isTemplate","plugin","getPlugin","ui","widget","setEditable","setUseMessageManager","push","path","scopeId","undefined","control","registerPlugin","generateLayout","validateAll","applyVisualState","errors","item","result","validate","setVisualValidationState","replace","name","getPluginByPath","cleanPath","startsWith","match","find","p","destroy","messageManager","Messaging","existingMessages","getMessageModel","getData","messagesToRemove","targetPath","matched","filter","getTarget","getMessageProcessor","getId","length","removeMessages","__exports","__esModule"],"sources":["Engine.ts"],"sourcesContent":["/**\n * @file Engine.ts\n * @description The central orchestrator that routes data between the Layout Factory and Plugin Registry (v2).\n */\n\nimport { ISchema, IPropertyMetadata } from \"../interfaces/ISchema\";\nimport { ILayoutManager } from \"../interfaces/ILayoutManager\";\nimport { IPlugin, IPluginValidationResult } from \"../interfaces/IPlugin\";\nimport { ConditionEngine } from \"./ConditionEngine\";\nimport { PluginRegistry } from \"./PluginRegistry\";\nimport Control from \"sap/ui/core/Control\";\nimport VBox from \"sap/m/VBox\";\nimport Text from \"sap/m/Text\";\nimport { Logger } from \"../utils/Logger\";\nimport { DefaultLayoutGenerator } from \"./DefaultLayoutGenerator\";\nimport Core from \"sap/ui/core/Core\";\nimport Messaging from \"sap/ui/core/Messaging\";\n\n/**\n * The Engine is responsible for translating a normalized schema into a physical UI5 layout.\n * It delegates layout generation to the configured `LayoutManager` and field generation to the `PluginRegistry`.\n * It strictly routes execution flow and tracks active plugins for validation.\n * It embodies the \"Plugin-First Philosophy\" by routing all complex field and layout rendering\n * through discrete, decoupled plugins rather than handling native overrides.\n * \n * @namespace nz.co.siliconst.ui5.metaui.core\n * @public\n */\nexport class Engine {\n /** Handles dynamic conditional logic across the active form. */\n private conditionEngine: ConditionEngine | null = null;\n\n /** Array of all instantiated plugins generated during the current build. */\n private activePlugins: { plugin: IPlugin, path: string }[] = [];\n\n /** Deterministic scope ID injected by the host control to prevent clone collisions. */\n public engineScopeId?: string;\n\n private activeModel?: sap.ui.model.Model;\n\n /** Reference to the GeneratorHost that instantiated this engine, for retrieving global definitions. */\n public host?: unknown;\n\n /** Callback to notify the host that an internal field changed. */\n public onChange?: (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => void;\n\n /** Tracks whether the entire engine is running in Editable mode. */\n public readonly isEditable: boolean = true;\n\n /** Tracks if any fields or sub-layouts failed to render, requiring a warning strip. */\n public hasPartialRenderingErrors: boolean = false;\n\n /** Tracks whether the engine should delegate visual state to the global MessageManager. */\n public readonly useMessageManager: boolean = false;\n\n /**\n * Initializes a new Engine instance.\n * @param editable Whether the engine should render form fields as editable or read-only.\n * @param useMessageManager Whether to delegate visual state to UI5 MessageManager.\n */\n constructor(editable: boolean = true, useMessageManager: boolean = false) {\n this.isEditable = editable;\n this.useMessageManager = useMessageManager;\n }\n\n /**\n * Bootstraps the layout generation process by resolving the correct layout strategy.\n * \n * @param schema The normalized JSON schema representing the view.\n * @param model The active StateManager JSONModel instance.\n * @param modelName The UI5 model alias used for isolation.\n * @param onSubmit Callback fired when form is submitted.\n * @param engineScopeId Deterministic scope ID for this engine instance.\n * @param onChange Callback fired when field values change.\n * @returns The generated root UI5 Control container.\n */\n public build(schema: ISchema, model: sap.ui.model.Model, modelName: string = \"meta\", onSubmit?: () => void, engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => void): Control {\n this.conditionEngine = new ConditionEngine(schema);\n this.activePlugins = [];\n this.activeModel = model;\n this.engineScopeId = engineScopeId;\n this.onChange = (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => {\n if (this.conditionEngine && fieldKey) {\n this.conditionEngine.handleEvent(fieldKey, isValid);\n }\n if (onChange) {\n onChange(isValid, fieldKey, errorMessage, controlId);\n }\n };\n\n try {\n // Intercept and synthesize a default layout if the developer/backend failed to provide one\n if (DefaultLayoutGenerator.ensureLayout(schema)) {\n Logger.warn(\"[MetaUI Engine] Missing 'uiLayout' array in schema. Synthesized a default layout mapping to prevent a blank render.\");\n }\n\n const layoutStrategy = schema.layoutStrategy || (schema.type === \"array\" ? \"table\" : \"form\");\n const layoutManager = PluginRegistry.getInstance().getLayout(layoutStrategy);\n\n return layoutManager.render(schema, modelName, this, onSubmit);\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(\"[MetaUI Engine] Critical error during layout generation\", msg);\n Logger.showErrorPopup(`Engine failed to generate the layout.\\n\\nDetails: ${msg}`);\n return new Text({ text: \"Critical Layout Error\" });\n }\n }\n\n /**\n * Instantiates the correct plugin for a specific field based on type and widget hints,\n * and tracks the plugin for global validation.\n * \n * @param fieldMeta The metadata schema specific to the field.\n * @param bindingPath The JSON path representing the field within the payload.\n * @param modelName The UI5 JSONModel name used for data binding.\n * @returns The generated UI5 Control for the field.\n */\n public generateField(fieldMeta: IPropertyMetadata, bindingPath: string, modelName: string, isTemplate: boolean = false): Control {\n try {\n const plugin = PluginRegistry.getInstance().getPlugin(fieldMeta.type || \"string\", fieldMeta.ui?.widget);\n if (typeof plugin.setEditable === \"function\") {\n plugin.setEditable(this.isEditable);\n }\n\n if (typeof plugin.setUseMessageManager === \"function\") {\n plugin.setUseMessageManager(this.useMessageManager);\n }\n\n if (!isTemplate) {\n this.activePlugins.push({ plugin, path: bindingPath });\n }\n const scopeId = isTemplate ? undefined : this.engineScopeId;\n const control = plugin.render(fieldMeta, bindingPath, modelName, scopeId, this.onChange, this.activeModel);\n\n if (this.conditionEngine) {\n this.conditionEngine.registerPlugin(bindingPath, plugin);\n }\n\n return control;\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(`[MetaUI Engine] Failed to generate field at ${bindingPath}`, msg);\n Logger.showErrorPopup(`Failed to generate field '${bindingPath}'.\\n\\nDetails: ${msg}`);\n return new Text({ text: `[Error generating field ${bindingPath}]` });\n }\n }\n\n /**\n * Generates a sub-layout (like an embedded table or nested form) without \n * destroying the current Engine state or Condition tracking.\n * \n * @param schema The normalized JSON schema representing the view.\n * @param modelName The UI5 JSONModel name used for data binding (defaults to \"meta\").\n * @param bindingPath Optional path to bind the sub-layout to a specific array/object property.\n * @returns The generated root UI5 Control container.\n */\n public generateLayout(schema: ISchema, modelName: string, bindingPath?: string): Control {\n try {\n const layoutStrategy = schema.layoutStrategy || (schema.type === \"array\" ? \"table\" : \"form\");\n const layoutManager = PluginRegistry.getInstance().getLayout(layoutStrategy);\n return layoutManager.render(schema, modelName, this, undefined, bindingPath);\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(`[MetaUI Engine] Critical error generating sub-layout for ${bindingPath}`, msg);\n Logger.showErrorPopup(`Engine failed to generate a sub-layout.\\n\\nDetails: ${msg}`);\n return new Text({ text: \"Critical Sub-Layout Error\" });\n }\n }\n\n /**\n * Iterates through all active plugins and triggers their internal validation pipelines.\n * \n * @param applyVisualState If true, explicitly instructs the plugin to natively paint its own ValueState.\n * @returns {IPluginValidationResult[]} Array of validation error objects. Empty array if valid.\n */\n public validateAll(applyVisualState: boolean = false): IPluginValidationResult[] {\n const errors: IPluginValidationResult[] = [];\n for (const item of this.activePlugins) {\n try {\n const result = item.plugin.validate();\n if (applyVisualState && typeof item.plugin.setVisualValidationState === \"function\") {\n item.plugin.setVisualValidationState(result.isValid, result.errorMessage);\n }\n\n if (!result.isValid) {\n // Ensure the path is bound to the error so GeneratorHost knows where to target it\n result.fieldKey = result.fieldKey || item.path.replace(/^\\//, \"\");\n errors.push(result);\n // Add console log to find which plugin fails silently\n Logger.error(\"[MetaUI Validation] Plugin failed validation silently:\", item.path || item.plugin.constructor.name);\n }\n } catch (error) {\n Logger.error(`[MetaUI Engine] Error validating plugin at ${item.path}`, (error as Error).message);\n }\n }\n return errors;\n }\n\n /**\n * Retrieves an active plugin instance by its absolute binding path.\n * Useful for programmatic field manipulation (e.g., custom error injection).\n * \n * @param path The binding path (e.g. \"/General/CustomerName\").\n * @returns {IPlugin | undefined} The plugin instance, or undefined if not found.\n */\n public getPluginByPath(path: string): import(\"../interfaces/IPlugin\").IPlugin | undefined {\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n const match = this.activePlugins.find(p => p.path === cleanPath || p.path === `/${cleanPath}`);\n return match ? match.plugin : undefined;\n }\n\n /**\n * Cleans up internal state and destroys the condition engine to prevent memory leaks.\n */\n public destroy(): void {\n if (this.conditionEngine) {\n this.conditionEngine.destroy();\n this.conditionEngine = null;\n }\n\n // ------------------------------------------------------------------------\n // Ghost Error Prevention\n // Flush MessageManager for active plugins before destroying their controls\n // ------------------------------------------------------------------------\n const messageManager = Messaging;\n const existingMessages = messageManager.getMessageModel().getData();\n const messagesToRemove: unknown[] = [];\n\n for (const item of this.activePlugins) {\n if (this.activeModel) {\n const targetPath = `/${item.path.replace(/^\\//, \"\")}`;\n const matched = (existingMessages as { getTarget: () => string, getMessageProcessor: () => { getId: () => string } }[]).filter(msg =>\n msg.getTarget() === targetPath && msg.getMessageProcessor() && msg.getMessageProcessor().getId() === this.activeModel!.getId()\n );\n messagesToRemove.push(...matched);\n }\n if (typeof item.plugin.destroy === \"function\") {\n item.plugin.destroy();\n }\n }\n\n if (messagesToRemove.length > 0) {\n messageManager.removeMessages(messagesToRemove);\n }\n\n this.activePlugins = [];\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"Engine.js","names":["ConditionEngine","___ConditionEngine","PluginRegistry","___PluginRegistry","Logger","___utils_Logger","DefaultLayoutGenerator","___DefaultLayoutGenerator","Engine","conditionEngine","activePlugins","isEditable","hasPartialRenderingErrors","useMessageManager","constructor","editable","pluginRegistry","this","getInstance","build","schema","model","modelName","onSubmit","engineScopeId","onChange","activeModel","isValid","fieldKey","errorMessage","controlId","handleEvent","ensureLayout","warn","layoutStrategy","type","layoutManager","getLayout","render","error","msg","message","showErrorPopup","Text","text","generateField","fieldMeta","bindingPath","isTemplate","plugin","getPlugin","ui","widget","setEditable","setUseMessageManager","push","path","scopeId","undefined","control","registerPlugin","generateLayout","validateAll","applyVisualState","errors","item","result","validate","setVisualValidationState","replace","name","getPluginByPath","cleanPath","startsWith","match","find","p","destroy","messageManager","Messaging","existingMessages","getMessageModel","getData","messagesToRemove","targetPath","matched","filter","getTarget","getMessageProcessor","getId","length","removeMessages","__exports","__esModule"],"sources":["Engine.ts"],"sourcesContent":["/**\n * @file Engine.ts\n * @description The central orchestrator that routes data between the Layout Factory and Plugin Registry (v2).\n */\n\nimport { ISchema, IPropertyMetadata } from \"../interfaces/ISchema\";\nimport { ILayoutManager } from \"../interfaces/ILayoutManager\";\nimport { IPlugin, IPluginValidationResult } from \"../interfaces/IPlugin\";\nimport { ConditionEngine } from \"./ConditionEngine\";\nimport { PluginRegistry } from \"./PluginRegistry\";\nimport Control from \"sap/ui/core/Control\";\nimport VBox from \"sap/m/VBox\";\nimport Text from \"sap/m/Text\";\nimport { Logger } from \"../utils/Logger\";\nimport { DefaultLayoutGenerator } from \"./DefaultLayoutGenerator\";\nimport Core from \"sap/ui/core/Core\";\nimport Messaging from \"sap/ui/core/Messaging\";\n\n/**\n * The Engine is responsible for translating a normalized schema into a physical UI5 layout.\n * It delegates layout generation to the configured `LayoutManager` and field generation to the `PluginRegistry`.\n * It strictly routes execution flow and tracks active plugins for validation.\n * It embodies the \"Plugin-First Philosophy\" by routing all complex field and layout rendering\n * through discrete, decoupled plugins rather than handling native overrides.\n * \n * @namespace nz.co.siliconst.ui5.metaui.core\n * @public\n */\nexport class Engine {\n /** Handles dynamic conditional logic across the active form. */\n private conditionEngine: ConditionEngine | null = null;\n\n /** Array of all instantiated plugins generated during the current build. */\n private activePlugins: { plugin: IPlugin, path: string }[] = [];\n\n /** Deterministic scope ID injected by the host control to prevent clone collisions. */\n public engineScopeId?: string;\n\n private activeModel?: sap.ui.model.Model;\n\n /** Reference to the GeneratorHost that instantiated this engine, for retrieving global definitions. */\n public host?: unknown;\n\n /** Callback to notify the host that an internal field changed. */\n public onChange?: (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => void;\n\n /** Tracks whether the entire engine is running in Editable mode. */\n public readonly isEditable: boolean = true;\n\n /** Tracks if any fields or sub-layouts failed to render, requiring a warning strip. */\n public hasPartialRenderingErrors: boolean = false;\n\n /** Tracks whether the engine should delegate visual state to the global MessageManager. */\n public readonly useMessageManager: boolean = false;\n\n /** The injected PluginRegistry instance */\n public readonly pluginRegistry: PluginRegistry;\n\n /**\n * Initializes a new Engine instance.\n * @param editable Whether the engine should render form fields as editable or read-only.\n * @param useMessageManager Whether to delegate visual state to UI5 MessageManager.\n * @param pluginRegistry Optional injected plugin registry. Defaults to singleton.\n */\n constructor(editable: boolean = true, useMessageManager: boolean = false, pluginRegistry?: PluginRegistry) {\n this.isEditable = editable;\n this.useMessageManager = useMessageManager;\n this.pluginRegistry = pluginRegistry || PluginRegistry.getInstance();\n }\n\n /**\n * Bootstraps the layout generation process by resolving the correct layout strategy.\n * \n * @param schema The normalized JSON schema representing the view.\n * @param model The active StateManager JSONModel instance.\n * @param modelName The UI5 model alias used for isolation.\n * @param onSubmit Callback fired when form is submitted.\n * @param engineScopeId Deterministic scope ID for this engine instance.\n * @param onChange Callback fired when field values change.\n * @returns The generated root UI5 Control container.\n */\n public build(schema: ISchema, model: sap.ui.model.Model, modelName: string = \"meta\", onSubmit?: () => void, engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => void): Control {\n this.conditionEngine = new ConditionEngine(schema);\n this.activePlugins = [];\n this.activeModel = model;\n this.engineScopeId = engineScopeId;\n this.onChange = (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => {\n if (this.conditionEngine && fieldKey) {\n this.conditionEngine.handleEvent(fieldKey, isValid);\n }\n if (onChange) {\n onChange(isValid, fieldKey, errorMessage, controlId);\n }\n };\n\n try {\n // Intercept and synthesize a default layout if the developer/backend failed to provide one\n if (DefaultLayoutGenerator.ensureLayout(schema)) {\n Logger.warn(\"[MetaUI Engine] Missing 'uiLayout' array in schema. Synthesized a default layout mapping to prevent a blank render.\");\n }\n\n const layoutStrategy = schema.layoutStrategy || (schema.type === \"array\" ? \"table\" : \"form\");\n const layoutManager = this.pluginRegistry.getLayout(layoutStrategy);\n\n return layoutManager.render(schema, modelName, this, onSubmit);\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(\"[MetaUI Engine] Critical error during layout generation\", msg);\n Logger.showErrorPopup(`Engine failed to generate the layout.\\n\\nDetails: ${msg}`);\n return new Text({ text: \"Critical Layout Error\" });\n }\n }\n\n /**\n * Instantiates the correct plugin for a specific field based on type and widget hints,\n * and tracks the plugin for global validation.\n * \n * @param fieldMeta The metadata schema specific to the field.\n * @param bindingPath The JSON path representing the field within the payload.\n * @param modelName The UI5 JSONModel name used for data binding.\n * @returns The generated UI5 Control for the field.\n */\n public generateField(fieldMeta: IPropertyMetadata, bindingPath: string, modelName: string, isTemplate: boolean = false): Control {\n try {\n const plugin = this.pluginRegistry.getPlugin(fieldMeta.type || \"string\", fieldMeta.ui?.widget);\n if (typeof plugin.setEditable === \"function\") {\n plugin.setEditable(this.isEditable);\n }\n\n if (typeof plugin.setUseMessageManager === \"function\") {\n plugin.setUseMessageManager(this.useMessageManager);\n }\n\n if (!isTemplate) {\n this.activePlugins.push({ plugin, path: bindingPath });\n }\n const scopeId = isTemplate ? undefined : this.engineScopeId;\n const control = plugin.render(fieldMeta, bindingPath, modelName, scopeId, this.onChange, this.activeModel);\n\n if (this.conditionEngine) {\n this.conditionEngine.registerPlugin(bindingPath, plugin);\n }\n\n return control;\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(`[MetaUI Engine] Failed to generate field at ${bindingPath}`, msg);\n Logger.showErrorPopup(`Failed to generate field '${bindingPath}'.\\n\\nDetails: ${msg}`);\n return new Text({ text: `[Error generating field ${bindingPath}]` });\n }\n }\n\n /**\n * Generates a sub-layout (like an embedded table or nested form) without \n * destroying the current Engine state or Condition tracking.\n * \n * @param schema The normalized JSON schema representing the view.\n * @param modelName The UI5 JSONModel name used for data binding (defaults to \"meta\").\n * @param bindingPath Optional path to bind the sub-layout to a specific array/object property.\n * @returns The generated root UI5 Control container.\n */\n public generateLayout(schema: ISchema, modelName: string, bindingPath?: string): Control {\n try {\n const layoutStrategy = schema.layoutStrategy || (schema.type === \"array\" ? \"table\" : \"form\");\n const layoutManager = this.pluginRegistry.getLayout(layoutStrategy);\n return layoutManager.render(schema, modelName, this, undefined, bindingPath);\n } catch (error) {\n this.hasPartialRenderingErrors = true;\n const msg = (error as Error).message;\n Logger.error(`[MetaUI Engine] Critical error generating sub-layout for ${bindingPath}`, msg);\n Logger.showErrorPopup(`Engine failed to generate a sub-layout.\\n\\nDetails: ${msg}`);\n return new Text({ text: \"Critical Sub-Layout Error\" });\n }\n }\n\n /**\n * Iterates through all active plugins and triggers their internal validation pipelines.\n * \n * @param applyVisualState If true, explicitly instructs the plugin to natively paint its own ValueState.\n * @returns {IPluginValidationResult[]} Array of validation error objects. Empty array if valid.\n */\n public validateAll(applyVisualState: boolean = false): IPluginValidationResult[] {\n const errors: IPluginValidationResult[] = [];\n for (const item of this.activePlugins) {\n try {\n const result = item.plugin.validate();\n if (applyVisualState && typeof item.plugin.setVisualValidationState === \"function\") {\n item.plugin.setVisualValidationState(result.isValid, result.errorMessage);\n }\n\n if (!result.isValid) {\n // Ensure the path is bound to the error so GeneratorHost knows where to target it\n result.fieldKey = result.fieldKey || item.path.replace(/^\\//, \"\");\n errors.push(result);\n // Add console log to find which plugin fails silently\n Logger.error(\"[MetaUI Validation] Plugin failed validation silently:\", item.path || item.plugin.constructor.name);\n }\n } catch (error) {\n Logger.error(`[MetaUI Engine] Error validating plugin at ${item.path}`, (error as Error).message);\n }\n }\n return errors;\n }\n\n /**\n * Retrieves an active plugin instance by its absolute binding path.\n * Useful for programmatic field manipulation (e.g., custom error injection).\n * \n * @param path The binding path (e.g. \"/General/CustomerName\").\n * @returns {IPlugin | undefined} The plugin instance, or undefined if not found.\n */\n public getPluginByPath(path: string): import(\"../interfaces/IPlugin\").IPlugin | undefined {\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n const match = this.activePlugins.find(p => p.path === cleanPath || p.path === `/${cleanPath}`);\n return match ? match.plugin : undefined;\n }\n\n /**\n * Cleans up internal state and destroys the condition engine to prevent memory leaks.\n */\n public destroy(): void {\n if (this.conditionEngine) {\n this.conditionEngine.destroy();\n this.conditionEngine = null;\n }\n\n // ------------------------------------------------------------------------\n // Ghost Error Prevention\n // Flush MessageManager for active plugins before destroying their controls\n // ------------------------------------------------------------------------\n const messageManager = Messaging;\n const existingMessages = messageManager.getMessageModel().getData();\n const messagesToRemove: unknown[] = [];\n\n for (const item of this.activePlugins) {\n if (this.activeModel) {\n const targetPath = `/${item.path.replace(/^\\//, \"\")}`;\n const matched = (existingMessages as { getTarget: () => string, getMessageProcessor: () => { getId: () => string } }[]).filter(msg =>\n msg.getTarget() === targetPath && msg.getMessageProcessor() && msg.getMessageProcessor().getId() === this.activeModel!.getId()\n );\n messagesToRemove.push(...matched);\n }\n if (typeof item.plugin.destroy === \"function\") {\n item.plugin.destroy();\n }\n }\n\n if (messagesToRemove.length > 0) {\n messageManager.removeMessages(messagesToRemove);\n }\n\n this.activePlugins = [];\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -53,14 +53,19 @@ export class Engine {
53
53
  /** Tracks whether the engine should delegate visual state to the global MessageManager. */
54
54
  public readonly useMessageManager: boolean = false;
55
55
 
56
+ /** The injected PluginRegistry instance */
57
+ public readonly pluginRegistry: PluginRegistry;
58
+
56
59
  /**
57
60
  * Initializes a new Engine instance.
58
61
  * @param editable Whether the engine should render form fields as editable or read-only.
59
62
  * @param useMessageManager Whether to delegate visual state to UI5 MessageManager.
63
+ * @param pluginRegistry Optional injected plugin registry. Defaults to singleton.
60
64
  */
61
- constructor(editable: boolean = true, useMessageManager: boolean = false) {
65
+ constructor(editable: boolean = true, useMessageManager: boolean = false, pluginRegistry?: PluginRegistry) {
62
66
  this.isEditable = editable;
63
67
  this.useMessageManager = useMessageManager;
68
+ this.pluginRegistry = pluginRegistry || PluginRegistry.getInstance();
64
69
  }
65
70
 
66
71
  /**
@@ -95,7 +100,7 @@ export class Engine {
95
100
  }
96
101
 
97
102
  const layoutStrategy = schema.layoutStrategy || (schema.type === "array" ? "table" : "form");
98
- const layoutManager = PluginRegistry.getInstance().getLayout(layoutStrategy);
103
+ const layoutManager = this.pluginRegistry.getLayout(layoutStrategy);
99
104
 
100
105
  return layoutManager.render(schema, modelName, this, onSubmit);
101
106
  } catch (error) {
@@ -118,7 +123,7 @@ export class Engine {
118
123
  */
119
124
  public generateField(fieldMeta: IPropertyMetadata, bindingPath: string, modelName: string, isTemplate: boolean = false): Control {
120
125
  try {
121
- const plugin = PluginRegistry.getInstance().getPlugin(fieldMeta.type || "string", fieldMeta.ui?.widget);
126
+ const plugin = this.pluginRegistry.getPlugin(fieldMeta.type || "string", fieldMeta.ui?.widget);
122
127
  if (typeof plugin.setEditable === "function") {
123
128
  plugin.setEditable(this.isEditable);
124
129
  }
@@ -159,7 +164,7 @@ export class Engine {
159
164
  public generateLayout(schema: ISchema, modelName: string, bindingPath?: string): Control {
160
165
  try {
161
166
  const layoutStrategy = schema.layoutStrategy || (schema.type === "array" ? "table" : "form");
162
- const layoutManager = PluginRegistry.getInstance().getLayout(layoutStrategy);
167
+ const layoutManager = this.pluginRegistry.getLayout(layoutStrategy);
163
168
  return layoutManager.render(schema, modelName, this, undefined, bindingPath);
164
169
  } catch (error) {
165
170
  this.hasPartialRenderingErrors = true;
@@ -34,6 +34,9 @@ sap.ui.define(["../utils/Logger"], function (___utils_Logger) {
34
34
  this.registerPluginPath("string", "select", "nz/co/siliconst/ui5/metaui/plugins/controls/DropdownPlugin");
35
35
  this.registerPluginPath("string", "textArea", "nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin");
36
36
  this.registerPluginPath("string", "codeEditor", "nz/co/siliconst/ui5/metaui/plugins/controls/CodeEditorPlugin");
37
+ this.registerPluginPath("string", "link", "nz/co/siliconst/ui5/metaui/plugins/controls/LinkPlugin");
38
+ this.registerPluginPath("string", "password", "nz/co/siliconst/ui5/metaui/plugins/controls/PasswordPlugin");
39
+ this.registerPluginPath("string", "email", "nz/co/siliconst/ui5/metaui/plugins/controls/EmailPlugin");
37
40
 
38
41
  // Phase 1 Mappings
39
42
  this.registerPluginPath("string", "fileUploader", "nz/co/siliconst/ui5/metaui/plugins/controls/FileUploaderPlugin");