├── .gitignore ├── HISTORY.md ├── LICENSE ├── README.md ├── README_zh.md ├── build ├── model.js └── stat.json ├── hey.js ├── package-lock.json ├── package.json ├── src ├── model.js ├── type.js └── utils.js └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | 1.1.1 / 2016-04-12 2 | ================== 3 | 4 | * 添加startOf,endOf方法 5 | 6 | ================== 7 | 8 | 1.1.4 / 2016-04-14 9 | ================== 10 | 11 | * 修改readMe文档 12 | 13 | ================== 14 | 15 | 1.1.5 / 2016-04-19 16 | ================== 17 | 18 | * 修改传递参数可直接初始化date的一些参数 19 | * 修改初始化错误日期后的处理 20 | 21 | ================== 22 | 23 | 24 | ================== 25 | 26 | 1.1.0 / 2016-05-10 27 | ================== 28 | 29 | * 添加default 参数 30 | * 添加计算属性 31 | 32 | ================== -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Alicia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # js-model 2 | Data model for javascript 3 | 4 | ## 中文文档 5 | [中文文档](https://github.com/vvpvvp/model/blob/master/README_zh.md) 6 | 7 | ## Install 8 | ### npm install 9 | ```sh 10 | npm install js-model --save 11 | ``` 12 | 13 | ## Model 14 | 15 | ### Column Define: 16 | - **String**: "" || String 17 | - **Number**: 0 || Number 18 | - **Date**: Date 19 | - **Array**: [] 20 | - **Object**: {} 21 | 22 | ### Default Parameter 23 | 24 | ```javascript 25 | { 26 | // when use dispose data, remove empty array. 27 | removeEmptyArray: false, 28 | 29 | // when use parse data, remove null value. 30 | removeNull: false, 31 | 32 | // remove null value from array. 33 | removeNullFromArray: false, 34 | 35 | // remove null value from object. 36 | removeEmptyObject: true, 37 | } 38 | ``` 39 | 40 | ### Const 41 | 42 | ```javascript 43 | Model.S // money ten 十 44 | Model.B // money hundred 百 45 | Model.Q // money thousand 千 46 | Model.W //money ten thousand 万 47 | Model.SW // money one hundred thousand 十万 48 | Model.BW // money million 百万 49 | Model.QW // money ten million 千万 50 | Model.Y // money billion 亿 51 | ``` 52 | 53 | ### Methods 54 | 55 | - **parse**: 56 | * **Fill property**: Creating a complete object data, allows you to get rid of the boredom of {{a&&a.b?a.b.c:''}} 57 | * **Data conversion**: Data standardization conversion, when data is transferred from the background, the date is a timestamp, the amount is in unit, parse method is to help you convert time stamp to time string, the amount is converted in a certain unit, and also can help you to complete all the fields. 58 | * **Default value**: define default value 59 | 60 | - **dispose**: 61 | * When you need to transfer the data to the background, convert the date into a timestamp, convert the amount to the amount in the unit, standardize the data format, and delete the empty data. 62 | 63 | 64 | Example: the value modified by input is String, and is converted to digital format through dispose. 65 | 66 | 67 | ## Basic 68 | 69 | **Basic.js** 70 | ``` javascript 71 | import Model from "js-model"; 72 | 73 | let Basic = new Model({ 74 | id: 0, 75 | source: { 76 | type: Date, 77 | format: 'l' // use manba date format, "l": "YYYY-MM-DD", 78 | }, 79 | description: "", 80 | tags: [ 0 ], 81 | companyId: "", 82 | rate: { 83 | type: Number, 84 | default: 0.8 // use default value, only effective for String, Number, Date 85 | }, 86 | salary: { 87 | type: Number, 88 | unit: Model.Q // money transfor, a unit of 1000 89 | } 90 | }); 91 | export default Basic; 92 | 93 | ``` 94 | ### parse 95 | **Usage 1**: fill property 96 | 97 | ``` javascript 98 | import Basic from './Basic.js' 99 | let basicValue = Basic.parse({}); 100 | ``` 101 | 102 | basicValue: 103 | ``` javascript 104 | { 105 | id: null, 106 | source: null, 107 | description: null, 108 | tags: [], 109 | companyId: null, 110 | rate: 0.8, // use default value 111 | salary: null 112 | } 113 | ``` 114 | 115 | **Usage 2**: conversion amount and date 116 | ``` javascript 117 | import Basic from './Basic.js' 118 | let basicValue = Basic.parse({ 119 | source: "2017-06-09T00:00:00+08:00", 120 | salary: 10000, 121 | rate: 0.1 122 | }); 123 | ``` 124 | 125 | basicValue: 126 | ``` javascript 127 | { 128 | id: null, 129 | source: "2017-06-09", // 130 | description: null, 131 | tags: [], 132 | companyId: null, 133 | rate: 0.1, 134 | salary: 10 //10000 conversion to a thousand units 135 | } 136 | ``` 137 | 138 | ### dispose 139 | **Usage 1**: remove null property 140 | 141 | ``` javascript 142 | import Basic from './Basic.js' 143 | let basicValue = Basic.dispose({ 144 | id: null, 145 | source: "2017-06-09", 146 | description: null, 147 | tags: [], 148 | companyId: null, 149 | rate: "0.1", 150 | salary: 10 151 | }); 152 | ``` 153 | 154 | basicValue: Consistent with the values converted from parse 155 | 156 | ``` javascript 157 | { 158 | source: "2017-06-09T00:00:00+08:00", 159 | salary: 10000, 160 | rate: 0.1 161 | } 162 | ``` 163 | 164 | 165 | ## Advanced 166 | 167 | ```javascript 168 | 169 | // Basic.js 170 | 171 | let Basic = new Model({ 172 | id: 0, 173 | companyId: "", 174 | rate: 0 175 | }); 176 | export default Basic; 177 | 178 | 179 | // Edu.js 180 | 181 | let Edu = new Model({ 182 | id: 0, 183 | major: "", 184 | school: "" 185 | }); 186 | export default Edu; 187 | 188 | 189 | // User.js 190 | 191 | import Edu from "./Edu"; 192 | import Basic from "./Basic"; 193 | let User = new Model({ 194 | basic: Basic, 195 | edu: [Edu] 196 | }); 197 | export default User; 198 | 199 | ``` 200 | 201 | ### parse 202 | ```javascript 203 | import User from './User' 204 | let user = User.parse({ 205 | basic:{ 206 | id:123123 207 | }, 208 | edu:[{ 209 | id: 12 210 | }], 211 | }) 212 | ``` 213 | 214 | **result**: 215 | ```javascript 216 | { 217 | basic: { 218 | id: 123123, 219 | companyId: null, 220 | rate: null 221 | }, 222 | edu: [{ 223 | id: 12, 224 | school: null 225 | major: null, 226 | }] 227 | } 228 | ``` 229 | 230 | ### dispose 231 | 232 | ``` javascript 233 | import User from './User' 234 | 235 | let user = User.dispose({ 236 | basic:{ 237 | id:123123, 238 | companyId: 123, 239 | rate: null 240 | }, 241 | edu:[{ 242 | id: 12, 243 | school: "school" 244 | major: null, 245 | }], 246 | }) 247 | ``` 248 | 249 | **result**: 250 | ```javascript 251 | { 252 | basic: { 253 | id:123123, 254 | companyId: 123, 255 | }, 256 | edu: [{ 257 | id: 12, 258 | school: "school" 259 | }] 260 | } 261 | ``` 262 | 263 | ## Extend 264 | 265 | 266 | ### Single display and dispose 267 | 268 | 269 | ``` javascript 270 | 271 | const info = new InfoModel({ 272 | salary: { 273 | type: Number, 274 | parse(data) { 275 | return data.salary / 1000 276 | }, 277 | dispose(data) { 278 | return data.salary * 1000 279 | } 280 | }, 281 | 282 | }); 283 | 284 | info.parse({salary: 10000}) 285 | // {salary: 10} 286 | 287 | info.parse({salary: 20}) 288 | // {salary: 20000} 289 | 290 | 291 | ``` 292 | 293 | ### Extend Model 294 | 295 | ``` javascript 296 | 297 | class InfoModel extends Model { 298 | parse(data) { 299 | let b = super.parse(data); 300 | if(b.imgUrls.type.length == 0) { 301 | b.imgUrls.type.push('http://*****') 302 | } 303 | return b; 304 | } 305 | 306 | dispose(data, param) { 307 | return super.dispose(data, param) 308 | } 309 | } 310 | 311 | const info = new InfoModel({ 312 | imgUrls: { 313 | type: [''] 314 | }, 315 | }); 316 | 317 | info.parse({}) 318 | 319 | 320 | ``` 321 | 322 | **result**: 323 | ```javascript 324 | { 325 | imgUrls: { 326 | type: ['http://*****'] 327 | }, 328 | } 329 | ``` 330 | 331 | ## Config 332 | 333 | 334 | **manba-config.js** 335 | The default is the ISO date format of the current time zone, for example: 2016-04-19T00:00:00+08:00 336 | ```javascript 337 | import Model from 'js-model'; 338 | // Redefining the format of the date conversion 339 | Model.config({ 340 | disposeDateFormat(date) { 341 | // change to use timestamp 342 | return manba(date).time(); 343 | } 344 | }) 345 | ``` 346 | 347 | 348 | ## Recommend 349 | - [manba](https://www.npmjs.com/package/manba): Date Format 350 | - [heyui](https://www.npmjs.com/package/heyui): 🎉UI Toolkit for Web, Vue2.0 351 | 352 | 353 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # js-model 2 | 为javascript准备的数据模型工具 3 | 4 | ## 安装 5 | ### npm安装 6 | ```sh 7 | npm install js-model --save 8 | ``` 9 | ## Model 10 | 11 | ### 字段定义: 12 | - **String**: "" || String 13 | - **Number**: 0 || Number 14 | - **Date**: Date 15 | - **Array**: [] 16 | - **Object**: {} 17 | 18 | ### Default Parameter 19 | 20 | ```javascript 21 | { 22 | //dispose的时候移除空数组 23 | removeEmptyArray: false, 24 | //parse的时候移除null数据 25 | removeNull: false, 26 | //移除null数据从数组中 27 | removeNullFromArray: false, 28 | //从子对象中移除空对象 29 | removeEmptyObject: true, 30 | } 31 | ``` 32 | 33 | ### Const 34 | 35 | ```javascript 36 | Model.S // money ten 十 37 | Model.B // money hundred 百 38 | Model.Q // money thousand 千 39 | Model.W //money ten thousand 万 40 | Model.SW // money one hundred thousand 十万 41 | Model.BW // money million 百万 42 | Model.QW // money ten million 千万 43 | Model.Y // money billion 亿 44 | ``` 45 | 46 | ### 方法 47 | 48 | - **parse**: 49 | * 创建完整对象数据,让你摆脱{{a&&a.b?a.b.c:''}}这种无聊的判断了 50 | * 数据标准化转换,当数据从后台传输过来的时候,日期是时间戳,金额是以元为单位,parse方法是帮你转换时间戳至时间字符串,金额以一定单位转换好,并且可以帮助你补全好所有的字段。 51 | 52 | - **dispose**: 53 | * 当你需要把数据传送至后台之前,把日期转换成时间戳,把金额转换为以元为单位的数额,标准化数据格式,删除为空的数据。 54 | 55 | 56 | 例:通过input修改的数值为String, 通过dispose转换成数字格式。 57 | 58 | ## 基本 59 | 60 | **Basic.js** 61 | ``` javascript 62 | import Model from "js-model"; 63 | 64 | let Basic = new Model({ 65 | id: 0, 66 | source: { 67 | type: Date, 68 | format: 'l' // 使用manba日期格式化, "l": "YYYY-MM-DD", 69 | }, 70 | description: "", 71 | tags: [ 0 ], 72 | companyId: "", 73 | rate: { 74 | type: Number, 75 | default: 0.8 // 使用默认值,只对 String, Number, Date 类型的值有效。 76 | }, 77 | salary: { 78 | type: Number, 79 | unit: Model.Q // 金额转换,此处单位为 千 80 | } 81 | }); 82 | export default Basic; 83 | 84 | ``` 85 | ### parse 86 | **Usage 1**: 补充字段 87 | 88 | ``` javascript 89 | import Basic from './Basic.js' 90 | let basicValue = Basic.parse({}); 91 | ``` 92 | 93 | basicValue: 94 | ``` javascript 95 | { 96 | id: null, 97 | source: null, 98 | description: null, 99 | tags: [], 100 | companyId: null, 101 | rate: 0.8, // use default value 102 | salary: null 103 | } 104 | ``` 105 | 106 | **Usage 2**: 转换金额与日期 107 | ``` javascript 108 | import Basic from './Basic.js' 109 | let basicValue = Basic.parse({ 110 | source: "2017-06-09T00:00:00+08:00", 111 | salary: 10000, 112 | rate: 0.1 113 | }); 114 | ``` 115 | 116 | **result**: 117 | ``` javascript 118 | { 119 | id: null, 120 | source: "2017-06-09", // 121 | description: null, 122 | tags: [], 123 | companyId: null, 124 | rate: 0.1, 125 | salary: 10 //10000 conversion to a thousand units 126 | } 127 | ``` 128 | 129 | ### dispose 130 | **Usage 1**: 删除null值的属性,并转换金额与日期 131 | 132 | ``` javascript 133 | import Basic from './Basic.js' 134 | let basicValue = Basic.dispose({ 135 | id: null, 136 | source: "2017-06-09", 137 | description: null, 138 | tags: [], 139 | companyId: null, 140 | rate: "0.1", 141 | salary: 10 142 | }); 143 | ``` 144 | 145 | **result**: 与从parse的值一致 146 | 147 | ``` javascript 148 | { 149 | source: "2017-06-09T00:00:00+08:00", 150 | salary: 10000, 151 | rate: 0.1 152 | } 153 | ``` 154 | 155 | 156 | ## 进阶 157 | 158 | ```javascript 159 | 160 | // Basic.js 161 | 162 | let Basic = new Model({ 163 | id: 0, 164 | companyId: "", 165 | rate: 0 166 | }); 167 | export default Basic; 168 | 169 | 170 | // Edu.js 171 | 172 | let Edu = new Model({ 173 | id: 0, 174 | major: "", 175 | school: "" 176 | }); 177 | export default Edu; 178 | 179 | 180 | // User.js 181 | 182 | import Edu from "./Edu"; 183 | import Basic from "./Basic"; 184 | let User = new Model({ 185 | basic: Basic, 186 | edu: [Edu] 187 | }); 188 | export default User; 189 | 190 | ``` 191 | 192 | ### parse 193 | ```javascript 194 | import User from './User' 195 | let user = User.parse({ 196 | basic:{ 197 | id:123123 198 | }, 199 | edu:[{ 200 | id: 12 201 | }], 202 | }) 203 | ``` 204 | 205 | **result**: 206 | ```javascript 207 | { 208 | basic: { 209 | id: 123123, 210 | companyId: null, 211 | rate: null 212 | }, 213 | edu: [{ 214 | id: 12, 215 | school: null 216 | major: null, 217 | }] 218 | } 219 | ``` 220 | 221 | ### dispose 222 | 223 | ``` javascript 224 | import User from './User' 225 | 226 | let user = User.dispose({ 227 | basic:{ 228 | id:123123, 229 | companyId: 123, 230 | rate: null 231 | }, 232 | edu:[{ 233 | id: 12, 234 | school: "school" 235 | major: null, 236 | }], 237 | }) 238 | ``` 239 | 240 | **result**: 241 | ```javascript 242 | { 243 | basic: { 244 | id:123123, 245 | companyId: 123, 246 | }, 247 | edu: [{ 248 | id: 12, 249 | school: "school" 250 | }] 251 | } 252 | ``` 253 | 254 | ## 扩展 255 | 256 | ### 单独编写display和dispose 257 | 258 | 259 | ``` javascript 260 | 261 | const info = new InfoModel({ 262 | salary: { 263 | type: Number, 264 | parse(data) { 265 | return data.salary / 1000 266 | }, 267 | dispose(data) { 268 | return data.salary * 1000 269 | } 270 | }, 271 | 272 | }); 273 | 274 | info.parse({salary: 10000}) 275 | // {salary: 10} 276 | 277 | info.parse({salary: 20}) 278 | // {salary: 20000} 279 | 280 | 281 | ``` 282 | 283 | ### 继承Model 284 | 285 | ``` javascript 286 | 287 | class InfoModel extends Model { 288 | parse(data) { 289 | let b = super.parse(data); 290 | if(b.imgUrls.type.length == 0) { 291 | b.imgUrls.type.push('http://*****') 292 | } 293 | return b; 294 | } 295 | 296 | dispose(data, param) { 297 | return super.dispose(data, param) 298 | } 299 | } 300 | 301 | const info = new InfoModel({ 302 | imgUrls: { 303 | type: [''] 304 | }, 305 | }); 306 | 307 | info.parse({}) 308 | 309 | 310 | ``` 311 | 312 | **result**: 313 | ```javascript 314 | { 315 | imgUrls: { 316 | type: ['http://*****'] 317 | }, 318 | } 319 | ``` 320 | 321 | ## 配置 322 | 323 | 324 | **manba-config.js** 325 | 默认的日期转换是使用当前时区的ISO日期格式, 比如: 2016-04-19T00:00:00+08:00 326 | ```javascript 327 | import Model from 'js-model'; 328 | // Redefining the format of the date conversion 329 | Model.config({ 330 | disposeDateFormat(date) { 331 | // change to use timestamp 332 | return manba(date).time(); 333 | } 334 | }) 335 | ``` 336 | 337 | ## 相关推荐 338 | - [manba](https://www.npmjs.com/package/manba): 日期格式化工具 339 | - [heyui](https://www.npmjs.com/package/heyui): HeyUI组件库 340 | 341 | 342 | 343 | -------------------------------------------------------------------------------- /build/model.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("manba")):"function"==typeof define&&define.amd?define(["manba"],e):"object"==typeof exports?exports.Model=e(require("manba")):t.Model=e(t.manba)}(this,function(t){return function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var n={};return e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,r){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:r})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=92)}([function(t,e){var n=t.exports={version:"2.5.3"};"number"==typeof __e&&(__e=n)},function(t,e){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(t,e,n){var r=n(24)("wks"),o=n(16),u=n(1).Symbol,i="function"==typeof u;(t.exports=function(t){return r[t]||(r[t]=i&&u[t]||(i?u:o)("Symbol."+t))}).store=r},function(t,e,n){t.exports=!n(6)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},function(t,e,n){var r=n(10),o=n(34),u=n(27),i=Object.defineProperty;e.f=n(3)?Object.defineProperty:function(t,e,n){if(r(t),e=u(e,!0),r(n),o)try{return i(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(t[e]=n.value),t}},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e,n){var r=n(5),o=n(15);t.exports=n(3)?function(t,e,n){return r.f(t,e,o(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,e,n){var r=n(35),o=n(18);t.exports=function(t){return r(o(t))}},function(t,e,n){var r=n(8);t.exports=function(t){if(!r(t))throw TypeError(t+" is not an object!");return t}},function(t,e,n){var r=n(1),o=n(0),u=n(66),i=n(7),f=function(t,e,n){var a,c,l,s=t&f.F,p=t&f.G,d=t&f.S,y=t&f.P,v=t&f.B,h=t&f.W,b=p?o:o[e]||(o[e]={}),m=b.prototype,g=p?r:d?r[e]:(r[e]||{}).prototype;p&&(n=e);for(a in n)(c=!s&&g&&void 0!==g[a])&&a in b||(l=c?g[a]:n[a],b[a]=p&&"function"!=typeof g[a]?n[a]:v&&c?u(l,r):h&&g[a]==l?function(t){var e=function(e,n,r){if(this instanceof t){switch(arguments.length){case 0:return new t;case 1:return new t(e);case 2:return new t(e,n)}return new t(e,n,r)}return t.apply(this,arguments)};return e.prototype=t.prototype,e}(l):y&&"function"==typeof l?u(Function.call,l):l,y&&((b.virtual||(b.virtual={}))[a]=l,t&f.R&&m&&!m[a]&&i(m,a,l)))};f.F=1,f.G=2,f.S=4,f.P=8,f.B=16,f.W=32,f.U=64,f.R=128,t.exports=f},function(t,e,n){var r=n(40),o=n(19);t.exports=Object.keys||function(t){return r(t,o)}},function(t,e){t.exports={}},function(t,e){e.f={}.propertyIsEnumerable},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e){var n=0,r=Math.random();t.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++n+r).toString(36))}},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e){t.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},function(t,e){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(t,e){t.exports=!0},function(t,e){e.f=Object.getOwnPropertySymbols},function(t,e,n){var r=n(5).f,o=n(4),u=n(2)("toStringTag");t.exports=function(t,e,n){t&&!o(t=n?t:t.prototype,u)&&r(t,u,{configurable:!0,value:e})}},function(t,e,n){var r=n(24)("keys"),o=n(16);t.exports=function(t){return r[t]||(r[t]=o(t))}},function(t,e,n){var r=n(1),o=r["__core-js_shared__"]||(r["__core-js_shared__"]={});t.exports=function(t){return o[t]||(o[t]={})}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},function(t,e,n){var r=n(18);t.exports=function(t){return Object(r(t))}},function(t,e,n){var r=n(8);t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if("function"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError("Can't convert object to primitive value")}},function(t,e,n){var r=n(1),o=n(0),u=n(20),i=n(29),f=n(5).f;t.exports=function(t){var e=o.Symbol||(o.Symbol=u?{}:r.Symbol||{});"_"==t.charAt(0)||t in e||f(e,t,{value:i.f(t)})}},function(t,e,n){e.f=n(2)},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(54),u=r(o),i=n(32),f=r(i),a=n(49),c=r(a),l=n(31),s=r(l);e.default={isObject:function(t){return"[object Object]"===Object.prototype.toString.call(t)},isArray:function(t){return t instanceof Array||"[object Array]"===Object.prototype.toString.call(t)},isDate:function(t){return t instanceof Date||"[object Date]"===Object.prototype.toString.call(t)},isNumber:function(t){return t instanceof Number||"[object Number]"===Object.prototype.toString.call(t)},isString:function(t){return t instanceof String||"[object String]"===Object.prototype.toString.call(t)},isBoolean:function(t){return"boolean"==typeof t},isFunction:function(t){return"function"==typeof t},deepCopy:function(t){var e=null;if(this.isObject(t)){e={};for(var n in t)e[n]=this.deepCopy(t[n])}else if(this.isArray(t)){e=[];var r=!0,o=!1,u=void 0;try{for(var i,f=(0,s.default)(t);!(r=(i=f.next()).done);r=!0){var a=i.value;e.push(this.deepCopy(a))}}catch(t){o=!0,u=t}finally{try{!r&&f.return&&f.return()}finally{if(o)throw u}}}else e=t;return e},deepFreeze:function(t){var e=this,n=this;return(0,c.default)(t),(0,f.default)(t).forEach(function(r,o){n.isObject(t[r])&&e.deepFreeze(t[r])}),t},mergeArray:function(t,e){for(var n=0;ndocument.F=Object<\/script>"),t.close(),a=t.F;r--;)delete a.prototype[u[r]];return a()};t.exports=Object.create||function(t,e){var n;return null!==t?(f.prototype=r(t),n=new f,f.prototype=null,n[i]=t):n=a(),void 0===e?n:o(n,e)}},function(t,e,n){var r=n(40),o=n(19).concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return r(t,o)}},function(t,e,n){var r=n(4),o=n(9),u=n(64)(!1),i=n(23)("IE_PROTO");t.exports=function(t,e){var n,f=o(t),a=0,c=[];for(n in f)n!=i&&r(f,n)&&c.push(n);for(;e.length>a;)r(f,n=e[a++])&&(~u(c,n)||c.push(n));return c}},function(t,e,n){var r=n(11),o=n(0),u=n(6);t.exports=function(t,e){var n=(o.Object||{})[t]||Object[t],i={};i[t]=e(n),r(r.S+r.F*u(function(){n(1)}),"Object",i)}},function(t,e,n){t.exports=n(7)},function(t,e,n){"use strict";var r=n(77)(!0);n(36)(String,"String",function(t){this._t=String(t),this._i=0},function(){var t,e=this._t,n=this._i;return n>=e.length?{value:void 0,done:!0}:(t=r(e,n),this._i+=t.length,{value:t,done:!1})})},function(t,e,n){n(82);for(var r=n(1),o=n(7),u=n(13),i=n(2)("toStringTag"),f="CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList".split(","),a=0;a1&&void 0!==arguments[1]?arguments[1]:{};return e.isParse=!0,e.isDispose=!1,f(t,this._model,g.default.extend({},_,e))}},{key:"dispose",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.isParse=!1,e.isDispose=!0,f(t,this._model,g.default.extend({},_,e))}}]),t}();A.DATE=S.default.DATE,A.NUMBER=S.default.NUMBER,A.STRING=S.default.STRING,A.BOOLEAN=S.default.BOOLEAN,A.Date=S.default.DATE,A.Number=S.default.NUMBER,A.String=S.default.STRING,A.Boolean=S.default.BOOLEAN,A.S=S.default.S,A.B=S.default.B,A.Q=S.default.Q,A.W=S.default.W,A.SW=S.default.SW,A.BW=S.default.BW,A.QW=S.default.QW,A.Y=S.default.Y,A.disposeDateFormat=function(t,e){return(0,j.default)(t).toISOString()},A.config=function(t){g.default.isFunction(t.disposeDateFormat)&&(A.disposeDateFormat=t.disposeDateFormat)},t.exports=A},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(30),o=function(t){return t&&t.__esModule?t:{default:t}}(r),u={STRING:String,DATE:Date,NUMBER:Number,BOOLEAN:Boolean,OBJECT:Object,ARRAY:Array,isType:function(t){return t===this.STRING||t===this.DATE||t===this.NUMBER||t===this.BOOLEAN},S:10,B:100,Q:1e3,W:1e4,SW:1e5,BW:1e6,QW:1e7,Y:1e8};o.default.deepFreeze(u),e.default=u},function(t,e,n){t.exports={default:n(56),__esModule:!0}},function(t,e,n){t.exports={default:n(57),__esModule:!0}},function(t,e,n){t.exports={default:n(58),__esModule:!0}},function(t,e,n){t.exports={default:n(60),__esModule:!0}},function(t,e,n){t.exports={default:n(61),__esModule:!0}},function(t,e,n){"use strict";e.__esModule=!0,e.default=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}},function(t,e,n){"use strict";e.__esModule=!0;var r=n(48),o=function(t){return t&&t.__esModule?t:{default:t}}(r);e.default=function(){function t(t,e){for(var n=0;nl;)if((f=a[l++])!=f)return!0}else for(;c>l;l++)if((t||l in a)&&a[l]===n)return t||l||0;return!t&&-1}}},function(t,e,n){var r=n(17),o=n(2)("toStringTag"),u="Arguments"==r(function(){return arguments}()),i=function(t,e){try{return t[e]}catch(t){}};t.exports=function(t){var e,n,f;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=i(e=Object(t),o))?n:u?r(e):"Object"==(f=r(e))&&"function"==typeof e.callee?"Arguments":f}},function(t,e,n){var r=n(62);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e,n){var r=n(12),o=n(21),u=n(14);t.exports=function(t){var e=r(t),n=o.f;if(n)for(var i,f=n(t),a=u.f,c=0;f.length>c;)a.call(t,i=f[c++])&&e.push(i);return e}},function(t,e,n){var r=n(1).document;t.exports=r&&r.documentElement},function(t,e,n){var r=n(17);t.exports=Array.isArray||function(t){return"Array"==r(t)}},function(t,e,n){"use strict";var r=n(38),o=n(15),u=n(22),i={};n(7)(i,n(2)("iterator"),function(){return this}),t.exports=function(t,e,n){t.prototype=r(i,{next:o(1,n)}),u(t,e+" Iterator")}},function(t,e){t.exports=function(t,e){return{value:e,done:!!t}}},function(t,e,n){"use strict";var r=n(12),o=n(21),u=n(14),i=n(26),f=n(35),a=Object.assign;t.exports=!a||n(6)(function(){var t={},e={},n=Symbol(),r="abcdefghijklmnopqrst";return t[n]=7,r.split("").forEach(function(t){e[t]=t}),7!=a({},t)[n]||Object.keys(a({},e)).join("")!=r})?function(t,e){for(var n=i(t),a=arguments.length,c=1,l=o.f,s=u.f;a>c;)for(var p,d=f(arguments[c++]),y=l?r(d).concat(l(d)):r(d),v=y.length,h=0;v>h;)s.call(d,p=y[h++])&&(n[p]=d[p]);return n}:a},function(t,e,n){var r=n(5),o=n(10),u=n(12);t.exports=n(3)?Object.defineProperties:function(t,e){o(t);for(var n,i=u(e),f=i.length,a=0;f>a;)r.f(t,n=i[a++],e[n]);return t}},function(t,e,n){var r=n(14),o=n(15),u=n(9),i=n(27),f=n(4),a=n(34),c=Object.getOwnPropertyDescriptor;e.f=n(3)?c:function(t,e){if(t=u(t),e=i(e,!0),a)try{return c(t,e)}catch(t){}if(f(t,e))return o(!r.f.call(t,e),t[e])}},function(t,e,n){var r=n(9),o=n(39).f,u={}.toString,i="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],f=function(t){try{return o(t)}catch(t){return i.slice()}};t.exports.f=function(t){return i&&"[object Window]"==u.call(t)?f(t):o(r(t))}},function(t,e,n){var r=n(4),o=n(26),u=n(23)("IE_PROTO"),i=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=o(t),r(t,u)?t[u]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?i:null}},function(t,e,n){var r=n(25),o=n(18);t.exports=function(t){return function(e,n){var u,i,f=String(o(e)),a=r(n),c=f.length;return a<0||a>=c?t?"":void 0:(u=f.charCodeAt(a),u<55296||u>56319||a+1===c||(i=f.charCodeAt(a+1))<56320||i>57343?t?f.charAt(a):u:t?f.slice(a,a+2):i-56320+(u-55296<<10)+65536)}}},function(t,e,n){var r=n(25),o=Math.max,u=Math.min;t.exports=function(t,e){return t=r(t),t<0?o(t+e,0):u(t,e)}},function(t,e,n){var r=n(25),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(65),o=n(2)("iterator"),u=n(13);t.exports=n(0).getIteratorMethod=function(t){if(void 0!=t)return t[o]||t["@@iterator"]||u[r(t)]}},function(t,e,n){var r=n(10),o=n(80);t.exports=n(0).getIterator=function(t){var e=o(t);if("function"!=typeof e)throw TypeError(t+" is not iterable!");return r(e.call(t))}},function(t,e,n){"use strict";var r=n(63),o=n(71),u=n(13),i=n(9);t.exports=n(36)(Array,"Array",function(t,e){this._t=i(t),this._i=0,this._k=e},function(){var t=this._t,e=this._k,n=this._i++;return!t||n>=t.length?(this._t=void 0,o(1)):"keys"==e?o(0,n):"values"==e?o(0,t[n]):o(0,[n,t[n]])},"values"),u.Arguments=u.Array,r("keys"),r("values"),r("entries")},function(t,e,n){var r=n(11);r(r.S+r.F,"Object",{assign:n(72)})},function(t,e,n){var r=n(11);r(r.S+r.F*!n(3),"Object",{defineProperty:n(5).f})},function(t,e,n){var r=n(8),o=n(37).onFreeze;n(41)("freeze",function(t){return function(e){return t&&r(e)?t(o(e)):e}})},function(t,e,n){var r=n(26),o=n(12);n(41)("keys",function(){return function(t){return o(r(t))}})},function(t,e){},function(t,e,n){"use strict";var r=n(1),o=n(4),u=n(3),i=n(11),f=n(42),a=n(37).KEY,c=n(6),l=n(24),s=n(22),p=n(16),d=n(2),y=n(29),v=n(28),h=n(67),b=n(69),m=n(10),g=n(8),O=n(9),S=n(27),x=n(15),j=n(38),_=n(75),w=n(74),E=n(5),A=n(12),N=w.f,M=E.f,P=_.f,T=r.Symbol,F=r.JSON,L=F&&F.stringify,R=d("_hidden"),k=d("toPrimitive"),B={}.propertyIsEnumerable,D=l("symbol-registry"),I=l("symbols"),C=l("op-symbols"),W=Object.prototype,G="function"==typeof T,U=r.QObject,Y=!U||!U.prototype||!U.prototype.findChild,z=u&&c(function(){return 7!=j(M({},"a",{get:function(){return M(this,"a",{value:7}).a}})).a})?function(t,e,n){var r=N(W,e);r&&delete W[e],M(t,e,n),r&&t!==W&&M(W,e,r)}:M,J=function(t){var e=I[t]=j(T.prototype);return e._k=t,e},Q=G&&"symbol"==typeof T.iterator?function(t){return"symbol"==typeof t}:function(t){return t instanceof T},V=function(t,e,n){return t===W&&V(C,e,n),m(t),e=S(e,!0),m(n),o(I,e)?(n.enumerable?(o(t,R)&&t[R][e]&&(t[R][e]=!1),n=j(n,{enumerable:x(0,!1)})):(o(t,R)||M(t,R,x(1,{})),t[R][e]=!0),z(t,e,n)):M(t,e,n)},q=function(t,e){m(t);for(var n,r=h(e=O(e)),o=0,u=r.length;u>o;)V(t,n=r[o++],e[n]);return t},H=function(t,e){return void 0===e?j(t):q(j(t),e)},K=function(t){var e=B.call(this,t=S(t,!0));return!(this===W&&o(I,t)&&!o(C,t))&&(!(e||!o(this,t)||!o(I,t)||o(this,R)&&this[R][t])||e)},X=function(t,e){if(t=O(t),e=S(e,!0),t!==W||!o(I,e)||o(C,e)){var n=N(t,e);return!n||!o(I,e)||o(t,R)&&t[R][e]||(n.enumerable=!0),n}},Z=function(t){for(var e,n=P(O(t)),r=[],u=0;n.length>u;)o(I,e=n[u++])||e==R||e==a||r.push(e);return r},$=function(t){for(var e,n=t===W,r=P(n?C:O(t)),u=[],i=0;r.length>i;)!o(I,e=r[i++])||n&&!o(W,e)||u.push(I[e]);return u};G||(T=function(){if(this instanceof T)throw TypeError("Symbol is not a constructor!");var t=p(arguments.length>0?arguments[0]:void 0),e=function(n){this===W&&e.call(C,n),o(this,R)&&o(this[R],t)&&(this[R][t]=!1),z(this,t,x(1,n))};return u&&Y&&z(W,t,{configurable:!0,set:e}),J(t)},f(T.prototype,"toString",function(){return this._k}),w.f=X,E.f=V,n(39).f=_.f=Z,n(14).f=K,n(21).f=$,u&&!n(20)&&f(W,"propertyIsEnumerable",K,!0),y.f=function(t){return J(d(t))}),i(i.G+i.W+i.F*!G,{Symbol:T});for(var tt="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),et=0;tt.length>et;)d(tt[et++]);for(var nt=A(d.store),rt=0;nt.length>rt;)v(nt[rt++]);i(i.S+i.F*!G,"Symbol",{for:function(t){return o(D,t+="")?D[t]:D[t]=T(t)},keyFor:function(t){if(!Q(t))throw TypeError(t+" is not a symbol!");for(var e in D)if(D[e]===t)return e},useSetter:function(){Y=!0},useSimple:function(){Y=!1}}),i(i.S+i.F*!G,"Object",{create:H,defineProperty:V,defineProperties:q,getOwnPropertyDescriptor:X,getOwnPropertyNames:Z,getOwnPropertySymbols:$}),F&&i(i.S+i.F*(!G||c(function(){var t=T();return"[null]"!=L([t])||"{}"!=L({a:t})||"{}"!=L(Object(t))})),"JSON",{stringify:function(t){for(var e,n,r=[t],o=1;arguments.length>o;)r.push(arguments[o++]);if(n=e=r[1],(g(e)||void 0!==t)&&!Q(t))return b(e)||(e=function(t,e){if("function"==typeof n&&(e=n.call(this,t,e)),!Q(e))return e}),r[1]=e,L.apply(F,r)}}),T.prototype[k]||n(7)(T.prototype,k,T.prototype.valueOf),s(T,"Symbol"),s(Math,"Math",!0),s(r.JSON,"JSON",!0)},function(t,e,n){n(28)("asyncIterator")},function(t,e,n){n(28)("observable")},function(e,n){e.exports=t},function(t,e,n){t.exports=n(45)}])}); -------------------------------------------------------------------------------- /hey.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: "build", 3 | webpack: { 4 | umd: { 5 | entry: "./src/model.js", 6 | library: "Model", 7 | filename: './model.js', 8 | }, 9 | externals: { 10 | "manba": "manba" 11 | } 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-model", 3 | "version": "1.6.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "manba": { 8 | "version": "1.2.8", 9 | "resolved": "https://registry.npmjs.org/manba/-/manba-1.2.8.tgz", 10 | "integrity": "sha512-+xCchh7TI1M7mVQFR+dMaFXWJnut/vlVbnE/K0CzQH40nN5/KIdRgc+WSvotbbszATXBI6jxvDXDXh5WHLPSGA==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-model", 3 | "version": "1.6.2", 4 | "description": "model for javascript", 5 | "main": "build/model.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/vvpvvp/model.git" 9 | }, 10 | "keywords": [ 11 | "model", 12 | "javascript", 13 | "js" 14 | ], 15 | "author": { 16 | "name": "alias" 17 | }, 18 | "license": "The MIT License", 19 | "bugs": { 20 | "url": "https://github.com/vvpvvp/model/issues" 21 | }, 22 | "scripts": { 23 | "build": "babel src/*.js -d build", 24 | "min": "babel build/*.js --minified --no-babelrc -o build/*.min.js", 25 | "test": "mocha --compilers js:babel-core/register ./test/*.js" 26 | }, 27 | "babel": { 28 | "presets": [ 29 | "es2015" 30 | ] 31 | }, 32 | "dependencies": { 33 | "manba": "^1.2.8" 34 | }, 35 | "homepage": "https://github.com/vvpvvp/model#readme", 36 | "readmeFilename": "README.md" 37 | } 38 | -------------------------------------------------------------------------------- /src/model.js: -------------------------------------------------------------------------------- 1 | import Utils from './utils'; 2 | import TYPE from './type'; 3 | import manba from 'manba'; 4 | 5 | const defaultParam = { 6 | //dispose的时候移除空数组 7 | removeEmptyArray: false, 8 | //parse的时候移除null数据 9 | removeNull: false, 10 | //移除null数据从数组中 11 | removeNullFromArray: false, 12 | //从子对象中移除空对象 13 | removeEmptyObject: true, 14 | } 15 | 16 | function analysis(data) { 17 | const outData = {}; 18 | if (Utils.isArray(data)) { 19 | if (data.length == 0) { 20 | return null; 21 | } else { 22 | return analysisObject(data[0]); 23 | } 24 | } else { 25 | for (const i of Object.keys(data)) { 26 | const n = data[i]; 27 | outData[i] = analysisObject(n); 28 | } 29 | return outData; 30 | } 31 | } 32 | 33 | function analysisObject(n) { 34 | let outData = null; 35 | if (n instanceof Model) { 36 | outData = n; 37 | } else if (Utils.isArray(n)) { 38 | outData = { 39 | type: TYPE.ARRAY, 40 | value: analysis(n), 41 | } 42 | } else if (Utils.isObject(n)) { 43 | let keys = Object.keys(n); 44 | let isNotSettingKeys = keys.some(item=>['type', 'default', 'unit', 'format', 'parse', 'dispose', 'computed'].indexOf(item) == -1); 45 | let type = getStaticType(n.type); 46 | // 已配置规则 47 | if (type && !isNotSettingKeys) { 48 | outData = {}; 49 | Object.assign(outData, n, {type}); 50 | } else { 51 | // 嵌套数据 52 | outData = { 53 | type: TYPE.OBJECT, 54 | value: analysis(n), 55 | } 56 | } 57 | } else { 58 | outData = { 59 | type: getType(n), 60 | } 61 | } 62 | return outData; 63 | } 64 | 65 | function parseObject(data, model, param, parent) { 66 | if (model instanceof Model) { 67 | if (param.isParse) { 68 | return model.parse(data, param); 69 | } else { 70 | return model.dispose(data, param); 71 | } 72 | } 73 | // isParse, parentData 74 | if (param.isDispose && Utils.isFunction(model.computed)) { 75 | return model.computed.call(null, parent); 76 | } 77 | 78 | if (param.isDispose && Utils.isFunction(model.dispose)) { 79 | return model.dispose.call(null, parent); 80 | } 81 | if (param.isParse && Utils.isFunction(model.parse)) { 82 | return model.parse.call(null, parent); 83 | } 84 | if (data === undefined || data === null) { 85 | if (model.type == TYPE.ARRAY && param.isParse) { 86 | return []; 87 | } else if (!(model.type == TYPE.OBJECT && param.isParse)) { 88 | if (!param.removeNull && model.default != undefined) { 89 | return model.default; 90 | } 91 | return null; 92 | } 93 | } 94 | let outData = data; 95 | switch (model.type) { 96 | case TYPE.OBJECT: 97 | outData = {}; 98 | const columns = 0; 99 | if (param.isParse) { 100 | const keys = Utils.mergeArray(Object.keys(model.value), data ? Object.keys(data) : []); 101 | for (const i of keys) { 102 | if (model.value.hasOwnProperty(i)) { 103 | data = data || {}; 104 | const _out = parseObject(data[i], model.value[i], param, data); 105 | if (param.removeNull && (_out == undefined || _out == null || (Utils.isArray(_out) && _out.length == 0))) { 106 | continue; 107 | } else { 108 | outData[i] = _out; 109 | } 110 | } else { 111 | outData[i] = Utils.deepCopy(data[i]); 112 | } 113 | } 114 | } else { 115 | for (const i of Object.keys(data)) { 116 | if (model.value.hasOwnProperty(i)) { 117 | const d = parseObject(data[i], model.value[i], param, data); 118 | if (d != undefined && d != null) { 119 | if (param.removeEmptyArray && Utils.isArray(d) && d.length == 0) { 120 | continue; 121 | } 122 | outData[i] = d; 123 | } 124 | } 125 | } 126 | } 127 | // 依旧为空对象 128 | if (Object.keys(outData).length == 0 && param.removeEmptyObject && !Utils.isArray(parent)) outData = null; 129 | break; 130 | case TYPE.ARRAY: 131 | outData = []; 132 | for (const n of data) { 133 | const r = parseObject(n, model.value, param, data); 134 | if (!(param.removeNullFromArray && r == null)) { outData.push(r); } 135 | } 136 | break; 137 | case TYPE.NUMBER: 138 | if (Utils.isString(data) && data == '') { 139 | outData = null; 140 | } else { 141 | outData = Number(data); 142 | if (model.unit) { 143 | if (param.isParse) { 144 | outData = Utils.div(outData, model.unit); 145 | } else { 146 | outData = Utils.mul(outData, model.unit); 147 | } 148 | } 149 | } 150 | break; 151 | case TYPE.DATE: 152 | if (Utils.isString(data) && data == '') { 153 | outData = null; 154 | } else if (!data) { 155 | outData = null; 156 | } else if (param.isParse) { 157 | outData = manba(data).format(model.format || ''); 158 | } else { 159 | outData = Model.disposeDateFormat(data, model.format); 160 | } 161 | break; 162 | case TYPE.BOOLEAN: 163 | if (data === true || data == 'true') { 164 | outData = true; 165 | } else if (data === false || data == 'false') { 166 | outData = false; 167 | } else { 168 | outData = null; 169 | } 170 | break; 171 | case TYPE.STRING: 172 | outData = String(data); 173 | 174 | } 175 | if (TYPE.isType(model.type) && param.isParse && Utils.isFunction(model.format) && outData) { 176 | outData = model.format.call(null, outData); 177 | } 178 | // dispose 的时候 如果为"",则输出null 179 | if (param.isDispose && param.setEmptyNull && Utils.isString(outData) && outData == '') { 180 | outData = null; 181 | } 182 | return outData; 183 | } 184 | 185 | function _parse(data, model, param) { 186 | let outData = null; 187 | 188 | if (data === null || data === undefined) { 189 | if (param.isParse) { 190 | data = {}; 191 | } else { 192 | return null; 193 | } 194 | } 195 | if (Utils.isArray(data)) { 196 | outData = []; 197 | for (const n of data) { 198 | outData.push(parseObject(n, model, param, data)); 199 | } 200 | } else if (Utils.isObject(data)) { 201 | outData = parseObject(data, model, param); 202 | if (outData == null) { 203 | return {}; 204 | } 205 | } else { 206 | outData = data; 207 | } 208 | 209 | return outData; 210 | } 211 | 212 | const getStaticType = function(data) { 213 | if (data == null) { 214 | return false; 215 | } 216 | if (TYPE.isType(data)) { 217 | return data; 218 | } 219 | return false; 220 | } 221 | 222 | const getType = function(data) { 223 | if (TYPE.isType(data)) { 224 | return data; 225 | } 226 | if (Utils.isNumber(data)) { 227 | return TYPE.NUMBER; 228 | } else if (Utils.isString(data)) { 229 | return TYPE.STRING; 230 | } else if (Utils.isBoolean(data)) { 231 | return TYPE.BOOLEAN; 232 | } 233 | return TYPE.STRING; 234 | } 235 | 236 | class Model { 237 | constructor(_model) { 238 | this._model = analysisObject(_model); 239 | } 240 | 241 | parse(data, param = {}) { 242 | param.isParse = true; 243 | param.isDispose = false; 244 | return _parse(data, this._model, Utils.extend({}, defaultParam, param)); 245 | } 246 | 247 | dispose(data, param = {}) { 248 | param.isParse = false; 249 | param.isDispose = true; 250 | return _parse(data, this._model, Utils.extend({}, defaultParam, param)); 251 | } 252 | } 253 | 254 | Model.DATE = TYPE.DATE; 255 | Model.NUMBER = TYPE.NUMBER; 256 | Model.STRING = TYPE.STRING; 257 | Model.BOOLEAN = TYPE.BOOLEAN; 258 | Model.Date = TYPE.DATE; 259 | Model.Number = TYPE.NUMBER; 260 | Model.String = TYPE.STRING; 261 | Model.Boolean = TYPE.BOOLEAN; 262 | Model.S = TYPE.S; 263 | Model.B = TYPE.B; 264 | Model.Q = TYPE.Q; 265 | Model.W = TYPE.W; 266 | Model.SW = TYPE.SW; 267 | Model.BW = TYPE.BW; 268 | Model.QW = TYPE.QW; 269 | Model.Y = TYPE.Y; 270 | 271 | Model.disposeDateFormat = (str, format) => { 272 | return manba(str).toISOString(); 273 | } 274 | Model.config = (params) => { 275 | if(Utils.isFunction(params.disposeDateFormat)){ 276 | Model.disposeDateFormat = params.disposeDateFormat; 277 | } 278 | } 279 | module.exports = Model; 280 | -------------------------------------------------------------------------------- /src/type.js: -------------------------------------------------------------------------------- 1 | import Utils from './utils'; 2 | const TYPE = { 3 | STRING: String, 4 | DATE: Date, 5 | NUMBER: Number, 6 | BOOLEAN: Boolean, 7 | OBJECT: Object, 8 | ARRAY: Array, 9 | isType(date) { 10 | return date === this.STRING || 11 | date === this.DATE || 12 | date === this.NUMBER || 13 | date === this.BOOLEAN; 14 | }, 15 | S: 10, 16 | B: 100, 17 | Q: 1000, 18 | W: 10000, 19 | SW: 100000, 20 | BW: 1000000, 21 | QW: 10000000, 22 | Y: 100000000, 23 | } 24 | Utils.deepFreeze(TYPE); 25 | export default TYPE; 26 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | isObject(input) { 4 | return Object.prototype.toString.call(input) === '[object Object]'; 5 | }, 6 | isArray(input) { 7 | return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]'; 8 | }, 9 | isDate(input) { 10 | return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]'; 11 | }, 12 | isNumber(input) { 13 | return input instanceof Number || Object.prototype.toString.call(input) === '[object Number]'; 14 | }, 15 | isString(input) { 16 | return input instanceof String || Object.prototype.toString.call(input) === '[object String]'; 17 | }, 18 | isBoolean(input) { 19 | return typeof input == 'boolean'; 20 | }, 21 | isFunction(input) { 22 | return typeof input == 'function'; 23 | }, 24 | deepCopy(data) { 25 | let copyOne = null; 26 | if (this.isObject(data)) { 27 | copyOne = {}; 28 | for (const key in data) { 29 | copyOne[key] = this.deepCopy(data[key]); 30 | } 31 | } else if (this.isArray(data)) { 32 | copyOne = []; 33 | for (const index of data) { 34 | copyOne.push(this.deepCopy(index)); 35 | } 36 | } else { 37 | copyOne = data; 38 | } 39 | return copyOne; 40 | }, 41 | deepFreeze(obj) { 42 | const that = this; 43 | Object.freeze(obj); 44 | Object.keys(obj).forEach((key, value) => { 45 | if (that.isObject(obj[key])) { 46 | this.deepFreeze(obj[key]); 47 | } 48 | }); 49 | return obj; 50 | }, 51 | mergeArray(arr1, arr2) { 52 | for (var i = 0; i < arr1.length; i++) { 53 | for (let j = 0; j < arr2.length; j++) { 54 | if (arr1[i] === arr2[j]) { 55 | arr1.splice(i, 1); 56 | } 57 | } 58 | } 59 | for (var i = 0; i < arr2.length; i++) { 60 | arr1.push(arr2[i]); 61 | } 62 | return arr1; 63 | }, 64 | extend: function () { 65 | var options, name, src, copy, copyIsArray, clone, 66 | target = arguments[0] || {}, 67 | i = 1, 68 | length = arguments.length, 69 | deep = false; 70 | if (typeof target === "boolean") { 71 | deep = target; 72 | target = arguments[1] || {}; 73 | i = 2; 74 | } 75 | if (typeof target !== "object" && !this.isFunction(target)) { 76 | target = {}; 77 | } 78 | if (length === i) { 79 | target = this; 80 | --i; 81 | } 82 | for (; i < length; i++) { 83 | if ((options = arguments[i]) != null) { 84 | for (name in options) { 85 | src = target[name]; 86 | copy = options[name]; 87 | if (target === copy) { 88 | continue; 89 | } 90 | if (deep && copy && (this.isPlainObject(copy) || (copyIsArray = this.isArray(copy)))) { 91 | if (copyIsArray) { 92 | copyIsArray = false; 93 | clone = src && this.isArray(src) ? src : []; 94 | } else { 95 | clone = src && this.isPlainObject(src) ? src : {}; 96 | } 97 | target[name] = this.extend(deep, clone, copy); 98 | } else if (copy !== undefined) { 99 | target[name] = copy; 100 | } 101 | } 102 | } 103 | } 104 | return target; 105 | }, 106 | add(arg1, arg2) { 107 | let s1 = arg1.toString(); 108 | let s2 = arg2.toString(); 109 | let arg1Arr = s1.split("."); 110 | let arg2Arr = s2.split("."); 111 | let d1 = arg1Arr.length == 2 ? arg1Arr[1] : ""; 112 | let d2 = arg2Arr.length == 2 ? arg2Arr[1] : ""; 113 | let maxLen = Math.max(d1.length, d2.length); 114 | let m = Math.pow(10, maxLen); 115 | return Number(((s1 * m + s2 * m) / m).toFixed(maxLen)); 116 | }, 117 | sub(arg1, arg2) { 118 | return this.add(arg1, -arg2); 119 | }, 120 | mul(arg1, arg2) { 121 | let m = 0; 122 | let s1 = arg1.toString(); 123 | let s2 = arg2.toString(); 124 | try { m += s1.split(".")[1].length } catch (e) {} 125 | try { m += s2.split(".")[1].length } catch (e) {} 126 | return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m); 127 | }, 128 | div(arg1, arg2) { 129 | let t1 = 0; 130 | let t2 = 0; 131 | try { t1 = arg1.toString().split(".")[1].length } catch (e) {} 132 | try { t2 = arg2.toString().split(".")[1].length } catch (e) {} 133 | let r1 = Number(arg1.toString().replace(".", "")); 134 | let r2 = Number(arg2.toString().replace(".", "")); 135 | return this.mul((r1 / r2) , Math.pow(10, t2 - t1)); 136 | } 137 | }; 138 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | // let Model = require("../build/model"); 2 | let Model = require("../src/model"); 3 | var expect = require('chai').expect; 4 | (function () { 5 | 'use strict'; 6 | const FORMAT = { 7 | L: "l", 8 | LL: "ll", 9 | KK: "k", 10 | GET: function (data) { 11 | return "get" + data; 12 | } 13 | } 14 | 15 | let Basic = new Model({ 16 | "source": Date, 17 | "description": { 18 | type: String, 19 | format: FORMAT.GET 20 | }, 21 | "tags": [ 22 | 0 23 | ], 24 | "companyId": { 25 | type: Model.String, 26 | default: "测试" 27 | }, 28 | "rate": { 29 | type: Model.Number, 30 | computed: function (data) { 31 | return data.rateFrom + 3; 32 | } 33 | }, 34 | "id": 0 35 | }); 36 | 37 | 38 | let Edu = new Model({ 39 | "startTime": { 40 | type: Date, 41 | format: FORMAT.L 42 | }, 43 | "degree": 0, 44 | "major": "", 45 | "school": "", 46 | "endTime": 0, 47 | "takeTime": "", 48 | "id": "" 49 | }); 50 | 51 | 52 | let User = new Model({ 53 | "basic": Basic, 54 | "bind": {}, 55 | "edu": [Edu] 56 | }); 57 | 58 | describe('judge type object', function () { 59 | 60 | let TypeModel = new Model({ 61 | type: String, 62 | list: [{ 63 | type: Number, 64 | default: 1 65 | }], 66 | object: { 67 | type: Boolean, 68 | id: 0, 69 | }, 70 | normal: { 71 | type: Number 72 | } 73 | }); 74 | 75 | it('judge type object parse', function () { 76 | expect(TypeModel.parse({list:["12"]})).to.be.deep.equal({ 77 | type: null, 78 | list: [12], 79 | object: { 80 | type: null, 81 | id: null, 82 | }, 83 | normal: null 84 | }); 85 | }); 86 | 87 | it('judge type object dispose', function () { 88 | expect(TypeModel.dispose({ 89 | type: 123, 90 | list: ["12"], 91 | object: { 92 | type: false, 93 | id: "23" 94 | }, 95 | normal: "123" 96 | })).to.be.deep.equal({ 97 | type: "123", 98 | list: [12], 99 | object: { 100 | type: false, 101 | id: 23, 102 | }, 103 | normal: 123 104 | }); 105 | }); 106 | 107 | }); 108 | 109 | describe('basic model', function () { 110 | 111 | 112 | let value = User.parse({ 113 | basic: { 114 | id: "123123", 115 | source: "Tue Apr 19 2016 21:46:11 GMT+0800 (CST)", 116 | tags: [ 117 | "12", "32" 118 | ], 119 | rateFrom: 1 120 | } 121 | }); 122 | 123 | 124 | 125 | it('parse full model', function () { 126 | expect(value).to.be.deep.equal({ 127 | bind: null, 128 | edu: [], 129 | basic: { 130 | description: null, 131 | companyId: '测试', 132 | rate: null, 133 | id: 123123, 134 | source: '2016-04-19', 135 | tags: [12, 32], 136 | rateFrom: 1 137 | } 138 | }); 139 | 140 | }); 141 | 142 | it('parse empty value', function () { 143 | expect(User.parse({})).to.be.deep.equal({ 144 | bind: null, 145 | edu: [], 146 | basic: { 147 | description: null, 148 | companyId: "测试", 149 | rate: null, 150 | id: null, 151 | source: null, 152 | tags: [] 153 | } 154 | }); 155 | 156 | }); 157 | 158 | 159 | it('dispose post data', function () { 160 | expect(User.dispose(value)).to.be.deep.equal({ 161 | edu: [], 162 | basic: { 163 | companyId: '测试', 164 | id: 123123, 165 | rate: 4, 166 | source: '2016-04-19T00:00:00+08:00', 167 | tags: [12, 32] 168 | } 169 | }); 170 | }); 171 | 172 | 173 | it('dispose post data2', function () { 174 | let Test = new Model({ 175 | id:0 176 | }); 177 | expect(Test.dispose([{id:null}])).to.be.deep.equal([{}]); 178 | }); 179 | 180 | 181 | 182 | it('disposeDateFormat', function () { 183 | let Test1 = new Model({ 184 | source: Model.DATE 185 | }); 186 | 187 | Model.config({ 188 | disposeDateFormat(date) { 189 | return new Date(date).getTime(); 190 | } 191 | }) 192 | expect(Test1.dispose({ 193 | source: '2016-04-19' 194 | })).to.be.deep.equal({ 195 | source: 1461024000000 196 | }); 197 | 198 | }); 199 | 200 | let Test2 = new Model({ 201 | money: { 202 | type: Number, 203 | unit: Model.Q 204 | } 205 | }); 206 | 207 | it('parseMoney', function () { 208 | expect(Test2.parse({ 209 | money: 32209.99 210 | })).to.be.deep.equal({ 211 | money: 32.20999 212 | }); 213 | }); 214 | 215 | it('disposeMoney', function () { 216 | expect(Test2.dispose({ 217 | money: 32.200 218 | })).to.be.deep.equal({ 219 | money: 32200 220 | }); 221 | }); 222 | 223 | }); 224 | 225 | 226 | 227 | describe('parse, dispose function', function () { 228 | 229 | let pdModel = new Model({ 230 | parse: { 231 | type: Number, 232 | parse(data) { 233 | return data.id + 1 234 | } 235 | }, 236 | dispose: { 237 | type: Number, 238 | parse(data) { 239 | return data.dispose * 10 240 | }, 241 | dispose(data) { 242 | return data.dispose / 10 243 | } 244 | }, 245 | id: 0 246 | }); 247 | 248 | it('judge type object parse', function () { 249 | expect(pdModel.parse({id: 1, dispose: 10})).to.be.deep.equal({ 250 | parse: 2, 251 | dispose: 100, 252 | id: 1, 253 | }); 254 | }); 255 | 256 | it('judge type object dispose', function () { 257 | expect(pdModel.dispose({ 258 | id: 1, dispose: 10 259 | })).to.be.deep.equal({ 260 | dispose: 1, 261 | id: 1 262 | }); 263 | }); 264 | 265 | }); 266 | 267 | }()); 268 | --------------------------------------------------------------------------------