@siliconst/metaui 1.4.37 → 1.4.51

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 (62) hide show
  1. package/package.json +1 -1
  2. package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost-dbg.js +24 -0
  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 +24 -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 +15 -1
  9. package/src/nz/co/siliconst/ui5/metaui/controls/host/GeneratorHost-dbg.js +34 -0
  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 +34 -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 +25 -1
  16. package/src/nz/co/siliconst/ui5/metaui/core/Engine-dbg.js +31 -1
  17. package/src/nz/co/siliconst/ui5/metaui/core/Engine-dbg.js.map +1 -1
  18. package/src/nz/co/siliconst/ui5/metaui/core/Engine.d.ts +2 -0
  19. package/src/nz/co/siliconst/ui5/metaui/core/Engine.d.ts.map +1 -1
  20. package/src/nz/co/siliconst/ui5/metaui/core/Engine.js +1 -1
  21. package/src/nz/co/siliconst/ui5/metaui/core/Engine.js.map +1 -1
  22. package/src/nz/co/siliconst/ui5/metaui/core/Engine.ts +38 -0
  23. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine-dbg.js +15 -96
  24. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine-dbg.js.map +1 -1
  25. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.d.ts +1 -6
  26. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.d.ts.map +1 -1
  27. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.js +1 -1
  28. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.js.map +1 -1
  29. package/src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.ts +20 -100
  30. package/src/nz/co/siliconst/ui5/metaui/core/StateManager-dbg.js.map +1 -1
  31. package/src/nz/co/siliconst/ui5/metaui/core/StateManager.js.map +1 -1
  32. package/src/nz/co/siliconst/ui5/metaui/core/StateManager.ts +1 -1
  33. package/src/nz/co/siliconst/ui5/metaui/interfaces/IPlugin-dbg.js.map +1 -1
  34. package/src/nz/co/siliconst/ui5/metaui/interfaces/IPlugin.d.ts +1 -0
  35. package/src/nz/co/siliconst/ui5/metaui/interfaces/IPlugin.d.ts.map +1 -1
  36. package/src/nz/co/siliconst/ui5/metaui/interfaces/IPlugin.ts +1 -0
  37. package/src/nz/co/siliconst/ui5/metaui/interfaces/ISchema-dbg.js.map +1 -1
  38. package/src/nz/co/siliconst/ui5/metaui/interfaces/ISchema.d.ts +2 -1
  39. package/src/nz/co/siliconst/ui5/metaui/interfaces/ISchema.d.ts.map +1 -1
  40. package/src/nz/co/siliconst/ui5/metaui/interfaces/ISchema.ts +2 -1
  41. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout-dbg.js +327 -67
  42. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout-dbg.js.map +1 -1
  43. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.d.ts +57 -15
  44. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.d.ts.map +1 -1
  45. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.js +1 -1
  46. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.js.map +1 -1
  47. package/src/nz/co/siliconst/ui5/metaui/layouts/WizardLayout.ts +375 -65
  48. package/src/nz/co/siliconst/ui5/metaui/library-preload.js +7 -7
  49. package/src/nz/co/siliconst/ui5/metaui/library-preload.js.map +1 -1
  50. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin-dbg.js +10 -15
  51. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin-dbg.js.map +1 -1
  52. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin.d.ts +4 -0
  53. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin.d.ts.map +1 -1
  54. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin.js +1 -1
  55. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin.js.map +1 -1
  56. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/BasePlugin.ts +10 -15
  57. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin-dbg.js +11 -1
  58. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin-dbg.js.map +1 -1
  59. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin.d.ts.map +1 -1
  60. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin.js +1 -1
  61. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin.js.map +1 -1
  62. package/src/nz/co/siliconst/ui5/metaui/plugins/controls/StepInputPlugin.ts +10 -1
@@ -1,2 +1,2 @@
1
- sap.ui.define(["./PluginRegistry","sap/m/Text","../utils/Logger","./DefaultLayoutGenerator","./PipelineManager"],function(e,t,i,r,n){"use strict";const a=e["PluginRegistry"];const s=i["Logger"];const o=r["DefaultLayoutGenerator"];const l=n["GlobalPipeline"];class g{activePlugins=[];templatePlugins=[];validationLedger=new Map;isEditable=true;hasPartialRenderingErrors=false;useMessageManager=false;constructor(e=true,t=false,i){this.isEditable=e;this.useMessageManager=t;this.pluginRegistry=i||a.getInstance()}build(e,i,r="meta",n,a,o){this.activePlugins=[];this.activeModel=i;this.engineScopeId=a;this.onChange=(e,t,i,r)=>{if(t){this.reportSchemaError(t,e?null:i||"Invalid input")}if(o){o(e,t,i,r)}};try{const t=e.layoutStrategy||(e.type==="array"?"table":"form");const i=this.pluginRegistry.getLayout(t);return i.render(e,r,this,n)}catch(e){this.hasPartialRenderingErrors=true;const i=e.message;s.error("[MetaUI Engine] Critical error during layout generation",i);s.showErrorPopup(`Engine failed to generate the layout.\n\nDetails: ${i}`);return new t({text:"Critical Layout Error"})}}generateField(e,i,r,n=false){try{const t=this.pluginRegistry.getPlugin(e.type||"string",e.ui?.widget);if(typeof t.setEditable==="function"){t.setEditable(this.isEditable)}if(typeof t.setUseMessageManager==="function"){t.setUseMessageManager(this.useMessageManager)}if(!n){this.activePlugins.push({plugin:t,path:i})}else{this.templatePlugins.push({plugin:t,path:i})}const a=n?undefined:this.engineScopeId;const s=t.render(e,i,r,a,this.onChange,this.activeModel);return s}catch(e){this.hasPartialRenderingErrors=true;const r=e.message;s.error(`[MetaUI Engine] Failed to generate field at ${i}`,r);s.showErrorPopup(`Failed to generate field '${i}'.\n\nDetails: ${r}`);return new t({text:`[Error generating field ${i}]`})}}generateLayout(e,i,r){try{if(o.ensureLayout(e)){s.warn(`[MetaUI Engine] Missing 'uiLayout' array in sub-schema for ${r}. Synthesized a default layout mapping.`)}const t=e.layoutStrategy||(e.type==="array"?"table":"form");const n=this.pluginRegistry.getLayout(t);return n.render(e,i,this,undefined,r)}catch(e){this.hasPartialRenderingErrors=true;const i=e.message;s.error(`[MetaUI Engine] Critical error generating sub-layout for ${r}`,i);s.showErrorPopup(`Engine failed to generate a sub-layout.\n\nDetails: ${i}`);return new t({text:"Critical Sub-Layout Error"})}}validateAll(e=false){const t=[];for(const i of this.activePlugins){try{const r=i.plugin.validate();if(e){this.reportSchemaError(i.path,r.isValid?null:r.errorMessage||"Invalid input")}if(!r.isValid){r.fieldKey=r.fieldKey||i.path.replace(/^\//,"");t.push(r);s.error("[MetaUI Validation] Plugin failed validation silently:",i.path||i.plugin.constructor.name)}}catch(e){s.error(`[MetaUI Engine] Error validating plugin at ${i.path}`,e.message)}}if(this.host&&typeof this.host.getStateManager==="function"){const i=this.host.getStateManager();if(i){const r=i.extractPayload();const n=i.getSchema?i.getSchema():this.host.getParsedSchema?.();if(r&&n){const i=this.validatePayloadArrays(n,r,"");if(e){i.forEach(e=>{if(e.fieldKey){this.reportSchemaError(e.fieldKey,e.isValid?null:e.errorMessage||"Invalid input")}})}t.push(...i.filter(e=>!e.isValid))}}}return t}onArrayMutated(e){if(this.host&&typeof this.host.getStateManager==="function"){const t=this.host.getStateManager();if(t&&typeof t.clearArrayMessages==="function"){t.clearArrayMessages(e)}}}validatePayloadArrays(e,t,i){const r=[];if(!e||!t||typeof t!=="object")return r;if(e.type==="object"&&e.properties){for(const n of Object.keys(e.properties)){const a=e.properties[n];if(t[n]!==undefined){const e=i?`${i}/${n}`:n;r.push(...this.validatePayloadArrays(a,t[n],e))}}}else if(e.type==="array"&&e.items&&Array.isArray(t)){t.forEach((t,n)=>{const a=i?`${i}/${n}`:`${n}`;if(e.items.type==="object"&&e.items.properties){for(const i of Object.keys(e.items.properties)){const n=e.items.properties[i];const s=`${a}/${i}`;const o=t?t[i]:undefined;const g=[];const u={};if(n.required)g.push("required");if(n.maxLength!==undefined){g.push("maxLength");u["maxLength"]=n.maxLength}if(n.minLength!==undefined){g.push("minLength");u["minLength"]=n.minLength}if(n.pattern!==undefined){g.push("pattern");u["pattern"]={regex:n.pattern}}if(n.minimum!==undefined||n.maximum!==undefined){g.push("range");u["range"]={min:n.minimum,max:n.maximum}}const c=n.ui?.format;if(c==="email"||c==="url"||c==="iban"){g.push(c)}if(g.length>0){const e=l.executeValidation(o,g,u);if(!e.isValid){r.push({isValid:false,errorMessage:e.errorMessage,fieldKey:s,fieldLabel:n.ui?.label||i})}else{r.push({isValid:true,fieldKey:s})}}}}})}return r}getPluginByPath(e){const t=e.replace(/^\//,"");const i=this.activePlugins.find(e=>e.path.replace(/^\//,"")===t);return i?i.plugin:undefined}reportSchemaError(e,t){const i=e.replace(/^\//,"");if(!this.validationLedger.has(i)){this.validationLedger.set(i,{schemaError:null,policyError:null})}this.validationLedger.get(i).schemaError=t;this.resolveVisualState(i)}reportPolicyError(e,t){const i=e.replace(/^\//,"");if(!this.validationLedger.has(i)){this.validationLedger.set(i,{schemaError:null,policyError:null})}this.validationLedger.get(i).policyError=t;this.resolveVisualState(i)}resolveVisualState(e){const t=this.getPluginByPath(e);const i=this.validationLedger.get(e);if(!i)return;const r=i.policyError!==null||i.schemaError!==null;const n=i.policyError||i.schemaError;if(t&&typeof t.setVisualValidationState==="function"){t.setVisualValidationState(!r,r?n||undefined:undefined)}else{this.setNativeControlError(e,r?n||undefined:undefined)}}setNativeControlError(e,t){if(this.host&&this.host.generatedContent){const i=this.host.generatedContent;this.traverseAndSetError(i,e,t)}}traverseAndSetError(e,t,i){if(!e)return;const r=[e.getBindingInfo("value"),e.getBindingInfo("selectedKey"),e.getBindingInfo("dateValue"),e.getBindingInfo("selected")];for(const n of r){if(n&&n.parts&&n.parts.length>0){const r=n.parts[0].path;if(r===t||t.endsWith(r)){const n=e.getBindingContext(this.host.activeModelName);if(n){const a=n.getPath()+"/"+r;const s=a.replace(/^\//,"");if(s===t){if(typeof e.setValueState==="function"){e.setValueState(i?"Error":"None");if(typeof e.setValueStateText==="function"){e.setValueStateText(i||"")}}}}}}}if(typeof e.getAggregation==="function"&&typeof e.getMetadata==="function"){const r=e.getMetadata().getAggregations();for(const n in r){const r=e.getAggregation(n);if(Array.isArray(r)){r.forEach(e=>this.traverseAndSetError(e,t,i))}else if(r){this.traverseAndSetError(r,t,i)}}}}destroy(){for(const e of this.activePlugins){if(typeof e.plugin.destroy==="function"){e.plugin.destroy()}}for(const e of this.templatePlugins){if(typeof e.plugin.destroy==="function"){e.plugin.destroy()}}this.validationLedger.clear();this.activePlugins=[];this.templatePlugins=[]}}var u={__esModule:true};u.Engine=g;return u});
1
+ sap.ui.define(["./PluginRegistry","sap/m/Text","../utils/Logger","./DefaultLayoutGenerator","sap/ui/core/Messaging","sap/ui/core/message/Message","sap/ui/core/library","./PipelineManager"],function(e,t,i,s,r,a,n,o){"use strict";const l=e["PluginRegistry"];const g=i["Logger"];const u=s["DefaultLayoutGenerator"];const c=o["GlobalPipeline"];class d{activePlugins=[];templatePlugins=[];validationLedger=new Map;activeMessages=new Map;isEditable=true;hasPartialRenderingErrors=false;useMessageManager=false;constructor(e=true,t=false,i){this.isEditable=e;this.useMessageManager=t;this.pluginRegistry=i||l.getInstance()}build(e,i,s="meta",r,a,n){this.activePlugins=[];this.activeModel=i;this.engineScopeId=a;this.onChange=(e,t,i,s)=>{if(t){this.reportSchemaError(t,e?null:i||"Invalid input")}if(n){n(e,t,i,s)}};try{const t=e.layoutStrategy||(e.type==="array"?"table":"form");const i=this.pluginRegistry.getLayout(t);return i.render(e,s,this,r)}catch(e){this.hasPartialRenderingErrors=true;const i=e.message;g.error("[MetaUI Engine] Critical error during layout generation",i);g.showErrorPopup(`Engine failed to generate the layout.\n\nDetails: ${i}`);return new t({text:"Critical Layout Error"})}}generateField(e,i,s,r=false){try{const t=this.pluginRegistry.getPlugin(e.type||"string",e.ui?.widget);if(typeof t.setEditable==="function"){t.setEditable(this.isEditable)}if(typeof t.setUseMessageManager==="function"){t.setUseMessageManager(this.useMessageManager)}if(!r){this.activePlugins.push({plugin:t,path:i})}else{this.templatePlugins.push({plugin:t,path:i})}const a=r?undefined:this.engineScopeId;const n=t.render(e,i,s,a,this.onChange,this.activeModel);return n}catch(e){this.hasPartialRenderingErrors=true;const s=e.message;g.error(`[MetaUI Engine] Failed to generate field at ${i}`,s);g.showErrorPopup(`Failed to generate field '${i}'.\n\nDetails: ${s}`);return new t({text:`[Error generating field ${i}]`})}}generateLayout(e,i,s){try{if(u.ensureLayout(e)){g.warn(`[MetaUI Engine] Missing 'uiLayout' array in sub-schema for ${s}. Synthesized a default layout mapping.`)}const t=e.layoutStrategy||(e.type==="array"?"table":"form");const r=this.pluginRegistry.getLayout(t);return r.render(e,i,this,undefined,s)}catch(e){this.hasPartialRenderingErrors=true;const i=e.message;g.error(`[MetaUI Engine] Critical error generating sub-layout for ${s}`,i);g.showErrorPopup(`Engine failed to generate a sub-layout.\n\nDetails: ${i}`);return new t({text:"Critical Sub-Layout Error"})}}validateAll(e=false){const t=[];for(const i of this.activePlugins){try{const s=i.plugin.validate();if(e){this.reportSchemaError(i.path,s.isValid?null:s.errorMessage||"Invalid input")}if(!s.isValid){s.fieldKey=s.fieldKey||i.path.replace(/^\//,"");t.push(s);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)}}if(this.host&&typeof this.host.getStateManager==="function"){const i=this.host.getStateManager();if(i){const s=i.extractPayload();const r=i.getSchema?i.getSchema():this.host.getParsedSchema?.();if(s&&r){const i=this.validatePayloadArrays(r,s,"");if(e){i.forEach(e=>{if(e.fieldKey){this.reportSchemaError(e.fieldKey,e.isValid?null:e.errorMessage||"Invalid input")}})}t.push(...i.filter(e=>!e.isValid))}}}return t}onArrayMutated(e){if(this.host&&typeof this.host.getStateManager==="function"){const t=this.host.getStateManager();if(t&&typeof t.clearArrayMessages==="function"){t.clearArrayMessages(e)}}}validatePayloadArrays(e,t,i){const s=[];if(!e||!t||typeof t!=="object")return s;if(e.type==="object"&&e.properties){for(const r of Object.keys(e.properties)){const a=e.properties[r];if(t[r]!==undefined){const e=i?`${i}/${r}`:r;s.push(...this.validatePayloadArrays(a,t[r],e))}}}else if(e.type==="array"&&e.items&&Array.isArray(t)){t.forEach((t,r)=>{const a=i?`${i}/${r}`:`${r}`;if(e.items.type==="object"&&e.items.properties){for(const i of Object.keys(e.items.properties)){const r=e.items.properties[i];const n=`${a}/${i}`;const o=t?t[i]:undefined;const l=[];const g={};if(r.required)l.push("required");if(r.maxLength!==undefined){l.push("maxLength");g["maxLength"]=r.maxLength}if(r.minLength!==undefined){l.push("minLength");g["minLength"]=r.minLength}if(r.pattern!==undefined){l.push("pattern");g["pattern"]={regex:r.pattern}}if(r.minimum!==undefined||r.maximum!==undefined){l.push("range");g["range"]={min:r.minimum,max:r.maximum}}const u=r.ui?.format;if(u==="email"||u==="url"||u==="iban"){l.push(u)}if(l.length>0){const e=c.executeValidation(o,l,g);if(!e.isValid){s.push({isValid:false,errorMessage:e.errorMessage,fieldKey:n,fieldLabel:r.ui?.label||i})}else{s.push({isValid:true,fieldKey:n})}}}}})}return s}getPluginByPath(e){const t=e.replace(/^\//,"");const i=this.activePlugins.find(e=>e.path.replace(/^\//,"")===t);return i?i.plugin:undefined}reportSchemaError(e,t){const i=e.replace(/^\//,"");if(!this.validationLedger.has(i)){this.validationLedger.set(i,{schemaError:null,policyError:null})}this.validationLedger.get(i).schemaError=t;this.resolveVisualState(i)}reportPolicyError(e,t){const i=e.replace(/^\//,"");if(!this.validationLedger.has(i)){this.validationLedger.set(i,{schemaError:null,policyError:null})}this.validationLedger.get(i).policyError=t;this.resolveVisualState(i)}resolveVisualState(e){const t=this.getPluginByPath(e);const i=this.validationLedger.get(e);if(!i)return;const s=i.policyError!==null||i.schemaError!==null;const o=i.policyError||i.schemaError;if(t&&typeof t.setVisualValidationState==="function"){t.setVisualValidationState(!s,s?o||undefined:undefined)}else{this.setNativeControlError(e,s?o||undefined:undefined)}if(this.useMessageManager){const i=this.activeMessages.get(e);if(i){r.removeMessages(i);this.activeMessages.delete(e)}if(s){const i=`/${e}`;const s=this.host&&typeof this.host.getStateManager==="function"?this.host.getStateManager()?.getModel():undefined;const l=typeof t?.getFieldLabel==="function"?t.getFieldLabel():undefined;const g=l||e;const u=`Field '${g}': ${o||"Validation Error"}`;const c=new a({message:u,additionalText:g!==i?g:undefined,type:n.MessageType.Error,target:i,processor:s});r.addMessages(c);this.activeMessages.set(e,c)}}}setNativeControlError(e,t){if(this.host&&this.host.generatedContent){const i=this.host.generatedContent;this.traverseAndSetError(i,e,t)}}traverseAndSetError(e,t,i){if(!e)return;const s=[e.getBindingInfo("value"),e.getBindingInfo("selectedKey"),e.getBindingInfo("dateValue"),e.getBindingInfo("selected")];for(const r of s){if(r&&r.parts&&r.parts.length>0){const s=r.parts[0].path;if(s===t||t.endsWith(s)){const r=e.getBindingContext(this.host.activeModelName);if(r){const a=r.getPath()+"/"+s;const n=a.replace(/^\//,"");if(n===t){if(typeof e.setValueState==="function"){e.setValueState(i?"Error":"None");if(typeof e.setValueStateText==="function"){e.setValueStateText(i||"")}}}}}}}if(typeof e.getAggregation==="function"&&typeof e.getMetadata==="function"){const s=e.getMetadata().getAggregations();for(const r in s){const s=e.getAggregation(r);if(Array.isArray(s)){s.forEach(e=>this.traverseAndSetError(e,t,i))}else if(s){this.traverseAndSetError(s,t,i)}}}}destroy(){for(const e of this.activePlugins){if(typeof e.plugin.destroy==="function"){e.plugin.destroy()}}for(const e of this.templatePlugins){if(typeof e.plugin.destroy==="function"){e.plugin.destroy()}}if(this.useMessageManager&&this.activeMessages.size>0){r.removeMessages(Array.from(this.activeMessages.values()))}this.validationLedger.clear();this.activeMessages.clear();this.activePlugins=[];this.templatePlugins=[]}}var h={__esModule:true};h.Engine=d;return h});
2
2
  //# sourceMappingURL=Engine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Engine.js","names":["PluginRegistry","___PluginRegistry","Logger","___utils_Logger","DefaultLayoutGenerator","___DefaultLayoutGenerator","GlobalPipeline","___PipelineManager","Engine","activePlugins","templatePlugins","validationLedger","Map","isEditable","hasPartialRenderingErrors","useMessageManager","constructor","editable","pluginRegistry","this","getInstance","build","schema","model","modelName","onSubmit","engineScopeId","onChange","activeModel","isValid","fieldKey","errorMessage","controlId","reportSchemaError","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","generateLayout","ensureLayout","warn","validateAll","applyVisualState","errors","item","result","validate","replace","name","host","getStateManager","stateManager","payload","extractPayload","getSchema","getParsedSchema","arrayErrors","validatePayloadArrays","forEach","err","filter","e","onArrayMutated","arrayPath","clearArrayMessages","currentPath","properties","key","Object","keys","propSchema","childPath","items","Array","isArray","index","itemPath","propMeta","propPath","val","validatorsToRun","argsMap","required","maxLength","minLength","pattern","regex","minimum","maximum","min","max","format","length","res","executeValidation","fieldLabel","label","getPluginByPath","cleanPath","match","find","p","fieldPath","has","set","schemaError","policyError","get","resolveVisualState","reportPolicyError","ledgerEntry","isError","setVisualValidationState","setNativeControlError","targetPath","generatedContent","rootControl","traverseAndSetError","bindingInfos","getBindingInfo","info","parts","boundPath","endsWith","context","getBindingContext","activeModelName","fullPath","getPath","cleanedFullPath","setValueState","setValueStateText","getAggregation","getMetadata","aggs","getAggregations","aggName","child","c","destroy","clear","__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\";\n\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\";\nimport { GlobalPipeline } from \"./PipelineManager\";\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\n\n /** Array of all instantiated plugins generated during the current build. */\n private activePlugins: { plugin: IPlugin, path: string }[] = [];\n\n /** Array of template plugins generated for table rows to prevent memory leaks during destruction. */\n private templatePlugins: { 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?: unknown;\n\n /** Ledger tracking local vs cross-field errors to prevent visual race conditions. */\n private validationLedger: Map<string, { schemaError: string | null, policyError: string | null }> = new Map();\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: unknown, modelName: string = \"meta\", onSubmit?: () => void, engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => void): Control {\n\n this.activePlugins = [];\n this.activeModel = model;\n this.engineScopeId = engineScopeId;\n this.onChange = (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => {\n if (fieldKey) {\n this.reportSchemaError(fieldKey, isValid ? null : errorMessage || \"Invalid input\");\n }\n\n if (onChange) {\n onChange(isValid, fieldKey, errorMessage, controlId);\n }\n };\n\n try {\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 } else {\n this.templatePlugins.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\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 if (DefaultLayoutGenerator.ensureLayout(schema)) {\n Logger.warn(`[MetaUI Engine] Missing 'uiLayout' array in sub-schema for ${bindingPath}. Synthesized a default layout mapping.`);\n }\n\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) {\n this.reportSchemaError(item.path, result.isValid ? null : result.errorMessage || \"Invalid input\");\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\n // 2. Recursively validate arrays via StateManager payload traversing for Table layout rows\n if (this.host && typeof (this.host as any).getStateManager === \"function\") {\n const stateManager = (this.host as any).getStateManager();\n if (stateManager) {\n const payload = stateManager.extractPayload();\n const schema = stateManager.getSchema ? stateManager.getSchema() : (this.host as any).getParsedSchema?.();\n if (payload && schema) {\n const arrayErrors = this.validatePayloadArrays(schema, payload, \"\");\n if (applyVisualState) {\n arrayErrors.forEach(err => {\n if (err.fieldKey) {\n this.reportSchemaError(err.fieldKey, err.isValid ? null : err.errorMessage || \"Invalid input\");\n }\n });\n }\n errors.push(...arrayErrors.filter(e => !e.isValid));\n }\n }\n }\n\n return errors;\n }\n\n public onArrayMutated(arrayPath: string): void {\n if (this.host && typeof (this.host as any).getStateManager === \"function\") {\n const stateManager = (this.host as any).getStateManager();\n if (stateManager && typeof stateManager.clearArrayMessages === \"function\") {\n stateManager.clearArrayMessages(arrayPath);\n }\n }\n }\n\n private validatePayloadArrays(schema: any, payload: any, currentPath: string): IPluginValidationResult[] {\n const errors: IPluginValidationResult[] = [];\n if (!schema || !payload || typeof payload !== \"object\") return errors;\n\n if (schema.type === \"object\" && schema.properties) {\n for (const key of Object.keys(schema.properties)) {\n const propSchema = schema.properties[key];\n if (payload[key] !== undefined) {\n const childPath = currentPath ? `${currentPath}/${key}` : key;\n errors.push(...this.validatePayloadArrays(propSchema, payload[key], childPath));\n }\n }\n } else if (schema.type === \"array\" && schema.items && Array.isArray(payload)) {\n payload.forEach((item, index) => {\n const itemPath = currentPath ? `${currentPath}/${index}` : `${index}`;\n if (schema.items.type === \"object\" && schema.items.properties) {\n for (const key of Object.keys(schema.items.properties)) {\n const propMeta = schema.items.properties[key];\n const propPath = `${itemPath}/${key}`;\n const val = item ? item[key] : undefined;\n \n const validatorsToRun: string[] = [];\n const argsMap: Record<string, unknown> = {};\n\n if (propMeta.required) validatorsToRun.push(\"required\");\n if (propMeta.maxLength !== undefined) {\n validatorsToRun.push(\"maxLength\");\n argsMap[\"maxLength\"] = propMeta.maxLength;\n }\n if (propMeta.minLength !== undefined) {\n validatorsToRun.push(\"minLength\");\n argsMap[\"minLength\"] = propMeta.minLength;\n }\n if (propMeta.pattern !== undefined) {\n validatorsToRun.push(\"pattern\");\n argsMap[\"pattern\"] = { regex: propMeta.pattern };\n }\n if (propMeta.minimum !== undefined || propMeta.maximum !== undefined) {\n validatorsToRun.push(\"range\");\n argsMap[\"range\"] = { min: propMeta.minimum, max: propMeta.maximum };\n }\n const format = propMeta.ui?.format;\n if (format === \"email\" || format === \"url\" || format === \"iban\") {\n validatorsToRun.push(format);\n }\n \n if (validatorsToRun.length > 0) {\n const res = GlobalPipeline.executeValidation(val, validatorsToRun, argsMap);\n if (!res.isValid) {\n errors.push({\n isValid: false,\n errorMessage: res.errorMessage,\n fieldKey: propPath,\n fieldLabel: propMeta.ui?.label || key\n });\n } else {\n errors.push({ isValid: true, fieldKey: propPath }); // Push successful state to clear old errors\n }\n }\n }\n }\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.replace(/^\\//, \"\");\n const match = this.activePlugins.find(p => p.path.replace(/^\\//, \"\") === cleanPath);\n return match ? match.plugin : undefined;\n }\n\n /**\n * Reports a localized schema validation error to the coordinator ledger.\n */\n public reportSchemaError(fieldPath: string, errorMessage: string | null): void {\n const cleanPath = fieldPath.replace(/^\\//, \"\");\n if (!this.validationLedger.has(cleanPath)) {\n this.validationLedger.set(cleanPath, { schemaError: null, policyError: null });\n }\n this.validationLedger.get(cleanPath)!.schemaError = errorMessage;\n this.resolveVisualState(cleanPath);\n }\n\n /**\n * Reports a cross-field policy error to the coordinator ledger.\n */\n public reportPolicyError(fieldPath: string, errorMessage: string | null): void {\n const cleanPath = fieldPath.replace(/^\\//, \"\");\n if (!this.validationLedger.has(cleanPath)) {\n this.validationLedger.set(cleanPath, { schemaError: null, policyError: null });\n }\n this.validationLedger.get(cleanPath)!.policyError = errorMessage;\n this.resolveVisualState(cleanPath);\n }\n\n /**\n * Computes the final visual state by checking both engines and applies it to the plugin.\n */\n private resolveVisualState(cleanPath: string): void {\n const plugin = this.getPluginByPath(cleanPath);\n const ledgerEntry = this.validationLedger.get(cleanPath);\n if (!ledgerEntry) return;\n\n const isError = ledgerEntry.policyError !== null || ledgerEntry.schemaError !== null;\n const errorMessage = ledgerEntry.policyError || ledgerEntry.schemaError;\n\n if (plugin && typeof plugin.setVisualValidationState === \"function\") {\n plugin.setVisualValidationState(!isError, isError ? errorMessage || undefined : undefined);\n } else {\n // Un-tracked template clones (Table Layout rows)\n this.setNativeControlError(cleanPath, isError ? errorMessage || undefined : undefined);\n }\n }\n\n private setNativeControlError(targetPath: string, errorMessage?: string): void {\n if (this.host && (this.host as any).generatedContent) {\n const rootControl = (this.host as any).generatedContent;\n this.traverseAndSetError(rootControl, targetPath, errorMessage);\n }\n }\n\n private traverseAndSetError(control: any, targetPath: string, errorMessage?: string): void {\n if (!control) return;\n \n const bindingInfos = [control.getBindingInfo(\"value\"), control.getBindingInfo(\"selectedKey\"), control.getBindingInfo(\"dateValue\"), control.getBindingInfo(\"selected\")];\n for (const info of bindingInfos) {\n if (info && info.parts && info.parts.length > 0) {\n const boundPath = info.parts[0].path;\n // UI5 relative bindings drop the leading slash in the context, but retain it in the path\n if (boundPath === targetPath || targetPath.endsWith(boundPath)) {\n // Ensure we match the exact row context path\n const context = control.getBindingContext((this.host as any).activeModelName);\n if (context) {\n const fullPath = context.getPath() + \"/\" + boundPath;\n const cleanedFullPath = fullPath.replace(/^\\//, \"\");\n if (cleanedFullPath === targetPath) {\n if (typeof control.setValueState === \"function\") {\n control.setValueState(errorMessage ? \"Error\" : \"None\");\n if (typeof control.setValueStateText === \"function\") {\n control.setValueStateText(errorMessage || \"\");\n }\n }\n }\n }\n }\n }\n }\n \n if (typeof control.getAggregation === \"function\" && typeof control.getMetadata === \"function\") {\n const aggs = control.getMetadata().getAggregations();\n for (const aggName in aggs) {\n const child = control.getAggregation(aggName);\n if (Array.isArray(child)) {\n child.forEach(c => this.traverseAndSetError(c, targetPath, errorMessage));\n } else if (child) {\n this.traverseAndSetError(child, targetPath, errorMessage);\n }\n }\n }\n }\n\n /**\n * Cleans up internal state and destroys the condition engine to prevent memory leaks.\n */\n public destroy(): void {\n\n\n for (const item of this.activePlugins) {\n if (typeof item.plugin.destroy === \"function\") {\n item.plugin.destroy();\n }\n }\n\n for (const item of this.templatePlugins) {\n if (typeof item.plugin.destroy === \"function\") {\n item.plugin.destroy();\n }\n }\n\n this.validationLedger.clear();\n this.activePlugins = [];\n this.templatePlugins = [];\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"Engine.js","names":["PluginRegistry","___PluginRegistry","Logger","___utils_Logger","DefaultLayoutGenerator","___DefaultLayoutGenerator","GlobalPipeline","___PipelineManager","Engine","activePlugins","templatePlugins","validationLedger","Map","activeMessages","isEditable","hasPartialRenderingErrors","useMessageManager","constructor","editable","pluginRegistry","this","getInstance","build","schema","model","modelName","onSubmit","engineScopeId","onChange","activeModel","isValid","fieldKey","errorMessage","controlId","reportSchemaError","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","generateLayout","ensureLayout","warn","validateAll","applyVisualState","errors","item","result","validate","replace","name","host","getStateManager","stateManager","payload","extractPayload","getSchema","getParsedSchema","arrayErrors","validatePayloadArrays","forEach","err","filter","e","onArrayMutated","arrayPath","clearArrayMessages","currentPath","properties","key","Object","keys","propSchema","childPath","items","Array","isArray","index","itemPath","propMeta","propPath","val","validatorsToRun","argsMap","required","maxLength","minLength","pattern","regex","minimum","maximum","min","max","format","length","res","executeValidation","fieldLabel","label","getPluginByPath","cleanPath","match","find","p","fieldPath","has","set","schemaError","policyError","get","resolveVisualState","reportPolicyError","ledgerEntry","isError","setVisualValidationState","setNativeControlError","currentMsg","Messaging","removeMessages","delete","targetPath","processorModel","getModel","getFieldLabel","displayLabel","displayText","newMsg","Message","additionalText","coreLibrary","MessageType","Error","target","processor","addMessages","generatedContent","rootControl","traverseAndSetError","bindingInfos","getBindingInfo","info","parts","boundPath","endsWith","context","getBindingContext","activeModelName","fullPath","getPath","cleanedFullPath","setValueState","setValueStateText","getAggregation","getMetadata","aggs","getAggregations","aggName","child","c","destroy","size","from","values","clear","__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\";\n\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\";\nimport Message from \"sap/ui/core/message/Message\";\nimport coreLibrary from \"sap/ui/core/library\";\nimport { GlobalPipeline } from \"./PipelineManager\";\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\n\n /** Array of all instantiated plugins generated during the current build. */\n private activePlugins: { plugin: IPlugin, path: string }[] = [];\n\n /** Array of template plugins generated for table rows to prevent memory leaks during destruction. */\n private templatePlugins: { 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?: unknown;\n\n /** Ledger tracking local vs cross-field errors to prevent visual race conditions. */\n private validationLedger: Map<string, { schemaError: string | null, policyError: string | null }> = new Map();\n\n /** Tracks active MessageManager messages created by this engine instance. */\n private activeMessages: Map<string, Message> = new Map();\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: unknown, modelName: string = \"meta\", onSubmit?: () => void, engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => void): Control {\n\n this.activePlugins = [];\n this.activeModel = model;\n this.engineScopeId = engineScopeId;\n this.onChange = (isValid: boolean, fieldKey?: string, errorMessage?: string, controlId?: string) => {\n if (fieldKey) {\n this.reportSchemaError(fieldKey, isValid ? null : errorMessage || \"Invalid input\");\n }\n\n if (onChange) {\n onChange(isValid, fieldKey, errorMessage, controlId);\n }\n };\n\n try {\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 } else {\n this.templatePlugins.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\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 if (DefaultLayoutGenerator.ensureLayout(schema)) {\n Logger.warn(`[MetaUI Engine] Missing 'uiLayout' array in sub-schema for ${bindingPath}. Synthesized a default layout mapping.`);\n }\n\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) {\n this.reportSchemaError(item.path, result.isValid ? null : result.errorMessage || \"Invalid input\");\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\n // 2. Recursively validate arrays via StateManager payload traversing for Table layout rows\n if (this.host && typeof (this.host as any).getStateManager === \"function\") {\n const stateManager = (this.host as any).getStateManager();\n if (stateManager) {\n const payload = stateManager.extractPayload();\n const schema = stateManager.getSchema ? stateManager.getSchema() : (this.host as any).getParsedSchema?.();\n if (payload && schema) {\n const arrayErrors = this.validatePayloadArrays(schema, payload, \"\");\n if (applyVisualState) {\n arrayErrors.forEach(err => {\n if (err.fieldKey) {\n this.reportSchemaError(err.fieldKey, err.isValid ? null : err.errorMessage || \"Invalid input\");\n }\n });\n }\n errors.push(...arrayErrors.filter(e => !e.isValid));\n }\n }\n }\n\n return errors;\n }\n\n public onArrayMutated(arrayPath: string): void {\n if (this.host && typeof (this.host as any).getStateManager === \"function\") {\n const stateManager = (this.host as any).getStateManager();\n if (stateManager && typeof stateManager.clearArrayMessages === \"function\") {\n stateManager.clearArrayMessages(arrayPath);\n }\n }\n }\n\n private validatePayloadArrays(schema: any, payload: any, currentPath: string): IPluginValidationResult[] {\n const errors: IPluginValidationResult[] = [];\n if (!schema || !payload || typeof payload !== \"object\") return errors;\n\n if (schema.type === \"object\" && schema.properties) {\n for (const key of Object.keys(schema.properties)) {\n const propSchema = schema.properties[key];\n if (payload[key] !== undefined) {\n const childPath = currentPath ? `${currentPath}/${key}` : key;\n errors.push(...this.validatePayloadArrays(propSchema, payload[key], childPath));\n }\n }\n } else if (schema.type === \"array\" && schema.items && Array.isArray(payload)) {\n payload.forEach((item, index) => {\n const itemPath = currentPath ? `${currentPath}/${index}` : `${index}`;\n if (schema.items.type === \"object\" && schema.items.properties) {\n for (const key of Object.keys(schema.items.properties)) {\n const propMeta = schema.items.properties[key];\n const propPath = `${itemPath}/${key}`;\n const val = item ? item[key] : undefined;\n \n const validatorsToRun: string[] = [];\n const argsMap: Record<string, unknown> = {};\n\n if (propMeta.required) validatorsToRun.push(\"required\");\n if (propMeta.maxLength !== undefined) {\n validatorsToRun.push(\"maxLength\");\n argsMap[\"maxLength\"] = propMeta.maxLength;\n }\n if (propMeta.minLength !== undefined) {\n validatorsToRun.push(\"minLength\");\n argsMap[\"minLength\"] = propMeta.minLength;\n }\n if (propMeta.pattern !== undefined) {\n validatorsToRun.push(\"pattern\");\n argsMap[\"pattern\"] = { regex: propMeta.pattern };\n }\n if (propMeta.minimum !== undefined || propMeta.maximum !== undefined) {\n validatorsToRun.push(\"range\");\n argsMap[\"range\"] = { min: propMeta.minimum, max: propMeta.maximum };\n }\n const format = propMeta.ui?.format;\n if (format === \"email\" || format === \"url\" || format === \"iban\") {\n validatorsToRun.push(format);\n }\n \n if (validatorsToRun.length > 0) {\n const res = GlobalPipeline.executeValidation(val, validatorsToRun, argsMap);\n if (!res.isValid) {\n errors.push({\n isValid: false,\n errorMessage: res.errorMessage,\n fieldKey: propPath,\n fieldLabel: propMeta.ui?.label || key\n });\n } else {\n errors.push({ isValid: true, fieldKey: propPath }); // Push successful state to clear old errors\n }\n }\n }\n }\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.replace(/^\\//, \"\");\n const match = this.activePlugins.find(p => p.path.replace(/^\\//, \"\") === cleanPath);\n return match ? match.plugin : undefined;\n }\n\n /**\n * Reports a localized schema validation error to the coordinator ledger.\n */\n public reportSchemaError(fieldPath: string, errorMessage: string | null): void {\n const cleanPath = fieldPath.replace(/^\\//, \"\");\n if (!this.validationLedger.has(cleanPath)) {\n this.validationLedger.set(cleanPath, { schemaError: null, policyError: null });\n }\n this.validationLedger.get(cleanPath)!.schemaError = errorMessage;\n this.resolveVisualState(cleanPath);\n }\n\n /**\n * Reports a cross-field policy error to the coordinator ledger.\n */\n public reportPolicyError(fieldPath: string, errorMessage: string | null): void {\n const cleanPath = fieldPath.replace(/^\\//, \"\");\n if (!this.validationLedger.has(cleanPath)) {\n this.validationLedger.set(cleanPath, { schemaError: null, policyError: null });\n }\n this.validationLedger.get(cleanPath)!.policyError = errorMessage;\n this.resolveVisualState(cleanPath);\n }\n\n /**\n * Computes the final visual state by checking both engines and applies it to the plugin.\n */\n private resolveVisualState(cleanPath: string): void {\n const plugin = this.getPluginByPath(cleanPath);\n const ledgerEntry = this.validationLedger.get(cleanPath);\n if (!ledgerEntry) return;\n\n const isError = ledgerEntry.policyError !== null || ledgerEntry.schemaError !== null;\n const errorMessage = ledgerEntry.policyError || ledgerEntry.schemaError;\n\n if (plugin && typeof plugin.setVisualValidationState === \"function\") {\n plugin.setVisualValidationState(!isError, isError ? errorMessage || undefined : undefined);\n } else {\n // Un-tracked template clones (Table Layout rows)\n this.setNativeControlError(cleanPath, isError ? errorMessage || undefined : undefined);\n }\n\n if (this.useMessageManager) {\n const currentMsg = this.activeMessages.get(cleanPath);\n if (currentMsg) {\n Messaging.removeMessages(currentMsg);\n this.activeMessages.delete(cleanPath);\n }\n if (isError) {\n const targetPath = `/${cleanPath}`;\n const processorModel = this.host && typeof (this.host as any).getStateManager === \"function\" \n ? (this.host as any).getStateManager()?.getModel() \n : undefined;\n \n const fieldLabel = typeof plugin?.getFieldLabel === \"function\" ? plugin.getFieldLabel() : undefined;\n const displayLabel = fieldLabel || cleanPath;\n const displayText = `Field '${displayLabel}': ${errorMessage || \"Validation Error\"}`;\n \n const newMsg = new Message({\n message: displayText,\n additionalText: displayLabel !== targetPath ? displayLabel : undefined,\n type: coreLibrary.MessageType.Error,\n target: targetPath,\n processor: processorModel\n });\n Messaging.addMessages(newMsg);\n this.activeMessages.set(cleanPath, newMsg);\n }\n }\n }\n\n private setNativeControlError(targetPath: string, errorMessage?: string): void {\n if (this.host && (this.host as any).generatedContent) {\n const rootControl = (this.host as any).generatedContent;\n this.traverseAndSetError(rootControl, targetPath, errorMessage);\n }\n }\n\n private traverseAndSetError(control: any, targetPath: string, errorMessage?: string): void {\n if (!control) return;\n \n const bindingInfos = [control.getBindingInfo(\"value\"), control.getBindingInfo(\"selectedKey\"), control.getBindingInfo(\"dateValue\"), control.getBindingInfo(\"selected\")];\n for (const info of bindingInfos) {\n if (info && info.parts && info.parts.length > 0) {\n const boundPath = info.parts[0].path;\n // UI5 relative bindings drop the leading slash in the context, but retain it in the path\n if (boundPath === targetPath || targetPath.endsWith(boundPath)) {\n // Ensure we match the exact row context path\n const context = control.getBindingContext((this.host as any).activeModelName);\n if (context) {\n const fullPath = context.getPath() + \"/\" + boundPath;\n const cleanedFullPath = fullPath.replace(/^\\//, \"\");\n if (cleanedFullPath === targetPath) {\n if (typeof control.setValueState === \"function\") {\n control.setValueState(errorMessage ? \"Error\" : \"None\");\n if (typeof control.setValueStateText === \"function\") {\n control.setValueStateText(errorMessage || \"\");\n }\n }\n }\n }\n }\n }\n }\n \n if (typeof control.getAggregation === \"function\" && typeof control.getMetadata === \"function\") {\n const aggs = control.getMetadata().getAggregations();\n for (const aggName in aggs) {\n const child = control.getAggregation(aggName);\n if (Array.isArray(child)) {\n child.forEach(c => this.traverseAndSetError(c, targetPath, errorMessage));\n } else if (child) {\n this.traverseAndSetError(child, targetPath, errorMessage);\n }\n }\n }\n }\n\n /**\n * Cleans up internal state and destroys the condition engine to prevent memory leaks.\n */\n public destroy(): void {\n\n\n for (const item of this.activePlugins) {\n if (typeof item.plugin.destroy === \"function\") {\n item.plugin.destroy();\n }\n }\n\n for (const item of this.templatePlugins) {\n if (typeof item.plugin.destroy === \"function\") {\n item.plugin.destroy();\n }\n }\n\n if (this.useMessageManager && this.activeMessages.size > 0) {\n Messaging.removeMessages(Array.from(this.activeMessages.values()));\n }\n\n this.validationLedger.clear();\n this.activeMessages.clear();\n this.activePlugins = [];\n this.templatePlugins = [];\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -15,6 +15,8 @@ import { Logger } from "../utils/Logger";
15
15
  import { DefaultLayoutGenerator } from "./DefaultLayoutGenerator";
16
16
  import Core from "sap/ui/core/Core";
17
17
  import Messaging from "sap/ui/core/Messaging";
18
+ import Message from "sap/ui/core/message/Message";
19
+ import coreLibrary from "sap/ui/core/library";
18
20
  import { GlobalPipeline } from "./PipelineManager";
19
21
 
20
22
  /**
@@ -44,6 +46,9 @@ export class Engine {
44
46
  /** Ledger tracking local vs cross-field errors to prevent visual race conditions. */
45
47
  private validationLedger: Map<string, { schemaError: string | null, policyError: string | null }> = new Map();
46
48
 
49
+ /** Tracks active MessageManager messages created by this engine instance. */
50
+ private activeMessages: Map<string, Message> = new Map();
51
+
47
52
  /** Reference to the GeneratorHost that instantiated this engine, for retrieving global definitions. */
48
53
  public host?: unknown;
49
54
 
@@ -360,6 +365,34 @@ export class Engine {
360
365
  // Un-tracked template clones (Table Layout rows)
361
366
  this.setNativeControlError(cleanPath, isError ? errorMessage || undefined : undefined);
362
367
  }
368
+
369
+ if (this.useMessageManager) {
370
+ const currentMsg = this.activeMessages.get(cleanPath);
371
+ if (currentMsg) {
372
+ Messaging.removeMessages(currentMsg);
373
+ this.activeMessages.delete(cleanPath);
374
+ }
375
+ if (isError) {
376
+ const targetPath = `/${cleanPath}`;
377
+ const processorModel = this.host && typeof (this.host as any).getStateManager === "function"
378
+ ? (this.host as any).getStateManager()?.getModel()
379
+ : undefined;
380
+
381
+ const fieldLabel = typeof plugin?.getFieldLabel === "function" ? plugin.getFieldLabel() : undefined;
382
+ const displayLabel = fieldLabel || cleanPath;
383
+ const displayText = `Field '${displayLabel}': ${errorMessage || "Validation Error"}`;
384
+
385
+ const newMsg = new Message({
386
+ message: displayText,
387
+ additionalText: displayLabel !== targetPath ? displayLabel : undefined,
388
+ type: coreLibrary.MessageType.Error,
389
+ target: targetPath,
390
+ processor: processorModel
391
+ });
392
+ Messaging.addMessages(newMsg);
393
+ this.activeMessages.set(cleanPath, newMsg);
394
+ }
395
+ }
363
396
  }
364
397
 
365
398
  private setNativeControlError(targetPath: string, errorMessage?: string): void {
@@ -427,7 +460,12 @@ export class Engine {
427
460
  }
428
461
  }
429
462
 
463
+ if (this.useMessageManager && this.activeMessages.size > 0) {
464
+ Messaging.removeMessages(Array.from(this.activeMessages.values()));
465
+ }
466
+
430
467
  this.validationLedger.clear();
468
+ this.activeMessages.clear();
431
469
  this.activePlugins = [];
432
470
  this.templatePlugins = [];
433
471
  }
@@ -8,8 +8,6 @@ sap.ui.define(["./PluginRegistry", "../utils/Logger"], function (___PluginRegist
8
8
  * It operates strictly on the JSON payload structure and returns an array of `IDeltaState` mutations which the GeneratorHost
9
9
  * then applies to the individual active plugins.
10
10
  *
11
- * It ensures the orchestration of conditional rendering, requiring, and invalidating of fields without the plugins
12
- * needing to be aware of each other.
13
11
  *
14
12
  * @namespace nz.co.siliconst.ui5.metaui.core
15
13
  */
@@ -23,59 +21,6 @@ sap.ui.define(["./PluginRegistry", "../utils/Logger"], function (___PluginRegist
23
21
  constructor(policies) {
24
22
  this.policies = policies || [];
25
23
  this.lastStateMatrix = new Map();
26
- this.detectCycles();
27
- }
28
-
29
- /**
30
- * Builds a directed dependency graph and detects cycles to prevent infinite event loops.
31
- */
32
- detectCycles() {
33
- const graph = new Map();
34
- for (const policy of this.policies) {
35
- const sources = new Set();
36
- if (policy.condition) {
37
- const addPaths = obj => {
38
- if (obj) Object.keys(obj).forEach(k => sources.add(k.split("/$row")[0]));
39
- };
40
- addPaths(policy.condition.NumericGreaterThan);
41
- addPaths(policy.condition.NumericLessThan);
42
- addPaths(policy.condition.StringEquals);
43
- if (policy.condition.IsNull) policy.condition.IsNull.forEach(p => sources.add(p.split("/$row")[0]));
44
- if (policy.condition.IsNotNull) policy.condition.IsNotNull.forEach(p => sources.add(p.split("/$row")[0]));
45
- }
46
- for (const target of policy.targets) {
47
- const cleanTarget = target.split("/$row")[0];
48
- if (!graph.has(cleanTarget)) {
49
- graph.set(cleanTarget, new Set());
50
- }
51
- sources.forEach(s => graph.get(cleanTarget).add(s));
52
- }
53
- }
54
- const visited = new Set();
55
- const recursionStack = new Set();
56
- const isCyclic = node => {
57
- if (!visited.has(node)) {
58
- visited.add(node);
59
- recursionStack.add(node);
60
- const neighbors = graph.get(node);
61
- if (neighbors) {
62
- for (const neighbor of neighbors) {
63
- if (!visited.has(neighbor) && isCyclic(neighbor)) {
64
- return true;
65
- } else if (recursionStack.has(neighbor)) {
66
- return true;
67
- }
68
- }
69
- }
70
- }
71
- recursionStack.delete(node);
72
- return false;
73
- };
74
- for (const node of graph.keys()) {
75
- if (isCyclic(node)) {
76
- throw new Error(`[MetaUI PolicyEngine] FATAL: Cyclic dependency detected involving policy target '${node}'. This will cause an infinite rendering loop.`);
77
- }
78
- }
79
24
  }
80
25
 
81
26
  /**
@@ -126,53 +71,27 @@ sap.ui.define(["./PluginRegistry", "../utils/Logger"], function (___PluginRegist
126
71
 
127
72
  /**
128
73
  * Expands relative $row policies into absolute index policies for each physical row.
74
+ * Uses generic stringification to decouple from specific condition operator plugins.
129
75
  */
130
76
  expandRowPolicies(data, policies) {
131
77
  const expanded = [];
132
78
  for (const policy of policies) {
133
- let hasRow = false;
134
- let arrayPath = "";
135
- for (const target of policy.targets) {
136
- if (target.includes("$row")) {
137
- hasRow = true;
138
- arrayPath = target.split("/$row")[0];
139
- break;
140
- }
141
- }
142
- if (!hasRow && policy.condition) {
143
- const checkPaths = obj => {
144
- if (!obj) return;
145
- for (const key of Object.keys(obj)) {
146
- if (key.includes("$row")) {
147
- hasRow = true;
148
- arrayPath = key.split("/$row")[0];
149
- break;
79
+ const policyStr = JSON.stringify(policy);
80
+ if (policyStr.includes("$row")) {
81
+ // Extract the array path (everything before "/$row" inside a JSON string value)
82
+ const match = policyStr.match(/"([^"]+)\/\$row/);
83
+ if (match) {
84
+ const arrayPath = match[1];
85
+ const arrayData = this.resolvePointer(data, arrayPath);
86
+ if (Array.isArray(arrayData)) {
87
+ for (let i = 0; i < arrayData.length; i++) {
88
+ const cloneStr = policyStr.replace(/\$row/g, String(i));
89
+ expanded.push(JSON.parse(cloneStr));
150
90
  }
151
91
  }
152
- };
153
- checkPaths(policy.condition.NumericGreaterThan);
154
- checkPaths(policy.condition.NumericLessThan);
155
- checkPaths(policy.condition.StringEquals);
156
- if (policy.condition.IsNull) policy.condition.IsNull.forEach(p => {
157
- if (p.includes("$row")) {
158
- hasRow = true;
159
- arrayPath = p.split("/$row")[0];
160
- }
161
- });
162
- if (policy.condition.IsNotNull) policy.condition.IsNotNull.forEach(p => {
163
- if (p.includes("$row")) {
164
- hasRow = true;
165
- arrayPath = p.split("/$row")[0];
166
- }
167
- });
168
- }
169
- if (hasRow && arrayPath) {
170
- const arrayData = this.resolvePointer(data, arrayPath);
171
- if (Array.isArray(arrayData)) {
172
- for (let i = 0; i < arrayData.length; i++) {
173
- const cloneStr = JSON.stringify(policy).replace(/\$row/g, String(i));
174
- expanded.push(JSON.parse(cloneStr));
175
- }
92
+ } else {
93
+ // Fallback if path couldn't be parsed
94
+ expanded.push(policy);
176
95
  }
177
96
  } else {
178
97
  expanded.push(policy);
@@ -1 +1 @@
1
- {"version":3,"file":"PolicyEngine-dbg.js","names":["PluginRegistry","___PluginRegistry","Logger","___utils_Logger","PolicyEngine","constructor","policies","lastStateMatrix","Map","detectCycles","graph","policy","sources","Set","condition","addPaths","obj","Object","keys","forEach","k","add","split","NumericGreaterThan","NumericLessThan","StringEquals","IsNull","p","IsNotNull","target","targets","cleanTarget","has","set","s","get","visited","recursionStack","isCyclic","node","neighbors","neighbor","delete","Error","resolvePointer","data","pointer","undefined","cleanPointer","replace","parts","current","part","evaluateCondition","result","registry","getInstance","key","payload","entries","plugin","getPolicyConditionPlugin","evaluate","bind","warn","expandRowPolicies","expanded","hasRow","arrayPath","includes","checkPaths","arrayData","Array","isArray","i","length","cloneStr","JSON","stringify","String","push","parse","expandedPolicies","ledger","initTargetInLedger","visibility","forcedFalse","forcedTrue","validity","required","editable","isConditionMet","currentLedger","effectPlugin","getPolicyEffectPlugin","effect","error","mapped","resolveState","value","property","message","lastMessage","newStateMatrix","stateMap","errorMessage","deltas","newState","lastState","__exports","__esModule"],"sources":["PolicyEngine.ts"],"sourcesContent":["import { IPolicy, IPolicyCondition, PolicyEffectType } from \"../interfaces/ISchema\";\nimport { PluginRegistry } from \"./PluginRegistry\";\nimport { Logger } from \"../utils/Logger\";\n\nexport type PropertyName = \"visibility\" | \"validity\" | \"required\" | \"editable\";\n\nexport interface IDeltaState {\n /** The absolute JSON pointer path of the target property (e.g., \"/VisitorInfo/PassportNumber\") */\n target: string;\n /** The UI5 visual or structural state to mutate */\n property: PropertyName;\n /** The boolean value to apply to the state */\n value: boolean;\n /** An optional custom error message to paint onto the field if validity is false */\n errorMessage?: string;\n}\n\ninterface ITargetState {\n visibility?: boolean;\n validity?: boolean;\n required?: boolean;\n editable?: boolean;\n errorMessage?: string;\n}\n\n/**\n * The PolicyEngine is responsible for evaluating complex, cross-field conditional logic defined in the schema's `uiPolicies` array.\n * It operates strictly on the JSON payload structure and returns an array of `IDeltaState` mutations which the GeneratorHost\n * then applies to the individual active plugins.\n * \n * It ensures the orchestration of conditional rendering, requiring, and invalidating of fields without the plugins\n * needing to be aware of each other.\n * \n * @namespace nz.co.siliconst.ui5.metaui.core\n */\nexport class PolicyEngine {\n private policies: IPolicy[];\n \n /** Caches the last computed state matrix for differential delta emission */\n private lastStateMatrix: Map<string, ITargetState>;\n\n /**\n * Instantiates the PolicyEngine with an array of policies.\n * @param policies Array of uiPolicies defined in the root schema.\n */\n constructor(policies: IPolicy[]) {\n this.policies = policies || [];\n this.lastStateMatrix = new Map();\n this.detectCycles();\n }\n\n /**\n * Builds a directed dependency graph and detects cycles to prevent infinite event loops.\n */\n private detectCycles(): void {\n const graph = new Map<string, Set<string>>();\n\n for (const policy of this.policies) {\n const sources = new Set<string>();\n if (policy.condition) {\n const addPaths = (obj: Record<string, unknown> | undefined) => {\n if (obj) Object.keys(obj).forEach(k => sources.add(k.split(\"/$row\")[0]));\n };\n addPaths(policy.condition.NumericGreaterThan);\n addPaths(policy.condition.NumericLessThan);\n addPaths(policy.condition.StringEquals);\n if (policy.condition.IsNull) policy.condition.IsNull.forEach(p => sources.add(p.split(\"/$row\")[0]));\n if (policy.condition.IsNotNull) policy.condition.IsNotNull.forEach(p => sources.add(p.split(\"/$row\")[0]));\n }\n\n for (const target of policy.targets) {\n const cleanTarget = target.split(\"/$row\")[0];\n if (!graph.has(cleanTarget)) {\n graph.set(cleanTarget, new Set());\n }\n sources.forEach(s => graph.get(cleanTarget)!.add(s));\n }\n }\n\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n\n const isCyclic = (node: string): boolean => {\n if (!visited.has(node)) {\n visited.add(node);\n recursionStack.add(node);\n\n const neighbors = graph.get(node);\n if (neighbors) {\n for (const neighbor of neighbors) {\n if (!visited.has(neighbor) && isCyclic(neighbor)) {\n return true;\n } else if (recursionStack.has(neighbor)) {\n return true;\n }\n }\n }\n }\n recursionStack.delete(node);\n return false;\n };\n\n for (const node of graph.keys()) {\n if (isCyclic(node)) {\n throw new Error(`[MetaUI PolicyEngine] FATAL: Cyclic dependency detected involving policy target '${node}'. This will cause an infinite rendering loop.`);\n }\n }\n }\n\n /**\n * Safely traverses a JSON payload using a JSON pointer.\n * Handles UI5 model prefixes (like metaui>) seamlessly.\n * \n * @param data The root JSON object representing the form payload.\n * @param pointer The JSON pointer to traverse (e.g., \"/Customer/Age\").\n * @returns The resolved value, or undefined if the path does not exist.\n */\n private resolvePointer(data: unknown, pointer: string): unknown {\n if (!data || !pointer) return undefined;\n // Strip leading slash and any UI5 prefixes\n const cleanPointer = pointer.replace(/^\\//, \"\").replace(/^metaui>\\/?/, \"\");\n if (!cleanPointer) return data;\n \n const parts = cleanPointer.split(\"/\");\n let current = data as Record<string, unknown>;\n for (const part of parts) {\n if (current === undefined || current === null) return undefined;\n current = current[part] as Record<string, unknown>;\n }\n return current;\n }\n\n /**\n * Evaluates a complex condition tree against the live JSON payload.\n * \n * @param condition The condition block to evaluate.\n * @param data The live JSON payload from the StateManager.\n * @returns True if all condition parameters are met, otherwise false.\n */\n private evaluateCondition(condition: IPolicyCondition, data: unknown): boolean {\n // If there are multiple operators, we treat them as AND for now\n let result = true;\n const registry = PluginRegistry.getInstance();\n\n for (const [key, payload] of Object.entries(condition)) {\n const plugin = registry.getPolicyConditionPlugin(key);\n if (plugin) {\n if (!plugin.evaluate(payload, data, this.resolvePointer.bind(this))) {\n result = false;\n }\n } else {\n Logger.warn(`[MetaUI PolicyEngine] Unrecognized condition operator: ${key}`);\n }\n }\n\n return result;\n }\n\n /**\n * Expands relative $row policies into absolute index policies for each physical row.\n */\n private expandRowPolicies(data: unknown, policies: IPolicy[]): IPolicy[] {\n const expanded: IPolicy[] = [];\n for (const policy of policies) {\n let hasRow = false;\n let arrayPath = \"\";\n \n for (const target of policy.targets) {\n if (target.includes(\"$row\")) {\n hasRow = true;\n arrayPath = target.split(\"/$row\")[0];\n break;\n }\n }\n if (!hasRow && policy.condition) {\n const checkPaths = (obj: any) => {\n if (!obj) return;\n for (const key of Object.keys(obj)) {\n if (key.includes(\"$row\")) {\n hasRow = true;\n arrayPath = key.split(\"/$row\")[0];\n break;\n }\n }\n };\n checkPaths(policy.condition.NumericGreaterThan);\n checkPaths(policy.condition.NumericLessThan);\n checkPaths(policy.condition.StringEquals);\n \n if (policy.condition.IsNull) policy.condition.IsNull.forEach(p => { if (p.includes(\"$row\")) { hasRow = true; arrayPath = p.split(\"/$row\")[0]; } });\n if (policy.condition.IsNotNull) policy.condition.IsNotNull.forEach(p => { if (p.includes(\"$row\")) { hasRow = true; arrayPath = p.split(\"/$row\")[0]; } });\n }\n\n if (hasRow && arrayPath) {\n const arrayData = this.resolvePointer(data, arrayPath);\n if (Array.isArray(arrayData)) {\n for (let i = 0; i < arrayData.length; i++) {\n const cloneStr = JSON.stringify(policy).replace(/\\$row/g, String(i));\n expanded.push(JSON.parse(cloneStr));\n }\n }\n } else {\n expanded.push(policy);\n }\n }\n return expanded;\n }\n\n /**\n * Evaluates policies against the given data payload using a State Resolution Matrix.\n * @param data The JSON data payload.\n * @returns Array of delta states to apply to the UI.\n */\n public evaluate(data: unknown): IDeltaState[] {\n if (!this.policies || this.policies.length === 0) {\n return [];\n }\n\n const expandedPolicies = this.expandRowPolicies(data, this.policies);\n\n // Ledger: target -> property -> { forcedFalse: number, forcedTrue: number, lastMessage?: string }\n const ledger = new Map<string, Record<PropertyName, { forcedFalse: number, forcedTrue: number, lastMessage?: string }>>();\n\n const initTargetInLedger = (target: string) => {\n if (!ledger.has(target)) {\n ledger.set(target, {\n visibility: { forcedFalse: 0, forcedTrue: 0 },\n validity: { forcedFalse: 0, forcedTrue: 0 },\n required: { forcedFalse: 0, forcedTrue: 0 },\n editable: { forcedFalse: 0, forcedTrue: 0 }\n });\n }\n };\n\n // 1. Build the Composite State Ledger Matrix\n for (const policy of expandedPolicies) {\n const isConditionMet = this.evaluateCondition(policy.condition, data);\n \n for (const target of policy.targets) {\n initTargetInLedger(target);\n const currentLedger = ledger.get(target)!;\n \n const effectPlugin = PluginRegistry.getInstance().getPolicyEffectPlugin(policy.effect);\n if (!effectPlugin) {\n Logger.error(`[MetaUI PolicyEngine] Unrecognized policy effect: ${policy.effect}`);\n continue;\n }\n const mapped = effectPlugin.resolveState(isConditionMet, policy.effect);\n \n // Track forces. For restrictable properties (visibility, validity, editable), forcedFalse acts as a lock.\n // For required, forcedTrue acts as a lock.\n if (mapped.value) {\n currentLedger[mapped.property].forcedTrue++;\n } else {\n currentLedger[mapped.property].forcedFalse++;\n if (mapped.property === \"validity\" && isConditionMet && policy.message) {\n currentLedger.validity.lastMessage = policy.message;\n }\n }\n }\n }\n\n const newStateMatrix = new Map<string, ITargetState>();\n\n // 2. Resolve the Ledger into a concrete State Matrix\n for (const [target, stateMap] of ledger.entries()) {\n newStateMatrix.set(target, {\n // False (Hidden) wins if ANY policy forced it false\n visibility: stateMap.visibility.forcedFalse > 0 ? false : true,\n // False (Invalid) wins if ANY policy forced it false\n validity: stateMap.validity.forcedFalse > 0 ? false : true,\n // True (Required) wins if ANY policy forced it true\n required: stateMap.required.forcedTrue > 0 ? true : false,\n // False (Disabled) wins if ANY policy forced it false\n editable: stateMap.editable.forcedFalse > 0 ? false : true,\n errorMessage: stateMap.validity.lastMessage\n });\n }\n\n const deltas: IDeltaState[] = [];\n\n // 3. Differential Emission\n for (const [target, newState] of newStateMatrix.entries()) {\n const lastState = this.lastStateMatrix.get(target) || {};\n\n if (newState.visibility !== undefined && newState.visibility !== lastState.visibility) {\n deltas.push({ target, property: \"visibility\", value: newState.visibility });\n }\n if (newState.validity !== undefined && newState.validity !== lastState.validity) {\n if (newState.validity !== lastState.validity || newState.errorMessage !== lastState.errorMessage) {\n deltas.push({ target, property: \"validity\", value: newState.validity, errorMessage: newState.errorMessage });\n }\n }\n if (newState.required !== undefined && newState.required !== lastState.required) {\n deltas.push({ target, property: \"required\", value: newState.required });\n }\n if (newState.editable !== undefined && newState.editable !== lastState.editable) {\n deltas.push({ target, property: \"editable\", value: newState.editable });\n }\n }\n\n // Cache for next evaluation sweep\n this.lastStateMatrix = newStateMatrix;\n\n return deltas;\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"PolicyEngine-dbg.js","names":["PluginRegistry","___PluginRegistry","Logger","___utils_Logger","PolicyEngine","constructor","policies","lastStateMatrix","Map","resolvePointer","data","pointer","undefined","cleanPointer","replace","parts","split","current","part","evaluateCondition","condition","result","registry","getInstance","key","payload","Object","entries","plugin","getPolicyConditionPlugin","evaluate","bind","warn","expandRowPolicies","expanded","policy","policyStr","JSON","stringify","includes","match","arrayPath","arrayData","Array","isArray","i","length","cloneStr","String","push","parse","expandedPolicies","ledger","initTargetInLedger","target","has","set","visibility","forcedFalse","forcedTrue","validity","required","editable","isConditionMet","targets","currentLedger","get","effectPlugin","getPolicyEffectPlugin","effect","error","mapped","resolveState","value","property","message","lastMessage","newStateMatrix","stateMap","errorMessage","deltas","newState","lastState","__exports","__esModule"],"sources":["PolicyEngine.ts"],"sourcesContent":["import { IPolicy, IPolicyCondition, PolicyEffectType } from \"../interfaces/ISchema\";\nimport { PluginRegistry } from \"./PluginRegistry\";\nimport { Logger } from \"../utils/Logger\";\n\nexport type PropertyName = \"visibility\" | \"validity\" | \"required\" | \"editable\";\n\nexport interface IDeltaState {\n /** The absolute JSON pointer path of the target property (e.g., \"/VisitorInfo/PassportNumber\") */\n target: string;\n /** The UI5 visual or structural state to mutate */\n property: PropertyName;\n /** The boolean value to apply to the state */\n value: boolean;\n /** An optional custom error message to paint onto the field if validity is false */\n errorMessage?: string;\n}\n\ninterface ITargetState {\n visibility?: boolean;\n validity?: boolean;\n required?: boolean;\n editable?: boolean;\n errorMessage?: string;\n}\n\n/**\n * The PolicyEngine is responsible for evaluating complex, cross-field conditional logic defined in the schema's `uiPolicies` array.\n * It operates strictly on the JSON payload structure and returns an array of `IDeltaState` mutations which the GeneratorHost\n * then applies to the individual active plugins.\n * \n * \n * @namespace nz.co.siliconst.ui5.metaui.core\n */\nexport class PolicyEngine {\n private policies: IPolicy[];\n\n /** Caches the last computed state matrix for differential delta emission */\n private lastStateMatrix: Map<string, ITargetState>;\n\n /**\n * Instantiates the PolicyEngine with an array of policies.\n * @param policies Array of uiPolicies defined in the root schema.\n */\n constructor(policies: IPolicy[]) {\n this.policies = policies || [];\n this.lastStateMatrix = new Map();\n }\n\n /**\n * Safely traverses a JSON payload using a JSON pointer.\n * Handles UI5 model prefixes (like metaui>) seamlessly.\n * \n * @param data The root JSON object representing the form payload.\n * @param pointer The JSON pointer to traverse (e.g., \"/Customer/Age\").\n * @returns The resolved value, or undefined if the path does not exist.\n */\n private resolvePointer(data: unknown, pointer: string): unknown {\n if (!data || !pointer) return undefined;\n // Strip leading slash and any UI5 prefixes\n const cleanPointer = pointer.replace(/^\\//, \"\").replace(/^metaui>\\/?/, \"\");\n if (!cleanPointer) return data;\n\n const parts = cleanPointer.split(\"/\");\n let current = data as Record<string, unknown>;\n for (const part of parts) {\n if (current === undefined || current === null) return undefined;\n current = current[part] as Record<string, unknown>;\n }\n return current;\n }\n\n /**\n * Evaluates a complex condition tree against the live JSON payload.\n * \n * @param condition The condition block to evaluate.\n * @param data The live JSON payload from the StateManager.\n * @returns True if all condition parameters are met, otherwise false.\n */\n private evaluateCondition(condition: IPolicyCondition, data: unknown): boolean {\n // If there are multiple operators, we treat them as AND for now\n let result = true;\n const registry = PluginRegistry.getInstance();\n\n for (const [key, payload] of Object.entries(condition)) {\n const plugin = registry.getPolicyConditionPlugin(key);\n if (plugin) {\n if (!plugin.evaluate(payload, data, this.resolvePointer.bind(this))) {\n result = false;\n }\n } else {\n Logger.warn(`[MetaUI PolicyEngine] Unrecognized condition operator: ${key}`);\n }\n }\n\n return result;\n }\n\n /**\n * Expands relative $row policies into absolute index policies for each physical row.\n * Uses generic stringification to decouple from specific condition operator plugins.\n */\n private expandRowPolicies(data: unknown, policies: IPolicy[]): IPolicy[] {\n const expanded: IPolicy[] = [];\n for (const policy of policies) {\n const policyStr = JSON.stringify(policy);\n if (policyStr.includes(\"$row\")) {\n // Extract the array path (everything before \"/$row\" inside a JSON string value)\n const match = policyStr.match(/\"([^\"]+)\\/\\$row/);\n if (match) {\n const arrayPath = match[1];\n const arrayData = this.resolvePointer(data, arrayPath);\n if (Array.isArray(arrayData)) {\n for (let i = 0; i < arrayData.length; i++) {\n const cloneStr = policyStr.replace(/\\$row/g, String(i));\n expanded.push(JSON.parse(cloneStr));\n }\n }\n } else {\n // Fallback if path couldn't be parsed\n expanded.push(policy);\n }\n } else {\n expanded.push(policy);\n }\n }\n return expanded;\n }\n\n /**\n * Evaluates policies against the given data payload using a State Resolution Matrix.\n * @param data The JSON data payload.\n * @returns Array of delta states to apply to the UI.\n */\n public evaluate(data: unknown): IDeltaState[] {\n if (!this.policies || this.policies.length === 0) {\n return [];\n }\n\n const expandedPolicies = this.expandRowPolicies(data, this.policies);\n\n // Ledger: target -> property -> { forcedFalse: number, forcedTrue: number, lastMessage?: string }\n const ledger = new Map<string, Record<PropertyName, { forcedFalse: number, forcedTrue: number, lastMessage?: string }>>();\n\n const initTargetInLedger = (target: string) => {\n if (!ledger.has(target)) {\n ledger.set(target, {\n visibility: { forcedFalse: 0, forcedTrue: 0 },\n validity: { forcedFalse: 0, forcedTrue: 0 },\n required: { forcedFalse: 0, forcedTrue: 0 },\n editable: { forcedFalse: 0, forcedTrue: 0 }\n });\n }\n };\n\n // 1. Build the Composite State Ledger Matrix\n for (const policy of expandedPolicies) {\n const isConditionMet = this.evaluateCondition(policy.condition, data);\n\n for (const target of policy.targets) {\n initTargetInLedger(target);\n const currentLedger = ledger.get(target)!;\n\n const effectPlugin = PluginRegistry.getInstance().getPolicyEffectPlugin(policy.effect);\n if (!effectPlugin) {\n Logger.error(`[MetaUI PolicyEngine] Unrecognized policy effect: ${policy.effect}`);\n continue;\n }\n const mapped = effectPlugin.resolveState(isConditionMet, policy.effect);\n\n // Track forces. For restrictable properties (visibility, validity, editable), forcedFalse acts as a lock.\n // For required, forcedTrue acts as a lock.\n if (mapped.value) {\n currentLedger[mapped.property].forcedTrue++;\n } else {\n currentLedger[mapped.property].forcedFalse++;\n if (mapped.property === \"validity\" && isConditionMet && policy.message) {\n currentLedger.validity.lastMessage = policy.message;\n }\n }\n }\n }\n\n const newStateMatrix = new Map<string, ITargetState>();\n\n // 2. Resolve the Ledger into a concrete State Matrix\n for (const [target, stateMap] of ledger.entries()) {\n newStateMatrix.set(target, {\n // False (Hidden) wins if ANY policy forced it false\n visibility: stateMap.visibility.forcedFalse > 0 ? false : true,\n // False (Invalid) wins if ANY policy forced it false\n validity: stateMap.validity.forcedFalse > 0 ? false : true,\n // True (Required) wins if ANY policy forced it true\n required: stateMap.required.forcedTrue > 0 ? true : false,\n // False (Disabled) wins if ANY policy forced it false\n editable: stateMap.editable.forcedFalse > 0 ? false : true,\n errorMessage: stateMap.validity.lastMessage\n });\n }\n\n const deltas: IDeltaState[] = [];\n\n // 3. Differential Emission\n for (const [target, newState] of newStateMatrix.entries()) {\n const lastState = this.lastStateMatrix.get(target) || {};\n\n if (newState.visibility !== undefined && newState.visibility !== lastState.visibility) {\n deltas.push({ target, property: \"visibility\", value: newState.visibility });\n }\n if (newState.validity !== undefined && newState.validity !== lastState.validity) {\n if (newState.validity !== lastState.validity || newState.errorMessage !== lastState.errorMessage) {\n deltas.push({ target, property: \"validity\", value: newState.validity, errorMessage: newState.errorMessage });\n }\n }\n if (newState.required !== undefined && newState.required !== lastState.required) {\n deltas.push({ target, property: \"required\", value: newState.required });\n }\n if (newState.editable !== undefined && newState.editable !== lastState.editable) {\n deltas.push({ target, property: \"editable\", value: newState.editable });\n }\n }\n\n // Cache for next evaluation sweep\n this.lastStateMatrix = newStateMatrix;\n\n return deltas;\n }\n}\n"],"mappings":";;;QACSA,cAAc,GAAAC,iBAAA;EAAA,MACdC,MAAM,GAAAC,eAAA;EAuBf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACO,MAAMC,YAAY,CAAC;IAGtB;;IAGA;AACJ;AACA;AACA;IACIC,WAAWA,CAACC,QAAmB,EAAE;MAC7B,IAAI,CAACA,QAAQ,GAAGA,QAAQ,IAAI,EAAE;MAC9B,IAAI,CAACC,eAAe,GAAG,IAAIC,GAAG,CAAC,CAAC;IACpC;;IAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;IACYC,cAAcA,CAACC,IAAa,EAAEC,OAAe,EAAW;MAC5D,IAAI,CAACD,IAAI,IAAI,CAACC,OAAO,EAAE,OAAOC,SAAS;MACvC;MACA,MAAMC,YAAY,GAAGF,OAAO,CAACG,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAACA,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;MAC1E,IAAI,CAACD,YAAY,EAAE,OAAOH,IAAI;MAE9B,MAAMK,KAAK,GAAGF,YAAY,CAACG,KAAK,CAAC,GAAG,CAAC;MACrC,IAAIC,OAAO,GAAGP,IAA+B;MAC7C,KAAK,MAAMQ,IAAI,IAAIH,KAAK,EAAE;QACtB,IAAIE,OAAO,KAAKL,SAAS,IAAIK,OAAO,KAAK,IAAI,EAAE,OAAOL,SAAS;QAC/DK,OAAO,GAAGA,OAAO,CAACC,IAAI,CAA4B;MACtD;MACA,OAAOD,OAAO;IAClB;;IAEA;AACJ;AACA;AACA;AACA;AACA;AACA;IACYE,iBAAiBA,CAACC,SAA2B,EAAEV,IAAa,EAAW;MAC3E;MACA,IAAIW,MAAM,GAAG,IAAI;MACjB,MAAMC,QAAQ,GAAGtB,cAAc,CAACuB,WAAW,CAAC,CAAC;MAE7C,KAAK,MAAM,CAACC,GAAG,EAAEC,OAAO,CAAC,IAAIC,MAAM,CAACC,OAAO,CAACP,SAAS,CAAC,EAAE;QACpD,MAAMQ,MAAM,GAAGN,QAAQ,CAACO,wBAAwB,CAACL,GAAG,CAAC;QACrD,IAAII,MAAM,EAAE;UACR,IAAI,CAACA,MAAM,CAACE,QAAQ,CAACL,OAAO,EAAEf,IAAI,EAAE,IAAI,CAACD,cAAc,CAACsB,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE;YACjEV,MAAM,GAAG,KAAK;UAClB;QACJ,CAAC,MAAM;UACHnB,MAAM,CAAC8B,IAAI,CAAC,0DAA0DR,GAAG,EAAE,CAAC;QAChF;MACJ;MAEA,OAAOH,MAAM;IACjB;;IAEA;AACJ;AACA;AACA;IACYY,iBAAiBA,CAACvB,IAAa,EAAEJ,QAAmB,EAAa;MACrE,MAAM4B,QAAmB,GAAG,EAAE;MAC9B,KAAK,MAAMC,MAAM,IAAI7B,QAAQ,EAAE;QAC3B,MAAM8B,SAAS,GAAGC,IAAI,CAACC,SAAS,CAACH,MAAM,CAAC;QACxC,IAAIC,SAAS,CAACG,QAAQ,CAAC,MAAM,CAAC,EAAE;UAC5B;UACA,MAAMC,KAAK,GAAGJ,SAAS,CAACI,KAAK,CAAC,iBAAiB,CAAC;UAChD,IAAIA,KAAK,EAAE;YACP,MAAMC,SAAS,GAAGD,KAAK,CAAC,CAAC,CAAC;YAC1B,MAAME,SAAS,GAAG,IAAI,CAACjC,cAAc,CAACC,IAAI,EAAE+B,SAAS,CAAC;YACtD,IAAIE,KAAK,CAACC,OAAO,CAACF,SAAS,CAAC,EAAE;cAC1B,KAAK,IAAIG,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGH,SAAS,CAACI,MAAM,EAAED,CAAC,EAAE,EAAE;gBACvC,MAAME,QAAQ,GAAGX,SAAS,CAACtB,OAAO,CAAC,QAAQ,EAAEkC,MAAM,CAACH,CAAC,CAAC,CAAC;gBACvDX,QAAQ,CAACe,IAAI,CAACZ,IAAI,CAACa,KAAK,CAACH,QAAQ,CAAC,CAAC;cACvC;YACJ;UACJ,CAAC,MAAM;YACH;YACAb,QAAQ,CAACe,IAAI,CAACd,MAAM,CAAC;UACzB;QACJ,CAAC,MAAM;UACHD,QAAQ,CAACe,IAAI,CAACd,MAAM,CAAC;QACzB;MACJ;MACA,OAAOD,QAAQ;IACnB;;IAEA;AACJ;AACA;AACA;AACA;IACWJ,QAAQA,CAACpB,IAAa,EAAiB;MAC1C,IAAI,CAAC,IAAI,CAACJ,QAAQ,IAAI,IAAI,CAACA,QAAQ,CAACwC,MAAM,KAAK,CAAC,EAAE;QAC9C,OAAO,EAAE;MACb;MAEA,MAAMK,gBAAgB,GAAG,IAAI,CAAClB,iBAAiB,CAACvB,IAAI,EAAE,IAAI,CAACJ,QAAQ,CAAC;;MAEpE;MACA,MAAM8C,MAAM,GAAG,IAAI5C,GAAG,CAAkG,CAAC;MAEzH,MAAM6C,kBAAkB,GAAIC,MAAc,IAAK;QAC3C,IAAI,CAACF,MAAM,CAACG,GAAG,CAACD,MAAM,CAAC,EAAE;UACrBF,MAAM,CAACI,GAAG,CAACF,MAAM,EAAE;YACfG,UAAU,EAAE;cAAEC,WAAW,EAAE,CAAC;cAAEC,UAAU,EAAE;YAAE,CAAC;YAC7CC,QAAQ,EAAE;cAAEF,WAAW,EAAE,CAAC;cAAEC,UAAU,EAAE;YAAE,CAAC;YAC3CE,QAAQ,EAAE;cAAEH,WAAW,EAAE,CAAC;cAAEC,UAAU,EAAE;YAAE,CAAC;YAC3CG,QAAQ,EAAE;cAAEJ,WAAW,EAAE,CAAC;cAAEC,UAAU,EAAE;YAAE;UAC9C,CAAC,CAAC;QACN;MACJ,CAAC;;MAED;MACA,KAAK,MAAMxB,MAAM,IAAIgB,gBAAgB,EAAE;QACnC,MAAMY,cAAc,GAAG,IAAI,CAAC5C,iBAAiB,CAACgB,MAAM,CAACf,SAAS,EAAEV,IAAI,CAAC;QAErE,KAAK,MAAM4C,MAAM,IAAInB,MAAM,CAAC6B,OAAO,EAAE;UACjCX,kBAAkB,CAACC,MAAM,CAAC;UAC1B,MAAMW,aAAa,GAAGb,MAAM,CAACc,GAAG,CAACZ,MAAM,CAAE;UAEzC,MAAMa,YAAY,GAAGnE,cAAc,CAACuB,WAAW,CAAC,CAAC,CAAC6C,qBAAqB,CAACjC,MAAM,CAACkC,MAAM,CAAC;UACtF,IAAI,CAACF,YAAY,EAAE;YACfjE,MAAM,CAACoE,KAAK,CAAC,qDAAqDnC,MAAM,CAACkC,MAAM,EAAE,CAAC;YAClF;UACJ;UACA,MAAME,MAAM,GAAGJ,YAAY,CAACK,YAAY,CAACT,cAAc,EAAE5B,MAAM,CAACkC,MAAM,CAAC;;UAEvE;UACA;UACA,IAAIE,MAAM,CAACE,KAAK,EAAE;YACdR,aAAa,CAACM,MAAM,CAACG,QAAQ,CAAC,CAACf,UAAU,EAAE;UAC/C,CAAC,MAAM;YACHM,aAAa,CAACM,MAAM,CAACG,QAAQ,CAAC,CAAChB,WAAW,EAAE;YAC5C,IAAIa,MAAM,CAACG,QAAQ,KAAK,UAAU,IAAIX,cAAc,IAAI5B,MAAM,CAACwC,OAAO,EAAE;cACpEV,aAAa,CAACL,QAAQ,CAACgB,WAAW,GAAGzC,MAAM,CAACwC,OAAO;YACvD;UACJ;QACJ;MACJ;MAEA,MAAME,cAAc,GAAG,IAAIrE,GAAG,CAAuB,CAAC;;MAEtD;MACA,KAAK,MAAM,CAAC8C,MAAM,EAAEwB,QAAQ,CAAC,IAAI1B,MAAM,CAACzB,OAAO,CAAC,CAAC,EAAE;QAC/CkD,cAAc,CAACrB,GAAG,CAACF,MAAM,EAAE;UACvB;UACAG,UAAU,EAAEqB,QAAQ,CAACrB,UAAU,CAACC,WAAW,GAAG,CAAC,GAAG,KAAK,GAAG,IAAI;UAC9D;UACAE,QAAQ,EAAEkB,QAAQ,CAAClB,QAAQ,CAACF,WAAW,GAAG,CAAC,GAAG,KAAK,GAAG,IAAI;UAC1D;UACAG,QAAQ,EAAEiB,QAAQ,CAACjB,QAAQ,CAACF,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,KAAK;UACzD;UACAG,QAAQ,EAAEgB,QAAQ,CAAChB,QAAQ,CAACJ,WAAW,GAAG,CAAC,GAAG,KAAK,GAAG,IAAI;UAC1DqB,YAAY,EAAED,QAAQ,CAAClB,QAAQ,CAACgB;QACpC,CAAC,CAAC;MACN;MAEA,MAAMI,MAAqB,GAAG,EAAE;;MAEhC;MACA,KAAK,MAAM,CAAC1B,MAAM,EAAE2B,QAAQ,CAAC,IAAIJ,cAAc,CAAClD,OAAO,CAAC,CAAC,EAAE;QACvD,MAAMuD,SAAS,GAAG,IAAI,CAAC3E,eAAe,CAAC2D,GAAG,CAACZ,MAAM,CAAC,IAAI,CAAC,CAAC;QAExD,IAAI2B,QAAQ,CAACxB,UAAU,KAAK7C,SAAS,IAAIqE,QAAQ,CAACxB,UAAU,KAAKyB,SAAS,CAACzB,UAAU,EAAE;UACnFuB,MAAM,CAAC/B,IAAI,CAAC;YAAEK,MAAM;YAAEoB,QAAQ,EAAE,YAAY;YAAED,KAAK,EAAEQ,QAAQ,CAACxB;UAAW,CAAC,CAAC;QAC/E;QACA,IAAIwB,QAAQ,CAACrB,QAAQ,KAAKhD,SAAS,IAAIqE,QAAQ,CAACrB,QAAQ,KAAKsB,SAAS,CAACtB,QAAQ,EAAE;UAC7E,IAAIqB,QAAQ,CAACrB,QAAQ,KAAKsB,SAAS,CAACtB,QAAQ,IAAIqB,QAAQ,CAACF,YAAY,KAAKG,SAAS,CAACH,YAAY,EAAE;YAC9FC,MAAM,CAAC/B,IAAI,CAAC;cAAEK,MAAM;cAAEoB,QAAQ,EAAE,UAAU;cAAED,KAAK,EAAEQ,QAAQ,CAACrB,QAAQ;cAAEmB,YAAY,EAAEE,QAAQ,CAACF;YAAa,CAAC,CAAC;UAChH;QACJ;QACA,IAAIE,QAAQ,CAACpB,QAAQ,KAAKjD,SAAS,IAAIqE,QAAQ,CAACpB,QAAQ,KAAKqB,SAAS,CAACrB,QAAQ,EAAE;UAC7EmB,MAAM,CAAC/B,IAAI,CAAC;YAAEK,MAAM;YAAEoB,QAAQ,EAAE,UAAU;YAAED,KAAK,EAAEQ,QAAQ,CAACpB;UAAS,CAAC,CAAC;QAC3E;QACA,IAAIoB,QAAQ,CAACnB,QAAQ,KAAKlD,SAAS,IAAIqE,QAAQ,CAACnB,QAAQ,KAAKoB,SAAS,CAACpB,QAAQ,EAAE;UAC7EkB,MAAM,CAAC/B,IAAI,CAAC;YAAEK,MAAM;YAAEoB,QAAQ,EAAE,UAAU;YAAED,KAAK,EAAEQ,QAAQ,CAACnB;UAAS,CAAC,CAAC;QAC3E;MACJ;;MAEA;MACA,IAAI,CAACvD,eAAe,GAAGsE,cAAc;MAErC,OAAOG,MAAM;IACjB;EACJ;EAAC,IAAAG,SAAA;IAAAC,UAAA;EAAA;EAAAD,SAAA,CAAA/E,YAAA,GAAAA,YAAA;EAAA,OAAA+E,SAAA;AAAA","ignoreList":[]}
@@ -23,8 +23,6 @@ declare module "nz/co/siliconst/ui5/metaui/core/PolicyEngine" {
23
23
  * It operates strictly on the JSON payload structure and returns an array of `IDeltaState` mutations which the GeneratorHost
24
24
  * then applies to the individual active plugins.
25
25
  *
26
- * It ensures the orchestration of conditional rendering, requiring, and invalidating of fields without the plugins
27
- * needing to be aware of each other.
28
26
  *
29
27
  * @namespace nz.co.siliconst.ui5.metaui.core
30
28
  */
@@ -37,10 +35,6 @@ declare module "nz/co/siliconst/ui5/metaui/core/PolicyEngine" {
37
35
  * @param policies Array of uiPolicies defined in the root schema.
38
36
  */
39
37
  constructor(policies: IPolicy[]);
40
- /**
41
- * Builds a directed dependency graph and detects cycles to prevent infinite event loops.
42
- */
43
- private detectCycles;
44
38
  /**
45
39
  * Safely traverses a JSON payload using a JSON pointer.
46
40
  * Handles UI5 model prefixes (like metaui>) seamlessly.
@@ -60,6 +54,7 @@ declare module "nz/co/siliconst/ui5/metaui/core/PolicyEngine" {
60
54
  private evaluateCondition;
61
55
  /**
62
56
  * Expands relative $row policies into absolute index policies for each physical row.
57
+ * Uses generic stringification to decouple from specific condition operator plugins.
63
58
  */
64
59
  private expandRowPolicies;
65
60
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"PolicyEngine.d.ts","sourceRoot":"../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,8CAA8C,CAAC;IAC9D,OAAO,EAAE,OAAO,EAAsC,MAAM,+CAA+C,CAAC;IAI5G,KAAY,YAAY,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IAE/E,UAAiB,WAAW;QACxB,kGAAkG;QAClG,MAAM,EAAE,MAAM,CAAC;QACf,mDAAmD;QACnD,QAAQ,EAAE,YAAY,CAAC;QACvB,8CAA8C;QAC9C,KAAK,EAAE,OAAO,CAAC;QACf,oFAAoF;QACpF,YAAY,CAAC,EAAE,MAAM,CAAC;KACzB;IAED,UAAU,YAAY;QAClB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;KACzB;IAED;;;;;;;;;OASG;IACH,MAAa,YAAY;QACrB,OAAO,CAAC,QAAQ,CAAY;QAE5B,4EAA4E;QAC5E,OAAO,CAAC,eAAe,CAA4B;QAEnD;;;WAGG;oBACS,QAAQ,EAAE,OAAO,EAAE;QAM/B;;WAEG;QACH,OAAO,CAAC,YAAY;QAuDpB;;;;;;;WAOG;QACH,OAAO,CAAC,cAAc;QAetB;;;;;;WAMG;QACH,OAAO,CAAC,iBAAiB;QAmBzB;;WAEG;QACH,OAAO,CAAC,iBAAiB;QA+CzB;;;;WAIG;QACI,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,EAAE;KA6FhD;CAEA"}
1
+ {"version":3,"file":"PolicyEngine.d.ts","sourceRoot":"../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/core/PolicyEngine.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,8CAA8C,CAAC;IAC9D,OAAO,EAAE,OAAO,EAAsC,MAAM,+CAA+C,CAAC;IAI5G,KAAY,YAAY,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IAE/E,UAAiB,WAAW;QACxB,kGAAkG;QAClG,MAAM,EAAE,MAAM,CAAC;QACf,mDAAmD;QACnD,QAAQ,EAAE,YAAY,CAAC;QACvB,8CAA8C;QAC9C,KAAK,EAAE,OAAO,CAAC;QACf,oFAAoF;QACpF,YAAY,CAAC,EAAE,MAAM,CAAC;KACzB;IAED,UAAU,YAAY;QAClB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;KACzB;IAED;;;;;;;OAOG;IACH,MAAa,YAAY;QACrB,OAAO,CAAC,QAAQ,CAAY;QAE5B,4EAA4E;QAC5E,OAAO,CAAC,eAAe,CAA4B;QAEnD;;;WAGG;oBACS,QAAQ,EAAE,OAAO,EAAE;QAK/B;;;;;;;WAOG;QACH,OAAO,CAAC,cAAc;QAetB;;;;;;WAMG;QACH,OAAO,CAAC,iBAAiB;QAmBzB;;;WAGG;QACH,OAAO,CAAC,iBAAiB;QA2BzB;;;;WAIG;QACI,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,EAAE;KA6FhD;CAEA"}
@@ -1,2 +1,2 @@
1
- sap.ui.define(["./PluginRegistry","../utils/Logger"],function(e,i){"use strict";const t=e["PluginRegistry"];const r=i["Logger"];class o{constructor(e){this.policies=e||[];this.lastStateMatrix=new Map;this.detectCycles()}detectCycles(){const e=new Map;for(const i of this.policies){const t=new Set;if(i.condition){const e=e=>{if(e)Object.keys(e).forEach(e=>t.add(e.split("/$row")[0]))};e(i.condition.NumericGreaterThan);e(i.condition.NumericLessThan);e(i.condition.StringEquals);if(i.condition.IsNull)i.condition.IsNull.forEach(e=>t.add(e.split("/$row")[0]));if(i.condition.IsNotNull)i.condition.IsNotNull.forEach(e=>t.add(e.split("/$row")[0]))}for(const r of i.targets){const i=r.split("/$row")[0];if(!e.has(i)){e.set(i,new Set)}t.forEach(t=>e.get(i).add(t))}}const i=new Set;const t=new Set;const r=o=>{if(!i.has(o)){i.add(o);t.add(o);const s=e.get(o);if(s){for(const e of s){if(!i.has(e)&&r(e)){return true}else if(t.has(e)){return true}}}}t.delete(o);return false};for(const i of e.keys()){if(r(i)){throw new Error(`[MetaUI PolicyEngine] FATAL: Cyclic dependency detected involving policy target '${i}'. This will cause an infinite rendering loop.`)}}}resolvePointer(e,i){if(!e||!i)return undefined;const t=i.replace(/^\//,"").replace(/^metaui>\/?/,"");if(!t)return e;const r=t.split("/");let o=e;for(const e of r){if(o===undefined||o===null)return undefined;o=o[e]}return o}evaluateCondition(e,i){let o=true;const s=t.getInstance();for(const[t,n]of Object.entries(e)){const e=s.getPolicyConditionPlugin(t);if(e){if(!e.evaluate(n,i,this.resolvePointer.bind(this))){o=false}}else{r.warn(`[MetaUI PolicyEngine] Unrecognized condition operator: ${t}`)}}return o}expandRowPolicies(e,i){const t=[];for(const r of i){let i=false;let o="";for(const e of r.targets){if(e.includes("$row")){i=true;o=e.split("/$row")[0];break}}if(!i&&r.condition){const e=e=>{if(!e)return;for(const t of Object.keys(e)){if(t.includes("$row")){i=true;o=t.split("/$row")[0];break}}};e(r.condition.NumericGreaterThan);e(r.condition.NumericLessThan);e(r.condition.StringEquals);if(r.condition.IsNull)r.condition.IsNull.forEach(e=>{if(e.includes("$row")){i=true;o=e.split("/$row")[0]}});if(r.condition.IsNotNull)r.condition.IsNotNull.forEach(e=>{if(e.includes("$row")){i=true;o=e.split("/$row")[0]}})}if(i&&o){const i=this.resolvePointer(e,o);if(Array.isArray(i)){for(let e=0;e<i.length;e++){const i=JSON.stringify(r).replace(/\$row/g,String(e));t.push(JSON.parse(i))}}}else{t.push(r)}}return t}evaluate(e){if(!this.policies||this.policies.length===0){return[]}const i=this.expandRowPolicies(e,this.policies);const o=new Map;const s=e=>{if(!o.has(e)){o.set(e,{visibility:{forcedFalse:0,forcedTrue:0},validity:{forcedFalse:0,forcedTrue:0},required:{forcedFalse:0,forcedTrue:0},editable:{forcedFalse:0,forcedTrue:0}})}};for(const n of i){const i=this.evaluateCondition(n.condition,e);for(const e of n.targets){s(e);const l=o.get(e);const c=t.getInstance().getPolicyEffectPlugin(n.effect);if(!c){r.error(`[MetaUI PolicyEngine] Unrecognized policy effect: ${n.effect}`);continue}const a=c.resolveState(i,n.effect);if(a.value){l[a.property].forcedTrue++}else{l[a.property].forcedFalse++;if(a.property==="validity"&&i&&n.message){l.validity.lastMessage=n.message}}}}const n=new Map;for(const[e,i]of o.entries()){n.set(e,{visibility:i.visibility.forcedFalse>0?false:true,validity:i.validity.forcedFalse>0?false:true,required:i.required.forcedTrue>0?true:false,editable:i.editable.forcedFalse>0?false:true,errorMessage:i.validity.lastMessage})}const l=[];for(const[e,i]of n.entries()){const t=this.lastStateMatrix.get(e)||{};if(i.visibility!==undefined&&i.visibility!==t.visibility){l.push({target:e,property:"visibility",value:i.visibility})}if(i.validity!==undefined&&i.validity!==t.validity){if(i.validity!==t.validity||i.errorMessage!==t.errorMessage){l.push({target:e,property:"validity",value:i.validity,errorMessage:i.errorMessage})}}if(i.required!==undefined&&i.required!==t.required){l.push({target:e,property:"required",value:i.required})}if(i.editable!==undefined&&i.editable!==t.editable){l.push({target:e,property:"editable",value:i.editable})}}this.lastStateMatrix=n;return l}}var s={__esModule:true};s.PolicyEngine=o;return s});
1
+ sap.ui.define(["./PluginRegistry","../utils/Logger"],function(e,i){"use strict";const t=e["PluginRegistry"];const r=i["Logger"];class s{constructor(e){this.policies=e||[];this.lastStateMatrix=new Map}resolvePointer(e,i){if(!e||!i)return undefined;const t=i.replace(/^\//,"").replace(/^metaui>\/?/,"");if(!t)return e;const r=t.split("/");let s=e;for(const e of r){if(s===undefined||s===null)return undefined;s=s[e]}return s}evaluateCondition(e,i){let s=true;const o=t.getInstance();for(const[t,n]of Object.entries(e)){const e=o.getPolicyConditionPlugin(t);if(e){if(!e.evaluate(n,i,this.resolvePointer.bind(this))){s=false}}else{r.warn(`[MetaUI PolicyEngine] Unrecognized condition operator: ${t}`)}}return s}expandRowPolicies(e,i){const t=[];for(const r of i){const i=JSON.stringify(r);if(i.includes("$row")){const s=i.match(/"([^"]+)\/\$row/);if(s){const r=s[1];const o=this.resolvePointer(e,r);if(Array.isArray(o)){for(let e=0;e<o.length;e++){const r=i.replace(/\$row/g,String(e));t.push(JSON.parse(r))}}}else{t.push(r)}}else{t.push(r)}}return t}evaluate(e){if(!this.policies||this.policies.length===0){return[]}const i=this.expandRowPolicies(e,this.policies);const s=new Map;const o=e=>{if(!s.has(e)){s.set(e,{visibility:{forcedFalse:0,forcedTrue:0},validity:{forcedFalse:0,forcedTrue:0},required:{forcedFalse:0,forcedTrue:0},editable:{forcedFalse:0,forcedTrue:0}})}};for(const n of i){const i=this.evaluateCondition(n.condition,e);for(const e of n.targets){o(e);const a=s.get(e);const l=t.getInstance().getPolicyEffectPlugin(n.effect);if(!l){r.error(`[MetaUI PolicyEngine] Unrecognized policy effect: ${n.effect}`);continue}const c=l.resolveState(i,n.effect);if(c.value){a[c.property].forcedTrue++}else{a[c.property].forcedFalse++;if(c.property==="validity"&&i&&n.message){a.validity.lastMessage=n.message}}}}const n=new Map;for(const[e,i]of s.entries()){n.set(e,{visibility:i.visibility.forcedFalse>0?false:true,validity:i.validity.forcedFalse>0?false:true,required:i.required.forcedTrue>0?true:false,editable:i.editable.forcedFalse>0?false:true,errorMessage:i.validity.lastMessage})}const a=[];for(const[e,i]of n.entries()){const t=this.lastStateMatrix.get(e)||{};if(i.visibility!==undefined&&i.visibility!==t.visibility){a.push({target:e,property:"visibility",value:i.visibility})}if(i.validity!==undefined&&i.validity!==t.validity){if(i.validity!==t.validity||i.errorMessage!==t.errorMessage){a.push({target:e,property:"validity",value:i.validity,errorMessage:i.errorMessage})}}if(i.required!==undefined&&i.required!==t.required){a.push({target:e,property:"required",value:i.required})}if(i.editable!==undefined&&i.editable!==t.editable){a.push({target:e,property:"editable",value:i.editable})}}this.lastStateMatrix=n;return a}}var o={__esModule:true};o.PolicyEngine=s;return o});
2
2
  //# sourceMappingURL=PolicyEngine.js.map