@telcomdataperu/zeus-vue-model-manager
Version:
Vue 3 Model Manager for Microfrontends with OpenUI5-style API - Part of ZEUS Platform by TelcomdataPeru
2 lines (1 loc) • 13 kB
JavaScript
(function(n,p){typeof exports=="object"&&typeof module<"u"?p(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],p):(n=typeof globalThis<"u"?globalThis:n||self,p(n.ZeusVueModelManager={},n.Vue))})(this,function(n,p){"use strict";class S{constructor(e,t={}){this.validators={},this.watchers=[],this.eventListeners={},this.changeCount=0,this.options={enableLogging:!1,enableValidation:!1,immutable:!1,pathSeparator:"/",...t},this.data=p.reactive(e),this.metadata={version:"1.0.0",created:new Date,lastModified:new Date,changeCount:0,paths:this.getAllPaths(this.data),size:JSON.stringify(this.data).length},this.options.enableLogging&&console.log("[JsonModel] Created with options:",this.options)}getData(){return this.data}getProperty(e){return e.replace(/^\//,"").split(this.options.pathSeparator||"/").reduce((s,r)=>{if(s&&typeof s=="object"&&r in s)return s[r]},this.data)}setProperty(e,t){const s=this.getProperty(e);if(this.options.enableValidation){const g=this.validatePath(e,t);if(g.length>0){this.emit("validation-error",{path:e,errors:g});return}}const r=e.replace(/^\//,"").split(this.options.pathSeparator||"/"),a=r.pop(),l=r.reduce((g,i)=>{if(g&&typeof g=="object"&&i in g)return g[i]},this.data);l&&typeof l=="object"&&a&&(l[a]=t,this.updateMetadata(),this.emit("property-changed",{path:e,oldValue:s,newValue:t,timestamp:Date.now(),source:"user"}),this.options.enableLogging&&console.log(`[JsonModel] Property changed: ${e}`,{oldValue:s,newValue:t}))}updateProperties(e){Object.entries(e).forEach(([t,s])=>{this.setProperty(t,s)})}createBinding(e){return p.computed(()=>this.getProperty(e))}addToArray(e,t){const s=this.getProperty(e);Array.isArray(s)&&(s.push(t),this.updateMetadata(),this.emit("array-changed",{path:e,action:"add",index:s.length-1,item:t}))}removeFromArray(e,t){const s=this.getProperty(e);if(Array.isArray(s)&&t>=0&&t<s.length){const r=s[t];s.splice(t,1),this.updateMetadata(),this.emit("array-changed",{path:e,action:"remove",index:t,item:r})}}updateArrayItem(e,t,s){const r=this.getProperty(e);if(Array.isArray(r)){const a=r.findIndex(t);if(a!==-1)return Object.assign(r[a],s),this.updateMetadata(),this.emit("array-changed",{path:e,action:"update",index:a,item:r[a]}),!0}return!1}getArrayLength(e){const t=this.getProperty(e);return Array.isArray(t)?t.length:0}hasProperty(e){return this.getProperty(e)!==void 0}resetProperty(e,t=void 0){this.setProperty(e,t)}getObjectKeys(e){const t=this.getProperty(e);return t&&typeof t=="object"&&!Array.isArray(t)?Object.keys(t):[]}clone(){return new S(JSON.parse(JSON.stringify(this.data)),this.options)}toJSON(){return JSON.stringify(this.data,null,2)}fromJSON(e){try{const t=JSON.parse(e);Object.assign(this.data,t),this.updateMetadata(),this.emit("model-reset",{timestamp:Date.now()})}catch(t){console.error("[JsonModel] Error parsing JSON:",t)}}watch(e,t,s={}){const r=p.watch(()=>this.getProperty(e),t,{immediate:s.immediate||!1,deep:s.deep||!0,flush:s.flush||"post"});return this.watchers.push(r),r}addValidator(e,t){this.validators[e]||(this.validators[e]=[]),this.validators[e].push(t)}removeValidator(e){delete this.validators[e]}validate(e){if(e){const t=this.getProperty(e);return this.validatePath(e,t).length===0}for(const t of Object.keys(this.validators))if(!this.validate(t))return!1;return!0}getErrors(e){if(e){const s=this.getProperty(e);return this.validatePath(e,s)}const t=[];for(const s of Object.keys(this.validators))t.push(...this.getErrors(s));return t}validatePath(e,t){const s=this.validators[e]||[],r=[];for(const a of s){const l=a.validate(t);l!==!0&&r.push(typeof l=="string"?l:a.message||"Validation failed")}return r}getMetadata(){return{...this.metadata}}reset(e){e?e.forEach(t=>{const s=this.options.defaultValues?.[t];this.setProperty(t,s)}):this.options.defaultValues&&Object.assign(this.data,this.options.defaultValues),this.updateMetadata(),this.emit("model-reset",{timestamp:Date.now()})}destroy(){this.watchers.forEach(e=>e()),this.watchers=[],this.validators={},this.eventListeners={},this.options.enableLogging&&console.log("[JsonModel] Destroyed")}updateMetadata(){this.changeCount++,this.metadata.lastModified=new Date,this.metadata.changeCount=this.changeCount,this.metadata.paths=this.getAllPaths(this.data),this.metadata.size=JSON.stringify(this.data).length}getAllPaths(e,t=""){const s=[];for(const r in e)if(e.hasOwnProperty(r)){const a=t?`${t}/${r}`:r;s.push(`/${a}`),e[r]&&typeof e[r]=="object"&&!Array.isArray(e[r])&&s.push(...this.getAllPaths(e[r],a))}return s}emit(e,t){(this.eventListeners[e]||[]).forEach(r=>r(t))}on(e,t){this.eventListeners[e]||(this.eventListeners[e]=[]),this.eventListeners[e].push(t)}off(e,t){const s=this.eventListeners[e]||[],r=s.indexOf(t);r>-1&&s.splice(r,1)}}class w{constructor(e,t={}){this.models=new Map,this.config={scope:e,security:{level:"basic"},audit:{enabled:!1},...t},this.config.audit?.enabled&&console.log(`[ModelManager] Created for scope: ${e} with config:`,this.config)}create(e,t,s){const r={enableLogging:this.config.audit?.enabled||!1,enableValidation:this.config.security?.level!=="basic",...s},a=new S(t,r);return this.models.set(e,a),this.config.audit?.enabled&&console.log(`[ModelManager] Model '${e}' created in scope '${this.config.scope}'`),a}createShared(e,t,s){const r={...s,enableLogging:!0,enableValidation:!0};return this.create(e,t,r)}createGlobal(e,t,s){const r={...s,enableLogging:!0,enableValidation:!0};return this.create(e,t,r)}getModel(e){return this.models.get(e)}hasModel(e){return this.models.has(e)}removeModel(e){const t=this.models.get(e);return t?(t.destroy(),this.models.delete(e),this.config.audit?.enabled&&console.log(`[ModelManager] Model '${e}' removed from scope '${this.config.scope}'`),!0):!1}getAllModels(){const e={};return this.models.forEach((t,s)=>{e[s]=t}),e}getModelNames(){return Array.from(this.models.keys())}getScope(){return this.config.scope}getConfig(){return{...this.config}}clear(){this.models.forEach((e,t)=>{e.destroy()}),this.models.clear(),this.config.audit?.enabled&&console.log(`[ModelManager] All models cleared from scope '${this.config.scope}'`)}exportModels(){const e={};return this.models.forEach((t,s)=>{e[s]=t.toJSON()}),e}importModels(e){Object.entries(e).forEach(([t,s])=>{const r=this.models.get(t);r&&r.fromJSON(s)})}getStatistics(){return{scope:this.config.scope,modelCount:this.models.size,modelNames:this.getModelNames(),totalSize:Array.from(this.models.values()).reduce((e,t)=>e+t.getMetadata().size,0)}}}class O{constructor(){this.managers=new Map,this.accessLog=[],this.enableAudit=!1}register(e,t){this.managers.has(e)&&console.warn(`[GlobalRegistry] Manager for scope '${e}' already exists. Replacing...`),this.managers.set(e,t),this.enableAudit&&console.log(`[GlobalRegistry] Manager registered for scope: ${e}`)}get(e){return this.managers.get(e)}unregister(e){const t=this.managers.get(e);t&&(t.clear(),this.managers.delete(e),this.enableAudit&&console.log(`[GlobalRegistry] Manager unregistered for scope: ${e}`))}hasModel(e,t){const s=this.managers.get(e);return s?s.hasModel(t):!1}removeModel(e,t){const s=this.managers.get(e);return s&&s.hasModel(t)?(s.removeModel(t),!0):!1}getAllScopes(){return Array.from(this.managers.keys())}clear(){this.managers.forEach((e,t)=>{e.clear()}),this.managers.clear(),this.accessLog=[],this.enableAudit&&console.log("[GlobalRegistry] All managers cleared")}enableAuditing(e=!0){this.enableAudit=e,console.log(`[GlobalRegistry] Auditing ${e?"enabled":"disabled"}`)}getModelFromScope(e,t,s){const r=this.managers.get(t);if(!r){console.warn(`[GlobalRegistry] Target scope '${t}' not found`);return}const a=r.getModel(s);return a&&this.enableAudit&&this.logAccess({sourceScope:e,targetScope:t,modelName:s,accessType:"read",timestamp:new Date}),a}getStatistics(){const e=this.getAllScopes(),t=Array.from(this.managers.values()).reduce((s,r)=>s+r.getModelNames().length,0);return{totalManagers:this.managers.size,totalModels:t,scopes:e,lastActivity:new Date}}getManagerStatistics(e){if(e){const s=this.managers.get(e);return s?{[e]:s.getStatistics()}:{}}const t={};return this.managers.forEach((s,r)=>{t[r]=s.getStatistics()}),t}broadcastToScope(e,t,s){return this.managers.get(e)?(this.enableAudit&&console.log(`[GlobalRegistry] Broadcasting '${t}' to scope '${e}'`,s),!0):(console.warn(`[GlobalRegistry] Cannot broadcast to scope '${e}' - not found`),!1)}shareModel(e,t,s,r){const a=this.managers.get(e),l=this.managers.get(t);if(!a||!l)return console.error("[GlobalRegistry] Source or target scope not found for model sharing"),!1;const g=a.getModel(s);if(!g)return console.error(`[GlobalRegistry] Model '${s}' not found in source scope '${e}'`),!1;const i=JSON.parse(g.toJSON()),c=r||s;return l.create(c,i),this.enableAudit&&console.log(`[GlobalRegistry] Model '${s}' shared from '${e}' to '${t}' as '${c}'`),!0}inspectScope(e){const t=this.managers.get(e);if(!t)return{error:`Scope '${e}' not found`};const s=t.getAllModels(),r={scope:e,config:t.getConfig(),statistics:t.getStatistics(),models:{}};return Object.entries(s).forEach(([a,l])=>{r.models[a]={metadata:l.getMetadata(),data:l.getData()}}),r}getAccessLog(){return[...this.accessLog]}logAccess(e){this.accessLog.push(e),this.accessLog.length>1e3&&(this.accessLog=this.accessLog.slice(-1e3))}dumpState(){console.group("[GlobalRegistry] Current State"),console.log("Statistics:",this.getStatistics()),console.log("Manager Statistics:",this.getManagerStatistics()),this.getAllScopes().forEach(e=>{console.group(`Scope: ${e}`),console.log(this.inspectScope(e)),console.groupEnd()}),this.accessLog.length>0&&console.log("Recent Access Log:",this.accessLog.slice(-10)),console.groupEnd()}}const d=new O;let m={fallbackToGlobalSearch:!0};function L(o){m.currentScope=o}function y(o){if(o)return d.get(o);if(m.currentScope)return d.get(m.currentScope);if(m.fallbackToGlobalSearch){const e=d.getAllScopes();if(e.length>0)return d.get(e[0])}}function b(o,e){if(e){const s=d.get(e)?.getModel(o);if(s)return{model:s,scope:e}}if(m.currentScope){const s=d.get(m.currentScope)?.getModel(o);if(s)return{model:s,scope:m.currentScope}}if(m.fallbackToGlobalSearch)for(const t of d.getAllScopes()){const r=d.get(t)?.getModel(o);if(r)return{model:r,scope:t}}}function G(o){m={...m,...o}}function C(){return{...m}}function v(o,e,t={}){const{scope:s,fallbackSearch:r=!0,defaultValue:a}=t;return p.computed({get(){if(s){const c=y(s)?.getModel(o);if(c){const u=c.getProperty(e);return u!==void 0?u:a}}if(r){const i=b(o,s);if(i){const c=i.model.getProperty(e);return c!==void 0?c:a}}const g=y()?.getModel(o);if(g){const i=g.getProperty(e);return i!==void 0?i:a}return a},set(l){if(l===void 0)return;if(s){const u=y(s)?.getModel(o);if(u){u.setProperty(e,l);return}}if(r){const c=b(o,s);if(c){c.model.setProperty(e,l);return}}const i=y()?.getModel(o);if(i){i.setProperty(e,l);return}console.warn(`[useModel] No se pudo encontrar el modelo '${o}' para actualizar '${e}'`)}})}function E(o,e,t){return v(e,t,{scope:o,fallbackSearch:!1})}function R(o,e,t){return v(o,e,{defaultValue:t})}const A=new Map;function P(o,e="",t={}){const{scope:s,fallbackSearch:r=!0}=t,a=`${o}:${e}`;if(A.has(a))return A.get(a);const l=new Proxy({},{get(g,i){if(i===Symbol.toStringTag)return"ZeusModelProxy";if(i===Symbol.toPrimitive)return()=>"[ZeusModelProxy]";if(typeof i=="symbol")return;const c=String(i),u=e?`${e}/${c}`:`/${c}`;let h;if(s?h=y(s)?.getModel(o):r?h=b(o,s)?.model:h=y()?.getModel(o),!h)return;const f=h.getProperty(u);if(f&&typeof f=="object"&&!Array.isArray(f)){const M=P(o,u,t);return A.set(`${o}:${u}`,M),M}return f},set(g,i,c){if(typeof i=="symbol")return!1;const u=String(i),h=e?`${e}/${u}`:`/${u}`;let f;return s?f=y(s)?.getModel(o):r?f=b(o,s)?.model:f=y()?.getModel(o),f?(f.setProperty(h,c),!0):(console.warn(`[useModels] No se pudo encontrar el modelo '${o}' para actualizar '${h}'`),!1)},has(g,i){if(typeof i=="symbol")return!1;const c=String(i),u=e?`${e}/${c}`:`/${c}`;let h;return s?h=y(s)?.getModel(o):h=b(o,s)?.model,h?h.hasProperty(u):!1}});return A.set(a,l),l}function $(o,e={}){const t={};return o.forEach(s=>{t[s]=p.reactive(P(s,"",e))}),t}function J(o,e={}){const t={};return o.forEach(s=>{t[s]=P(s,"",e)}),t}function V(o,e){return $(e,{scope:o,fallbackSearch:!1})}function D(o){return $(o,{})}function k(o,e){const t=new w(o,e);return d.register(o,t),t}function T(){d.enableAuditing(!0)}function F(){d.dumpState()}function j(){return{registry:d.getStatistics(),managers:d.getManagerStatistics()}}function z(o,e,t){return d.getModelFromScope(o,e,t)}function B(o,e,t,s){return d.shareModel(o,e,t,s)}n.GlobalRegistry=d,n.JsonModel=S,n.ModelManager=w,n.configureComposables=G,n.createModelManager=k,n.dumpGlobalState=F,n.enableGlobalAuditing=T,n.getComposableContext=C,n.getGlobalStatistics=j,n.getModelFromMicrofrontend=z,n.setComposableScope=L,n.shareModelBetweenMicrofrontends=B,n.useModel=v,n.useModelFromScope=E,n.useModelWithDefault=R,n.useModels=$,n.useModelsFromScope=V,n.useModelsRaw=J,n.useModelsShallow=D,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})});