@jaysalvat/smart-model
Advanced tools
Comparing version 0.4.0 to 0.5.0
@@ -5,3 +5,3 @@ /**! | ||
* https://github.com/jaysalvat/smart-model | ||
* @version 0.4.0 built 2021-02-24 12:33:33 | ||
* @version 0.5.0 built 2021-02-25 09:18:46 | ||
* @license ISC | ||
@@ -38,2 +38,6 @@ * @author Jay Salvat http://jaysalvat.com | ||
function isTypeArrayOfSmartModels(type) { | ||
return isArray(type) && type.length === 1 && isSmartModel(type[0]); | ||
} | ||
function keys(obj, cb = function() {}) { | ||
@@ -102,8 +106,9 @@ return Object.keys(obj).map(cb); | ||
const shortCode = code.split(":")[0]; | ||
source = source && source.constructor.name; | ||
if (settings.exceptions === true || isPlainObject(settings.exceptions) && settings.exceptions[shortCode]) { | ||
throw new SmartModelError({ | ||
message: message, | ||
message: `[${source}] ${message}`, | ||
source: source, | ||
property: property, | ||
code: code, | ||
source: source && source.constructor.name | ||
code: code | ||
}); | ||
@@ -115,3 +120,3 @@ } | ||
const errors = []; | ||
if (settings.strict && (!entry || !keys(entry).length)) { | ||
if (settings.strict && !keys(entry || {}).length) { | ||
errors.push({ | ||
@@ -131,3 +136,3 @@ message: `Property "${property}" can't be set in strict mode`, | ||
errors.push({ | ||
message: `Property '${property}' is 'readonly'`, | ||
message: `Property "${property}" is "readonly"`, | ||
code: "readonly" | ||
@@ -155,3 +160,3 @@ }); | ||
errors.push({ | ||
message: `Property "${property}" breaks the "${key}" rule`, | ||
message: `Property "${property}" triggers the "${key}" rule error`, | ||
code: "rule:" + key | ||
@@ -166,12 +171,11 @@ }); | ||
function createNested(entry = {}, property, settings) { | ||
if (!entry.type) { | ||
return false; | ||
if (entry.type) { | ||
const Child = isSmartModel(entry.type) ? entry.type : false; | ||
const schema = isPlainObject(entry.type) ? entry.type : false; | ||
if (Child || schema) { | ||
const Model = Child ? Child : SmartModel.create(pascalCase(property), schema, settings); | ||
entry.type = Model; | ||
return Model; | ||
} | ||
} | ||
const Child = isSmartModel(entry.type) ? entry.type : false; | ||
const schema = isPlainObject(entry.type) ? entry.type : false; | ||
if (Child || schema) { | ||
const Model = Child ? Child : SmartModel.create(pascalCase(property), schema, settings); | ||
entry.type = Model; | ||
return Model; | ||
} | ||
return false; | ||
@@ -200,2 +204,6 @@ } | ||
} | ||
if (isTypeArrayOfSmartModels(entry.type)) { | ||
value = entry.type[0].$hydrate(value); | ||
entry.type = Array; | ||
} | ||
const errors = checkErrors(entry, property, value, first, settings); | ||
@@ -202,0 +210,0 @@ if (errors.length) { |
@@ -1,2 +0,2 @@ | ||
/*! SmartModel v0.4.0 */ | ||
function e(e){return Array.isArray(e)}function t(e){return void 0===e}function r(e){return"function"==typeof e}function n(e){return e&&e.toString().startsWith("class")}function o(e){return e.prototype instanceof l||e instanceof l}function s(e){return e&&"[object Object]"===e.toString()}function c(e,t=function(){}){return Object.keys(e).map(t)}function i(e){return[].concat([],e)}function u(e,t){return t=Object.assign({},e,t),c(e,(r=>{s(e[r])&&s(t[r])&&(t[r]=Object.assign({},e[r],u(e[r],t[r])))})),t}class a extends Error{constructor(e){super(e.message),Object.assign(this,e)}}function p(t,r,u,a,p){const f=[];return!p.strict||t&&c(t).length||f.push({message:`Property "${r}" can't be set in strict mode`,code:"strict"}),t.required&&p.empty(u)?(f.push({message:`Property "${r}" is "required"`,code:"required"}),f):t.readonly&&!a?(f.push({message:`Property '${r}' is 'readonly'`,code:"readonly"}),f):(void 0===u||(!t.type||!t.required&&p.empty(u)||o(t.type)&&s(u)||i(t.type).some((t=>function(t,r){const o=r&&r.toString().match(/^\s*function (\w+)/),s=(o?o[1]:"object").toLowerCase();if("date"===s&&t instanceof r)return!0;if("array"===s&&e(t))return!0;if("object"===s){if(n(r)&&t instanceof r)return!0;if(!n(r)&&typeof t===s)return!0}else if(typeof t===s)return!0;return!1}(u,t)))||f.push({message:`Property "${r}" has an invalid type "${typeof u}"`,code:"type"}),t.rule&&c(t.rule,(e=>{(0,t.rule[e])(u)&&f.push({message:`Property "${r}" breaks the "${e}" rule`,code:"rule:"+e})}))),f)}function f(e={},t,r){if(!e.type)return!1;const n=!!o(e.type)&&e.type,c=!!s(e.type)&&e.type;if(n||c){const o=n||l.create(t.normalize("NFD").replace(/[\u0300-\u036f]/g,"").match(/[a-z1-9]+/gi).map((e=>e.charAt(0).toUpperCase()+e.substr(1).toLowerCase())).join(""),c,r);return e.type=o,o}return!1}a.throw=function(e,t,r,n,o){const c=t.split(":")[0];if(!0===e.exceptions||s(e.exceptions)&&e.exceptions[c])throw new a({message:r,property:n,code:t,source:o&&o.constructor.name})};class l extends class{constructor(e,n){return new Proxy(this,{set(o,s,i){const u=e[s]||{},l=o[s],d=t(l),y=!(d||(h=i,$=l,JSON.stringify(h)===JSON.stringify($)));var h,$;const g=f(u,s,n);function m(r,n){const c=Reflect.apply(r,o,n||[s,i,l,e]);return t(c)?i:c}i=m(o.$onBeforeSet),y&&(i=m(o.$onBeforeUpdate)),r(u.transform)&&(i=m(u.transform,[i,e]));const b=p(u,s,i,d,n);if(b.length){if(!n.exceptions)return!0;a.throw(n,b[0].code,b[0].message,s,o)}return n.strict&&!c(u).length||(g&&(i=new g(i)),o[s]=i,m(o.$onSet),y&&m(o.$onUpdate)),!0},get(n,s){const i=e[s];let u=n[s];if(["$get"].includes(s))return function(){return function(e){return c(e=Object.assign({},e),(t=>{o(e[t])&&(e[t]=e[t].$get())})),e}(n)};if(!i)return n[s];function a(r,o){const c=Reflect.apply(r,n,o||[s,u,e]);return t(c)?u:c}return u=a(n.$onBeforeGet),r(i)&&(u=a(i,[n,e])),r(i.format)&&(u=a(i.format,[u,e])),u=a(n.$onGet),u},deleteProperty(t,r){const o=t[r];function s(n,s){return Reflect.apply(n,t,s||[r,o,e])}return(e[r]||{}).required&&a.throw(n,"required",`Property "${r}" is "required"`,r,t),s(t.$onBeforeDelete),Reflect.deleteProperty(t,r),s(t.$onDelete),s(t.$onUpdate),!0}})}}{constructor(e={},n={},o){super(e,o),c(e,(o=>{t(n[o])&&(t(e[o].default)?r(e[o])||(this[o]=n[o]):this[o]=e[o].default)})),this.$patch(n)}$patch(e){c(e,(t=>{this[t]=e[t]}))}$put(e){c(this,(t=>{e[t]?o(this[t])?this[t].$put(e[t]):this[t]=e[t]:this.$delete(t)})),c(e,(t=>{this[t]||(this[t]=e[t])}))}$post(e){return this.$put(e)}$delete(e){i(e).forEach((e=>{Reflect.deleteProperty(this,e)}))}}l.settings={empty:e=>""===e||null===e||t(e),strict:!1,exceptions:{readonly:!1,required:!0,rule:!0,strict:!1,type:!0},methods:{$onBeforeGet:()=>{},$onBeforeSet:()=>{},$onBeforeUpdate:()=>{},$onDelete:()=>{},$onGet:()=>{},$onBeforeDelete:()=>{},$onSet:()=>{},$onUpdate:()=>{}}},l.create=function(t,r,n){n=u(l.settings,n);const o={[t]:class extends l{constructor(e){super(r,e,n)}}}[t];return o.$check=function(e,t){const o={};return c(r,(s=>{let c;const u=e[s],a=r[s],l=f(a,s,n);l&&(c=l.$check(u,t));let d=p(a,s,u,!1,n);c?o[s]=c:d.length&&(t&&(d=d.filter((e=>!i(t).includes(e.code)))),d.length&&(o[s]=d))})),!!c(o).length&&o},o.$hydrate=function(t){return e(t)?t.map((e=>new o(e))):new o(t)},Object.assign(o.prototype,n.methods),o.schema=r,o};export default l; | ||
/*! SmartModel v0.5.0 */ | ||
function e(e){return Array.isArray(e)}function t(e){return void 0===e}function r(e){return"function"==typeof e}function n(e){return e&&e.toString().startsWith("class")}function o(e){return e.prototype instanceof l||e instanceof l}function s(e){return e&&"[object Object]"===e.toString()}function c(e,t=function(){}){return Object.keys(e).map(t)}function i(e){return[].concat([],e)}function u(e,t){return t=Object.assign({},e,t),c(e,(r=>{s(e[r])&&s(t[r])&&(t[r]=Object.assign({},e[r],u(e[r],t[r])))})),t}class a extends Error{constructor(e){super(e.message),Object.assign(this,e)}}function p(t,r,u,a,p){const f=[];return p.strict&&!c(t||{}).length&&f.push({message:`Property "${r}" can't be set in strict mode`,code:"strict"}),t.required&&p.empty(u)?(f.push({message:`Property "${r}" is "required"`,code:"required"}),f):t.readonly&&!a?(f.push({message:`Property "${r}" is "readonly"`,code:"readonly"}),f):(void 0===u||(!t.type||!t.required&&p.empty(u)||o(t.type)&&s(u)||i(t.type).some((t=>function(t,r){const o=r&&r.toString().match(/^\s*function (\w+)/),s=(o?o[1]:"object").toLowerCase();if("date"===s&&t instanceof r)return!0;if("array"===s&&e(t))return!0;if("object"===s){if(n(r)&&t instanceof r)return!0;if(!n(r)&&typeof t===s)return!0}else if(typeof t===s)return!0;return!1}(u,t)))||f.push({message:`Property "${r}" has an invalid type "${typeof u}"`,code:"type"}),t.rule&&c(t.rule,(e=>{(0,t.rule[e])(u)&&f.push({message:`Property "${r}" triggers the "${e}" rule error`,code:"rule:"+e})}))),f)}function f(e={},t,r){if(e.type){const n=!!o(e.type)&&e.type,c=!!s(e.type)&&e.type;if(n||c){const o=n||l.create(t.normalize("NFD").replace(/[\u0300-\u036f]/g,"").match(/[a-z1-9]+/gi).map((e=>e.charAt(0).toUpperCase()+e.substr(1).toLowerCase())).join(""),c,r);return e.type=o,o}}return!1}a.throw=function(e,t,r,n,o){const c=t.split(":")[0];if(o=o&&o.constructor.name,!0===e.exceptions||s(e.exceptions)&&e.exceptions[c])throw new a({message:`[${o}] ${r}`,source:o,property:n,code:t})};class l extends class{constructor(n,s){return new Proxy(this,{set(i,u,l){const y=n[u]||{},d=i[u],h=t(d),$=!(h||(g=l,m=d,JSON.stringify(g)===JSON.stringify(m)));var g,m;const b=f(y,u,s);function w(e,r){const o=Reflect.apply(e,i,r||[u,l,d,n]);return t(o)?l:o}var j;l=w(i.$onBeforeSet),$&&(l=w(i.$onBeforeUpdate)),r(y.transform)&&(l=w(y.transform,[l,n])),e(j=y.type)&&1===j.length&&o(j[0])&&(l=y.type[0].$hydrate(l),y.type=Array);const x=p(y,u,l,h,s);if(x.length){if(!s.exceptions)return!0;a.throw(s,x[0].code,x[0].message,u,i)}return s.strict&&!c(y).length||(b&&(l=new b(l)),i[u]=l,w(i.$onSet),$&&w(i.$onUpdate)),!0},get(e,s){const i=n[s];let u=e[s];if(["$get"].includes(s))return function(){return function(e){return c(e=Object.assign({},e),(t=>{o(e[t])&&(e[t]=e[t].$get())})),e}(e)};if(!i)return e[s];function a(r,o){const c=Reflect.apply(r,e,o||[s,u,n]);return t(c)?u:c}return u=a(e.$onBeforeGet),r(i)&&(u=a(i,[e,n])),r(i.format)&&(u=a(i.format,[u,n])),u=a(e.$onGet),u},deleteProperty(e,t){const r=e[t];function o(o,s){return Reflect.apply(o,e,s||[t,r,n])}return(n[t]||{}).required&&a.throw(s,"required",`Property "${t}" is "required"`,t,e),o(e.$onBeforeDelete),Reflect.deleteProperty(e,t),o(e.$onDelete),o(e.$onUpdate),!0}})}}{constructor(e={},n={},o){super(e,o),c(e,(o=>{t(n[o])&&(t(e[o].default)?r(e[o])||(this[o]=n[o]):this[o]=e[o].default)})),this.$patch(n)}$patch(e){c(e,(t=>{this[t]=e[t]}))}$put(e){c(this,(t=>{e[t]?o(this[t])?this[t].$put(e[t]):this[t]=e[t]:this.$delete(t)})),c(e,(t=>{this[t]||(this[t]=e[t])}))}$post(e){return this.$put(e)}$delete(e){i(e).forEach((e=>{Reflect.deleteProperty(this,e)}))}}l.settings={empty:e=>""===e||null===e||t(e),strict:!1,exceptions:{readonly:!1,required:!0,rule:!0,strict:!1,type:!0},methods:{$onBeforeGet:()=>{},$onBeforeSet:()=>{},$onBeforeUpdate:()=>{},$onDelete:()=>{},$onGet:()=>{},$onBeforeDelete:()=>{},$onSet:()=>{},$onUpdate:()=>{}}},l.create=function(t,r,n){n=u(l.settings,n);const o={[t]:class extends l{constructor(e){super(r,e,n)}}}[t];return o.$check=function(e,t){const o={};return c(r,(s=>{let c;const u=e[s],a=r[s],l=f(a,s,n);l&&(c=l.$check(u,t));let y=p(a,s,u,!1,n);c?o[s]=c:y.length&&(t&&(y=y.filter((e=>!i(t).includes(e.code)))),y.length&&(o[s]=y))})),!!c(o).length&&o},o.$hydrate=function(t){return e(t)?t.map((e=>new o(e))):new o(t)},Object.assign(o.prototype,n.methods),o.schema=r,o};export default l; |
@@ -5,3 +5,3 @@ /**! | ||
* https://github.com/jaysalvat/smart-model | ||
* @version 0.4.0 built 2021-02-24 12:33:33 | ||
* @version 0.5.0 built 2021-02-25 09:18:46 | ||
* @license ISC | ||
@@ -33,2 +33,5 @@ * @author Jay Salvat http://jaysalvat.com | ||
} | ||
function isTypeArrayOfSmartModels(type) { | ||
return isArray(type) && type.length === 1 && isSmartModel(type[0]); | ||
} | ||
function keys(obj, cb = function() {}) { | ||
@@ -90,8 +93,9 @@ return Object.keys(obj).map(cb); | ||
const shortCode = code.split(":")[0]; | ||
source = source && source.constructor.name; | ||
if (settings.exceptions === true || isPlainObject(settings.exceptions) && settings.exceptions[shortCode]) { | ||
throw new SmartModelError({ | ||
message: message, | ||
message: `[${source}] ${message}`, | ||
source: source, | ||
property: property, | ||
code: code, | ||
source: source && source.constructor.name | ||
code: code | ||
}); | ||
@@ -102,3 +106,3 @@ } | ||
const errors = []; | ||
if (settings.strict && (!entry || !keys(entry).length)) { | ||
if (settings.strict && !keys(entry || {}).length) { | ||
errors.push({ | ||
@@ -118,3 +122,3 @@ message: `Property "${property}" can't be set in strict mode`, | ||
errors.push({ | ||
message: `Property '${property}' is 'readonly'`, | ||
message: `Property "${property}" is "readonly"`, | ||
code: "readonly" | ||
@@ -142,3 +146,3 @@ }); | ||
errors.push({ | ||
message: `Property "${property}" breaks the "${key}" rule`, | ||
message: `Property "${property}" triggers the "${key}" rule error`, | ||
code: "rule:" + key | ||
@@ -152,12 +156,11 @@ }); | ||
function createNested(entry = {}, property, settings) { | ||
if (!entry.type) { | ||
return false; | ||
if (entry.type) { | ||
const Child = isSmartModel(entry.type) ? entry.type : false; | ||
const schema = isPlainObject(entry.type) ? entry.type : false; | ||
if (Child || schema) { | ||
const Model = Child ? Child : SmartModel.create(pascalCase(property), schema, settings); | ||
entry.type = Model; | ||
return Model; | ||
} | ||
} | ||
const Child = isSmartModel(entry.type) ? entry.type : false; | ||
const schema = isPlainObject(entry.type) ? entry.type : false; | ||
if (Child || schema) { | ||
const Model = Child ? Child : SmartModel.create(pascalCase(property), schema, settings); | ||
entry.type = Model; | ||
return Model; | ||
} | ||
return false; | ||
@@ -185,2 +188,6 @@ } | ||
} | ||
if (isTypeArrayOfSmartModels(entry.type)) { | ||
value = entry.type[0].$hydrate(value); | ||
entry.type = Array; | ||
} | ||
const errors = checkErrors(entry, property, value, first, settings); | ||
@@ -187,0 +194,0 @@ if (errors.length) { |
@@ -1,2 +0,2 @@ | ||
/*! SmartModel v0.4.0 */ | ||
var SmartModel=function(){"use strict";function e(e){return Array.isArray(e)}function t(e){return void 0===e}function r(e){return"function"==typeof e}function n(e){return e&&e.toString().startsWith("class")}function o(e){return e.prototype instanceof l||e instanceof l}function s(e){return e&&"[object Object]"===e.toString()}function c(e,t=function(){}){return Object.keys(e).map(t)}function i(e){return[].concat([],e)}function u(e,t){return t=Object.assign({},e,t),c(e,(r=>{s(e[r])&&s(t[r])&&(t[r]=Object.assign({},e[r],u(e[r],t[r])))})),t}class a extends Error{constructor(e){super(e.message),Object.assign(this,e)}}function p(t,r,u,a,p){const f=[];return!p.strict||t&&c(t).length||f.push({message:`Property "${r}" can't be set in strict mode`,code:"strict"}),t.required&&p.empty(u)?(f.push({message:`Property "${r}" is "required"`,code:"required"}),f):t.readonly&&!a?(f.push({message:`Property '${r}' is 'readonly'`,code:"readonly"}),f):(void 0===u||(!t.type||!t.required&&p.empty(u)||o(t.type)&&s(u)||i(t.type).some((t=>function(t,r){const o=r&&r.toString().match(/^\s*function (\w+)/),s=(o?o[1]:"object").toLowerCase();if("date"===s&&t instanceof r)return!0;if("array"===s&&e(t))return!0;if("object"===s){if(n(r)&&t instanceof r)return!0;if(!n(r)&&typeof t===s)return!0}else if(typeof t===s)return!0;return!1}(u,t)))||f.push({message:`Property "${r}" has an invalid type "${typeof u}"`,code:"type"}),t.rule&&c(t.rule,(e=>{(0,t.rule[e])(u)&&f.push({message:`Property "${r}" breaks the "${e}" rule`,code:"rule:"+e})}))),f)}function f(e={},t,r){if(!e.type)return!1;const n=!!o(e.type)&&e.type,c=!!s(e.type)&&e.type;if(n||c){const o=n||l.create(t.normalize("NFD").replace(/[\u0300-\u036f]/g,"").match(/[a-z1-9]+/gi).map((e=>e.charAt(0).toUpperCase()+e.substr(1).toLowerCase())).join(""),c,r);return e.type=o,o}return!1}a.throw=function(e,t,r,n,o){const c=t.split(":")[0];if(!0===e.exceptions||s(e.exceptions)&&e.exceptions[c])throw new a({message:r,property:n,code:t,source:o&&o.constructor.name})};class l extends class{constructor(e,n){return new Proxy(this,{set(o,s,i){const u=e[s]||{},l=o[s],d=t(l),y=!(d||(h=i,$=l,JSON.stringify(h)===JSON.stringify($)));var h,$;const g=f(u,s,n);function m(r,n){const c=Reflect.apply(r,o,n||[s,i,l,e]);return t(c)?i:c}i=m(o.$onBeforeSet),y&&(i=m(o.$onBeforeUpdate)),r(u.transform)&&(i=m(u.transform,[i,e]));const b=p(u,s,i,d,n);if(b.length){if(!n.exceptions)return!0;a.throw(n,b[0].code,b[0].message,s,o)}return n.strict&&!c(u).length||(g&&(i=new g(i)),o[s]=i,m(o.$onSet),y&&m(o.$onUpdate)),!0},get(n,s){const i=e[s];let u=n[s];if(["$get"].includes(s))return function(){return function(e){return c(e=Object.assign({},e),(t=>{o(e[t])&&(e[t]=e[t].$get())})),e}(n)};if(!i)return n[s];function a(r,o){const c=Reflect.apply(r,n,o||[s,u,e]);return t(c)?u:c}return u=a(n.$onBeforeGet),r(i)&&(u=a(i,[n,e])),r(i.format)&&(u=a(i.format,[u,e])),u=a(n.$onGet),u},deleteProperty(t,r){const o=t[r];function s(n,s){return Reflect.apply(n,t,s||[r,o,e])}return(e[r]||{}).required&&a.throw(n,"required",`Property "${r}" is "required"`,r,t),s(t.$onBeforeDelete),Reflect.deleteProperty(t,r),s(t.$onDelete),s(t.$onUpdate),!0}})}}{constructor(e={},n={},o){super(e,o),c(e,(o=>{t(n[o])&&(t(e[o].default)?r(e[o])||(this[o]=n[o]):this[o]=e[o].default)})),this.$patch(n)}$patch(e){c(e,(t=>{this[t]=e[t]}))}$put(e){c(this,(t=>{e[t]?o(this[t])?this[t].$put(e[t]):this[t]=e[t]:this.$delete(t)})),c(e,(t=>{this[t]||(this[t]=e[t])}))}$post(e){return this.$put(e)}$delete(e){i(e).forEach((e=>{Reflect.deleteProperty(this,e)}))}}return l.settings={empty:e=>""===e||null===e||t(e),strict:!1,exceptions:{readonly:!1,required:!0,rule:!0,strict:!1,type:!0},methods:{$onBeforeGet:()=>{},$onBeforeSet:()=>{},$onBeforeUpdate:()=>{},$onDelete:()=>{},$onGet:()=>{},$onBeforeDelete:()=>{},$onSet:()=>{},$onUpdate:()=>{}}},l.create=function(t,r,n){n=u(l.settings,n);const o={[t]:class extends l{constructor(e){super(r,e,n)}}}[t];return o.$check=function(e,t){const o={};return c(r,(s=>{let c;const u=e[s],a=r[s],l=f(a,s,n);l&&(c=l.$check(u,t));let d=p(a,s,u,!1,n);c?o[s]=c:d.length&&(t&&(d=d.filter((e=>!i(t).includes(e.code)))),d.length&&(o[s]=d))})),!!c(o).length&&o},o.$hydrate=function(t){return e(t)?t.map((e=>new o(e))):new o(t)},Object.assign(o.prototype,n.methods),o.schema=r,o},l}(); | ||
/*! SmartModel v0.5.0 */ | ||
var SmartModel=function(){"use strict";function e(e){return Array.isArray(e)}function t(e){return void 0===e}function r(e){return"function"==typeof e}function n(e){return e&&e.toString().startsWith("class")}function o(e){return e.prototype instanceof l||e instanceof l}function s(e){return e&&"[object Object]"===e.toString()}function c(e,t=function(){}){return Object.keys(e).map(t)}function i(e){return[].concat([],e)}function u(e,t){return t=Object.assign({},e,t),c(e,(r=>{s(e[r])&&s(t[r])&&(t[r]=Object.assign({},e[r],u(e[r],t[r])))})),t}class a extends Error{constructor(e){super(e.message),Object.assign(this,e)}}function p(t,r,u,a,p){const f=[];return p.strict&&!c(t||{}).length&&f.push({message:`Property "${r}" can't be set in strict mode`,code:"strict"}),t.required&&p.empty(u)?(f.push({message:`Property "${r}" is "required"`,code:"required"}),f):t.readonly&&!a?(f.push({message:`Property "${r}" is "readonly"`,code:"readonly"}),f):(void 0===u||(!t.type||!t.required&&p.empty(u)||o(t.type)&&s(u)||i(t.type).some((t=>function(t,r){const o=r&&r.toString().match(/^\s*function (\w+)/),s=(o?o[1]:"object").toLowerCase();if("date"===s&&t instanceof r)return!0;if("array"===s&&e(t))return!0;if("object"===s){if(n(r)&&t instanceof r)return!0;if(!n(r)&&typeof t===s)return!0}else if(typeof t===s)return!0;return!1}(u,t)))||f.push({message:`Property "${r}" has an invalid type "${typeof u}"`,code:"type"}),t.rule&&c(t.rule,(e=>{(0,t.rule[e])(u)&&f.push({message:`Property "${r}" triggers the "${e}" rule error`,code:"rule:"+e})}))),f)}function f(e={},t,r){if(e.type){const n=!!o(e.type)&&e.type,c=!!s(e.type)&&e.type;if(n||c){const o=n||l.create(t.normalize("NFD").replace(/[\u0300-\u036f]/g,"").match(/[a-z1-9]+/gi).map((e=>e.charAt(0).toUpperCase()+e.substr(1).toLowerCase())).join(""),c,r);return e.type=o,o}}return!1}a.throw=function(e,t,r,n,o){const c=t.split(":")[0];if(o=o&&o.constructor.name,!0===e.exceptions||s(e.exceptions)&&e.exceptions[c])throw new a({message:`[${o}] ${r}`,source:o,property:n,code:t})};class l extends class{constructor(n,s){return new Proxy(this,{set(i,u,l){const y=n[u]||{},d=i[u],h=t(d),$=!(h||(g=l,m=d,JSON.stringify(g)===JSON.stringify(m)));var g,m;const b=f(y,u,s);function w(e,r){const o=Reflect.apply(e,i,r||[u,l,d,n]);return t(o)?l:o}var j;l=w(i.$onBeforeSet),$&&(l=w(i.$onBeforeUpdate)),r(y.transform)&&(l=w(y.transform,[l,n])),e(j=y.type)&&1===j.length&&o(j[0])&&(l=y.type[0].$hydrate(l),y.type=Array);const P=p(y,u,l,h,s);if(P.length){if(!s.exceptions)return!0;a.throw(s,P[0].code,P[0].message,u,i)}return s.strict&&!c(y).length||(b&&(l=new b(l)),i[u]=l,w(i.$onSet),$&&w(i.$onUpdate)),!0},get(e,s){const i=n[s];let u=e[s];if(["$get"].includes(s))return function(){return function(e){return c(e=Object.assign({},e),(t=>{o(e[t])&&(e[t]=e[t].$get())})),e}(e)};if(!i)return e[s];function a(r,o){const c=Reflect.apply(r,e,o||[s,u,n]);return t(c)?u:c}return u=a(e.$onBeforeGet),r(i)&&(u=a(i,[e,n])),r(i.format)&&(u=a(i.format,[u,n])),u=a(e.$onGet),u},deleteProperty(e,t){const r=e[t];function o(o,s){return Reflect.apply(o,e,s||[t,r,n])}return(n[t]||{}).required&&a.throw(s,"required",`Property "${t}" is "required"`,t,e),o(e.$onBeforeDelete),Reflect.deleteProperty(e,t),o(e.$onDelete),o(e.$onUpdate),!0}})}}{constructor(e={},n={},o){super(e,o),c(e,(o=>{t(n[o])&&(t(e[o].default)?r(e[o])||(this[o]=n[o]):this[o]=e[o].default)})),this.$patch(n)}$patch(e){c(e,(t=>{this[t]=e[t]}))}$put(e){c(this,(t=>{e[t]?o(this[t])?this[t].$put(e[t]):this[t]=e[t]:this.$delete(t)})),c(e,(t=>{this[t]||(this[t]=e[t])}))}$post(e){return this.$put(e)}$delete(e){i(e).forEach((e=>{Reflect.deleteProperty(this,e)}))}}return l.settings={empty:e=>""===e||null===e||t(e),strict:!1,exceptions:{readonly:!1,required:!0,rule:!0,strict:!1,type:!0},methods:{$onBeforeGet:()=>{},$onBeforeSet:()=>{},$onBeforeUpdate:()=>{},$onDelete:()=>{},$onGet:()=>{},$onBeforeDelete:()=>{},$onSet:()=>{},$onUpdate:()=>{}}},l.create=function(t,r,n){n=u(l.settings,n);const o={[t]:class extends l{constructor(e){super(r,e,n)}}}[t];return o.$check=function(e,t){const o={};return c(r,(s=>{let c;const u=e[s],a=r[s],l=f(a,s,n);l&&(c=l.$check(u,t));let y=p(a,s,u,!1,n);c?o[s]=c:y.length&&(t&&(y=y.filter((e=>!i(t).includes(e.code)))),y.length&&(o[s]=y))})),!!c(o).length&&o},o.$hydrate=function(t){return e(t)?t.map((e=>new o(e))):new o(t)},Object.assign(o.prototype,n.methods),o.schema=r,o},l}(); |
@@ -5,3 +5,3 @@ /**! | ||
* https://github.com/jaysalvat/smart-model | ||
* @version 0.4.0 built 2021-02-24 12:33:33 | ||
* @version 0.5.0 built 2021-02-25 09:18:46 | ||
* @license ISC | ||
@@ -36,2 +36,5 @@ * @author Jay Salvat http://jaysalvat.com | ||
} | ||
function isTypeArrayOfSmartModels(type) { | ||
return isArray(type) && type.length === 1 && isSmartModel(type[0]); | ||
} | ||
function keys(obj, cb = function() {}) { | ||
@@ -93,8 +96,9 @@ return Object.keys(obj).map(cb); | ||
const shortCode = code.split(":")[0]; | ||
source = source && source.constructor.name; | ||
if (settings.exceptions === true || isPlainObject(settings.exceptions) && settings.exceptions[shortCode]) { | ||
throw new SmartModelError({ | ||
message: message, | ||
message: `[${source}] ${message}`, | ||
source: source, | ||
property: property, | ||
code: code, | ||
source: source && source.constructor.name | ||
code: code | ||
}); | ||
@@ -105,3 +109,3 @@ } | ||
const errors = []; | ||
if (settings.strict && (!entry || !keys(entry).length)) { | ||
if (settings.strict && !keys(entry || {}).length) { | ||
errors.push({ | ||
@@ -121,3 +125,3 @@ message: `Property "${property}" can't be set in strict mode`, | ||
errors.push({ | ||
message: `Property '${property}' is 'readonly'`, | ||
message: `Property "${property}" is "readonly"`, | ||
code: "readonly" | ||
@@ -145,3 +149,3 @@ }); | ||
errors.push({ | ||
message: `Property "${property}" breaks the "${key}" rule`, | ||
message: `Property "${property}" triggers the "${key}" rule error`, | ||
code: "rule:" + key | ||
@@ -155,12 +159,11 @@ }); | ||
function createNested(entry = {}, property, settings) { | ||
if (!entry.type) { | ||
return false; | ||
if (entry.type) { | ||
const Child = isSmartModel(entry.type) ? entry.type : false; | ||
const schema = isPlainObject(entry.type) ? entry.type : false; | ||
if (Child || schema) { | ||
const Model = Child ? Child : SmartModel.create(pascalCase(property), schema, settings); | ||
entry.type = Model; | ||
return Model; | ||
} | ||
} | ||
const Child = isSmartModel(entry.type) ? entry.type : false; | ||
const schema = isPlainObject(entry.type) ? entry.type : false; | ||
if (Child || schema) { | ||
const Model = Child ? Child : SmartModel.create(pascalCase(property), schema, settings); | ||
entry.type = Model; | ||
return Model; | ||
} | ||
return false; | ||
@@ -188,2 +191,6 @@ } | ||
} | ||
if (isTypeArrayOfSmartModels(entry.type)) { | ||
value = entry.type[0].$hydrate(value); | ||
entry.type = Array; | ||
} | ||
const errors = checkErrors(entry, property, value, first, settings); | ||
@@ -190,0 +197,0 @@ if (errors.length) { |
@@ -1,2 +0,2 @@ | ||
/*! SmartModel v0.4.0 */ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).SmartModel=t()}(this,(function(){"use strict";function e(e){return Array.isArray(e)}function t(e){return void 0===e}function r(e){return"function"==typeof e}function n(e){return e&&e.toString().startsWith("class")}function o(e){return e.prototype instanceof l||e instanceof l}function s(e){return e&&"[object Object]"===e.toString()}function i(e,t=function(){}){return Object.keys(e).map(t)}function c(e){return[].concat([],e)}function u(e,t){return t=Object.assign({},e,t),i(e,(r=>{s(e[r])&&s(t[r])&&(t[r]=Object.assign({},e[r],u(e[r],t[r])))})),t}class f extends Error{constructor(e){super(e.message),Object.assign(this,e)}}function a(t,r,u,f,a){const p=[];return!a.strict||t&&i(t).length||p.push({message:`Property "${r}" can't be set in strict mode`,code:"strict"}),t.required&&a.empty(u)?(p.push({message:`Property "${r}" is "required"`,code:"required"}),p):t.readonly&&!f?(p.push({message:`Property '${r}' is 'readonly'`,code:"readonly"}),p):(void 0===u||(!t.type||!t.required&&a.empty(u)||o(t.type)&&s(u)||c(t.type).some((t=>function(t,r){const o=r&&r.toString().match(/^\s*function (\w+)/),s=(o?o[1]:"object").toLowerCase();if("date"===s&&t instanceof r)return!0;if("array"===s&&e(t))return!0;if("object"===s){if(n(r)&&t instanceof r)return!0;if(!n(r)&&typeof t===s)return!0}else if(typeof t===s)return!0;return!1}(u,t)))||p.push({message:`Property "${r}" has an invalid type "${typeof u}"`,code:"type"}),t.rule&&i(t.rule,(e=>{(0,t.rule[e])(u)&&p.push({message:`Property "${r}" breaks the "${e}" rule`,code:"rule:"+e})}))),p)}function p(e={},t,r){if(!e.type)return!1;const n=!!o(e.type)&&e.type,i=!!s(e.type)&&e.type;if(n||i){const o=n||l.create(t.normalize("NFD").replace(/[\u0300-\u036f]/g,"").match(/[a-z1-9]+/gi).map((e=>e.charAt(0).toUpperCase()+e.substr(1).toLowerCase())).join(""),i,r);return e.type=o,o}return!1}f.throw=function(e,t,r,n,o){const i=t.split(":")[0];if(!0===e.exceptions||s(e.exceptions)&&e.exceptions[i])throw new f({message:r,property:n,code:t,source:o&&o.constructor.name})};class l extends class{constructor(e,n){return new Proxy(this,{set(o,s,c){const u=e[s]||{},l=o[s],d=t(l),y=!(d||(h=c,$=l,JSON.stringify(h)===JSON.stringify($)));var h,$;const g=p(u,s,n);function m(r,n){const i=Reflect.apply(r,o,n||[s,c,l,e]);return t(i)?c:i}c=m(o.$onBeforeSet),y&&(c=m(o.$onBeforeUpdate)),r(u.transform)&&(c=m(u.transform,[c,e]));const b=a(u,s,c,d,n);if(b.length){if(!n.exceptions)return!0;f.throw(n,b[0].code,b[0].message,s,o)}return n.strict&&!i(u).length||(g&&(c=new g(c)),o[s]=c,m(o.$onSet),y&&m(o.$onUpdate)),!0},get(n,s){const c=e[s];let u=n[s];if(["$get"].includes(s))return function(){return function(e){return i(e=Object.assign({},e),(t=>{o(e[t])&&(e[t]=e[t].$get())})),e}(n)};if(!c)return n[s];function f(r,o){const i=Reflect.apply(r,n,o||[s,u,e]);return t(i)?u:i}return u=f(n.$onBeforeGet),r(c)&&(u=f(c,[n,e])),r(c.format)&&(u=f(c.format,[u,e])),u=f(n.$onGet),u},deleteProperty(t,r){const o=t[r];function s(n,s){return Reflect.apply(n,t,s||[r,o,e])}return(e[r]||{}).required&&f.throw(n,"required",`Property "${r}" is "required"`,r,t),s(t.$onBeforeDelete),Reflect.deleteProperty(t,r),s(t.$onDelete),s(t.$onUpdate),!0}})}}{constructor(e={},n={},o){super(e,o),i(e,(o=>{t(n[o])&&(t(e[o].default)?r(e[o])||(this[o]=n[o]):this[o]=e[o].default)})),this.$patch(n)}$patch(e){i(e,(t=>{this[t]=e[t]}))}$put(e){i(this,(t=>{e[t]?o(this[t])?this[t].$put(e[t]):this[t]=e[t]:this.$delete(t)})),i(e,(t=>{this[t]||(this[t]=e[t])}))}$post(e){return this.$put(e)}$delete(e){c(e).forEach((e=>{Reflect.deleteProperty(this,e)}))}}return l.settings={empty:e=>""===e||null===e||t(e),strict:!1,exceptions:{readonly:!1,required:!0,rule:!0,strict:!1,type:!0},methods:{$onBeforeGet:()=>{},$onBeforeSet:()=>{},$onBeforeUpdate:()=>{},$onDelete:()=>{},$onGet:()=>{},$onBeforeDelete:()=>{},$onSet:()=>{},$onUpdate:()=>{}}},l.create=function(t,r,n){n=u(l.settings,n);const o={[t]:class extends l{constructor(e){super(r,e,n)}}}[t];return o.$check=function(e,t){const o={};return i(r,(s=>{let i;const u=e[s],f=r[s],l=p(f,s,n);l&&(i=l.$check(u,t));let d=a(f,s,u,!1,n);i?o[s]=i:d.length&&(t&&(d=d.filter((e=>!c(t).includes(e.code)))),d.length&&(o[s]=d))})),!!i(o).length&&o},o.$hydrate=function(t){return e(t)?t.map((e=>new o(e))):new o(t)},Object.assign(o.prototype,n.methods),o.schema=r,o},l})); | ||
/*! SmartModel v0.5.0 */ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).SmartModel=t()}(this,(function(){"use strict";function e(e){return Array.isArray(e)}function t(e){return void 0===e}function r(e){return"function"==typeof e}function n(e){return e&&e.toString().startsWith("class")}function o(e){return e.prototype instanceof l||e instanceof l}function s(e){return e&&"[object Object]"===e.toString()}function i(e,t=function(){}){return Object.keys(e).map(t)}function c(e){return[].concat([],e)}function u(e,t){return t=Object.assign({},e,t),i(e,(r=>{s(e[r])&&s(t[r])&&(t[r]=Object.assign({},e[r],u(e[r],t[r])))})),t}class f extends Error{constructor(e){super(e.message),Object.assign(this,e)}}function p(t,r,u,f,p){const a=[];return p.strict&&!i(t||{}).length&&a.push({message:`Property "${r}" can't be set in strict mode`,code:"strict"}),t.required&&p.empty(u)?(a.push({message:`Property "${r}" is "required"`,code:"required"}),a):t.readonly&&!f?(a.push({message:`Property "${r}" is "readonly"`,code:"readonly"}),a):(void 0===u||(!t.type||!t.required&&p.empty(u)||o(t.type)&&s(u)||c(t.type).some((t=>function(t,r){const o=r&&r.toString().match(/^\s*function (\w+)/),s=(o?o[1]:"object").toLowerCase();if("date"===s&&t instanceof r)return!0;if("array"===s&&e(t))return!0;if("object"===s){if(n(r)&&t instanceof r)return!0;if(!n(r)&&typeof t===s)return!0}else if(typeof t===s)return!0;return!1}(u,t)))||a.push({message:`Property "${r}" has an invalid type "${typeof u}"`,code:"type"}),t.rule&&i(t.rule,(e=>{(0,t.rule[e])(u)&&a.push({message:`Property "${r}" triggers the "${e}" rule error`,code:"rule:"+e})}))),a)}function a(e={},t,r){if(e.type){const n=!!o(e.type)&&e.type,i=!!s(e.type)&&e.type;if(n||i){const o=n||l.create(t.normalize("NFD").replace(/[\u0300-\u036f]/g,"").match(/[a-z1-9]+/gi).map((e=>e.charAt(0).toUpperCase()+e.substr(1).toLowerCase())).join(""),i,r);return e.type=o,o}}return!1}f.throw=function(e,t,r,n,o){const i=t.split(":")[0];if(o=o&&o.constructor.name,!0===e.exceptions||s(e.exceptions)&&e.exceptions[i])throw new f({message:`[${o}] ${r}`,source:o,property:n,code:t})};class l extends class{constructor(n,s){return new Proxy(this,{set(c,u,l){const d=n[u]||{},y=c[u],h=t(y),$=!(h||(g=l,m=y,JSON.stringify(g)===JSON.stringify(m)));var g,m;const b=a(d,u,s);function j(e,r){const o=Reflect.apply(e,c,r||[u,l,y,n]);return t(o)?l:o}var w;l=j(c.$onBeforeSet),$&&(l=j(c.$onBeforeUpdate)),r(d.transform)&&(l=j(d.transform,[l,n])),e(w=d.type)&&1===w.length&&o(w[0])&&(l=d.type[0].$hydrate(l),d.type=Array);const x=p(d,u,l,h,s);if(x.length){if(!s.exceptions)return!0;f.throw(s,x[0].code,x[0].message,u,c)}return s.strict&&!i(d).length||(b&&(l=new b(l)),c[u]=l,j(c.$onSet),$&&j(c.$onUpdate)),!0},get(e,s){const c=n[s];let u=e[s];if(["$get"].includes(s))return function(){return function(e){return i(e=Object.assign({},e),(t=>{o(e[t])&&(e[t]=e[t].$get())})),e}(e)};if(!c)return e[s];function f(r,o){const i=Reflect.apply(r,e,o||[s,u,n]);return t(i)?u:i}return u=f(e.$onBeforeGet),r(c)&&(u=f(c,[e,n])),r(c.format)&&(u=f(c.format,[u,n])),u=f(e.$onGet),u},deleteProperty(e,t){const r=e[t];function o(o,s){return Reflect.apply(o,e,s||[t,r,n])}return(n[t]||{}).required&&f.throw(s,"required",`Property "${t}" is "required"`,t,e),o(e.$onBeforeDelete),Reflect.deleteProperty(e,t),o(e.$onDelete),o(e.$onUpdate),!0}})}}{constructor(e={},n={},o){super(e,o),i(e,(o=>{t(n[o])&&(t(e[o].default)?r(e[o])||(this[o]=n[o]):this[o]=e[o].default)})),this.$patch(n)}$patch(e){i(e,(t=>{this[t]=e[t]}))}$put(e){i(this,(t=>{e[t]?o(this[t])?this[t].$put(e[t]):this[t]=e[t]:this.$delete(t)})),i(e,(t=>{this[t]||(this[t]=e[t])}))}$post(e){return this.$put(e)}$delete(e){c(e).forEach((e=>{Reflect.deleteProperty(this,e)}))}}return l.settings={empty:e=>""===e||null===e||t(e),strict:!1,exceptions:{readonly:!1,required:!0,rule:!0,strict:!1,type:!0},methods:{$onBeforeGet:()=>{},$onBeforeSet:()=>{},$onBeforeUpdate:()=>{},$onDelete:()=>{},$onGet:()=>{},$onBeforeDelete:()=>{},$onSet:()=>{},$onUpdate:()=>{}}},l.create=function(t,r,n){n=u(l.settings,n);const o={[t]:class extends l{constructor(e){super(r,e,n)}}}[t];return o.$check=function(e,t){const o={};return i(r,(s=>{let i;const u=e[s],f=r[s],l=a(f,s,n);l&&(i=l.$check(u,t));let d=p(f,s,u,!1,n);i?o[s]=i:d.length&&(t&&(d=d.filter((e=>!c(t).includes(e.code)))),d.length&&(o[s]=d))})),!!i(o).length&&o},o.$hydrate=function(t){return e(t)?t.map((e=>new o(e))):new o(t)},Object.assign(o.prototype,n.methods),o.schema=r,o},l})); |
{ | ||
"name": "@jaysalvat/smart-model", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "Javascript object model", | ||
@@ -5,0 +5,0 @@ "main": "./build/smart-model.cjs.min.cjs", |
@@ -23,3 +23,3 @@ ``` | ||
- [x] Readonly properties | ||
- [x] Virtual property | ||
- [x] Computed property | ||
- [x] Throw exception (or not) if invalid | ||
@@ -107,3 +107,3 @@ - [x] Nested models | ||
}, | ||
// Virtual properties | ||
// Computed properties | ||
bodyLength: (post) => post.body.length, | ||
@@ -202,3 +202,17 @@ readingTime: (post) => readingTime(post.body) | ||
** Use with caution **, it could be unexpected effects when object are copied (the formated value becomes the new value). | ||
**Use with caution**, it could cause unexpected effects when the model is cloned. | ||
```javascript | ||
const cloned = Object.assign({}, model) | ||
``` | ||
The formatted value becomes the new value of the cloned object. | ||
Consider using the `$get()` method instead. | ||
```javascript | ||
const cloned = model.$get() | ||
``` | ||
it could also cause unexpected effects when model is used in other Proxies (like Vue). | ||
The formatting could be applied multiple times. | ||
Consider using a computed property instead. | ||
@@ -310,2 +324,31 @@ | ||
An array of models can be attach to a property with this fancy syntax. | ||
```javascript | ||
const Article = SmartModel.create('Article', { | ||
body: { | ||
type: String | ||
}, | ||
comments: { | ||
type: [ Comment ] | ||
} | ||
}) | ||
``` | ||
The syntax above is a shortcut for: | ||
```javascript | ||
const Article = SmartModel.create('Article', { | ||
body: { | ||
type: String | ||
}, | ||
comments: { | ||
type: Array, | ||
transform: (value) => Comment.$hydrate(value) | ||
} | ||
}) | ||
``` | ||
Now `comments` always is an array of `Comment` models. | ||
### Settings | ||
@@ -312,0 +355,0 @@ |
@@ -6,3 +6,3 @@ import { keys, isSmartModel, toArray, checkType, isPlainObject } from './utils.js' | ||
if (settings.strict && (!entry || !keys(entry).length)) { | ||
if (settings.strict && !keys(entry || {}).length) { | ||
errors.push({ | ||
@@ -25,3 +25,3 @@ message: `Property "${property}" can't be set in strict mode`, | ||
errors.push({ | ||
message: `Property '${property}' is 'readonly'`, | ||
message: `Property "${property}" is "readonly"`, | ||
code: 'readonly' | ||
@@ -54,3 +54,3 @@ }) | ||
errors.push({ | ||
message: `Property "${property}" breaks the "${key}" rule`, | ||
message: `Property "${property}" triggers the "${key}" rule error`, | ||
code: 'rule:' + key | ||
@@ -57,0 +57,0 @@ }) |
@@ -5,15 +5,13 @@ import { pascalCase, isSmartModel, isPlainObject } from './utils.js' | ||
export default function createNested(entry = {}, property, settings) { | ||
if (!entry.type) { | ||
return false | ||
} | ||
if (entry.type) { | ||
const Child = isSmartModel(entry.type) ? entry.type : false | ||
const schema = isPlainObject(entry.type) ? entry.type : false | ||
const Child = isSmartModel(entry.type) ? entry.type : false | ||
const schema = isPlainObject(entry.type) ? entry.type : false | ||
if (Child || schema) { | ||
const Model = Child ? Child : SmartModel.create(pascalCase(property), schema, settings) | ||
if (Child || schema) { | ||
const Model = Child ? Child : SmartModel.create(pascalCase(property), schema, settings) | ||
entry.type = Model | ||
entry.type = Model | ||
return Model | ||
return Model | ||
} | ||
} | ||
@@ -20,0 +18,0 @@ |
@@ -13,8 +13,10 @@ import { isPlainObject } from './utils.js' | ||
source = source && source.constructor.name | ||
if (settings.exceptions === true || (isPlainObject(settings.exceptions) && settings.exceptions[shortCode])) { | ||
throw new SmartModelError({ | ||
message, | ||
message: `[${source}] ${message}`, | ||
source: source, | ||
property, | ||
code, | ||
source: source && source.constructor.name | ||
code | ||
}) | ||
@@ -21,0 +23,0 @@ } |
import SmartModelError from './SmartModelError.js' | ||
import checkErrors from './checkErrors.js' | ||
import createNested from './createNested.js' | ||
import { keys, eject, isFn, isEqual, isUndef } from './utils.js' | ||
import { keys, eject, isFn, isTypeArrayOfSmartModels, isEqual, isUndef } from './utils.js' | ||
@@ -32,2 +32,7 @@ class SmartModelProxy { | ||
if (isTypeArrayOfSmartModels(entry.type)) { | ||
value = entry.type[0].$hydrate(value) | ||
entry.type = Array | ||
} | ||
const errors = checkErrors(entry, property, value, first, settings) | ||
@@ -34,0 +39,0 @@ |
@@ -33,2 +33,6 @@ /* eslint-disable new-cap */ | ||
export function isTypeArrayOfSmartModels(type) { | ||
return isArray(type) && type.length === 1 && isSmartModel(type[0]) | ||
} | ||
export function keys(obj, cb = function () { }) { | ||
@@ -35,0 +39,0 @@ return Object.keys(obj).map(cb) |
@@ -306,6 +306,6 @@ /* eslint-disable prefer-reflect */ | ||
// Virtual / Readonly property | ||
// Computed / Readonly property | ||
describe('Virtual property', function () { | ||
it('should get a virtual property', function () { | ||
describe('Computed property', function () { | ||
it('should get a computed property', function () { | ||
const Model = SmartModel.create('Model', { | ||
@@ -320,6 +320,6 @@ today: () => new Date() | ||
it('should get a virtual property with context', function () { | ||
it('should get a computed property with context', function () { | ||
const Model = SmartModel.create('Model', { | ||
prop1: { default: 'string' }, | ||
prop2: (model) => 'virtual: ' + model.prop1 | ||
prop2: (model) => 'computed: ' + model.prop1 | ||
}) | ||
@@ -330,3 +330,3 @@ | ||
expect(model.prop1).to.be.equal('string') | ||
expect(model.prop2).to.be.equal('virtual: string') | ||
expect(model.prop2).to.be.equal('computed: string') | ||
}) | ||
@@ -442,3 +442,3 @@ | ||
type: { | ||
nestedProp: { default: 'string2' } | ||
prop: { default: 'string2' } | ||
} | ||
@@ -466,4 +466,4 @@ } | ||
type: { | ||
nestedProp1: { default: 'string3' }, | ||
nestedProp2: { default: 'string4' } | ||
prop1: { default: 'string3' }, | ||
prop2: { default: 'string4' } | ||
} | ||
@@ -478,3 +478,3 @@ } | ||
prop3: { | ||
nestedProp1: 'newString2', | ||
prop1: 'newString2', | ||
new: 'string' | ||
@@ -488,4 +488,4 @@ }, | ||
expect(model.new).to.be.equal('string') | ||
expect(model.prop3.nestedProp1).to.be.equal('newString2') | ||
expect(model.prop3.nestedProp2).to.be.equal(undef) | ||
expect(model.prop3.prop1).to.be.equal('newString2') | ||
expect(model.prop3.prop2).to.be.equal(undef) | ||
expect(model.prop3.new).to.be.equal('string') | ||
@@ -502,4 +502,4 @@ }) | ||
type: { | ||
nestedProp1: { default: 'string3' }, | ||
nestedProp2: { default: 'string4' } | ||
prop1: { default: 'string3' }, | ||
prop2: { default: 'string4' } | ||
} | ||
@@ -514,3 +514,3 @@ } | ||
prop3: { | ||
nestedProp1: 'newString2', | ||
prop1: 'newString2', | ||
new: 'string' | ||
@@ -524,4 +524,4 @@ }, | ||
expect(model.new).to.be.equal('string') | ||
expect(model.prop3.nestedProp1).to.be.equal('newString2') | ||
expect(model.prop3.nestedProp2).to.be.equal('string4') | ||
expect(model.prop3.prop1).to.be.equal('newString2') | ||
expect(model.prop3.prop2).to.be.equal('string4') | ||
expect(model.prop3.new).to.be.equal('string') | ||
@@ -868,3 +868,3 @@ }) | ||
const SubModel = SmartModel.create('SubModel', { | ||
nestedProp: { | ||
prop: { | ||
default: 'string2' | ||
@@ -884,3 +884,3 @@ } | ||
expect(model.prop2).to. be.an.instanceOf(SmartModel) | ||
expect(model.prop2.nestedProp).to.be.equal('string2') | ||
expect(model.prop2.prop).to.be.equal('string2') | ||
}) | ||
@@ -895,3 +895,3 @@ | ||
type: { | ||
nestedProp: { | ||
prop: { | ||
default: 'string2' | ||
@@ -907,3 +907,3 @@ } | ||
expect(model.prop2).to.be.an.instanceOf(SmartModel) | ||
expect(model.prop2.nestedProp).to.be.equal('string2') | ||
expect(model.prop2.prop).to.be.equal('string2') | ||
}) | ||
@@ -915,3 +915,3 @@ | ||
type: { | ||
nestedProp: { | ||
prop: { | ||
type: { | ||
@@ -931,3 +931,3 @@ nestedNestedProp: { | ||
expect(model.prop).to.be.an.instanceOf(SmartModel) | ||
expect(model.prop.nestedProp).to.be.an.instanceOf(SmartModel) | ||
expect(model.prop.prop).to.be.an.instanceOf(SmartModel) | ||
}) | ||
@@ -939,3 +939,3 @@ | ||
type: { | ||
nestedProp: { | ||
prop: { | ||
default: 'string' | ||
@@ -951,3 +951,3 @@ } | ||
expect(model.prop.nestedProp).to.be.equal('string') | ||
expect(model.prop.prop).to.be.equal('string') | ||
}) | ||
@@ -960,3 +960,3 @@ | ||
type: { | ||
nestedProp: { | ||
prop: { | ||
default: 'string' | ||
@@ -981,3 +981,3 @@ } | ||
type: { | ||
nestedProp: {} | ||
prop: {} | ||
} | ||
@@ -1000,3 +1000,3 @@ } | ||
type: { | ||
nestedProp: { | ||
prop: { | ||
required: true | ||
@@ -1010,7 +1010,7 @@ } | ||
new Model({ | ||
prop: { nestedProp: null } | ||
prop: { prop: null } | ||
}) | ||
}) | ||
expect(err.property).to.be.equal('nestedProp') | ||
expect(err.property).to.be.equal('prop') | ||
expect(err.source).to.be.equal('Prop') | ||
@@ -1024,3 +1024,3 @@ expect(err.code).to.be.equal('required') | ||
type: { | ||
nestedProp: { | ||
prop: { | ||
type: String | ||
@@ -1035,9 +1035,35 @@ } | ||
model.prop.nestedProp = 0 | ||
model.prop.prop = 0 | ||
}) | ||
expect(err.property).to.be.equal('nestedProp') | ||
expect(err.property).to.be.equal('prop') | ||
expect(err.source).to.be.equal('Prop') | ||
expect(err.code).to.be.equal('type') | ||
}) | ||
it('should attach an array of models', function () { | ||
const SubModel = SmartModel.create('SubModel', { | ||
prop: { | ||
default: 'string' | ||
} | ||
}) | ||
const Model = SmartModel.create('Model', { | ||
prop: { | ||
type: [ SubModel ] | ||
} | ||
}) | ||
const model = new Model({ | ||
prop: [ | ||
{ prop: 'string1' }, | ||
{ prop: 'string2' } | ||
] | ||
}) | ||
expect(model.prop[0]).to.be.an.instanceOf(SmartModel) | ||
expect(model.prop[1]).to.be.an.instanceOf(SmartModel) | ||
expect(model.prop[0].prop).to.be.equal('string1') | ||
expect(model.prop[1].prop).to.be.equal('string2') | ||
}) | ||
}) | ||
@@ -1044,0 +1070,0 @@ }) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
121588
2958
556