├── .gitignore ├── LICENSE ├── README.md ├── lib ├── deepClone.ts ├── filedsUtils.ts ├── index.d.ts ├── index.ts ├── log.ts ├── turboSetData.ts ├── typeUtils.ts └── watcher.ts ├── package-lock.json ├── package.json ├── rollup.config.js └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2022 CorderLiu(yuluLiu) 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.MITLicenseCopyright2022CorderLiuPermissionisherebygranted,freeofcharge,toanypersonobtainingacopyofthissoftwareandassociateddocumentationfilestodealintheSoftwarewithoutrestriction,includingwithoutlimitationtherightstouse,copy,modify,merge,publish,distribute,sublicense,and/orsellcopiesoftheSoftware,andtopermitpersonstowhomtheSoftwareisfurnishedtodoso,subjecttothefollowingconditionsMITLicenseCopyright2022CorderLiuPermissionisherebygranted,freeofcharge,toanypersonobtainingacopyofthissoftwareandassociateddocumentationfilestodealintheSoftwarewithoutrestriction,includingwithoutlimitationtherightstouse,copy,modify,merge,publish,distribute,sublicense,and/orsellcopiesoftheSoftware,andtopermitpersonstowhomtheSoftwareisfurnishedtodoso,subjecttothefollowingconditions 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # miniprogram-turbo-setdata 3 | 4 | `miniprogram-turbo-setdata` 是一个小程序 `setData` 增强库,该库顾名思义,用来增强原生`setData`能力,大幅提高 `setData` 的性能,该工具对照官方优化建议文档,尽可能地自动实现 `setData` 优化,让你放心地使用 `setData` ,开发中只需关注业务逻辑,提高开发效率和开发体验的同时也能大幅提高性能。 5 | 6 | 具体支持特性如下: 7 | 8 | * 合并 `setData` 9 | * 去重 `setData` 10 | * 监听 `setData` 11 | * 输出 `setData` 调用日志 12 | 13 | ## 使用 14 | 15 | ``` bash 16 | npm install miniprogram-turbo-setdata 17 | ``` 18 | 19 | 工具支持按需引入,可以全局使用,也可以在某个页面或组件中单独使用 20 | 21 | ``` js 22 | // app.js 全局引入,会增强所有页面 23 | import { useTurboAllPage } from 'miniprogram-turbo-setdata'; 24 | 25 | useTurboAllPage(); 26 | ``` 27 | 28 | ``` js 29 | // app.js 全局引入,会增强所有组件 30 | import { useTurboAllComponent } from 'miniprogram-turbo-setdata'; 31 | 32 | useTurboAllComponent(); 33 | ``` 34 | 35 | ``` js 36 | // 单个页面使用,只需一行导入即可生效 37 | import { Page } from 'miniprogram-turbo-setdata'; 38 | 39 | Page({ 40 | data: {}, 41 | ... 42 | }) 43 | ``` 44 | 45 | ``` js 46 | // 单个组件使用,只需一行导入即可生效 47 | import { Component } from 'miniprogram-turbo-setdata'; 48 | 49 | Component({ 50 | data: {}, 51 | ... 52 | }) 53 | ``` 54 | 55 | > 已经全局应用后,无需再单独引入。 56 | 57 | ## 特性 58 | 59 | ### 合并 setData 60 | 61 | 自动合并同一时间片的被更新数据,工具将缓冲它们到下一个时机统一执行更新操作。该功能针对官方优化建议中的第二条:**减少setData频率**。 62 | 63 | 例如: 64 | 65 | ``` js 66 | // 处理前 67 | this.setData({obj: {a: 3}}); 68 | this.setData({arr: []}); 69 | this.setData({obj1: {a: 3}}); 70 | this.setData({obj2: {a: 3}}); 71 | this.setData({obj3: {a: 3}}); 72 | // 5次连续的setData正常情况下,会触发5次与渲染层的通讯,性能严重浪费 73 | 74 | // 处理后 75 | this.setData({obj: {a: 4}, arr: [], ..., obj3: {a: 3}}); 76 | // 使用工具后,工具会自动将数据合并,只执行一次setData,大大减少通信消耗,提高响应速度 77 | 78 | ``` 79 | 80 | 回调函数也会正常触发 81 | 82 | ``` js 83 | // 处理前 84 | 85 | this.setData({obj2: {a: 3}}, ()=>{}); 86 | this.setData({obj3: {a: 3}}, ()=>{}); 87 | // 5次连续的setData正常情况下,会触发5次与渲染层的通讯,性能严重浪费 88 | 89 | // 处理后 90 | this.setData({obj: {a: 4}, arr: [], ..., obj3: {a: 3}}, ()=>{ 91 | // 遍历执行所有回调函数 92 | }); 93 | // 使用工具后,工具会自动将数据合并,只执行一次setData,大大减少通信消耗,提高响应速度 94 | 95 | ``` 96 | 97 | 同一时间片的相同 setData 只会生效最后一个 98 | 99 | ``` js 100 | // 处理前 101 | 102 | this.setData({obj: {a: 3}}, ()=>{}); // 该 setData 不会与渲染层交互,但会执行回调 103 | this.setData({obj: {a: 3}}, ()=>{}); // 该 setData 后生效 104 | 105 | // 处理后 106 | this.setData({obj: {a: 3}}, ()=>{ 107 | // 遍历执行所有回调函数,即使 setData 的数据相同,回调函数也会依次执行,但是数据更新只执行一次 108 | }); 109 | // 使用工具后,工具会自动将数据合并,只执行一次setData,大大减少通信消耗,提高响应速度 110 | 111 | ``` 112 | 113 | 存在异步任务的情况 114 | 115 | ``` js 116 | // 处理前 117 | this.setData({obj: {a: 3}}); 118 | this.setData({arr: []}); 119 | this.setData({obj1: {a: 3}}); 120 | this.setData({obj2: {a: 3}}); 121 | this.setData({obj3: {a: 3}}); 122 | // 宏任务在下一轮事件循环开始时执行 123 | setTimeout(()=>{ 124 | this.setData({obj4: {a: 3}}); 125 | }, 1000); 126 | 127 | // 微任务在本轮循环结束前执行,即宏任务执行完立刻执行微任务,微任务属于本轮事件循环 128 | new Promise((resolve) => { 129 | resolve(); 130 | }).then((res) => { 131 | this.setData({ obj6: { a: 3 } }); 132 | }); 133 | Promise.resolve().then(() => { 134 | this.setData({ obj5: { a: 3 } }); 135 | }); 136 | 137 | // 小程序中的nextTick属于宏任务,在下个事件循环开始时执行,类似于setTimeout,但是它的执行时机永远早于setTimeout 138 | wx.nextTick(() => { 139 | this.setData({ obj7: { a: 3 } }); 140 | }); 141 | wx.nextTick(() => { 142 | this.setData({ obj8: { a: 3 } }); 143 | }); 144 | 145 | 146 | // 处理后 147 | this.setData({obj: {a: 4}, arr: [], ..., obj3: {a: 3}, obj5:{a: 3}, obj6: {a: 3}}); 148 | this.setData({ obj7: { a: 3 }, obj8: {a: 3} }); 149 | this.setData({obj4: {a: 3}}); 150 | 151 | // 异步任务被放入下一时间片处理,以上那么多个setData最终被合并为3个。 152 | 153 | ``` 154 | 155 | ### 去重 setData 156 | 157 | 将即将被更新的数据与现存数据进行对比,忽略重复数据,达到只更新发生变化的数据的效果。 158 | 159 | 例如: 160 | 161 | ``` js 162 | Page({ 163 | data: { 164 | obj: {a: 3, b: 6}, 165 | open: true, 166 | }, 167 | onLoad(){ 168 | this.setData({ open: true }); // 该 setData 不会被触发 169 | this.setData({ 'obj.a': 3 }); // 该 setData 不会被触发 170 | this.setData({ obj: {a: 3, b: 5} }); // 只更新 this.setData({'obj.b': 5}),自动更改为数据路径形式 171 | this.setData({ 'obj.b': 5 }); // 已经被改为 5 了,该 setData 不会被触发 172 | } 173 | }) 174 | ``` 175 | 176 | 深层级的对象或数组也支持 `diff`,都会在内部被改成数据路径形式,例如`this.setData({'obj.a.b.c': {a: 3}})`,开发者对此是无感知的,正常写逻辑代码就好。 177 | 178 | ## 监听 setData 179 | 180 | 可以使用 watch 字段对数据变化进行监听: 181 | 182 | ``` js 183 | Page({ 184 | watch: { 185 | arr(newVal, oldval) { // 监听数组字段 186 | 187 | }, 188 | 189 | 'filter.expanding'(newVal, oldval) { // 监听对象子属性,兄弟属性变化不触发 190 | 191 | }, 192 | 193 | 'entries[1].key'(newVal, oldval) { // 监听数组对象子属性 194 | 195 | }, 196 | 197 | obj(newVal, oldval) { // 监听对象,子属性变化也会触发 198 | 199 | }, 200 | }, 201 | }) 202 | 203 | ``` 204 | 205 | **只有变化的数据才会触发监听回调**。 206 | 207 | **特别注意:** 208 | 209 | 小程序官方对于 setData 的限制是只能传入可 JSON 化的数据,如 `Map`、`Set`、正则、`Date` 等会被转为 `{}`,空对象,不要监听这些数据。 210 | 211 | 异常类型示例: 212 | 213 | ``` js 214 | 215 | const obj = { 216 | nan: NaN, 217 | infinityMax: 1.7976931348623157E+10308, 218 | infinityMin: -1.7976931348623157E+10308, 219 | undef: undefined, 220 | fun: () => 'func', 221 | date: new Date(), 222 | map: new Map(), 223 | set: new Set(), 224 | reg: /\w+/, 225 | }, 226 | 227 | 小程序处理后的数据: 228 | 229 | 1. date: {} 230 | 2. fun: ƒ fun() // 函数可以正常传递,从基础库 2.0.9 开始,对象类型的属性和 data 字段中可以包含函数类型的子字段,即可以通过对象类型的属性字段来传递函数。 231 | 3. infinityMax: Infinity 232 | 4. infinityMin: -Infinity 233 | 5. map: {} 234 | 6. nan: NaN 235 | 7. reg: {} 236 | 8. set: {} 237 | 9. undef: undefined 238 | 239 | 而 JSON.stringfy 之后的结果: 240 | 241 | nan: NaN, // NaN拷贝后变成null 242 | infinityMax: 1.7976931348623157E+10308, // 浮点数的最大值拷贝后变成null 243 | infinityMin: -1.7976931348623157E+10308, // 浮点数的最小值拷贝后变成null 244 | undef: undefined, // 拷贝后直接丢失 245 | fun: () => 'func', // 拷贝后直接丢失 246 | date: new Date(), // 时间类型拷贝后会被变成字符串类型数据 247 | map: new Map(), // {} 248 | set: new Set(), // {} 249 | reg: /\w+/, // {} 250 | 251 | ``` 252 | 253 | 所以小程序内的数据转化还不完全是依赖 `JSON.stringfy`,还有额外的判断和处理,例如要做函数支持等,应该是先对数据进行处理再 `stringfy` 然后传给渲染层,这也恰好说明了 `setData` 一次性能消耗过大的原因。 254 | 255 | ## setData 选项 256 | 257 | **SetDataOptions** 258 | 259 | |参数 |说明 |类型 |默认值 260 | |:--|:--|:--:|:--:| 261 | |`useNative` |是否使用原生setData方法 | boolean | false | 262 | |`useOldValue` |是否在数据长度变化时复用旧值 |boolean | false| 263 | |`useSyncData` |是否需要在setData后同步获取新值 |boolean |false | 264 | 265 | **使用:** 266 | 267 | ``` js 268 | // useNative 269 | 270 | this.setData({obj: {a: 3}}, null, {useNative: true}); 271 | 272 | // 工具已经足够健壮,但是任何情况你不想使用优化 setData 了(遇到了一些极端情况),仍提供可以调用原生 setData 方法的选择 273 | ``` 274 | 275 | ``` js 276 | // useOldValue 277 | 278 | const list = [...]; // length: 10 279 | const newList = [...].concat(list); // length: 20 280 | this.setData({list: newList}, null, {useOldValue: true}); 281 | 282 | // 默认情况下当数据长度变化时不再 diff 子属性,而是直接更新 newList 的所有数据(20 条),开启useOldValue后,会复用旧值,前 10 个已经渲染过,本次更新将只更新新添加的后 10 个 283 | ``` 284 | 285 | ``` js 286 | // useSyncData 287 | 288 | this.setData({obj: {a: 6}}, null, {useSyncData: true}); 289 | console.log(this.data.obj); // {a: 6},可以立即获取到新值 290 | 291 | // 在setData后同步获取新值,默认禁用,原生是可以在 setData 后 通过 this.data 获取到新值的,但是一般情况用不到,对于有大量数据路径形式更新值的页面禁用会节省一些性能消耗,使 turbo setdata 工具发挥极致作用 292 | ``` 293 | 294 | 你还可以在 setData 的回调中获取新值,或者像 `Vue` 一样,在 `nextTick` 中获取新值。 295 | 296 | 例如: 297 | 298 | ``` js 299 | this.setData({obj: {a: 6}}, null, {useSyncData: true}); 300 | // 使用下面两种方式也可以 301 | this.setData({ 'obj.b.c': 8 }); 302 | wx.nextTick(() => { 303 | console.log(this.data.obj.b.c); // 8 304 | }); 305 | ``` 306 | 307 | 如果你想兼容旧项目或页面,想拿来即用并不想做任何修改,也有全局选项可以提供设置,后面详细说明。 308 | > 但是还是推荐不要开启全局同步更新,人工查找一下页面内通过 `this.data` 方式同步获取值的代码也非常容易。 309 | 310 | **为什么默认禁用同步更新逻辑层 data 的功能?** 311 | 312 | 1. **为了工具有更强的表现**,实际上这部分做了一个解析数据路径并遍历赋值的操作,但是其实倒也不复杂,仅可能会对使用较多数据路径更新值的页面或组件有较大影响。 313 | 314 | 2. **同步使用 this.data 获取值并不常用**(如果你的 data 都是仅与渲染层相关的数据,而不是把其他数据也挂在 this.data 上,这里不理解的同学可以看我的另一篇关于 setData 的文章),工具自动更新了但是开发者没有使用,性能就浪费了,所以由开发者根据需求自由开启。 315 | 316 | ### 工具选项 317 | 318 | **TurboOptions** 319 | 320 | |参数 |说明 |类型 |默认值 321 | |:--|:--|:--:|:--:| 322 | |`useSyncData` |是否需要在 setData 后同步获取新值(全局生效) | boolean | false | 323 | |`logNative` |是否输出原生表现日志 | boolean | false | 324 | |`logTimeConsuming` |是否输出优化后的 setData 耗时和次数 |boolean | false| 325 | |`logUpdatedData` |是否输出每次 setData 被更新的数据(合并且 diff 后的) |boolean |false | 326 | |`logDuplicateData` |是否输出查找到的重复数据 |boolean |false | 327 | 328 | 使用: 329 | 330 | ``` js 331 | // 在 Page 或 Component 构造器的第二个参数中填写以下选项 332 | Page( 333 | { 334 | data: {}, 335 | methods: {}, 336 | ... 337 | }, 338 | { 339 | turboOptions: { 340 | useSyncData: true, // 是否需要在 setData 后同步获取新值(全局配置) 341 | logNative: true, // 是否输出原生表现日志,开启后会使用原生 setData 并输出耗时和次数,可用于对比优化效果 342 | logTimeConsuming: true, // 是否输出优化后的 setData 耗时和次数 343 | logUpdatedData: true, // 是否输出本次 setData 被更新的数据(合并且 diff 后的) 344 | logDuplicateData: true, // 是否输出被筛选出的重复数据 345 | } 346 | } 347 | ) 348 | ``` 349 | 350 | 以上日志输出功能对帮助开发者自查和自优化有很大作用。 351 | 352 | ## miniprogram-turbo-setdata 优势 353 | 354 | #### 1. 高性能 355 | 356 | 工具遵循性能优先原则,实现的代码优先考虑时间复杂度以及执行效率,开发过程中反复对比测试不同写法的耗时,力求既快又强。 357 | 358 | > 因库的性能优先性质,所以很多写法都与正常业务代码不一样,对源码感兴趣的同学学习过程中请注意这点。 359 | 360 | #### 2. 非侵入性、稳定 361 | 362 | 遵循面向切面开发思想,在小程序原有功能基础上进行扩展,所有功能的实现无任何破坏性,无论是引入使用方式和工具选项的传参方式都极具兼容性,不使用时去掉引用即可,代码无需任何更改,小程序照跑不误。工具经过长期测试才放出稳定版本。 363 | 364 | #### 3. 灵活、简单 365 | 366 | 工具支持按需引入,可以全局使用,也可以在某个页面或组件中单独使用,给你足够灵活的选择空间,无论是新项目还是旧项目引入形式任意选,简单到不能再简单~ 367 | 368 | ``` js 369 | // app.js 全局引入,会增强所有页面 370 | import { useTurboAllPage } from 'miniprogram-turbo-setdata'; 371 | useTurboAllPage(); 372 | ``` 373 | 374 | ``` js 375 | // app.js 全局引入,会增强所有组件 376 | import { useTurboAllComponent } from 'miniprogram-turbo-setdata'; 377 | useTurboAllComponent(); 378 | ``` 379 | 380 | ``` js 381 | // 单个页面使用,只需一行导入即可生效 382 | import { Page } from 'miniprogram-turbo-setdata'; 383 | Page({ 384 | data: {}, 385 | ... 386 | }) 387 | ``` 388 | 389 | ``` js 390 | // 单个组件使用,只需一行导入即可生效 391 | import { Component } from 'miniprogram-turbo-setdata'; 392 | Component({ 393 | data: {}, 394 | ... 395 | }) 396 | ``` 397 | 398 | > miniprogram-turbo-setdata 更擅长优化数据复杂、setData 次数较多的页面,对于较简单的页面,setData 次数也就一两次,工具可能起到的作用很有限。 399 | 400 | > 也可仅用于开发阶段的 setData 分析和自查,在不是很复杂的页面,你也可以使用工具分析之后自己手动优化。 401 | 402 | 目前看来,该工具已经可以实现让开发者更专注于业务逻辑,不用额外花精力去思考如何减少 `setData`、如何只更新变化数据,从而**提高开发效率和开发体验**了,那说了这么多,它的实际效果怎么样呢? 403 | 404 | ## 效果分析 405 | 406 | 以一个 百万 `DAU` 小程序的较为复杂的列表页为例,从进入页面到加载完成: 407 | 408 | **使用低性能机型测试 5 次平均耗时为:** 409 | 410 | 原生 setData:setData 次数 `41`次,耗时: `5100ms`; 411 | 412 | turbo setData:setData 次数 `19` 次,耗时: `2400ms`; 413 | 414 | ##### 使用高性能机型原生测试 5 次平均耗时为 415 | 416 | 原生 setData:setData 次数 `41` 次,耗时: `3900ms`; 417 | 418 | turbo setData: setData 次数 `19` 次,耗时: `1800ms`; 419 | 420 | 以上结果只是测量页面内调用 `setData` 的耗时,不包含网络请求等其他耗时,可以看出,不考虑页面的网络请求和其他逻辑代码的执行效率的话,优化之后是可以提升**一倍以上**渲染性能的,这是人工优化极难做到的,因为我们要兼顾对复杂页面代码可读性、可维护性的考虑。 421 | 422 | 优化能够提升的性能与页面的数据组织方式、写法等都有很大关系,例如你同样更新一个数组,连续更新了 3 次,那工具就会帮你把后面的 2 次过滤掉,只 setData 一次,那么理论上你就能获得 2 倍的性能提升,当然只是举例,绝对不推荐这么做。 423 | 424 | 当页面足够复杂时,开发中有很多 `setData` 都是隐性的(尤其你在代码中直接 `setData` 了一个对象,或者使用了扩展运算符),有时候自己都很难搞清楚哪些数据在哪里被 `setData` 了,这就是工具的价值所在,帮你找到那些 `setData`,并优化它。 425 | 426 | ## 更佳实践 427 | 428 | ##### 1. 避免通过 `this.data.xxx` 的形式去更改数据值,包括 this.data.xxx 指向的引用类型 429 | 430 | 例如下面这种情况,更新一个字段值为引用类型时,可能会造成数据不准确: 431 | 432 | ``` js 433 | this.viewModal = {obj: {a: 3}}; 434 | this.setData({obj: this.viewModal.obj}); // 此时逻辑层的data.obj已经指向viewModal.obj对象的地址 435 | 436 | viewModal.obj.a = 666; // 操作了 viewModal 对象 437 | this.data.obj.a === 666; // true,预期的 a 应该是 3,但是却变成 6 了 438 | // 之后无论你在任何地方不小心更改了viewModal.obj,那么this.data.obj也变了,而此时在渲染层的数据还是旧数据,你本意是想通过this.data获取当前被渲染的值,但是这时候可能值已经并不符合你的预期了。 439 | ``` 440 | 441 | data 理应就是渲染层的数据,由于框架的特殊原因,不得不在渲染层和逻辑层通讯才维护了两份数据,**逻辑层的 data 应始终是渲染层 data 的影子,时时刻刻保持绝对一致**,应该仅通过 setData 的形式对 data 进行更新,这样能避免很多奇怪问题和 Bug,既安全也更利于维护,所以避免通过 `this.data.xxx` 的形式去更改数据值,包括 `this.data.xxx` 指向的引用类型。 442 | 443 | > 不安全不说,另外维护一份数据,类似上面 `viewModal` 这种,还会分散你的精力。 444 | 445 | 实际上这种写法对工具也会有一个较大的影响: 446 | 447 | ``` js 448 | this.viewModal = {obj: {a: 3}}; 449 | this.viewModal.obj.a === 666; 450 | this.setData({obj: this.viewModal.obj}); // 此时逻辑层的data.obj已经指向viewModal.obj对象的地址 451 | ``` 452 | 453 | 执行 setData 时工具内部会对比旧数据(`this.data`)和新数据,上面的写法在 setData 之前旧数据就已经变成新数据了,即旧数据是 `{obj: {a: 6}}`,新数据也是 `{obj: {a: 6}}`,那 diff 的结果就是没有发现变化,从而不触发 setData,显然工具如果直接忽略这次的 setData 那就会造成大 Bug,所以遇到这种情况内部会直接调用原生 setData,那么工具实际上就发挥不了任何优化作用了。 454 | 455 | 所以,不随意操作 `this.data` 以及其指向的引用对象是一个对大家都好的习惯。 456 | 457 | > 工具会对这种情况的代码信息 warn 到控制台,使你能够迅速定位是哪里的 setData 更新了值为引用类型。 458 | 459 | > 如果你依旧要通过非 setData 的形式去改变 this.data: 460 | > 461 | > 当你明确知道某处 setData 使用了引用类型,并且在 setData 之前已经被更改了, 462 | 那可以直接使用 useNative 选项,工具就不会做多余的 `diff` 而是直接走原生方法,如: 463 | 464 | ``` js 465 | this.setData({obj: this.viewModal.obj}, null, {useNative: true}) 466 | ``` 467 | 468 | 当然不改动也完全没问题,内部也做好了兼容,使用 `useNative` 的好处是让工具直接忽略掉, **不会再做多余的 diff 操作**。 469 | 470 | #### 2. 使用 setData 同步维护渲染层的数据状态 471 | 472 | 例如,这种场景: 473 | 474 | 一个 Dialog 组件,由 `show` 属性控制展示隐藏,但是组件内部也提供了方法来关闭弹窗,即组件内部自己更改了它的 `show` 属性,如下,当你使用 `showDialog:true` 打开对话框后,操作按钮关闭了对话框,但此时页面的 `showDialog` 字段值还是 `true`,当你再次 调用 `setData({showDialog: true})` 的时候,工具会判定属性未发生改变此次 `setData` 并不会生效,所以记得**同步维护渲染层的数据状态**,在 onClose 回调中更新一下 `setData({showDialog: false})`。 475 | 476 | ``` html 477 | 478 | ``` 479 | 480 | #### 3. 遇到问题善用日志选项排查,它能帮你定位 90% 的问题 481 | 482 | 例如上例,当你使用日志选项中的 logDuplicateData 时,便会立即发现 setData({showDialog: true}) 重复了,所以本次 setData 没有生效。 483 | 484 | ``` js 485 | turboOptions: { 486 | useSyncData: true, // 是否需要在 setData 后同步获取新值(全局配置) 487 | // logNative: true, // 是否输出原生表现日志,开启后会使用原生 setData 并输出耗时和次数,可用于对比优化效果 488 | logTimeConsuming: true, // 是否输出优化后的 setData 耗时和次数 489 | logUpdatedData: true, // 是否输出本次 setData 被更新的数据(合并且 diff 后的) 490 | logDuplicateData: true, // 是否输出被筛选出的重复数据 491 | } 492 | ``` 493 | 494 | 即使在排查日志后也解决不了问题,也有终极方案: `useNative` 选项,该选项会使用原生 setData,最后如果你觉得你遇到的问题是一个 bug,别忘了提 issue 给我。 495 | 496 | ``` js 497 | this.setData({}, null, {useNative: true}) 498 | ``` 499 | 500 | > 更多细节参见 501 | > 502 | > [为什么要优化 setData ?如何优化 setData ?](https://juejin.cn/post/7155646965978497032) 503 | > 504 | > [小程序极致性能优化之 setData,让你的 setData速度翻倍提升](https://juejin.cn/post/7160475467362304030/) 505 | -------------------------------------------------------------------------------- /lib/deepClone.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-plusplus */ 2 | 3 | import { isPlainObjectOrArray } from './typeUtils'; 4 | 5 | /** 6 | * 深拷贝 7 | * 8 | * @param {*} target 拷贝目标 9 | * @param {WeakMap} [cache=new WeakMap()] 内部缓存,无需传入 10 | * @returns {*} 11 | */ 12 | export function deepClone(target: any, cache = new WeakMap()): any { 13 | // 如果已经拷贝过该对象,则直接返回拷贝结果,不再进入递归逻辑,提高性能,并且能够防止循环引用 14 | // WeakMap可在target不被引用时自动垃圾回收,节省内存消耗 15 | if (cache.get(target)) return cache.get(target); 16 | 17 | // 处理数组和对象 18 | if (isPlainObjectOrArray(target)) { 19 | const cloneTarget = new target.constructor(); // 直接获取数组或对象的构造器,并实例化 20 | cache.set(target, cloneTarget); 21 | const keys = Reflect.ownKeys(target); // ownKeys 可遍历不可枚举属性和symbol 22 | for (let i = keys.length; i--;) { 23 | const key = keys[i]; 24 | cloneTarget[key] = deepClone(target[key], cache); // 递归拷贝每一层 25 | } 26 | return cloneTarget; 27 | } 28 | 29 | // 其他引用类型: 小程序会把 typeof 为 object类型的数据(不包含null)都转为 {},这是渲染层需要的数据结构, 30 | // 例如data: { obj: { reg: /\w/ } },会变成{ obj: { reg: { } } },所以此处无需处理 Map Set Date 等类型。 31 | // 基本类型: undefined,Symbol,null等直接返回 32 | // 函数类型: 支持返回函数,从基础库 2.0.9 开始,对象类型的属性和 data 字段中可以包含函数类型的子字段,即可以通过对象类型的属性字段来传递函数。 33 | return target; 34 | } 35 | -------------------------------------------------------------------------------- /lib/filedsUtils.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable complexity */ 2 | /* eslint-disable no-param-reassign */ 3 | /* eslint-disable no-plusplus */ 4 | import { warn } from './log'; 5 | import { isArray, isPlainObjectOrArray } from './typeUtils'; 6 | 7 | // 全局解析路径缓存(生命周期内都有效) 8 | const filedsCacheMap = new Map(); 9 | 10 | /** 11 | * 解析路径为字段数组 12 | * @example 13 | * getPathFileds('arr[0].a.b'); 14 | * // ['arr', '0', 'a', 'b'] 15 | * @export 16 | * @param {string} path 解析路径 17 | * @returns {string[]} 18 | */ 19 | export function getPathFileds(path: string): string[] { 20 | // 取缓存解析过的路径 21 | if (filedsCacheMap.has(path)) return filedsCacheMap.get(path); 22 | const segments: string[] | number[] = path.split('.'); // 分割字段片段, 如 a[5].b[4][0].c 23 | let fileds = segments; // 保存字段名 24 | 25 | // 处理包含数组的情况,例如 a[5].b[4][0].c 路径,要把b[4][0]这样的格式处理成[b, 4, 0] 26 | if (path.includes('[')) { 27 | fileds = []; 28 | let i = 0; 29 | const len = segments.length; 30 | while (i < len) { 31 | const segment = segments[i]; 32 | if (segment.includes('[')) { 33 | const arrFileds = segment.split(/[[\]]/); // ["b", "4", "", "0", ""] 34 | // for循环比push(...arrFileds)更快,而且加入判断非必要不push会更快 35 | for (let i = 0, len = arrFileds.length; i < len; i++) { 36 | if (arrFileds[i] !== '') fileds[fileds.length] = arrFileds[i]; // 使用下标赋值比 fileds.push(arrFileds[i])更快 37 | } 38 | // fileds.push(...arrFileds); // push(...arr)比concat效率更高,push直接操作原数组,concat会创建新数组 39 | } else { // 如果是被'.'分割完的字段直接push 40 | fileds.push(segment); 41 | } 42 | i++; 43 | } 44 | } 45 | filedsCacheMap.set(path, fileds); // 缓存解析过的路径 46 | return fileds; 47 | } 48 | 49 | /** 50 | * 链式取值 51 | * 52 | * @param {object} target 53 | * @param {string} path 54 | * @returns {*} 55 | */ 56 | export function getValByPath(target: object, path: string): any { 57 | // 比 !(/[\\.\\[]/.test(path)) 性能高约15倍,比 !(path.includes('.') || path.includes('[')) 高约6倍 58 | if (!path.includes('.') && !path.includes('[')) return target[path]; 59 | 60 | const fileds = getPathFileds(path); 61 | // const val = fileds.reduce((pre, cur) => pre?.[cur], target); 62 | // while 比 reduce快(2-3倍),实际上while比缓存len的for循环更快,但是数据量较少时差异微乎其微 63 | let i = 0; 64 | let val = target; 65 | const len = fileds.length; 66 | while (i < len) { 67 | val = val?.[fileds[i]]; 68 | i++; 69 | } 70 | return val; 71 | } 72 | 73 | /** 74 | * 链式更新值 75 | * 76 | * @param {*} target 77 | * @param {string} path 78 | * @param {*} value 79 | */ 80 | export function updateValByPath(target: any, path: string, value: any): void { 81 | // 非链式属性直接赋值 82 | if (!path.includes('.') && !path.includes('[')) return target[path] = value; 83 | const fileds = getPathFileds(path); 84 | 85 | let i = 0; 86 | const len = fileds.length; 87 | while (i < len) { 88 | const key = fileds[i]; 89 | if (i + 1 === len) { // 当前键是被更新路径的最后一个字段, 如 'obj.a.b'中的b则直接赋值 90 | target[key] = value; 91 | return; 92 | } 93 | 94 | // 创建对象或数组 95 | 96 | // 下一个字段的形式决定当前字段对应的数据类型,例如,arr[0],0决定了arr字段是数组类型,如果字段为纯数字则判定为数组(忽略对象键为数字的情况),key不会为'' 97 | const curKeyDataType = isNaN(Number(fileds[i + 1])) ? 'object' : 'array'; 98 | let typeMutation = false; 99 | const val = target[key]; 100 | if (val) { 101 | const oriDataType = isArray(val) ? 'array' : 'object'; 102 | typeMutation = oriDataType !== curKeyDataType || !isPlainObjectOrArray(val); 103 | } 104 | // 如果路径值不存在,或者存在但是数据类型变了,则创建对应数据类型 105 | if (!val || typeMutation) { 106 | target[key] = curKeyDataType === 'object' ? {} : []; 107 | // !更新 data 中不存在引用的属性或随意变更数据类型,理论上工具不会阻止这种行为,但是并不推荐,因为这种写法可能不利于维护 108 | warn(`updated field "${path}" does not exist in the data or datatype is inconsistent, may not be easy to maintain.`); 109 | } 110 | 111 | target = target[key]; 112 | i++; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | export declare type Page = WechatMiniprogram.Page.Constructor; 4 | export declare type Component = WechatMiniprogram.Component.Constructor; 5 | 6 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-native-reassign */ 2 | /* eslint-disable no-param-reassign */ 3 | 4 | import { Watcher, WatchCallBack } from './watcher'; 5 | import TurboSetData, { TurboOpts } from './turboSetData'; 6 | 7 | type Page = WechatMiniprogram.Page.Constructor; 8 | type Component = WechatMiniprogram.Component.Constructor; 9 | interface CompOpts extends WechatMiniprogram.Component.TrivialOption { 10 | watch?: { 11 | [propName: string]: WatchCallBack, 12 | }, 13 | }; 14 | 15 | /** 16 | * 增强单个页面 17 | * @param {object} pageOpts 页面选项(选项式api) 18 | */ 19 | const turboPage: Page = function (pageOpts, options?: { turboOptions: TurboOpts }): void { 20 | const { onLoad, watch = null } = pageOpts; 21 | let watcher: Watcher | null = null; 22 | pageOpts.onLoad = function (...args: any) { 23 | if (watch) watcher = new Watcher(this); 24 | new TurboSetData(this as WechatMiniprogram.Page.TrivialInstance, watcher, options?.turboOptions); // 增强setData 25 | onLoad?.apply(this, args); 26 | }; 27 | 28 | Page(pageOpts); 29 | }; 30 | 31 | /** 32 | * 增强单个组件 33 | * @param {*} compOpts 组件选项 34 | * @returns {string} 35 | */ 36 | const turboComponent: Component = function (compOpts: CompOpts, options?: { turboOptions: TurboOpts }): string { 37 | const { lifetimes = {}, watch } = compOpts; 38 | let ref: any = compOpts; 39 | if (lifetimes.created) { 40 | ref = compOpts.lifetimes; 41 | } 42 | const oriCreated = ref.created || function () { }; 43 | let watcher: Watcher | null = null; 44 | ref.created = function (...args: any[]) { 45 | if (watch) { 46 | this.watch = watch; 47 | watcher = new Watcher(this); 48 | }; 49 | new TurboSetData(this as WechatMiniprogram.Component.TrivialInstance, watcher, options?.turboOptions); // 增强setData 50 | oriCreated?.apply(this, args); 51 | }; 52 | 53 | return Component(compOpts); 54 | }; 55 | 56 | /** 57 | * 增强全局所有页面钩子 58 | */ 59 | function useTurboAllPage() { 60 | const originalPage = Page; 61 | Page = function (pageOpts, options?: { turboOptions: TurboOpts }) { 62 | const { onLoad, watch = null } = pageOpts; 63 | let watcher: Watcher | null = null; 64 | pageOpts.onLoad = async function (...args) { 65 | if (watch) watcher = new Watcher(this); 66 | new TurboSetData(this as WechatMiniprogram.Page.TrivialInstance, watcher, options?.turboOptions); // 增强setData 67 | onLoad?.apply(this, args); 68 | }; 69 | originalPage(pageOpts); 70 | }; 71 | } 72 | 73 | /** 74 | * 增强全局所有组件钩子 75 | */ 76 | function useTurboAllComponent() { 77 | const originalComponent = Component; 78 | Component = function (compOpts: any, options?: { turboOptions: TurboOpts }): string { 79 | const { lifetimes = {}, watch = null } = compOpts; 80 | let lifetimesObj = compOpts; 81 | if (lifetimes.created) { 82 | lifetimesObj = compOpts.lifetimes; 83 | } 84 | const oriCreated = lifetimesObj.created || function () { }; 85 | let watcher: Watcher | null = null; 86 | lifetimesObj.created = function (...args: any[]) { 87 | if (watch) { 88 | this.watch = watch; 89 | watcher = new Watcher(this); 90 | }; 91 | new TurboSetData(this, watcher, options?.turboOptions); // 增强setData 92 | oriCreated?.apply(this, args); 93 | }; 94 | return originalComponent(compOpts); 95 | }; 96 | }; 97 | 98 | export { 99 | turboPage as Page, 100 | turboComponent as Component, 101 | useTurboAllPage, 102 | useTurboAllComponent, 103 | }; 104 | -------------------------------------------------------------------------------- /lib/log.ts: -------------------------------------------------------------------------------- 1 | export function warn(msg: string, ...args: any[]) { 2 | console.warn(`[turbo warn 🚀 ] ${msg}`, ...args); 3 | } 4 | 5 | export function log(msg: string, ...args: any[]) { 6 | console.log(`[turbo log 🚀 ] ${msg}`, ...args); 7 | } 8 | -------------------------------------------------------------------------------- /lib/turboSetData.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | import { getValByPath, updateValByPath } from './filedsUtils'; 4 | import { isArray, isObject, isPlainObject } from './typeUtils'; 5 | import { warn, log } from './log'; 6 | import { Watcher } from './watcher'; 7 | 8 | export interface TurboOpts { 9 | useSyncData: boolean, // 是否需要在 setData 后同步获取新值 10 | logNative: boolean, // 是否输出原生表现日志 11 | logTimeConsuming: boolean, // 是否输出优化后的 setData 耗时和次数 12 | logUpdatedData: boolean, // 是否输出本次 setData 被更新的数据(合并且 diff 后的) 13 | logDuplicateData: boolean, // 是否输出被筛选出的重复数据 14 | } 15 | export type Instance = WechatMiniprogram.Page.TrivialInstance | WechatMiniprogram.Component.TrivialInstance; 16 | interface SetDataOptions { 17 | useNative?: boolean, // 是否使用原生setData方法 18 | useOldValue?: boolean, // 是否在数据长度变化时复用旧值,默认不使用,即在数据长度变化时直接渲染新值 19 | // 是否需要在setData后同步获取新值,默认禁用,原生是可以在 setData 后 通过 this.data 获取到新值的,但是一般情况用不到,对于有大量链式属性更新的页面关闭可能节省一些性能消耗 20 | useSyncData?: boolean, 21 | }; 22 | type Data = Record; 23 | type Fn = Function | null; 24 | 25 | export default class TurboSetData { 26 | private updatedData: Data = Object.create(null); // 保存要渲染的数据 27 | private setDataCbQueue: Array = []; // setData 回调队列 28 | private renderedFlag = false; // 本轮是否被渲染过标识 29 | private oriSetData: Function; // 原生setData方法 30 | private setDataTimeStamp = 0; // setData 开始时间戳 31 | private timeConsuming = 0; // setData 结束耗时 32 | private setDataTimes = 0; // setData 次数 33 | 34 | constructor(private instance: Instance, private watcher: Watcher | null, private turboOpts?: TurboOpts) { 35 | this.oriSetData = instance.setData; 36 | this.turbo(); 37 | } 38 | 39 | // 增强 setData 40 | private turbo() { 41 | log('turbo setData has taken effect '); 42 | 43 | const instance = this.instance; 44 | // 替换 setData 方法为修改后的 45 | instance.setData = (data: Data, fn?: Fn, options: SetDataOptions = {}) => { 46 | this.setDataTimeStamp = Date.now(); 47 | this.renderedFlag = false; 48 | 49 | if (this.turboOpts?.logNative) { 50 | this.oriSetData.call(instance, data, () => { 51 | this.timeConsuming += Date.now() - this.setDataTimeStamp; 52 | ++this.setDataTimes; 53 | log('total:', this.setDataTimes, 'timeConsuming:', this.timeConsuming, 'ms'); 54 | fn?.(); 55 | }); 56 | return; 57 | } 58 | 59 | // 提供使用原生方法的选择(不会打印日志) 60 | if (options.useNative) return this.useNativeSetData(data, fn); 61 | 62 | // 保存回调函数 63 | if (fn) this.setDataCbQueue.push(fn); 64 | 65 | // 开始 diff 数据 66 | const keys = Object.keys(data); 67 | 68 | // 数据量较少时优化for--(倒序for循环)最快,数据量较大时while--更快 69 | // 且for循环结束会销毁内部变量,减少内存占用,while则会占用外部变量 70 | for (let i = keys.length; i--;) { 71 | const path = keys[i]; 72 | // 本轮即将被setData的数据也要去重,如果没有再去data对象里找 73 | const oldval = this.updatedData[path] || getValByPath(instance.data, path); 74 | const newval = data[path]; 75 | this.diff(newval, oldval, path, options); 76 | } 77 | 78 | // 向任务队列中push新任务,在下个时间片统一更新数据,本轮 updatedData 对象继续收集 79 | wx.nextTick(() => { 80 | this.performUpdate(); 81 | }); 82 | };; 83 | } 84 | 85 | // 更新数据 86 | private updateData(path: string, newVal: any, options: SetDataOptions) { 87 | // 收集本轮待更新数据 88 | this.updatedData[path] = newVal; 89 | // 同步更新值 90 | if (this.turboOpts?.useSyncData || options.useSyncData) updateValByPath(this.instance.data, path, newVal); 91 | // 触发watch收集watch回调 92 | this.watcher?.updateWatchedData(path, newVal); 93 | } 94 | 95 | // 合并(批量)更新数据(异步更新队列,降低渲染消耗) 96 | private performUpdate() { 97 | // 任务队列中的performUpdate函数会依次执行,但是只渲染一次,随后清空this.updatedData 和 this.setDataCbQueue 98 | if (this.renderedFlag) return; 99 | this.renderedFlag = true; 100 | 101 | const updatedDataKeys = Object.keys(this.updatedData); 102 | const dataLen = updatedDataKeys.length; 103 | 104 | // 存在要更新数据时或者如果没有数据需要更新,但是有回调时执行 105 | if (dataLen || this.setDataCbQueue.length) { 106 | if (this.turboOpts?.logUpdatedData) { 107 | log('merged setData data:', this.updatedData); 108 | } 109 | 110 | // 执行合并后的setData 111 | this.oriSetData.call(this.instance, this.updatedData, () => { 112 | if (this.turboOpts?.logTimeConsuming) { 113 | this.timeConsuming += Date.now() - this.setDataTimeStamp; 114 | ++this.setDataTimes; 115 | log('total:', this.setDataTimes, 'timeConsuming:', this.timeConsuming, 'ms'); 116 | } 117 | this.execSetDataCb(); 118 | 119 | // 触发watch回调 120 | this.watcher?.trigger(); 121 | }); 122 | // 一个时间片内执行一次,执行后清除数据 123 | this.updatedData = {}; 124 | } 125 | } 126 | 127 | // 执行本轮所有setData回调 128 | private execSetDataCb() { 129 | const cbLen = this.setDataCbQueue.length; 130 | if (cbLen) { 131 | for (let i = cbLen; i--;) { 132 | // 这里可以使用shift,但是shift较慢,shift额外需要移动数组元素重新编号的操作 133 | const cb = this.setDataCbQueue[cbLen - i - 1]; // 回调执行顺序保证与原生表现一致 134 | cb?.(); 135 | } 136 | this.setDataCbQueue.length = 0; 137 | } 138 | } 139 | 140 | // diff 数据变化 141 | private diff(newVal: unknown, oldVal: unknown, path: string, options: SetDataOptions, isSubProp = false): void { 142 | // 值相等或引用地址相同不更新数据 143 | if (newVal === oldVal) { 144 | this.logSameValue(path, newVal); 145 | 146 | // 相同引用地址的数据(仅指当前setData的字段,不关心其子属性是否是同一地址)不会被diff, 147 | // 也不会进入异步更新队列,而是直接使用原生setData方法,这样的话框架不会起到任何优化作用,所以尽量避免设置一个字段值为会变更的引用类型 148 | if (!isSubProp && isObject(newVal)) { 149 | this.useNativeSetData({ [path]: newVal }); 150 | warn( 151 | 'data with the same reference address will not be diff, or put it in the asynchronous update queue, but directly use the native "setData" method, the tool will not play any optimization role, so please avoid this way of writing;', 152 | '\n field:', `"${path}"`, 153 | '\n newVal:', newVal, 154 | '\n oldVal', oldVal, 155 | ); 156 | } 157 | return; 158 | }; 159 | 160 | // undefined number symbol boolean string null function 161 | // 以上类型发生变化直接使用新数据 162 | if (typeof newVal !== 'object' || typeof oldVal !== 'object' || !newVal || !oldVal) { 163 | return this.updateData(path, newVal, options); 164 | } 165 | 166 | /** 167 | * 处理新值旧值都为引用类型的情况 168 | */ 169 | 170 | // 如果类型不同了,例如原来是数组变成对象了,直接使用新数据 171 | if (newVal.constructor !== oldVal.constructor) { 172 | return this.updateData(path, newVal, options); 173 | } 174 | 175 | // 数组和对象分开处理,执行Object.keys() 有一定消耗,值为数组时直接.length即可 176 | if (isArray(newVal)) { 177 | let newValLen = newVal.length; // 数组长度 178 | const oldValLen = (oldVal as []).length; // 旧值数组长度 179 | 180 | const breakDiff = this.diffLength(newValLen, oldValLen, path, newVal, isSubProp, options); 181 | if (breakDiff) return; 182 | 183 | // 其余情况遍历递归对比子属性 184 | for (; newValLen--;) { 185 | const newSubVal = newVal[newValLen]; 186 | const oldSubVal = oldVal[newValLen]; 187 | const subPath = `${path}[${newValLen}]`; 188 | // 递归diff子属性 189 | this.diff(newSubVal, oldSubVal, subPath, options, true); 190 | } 191 | return; 192 | } 193 | 194 | // 对象 195 | if (isPlainObject(newVal)) { 196 | const newValKeys = Object.keys(newVal); 197 | let newValLen = newValKeys.length; // 对象长度 198 | const oldValLen = Object.keys(oldVal).length; // 对象长度 199 | 200 | const breakDiff = this.diffLength(newValLen, oldValLen, path, newVal, isSubProp, options); 201 | if (breakDiff) return; 202 | 203 | for (; newValLen--;) { 204 | const newSubKey = newValKeys[newValLen]; 205 | const newSubVal = newVal[newSubKey]; 206 | const oldSubVal = oldVal[newSubKey]; 207 | const subPath = `${path}.${newSubKey}`; 208 | this.diff(newSubVal, oldSubVal, subPath, options, true); 209 | } 210 | return; 211 | } 212 | 213 | // 非上述类型(如 Map,Date等),直接使用新数据 (触发概率较低) 214 | return this.updateData(path, newVal, options); 215 | } 216 | 217 | // 对比长度变化 218 | private diffLength( 219 | newValLen: number, oldValLen: number, path: string, newVal: any, 220 | isSubProp: boolean, 221 | options: SetDataOptions, 222 | ): boolean { 223 | const breakDiff = true; // 中断diff 224 | 225 | // 不对比长度,即长度增加时接着diff数据,达到复用旧数据的目的,提高渲染性能,适用于分页列表等场景(子属性长度发生变化依旧直接使用新数据) 226 | if (options.useOldValue && !isSubProp) { 227 | // 全为0,不更新(位运算更快) 228 | if ((newValLen | oldValLen) === 0) return breakDiff; 229 | 230 | // 任意一个为0,直接使用新数据 231 | // 新值长度小于旧值,直接使用新数据(因为遍历目标是新值,如果新值长度比旧值小,对比时旧值某些键会被忽略,从而无法被更新) 232 | if ((newValLen && oldValLen) === 0 || (newValLen < oldValLen)) { 233 | this.updateData(path, newVal, options); 234 | return breakDiff; 235 | }; 236 | return false; 237 | } 238 | 239 | //默认需要对比长度变化,当长度发生变化时不再diff直接使用新数据 240 | 241 | // 长度发生变化,直接使用新数据 242 | if (newValLen !== oldValLen) { 243 | this.updateData(path, newVal, options); 244 | return breakDiff; 245 | } 246 | 247 | // 长度没变化,都为0,不更新 248 | if (newValLen === 0) return breakDiff; 249 | return false; 250 | } 251 | 252 | // 调用原生setData(不会 diff) 253 | private useNativeSetData(data: Data, fn?: Fn) { 254 | return this.oriSetData.call(this.instance, data, fn); 255 | } 256 | 257 | // 输出重复数据 258 | private logSameValue(path: string, newVal: any) { 259 | if (this.turboOpts?.logDuplicateData) log('same value was found: ', path, newVal) 260 | } 261 | 262 | } 263 | 264 | 265 | -------------------------------------------------------------------------------- /lib/typeUtils.ts: -------------------------------------------------------------------------------- 1 | 2 | // 获取数据类型 如:[object Array] 3 | export const getTypeString = (val: unknown): string => Object.prototype.toString.call(val); 4 | 5 | // 获取原始数据类型 如:array 6 | export const getRawType = (val: unknown) => getTypeString(val).slice(8, -1) 7 | .toLowerCase(); 8 | 9 | export const isObject = (val: unknown): val is Record => val !== null && typeof val === 'object'; 10 | 11 | export const { isArray } = Array; 12 | 13 | /** 14 | * 判断是否是普通对象 15 | * 16 | * 直接调用constructor属性判断对象,替代调用函数转成字符串,减少性能开销, 17 | * 一般情况都可以通过constructor来判断,但是constructor属性不稳定,容易被更改, 18 | * 而且没有原型的对象(如Object.create(null)创建的纯净对象)是没有constructor属性的, 19 | * 此时仍然需要使用toString()方法来判断。 20 | * 21 | * @param {unknown} val 22 | * @returns {val is object} 23 | */ 24 | export const isPlainObject = (val: unknown): val is object => { 25 | if (val?.constructor) return val.constructor === Object; 26 | return getTypeString(val) === '[object Object]'; 27 | }; 28 | 29 | export const isPlainObjectOrArray = (val: unknown): boolean => isPlainObject(val) || isArray(val); 30 | 31 | 32 | -------------------------------------------------------------------------------- /lib/watcher.ts: -------------------------------------------------------------------------------- 1 | import { getPathFileds, getValByPath, updateValByPath } from './filedsUtils'; 2 | import { isPlainObjectOrArray } from './typeUtils'; 3 | import { deepClone } from './deepClone'; 4 | 5 | export type WatchCallBack = ( 6 | newValue?: NV, 7 | oldValue?: OV, 8 | ) => any; 9 | 10 | interface ReactiveObj { 11 | path: string, 12 | fields: string[], 13 | proxy: object, 14 | } 15 | 16 | export class Watcher { 17 | private dep: Map = new Map(); 18 | private oldValMap: Map = new Map(); 19 | private proxyMap: WeakMap = new WeakMap(); 20 | public reactiveWatchMap: Map = new Map(); 21 | 22 | constructor(private instance: any) { 23 | const { data, watch } = instance; 24 | const watchKeys = Object.keys(watch); 25 | 26 | for (let i = 0, len = watchKeys.length; i < len; i++) { 27 | const path = watchKeys[i]; 28 | const fields = getPathFileds(path); 29 | const key = fields[0]; 30 | 31 | // 初始化被监听对象(不直接监听data的目的是与小程序内部操作隔离,不然小程序自身对data的操作,如toJson,访问和修改等也会触发监听) 32 | const rawVal = deepClone(data[key]); 33 | const watchData = {}; // 缩减版data 34 | watchData[key] = rawVal; 35 | 36 | const watchDataProxy = this.reactive(watchData, path); 37 | // 保存每个路径的唯一响应式对象 38 | this.reactiveWatchMap.set(key, { 39 | path, 40 | fields, 41 | proxy: watchDataProxy, 42 | }); 43 | } 44 | } 45 | 46 | // 触发依赖 47 | public trigger() { 48 | if (this.dep.size) { 49 | // forEach每次循环都会调用函数,但是有js引擎层面(解释器)的优化 50 | this.dep.forEach((cb, path) => { 51 | cb(); 52 | this.oldValMap.delete(path); 53 | }); 54 | this.dep.clear(); 55 | 56 | // for (const [path, cb] of this.dep.entries()) { 57 | // cb(); 58 | // this.oldValMap.delete(path); 59 | // } 60 | 61 | /** 62 | 不使用 for of 原因: 63 | 64 | 一方面for of 内部循环调用迭代器接口(entries()方法实际上返回的就是迭代器,entries()比values()方法更慢),原理类似这样: 65 | // 遍历迭代器 66 | const iterator = this.dep[Symbol.iterator](); // 获取Map的迭代器接口(迭代器为各种不同的数据结构提供统一的访问机制) 67 | while (true) { 68 | const item = iterator.next(); 69 | if (item.done) break; 70 | ... // 执行功能代码 71 | } 72 | 但是具体实现可能要比这复杂的多,单纯使用 while 仅遍历 values() 的时候,上面方法是比forEach(key,value都会处理)快的, 73 | (while遍历values()更快,但是遍历entries()比forEach慢,所以使用forEach,另外while遍历迭代器可读性较差) 74 | 而for of 仅遍历values()时也比forEach慢,所以js对于遍历迭代器的执行效率似乎并不高。 75 | 76 | ...运算符也是同理,一样是通过遍历迭代器实现,性能也一般,例如原生call是比apply快的(以前,或者某些低版本浏览器,现在差距不大了, 77 | 据说是因为apply参数是数组,内部实现时需要处理这个数组有额外消耗),call(this, a, b, c)本来是比apply(this, [a, b, c])性能高或者持平的, 78 | 但是如果非要用call(this, ...[a, b, c]),那就有点画蛇添足了,强行多出来一个遍历迭代器的工作,性能直接变low 79 | 80 | 另一方面,解构也会消耗一定性能(其实内部也是遍历迭代器接口按顺序获取对应的值进行赋值,比正常取值慢2-3倍),所以此处使用forEach, 81 | 仅针对数组解构,对象解构还是通过属性取值,只是换了种写法而已,性能一致。 82 | */ 83 | } 84 | }; 85 | 86 | // 更新被监听的响应式对象,触发响应式对象的set,收集被监听路径的依赖 87 | public updateWatchedData(path: string, newVal: any) { 88 | const fields = getPathFileds(path); // upadteFileds 89 | if (this.reactiveWatchMap.has(fields[0])) { 90 | const curWatch = this.reactiveWatchMap.get(fields[0])!; 91 | // 兄弟属性更新不触发回调 92 | if (fields.length === curWatch.fields.length && path !== curWatch.path) return; 93 | // 父属性、子属性、自身更新触发回调 94 | updateValByPath(curWatch.proxy, path, newVal); 95 | } 96 | } 97 | 98 | // 收集被监听路径的依赖 99 | private track(path: string, cb: WatchCallBack) { 100 | const newVal = getValByPath(this.instance.data, path); 101 | const oldVal = this.oldValMap.get(path); 102 | this.dep.set(path, cb.bind(null, newVal, oldVal)); 103 | }; 104 | 105 | // 创建响应式对象(只监听对象和数组) 106 | private reactive(target: object, path: string) { 107 | if (!isPlainObjectOrArray(target)) return target; 108 | 109 | // 已经代理过,直接返回 110 | const existingProxy = this.proxyMap.get(target); 111 | if (existingProxy) return existingProxy; 112 | 113 | const { watch } = this.instance; 114 | const cb = watch[path]; 115 | 116 | const proxy = new Proxy(target, { 117 | get: (target, key: string, receiver) => { 118 | const result = Reflect.get(target, key, receiver); 119 | // 初次访问时保存旧值 120 | if (!this.oldValMap.has(path)) this.oldValMap.set(path, deepClone(getValByPath(target, path))); 121 | 122 | // 深度监听(惰性,只有属性被访问时才会开始监听) 123 | if (isPlainObjectOrArray(result)) { 124 | return this.reactive(result, path); 125 | } 126 | return result; 127 | }, 128 | 129 | set: (target, key, value, receiver) => { 130 | // 属性被更新时收集依赖 131 | this.track(path, cb); 132 | return Reflect.set(target, key, value, receiver); 133 | }, 134 | }); 135 | 136 | this.proxyMap.set(target, proxy); 137 | return proxy; 138 | }; 139 | } 140 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "miniprogram-turbo-setdata", 3 | "version": "1.0.4", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "miniprogram-turbo-setdata", 9 | "version": "1.0.4", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "miniprogram-api-typings": "^3.6.0", 13 | "rollup": "^2.0.0", 14 | "rollup-plugin-license": "^2.8.2", 15 | "rollup-plugin-terser": "^7.0.2", 16 | "rollup-plugin-typescript2": "^0.34.1" 17 | } 18 | }, 19 | "node_modules/@babel/code-frame": { 20 | "version": "7.18.6", 21 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", 22 | "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", 23 | "dev": true, 24 | "dependencies": { 25 | "@babel/highlight": "^7.18.6" 26 | }, 27 | "engines": { 28 | "node": ">=6.9.0" 29 | } 30 | }, 31 | "node_modules/@babel/helper-validator-identifier": { 32 | "version": "7.19.1", 33 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", 34 | "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", 35 | "dev": true, 36 | "engines": { 37 | "node": ">=6.9.0" 38 | } 39 | }, 40 | "node_modules/@babel/highlight": { 41 | "version": "7.18.6", 42 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", 43 | "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", 44 | "dev": true, 45 | "dependencies": { 46 | "@babel/helper-validator-identifier": "^7.18.6", 47 | "chalk": "^2.0.0", 48 | "js-tokens": "^4.0.0" 49 | }, 50 | "engines": { 51 | "node": ">=6.9.0" 52 | } 53 | }, 54 | "node_modules/@jridgewell/gen-mapping": { 55 | "version": "0.3.2", 56 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", 57 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", 58 | "dev": true, 59 | "dependencies": { 60 | "@jridgewell/set-array": "^1.0.1", 61 | "@jridgewell/sourcemap-codec": "^1.4.10", 62 | "@jridgewell/trace-mapping": "^0.3.9" 63 | }, 64 | "engines": { 65 | "node": ">=6.0.0" 66 | } 67 | }, 68 | "node_modules/@jridgewell/resolve-uri": { 69 | "version": "3.1.0", 70 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 71 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 72 | "dev": true, 73 | "engines": { 74 | "node": ">=6.0.0" 75 | } 76 | }, 77 | "node_modules/@jridgewell/set-array": { 78 | "version": "1.1.2", 79 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 80 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 81 | "dev": true, 82 | "engines": { 83 | "node": ">=6.0.0" 84 | } 85 | }, 86 | "node_modules/@jridgewell/source-map": { 87 | "version": "0.3.2", 88 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", 89 | "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", 90 | "dev": true, 91 | "dependencies": { 92 | "@jridgewell/gen-mapping": "^0.3.0", 93 | "@jridgewell/trace-mapping": "^0.3.9" 94 | } 95 | }, 96 | "node_modules/@jridgewell/sourcemap-codec": { 97 | "version": "1.4.14", 98 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 99 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 100 | "dev": true 101 | }, 102 | "node_modules/@jridgewell/trace-mapping": { 103 | "version": "0.3.17", 104 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", 105 | "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", 106 | "dev": true, 107 | "dependencies": { 108 | "@jridgewell/resolve-uri": "3.1.0", 109 | "@jridgewell/sourcemap-codec": "1.4.14" 110 | } 111 | }, 112 | "node_modules/@rollup/pluginutils": { 113 | "version": "4.2.1", 114 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 115 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 116 | "dev": true, 117 | "dependencies": { 118 | "estree-walker": "^2.0.1", 119 | "picomatch": "^2.2.2" 120 | }, 121 | "engines": { 122 | "node": ">= 8.0.0" 123 | } 124 | }, 125 | "node_modules/@types/node": { 126 | "version": "18.11.3", 127 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz", 128 | "integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==", 129 | "dev": true 130 | }, 131 | "node_modules/acorn": { 132 | "version": "8.8.0", 133 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", 134 | "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", 135 | "dev": true, 136 | "bin": { 137 | "acorn": "bin/acorn" 138 | }, 139 | "engines": { 140 | "node": ">=0.4.0" 141 | } 142 | }, 143 | "node_modules/ansi-styles": { 144 | "version": "3.2.1", 145 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 146 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 147 | "dev": true, 148 | "dependencies": { 149 | "color-convert": "^1.9.0" 150 | }, 151 | "engines": { 152 | "node": ">=4" 153 | } 154 | }, 155 | "node_modules/array-find-index": { 156 | "version": "1.0.2", 157 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", 158 | "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", 159 | "dev": true, 160 | "engines": { 161 | "node": ">=0.10.0" 162 | } 163 | }, 164 | "node_modules/balanced-match": { 165 | "version": "1.0.2", 166 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 167 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 168 | "dev": true 169 | }, 170 | "node_modules/brace-expansion": { 171 | "version": "1.1.11", 172 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 173 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 174 | "dev": true, 175 | "dependencies": { 176 | "balanced-match": "^1.0.0", 177 | "concat-map": "0.0.1" 178 | } 179 | }, 180 | "node_modules/buffer-from": { 181 | "version": "1.1.2", 182 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 183 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 184 | "dev": true 185 | }, 186 | "node_modules/chalk": { 187 | "version": "2.4.2", 188 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 189 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 190 | "dev": true, 191 | "dependencies": { 192 | "ansi-styles": "^3.2.1", 193 | "escape-string-regexp": "^1.0.5", 194 | "supports-color": "^5.3.0" 195 | }, 196 | "engines": { 197 | "node": ">=4" 198 | } 199 | }, 200 | "node_modules/color-convert": { 201 | "version": "1.9.3", 202 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 203 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 204 | "dev": true, 205 | "dependencies": { 206 | "color-name": "1.1.3" 207 | } 208 | }, 209 | "node_modules/color-name": { 210 | "version": "1.1.3", 211 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 212 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", 213 | "dev": true 214 | }, 215 | "node_modules/commander": { 216 | "version": "2.20.3", 217 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 218 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 219 | "dev": true 220 | }, 221 | "node_modules/commenting": { 222 | "version": "1.1.0", 223 | "resolved": "https://registry.npmjs.org/commenting/-/commenting-1.1.0.tgz", 224 | "integrity": "sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==", 225 | "dev": true 226 | }, 227 | "node_modules/commondir": { 228 | "version": "1.0.1", 229 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", 230 | "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", 231 | "dev": true 232 | }, 233 | "node_modules/concat-map": { 234 | "version": "0.0.1", 235 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 236 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 237 | "dev": true 238 | }, 239 | "node_modules/escape-string-regexp": { 240 | "version": "1.0.5", 241 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 242 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 243 | "dev": true, 244 | "engines": { 245 | "node": ">=0.8.0" 246 | } 247 | }, 248 | "node_modules/estree-walker": { 249 | "version": "2.0.2", 250 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 251 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 252 | "dev": true 253 | }, 254 | "node_modules/find-cache-dir": { 255 | "version": "3.3.2", 256 | "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", 257 | "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", 258 | "dev": true, 259 | "dependencies": { 260 | "commondir": "^1.0.1", 261 | "make-dir": "^3.0.2", 262 | "pkg-dir": "^4.1.0" 263 | }, 264 | "engines": { 265 | "node": ">=8" 266 | }, 267 | "funding": { 268 | "url": "https://github.com/avajs/find-cache-dir?sponsor=1" 269 | } 270 | }, 271 | "node_modules/find-up": { 272 | "version": "4.1.0", 273 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 274 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 275 | "dev": true, 276 | "dependencies": { 277 | "locate-path": "^5.0.0", 278 | "path-exists": "^4.0.0" 279 | }, 280 | "engines": { 281 | "node": ">=8" 282 | } 283 | }, 284 | "node_modules/fs-extra": { 285 | "version": "10.1.0", 286 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", 287 | "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", 288 | "dev": true, 289 | "dependencies": { 290 | "graceful-fs": "^4.2.0", 291 | "jsonfile": "^6.0.1", 292 | "universalify": "^2.0.0" 293 | }, 294 | "engines": { 295 | "node": ">=12" 296 | } 297 | }, 298 | "node_modules/fs.realpath": { 299 | "version": "1.0.0", 300 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 301 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 302 | "dev": true 303 | }, 304 | "node_modules/fsevents": { 305 | "version": "2.3.2", 306 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 307 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 308 | "dev": true, 309 | "hasInstallScript": true, 310 | "optional": true, 311 | "os": [ 312 | "darwin" 313 | ], 314 | "engines": { 315 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 316 | } 317 | }, 318 | "node_modules/glob": { 319 | "version": "7.2.3", 320 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 321 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 322 | "dev": true, 323 | "dependencies": { 324 | "fs.realpath": "^1.0.0", 325 | "inflight": "^1.0.4", 326 | "inherits": "2", 327 | "minimatch": "^3.1.1", 328 | "once": "^1.3.0", 329 | "path-is-absolute": "^1.0.0" 330 | }, 331 | "engines": { 332 | "node": "*" 333 | }, 334 | "funding": { 335 | "url": "https://github.com/sponsors/isaacs" 336 | } 337 | }, 338 | "node_modules/graceful-fs": { 339 | "version": "4.2.10", 340 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", 341 | "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", 342 | "dev": true 343 | }, 344 | "node_modules/has-flag": { 345 | "version": "3.0.0", 346 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 347 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 348 | "dev": true, 349 | "engines": { 350 | "node": ">=4" 351 | } 352 | }, 353 | "node_modules/inflight": { 354 | "version": "1.0.6", 355 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 356 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 357 | "dev": true, 358 | "dependencies": { 359 | "once": "^1.3.0", 360 | "wrappy": "1" 361 | } 362 | }, 363 | "node_modules/inherits": { 364 | "version": "2.0.4", 365 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 366 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 367 | "dev": true 368 | }, 369 | "node_modules/jest-worker": { 370 | "version": "26.6.2", 371 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", 372 | "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", 373 | "dev": true, 374 | "dependencies": { 375 | "@types/node": "*", 376 | "merge-stream": "^2.0.0", 377 | "supports-color": "^7.0.0" 378 | }, 379 | "engines": { 380 | "node": ">= 10.13.0" 381 | } 382 | }, 383 | "node_modules/jest-worker/node_modules/has-flag": { 384 | "version": "4.0.0", 385 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 386 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 387 | "dev": true, 388 | "engines": { 389 | "node": ">=8" 390 | } 391 | }, 392 | "node_modules/jest-worker/node_modules/supports-color": { 393 | "version": "7.2.0", 394 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 395 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 396 | "dev": true, 397 | "dependencies": { 398 | "has-flag": "^4.0.0" 399 | }, 400 | "engines": { 401 | "node": ">=8" 402 | } 403 | }, 404 | "node_modules/js-tokens": { 405 | "version": "4.0.0", 406 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 407 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 408 | "dev": true 409 | }, 410 | "node_modules/jsonfile": { 411 | "version": "6.1.0", 412 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 413 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 414 | "dev": true, 415 | "dependencies": { 416 | "universalify": "^2.0.0" 417 | }, 418 | "optionalDependencies": { 419 | "graceful-fs": "^4.1.6" 420 | } 421 | }, 422 | "node_modules/locate-path": { 423 | "version": "5.0.0", 424 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 425 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 426 | "dev": true, 427 | "dependencies": { 428 | "p-locate": "^4.1.0" 429 | }, 430 | "engines": { 431 | "node": ">=8" 432 | } 433 | }, 434 | "node_modules/lodash": { 435 | "version": "4.17.21", 436 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 437 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 438 | "dev": true 439 | }, 440 | "node_modules/lru-cache": { 441 | "version": "6.0.0", 442 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 443 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 444 | "dev": true, 445 | "dependencies": { 446 | "yallist": "^4.0.0" 447 | }, 448 | "engines": { 449 | "node": ">=10" 450 | } 451 | }, 452 | "node_modules/magic-string": { 453 | "version": "0.26.7", 454 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", 455 | "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", 456 | "dev": true, 457 | "dependencies": { 458 | "sourcemap-codec": "^1.4.8" 459 | }, 460 | "engines": { 461 | "node": ">=12" 462 | } 463 | }, 464 | "node_modules/make-dir": { 465 | "version": "3.1.0", 466 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", 467 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", 468 | "dev": true, 469 | "dependencies": { 470 | "semver": "^6.0.0" 471 | }, 472 | "engines": { 473 | "node": ">=8" 474 | }, 475 | "funding": { 476 | "url": "https://github.com/sponsors/sindresorhus" 477 | } 478 | }, 479 | "node_modules/make-dir/node_modules/semver": { 480 | "version": "6.3.0", 481 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 482 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 483 | "dev": true, 484 | "bin": { 485 | "semver": "bin/semver.js" 486 | } 487 | }, 488 | "node_modules/merge-stream": { 489 | "version": "2.0.0", 490 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", 491 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", 492 | "dev": true 493 | }, 494 | "node_modules/minimatch": { 495 | "version": "3.1.2", 496 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 497 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 498 | "dev": true, 499 | "dependencies": { 500 | "brace-expansion": "^1.1.7" 501 | }, 502 | "engines": { 503 | "node": "*" 504 | } 505 | }, 506 | "node_modules/miniprogram-api-typings": { 507 | "version": "3.6.0", 508 | "resolved": "https://registry.npmjs.org/miniprogram-api-typings/-/miniprogram-api-typings-3.6.0.tgz", 509 | "integrity": "sha512-xwK3PzhhxnfWqDfBikHLdAbj7Wy4F887nBcQrzwuF758Fw2qC4ivpKPL9t0uJZk5QYnU28+NqA7Q3lzYGMHQnA==", 510 | "dev": true 511 | }, 512 | "node_modules/mkdirp": { 513 | "version": "1.0.4", 514 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 515 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", 516 | "dev": true, 517 | "bin": { 518 | "mkdirp": "bin/cmd.js" 519 | }, 520 | "engines": { 521 | "node": ">=10" 522 | } 523 | }, 524 | "node_modules/moment": { 525 | "version": "2.29.4", 526 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", 527 | "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", 528 | "dev": true, 529 | "engines": { 530 | "node": "*" 531 | } 532 | }, 533 | "node_modules/once": { 534 | "version": "1.4.0", 535 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 536 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 537 | "dev": true, 538 | "dependencies": { 539 | "wrappy": "1" 540 | } 541 | }, 542 | "node_modules/p-limit": { 543 | "version": "2.3.0", 544 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 545 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 546 | "dev": true, 547 | "dependencies": { 548 | "p-try": "^2.0.0" 549 | }, 550 | "engines": { 551 | "node": ">=6" 552 | }, 553 | "funding": { 554 | "url": "https://github.com/sponsors/sindresorhus" 555 | } 556 | }, 557 | "node_modules/p-locate": { 558 | "version": "4.1.0", 559 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 560 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 561 | "dev": true, 562 | "dependencies": { 563 | "p-limit": "^2.2.0" 564 | }, 565 | "engines": { 566 | "node": ">=8" 567 | } 568 | }, 569 | "node_modules/p-try": { 570 | "version": "2.2.0", 571 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 572 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 573 | "dev": true, 574 | "engines": { 575 | "node": ">=6" 576 | } 577 | }, 578 | "node_modules/package-name-regex": { 579 | "version": "2.0.6", 580 | "resolved": "https://registry.npmjs.org/package-name-regex/-/package-name-regex-2.0.6.tgz", 581 | "integrity": "sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==", 582 | "dev": true, 583 | "engines": { 584 | "node": ">=12" 585 | }, 586 | "funding": { 587 | "url": "https://github.com/sponsors/dword-design" 588 | } 589 | }, 590 | "node_modules/path-exists": { 591 | "version": "4.0.0", 592 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 593 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 594 | "dev": true, 595 | "engines": { 596 | "node": ">=8" 597 | } 598 | }, 599 | "node_modules/path-is-absolute": { 600 | "version": "1.0.1", 601 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 602 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 603 | "dev": true, 604 | "engines": { 605 | "node": ">=0.10.0" 606 | } 607 | }, 608 | "node_modules/picomatch": { 609 | "version": "2.3.1", 610 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 611 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 612 | "dev": true, 613 | "engines": { 614 | "node": ">=8.6" 615 | }, 616 | "funding": { 617 | "url": "https://github.com/sponsors/jonschlinkert" 618 | } 619 | }, 620 | "node_modules/pkg-dir": { 621 | "version": "4.2.0", 622 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 623 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 624 | "dev": true, 625 | "dependencies": { 626 | "find-up": "^4.0.0" 627 | }, 628 | "engines": { 629 | "node": ">=8" 630 | } 631 | }, 632 | "node_modules/randombytes": { 633 | "version": "2.1.0", 634 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 635 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 636 | "dev": true, 637 | "dependencies": { 638 | "safe-buffer": "^5.1.0" 639 | } 640 | }, 641 | "node_modules/rollup": { 642 | "version": "2.79.1", 643 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", 644 | "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", 645 | "dev": true, 646 | "bin": { 647 | "rollup": "dist/bin/rollup" 648 | }, 649 | "engines": { 650 | "node": ">=10.0.0" 651 | }, 652 | "optionalDependencies": { 653 | "fsevents": "~2.3.2" 654 | } 655 | }, 656 | "node_modules/rollup-plugin-license": { 657 | "version": "2.8.2", 658 | "resolved": "https://registry.npmjs.org/rollup-plugin-license/-/rollup-plugin-license-2.8.2.tgz", 659 | "integrity": "sha512-jv268aj71J0Ee6+isjy1mYD2LlwuNg6aUiSdgly0PS0fQ2+vsuc+PLx1ueSk2/QKfjk5OJzcGPEDMHyoIeAFCw==", 660 | "dev": true, 661 | "dependencies": { 662 | "commenting": "~1.1.0", 663 | "glob": "~7.2.0", 664 | "lodash": "~4.17.21", 665 | "magic-string": "~0.26.2", 666 | "mkdirp": "~1.0.4", 667 | "moment": "~2.29.3", 668 | "package-name-regex": "~2.0.6", 669 | "spdx-expression-validate": "~2.0.0", 670 | "spdx-satisfies": "~5.0.1" 671 | }, 672 | "engines": { 673 | "node": ">=10.0.0" 674 | }, 675 | "peerDependencies": { 676 | "rollup": "^1.0.0 || ^2.0.0" 677 | } 678 | }, 679 | "node_modules/rollup-plugin-terser": { 680 | "version": "7.0.2", 681 | "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", 682 | "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", 683 | "dev": true, 684 | "dependencies": { 685 | "@babel/code-frame": "^7.10.4", 686 | "jest-worker": "^26.2.1", 687 | "serialize-javascript": "^4.0.0", 688 | "terser": "^5.0.0" 689 | }, 690 | "peerDependencies": { 691 | "rollup": "^2.0.0" 692 | } 693 | }, 694 | "node_modules/rollup-plugin-typescript2": { 695 | "version": "0.34.1", 696 | "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.34.1.tgz", 697 | "integrity": "sha512-P4cHLtGikESmqi1CA+tdMDUv8WbQV48mzPYt77TSTOPJpERyZ9TXdDgjSDix8Fkqce6soYz3+fa4lrC93IEkcw==", 698 | "dev": true, 699 | "dependencies": { 700 | "@rollup/pluginutils": "^4.1.2", 701 | "find-cache-dir": "^3.3.2", 702 | "fs-extra": "^10.0.0", 703 | "semver": "^7.3.7", 704 | "tslib": "^2.4.0" 705 | }, 706 | "peerDependencies": { 707 | "rollup": ">=1.26.3", 708 | "typescript": ">=2.4.0" 709 | } 710 | }, 711 | "node_modules/safe-buffer": { 712 | "version": "5.2.1", 713 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 714 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 715 | "dev": true, 716 | "funding": [ 717 | { 718 | "type": "github", 719 | "url": "https://github.com/sponsors/feross" 720 | }, 721 | { 722 | "type": "patreon", 723 | "url": "https://www.patreon.com/feross" 724 | }, 725 | { 726 | "type": "consulting", 727 | "url": "https://feross.org/support" 728 | } 729 | ] 730 | }, 731 | "node_modules/semver": { 732 | "version": "7.3.8", 733 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", 734 | "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", 735 | "dev": true, 736 | "dependencies": { 737 | "lru-cache": "^6.0.0" 738 | }, 739 | "bin": { 740 | "semver": "bin/semver.js" 741 | }, 742 | "engines": { 743 | "node": ">=10" 744 | } 745 | }, 746 | "node_modules/serialize-javascript": { 747 | "version": "4.0.0", 748 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", 749 | "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", 750 | "dev": true, 751 | "dependencies": { 752 | "randombytes": "^2.1.0" 753 | } 754 | }, 755 | "node_modules/source-map": { 756 | "version": "0.6.1", 757 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 758 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 759 | "dev": true, 760 | "engines": { 761 | "node": ">=0.10.0" 762 | } 763 | }, 764 | "node_modules/source-map-support": { 765 | "version": "0.5.21", 766 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 767 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 768 | "dev": true, 769 | "dependencies": { 770 | "buffer-from": "^1.0.0", 771 | "source-map": "^0.6.0" 772 | } 773 | }, 774 | "node_modules/sourcemap-codec": { 775 | "version": "1.4.8", 776 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 777 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 778 | "dev": true 779 | }, 780 | "node_modules/spdx-compare": { 781 | "version": "1.0.0", 782 | "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", 783 | "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", 784 | "dev": true, 785 | "dependencies": { 786 | "array-find-index": "^1.0.2", 787 | "spdx-expression-parse": "^3.0.0", 788 | "spdx-ranges": "^2.0.0" 789 | } 790 | }, 791 | "node_modules/spdx-exceptions": { 792 | "version": "2.3.0", 793 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", 794 | "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", 795 | "dev": true 796 | }, 797 | "node_modules/spdx-expression-parse": { 798 | "version": "3.0.1", 799 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", 800 | "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", 801 | "dev": true, 802 | "dependencies": { 803 | "spdx-exceptions": "^2.1.0", 804 | "spdx-license-ids": "^3.0.0" 805 | } 806 | }, 807 | "node_modules/spdx-expression-validate": { 808 | "version": "2.0.0", 809 | "resolved": "https://registry.npmjs.org/spdx-expression-validate/-/spdx-expression-validate-2.0.0.tgz", 810 | "integrity": "sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==", 811 | "dev": true, 812 | "dependencies": { 813 | "spdx-expression-parse": "^3.0.0" 814 | } 815 | }, 816 | "node_modules/spdx-license-ids": { 817 | "version": "3.0.12", 818 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", 819 | "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", 820 | "dev": true 821 | }, 822 | "node_modules/spdx-ranges": { 823 | "version": "2.1.1", 824 | "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", 825 | "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", 826 | "dev": true 827 | }, 828 | "node_modules/spdx-satisfies": { 829 | "version": "5.0.1", 830 | "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-5.0.1.tgz", 831 | "integrity": "sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==", 832 | "dev": true, 833 | "dependencies": { 834 | "spdx-compare": "^1.0.0", 835 | "spdx-expression-parse": "^3.0.0", 836 | "spdx-ranges": "^2.0.0" 837 | } 838 | }, 839 | "node_modules/supports-color": { 840 | "version": "5.5.0", 841 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 842 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 843 | "dev": true, 844 | "dependencies": { 845 | "has-flag": "^3.0.0" 846 | }, 847 | "engines": { 848 | "node": ">=4" 849 | } 850 | }, 851 | "node_modules/terser": { 852 | "version": "5.15.1", 853 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", 854 | "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", 855 | "dev": true, 856 | "dependencies": { 857 | "@jridgewell/source-map": "^0.3.2", 858 | "acorn": "^8.5.0", 859 | "commander": "^2.20.0", 860 | "source-map-support": "~0.5.20" 861 | }, 862 | "bin": { 863 | "terser": "bin/terser" 864 | }, 865 | "engines": { 866 | "node": ">=10" 867 | } 868 | }, 869 | "node_modules/tslib": { 870 | "version": "2.4.0", 871 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", 872 | "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", 873 | "dev": true 874 | }, 875 | "node_modules/typescript": { 876 | "version": "4.8.4", 877 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", 878 | "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", 879 | "dev": true, 880 | "peer": true, 881 | "bin": { 882 | "tsc": "bin/tsc", 883 | "tsserver": "bin/tsserver" 884 | }, 885 | "engines": { 886 | "node": ">=4.2.0" 887 | } 888 | }, 889 | "node_modules/universalify": { 890 | "version": "2.0.0", 891 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", 892 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", 893 | "dev": true, 894 | "engines": { 895 | "node": ">= 10.0.0" 896 | } 897 | }, 898 | "node_modules/wrappy": { 899 | "version": "1.0.2", 900 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 901 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 902 | "dev": true 903 | }, 904 | "node_modules/yallist": { 905 | "version": "4.0.0", 906 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 907 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 908 | "dev": true 909 | } 910 | }, 911 | "dependencies": { 912 | "@babel/code-frame": { 913 | "version": "7.18.6", 914 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", 915 | "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", 916 | "dev": true, 917 | "requires": { 918 | "@babel/highlight": "^7.18.6" 919 | } 920 | }, 921 | "@babel/helper-validator-identifier": { 922 | "version": "7.19.1", 923 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", 924 | "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", 925 | "dev": true 926 | }, 927 | "@babel/highlight": { 928 | "version": "7.18.6", 929 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", 930 | "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", 931 | "dev": true, 932 | "requires": { 933 | "@babel/helper-validator-identifier": "^7.18.6", 934 | "chalk": "^2.0.0", 935 | "js-tokens": "^4.0.0" 936 | } 937 | }, 938 | "@jridgewell/gen-mapping": { 939 | "version": "0.3.2", 940 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", 941 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", 942 | "dev": true, 943 | "requires": { 944 | "@jridgewell/set-array": "^1.0.1", 945 | "@jridgewell/sourcemap-codec": "^1.4.10", 946 | "@jridgewell/trace-mapping": "^0.3.9" 947 | } 948 | }, 949 | "@jridgewell/resolve-uri": { 950 | "version": "3.1.0", 951 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 952 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 953 | "dev": true 954 | }, 955 | "@jridgewell/set-array": { 956 | "version": "1.1.2", 957 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 958 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 959 | "dev": true 960 | }, 961 | "@jridgewell/source-map": { 962 | "version": "0.3.2", 963 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", 964 | "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", 965 | "dev": true, 966 | "requires": { 967 | "@jridgewell/gen-mapping": "^0.3.0", 968 | "@jridgewell/trace-mapping": "^0.3.9" 969 | } 970 | }, 971 | "@jridgewell/sourcemap-codec": { 972 | "version": "1.4.14", 973 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 974 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 975 | "dev": true 976 | }, 977 | "@jridgewell/trace-mapping": { 978 | "version": "0.3.17", 979 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", 980 | "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", 981 | "dev": true, 982 | "requires": { 983 | "@jridgewell/resolve-uri": "3.1.0", 984 | "@jridgewell/sourcemap-codec": "1.4.14" 985 | } 986 | }, 987 | "@rollup/pluginutils": { 988 | "version": "4.2.1", 989 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 990 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 991 | "dev": true, 992 | "requires": { 993 | "estree-walker": "^2.0.1", 994 | "picomatch": "^2.2.2" 995 | } 996 | }, 997 | "@types/node": { 998 | "version": "18.11.3", 999 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz", 1000 | "integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==", 1001 | "dev": true 1002 | }, 1003 | "acorn": { 1004 | "version": "8.8.0", 1005 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", 1006 | "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", 1007 | "dev": true 1008 | }, 1009 | "ansi-styles": { 1010 | "version": "3.2.1", 1011 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 1012 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 1013 | "dev": true, 1014 | "requires": { 1015 | "color-convert": "^1.9.0" 1016 | } 1017 | }, 1018 | "array-find-index": { 1019 | "version": "1.0.2", 1020 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", 1021 | "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", 1022 | "dev": true 1023 | }, 1024 | "balanced-match": { 1025 | "version": "1.0.2", 1026 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1027 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1028 | "dev": true 1029 | }, 1030 | "brace-expansion": { 1031 | "version": "1.1.11", 1032 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1033 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1034 | "dev": true, 1035 | "requires": { 1036 | "balanced-match": "^1.0.0", 1037 | "concat-map": "0.0.1" 1038 | } 1039 | }, 1040 | "buffer-from": { 1041 | "version": "1.1.2", 1042 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 1043 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 1044 | "dev": true 1045 | }, 1046 | "chalk": { 1047 | "version": "2.4.2", 1048 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 1049 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 1050 | "dev": true, 1051 | "requires": { 1052 | "ansi-styles": "^3.2.1", 1053 | "escape-string-regexp": "^1.0.5", 1054 | "supports-color": "^5.3.0" 1055 | } 1056 | }, 1057 | "color-convert": { 1058 | "version": "1.9.3", 1059 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 1060 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 1061 | "dev": true, 1062 | "requires": { 1063 | "color-name": "1.1.3" 1064 | } 1065 | }, 1066 | "color-name": { 1067 | "version": "1.1.3", 1068 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 1069 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", 1070 | "dev": true 1071 | }, 1072 | "commander": { 1073 | "version": "2.20.3", 1074 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 1075 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 1076 | "dev": true 1077 | }, 1078 | "commenting": { 1079 | "version": "1.1.0", 1080 | "resolved": "https://registry.npmjs.org/commenting/-/commenting-1.1.0.tgz", 1081 | "integrity": "sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==", 1082 | "dev": true 1083 | }, 1084 | "commondir": { 1085 | "version": "1.0.1", 1086 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", 1087 | "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", 1088 | "dev": true 1089 | }, 1090 | "concat-map": { 1091 | "version": "0.0.1", 1092 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1093 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 1094 | "dev": true 1095 | }, 1096 | "escape-string-regexp": { 1097 | "version": "1.0.5", 1098 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 1099 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 1100 | "dev": true 1101 | }, 1102 | "estree-walker": { 1103 | "version": "2.0.2", 1104 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1105 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 1106 | "dev": true 1107 | }, 1108 | "find-cache-dir": { 1109 | "version": "3.3.2", 1110 | "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", 1111 | "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", 1112 | "dev": true, 1113 | "requires": { 1114 | "commondir": "^1.0.1", 1115 | "make-dir": "^3.0.2", 1116 | "pkg-dir": "^4.1.0" 1117 | } 1118 | }, 1119 | "find-up": { 1120 | "version": "4.1.0", 1121 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 1122 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 1123 | "dev": true, 1124 | "requires": { 1125 | "locate-path": "^5.0.0", 1126 | "path-exists": "^4.0.0" 1127 | } 1128 | }, 1129 | "fs-extra": { 1130 | "version": "10.1.0", 1131 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", 1132 | "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", 1133 | "dev": true, 1134 | "requires": { 1135 | "graceful-fs": "^4.2.0", 1136 | "jsonfile": "^6.0.1", 1137 | "universalify": "^2.0.0" 1138 | } 1139 | }, 1140 | "fs.realpath": { 1141 | "version": "1.0.0", 1142 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1143 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 1144 | "dev": true 1145 | }, 1146 | "fsevents": { 1147 | "version": "2.3.2", 1148 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1149 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1150 | "dev": true, 1151 | "optional": true 1152 | }, 1153 | "glob": { 1154 | "version": "7.2.3", 1155 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 1156 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 1157 | "dev": true, 1158 | "requires": { 1159 | "fs.realpath": "^1.0.0", 1160 | "inflight": "^1.0.4", 1161 | "inherits": "2", 1162 | "minimatch": "^3.1.1", 1163 | "once": "^1.3.0", 1164 | "path-is-absolute": "^1.0.0" 1165 | } 1166 | }, 1167 | "graceful-fs": { 1168 | "version": "4.2.10", 1169 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", 1170 | "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", 1171 | "dev": true 1172 | }, 1173 | "has-flag": { 1174 | "version": "3.0.0", 1175 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1176 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 1177 | "dev": true 1178 | }, 1179 | "inflight": { 1180 | "version": "1.0.6", 1181 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1182 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 1183 | "dev": true, 1184 | "requires": { 1185 | "once": "^1.3.0", 1186 | "wrappy": "1" 1187 | } 1188 | }, 1189 | "inherits": { 1190 | "version": "2.0.4", 1191 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1192 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1193 | "dev": true 1194 | }, 1195 | "jest-worker": { 1196 | "version": "26.6.2", 1197 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", 1198 | "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", 1199 | "dev": true, 1200 | "requires": { 1201 | "@types/node": "*", 1202 | "merge-stream": "^2.0.0", 1203 | "supports-color": "^7.0.0" 1204 | }, 1205 | "dependencies": { 1206 | "has-flag": { 1207 | "version": "4.0.0", 1208 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1209 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1210 | "dev": true 1211 | }, 1212 | "supports-color": { 1213 | "version": "7.2.0", 1214 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1215 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1216 | "dev": true, 1217 | "requires": { 1218 | "has-flag": "^4.0.0" 1219 | } 1220 | } 1221 | } 1222 | }, 1223 | "js-tokens": { 1224 | "version": "4.0.0", 1225 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1226 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1227 | "dev": true 1228 | }, 1229 | "jsonfile": { 1230 | "version": "6.1.0", 1231 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 1232 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 1233 | "dev": true, 1234 | "requires": { 1235 | "graceful-fs": "^4.1.6", 1236 | "universalify": "^2.0.0" 1237 | } 1238 | }, 1239 | "locate-path": { 1240 | "version": "5.0.0", 1241 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 1242 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 1243 | "dev": true, 1244 | "requires": { 1245 | "p-locate": "^4.1.0" 1246 | } 1247 | }, 1248 | "lodash": { 1249 | "version": "4.17.21", 1250 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1251 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 1252 | "dev": true 1253 | }, 1254 | "lru-cache": { 1255 | "version": "6.0.0", 1256 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1257 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1258 | "dev": true, 1259 | "requires": { 1260 | "yallist": "^4.0.0" 1261 | } 1262 | }, 1263 | "magic-string": { 1264 | "version": "0.26.7", 1265 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", 1266 | "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", 1267 | "dev": true, 1268 | "requires": { 1269 | "sourcemap-codec": "^1.4.8" 1270 | } 1271 | }, 1272 | "make-dir": { 1273 | "version": "3.1.0", 1274 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", 1275 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", 1276 | "dev": true, 1277 | "requires": { 1278 | "semver": "^6.0.0" 1279 | }, 1280 | "dependencies": { 1281 | "semver": { 1282 | "version": "6.3.0", 1283 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1284 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1285 | "dev": true 1286 | } 1287 | } 1288 | }, 1289 | "merge-stream": { 1290 | "version": "2.0.0", 1291 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", 1292 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", 1293 | "dev": true 1294 | }, 1295 | "minimatch": { 1296 | "version": "3.1.2", 1297 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1298 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1299 | "dev": true, 1300 | "requires": { 1301 | "brace-expansion": "^1.1.7" 1302 | } 1303 | }, 1304 | "miniprogram-api-typings": { 1305 | "version": "3.6.0", 1306 | "resolved": "https://registry.npmjs.org/miniprogram-api-typings/-/miniprogram-api-typings-3.6.0.tgz", 1307 | "integrity": "sha512-xwK3PzhhxnfWqDfBikHLdAbj7Wy4F887nBcQrzwuF758Fw2qC4ivpKPL9t0uJZk5QYnU28+NqA7Q3lzYGMHQnA==", 1308 | "dev": true 1309 | }, 1310 | "mkdirp": { 1311 | "version": "1.0.4", 1312 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 1313 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", 1314 | "dev": true 1315 | }, 1316 | "moment": { 1317 | "version": "2.29.4", 1318 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", 1319 | "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", 1320 | "dev": true 1321 | }, 1322 | "once": { 1323 | "version": "1.4.0", 1324 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1325 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 1326 | "dev": true, 1327 | "requires": { 1328 | "wrappy": "1" 1329 | } 1330 | }, 1331 | "p-limit": { 1332 | "version": "2.3.0", 1333 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 1334 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 1335 | "dev": true, 1336 | "requires": { 1337 | "p-try": "^2.0.0" 1338 | } 1339 | }, 1340 | "p-locate": { 1341 | "version": "4.1.0", 1342 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 1343 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 1344 | "dev": true, 1345 | "requires": { 1346 | "p-limit": "^2.2.0" 1347 | } 1348 | }, 1349 | "p-try": { 1350 | "version": "2.2.0", 1351 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 1352 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 1353 | "dev": true 1354 | }, 1355 | "package-name-regex": { 1356 | "version": "2.0.6", 1357 | "resolved": "https://registry.npmjs.org/package-name-regex/-/package-name-regex-2.0.6.tgz", 1358 | "integrity": "sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==", 1359 | "dev": true 1360 | }, 1361 | "path-exists": { 1362 | "version": "4.0.0", 1363 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1364 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1365 | "dev": true 1366 | }, 1367 | "path-is-absolute": { 1368 | "version": "1.0.1", 1369 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1370 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 1371 | "dev": true 1372 | }, 1373 | "picomatch": { 1374 | "version": "2.3.1", 1375 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1376 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1377 | "dev": true 1378 | }, 1379 | "pkg-dir": { 1380 | "version": "4.2.0", 1381 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 1382 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 1383 | "dev": true, 1384 | "requires": { 1385 | "find-up": "^4.0.0" 1386 | } 1387 | }, 1388 | "randombytes": { 1389 | "version": "2.1.0", 1390 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 1391 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 1392 | "dev": true, 1393 | "requires": { 1394 | "safe-buffer": "^5.1.0" 1395 | } 1396 | }, 1397 | "rollup": { 1398 | "version": "2.79.1", 1399 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", 1400 | "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", 1401 | "dev": true, 1402 | "requires": { 1403 | "fsevents": "~2.3.2" 1404 | } 1405 | }, 1406 | "rollup-plugin-license": { 1407 | "version": "2.8.2", 1408 | "resolved": "https://registry.npmjs.org/rollup-plugin-license/-/rollup-plugin-license-2.8.2.tgz", 1409 | "integrity": "sha512-jv268aj71J0Ee6+isjy1mYD2LlwuNg6aUiSdgly0PS0fQ2+vsuc+PLx1ueSk2/QKfjk5OJzcGPEDMHyoIeAFCw==", 1410 | "dev": true, 1411 | "requires": { 1412 | "commenting": "~1.1.0", 1413 | "glob": "~7.2.0", 1414 | "lodash": "~4.17.21", 1415 | "magic-string": "~0.26.2", 1416 | "mkdirp": "~1.0.4", 1417 | "moment": "~2.29.3", 1418 | "package-name-regex": "~2.0.6", 1419 | "spdx-expression-validate": "~2.0.0", 1420 | "spdx-satisfies": "~5.0.1" 1421 | } 1422 | }, 1423 | "rollup-plugin-terser": { 1424 | "version": "7.0.2", 1425 | "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", 1426 | "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", 1427 | "dev": true, 1428 | "requires": { 1429 | "@babel/code-frame": "^7.10.4", 1430 | "jest-worker": "^26.2.1", 1431 | "serialize-javascript": "^4.0.0", 1432 | "terser": "^5.0.0" 1433 | } 1434 | }, 1435 | "rollup-plugin-typescript2": { 1436 | "version": "0.34.1", 1437 | "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.34.1.tgz", 1438 | "integrity": "sha512-P4cHLtGikESmqi1CA+tdMDUv8WbQV48mzPYt77TSTOPJpERyZ9TXdDgjSDix8Fkqce6soYz3+fa4lrC93IEkcw==", 1439 | "dev": true, 1440 | "requires": { 1441 | "@rollup/pluginutils": "^4.1.2", 1442 | "find-cache-dir": "^3.3.2", 1443 | "fs-extra": "^10.0.0", 1444 | "semver": "^7.3.7", 1445 | "tslib": "^2.4.0" 1446 | } 1447 | }, 1448 | "safe-buffer": { 1449 | "version": "5.2.1", 1450 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1451 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1452 | "dev": true 1453 | }, 1454 | "semver": { 1455 | "version": "7.3.8", 1456 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", 1457 | "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", 1458 | "dev": true, 1459 | "requires": { 1460 | "lru-cache": "^6.0.0" 1461 | } 1462 | }, 1463 | "serialize-javascript": { 1464 | "version": "4.0.0", 1465 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", 1466 | "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", 1467 | "dev": true, 1468 | "requires": { 1469 | "randombytes": "^2.1.0" 1470 | } 1471 | }, 1472 | "source-map": { 1473 | "version": "0.6.1", 1474 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1475 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1476 | "dev": true 1477 | }, 1478 | "source-map-support": { 1479 | "version": "0.5.21", 1480 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 1481 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 1482 | "dev": true, 1483 | "requires": { 1484 | "buffer-from": "^1.0.0", 1485 | "source-map": "^0.6.0" 1486 | } 1487 | }, 1488 | "sourcemap-codec": { 1489 | "version": "1.4.8", 1490 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 1491 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 1492 | "dev": true 1493 | }, 1494 | "spdx-compare": { 1495 | "version": "1.0.0", 1496 | "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", 1497 | "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", 1498 | "dev": true, 1499 | "requires": { 1500 | "array-find-index": "^1.0.2", 1501 | "spdx-expression-parse": "^3.0.0", 1502 | "spdx-ranges": "^2.0.0" 1503 | } 1504 | }, 1505 | "spdx-exceptions": { 1506 | "version": "2.3.0", 1507 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", 1508 | "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", 1509 | "dev": true 1510 | }, 1511 | "spdx-expression-parse": { 1512 | "version": "3.0.1", 1513 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", 1514 | "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", 1515 | "dev": true, 1516 | "requires": { 1517 | "spdx-exceptions": "^2.1.0", 1518 | "spdx-license-ids": "^3.0.0" 1519 | } 1520 | }, 1521 | "spdx-expression-validate": { 1522 | "version": "2.0.0", 1523 | "resolved": "https://registry.npmjs.org/spdx-expression-validate/-/spdx-expression-validate-2.0.0.tgz", 1524 | "integrity": "sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==", 1525 | "dev": true, 1526 | "requires": { 1527 | "spdx-expression-parse": "^3.0.0" 1528 | } 1529 | }, 1530 | "spdx-license-ids": { 1531 | "version": "3.0.12", 1532 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", 1533 | "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", 1534 | "dev": true 1535 | }, 1536 | "spdx-ranges": { 1537 | "version": "2.1.1", 1538 | "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", 1539 | "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", 1540 | "dev": true 1541 | }, 1542 | "spdx-satisfies": { 1543 | "version": "5.0.1", 1544 | "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-5.0.1.tgz", 1545 | "integrity": "sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==", 1546 | "dev": true, 1547 | "requires": { 1548 | "spdx-compare": "^1.0.0", 1549 | "spdx-expression-parse": "^3.0.0", 1550 | "spdx-ranges": "^2.0.0" 1551 | } 1552 | }, 1553 | "supports-color": { 1554 | "version": "5.5.0", 1555 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1556 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1557 | "dev": true, 1558 | "requires": { 1559 | "has-flag": "^3.0.0" 1560 | } 1561 | }, 1562 | "terser": { 1563 | "version": "5.15.1", 1564 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", 1565 | "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", 1566 | "dev": true, 1567 | "requires": { 1568 | "@jridgewell/source-map": "^0.3.2", 1569 | "acorn": "^8.5.0", 1570 | "commander": "^2.20.0", 1571 | "source-map-support": "~0.5.20" 1572 | } 1573 | }, 1574 | "tslib": { 1575 | "version": "2.4.0", 1576 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", 1577 | "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", 1578 | "dev": true 1579 | }, 1580 | "typescript": { 1581 | "version": "4.8.4", 1582 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", 1583 | "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", 1584 | "dev": true, 1585 | "peer": true 1586 | }, 1587 | "universalify": { 1588 | "version": "2.0.0", 1589 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", 1590 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", 1591 | "dev": true 1592 | }, 1593 | "wrappy": { 1594 | "version": "1.0.2", 1595 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1596 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1597 | "dev": true 1598 | }, 1599 | "yallist": { 1600 | "version": "4.0.0", 1601 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1602 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 1603 | "dev": true 1604 | } 1605 | } 1606 | } 1607 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "miniprogram-turbo-setdata", 3 | "version": "1.0.5", 4 | "main": "./dist/index.min.js", 5 | "scripts": { 6 | "build": "rollup -c" 7 | }, 8 | "keywords": [ 9 | "miniprogram", 10 | "优化 setData", 11 | "setData", 12 | "小程序 watch", 13 | "小程序 computed", 14 | "小程序监听", 15 | "小程序优化" 16 | ], 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/Pursue-LLL/miniprogram-turbo-setdata.git" 20 | }, 21 | "homepage": "https://juejin.cn/post/7160475467362304030", 22 | "author": { 23 | "name": "CorderLiu", 24 | "email": "xxiaoer2018@163.com", 25 | "url": "https://juejin.cn/user/817692379722311" 26 | }, 27 | "license": "MIT", 28 | "description": "小程序 setData 增强库", 29 | "typeRoots": [ 30 | "./node_modules/miniprogram-api-typings" 31 | ], 32 | "type": "module", 33 | "types": "lib/index.d.ts", 34 | "files": [ 35 | "dist", 36 | "LICENSE", 37 | "lib/index.d.ts" 38 | ], 39 | "devDependencies": { 40 | "miniprogram-api-typings": "^3.6.0", 41 | "rollup": "^2.0.0", 42 | "rollup-plugin-license": "^2.8.2", 43 | "rollup-plugin-terser": "^7.0.2", 44 | "rollup-plugin-typescript2": "^0.34.1" 45 | }, 46 | "dependencies": {} 47 | } 48 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | import pkg from './package.json' 4 | // 压缩代码 5 | import { terser } from "rollup-plugin-terser"; 6 | // 添加版权信息 7 | import license from 'rollup-plugin-license'; 8 | // 编译 ts 9 | import ts from "rollup-plugin-typescript2" 10 | 11 | 12 | export default { 13 | input: path.resolve(__dirname, 'lib/index.ts'), // __dirname指的是当前文件所在文件夹的绝对路径。 14 | 15 | plugins: [ 16 | ts(), 17 | terser({ compress: { } }), 18 | license({ 19 | banner: { 20 | content: { 21 | file: path.join(__dirname, 'LICENSE'), 22 | encoding: 'utf-8', // Default is utf-8 23 | }, 24 | }, 25 | }), 26 | ], 27 | output: [ 28 | { 29 | file: pkg.main, 30 | format: `esm` 31 | }, 32 | ], 33 | } 34 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "outDir": "dist", 5 | "sourceMap": false, 6 | "noImplicitAny": false, 7 | "target": "es6", 8 | "newLine": "LF", 9 | "useDefineForClassFields": false, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "allowJs": false, 13 | "strict": true, 14 | "noUnusedLocals": true, 15 | "experimentalDecorators": true, 16 | "resolveJsonModule": true, 17 | "esModuleInterop": true, 18 | "removeComments": true, 19 | "jsx": "preserve", 20 | "lib": ["esnext", "dom"], 21 | "typeRoots": [ 22 | "./node_modules/miniprogram-api-typings" 23 | ], 24 | "rootDir": ".", 25 | }, 26 | "include": [ 27 | "lib" 28 | ], 29 | "exclude": [ 30 | "node_modules" 31 | ] 32 | } 33 | --------------------------------------------------------------------------------