文字文字1
47 |文字文字2
48 | 49 |文字文字3
50 |文字文字4
51 |文字文字5
52 |文字文字6
53 |文字文字7
54 |文字文字8
55 |文字文字9
56 |文字文字10
57 |文字文字11
58 |├── .gitignore ├── 001_Eventhub ├── README.md ├── src │ └── index.ts └── test │ └── index.ts ├── 002_DeepClone ├── README.md ├── package.json ├── src │ └── index.js ├── test │ └── index.js └── yarn.lock ├── 003_MethodChaining └── index.js ├── 004_Bind ├── .keep ├── README.md ├── src │ └── index.js └── test │ └── index.js ├── 005_Promise ├── README.md ├── package.json ├── pnpm-lock.yaml ├── src │ └── index.ts └── test │ └── index.ts ├── 006_EventLoop ├── .DS_Store ├── README.md └── images │ ├── .DS_Store │ └── message_queue1.png ├── 007_Vue2Reactivity ├── README.md ├── index.html ├── index.js └── vue.js ├── 008_Sort ├── CountingSort.js ├── MergeSort.js ├── QuickSort.js └── SelectionSort.js ├── 009_TextHorizontalAlignment ├── README.md ├── images │ └── img.png └── index.html ├── 010_Dynamic_REM └── README.md ├── 011_JS_Wheels ├── Dialog.html ├── README.md ├── Slides.html ├── Sticky.html └── Tabs.html └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /001_Eventhub/README.md: -------------------------------------------------------------------------------- 1 | # EventHub 2 | 3 | ## 一、`EventHub` 是什么 4 | 5 | - `EventHub` 又叫 `发布/ 订阅模式`,是用于多个模块之间进行通信的 6 | - 比如我们有两个文件,分别是:`1.js` 和 `2.js` 7 | - `1.js` 里有一个函数 `fn1`,`2.js` 里有个函数 `fn2` 8 | - `fn1` 想要调佣 `fn2`,怎么才能做到呢? 9 | - 如果不用全局变量,那我们就可以使用 `EventHub` 10 | - 那么就可以这么写: 11 | ```js 12 | // 1.js 13 | // 发布 14 | fn1 = () => { 15 | eventhub.emit('轮到fn2') // 调用 '轮到fn2' 事件,eventhub 会通知注册 '轮到fn2' 事件的模块 16 | } 17 | 18 | // 2.js 19 | // 订阅 20 | eventhub.on('轮到fn2', () => { 21 | // 注册/监听 '轮到fn2' 事件 22 | fn2() 23 | }) 24 | ``` 25 | 26 | ## 二、确定 API 27 | 28 | > 先确认各个 API 的功能,再去实现,再去写代码 29 | 30 | ### API 列表 31 | 32 | > 为什么我用井号?因为 `EventHub` 是一个类,井号表示是一个对象的属性 33 | 34 | - EventHub#on 35 | 36 | > 注册/监听事件 37 | 38 | - EventHub#off 39 | > 取消事件 40 | - EventHub#emit 41 | > 触发事件 42 | 43 | ## 三、源码书写过程 44 | 45 | > 采用测试驱动开发:添加测试用例,想办法让测试通过\ 46 | > 不使用库,而是用非常简单的 `console` 方式\ 47 | > 需要全局安装 `ts-node@8.3.0` 48 | 49 | ### 1. 在根目录下创建 `test/index.ts` 和 `src/index.ts` 50 | 51 | ```ts 52 | // src/index.ts 53 | export class EventHub {} 54 | ``` 55 | 56 | ```ts 57 | // test/index.ts 58 | import { EventHub } from '../src/index' 59 | const eventhub = new EventHub() 60 | console.assert(eventHub instanceof Object === true, 'eventHub 是一个对象') 61 | ``` 62 | 63 | 然后在当前目录下执行 `ts-node test/index.ts`,如果没有报错,则测试通过 64 | 65 | ### 2. `on` 和 `emit` 66 | 67 | #### 添加测试用例 `on` 和 `emit` 68 | 69 | ```ts 70 | // test/index.ts 71 | import { EventHub } from '../src/index' 72 | const eventhub = new EventHub() 73 | 74 | let called = false 75 | eventhub.on('xxx', () => { 76 | called = true 77 | console.log('called:' + called) 78 | }) 79 | eventhub.emit('xxx') 80 | ``` 81 | 82 | #### 实现 `on` 和 `emit` 83 | 84 | 1. `on` 接受两个参数,第一个是 `事件名`、第二个是一个 `回调事件` 85 | 2. `emit` 接受一个参数,为 `事件名` 86 | 3. `on`:当有人订阅了事件之后,我们需要把 `事件名` 和 `事件回调` 存在一个 `map` 里,这里我放在 `cache` 这个对象 87 | ```ts 88 | // cache 的数据结构 89 | cache = { 90 | 事件1: [fn1, fn2, fn3], 91 | 事件2: [fn1, fn2, fn3] 92 | } 93 | ``` 94 | 4. `emit`:触发 `事件回调`,读取事件名相对应的函数,并且依次调用这些函数 95 | 96 | ```ts 97 | // src/index.ts 98 | export class EventHub { 99 | cache = {} 100 | on(eventName, fn) { 101 | // cache 可能为空,所以需要对这个 cache 初始化:如果 eventName 没有出现过,就初始化成一个数组 102 | if (this.cache[eventName] === undefined) { 103 | this.cache[eventName] = [] 104 | } 105 | // 然后把函数放进数组里 106 | const array = this.cache[eventName] 107 | array.push(fn) 108 | } 109 | emit(eventName) { 110 | // 读取 eventName 相对应的函数,但可能 cache 里不存在 eventName,就把他变成一个空数组,所以不管怎么样都是个数组,我们就可以去遍历它 111 | let array = this.cache[eventName] 112 | if (array === undefined) { 113 | array = [] 114 | } 115 | array.forEach(fn => { 116 | fn() 117 | }) 118 | } 119 | } 120 | ``` 121 | 122 | 运行 `ts-node test/index.ts`,如果控制台输出 `called:true` 那么就测试通过 123 | 124 | ### 3. 优化代码 125 | 126 | ```diff 127 | export class EventHub { 128 | cache = {} 129 | on(eventName, fn) { 130 | - if (this.cache[eventName] === undefined) { 131 | - this.cache[eventName] = [] 132 | - } 133 | + this.cache[eventName] = this.cache[eventName] || [] 134 | - const array = this.cache[eventName] 135 | - array.push(fn) 136 | + this.cache[eventName].push 137 | } 138 | emit(eventName) { 139 | - let array = this.cache[eventName] 140 | - if (array === undefined) { 141 | - array = [] 142 | - } 143 | - let array = this.cache[eventName] || [] 144 | - array.forEach(fn => { 145 | - fn() 146 | - }) 147 | + (this.cache[eventName] || []).forEach(fn => fn()) 148 | } 149 | } 150 | ``` 151 | 152 | 运行 `ts-node test/index.ts`,如果不报任何错误,则测试通过 153 | 154 | ### 4. 实现 `emit` 的第二个参数 155 | 156 | #### 添加测试用例 157 | 158 | ```ts 159 | // test/index.ts 160 | import { EventHub } from '../src/index' 161 | const eventhub = new EventHub() 162 | 163 | let called = false 164 | eventhub.on('xxx', data => { 165 | called = true 166 | console.log('called:' + called) 167 | console.assert(data === '接受的数据') // 断言 data 和函数接受的数据相等 168 | }) 169 | eventhub.emit('xxx', '接受的数据') // 第二个参数接受数据 170 | ``` 171 | 172 | #### 实现功能 173 | 174 | 很简单,把 `接受的数据` 传给每一个函数即可 175 | 176 | ```ts 177 | // src/index.ts 178 | export class EventHub { 179 | cache = {} 180 | on(eventName, fn) { 181 | this.cache[eventName] = this.cache[eventName] || [] 182 | this.cache[eventName].push 183 | } 184 | emit(eventName, data?) { 185 | // 把接收的数据传给每一个函数就可以了 186 | (this.cache[eventName] || []).forEach(fn => fn(data)) 187 | } 188 | ``` 189 | 190 | 运行 `ts-node test/index.ts`,如果不报任何错误,则测试通过 191 | 192 | ### 5. 实现 `off` 193 | 194 | #### 测试用例 195 | 196 | 想象在淘宝买东西:我下单后,在发货前,马上取消订单,这样子货就不会送到家里 197 | 198 | ```ts 199 | // test/index.ts 200 | import { EventHub } from '../src/index' 201 | const eventhub = new EventHub() 202 | 203 | let called = false 204 | eventhub.on('xxx', data => { 205 | called = true 206 | console.log('called:' + called) 207 | console.assert(data === '接受的数据') 208 | }) 209 | eventhub.emit('xxx', '接受的数据') 210 | 211 | const eventHub2 = new EventHub() 212 | let called2 = false 213 | const fn1 = () => { 214 | called2 = true 215 | } 216 | eventHub.on('yyy', fn1) 217 | eventHub.off('yyy', fn1) // 顺序非常重要,要在订阅之后(发布之前)马上取消 218 | eventHub.emit('yyy') 219 | setTimeout(() => { 220 | console.log(called2) // 如果值为 false,则测试通过 221 | }, 1000) 222 | ``` 223 | 224 | #### 实现功能 225 | 226 | 把 `map` 里相对应的函数删掉 227 | 228 | ```ts 229 | // src/index.ts 230 | export class EventHub { 231 | cache = {} 232 | on(eventName, fn) { 233 | this.cache[eventName] = this.cache[eventName] || [] 234 | this.cache[eventName].push 235 | } 236 | emit(eventName, data?) { 237 | ;(this.cache[eventName] || []).forEach(fn => fn(data)) 238 | } 239 | off(eventName, fn) { 240 | // 把 fn 从 this.cache[eventName] 里删掉 241 | this.cache[eventName] = this.cache[eventName] || [] 242 | let index = undefined 243 | for (let i = 0; i < this.cache[eventName].length; i++) { 244 | if (this.cache[eventName][i] === fn) { 245 | index = i 246 | break 247 | } 248 | } 249 | if ((index = undefined)) { 250 | return 251 | } else { 252 | this.cache[eventName].splice(index, 1) 253 | } 254 | } 255 | } 256 | ``` 257 | 258 | 运行 `ts-node test/index.ts`,输出 `false` 则测试成功 259 | 260 | ### 6. 优化代码 261 | 262 | ```diff 263 | export class EventHub { 264 | cache = {} 265 | on(eventName, fn) { 266 | this.cache[eventName] = this.cache[eventName] || [] 267 | this.cache[eventName].push 268 | } 269 | emit(eventName, data?) { 270 | (this.cache[eventName] || []).forEach(fn => fn(data)) 271 | } 272 | off(eventName, fn) { 273 | - this.cache[eventName] = this.cache[eventName] || [] 274 | - let index = undefined 275 | - for(let i = 0; i < this.cache[eventName].length; i++) { 276 | - if(this.cache[eventName][i] === fn) { 277 | - index = i 278 | - break 279 | - } 280 | - } 281 | + let index = indexOf(this.cache[eventName], fn) 282 | - if(index = undefined) { 283 | - return 284 | - } else { 285 | - this.cache[eventName].splice(index, 1) 286 | - } 287 | + if(index = -1) return 288 | + this.cache[eventName].splice(index, 1) 289 | } 290 | } 291 | 292 | +function indexOf(array, item) { 293 | + if (array === undefined) return -1 294 | + let index = -1 295 | + for (let i = 0; i < array.length; i++) { 296 | + if (array[i] === item) { 297 | + index = i 298 | + } 299 | + } 300 | + return index 301 | +} 302 | ``` 303 | 304 | ## 五、重构代码 305 | 306 | > 重构!优化! 307 | 308 | ### 1. 重构优化测试代码 309 | 310 | ```ts 311 | import { EventHub } from '../src/index' 312 | 313 | type TestCase = (message: string) => void 314 | 315 | const test1: TestCase = message => { 316 | const eventHub = new EventHub() 317 | console.assert(eventHub instanceof Object === true, 'eventHub 是一个对象') 318 | console.log(message) 319 | } 320 | 321 | const test2: TestCase = message => { 322 | // on emit 323 | const eventHub = new EventHub() 324 | let called = false 325 | eventHub.on('xxx', data => { 326 | called = true 327 | console.assert(data[0] === '接受的数据1') 328 | console.assert(data[1] === '接受的数据2') 329 | }) 330 | eventHub.emit('xxx', ['接受的数据1', '接受的数据2']) 331 | console.assert(called) 332 | console.log(message) 333 | } 334 | 335 | const test3: TestCase = message => { 336 | const eventHub = new EventHub() 337 | let called = false 338 | const fn1 = () => { 339 | called = true 340 | } 341 | 342 | eventHub.on('yyy', fn1) 343 | eventHub.off('yyy', fn1) 344 | eventHub.emit('yyy') 345 | console.assert(called === false) 346 | console.log(message) 347 | } 348 | 349 | test1('EventHub 可以创建对象') 350 | test2('.on 之后 .emit 会触发 .on 的函数') 351 | test3('.off 是有用的') 352 | ``` 353 | 354 | ### 2. 重构优化 `EventHub` 355 | 356 | ```ts 357 | export class EventHub { 358 | private cache: { [key: string]: Array<(data: unknown) => void> } = {} 359 | on(eventName: string, fn: (data: any) => void) { 360 | this.cache[eventName] = this.cache[eventName] || [] 361 | this.cache[eventName].push(fn) 362 | } 363 | emit(eventName: string, data?: unknown) { 364 | (this.cache[eventName] || []).forEach(fn => fn(data)) 365 | } 366 | off(eventName: string, fn: (data: unknown) => void) { 367 | let index = indexOf(this.cache[eventName], fn) 368 | if (index === -1) return 369 | this.cache[eventName].splice(index, 1) 370 | } 371 | } 372 | 373 | /** 374 | * 帮助函数 indexOf 375 | */ 376 | function indexOf(array, item) { 377 | if (array === undefined) return -1 378 | let index = -1 379 | for (let i = 0; i < array.length; i++) { 380 | if (array[i] === item) { 381 | index = i 382 | } 383 | } 384 | return index 385 | } 386 | ``` 387 | -------------------------------------------------------------------------------- /001_Eventhub/src/index.ts: -------------------------------------------------------------------------------- 1 | export class EventHub { 2 | private cache: { [key: string]: Array<(data: unknown) => void> } = {} 3 | on(eventName: string, fn: (data: any) => void) { 4 | this.cache[eventName] = this.cache[eventName] || [] 5 | this.cache[eventName].push(fn) 6 | } 7 | emit(eventName: string, data?: unknown) { 8 | (this.cache[eventName] || []).forEach(fn => fn(data)) 9 | } 10 | off(eventName: string, fn: (data: unknown) => void) { 11 | let index = indexOf(this.cache[eventName], fn) 12 | if (index === -1) return 13 | this.cache[eventName].splice(index, 1) 14 | } 15 | } 16 | 17 | /** 18 | * 帮助函数 indexOf 19 | */ 20 | function indexOf(array, item) { 21 | if (array === undefined) return -1 22 | let index = -1 23 | for (let i = 0; i < array.length; i++) { 24 | if (array[i] === item) { 25 | index = i 26 | } 27 | } 28 | return index 29 | } 30 | -------------------------------------------------------------------------------- /001_Eventhub/test/index.ts: -------------------------------------------------------------------------------- 1 | import { EventHub } from '../src/index' 2 | 3 | type TestCase = (message: string) => void 4 | 5 | const test1: TestCase = message => { 6 | const eventHub = new EventHub() 7 | console.assert(eventHub instanceof Object === true, 'eventHub 是一个对象') 8 | console.log(message) 9 | } 10 | 11 | const test2: TestCase = message => { 12 | // on emit 13 | const eventHub = new EventHub() 14 | let called = false 15 | eventHub.on('xxx', data => { 16 | called = true 17 | console.assert(data[0] === '接受的数据1') 18 | console.assert(data[1] === '接受的数据2') 19 | }) 20 | eventHub.emit('xxx', ['接受的数据1', '接受的数据2']) 21 | console.assert(called) 22 | console.log(message) 23 | } 24 | 25 | const test3: TestCase = message => { 26 | const eventHub = new EventHub() 27 | let called = false 28 | const fn1 = () => { 29 | called = true 30 | } 31 | 32 | eventHub.on('yyy', fn1) 33 | eventHub.off('yyy', fn1) 34 | eventHub.emit('yyy') 35 | console.assert(called === false) 36 | console.log(message) 37 | } 38 | 39 | test1('EventHub 可以创建对象') 40 | test2('.on 之后 .emit 会触发 .on 的函数') 41 | test3('.off 是有用的') 42 | -------------------------------------------------------------------------------- /002_DeepClone/README.md: -------------------------------------------------------------------------------- 1 | # 来!跟我一起手写「深拷贝」 2 | 3 | 4 | -------------------------------------------------------------------------------- /002_DeepClone/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deep-clone", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "mocha test/**/*.js" 8 | }, 9 | "devDependencies": { 10 | "chai": "^4.2.0", 11 | "mocha": "^6.2.0", 12 | "sinon": "^7.4.1", 13 | "sinon-chai": "^3.3.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /002_DeepClone/src/index.js: -------------------------------------------------------------------------------- 1 | class DeepCloner { 2 | cache = [] 3 | clone(source) { 4 | if (source instanceof Object) { 5 | let cacheDist = this.findCache(source) 6 | if (cacheDist) { 7 | return cacheDist 8 | } else { 9 | let dist 10 | if (source instanceof Array) { 11 | dist = new Array() 12 | } else if (source instanceof Function) { 13 | dist = function () { 14 | return source.apply(this, arguments) 15 | } 16 | } else if (source instanceof RegExp) { 17 | dist = new RegExp(source.source, source.flags) 18 | } else if (source instanceof Date) { 19 | dist = new Date(source) 20 | } else if (source instanceof Set) { 21 | dist = new Set(source) 22 | } else if (source instanceof Map) { 23 | dist = new Map(source) 24 | } else { 25 | dist = new Object() 26 | } 27 | this.cache.push([source, dist]) 28 | for (let key in source) { 29 | if (source.hasOwnProperty(key)) { 30 | dist[key] = this.clone(source[key]) 31 | } 32 | } 33 | return dist 34 | } 35 | } 36 | return source 37 | } 38 | 39 | findCache(source) { 40 | for (let i = 0; i < this.cache.length; i++) { 41 | if (this.cache[i][0] === source) { 42 | return this.cache[i][1] 43 | } 44 | } 45 | return undefined 46 | } 47 | } 48 | 49 | module.exports = DeepCloner 50 | -------------------------------------------------------------------------------- /002_DeepClone/test/index.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const sinon = require('sinon') 3 | const sinonChai = require('sinon-chai') 4 | chai.use(sinonChai) 5 | 6 | const assert = chai.assert 7 | const DeepCloner = require('../src/index') 8 | 9 | describe('deepClone', () => { 10 | it('是一个类', () => { 11 | assert.isFunction(DeepCloner) 12 | }) 13 | it('能够复制基本类型', () => { 14 | const num = 123 15 | assert(num === new DeepCloner().clone(num)) 16 | const str = 'string' 17 | assert(str === new DeepCloner().clone(str)) 18 | const bool = true 19 | assert(bool === new DeepCloner().clone(bool)) 20 | const und = undefined 21 | assert(und === new DeepCloner().clone(und)) 22 | const nul = null 23 | assert(nul === new DeepCloner().clone(nul)) 24 | const sym = Symbol() 25 | assert(sym === new DeepCloner().clone(sym)) 26 | }) 27 | describe('对象', () => { 28 | it('能够复制普通对象', () => { 29 | const obj = { name: 'heycn', child: { name: 'small-heycn' } } 30 | const obj2 = new DeepCloner().clone(obj) 31 | assert(obj !== obj2) 32 | assert(obj.name === obj2.name) 33 | assert(obj.child !== obj2.child) 34 | assert(obj.child.name === obj2.child.name) 35 | }) 36 | it('能够复制数组对象', () => { 37 | const arr = [[11, 12], [21, 22], [31, 32]] 38 | const arr2 = new DeepCloner().clone(arr) 39 | assert(arr !== arr2) 40 | assert(arr[0] !== arr2[0]) 41 | assert(arr[1] !== arr2[1]) 42 | assert(arr[2] !== arr2[2]) 43 | assert.deepEqual(arr, arr2) 44 | }) 45 | it('能够复制函数', () => { 46 | const fn = (x, y) => x + y 47 | fn.xxx = { yyy: { zzz: 1 } } 48 | const fn2 = new DeepCloner().clone(fn) 49 | assert(fn !== fn2) 50 | assert(fn.xxx.yyy.zzz === fn2.xxx.yyy.zzz) 51 | assert(fn.xxx.yyy !== fn2.xxx.yyy) 52 | assert(fn.xxx !== fn2.xxx) 53 | assert(fn(1, 2) === fn2(1, 2)) 54 | }) 55 | it('能够复制环', () => { 56 | const cycle = { name: 'heycn' } 57 | cycle.self = cycle 58 | const cycle2 = new DeepCloner().clone(cycle) 59 | assert(cycle.name === cycle2.name) 60 | assert(cycle.self !== cycle2.self) 61 | }) 62 | xit('不会爆栈', () => { 63 | const a = { child: null } 64 | let b = a 65 | for (let i = 0; i < 100000; i++) { 66 | b.child = { 67 | child: null 68 | } 69 | b = b.child 70 | } 71 | const a2 = new DeepCloner().clone(a) 72 | assert(a !== a2) 73 | assert(a.child !== a2.child) 74 | }) 75 | it('可以复制正则表达式', () => { 76 | const reg = new RegExp('hi\\d+', 'gi') 77 | reg.xxx = { yyy: { zzz: 1 } } 78 | const reg2 = new DeepCloner().clone(reg) 79 | assert(reg.source === reg2.source) 80 | assert(reg.flags === reg2.flags) 81 | assert(reg !== reg2) 82 | assert(reg.xxx.yyy.zzz === reg2.xxx.yyy.zzz) 83 | assert(reg.xxx.yyy !== reg2.xxx.yyy) 84 | assert(reg.xxx !== reg2.xxx) 85 | }) 86 | it('可以复制日期', () => { 87 | const date = new Date() 88 | date.xxx = { yyy: { zzz: 1 } } 89 | const date2 = new DeepCloner().clone(date) 90 | assert(date !== date2) 91 | assert(date.getTime() === date2.getTime()) 92 | assert(date.xxx.yyy.zzz === date2.xxx.yyy.zzz) 93 | assert(date.xxx.yyy !== date2.xxx.yyy) 94 | assert(date.xxx !== date2.xxx) 95 | }) 96 | it('自动跳过原型属性', () => { 97 | const obj = Object.create({ name: 'heycn' }) 98 | obj.xxx = { yyy: { zzz: 1 } } 99 | const obj2 = new DeepCloner().clone(obj) 100 | assert(obj !== obj2) 101 | assert.isFalse('name' in obj2) 102 | assert(obj.xxx.yyy.zzz === obj2.xxx.yyy.zzz) 103 | assert(obj.xxx.yyy !== obj2.xxx.yyy) 104 | assert(obj.xxx !== obj2.xxx) 105 | }) 106 | it('可以复制很复杂的对象', () => { 107 | const a = { 108 | n: NaN, 109 | n2: Infinity, 110 | s: '', 111 | bool: false, 112 | null: null, 113 | u: undefined, 114 | sym: Symbol(), 115 | o: { 116 | n: NaN, 117 | n2: Infinity, 118 | s: '', 119 | bool: false, 120 | null: null, 121 | u: undefined, 122 | sym: Symbol() 123 | }, 124 | array: [ 125 | { 126 | n: NaN, 127 | n2: Infinity, 128 | s: '', 129 | bool: false, 130 | null: null, 131 | u: undefined, 132 | sym: Symbol() 133 | } 134 | ] 135 | } 136 | const a2 = new DeepCloner().clone(a) 137 | assert(a !== a2) 138 | assert.isNaN(a2.n) 139 | assert(a.n2 === a2.n2) 140 | assert(a.s === a2.s) 141 | assert(a.bool === a2.bool) 142 | assert(a.null === a2.null) 143 | assert(a.u === a2.u) 144 | assert(a.sym === a2.sym) 145 | assert(a.o !== a2.o) 146 | assert.isNaN(a2.o.n) 147 | assert(a.o.n2 === a2.o.n2) 148 | assert(a.o.s === a2.o.s) 149 | assert(a.o.bool === a2.o.bool) 150 | assert(a.o.null === a2.o.null) 151 | assert(a.o.u === a2.o.u) 152 | assert(a.o.sym === a2.o.sym) 153 | assert(a.array !== a2.array) 154 | assert(a.array[0] !== a2.array[0]) 155 | assert.isNaN(a2.array[0].n) 156 | assert(a.array[0].n2 === a2.array[0].n2) 157 | assert(a.array[0].s === a2.array[0].s) 158 | assert(a.array[0].bool === a2.array[0].bool) 159 | assert(a.array[0].null === a2.array[0].null) 160 | assert(a.array[0].u === a2.array[0].u) 161 | assert(a.array[0].sym === a2.array[0].sym) 162 | }) 163 | it('可以复制 Set', () => { 164 | const a = new Set() 165 | a.add(1) 166 | a.add({ n: 1 }) 167 | const a2 = new DeepCloner().clone(a) 168 | assert(a !== a2) 169 | assert(a.size === a2.size) 170 | assert(a.has(1) === a2.has(1)) 171 | assert(a.has({ n: 1 }) === a2.has({ n: 1 })) 172 | }) 173 | it('可以复制 Map', () => { 174 | const a = new Map() 175 | a.set('a', 1) 176 | a.set('b', { n: 1 }) 177 | const a2 = new DeepCloner().clone(a) 178 | assert(a !== a2) 179 | }) 180 | }) 181 | }) 182 | -------------------------------------------------------------------------------- /002_DeepClone/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0", "@sinonjs/commons@^1.7.0": 6 | version "1.8.6" 7 | resolved "https://registry.npmmirror.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" 8 | integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== 9 | dependencies: 10 | type-detect "4.0.8" 11 | 12 | "@sinonjs/formatio@^3.2.1": 13 | version "3.2.2" 14 | resolved "https://registry.npmmirror.com/@sinonjs/formatio/-/formatio-3.2.2.tgz#771c60dfa75ea7f2d68e3b94c7e888a78781372c" 15 | integrity sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ== 16 | dependencies: 17 | "@sinonjs/commons" "^1" 18 | "@sinonjs/samsam" "^3.1.0" 19 | 20 | "@sinonjs/samsam@^3.1.0", "@sinonjs/samsam@^3.3.3": 21 | version "3.3.3" 22 | resolved "https://registry.npmmirror.com/@sinonjs/samsam/-/samsam-3.3.3.tgz#46682efd9967b259b81136b9f120fd54585feb4a" 23 | integrity sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ== 24 | dependencies: 25 | "@sinonjs/commons" "^1.3.0" 26 | array-from "^2.1.1" 27 | lodash "^4.17.15" 28 | 29 | "@sinonjs/text-encoding@^0.7.1": 30 | version "0.7.2" 31 | resolved "https://registry.npmmirror.com/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz#5981a8db18b56ba38ef0efb7d995b12aa7b51918" 32 | integrity sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ== 33 | 34 | ansi-colors@3.2.3: 35 | version "3.2.3" 36 | resolved "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" 37 | integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== 38 | 39 | ansi-regex@^3.0.0: 40 | version "3.0.1" 41 | resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" 42 | integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== 43 | 44 | ansi-regex@^4.1.0: 45 | version "4.1.1" 46 | resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" 47 | integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== 48 | 49 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: 50 | version "3.2.1" 51 | resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 52 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 53 | dependencies: 54 | color-convert "^1.9.0" 55 | 56 | argparse@^1.0.7: 57 | version "1.0.10" 58 | resolved "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 59 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 60 | dependencies: 61 | sprintf-js "~1.0.2" 62 | 63 | array-from@^2.1.1: 64 | version "2.1.1" 65 | resolved "https://registry.npmmirror.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195" 66 | integrity sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg== 67 | 68 | array.prototype.reduce@^1.0.5: 69 | version "1.0.5" 70 | resolved "https://registry.npmmirror.com/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz#6b20b0daa9d9734dd6bc7ea66b5bbce395471eac" 71 | integrity sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q== 72 | dependencies: 73 | call-bind "^1.0.2" 74 | define-properties "^1.1.4" 75 | es-abstract "^1.20.4" 76 | es-array-method-boxes-properly "^1.0.0" 77 | is-string "^1.0.7" 78 | 79 | assertion-error@^1.1.0: 80 | version "1.1.0" 81 | resolved "https://registry.npmmirror.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" 82 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== 83 | 84 | balanced-match@^1.0.0: 85 | version "1.0.2" 86 | resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 87 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 88 | 89 | brace-expansion@^1.1.7: 90 | version "1.1.11" 91 | resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 92 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 93 | dependencies: 94 | balanced-match "^1.0.0" 95 | concat-map "0.0.1" 96 | 97 | browser-stdout@1.3.1: 98 | version "1.3.1" 99 | resolved "https://registry.npmmirror.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 100 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 101 | 102 | call-bind@^1.0.0, call-bind@^1.0.2: 103 | version "1.0.2" 104 | resolved "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" 105 | integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== 106 | dependencies: 107 | function-bind "^1.1.1" 108 | get-intrinsic "^1.0.2" 109 | 110 | camelcase@^5.0.0: 111 | version "5.3.1" 112 | resolved "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 113 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 114 | 115 | chai@^4.2.0: 116 | version "4.3.7" 117 | resolved "https://registry.npmmirror.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51" 118 | integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== 119 | dependencies: 120 | assertion-error "^1.1.0" 121 | check-error "^1.0.2" 122 | deep-eql "^4.1.2" 123 | get-func-name "^2.0.0" 124 | loupe "^2.3.1" 125 | pathval "^1.1.1" 126 | type-detect "^4.0.5" 127 | 128 | chalk@^2.0.1: 129 | version "2.4.2" 130 | resolved "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 131 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 132 | dependencies: 133 | ansi-styles "^3.2.1" 134 | escape-string-regexp "^1.0.5" 135 | supports-color "^5.3.0" 136 | 137 | check-error@^1.0.2: 138 | version "1.0.2" 139 | resolved "https://registry.npmmirror.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 140 | integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== 141 | 142 | cliui@^5.0.0: 143 | version "5.0.0" 144 | resolved "https://registry.npmmirror.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" 145 | integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== 146 | dependencies: 147 | string-width "^3.1.0" 148 | strip-ansi "^5.2.0" 149 | wrap-ansi "^5.1.0" 150 | 151 | color-convert@^1.9.0: 152 | version "1.9.3" 153 | resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 154 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 155 | dependencies: 156 | color-name "1.1.3" 157 | 158 | color-name@1.1.3: 159 | version "1.1.3" 160 | resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 161 | integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== 162 | 163 | concat-map@0.0.1: 164 | version "0.0.1" 165 | resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 166 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 167 | 168 | debug@3.2.6: 169 | version "3.2.6" 170 | resolved "https://registry.npmmirror.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 171 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 172 | dependencies: 173 | ms "^2.1.1" 174 | 175 | decamelize@^1.2.0: 176 | version "1.2.0" 177 | resolved "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 178 | integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== 179 | 180 | deep-eql@^4.1.2: 181 | version "4.1.3" 182 | resolved "https://registry.npmmirror.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" 183 | integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== 184 | dependencies: 185 | type-detect "^4.0.0" 186 | 187 | define-properties@^1.1.2, define-properties@^1.1.3, define-properties@^1.1.4: 188 | version "1.1.4" 189 | resolved "https://registry.npmmirror.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" 190 | integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== 191 | dependencies: 192 | has-property-descriptors "^1.0.0" 193 | object-keys "^1.1.1" 194 | 195 | diff@3.5.0, diff@^3.5.0: 196 | version "3.5.0" 197 | resolved "https://registry.npmmirror.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 198 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== 199 | 200 | emoji-regex@^7.0.1: 201 | version "7.0.3" 202 | resolved "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 203 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 204 | 205 | es-abstract@^1.19.0, es-abstract@^1.20.4: 206 | version "1.20.5" 207 | resolved "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.20.5.tgz#e6dc99177be37cacda5988e692c3fa8b218e95d2" 208 | integrity sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ== 209 | dependencies: 210 | call-bind "^1.0.2" 211 | es-to-primitive "^1.2.1" 212 | function-bind "^1.1.1" 213 | function.prototype.name "^1.1.5" 214 | get-intrinsic "^1.1.3" 215 | get-symbol-description "^1.0.0" 216 | gopd "^1.0.1" 217 | has "^1.0.3" 218 | has-property-descriptors "^1.0.0" 219 | has-symbols "^1.0.3" 220 | internal-slot "^1.0.3" 221 | is-callable "^1.2.7" 222 | is-negative-zero "^2.0.2" 223 | is-regex "^1.1.4" 224 | is-shared-array-buffer "^1.0.2" 225 | is-string "^1.0.7" 226 | is-weakref "^1.0.2" 227 | object-inspect "^1.12.2" 228 | object-keys "^1.1.1" 229 | object.assign "^4.1.4" 230 | regexp.prototype.flags "^1.4.3" 231 | safe-regex-test "^1.0.0" 232 | string.prototype.trimend "^1.0.6" 233 | string.prototype.trimstart "^1.0.6" 234 | unbox-primitive "^1.0.2" 235 | 236 | es-array-method-boxes-properly@^1.0.0: 237 | version "1.0.0" 238 | resolved "https://registry.npmmirror.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" 239 | integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== 240 | 241 | es-to-primitive@^1.2.1: 242 | version "1.2.1" 243 | resolved "https://registry.npmmirror.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" 244 | integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== 245 | dependencies: 246 | is-callable "^1.1.4" 247 | is-date-object "^1.0.1" 248 | is-symbol "^1.0.2" 249 | 250 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: 251 | version "1.0.5" 252 | resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 253 | integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== 254 | 255 | esprima@^4.0.0: 256 | version "4.0.1" 257 | resolved "https://registry.npmmirror.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 258 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 259 | 260 | find-up@3.0.0, find-up@^3.0.0: 261 | version "3.0.0" 262 | resolved "https://registry.npmmirror.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" 263 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== 264 | dependencies: 265 | locate-path "^3.0.0" 266 | 267 | flat@^4.1.0: 268 | version "4.1.1" 269 | resolved "https://registry.npmmirror.com/flat/-/flat-4.1.1.tgz#a392059cc382881ff98642f5da4dde0a959f309b" 270 | integrity sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA== 271 | dependencies: 272 | is-buffer "~2.0.3" 273 | 274 | fs.realpath@^1.0.0: 275 | version "1.0.0" 276 | resolved "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 277 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 278 | 279 | function-bind@^1.1.1: 280 | version "1.1.1" 281 | resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 282 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 283 | 284 | function.prototype.name@^1.1.5: 285 | version "1.1.5" 286 | resolved "https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" 287 | integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== 288 | dependencies: 289 | call-bind "^1.0.2" 290 | define-properties "^1.1.3" 291 | es-abstract "^1.19.0" 292 | functions-have-names "^1.2.2" 293 | 294 | functions-have-names@^1.2.2: 295 | version "1.2.3" 296 | resolved "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" 297 | integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== 298 | 299 | get-caller-file@^2.0.1: 300 | version "2.0.5" 301 | resolved "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 302 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 303 | 304 | get-func-name@^2.0.0: 305 | version "2.0.0" 306 | resolved "https://registry.npmmirror.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 307 | integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== 308 | 309 | get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: 310 | version "1.1.3" 311 | resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" 312 | integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== 313 | dependencies: 314 | function-bind "^1.1.1" 315 | has "^1.0.3" 316 | has-symbols "^1.0.3" 317 | 318 | get-symbol-description@^1.0.0: 319 | version "1.0.0" 320 | resolved "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" 321 | integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== 322 | dependencies: 323 | call-bind "^1.0.2" 324 | get-intrinsic "^1.1.1" 325 | 326 | glob@7.1.3: 327 | version "7.1.3" 328 | resolved "https://registry.npmmirror.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" 329 | integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== 330 | dependencies: 331 | fs.realpath "^1.0.0" 332 | inflight "^1.0.4" 333 | inherits "2" 334 | minimatch "^3.0.4" 335 | once "^1.3.0" 336 | path-is-absolute "^1.0.0" 337 | 338 | gopd@^1.0.1: 339 | version "1.0.1" 340 | resolved "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" 341 | integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== 342 | dependencies: 343 | get-intrinsic "^1.1.3" 344 | 345 | growl@1.10.5: 346 | version "1.10.5" 347 | resolved "https://registry.npmmirror.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 348 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 349 | 350 | has-bigints@^1.0.1, has-bigints@^1.0.2: 351 | version "1.0.2" 352 | resolved "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" 353 | integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== 354 | 355 | has-flag@^3.0.0: 356 | version "3.0.0" 357 | resolved "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 358 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== 359 | 360 | has-property-descriptors@^1.0.0: 361 | version "1.0.0" 362 | resolved "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" 363 | integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== 364 | dependencies: 365 | get-intrinsic "^1.1.1" 366 | 367 | has-symbols@^1.0.0, has-symbols@^1.0.2, has-symbols@^1.0.3: 368 | version "1.0.3" 369 | resolved "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" 370 | integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== 371 | 372 | has-tostringtag@^1.0.0: 373 | version "1.0.0" 374 | resolved "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" 375 | integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== 376 | dependencies: 377 | has-symbols "^1.0.2" 378 | 379 | has@^1.0.3: 380 | version "1.0.3" 381 | resolved "https://registry.npmmirror.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 382 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 383 | dependencies: 384 | function-bind "^1.1.1" 385 | 386 | he@1.2.0: 387 | version "1.2.0" 388 | resolved "https://registry.npmmirror.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 389 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 390 | 391 | inflight@^1.0.4: 392 | version "1.0.6" 393 | resolved "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 394 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 395 | dependencies: 396 | once "^1.3.0" 397 | wrappy "1" 398 | 399 | inherits@2: 400 | version "2.0.4" 401 | resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 402 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 403 | 404 | internal-slot@^1.0.3: 405 | version "1.0.4" 406 | resolved "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.0.4.tgz#8551e7baf74a7a6ba5f749cfb16aa60722f0d6f3" 407 | integrity sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ== 408 | dependencies: 409 | get-intrinsic "^1.1.3" 410 | has "^1.0.3" 411 | side-channel "^1.0.4" 412 | 413 | is-bigint@^1.0.1: 414 | version "1.0.4" 415 | resolved "https://registry.npmmirror.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" 416 | integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== 417 | dependencies: 418 | has-bigints "^1.0.1" 419 | 420 | is-boolean-object@^1.1.0: 421 | version "1.1.2" 422 | resolved "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" 423 | integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== 424 | dependencies: 425 | call-bind "^1.0.2" 426 | has-tostringtag "^1.0.0" 427 | 428 | is-buffer@~2.0.3: 429 | version "2.0.5" 430 | resolved "https://registry.npmmirror.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" 431 | integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== 432 | 433 | is-callable@^1.1.4, is-callable@^1.2.7: 434 | version "1.2.7" 435 | resolved "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" 436 | integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== 437 | 438 | is-date-object@^1.0.1: 439 | version "1.0.5" 440 | resolved "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" 441 | integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== 442 | dependencies: 443 | has-tostringtag "^1.0.0" 444 | 445 | is-fullwidth-code-point@^2.0.0: 446 | version "2.0.0" 447 | resolved "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 448 | integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== 449 | 450 | is-negative-zero@^2.0.2: 451 | version "2.0.2" 452 | resolved "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" 453 | integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== 454 | 455 | is-number-object@^1.0.4: 456 | version "1.0.7" 457 | resolved "https://registry.npmmirror.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" 458 | integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== 459 | dependencies: 460 | has-tostringtag "^1.0.0" 461 | 462 | is-regex@^1.1.4: 463 | version "1.1.4" 464 | resolved "https://registry.npmmirror.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" 465 | integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== 466 | dependencies: 467 | call-bind "^1.0.2" 468 | has-tostringtag "^1.0.0" 469 | 470 | is-shared-array-buffer@^1.0.2: 471 | version "1.0.2" 472 | resolved "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" 473 | integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== 474 | dependencies: 475 | call-bind "^1.0.2" 476 | 477 | is-string@^1.0.5, is-string@^1.0.7: 478 | version "1.0.7" 479 | resolved "https://registry.npmmirror.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" 480 | integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== 481 | dependencies: 482 | has-tostringtag "^1.0.0" 483 | 484 | is-symbol@^1.0.2, is-symbol@^1.0.3: 485 | version "1.0.4" 486 | resolved "https://registry.npmmirror.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" 487 | integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== 488 | dependencies: 489 | has-symbols "^1.0.2" 490 | 491 | is-weakref@^1.0.2: 492 | version "1.0.2" 493 | resolved "https://registry.npmmirror.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" 494 | integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== 495 | dependencies: 496 | call-bind "^1.0.2" 497 | 498 | isarray@0.0.1: 499 | version "0.0.1" 500 | resolved "https://registry.npmmirror.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 501 | integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== 502 | 503 | isexe@^2.0.0: 504 | version "2.0.0" 505 | resolved "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 506 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 507 | 508 | js-yaml@3.13.1: 509 | version "3.13.1" 510 | resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 511 | integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== 512 | dependencies: 513 | argparse "^1.0.7" 514 | esprima "^4.0.0" 515 | 516 | just-extend@^4.0.2: 517 | version "4.2.1" 518 | resolved "https://registry.npmmirror.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" 519 | integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg== 520 | 521 | locate-path@^3.0.0: 522 | version "3.0.0" 523 | resolved "https://registry.npmmirror.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 524 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== 525 | dependencies: 526 | p-locate "^3.0.0" 527 | path-exists "^3.0.0" 528 | 529 | lodash@^4.17.15: 530 | version "4.17.21" 531 | resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 532 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 533 | 534 | log-symbols@2.2.0: 535 | version "2.2.0" 536 | resolved "https://registry.npmmirror.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" 537 | integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== 538 | dependencies: 539 | chalk "^2.0.1" 540 | 541 | lolex@^4.2.0: 542 | version "4.2.0" 543 | resolved "https://registry.npmmirror.com/lolex/-/lolex-4.2.0.tgz#ddbd7f6213ca1ea5826901ab1222b65d714b3cd7" 544 | integrity sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg== 545 | 546 | lolex@^5.0.1: 547 | version "5.1.2" 548 | resolved "https://registry.npmmirror.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" 549 | integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== 550 | dependencies: 551 | "@sinonjs/commons" "^1.7.0" 552 | 553 | loupe@^2.3.1: 554 | version "2.3.6" 555 | resolved "https://registry.npmmirror.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" 556 | integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== 557 | dependencies: 558 | get-func-name "^2.0.0" 559 | 560 | minimatch@3.0.4: 561 | version "3.0.4" 562 | resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 563 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 564 | dependencies: 565 | brace-expansion "^1.1.7" 566 | 567 | minimatch@^3.0.4: 568 | version "3.1.2" 569 | resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 570 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 571 | dependencies: 572 | brace-expansion "^1.1.7" 573 | 574 | minimist@^1.2.5: 575 | version "1.2.7" 576 | resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" 577 | integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== 578 | 579 | mkdirp@0.5.4: 580 | version "0.5.4" 581 | resolved "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" 582 | integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== 583 | dependencies: 584 | minimist "^1.2.5" 585 | 586 | mocha@^6.2.0: 587 | version "6.2.3" 588 | resolved "https://registry.npmmirror.com/mocha/-/mocha-6.2.3.tgz#e648432181d8b99393410212664450a4c1e31912" 589 | integrity sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg== 590 | dependencies: 591 | ansi-colors "3.2.3" 592 | browser-stdout "1.3.1" 593 | debug "3.2.6" 594 | diff "3.5.0" 595 | escape-string-regexp "1.0.5" 596 | find-up "3.0.0" 597 | glob "7.1.3" 598 | growl "1.10.5" 599 | he "1.2.0" 600 | js-yaml "3.13.1" 601 | log-symbols "2.2.0" 602 | minimatch "3.0.4" 603 | mkdirp "0.5.4" 604 | ms "2.1.1" 605 | node-environment-flags "1.0.5" 606 | object.assign "4.1.0" 607 | strip-json-comments "2.0.1" 608 | supports-color "6.0.0" 609 | which "1.3.1" 610 | wide-align "1.1.3" 611 | yargs "13.3.2" 612 | yargs-parser "13.1.2" 613 | yargs-unparser "1.6.0" 614 | 615 | ms@2.1.1: 616 | version "2.1.1" 617 | resolved "https://registry.npmmirror.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 618 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 619 | 620 | ms@^2.1.1: 621 | version "2.1.3" 622 | resolved "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 623 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 624 | 625 | nise@^1.5.2: 626 | version "1.5.3" 627 | resolved "https://registry.npmmirror.com/nise/-/nise-1.5.3.tgz#9d2cfe37d44f57317766c6e9408a359c5d3ac1f7" 628 | integrity sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ== 629 | dependencies: 630 | "@sinonjs/formatio" "^3.2.1" 631 | "@sinonjs/text-encoding" "^0.7.1" 632 | just-extend "^4.0.2" 633 | lolex "^5.0.1" 634 | path-to-regexp "^1.7.0" 635 | 636 | node-environment-flags@1.0.5: 637 | version "1.0.5" 638 | resolved "https://registry.npmmirror.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" 639 | integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== 640 | dependencies: 641 | object.getownpropertydescriptors "^2.0.3" 642 | semver "^5.7.0" 643 | 644 | object-inspect@^1.12.2, object-inspect@^1.9.0: 645 | version "1.12.2" 646 | resolved "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" 647 | integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== 648 | 649 | object-keys@^1.0.11, object-keys@^1.1.1: 650 | version "1.1.1" 651 | resolved "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 652 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 653 | 654 | object.assign@4.1.0: 655 | version "4.1.0" 656 | resolved "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" 657 | integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== 658 | dependencies: 659 | define-properties "^1.1.2" 660 | function-bind "^1.1.1" 661 | has-symbols "^1.0.0" 662 | object-keys "^1.0.11" 663 | 664 | object.assign@^4.1.4: 665 | version "4.1.4" 666 | resolved "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" 667 | integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== 668 | dependencies: 669 | call-bind "^1.0.2" 670 | define-properties "^1.1.4" 671 | has-symbols "^1.0.3" 672 | object-keys "^1.1.1" 673 | 674 | object.getownpropertydescriptors@^2.0.3: 675 | version "2.1.5" 676 | resolved "https://registry.npmmirror.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz#db5a9002489b64eef903df81d6623c07e5b4b4d3" 677 | integrity sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw== 678 | dependencies: 679 | array.prototype.reduce "^1.0.5" 680 | call-bind "^1.0.2" 681 | define-properties "^1.1.4" 682 | es-abstract "^1.20.4" 683 | 684 | once@^1.3.0: 685 | version "1.4.0" 686 | resolved "https://registry.npmmirror.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 687 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 688 | dependencies: 689 | wrappy "1" 690 | 691 | p-limit@^2.0.0: 692 | version "2.3.0" 693 | resolved "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" 694 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== 695 | dependencies: 696 | p-try "^2.0.0" 697 | 698 | p-locate@^3.0.0: 699 | version "3.0.0" 700 | resolved "https://registry.npmmirror.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 701 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== 702 | dependencies: 703 | p-limit "^2.0.0" 704 | 705 | p-try@^2.0.0: 706 | version "2.2.0" 707 | resolved "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 708 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 709 | 710 | path-exists@^3.0.0: 711 | version "3.0.0" 712 | resolved "https://registry.npmmirror.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 713 | integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== 714 | 715 | path-is-absolute@^1.0.0: 716 | version "1.0.1" 717 | resolved "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 718 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 719 | 720 | path-to-regexp@^1.7.0: 721 | version "1.8.0" 722 | resolved "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" 723 | integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== 724 | dependencies: 725 | isarray "0.0.1" 726 | 727 | pathval@^1.1.1: 728 | version "1.1.1" 729 | resolved "https://registry.npmmirror.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" 730 | integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== 731 | 732 | regexp.prototype.flags@^1.4.3: 733 | version "1.4.3" 734 | resolved "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" 735 | integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== 736 | dependencies: 737 | call-bind "^1.0.2" 738 | define-properties "^1.1.3" 739 | functions-have-names "^1.2.2" 740 | 741 | require-directory@^2.1.1: 742 | version "2.1.1" 743 | resolved "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 744 | integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== 745 | 746 | require-main-filename@^2.0.0: 747 | version "2.0.0" 748 | resolved "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" 749 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== 750 | 751 | safe-regex-test@^1.0.0: 752 | version "1.0.0" 753 | resolved "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" 754 | integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== 755 | dependencies: 756 | call-bind "^1.0.2" 757 | get-intrinsic "^1.1.3" 758 | is-regex "^1.1.4" 759 | 760 | semver@^5.7.0: 761 | version "5.7.1" 762 | resolved "https://registry.npmmirror.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 763 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 764 | 765 | set-blocking@^2.0.0: 766 | version "2.0.0" 767 | resolved "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 768 | integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== 769 | 770 | side-channel@^1.0.4: 771 | version "1.0.4" 772 | resolved "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" 773 | integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== 774 | dependencies: 775 | call-bind "^1.0.0" 776 | get-intrinsic "^1.0.2" 777 | object-inspect "^1.9.0" 778 | 779 | sinon-chai@^3.3.0: 780 | version "3.7.0" 781 | resolved "https://registry.npmmirror.com/sinon-chai/-/sinon-chai-3.7.0.tgz#cfb7dec1c50990ed18c153f1840721cf13139783" 782 | integrity sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g== 783 | 784 | sinon@^7.4.1: 785 | version "7.5.0" 786 | resolved "https://registry.npmmirror.com/sinon/-/sinon-7.5.0.tgz#e9488ea466070ea908fd44a3d6478fd4923c67ec" 787 | integrity sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q== 788 | dependencies: 789 | "@sinonjs/commons" "^1.4.0" 790 | "@sinonjs/formatio" "^3.2.1" 791 | "@sinonjs/samsam" "^3.3.3" 792 | diff "^3.5.0" 793 | lolex "^4.2.0" 794 | nise "^1.5.2" 795 | supports-color "^5.5.0" 796 | 797 | sprintf-js@~1.0.2: 798 | version "1.0.3" 799 | resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 800 | integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== 801 | 802 | "string-width@^1.0.2 || 2": 803 | version "2.1.1" 804 | resolved "https://registry.npmmirror.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 805 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 806 | dependencies: 807 | is-fullwidth-code-point "^2.0.0" 808 | strip-ansi "^4.0.0" 809 | 810 | string-width@^3.0.0, string-width@^3.1.0: 811 | version "3.1.0" 812 | resolved "https://registry.npmmirror.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 813 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 814 | dependencies: 815 | emoji-regex "^7.0.1" 816 | is-fullwidth-code-point "^2.0.0" 817 | strip-ansi "^5.1.0" 818 | 819 | string.prototype.trimend@^1.0.6: 820 | version "1.0.6" 821 | resolved "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" 822 | integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== 823 | dependencies: 824 | call-bind "^1.0.2" 825 | define-properties "^1.1.4" 826 | es-abstract "^1.20.4" 827 | 828 | string.prototype.trimstart@^1.0.6: 829 | version "1.0.6" 830 | resolved "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" 831 | integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== 832 | dependencies: 833 | call-bind "^1.0.2" 834 | define-properties "^1.1.4" 835 | es-abstract "^1.20.4" 836 | 837 | strip-ansi@^4.0.0: 838 | version "4.0.0" 839 | resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 840 | integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== 841 | dependencies: 842 | ansi-regex "^3.0.0" 843 | 844 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: 845 | version "5.2.0" 846 | resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 847 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 848 | dependencies: 849 | ansi-regex "^4.1.0" 850 | 851 | strip-json-comments@2.0.1: 852 | version "2.0.1" 853 | resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 854 | integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== 855 | 856 | supports-color@6.0.0: 857 | version "6.0.0" 858 | resolved "https://registry.npmmirror.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" 859 | integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== 860 | dependencies: 861 | has-flag "^3.0.0" 862 | 863 | supports-color@^5.3.0, supports-color@^5.5.0: 864 | version "5.5.0" 865 | resolved "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 866 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 867 | dependencies: 868 | has-flag "^3.0.0" 869 | 870 | type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5: 871 | version "4.0.8" 872 | resolved "https://registry.npmmirror.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 873 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 874 | 875 | unbox-primitive@^1.0.2: 876 | version "1.0.2" 877 | resolved "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" 878 | integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== 879 | dependencies: 880 | call-bind "^1.0.2" 881 | has-bigints "^1.0.2" 882 | has-symbols "^1.0.3" 883 | which-boxed-primitive "^1.0.2" 884 | 885 | which-boxed-primitive@^1.0.2: 886 | version "1.0.2" 887 | resolved "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" 888 | integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== 889 | dependencies: 890 | is-bigint "^1.0.1" 891 | is-boolean-object "^1.1.0" 892 | is-number-object "^1.0.4" 893 | is-string "^1.0.5" 894 | is-symbol "^1.0.3" 895 | 896 | which-module@^2.0.0: 897 | version "2.0.0" 898 | resolved "https://registry.npmmirror.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" 899 | integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== 900 | 901 | which@1.3.1: 902 | version "1.3.1" 903 | resolved "https://registry.npmmirror.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 904 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 905 | dependencies: 906 | isexe "^2.0.0" 907 | 908 | wide-align@1.1.3: 909 | version "1.1.3" 910 | resolved "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 911 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 912 | dependencies: 913 | string-width "^1.0.2 || 2" 914 | 915 | wrap-ansi@^5.1.0: 916 | version "5.1.0" 917 | resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" 918 | integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== 919 | dependencies: 920 | ansi-styles "^3.2.0" 921 | string-width "^3.0.0" 922 | strip-ansi "^5.0.0" 923 | 924 | wrappy@1: 925 | version "1.0.2" 926 | resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 927 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 928 | 929 | y18n@^4.0.0: 930 | version "4.0.3" 931 | resolved "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" 932 | integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== 933 | 934 | yargs-parser@13.1.2, yargs-parser@^13.1.2: 935 | version "13.1.2" 936 | resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" 937 | integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== 938 | dependencies: 939 | camelcase "^5.0.0" 940 | decamelize "^1.2.0" 941 | 942 | yargs-unparser@1.6.0: 943 | version "1.6.0" 944 | resolved "https://registry.npmmirror.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" 945 | integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== 946 | dependencies: 947 | flat "^4.1.0" 948 | lodash "^4.17.15" 949 | yargs "^13.3.0" 950 | 951 | yargs@13.3.2, yargs@^13.3.0: 952 | version "13.3.2" 953 | resolved "https://registry.npmmirror.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" 954 | integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== 955 | dependencies: 956 | cliui "^5.0.0" 957 | find-up "^3.0.0" 958 | get-caller-file "^2.0.1" 959 | require-directory "^2.1.1" 960 | require-main-filename "^2.0.0" 961 | set-blocking "^2.0.0" 962 | string-width "^3.0.0" 963 | which-module "^2.0.0" 964 | y18n "^4.0.0" 965 | yargs-parser "^13.1.2" 966 | -------------------------------------------------------------------------------- /003_MethodChaining/index.js: -------------------------------------------------------------------------------- 1 | // 分享几个编程技巧:for of、reduce、链式编程 2 | 3 | // 需求 4 | // 输入 ['avatar.jpg ', '.gitignore', ' ', 'index.js'] 5 | // 输出 ['~/app/avatar.jpg', '~/app/.gitignore', '~/app/index.js'] 6 | 7 | const files = ['avatar.jpg ', '.gitignore', ' ', 'index.js'] 8 | 9 | // 1. 使用 for of 10 | const forLoops = files => { 11 | const result = [] 12 | for (const file of files) { 13 | const fileName = file.trim() 14 | if (fileName) { 15 | const filePath = `~/app/${fileName}` 16 | result.push(filePath) 17 | } 18 | } 19 | return result 20 | } 21 | 22 | console.log(forLoops(files)) 23 | 24 | // 2. 使用 reduce 25 | const reduceWay = files => { 26 | return (files.reduce((result, file) => { 27 | const fileName = file.trim() 28 | if (fileName) { 29 | const filePath = `~/app/${fileName}` 30 | result.push(filePath) 31 | } 32 | return result 33 | }, [])) 34 | } 35 | 36 | console.log(reduceWay(files)) 37 | 38 | // 3. 使用链式编程 39 | const chain = files => ( 40 | files 41 | .map(file => file.trim()) 42 | .filter(Boolean) 43 | .map(fileName => `~/app/${fileName}`) 44 | ) 45 | 46 | console.log(chain(files)) 47 | -------------------------------------------------------------------------------- /004_Bind/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heycn/code-more/73e066b22d3dbb455bf59447f205f8e03aa3ed07/004_Bind/.keep -------------------------------------------------------------------------------- /004_Bind/README.md: -------------------------------------------------------------------------------- 1 | # 来!和我一起手写 `bin` 2 | 3 | ## 确定 API 4 | 5 | 特殊性 6 | 7 | - `bind` 位于 `Function.prototype` 上 8 | - 需要做 `polyfill` 9 | 10 | API 11 | 12 | - `fn.bind(asThis)` 13 | - `fn.bind(asThis, param1, param2)` 14 | - `fn.bind(asThis)()` 15 | - `fn.bind(asThis, param1, param2)()` 16 | - `fn.bind(asThis)(param1)` 17 | - `fn.bind(asThis, param1, param2)(p3, p4)` 18 | 19 | ## 步骤 20 | 21 | commit 记录 22 | 23 | - [初始化](https://github.com/heycn/code-more/commit/3aad1346105bc401647e6b09bd6eb7716a96745a) 24 | - [支持 this](https://github.com/heycn/code-more/commit/de0b71a130608a4d8539264387707b6d80dd8ed8) 25 | - [支持接受参数](https://github.com/heycn/code-more/commit/367c728a7f0147ad239478fa33bbf77013c0f6d7) 26 | - [支持 bind 之后还可以接受参数](https://github.com/heycn/code-more/commit/c20e67b61fe34d2c919991fb4ffd14a4d3185a64) 27 | - [把 const 改为 var,连 bind 都不支持,怎么可能支持 const?](https://github.com/heycn/code-more/commit/2415692e249181cdbd3f3ca351f5a7bac0d35211) 28 | - [加一句错误提示](https://github.com/heycn/code-more/commit/b698794c19e54b207a764a62631c2d6831a9bd4b) 29 | - [不用 ...操作符,使用 slice 代替处理](https://github.com/heycn/code-more/commit/39326cc3c5b845421344b5c0e57664a8bf240f19) 30 | - [整理测试用例](https://github.com/heycn/code-more/commit/d324559a0164ee8826e2f1b1fde7f60815e2c43d) 31 | - [支持 new 的时候,绑定了 p1, p2](https://github.com/heycn/code-more/commit/acba6facae5df1653f529808fb3e52e1002c101a) 32 | - [支持 new 的时候,绑定了 p1, p2, 并且 fn 有 prototype](https://github.com/heycn/code-more/commit/30df9f7501d1b131ee842772bf974b3c94ebfe28) 33 | -------------------------------------------------------------------------------- /004_Bind/src/index.js: -------------------------------------------------------------------------------- 1 | var slice = Array.prototype.slice 2 | function bind(asThis) { 3 | // this 就是函数 4 | var args = slice.call(arguments, 1) 5 | var fn = this 6 | if (typeof fn !== "function") { 7 | throw new Error("bind 必须调用在函数身上") 8 | } 9 | function resultFn() { 10 | var args2 = slice.call(arguments, 0) 11 | return fn.apply( 12 | resultFn.prototype.isPrototypeOf(this) ? this : asThis, 13 | args.concat(args2) 14 | ) 15 | } 16 | resultFn.prototype = fn.prototype 17 | return resultFn 18 | } 19 | 20 | function _bind(asThis, ...args) { 21 | // this 就是函数 22 | var fn = this; 23 | function resultFn(...args2) { 24 | // resultFn.prototype.isPrototypeOf(this); 25 | return fn.call(this instanceof resultFn ? this : asThis, ...args, ...args2); 26 | } 27 | resultFn.prototype = fn.prototype; 28 | return resultFn; 29 | } 30 | 31 | module.exports = bind 32 | 33 | if (!Function.prototype.bind) { 34 | Function.prototype.bind = bind 35 | } 36 | -------------------------------------------------------------------------------- /004_Bind/test/index.js: -------------------------------------------------------------------------------- 1 | const bind = require('../src/index.js') 2 | 3 | test1('fn.bind 能用') 4 | test2('this.bind 能用') 5 | test3('this, p1, p2 能用') 6 | test4('this, p1 绑定成功后传 p2 成功') 7 | test5('new 的时候,绑定了 p1, p2') 8 | test6('new 的时候,绑定了 p1, p2, 并且 fn 有 prototype') 9 | test7('不用 new 但是用类似的对象') 10 | 11 | function test1(message) { 12 | Function.prototype.bind2 = bind 13 | console.assert(Function.prototype.bind2 !== undefined) 14 | console.log(message) 15 | } 16 | 17 | function test2(message) { 18 | Function.prototype.bind2 = bind 19 | const fn1 = function () { 20 | return this 21 | } 22 | const newFn1 = fn1.bind2({ name: 'Jack' }) 23 | console.assert(newFn1().name === 'Jack') 24 | console.log(message) 25 | } 26 | 27 | function test3(message) { 28 | Function.prototype.bind2 = bind 29 | const fn2 = function (p1, p2) { 30 | return [this, p1, p2] 31 | } 32 | const newFn2 = fn2.bind({ name: 'Jack' }, 123, 456) 33 | console.assert(newFn2()[0].name === 'Jack') 34 | console.assert(newFn2()[1] === 123) 35 | console.assert(newFn2()[2] === 456) 36 | console.log(message) 37 | } 38 | 39 | function test4(message) { 40 | Function.prototype.bind2 = bind 41 | const fn2 = function (p1, p2) { 42 | return [this, p1, p2] 43 | } 44 | const anotherFn2 = fn2.bind({ name: 'Jack' }, 123) 45 | console.assert(anotherFn2(456)[0].name === 'Jack') 46 | console.assert(anotherFn2(456)[1] === 123) 47 | console.assert(anotherFn2(456)[2] === 456) 48 | console.log(message) 49 | } 50 | 51 | function test5(message) { 52 | Function.prototype.bind2 = bind 53 | const fn = function (p1, p2) { 54 | this.p1 = p1 55 | this.p2 = p2 56 | } 57 | const fn2 = fn.bind2(undefined, 'x', 'y') 58 | const object = new fn2() 59 | console.assert(object.p1 === 'x', 'x') 60 | console.assert(object.p2 === 'y', 'y') 61 | console.log(message) 62 | } 63 | 64 | function test6(message) { 65 | Function.prototype.bind2 = bind 66 | const fn = function (p1, p2) { 67 | this.p1 = p1 68 | this.p2 = p2 69 | } 70 | fn.prototype.sayHi = function () { } 71 | const fn2 = fn.bind2(undefined, 'x', 'y') 72 | const object = new fn2() 73 | console.assert(object.p1 === 'x', 'x') 74 | console.assert(object.p2 === 'y', 'y') 75 | console.assert(object.__proto__ === fn.prototype) 76 | console.assert(typeof object.sayHi === 'function') 77 | console.log(message) 78 | } 79 | 80 | function test7(message) { 81 | Function.prototype.bind2 = bind; 82 | const fn = function (p1, p2) { 83 | this.p1 = p1; 84 | this.p2 = p2; 85 | }; 86 | fn.prototype.sayHi = function () { }; 87 | const object1 = new fn("a", "b"); 88 | const fn2 = fn.bind2(object1, "x", "y"); 89 | const object = fn2(); // 没有new 90 | console.assert(object === undefined, "object 为空"); 91 | console.assert(object1.p1 === "x", "x"); 92 | console.assert(object1.p2 === "y", "y"); 93 | console.log(message) 94 | } 95 | -------------------------------------------------------------------------------- /005_Promise/README.md: -------------------------------------------------------------------------------- 1 | # 手写 Promise 2 | 3 | 根据 [Promises/A+ 规范](https://promisesaplus.com/) `TDD` 手写 `Promise` 4 | 5 | ## 测试 6 | 7 | ```bash 8 | pnpm i 9 | pnpm test 10 | ``` 11 | -------------------------------------------------------------------------------- /005_Promise/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "005_Promise", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "mocha --require ts-node/register test/**/*.ts" 8 | }, 9 | "devDependencies": { 10 | "@types/chai": "4.3.5", 11 | "@types/mocha": "10.0.1", 12 | "@types/node": "20.1.4", 13 | "@types/sinon": "10.0.14", 14 | "@types/sinon-chai": "3.2.9", 15 | "chai": "4.3.7", 16 | "mocha": "10.2.0", 17 | "ts-node": "10.9.1", 18 | "typescript": "5.0.4", 19 | "sinon": "15.0.4", 20 | "sinon-chai": "3.7.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /005_Promise/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | devDependencies: 4 | '@types/chai': 5 | specifier: 4.3.5 6 | version: 4.3.5 7 | '@types/mocha': 8 | specifier: 10.0.1 9 | version: 10.0.1 10 | '@types/node': 11 | specifier: 20.1.4 12 | version: 20.1.4 13 | '@types/sinon': 14 | specifier: 10.0.14 15 | version: 10.0.14 16 | '@types/sinon-chai': 17 | specifier: 3.2.9 18 | version: 3.2.9 19 | chai: 20 | specifier: 4.3.7 21 | version: 4.3.7 22 | mocha: 23 | specifier: 10.2.0 24 | version: 10.2.0 25 | sinon: 26 | specifier: 15.0.4 27 | version: 15.0.4 28 | sinon-chai: 29 | specifier: 3.7.0 30 | version: 3.7.0(chai@4.3.7)(sinon@15.0.4) 31 | ts-node: 32 | specifier: 10.9.1 33 | version: 10.9.1(@types/node@20.1.4)(typescript@5.0.4) 34 | typescript: 35 | specifier: 5.0.4 36 | version: 5.0.4 37 | 38 | packages: 39 | 40 | /@cspotcode/source-map-support@0.8.1: 41 | resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} 42 | engines: {node: '>=12'} 43 | dependencies: 44 | '@jridgewell/trace-mapping': 0.3.9 45 | dev: true 46 | 47 | /@jridgewell/resolve-uri@3.1.1: 48 | resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} 49 | engines: {node: '>=6.0.0'} 50 | dev: true 51 | 52 | /@jridgewell/sourcemap-codec@1.4.15: 53 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 54 | dev: true 55 | 56 | /@jridgewell/trace-mapping@0.3.9: 57 | resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} 58 | dependencies: 59 | '@jridgewell/resolve-uri': 3.1.1 60 | '@jridgewell/sourcemap-codec': 1.4.15 61 | dev: true 62 | 63 | /@sinonjs/commons@2.0.0: 64 | resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} 65 | dependencies: 66 | type-detect: 4.0.8 67 | dev: true 68 | 69 | /@sinonjs/commons@3.0.0: 70 | resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==} 71 | dependencies: 72 | type-detect: 4.0.8 73 | dev: true 74 | 75 | /@sinonjs/fake-timers@10.1.0: 76 | resolution: {integrity: sha512-w1qd368vtrwttm1PRJWPW1QHlbmHrVDGs1eBH/jZvRPUFS4MNXV9Q33EQdjOdeAxZ7O8+3wM7zxztm2nfUSyKw==} 77 | dependencies: 78 | '@sinonjs/commons': 3.0.0 79 | dev: true 80 | 81 | /@sinonjs/samsam@8.0.0: 82 | resolution: {integrity: sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==} 83 | dependencies: 84 | '@sinonjs/commons': 2.0.0 85 | lodash.get: 4.4.2 86 | type-detect: 4.0.8 87 | dev: true 88 | 89 | /@sinonjs/text-encoding@0.7.2: 90 | resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==} 91 | dev: true 92 | 93 | /@tsconfig/node10@1.0.9: 94 | resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} 95 | dev: true 96 | 97 | /@tsconfig/node12@1.0.11: 98 | resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} 99 | dev: true 100 | 101 | /@tsconfig/node14@1.0.3: 102 | resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} 103 | dev: true 104 | 105 | /@tsconfig/node16@1.0.4: 106 | resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} 107 | dev: true 108 | 109 | /@types/chai@4.3.5: 110 | resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==} 111 | dev: true 112 | 113 | /@types/mocha@10.0.1: 114 | resolution: {integrity: sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==} 115 | dev: true 116 | 117 | /@types/node@20.1.4: 118 | resolution: {integrity: sha512-At4pvmIOki8yuwLtd7BNHl3CiWNbtclUbNtScGx4OHfBd4/oWoJC8KRCIxXwkdndzhxOsPXihrsOoydxBjlE9Q==} 119 | dev: true 120 | 121 | /@types/sinon-chai@3.2.9: 122 | resolution: {integrity: sha512-/19t63pFYU0ikrdbXKBWj9PCdnKyTd0Qkz0X91Ta081cYsq90OxYdcWwK/dwEoDa6dtXgj2HJfmzgq+QZTHdmQ==} 123 | dependencies: 124 | '@types/chai': 4.3.5 125 | '@types/sinon': 10.0.14 126 | dev: true 127 | 128 | /@types/sinon@10.0.14: 129 | resolution: {integrity: sha512-mn72up6cjaMyMuaPaa/AwKf6WtsSRysQC7wxFkCm1XcOKXPM1z+5Y4H5wjIVBz4gdAkjvZxVVfjA6ba1nHr5WQ==} 130 | dependencies: 131 | '@types/sinonjs__fake-timers': 8.1.2 132 | dev: true 133 | 134 | /@types/sinonjs__fake-timers@8.1.2: 135 | resolution: {integrity: sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==} 136 | dev: true 137 | 138 | /acorn-walk@8.2.0: 139 | resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} 140 | engines: {node: '>=0.4.0'} 141 | dev: true 142 | 143 | /acorn@8.8.2: 144 | resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} 145 | engines: {node: '>=0.4.0'} 146 | hasBin: true 147 | dev: true 148 | 149 | /ansi-colors@4.1.1: 150 | resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} 151 | engines: {node: '>=6'} 152 | dev: true 153 | 154 | /ansi-regex@5.0.1: 155 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 156 | engines: {node: '>=8'} 157 | dev: true 158 | 159 | /ansi-styles@4.3.0: 160 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 161 | engines: {node: '>=8'} 162 | dependencies: 163 | color-convert: 2.0.1 164 | dev: true 165 | 166 | /anymatch@3.1.3: 167 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 168 | engines: {node: '>= 8'} 169 | dependencies: 170 | normalize-path: 3.0.0 171 | picomatch: 2.3.1 172 | dev: true 173 | 174 | /arg@4.1.3: 175 | resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} 176 | dev: true 177 | 178 | /argparse@2.0.1: 179 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 180 | dev: true 181 | 182 | /assertion-error@1.1.0: 183 | resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} 184 | dev: true 185 | 186 | /balanced-match@1.0.2: 187 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 188 | dev: true 189 | 190 | /binary-extensions@2.2.0: 191 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 192 | engines: {node: '>=8'} 193 | dev: true 194 | 195 | /brace-expansion@1.1.11: 196 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 197 | dependencies: 198 | balanced-match: 1.0.2 199 | concat-map: 0.0.1 200 | dev: true 201 | 202 | /brace-expansion@2.0.1: 203 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 204 | dependencies: 205 | balanced-match: 1.0.2 206 | dev: true 207 | 208 | /braces@3.0.2: 209 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 210 | engines: {node: '>=8'} 211 | dependencies: 212 | fill-range: 7.0.1 213 | dev: true 214 | 215 | /browser-stdout@1.3.1: 216 | resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} 217 | dev: true 218 | 219 | /camelcase@6.3.0: 220 | resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} 221 | engines: {node: '>=10'} 222 | dev: true 223 | 224 | /chai@4.3.7: 225 | resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} 226 | engines: {node: '>=4'} 227 | dependencies: 228 | assertion-error: 1.1.0 229 | check-error: 1.0.2 230 | deep-eql: 4.1.3 231 | get-func-name: 2.0.0 232 | loupe: 2.3.6 233 | pathval: 1.1.1 234 | type-detect: 4.0.8 235 | dev: true 236 | 237 | /chalk@4.1.2: 238 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 239 | engines: {node: '>=10'} 240 | dependencies: 241 | ansi-styles: 4.3.0 242 | supports-color: 7.2.0 243 | dev: true 244 | 245 | /check-error@1.0.2: 246 | resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} 247 | dev: true 248 | 249 | /chokidar@3.5.3: 250 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} 251 | engines: {node: '>= 8.10.0'} 252 | dependencies: 253 | anymatch: 3.1.3 254 | braces: 3.0.2 255 | glob-parent: 5.1.2 256 | is-binary-path: 2.1.0 257 | is-glob: 4.0.3 258 | normalize-path: 3.0.0 259 | readdirp: 3.6.0 260 | optionalDependencies: 261 | fsevents: 2.3.2 262 | dev: true 263 | 264 | /cliui@7.0.4: 265 | resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} 266 | dependencies: 267 | string-width: 4.2.3 268 | strip-ansi: 6.0.1 269 | wrap-ansi: 7.0.0 270 | dev: true 271 | 272 | /color-convert@2.0.1: 273 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 274 | engines: {node: '>=7.0.0'} 275 | dependencies: 276 | color-name: 1.1.4 277 | dev: true 278 | 279 | /color-name@1.1.4: 280 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 281 | dev: true 282 | 283 | /concat-map@0.0.1: 284 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 285 | dev: true 286 | 287 | /create-require@1.1.1: 288 | resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} 289 | dev: true 290 | 291 | /debug@4.3.4(supports-color@8.1.1): 292 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 293 | engines: {node: '>=6.0'} 294 | peerDependencies: 295 | supports-color: '*' 296 | peerDependenciesMeta: 297 | supports-color: 298 | optional: true 299 | dependencies: 300 | ms: 2.1.2 301 | supports-color: 8.1.1 302 | dev: true 303 | 304 | /decamelize@4.0.0: 305 | resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} 306 | engines: {node: '>=10'} 307 | dev: true 308 | 309 | /deep-eql@4.1.3: 310 | resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} 311 | engines: {node: '>=6'} 312 | dependencies: 313 | type-detect: 4.0.8 314 | dev: true 315 | 316 | /diff@4.0.2: 317 | resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} 318 | engines: {node: '>=0.3.1'} 319 | dev: true 320 | 321 | /diff@5.0.0: 322 | resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} 323 | engines: {node: '>=0.3.1'} 324 | dev: true 325 | 326 | /diff@5.1.0: 327 | resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} 328 | engines: {node: '>=0.3.1'} 329 | dev: true 330 | 331 | /emoji-regex@8.0.0: 332 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 333 | dev: true 334 | 335 | /escalade@3.1.1: 336 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} 337 | engines: {node: '>=6'} 338 | dev: true 339 | 340 | /escape-string-regexp@4.0.0: 341 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 342 | engines: {node: '>=10'} 343 | dev: true 344 | 345 | /fill-range@7.0.1: 346 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 347 | engines: {node: '>=8'} 348 | dependencies: 349 | to-regex-range: 5.0.1 350 | dev: true 351 | 352 | /find-up@5.0.0: 353 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 354 | engines: {node: '>=10'} 355 | dependencies: 356 | locate-path: 6.0.0 357 | path-exists: 4.0.0 358 | dev: true 359 | 360 | /flat@5.0.2: 361 | resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} 362 | hasBin: true 363 | dev: true 364 | 365 | /fs.realpath@1.0.0: 366 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 367 | dev: true 368 | 369 | /fsevents@2.3.2: 370 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 371 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 372 | os: [darwin] 373 | requiresBuild: true 374 | dev: true 375 | optional: true 376 | 377 | /get-caller-file@2.0.5: 378 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 379 | engines: {node: 6.* || 8.* || >= 10.*} 380 | dev: true 381 | 382 | /get-func-name@2.0.0: 383 | resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} 384 | dev: true 385 | 386 | /glob-parent@5.1.2: 387 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 388 | engines: {node: '>= 6'} 389 | dependencies: 390 | is-glob: 4.0.3 391 | dev: true 392 | 393 | /glob@7.2.0: 394 | resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} 395 | dependencies: 396 | fs.realpath: 1.0.0 397 | inflight: 1.0.6 398 | inherits: 2.0.4 399 | minimatch: 3.1.2 400 | once: 1.4.0 401 | path-is-absolute: 1.0.1 402 | dev: true 403 | 404 | /has-flag@4.0.0: 405 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 406 | engines: {node: '>=8'} 407 | dev: true 408 | 409 | /he@1.2.0: 410 | resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} 411 | hasBin: true 412 | dev: true 413 | 414 | /inflight@1.0.6: 415 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 416 | dependencies: 417 | once: 1.4.0 418 | wrappy: 1.0.2 419 | dev: true 420 | 421 | /inherits@2.0.4: 422 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 423 | dev: true 424 | 425 | /is-binary-path@2.1.0: 426 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 427 | engines: {node: '>=8'} 428 | dependencies: 429 | binary-extensions: 2.2.0 430 | dev: true 431 | 432 | /is-extglob@2.1.1: 433 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 434 | engines: {node: '>=0.10.0'} 435 | dev: true 436 | 437 | /is-fullwidth-code-point@3.0.0: 438 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 439 | engines: {node: '>=8'} 440 | dev: true 441 | 442 | /is-glob@4.0.3: 443 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 444 | engines: {node: '>=0.10.0'} 445 | dependencies: 446 | is-extglob: 2.1.1 447 | dev: true 448 | 449 | /is-number@7.0.0: 450 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 451 | engines: {node: '>=0.12.0'} 452 | dev: true 453 | 454 | /is-plain-obj@2.1.0: 455 | resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} 456 | engines: {node: '>=8'} 457 | dev: true 458 | 459 | /is-unicode-supported@0.1.0: 460 | resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} 461 | engines: {node: '>=10'} 462 | dev: true 463 | 464 | /isarray@0.0.1: 465 | resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} 466 | dev: true 467 | 468 | /js-yaml@4.1.0: 469 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 470 | hasBin: true 471 | dependencies: 472 | argparse: 2.0.1 473 | dev: true 474 | 475 | /just-extend@4.2.1: 476 | resolution: {integrity: sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==} 477 | dev: true 478 | 479 | /locate-path@6.0.0: 480 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 481 | engines: {node: '>=10'} 482 | dependencies: 483 | p-locate: 5.0.0 484 | dev: true 485 | 486 | /lodash.get@4.4.2: 487 | resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} 488 | dev: true 489 | 490 | /log-symbols@4.1.0: 491 | resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} 492 | engines: {node: '>=10'} 493 | dependencies: 494 | chalk: 4.1.2 495 | is-unicode-supported: 0.1.0 496 | dev: true 497 | 498 | /loupe@2.3.6: 499 | resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} 500 | dependencies: 501 | get-func-name: 2.0.0 502 | dev: true 503 | 504 | /make-error@1.3.6: 505 | resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} 506 | dev: true 507 | 508 | /minimatch@3.1.2: 509 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 510 | dependencies: 511 | brace-expansion: 1.1.11 512 | dev: true 513 | 514 | /minimatch@5.0.1: 515 | resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} 516 | engines: {node: '>=10'} 517 | dependencies: 518 | brace-expansion: 2.0.1 519 | dev: true 520 | 521 | /mocha@10.2.0: 522 | resolution: {integrity: sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==} 523 | engines: {node: '>= 14.0.0'} 524 | hasBin: true 525 | dependencies: 526 | ansi-colors: 4.1.1 527 | browser-stdout: 1.3.1 528 | chokidar: 3.5.3 529 | debug: 4.3.4(supports-color@8.1.1) 530 | diff: 5.0.0 531 | escape-string-regexp: 4.0.0 532 | find-up: 5.0.0 533 | glob: 7.2.0 534 | he: 1.2.0 535 | js-yaml: 4.1.0 536 | log-symbols: 4.1.0 537 | minimatch: 5.0.1 538 | ms: 2.1.3 539 | nanoid: 3.3.3 540 | serialize-javascript: 6.0.0 541 | strip-json-comments: 3.1.1 542 | supports-color: 8.1.1 543 | workerpool: 6.2.1 544 | yargs: 16.2.0 545 | yargs-parser: 20.2.4 546 | yargs-unparser: 2.0.0 547 | dev: true 548 | 549 | /ms@2.1.2: 550 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 551 | dev: true 552 | 553 | /ms@2.1.3: 554 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 555 | dev: true 556 | 557 | /nanoid@3.3.3: 558 | resolution: {integrity: sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==} 559 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 560 | hasBin: true 561 | dev: true 562 | 563 | /nise@5.1.4: 564 | resolution: {integrity: sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==} 565 | dependencies: 566 | '@sinonjs/commons': 2.0.0 567 | '@sinonjs/fake-timers': 10.1.0 568 | '@sinonjs/text-encoding': 0.7.2 569 | just-extend: 4.2.1 570 | path-to-regexp: 1.8.0 571 | dev: true 572 | 573 | /normalize-path@3.0.0: 574 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 575 | engines: {node: '>=0.10.0'} 576 | dev: true 577 | 578 | /once@1.4.0: 579 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 580 | dependencies: 581 | wrappy: 1.0.2 582 | dev: true 583 | 584 | /p-limit@3.1.0: 585 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 586 | engines: {node: '>=10'} 587 | dependencies: 588 | yocto-queue: 0.1.0 589 | dev: true 590 | 591 | /p-locate@5.0.0: 592 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 593 | engines: {node: '>=10'} 594 | dependencies: 595 | p-limit: 3.1.0 596 | dev: true 597 | 598 | /path-exists@4.0.0: 599 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 600 | engines: {node: '>=8'} 601 | dev: true 602 | 603 | /path-is-absolute@1.0.1: 604 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 605 | engines: {node: '>=0.10.0'} 606 | dev: true 607 | 608 | /path-to-regexp@1.8.0: 609 | resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==} 610 | dependencies: 611 | isarray: 0.0.1 612 | dev: true 613 | 614 | /pathval@1.1.1: 615 | resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} 616 | dev: true 617 | 618 | /picomatch@2.3.1: 619 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 620 | engines: {node: '>=8.6'} 621 | dev: true 622 | 623 | /randombytes@2.1.0: 624 | resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} 625 | dependencies: 626 | safe-buffer: 5.2.1 627 | dev: true 628 | 629 | /readdirp@3.6.0: 630 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 631 | engines: {node: '>=8.10.0'} 632 | dependencies: 633 | picomatch: 2.3.1 634 | dev: true 635 | 636 | /require-directory@2.1.1: 637 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 638 | engines: {node: '>=0.10.0'} 639 | dev: true 640 | 641 | /safe-buffer@5.2.1: 642 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 643 | dev: true 644 | 645 | /serialize-javascript@6.0.0: 646 | resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} 647 | dependencies: 648 | randombytes: 2.1.0 649 | dev: true 650 | 651 | /sinon-chai@3.7.0(chai@4.3.7)(sinon@15.0.4): 652 | resolution: {integrity: sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==} 653 | peerDependencies: 654 | chai: ^4.0.0 655 | sinon: '>=4.0.0' 656 | dependencies: 657 | chai: 4.3.7 658 | sinon: 15.0.4 659 | dev: true 660 | 661 | /sinon@15.0.4: 662 | resolution: {integrity: sha512-uzmfN6zx3GQaria1kwgWGeKiXSSbShBbue6Dcj0SI8fiCNFbiUDqKl57WFlY5lyhxZVUKmXvzgG2pilRQCBwWg==} 663 | dependencies: 664 | '@sinonjs/commons': 3.0.0 665 | '@sinonjs/fake-timers': 10.1.0 666 | '@sinonjs/samsam': 8.0.0 667 | diff: 5.1.0 668 | nise: 5.1.4 669 | supports-color: 7.2.0 670 | dev: true 671 | 672 | /string-width@4.2.3: 673 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 674 | engines: {node: '>=8'} 675 | dependencies: 676 | emoji-regex: 8.0.0 677 | is-fullwidth-code-point: 3.0.0 678 | strip-ansi: 6.0.1 679 | dev: true 680 | 681 | /strip-ansi@6.0.1: 682 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 683 | engines: {node: '>=8'} 684 | dependencies: 685 | ansi-regex: 5.0.1 686 | dev: true 687 | 688 | /strip-json-comments@3.1.1: 689 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 690 | engines: {node: '>=8'} 691 | dev: true 692 | 693 | /supports-color@7.2.0: 694 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 695 | engines: {node: '>=8'} 696 | dependencies: 697 | has-flag: 4.0.0 698 | dev: true 699 | 700 | /supports-color@8.1.1: 701 | resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} 702 | engines: {node: '>=10'} 703 | dependencies: 704 | has-flag: 4.0.0 705 | dev: true 706 | 707 | /to-regex-range@5.0.1: 708 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 709 | engines: {node: '>=8.0'} 710 | dependencies: 711 | is-number: 7.0.0 712 | dev: true 713 | 714 | /ts-node@10.9.1(@types/node@20.1.4)(typescript@5.0.4): 715 | resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} 716 | hasBin: true 717 | peerDependencies: 718 | '@swc/core': '>=1.2.50' 719 | '@swc/wasm': '>=1.2.50' 720 | '@types/node': '*' 721 | typescript: '>=2.7' 722 | peerDependenciesMeta: 723 | '@swc/core': 724 | optional: true 725 | '@swc/wasm': 726 | optional: true 727 | dependencies: 728 | '@cspotcode/source-map-support': 0.8.1 729 | '@tsconfig/node10': 1.0.9 730 | '@tsconfig/node12': 1.0.11 731 | '@tsconfig/node14': 1.0.3 732 | '@tsconfig/node16': 1.0.4 733 | '@types/node': 20.1.4 734 | acorn: 8.8.2 735 | acorn-walk: 8.2.0 736 | arg: 4.1.3 737 | create-require: 1.1.1 738 | diff: 4.0.2 739 | make-error: 1.3.6 740 | typescript: 5.0.4 741 | v8-compile-cache-lib: 3.0.1 742 | yn: 3.1.1 743 | dev: true 744 | 745 | /type-detect@4.0.8: 746 | resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} 747 | engines: {node: '>=4'} 748 | dev: true 749 | 750 | /typescript@5.0.4: 751 | resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} 752 | engines: {node: '>=12.20'} 753 | hasBin: true 754 | dev: true 755 | 756 | /v8-compile-cache-lib@3.0.1: 757 | resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} 758 | dev: true 759 | 760 | /workerpool@6.2.1: 761 | resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} 762 | dev: true 763 | 764 | /wrap-ansi@7.0.0: 765 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 766 | engines: {node: '>=10'} 767 | dependencies: 768 | ansi-styles: 4.3.0 769 | string-width: 4.2.3 770 | strip-ansi: 6.0.1 771 | dev: true 772 | 773 | /wrappy@1.0.2: 774 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 775 | dev: true 776 | 777 | /y18n@5.0.8: 778 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 779 | engines: {node: '>=10'} 780 | dev: true 781 | 782 | /yargs-parser@20.2.4: 783 | resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} 784 | engines: {node: '>=10'} 785 | dev: true 786 | 787 | /yargs-unparser@2.0.0: 788 | resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} 789 | engines: {node: '>=10'} 790 | dependencies: 791 | camelcase: 6.3.0 792 | decamelize: 4.0.0 793 | flat: 5.0.2 794 | is-plain-obj: 2.1.0 795 | dev: true 796 | 797 | /yargs@16.2.0: 798 | resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} 799 | engines: {node: '>=10'} 800 | dependencies: 801 | cliui: 7.0.4 802 | escalade: 3.1.1 803 | get-caller-file: 2.0.5 804 | require-directory: 2.1.1 805 | string-width: 4.2.3 806 | y18n: 5.0.8 807 | yargs-parser: 20.2.4 808 | dev: true 809 | 810 | /yn@3.1.1: 811 | resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} 812 | engines: {node: '>=6'} 813 | dev: true 814 | 815 | /yocto-queue@0.1.0: 816 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 817 | engines: {node: '>=10'} 818 | dev: true 819 | -------------------------------------------------------------------------------- /005_Promise/src/index.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | 3 | class Promise2 { 4 | state = "pending" 5 | callbacks = [] 6 | 7 | private resolveOrReject(state, data, i) { 8 | if (this.state !== "pending") return 9 | this.state = state 10 | nextTick(() => { 11 | this.callbacks.forEach(handle => { 12 | if (typeof handle[i] === "function") { 13 | let x 14 | try { 15 | x = handle[i].call(undefined, data) 16 | } catch (e) { 17 | return handle[2].reject(e) 18 | } 19 | handle[2].resolveWith(x) 20 | } 21 | }) 22 | }) 23 | } 24 | private resolve(result) { 25 | this.resolveOrReject("fulfilled", result, 0) 26 | } 27 | private reject(reason) { 28 | this.resolveOrReject("rejected", reason, 1) 29 | } 30 | 31 | constructor(fn) { 32 | if (typeof fn !== "function") { 33 | throw new Error("我只接受函数") 34 | } 35 | fn(this.resolve.bind(this), this.reject.bind(this)) 36 | } 37 | then(succeed?, fail?) { 38 | const handle = [] 39 | if (typeof succeed === "function") { 40 | handle[0] = succeed 41 | } 42 | if (typeof fail === "function") { 43 | handle[1] = fail 44 | } 45 | handle[2] = new Promise2(() => {}) 46 | this.callbacks.push(handle) 47 | return handle[2] 48 | } 49 | private resolveWithSelf() { 50 | this.reject(new TypeError()) 51 | } 52 | private resolveWithPromise(x) { 53 | x.then( 54 | result => { this.resolve(result) }, 55 | reason => { this.reject(reason) } 56 | ) 57 | } 58 | private getThen(x) { 59 | let then 60 | try { 61 | then = x.then 62 | } catch (e) { 63 | return this.reject(e) 64 | } 65 | return then 66 | } 67 | private resolveWithThenable(x) { 68 | try { 69 | x.then( 70 | y => { this.resolveWith(y) }, 71 | r => { this.reject(r) } 72 | ) 73 | } catch (e) { 74 | this.reject(e) 75 | } 76 | } 77 | private resolveWithObject(x) { 78 | let then = this.getThen(x) 79 | if (then instanceof Function) { 80 | this.resolveWithThenable(x) 81 | } else { 82 | this.resolve(x) 83 | } 84 | } 85 | private resolveWith(x) { 86 | if (this === x) { 87 | this.resolveWithSelf() 88 | } else if (x instanceof Promise2) { 89 | this.resolveWithPromise(x) 90 | } else if (x instanceof Object) { 91 | this.resolveWithObject(x) 92 | } else { 93 | this.resolve(x) 94 | } 95 | } 96 | } 97 | 98 | export default Promise2 99 | 100 | function nextTick(fn) { 101 | if (process !== undefined && typeof process.nextTick === "function") { 102 | return process.nextTick(fn) 103 | } else { 104 | var counter = 1 105 | var observer = new MutationObserver(fn) 106 | var textNode = document.createTextNode(String(counter)) 107 | 108 | observer.observe(textNode, { 109 | characterData: true 110 | }) 111 | 112 | counter = counter + 1 113 | textNode.data = String(counter) 114 | } 115 | } -------------------------------------------------------------------------------- /005_Promise/test/index.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import chai from 'chai' 3 | import { assert } from 'chai' 4 | import { describe } from 'mocha' 5 | import sinon from 'sinon' 6 | import sinonChai from 'sinon-chai' 7 | chai.use(sinonChai) 8 | 9 | import Promise from '../src' 10 | 11 | describe("Promise", () => { 12 | it("是一个类", () => { 13 | assert.isFunction(Promise) 14 | assert.isObject(Promise.prototype) 15 | }) 16 | it("new Promise() 如果接受的不是一个函数就报错", () => { 17 | assert.throw(() => new Promise()) 18 | assert.throw(() => new Promise(1)) 19 | assert.throw(() => new Promise('1')) 20 | assert.throw(() => new Promise(false)) 21 | }) 22 | it("new Promise(fn) 会生成一个对象,对象有 then 方法", () => { 23 | const promise = new Promise(() => {}) 24 | assert.isFunction(promise.then) 25 | }) 26 | it("new Promise(fn) 中的 fn 是立即执行的", () => { 27 | const fn = sinon.fake() 28 | new Promise(fn) 29 | assert(fn.called) 30 | }) 31 | it("new Promise(fn) 中的 fn 接受两个函数作为参数", done => { 32 | new Promise((resolve, reject) => { 33 | assert.isFunction(resolve) 34 | assert.isFunction(reject) 35 | done() 36 | }) 37 | }) 38 | it("promise.then 中的 success 会在 resolve 被调用的时候执行", done => { 39 | const success = sinon.fake() 40 | const promise = new Promise((resolve, reject) => { 41 | assert.isFalse(success.called) 42 | resolve() 43 | setTimeout(() => { 44 | assert.isTrue(success.called) 45 | done() 46 | }) 47 | }) 48 | promise.then(success) 49 | }) 50 | it("promise.then 中的 fail 会在 reject 被调用的时候执行", done => { 51 | const fail = sinon.fake() 52 | const promise = new Promise((resolve, reject) => { 53 | assert.isFalse(fail.called) 54 | reject() 55 | setTimeout(() => { 56 | assert.isTrue(fail.called) 57 | done() 58 | }) 59 | }) 60 | promise.then(null, fail) 61 | }) 62 | it("2.2.1.1 如果 onFulfilled 不是函数,则必须忽略它", () => { 63 | const promise = new Promise((resolve, reject) => { 64 | resolve() 65 | }) 66 | promise.then(false, null) 67 | assert(1 === 1) 68 | }) 69 | it("2.2.1.2 如果 onRejected 不是函数,则必须忽略它", () => { 70 | const promise = new Promise((resolve, reject) => { 71 | reject() 72 | }) 73 | promise.then(null, false) 74 | assert(1 === 1) 75 | }) 76 | it("2.2.2 中的 3 个规范", done => { 77 | const succeed = sinon.fake() 78 | const promise = new Promise((resolve, reject) => { 79 | assert.isFalse(succeed.called) 80 | resolve(233) 81 | resolve(2333) 82 | setTimeout(() => { 83 | assert(promise.state === 'fulfilled') 84 | assert.isTrue(succeed.calledOnce) 85 | assert(succeed.calledWith(233)) 86 | done() 87 | }, 0) 88 | }) 89 | promise.then(succeed) 90 | }) 91 | it("2.2.3 在执行上下文堆栈仅包含平台代码之前,不得调用 onFulfilled 或 onRejected", done => { 92 | const succeed = sinon.fake() 93 | const promise = new Promise((resolve, reject) => { 94 | resolve() 95 | }) 96 | promise.then(succeed) 97 | assert.isFalse(succeed.called) 98 | setTimeout(() => { 99 | assert.isTrue(succeed.called) 100 | done() 101 | }, 0) 102 | }) 103 | it("2.2.4 在执行上下文堆栈仅包含平台代码之前,不得调用 onFulfilled 或 onRejected", done => { 104 | const fail = sinon.fake() 105 | const promise = new Promise((resolve, reject) => { 106 | reject() 107 | }) 108 | promise.then(null, fail) 109 | assert.isFalse(fail.called) 110 | setTimeout(() => { 111 | assert.isTrue(fail.called) 112 | done() 113 | }, 0) 114 | }) 115 | it("2.2.5 onFulfilled 和 onRejected 必须作为函数调用(即没有 this 值)", done => { 116 | const promise = new Promise((resolve, reject) => { 117 | resolve() 118 | }) 119 | promise.then(function() { 120 | "use strict" 121 | assert(this === undefined) 122 | done() 123 | } 124 | ) 125 | }) 126 | it("2.2.6.1 then 可能会在同一个 promise 上被多次调用,当 fulfilled 时,onFulfilled 的所有回调必须按照原始的调用顺序执行", done => { 127 | const promise = new Promise((resolve, reject) => { 128 | resolve() 129 | }) 130 | const callbacks = [sinon.fake(), sinon.fake(), sinon.fake()] 131 | promise.then(callbacks[0]) 132 | promise.then(callbacks[1]) 133 | promise.then(callbacks[2]) 134 | setTimeout(() => { 135 | assert(callbacks[0].called) 136 | assert(callbacks[1].called) 137 | assert(callbacks[2].called) 138 | assert(callbacks[1].calledAfter(callbacks[0])) 139 | assert(callbacks[2].calledAfter(callbacks[1])) 140 | done() 141 | }, 0) 142 | }) 143 | it("2.2.6.2 then 可能会在同一个 promise 上被多次调用,当 rejected 时,onFulfilled 的所有回调必须按照原始的调用顺序执行", done => { 144 | const promise = new Promise((resolve, reject) => { 145 | reject() 146 | }) 147 | const callbacks = [sinon.fake(), sinon.fake(), sinon.fake()] 148 | promise.then(null, callbacks[0]) 149 | promise.then(null, callbacks[1]) 150 | promise.then(null, callbacks[2]) 151 | setTimeout(() => { 152 | assert(callbacks[0].called) 153 | assert(callbacks[1].called) 154 | assert(callbacks[2].called) 155 | assert(callbacks[1].calledAfter(callbacks[0])) 156 | assert(callbacks[2].calledAfter(callbacks[1])) 157 | done() 158 | }, 0) 159 | }) 160 | it("2.2.7 then 必须返回一个 Promise", () => { 161 | const promise = new Promise((resolve, reject) => { 162 | resolve() 163 | }) 164 | const promise2 = promise.then(() => {}, () => {}) 165 | assert(promise2 instanceof Promise) 166 | }) 167 | it("2.2.7.1 如果 then(success, fail) 中的 success 返回一个值 x,运行 [[Resolve]](promise2, x)", done => { 168 | const promise1 = new Promise((resolve, reject) => { 169 | resolve() 170 | }) 171 | promise1.then(() => "成功", () => {}).then(result => { 172 | assert.equal(result, "成功") 173 | done() 174 | }) 175 | }) 176 | it("2.2.7.1.2 success 的返回值是一个 Promise 实例", done => { 177 | const promise1 = new Promise((resolve, reject) => { 178 | resolve() 179 | }) 180 | const fn = sinon.fake() 181 | const promise2 = promise1.then(() => new Promise(resolve => resolve())) 182 | promise2.then(fn) 183 | setTimeout(() => { 184 | assert(fn.called) 185 | done() 186 | }) 187 | }) 188 | it("2.2.7.1.2 success 的返回值是一个 Promise 实例,且失败了", done => { 189 | const promise1 = new Promise((resolve, reject) => { 190 | resolve() 191 | }) 192 | const fn = sinon.fake() 193 | const promise2 = promise1.then(() => new Promise((resolve, reject) => reject())) 194 | promise2.then(null, fn) 195 | setTimeout(() => { 196 | assert(fn.called) 197 | done() 198 | }) 199 | }) 200 | it("2.2.7.1.2 fail 的返回值是一个 Promise 实例", done => { 201 | const promise1 = new Promise((resolve, reject) => { 202 | reject() 203 | }) 204 | const fn = sinon.fake() 205 | const promise2 = promise1.then( 206 | null, 207 | () => new Promise(resolve => resolve()) 208 | ) 209 | promise2.then(fn, null) 210 | setTimeout(() => { 211 | assert(fn.called) 212 | done() 213 | }) 214 | }) 215 | it("2.2.7.1.2 fail 的返回值是一个 Promise 实例, 且失败了", done => { 216 | const promise1 = new Promise((resolve, reject) => { 217 | reject() 218 | }) 219 | const fn = sinon.fake() 220 | const promise2 = promise1.then( 221 | null, 222 | () => new Promise((resolve, reject) => reject()) 223 | ) 224 | promise2.then(null, fn) 225 | setTimeout(() => { 226 | assert(fn.called) 227 | done() 228 | }) 229 | }) 230 | it("2.2.7.2 如果 success 抛出一个异常 e,promise2 必须被拒绝", done => { 231 | const promise1 = new Promise((resolve, reject) => { 232 | resolve() 233 | }) 234 | const fn = sinon.fake() 235 | const error = new Error() 236 | const promise2 = promise1.then(() => { 237 | throw error 238 | }) 239 | promise2.then(null, fn) 240 | setTimeout(() => { 241 | assert(fn.called) 242 | assert(fn.calledWith(error)) 243 | done() 244 | }) 245 | }) 246 | it("2.2.7.2 如果 fail 抛出一个异常 e,promise2 必须被拒绝", done => { 247 | const promise1 = new Promise((resolve, reject) => { 248 | reject() 249 | }) 250 | const fn = sinon.fake() 251 | const error = new Error() 252 | const promise2 = promise1.then(null, () => { 253 | throw error 254 | }) 255 | promise2.then(null, fn) 256 | setTimeout(() => { 257 | assert(fn.called) 258 | assert(fn.calledWith(error)) 259 | done() 260 | }) 261 | }) 262 | }) 263 | -------------------------------------------------------------------------------- /006_EventLoop/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heycn/code-more/73e066b22d3dbb455bf59447f205f8e03aa3ed07/006_EventLoop/.DS_Store -------------------------------------------------------------------------------- /006_EventLoop/README.md: -------------------------------------------------------------------------------- 1 | # EventLoop - 事件循环 2 | 3 | ## 一、浏览器的进程模型 4 | 5 | ### 1. 什么是进程? 6 | 7 | - 程序的运行需要有自己的 `内存空间`,每个程序至少有一个 `内存空间`,它们的内存互不交叉,相互隔离 8 | - 它们之间可以相互通信,但是需要双方同意 9 | 10 | 这里,可以把 `进程` 简单地理解为是这块 `内存空间` 11 | 12 | ### 2. 什么是线程? 13 | 14 | 有了 `进程` 之后,就可以运行程序的代码了,但是谁来运行代码呢?\ 15 | 那就是 —— 线程 16 | 17 | 一个 `进程` 至少有一个线程, 在 `进程` 开启后会自动创建一个 `线程` 来运行代码,这个线程称为 `「主线程」`(如果主线程结束了,那么整个程序也就结束了) 18 | 19 | 如果程序需要同时做很多事,比如:网络通信,音频播放,等等...\ 20 | 主线程就会启动更多的线程来执行代码,所以一个进程中可以包含多个线程(这些线程称为 `「子线程」`) 21 | 22 | ### 3. 浏览器有哪些进程和线程? 23 | 24 | > 浏览器是一个 `多进程`、`多线程` 的应用程序 25 | 26 | 浏览器内部的工作极其复杂,它的复杂度已经接近于操作系统了 27 | 28 | 为了避免相互影响,为了减少连环崩溃的几率(`进程a` 崩溃了,不会影响到其他的 `进程b、c、d`),当启动浏览器后,它就会自动启动多个 `进程` 29 | 30 | 这些进程我们需要关心的主要有 3 个: 31 | 32 | 1. 浏览器进程 33 | 2. 网络进程 34 | 3. 渲染进程(一个标签页为一个渲染进程) 35 | 36 | #### 3.1 浏览器进程 37 | 38 | 主要负责: 39 | 40 | - 启动多个线程处理不同的任务 41 | - 界面显示,注意!不是页面的显示,而是浏览器界面的显示,如:刷新按钮、前进后退、书签栏,等等... 42 | - 用户交互:滚动、鼠标事件、键盘事件,等等... 43 | - 子进程管理:其他进程是由浏览器进程启动的,如:网络进程,渲染进程,等等... 44 | - 等等... 45 | 46 | #### 3.2 网络进程 47 | 48 | - 负责加载网络资源 49 | - 网络进程内部会启动多个线程来处理不同的网络任务 50 | 51 | #### 3.3 渲染进程(重点) 52 | 53 | - 渲染进程启动后,会开启一个 `渲染主线程` 54 | - `渲染主线程` 负责执行 `HTML`、`CSS`、`JS` 55 | - 默认情况下,每一个标签页会开辟一个新的 `渲染进程`,以保证不同的标签页之间互不影响(这个模式将来可能会改变) 56 | 57 | ## 二、渲染主线程是如何工作的? 58 | 59 | ### 1. 主要工作 60 | 61 | > 渲染主线程是浏览器最繁忙的线程,需要它处理的任务包括但不限于以下: 62 | 63 | - 解析 `HTML` 64 | - 解析 `CSS` 65 | - 计算样式 66 | - 布局 67 | - 图层处理 68 | - 每秒把页面画 60 次(脑补游戏的 FPS) 69 | - 执行全局 JS 代码 70 | - 执行事件处理函数 71 | - 执行计时器的回调函数 72 | - 等等...... 73 | 74 | 我们是「996」,渲染进程就是「没有工资的007」 75 | 76 | ### 2. 主线程如何调度任务? 77 | 78 | > 这是一个大问题 79 | 80 | 比如: 81 | 82 | - 一个 JS 函数执行到一半时,用户点击了一个按钮,这时候,应该立即去执行点击事件的处理函数吗? 83 | - 一个 JS 函数执行到一半时,某个计时器到时间了,这时候,应该立即去执行计时器的回调函数吗? 84 | - 用户点击了一个按钮的同时,某个计时器到时间了,这时候,应该先执行哪个任务? 85 | - 等等... 86 | 87 | 解决这个问题的方法就是 —— 排队 88 | 89 | - 在最开始的时候,渲染主进程会进入一个无限循环(浏览器源码 `base/message_loop/message_pump_default.cc` 中,渲染主线程的启动函数中写了 `for (;;) { ...some code }`) 90 | - 每一次循环会检查消息队列中是否有任务存在。如果有,就取出第一个任务执行,执行完一个后,进入下一次循环,如果没有,则进入休眠状态 91 | - 其他所有线程(包括其他进程的线程)可以随时向消息队列添加任务。新任务会加到消息队列的末尾。在添加新任务时,如果主线程是休眠状态,则会将其唤醒,继续循环拿任务 92 | 93 | 这整个过程,就叫作 —— 事件循环(消息循环) 94 | 95 | [事件循环源码链接](https://github.com/chromium/chromium/blob/main/base/message_loop/message_pump_default.cc#L32) 96 | 97 |  98 | 99 | ## 三、什么是异步 100 | 101 | 在代码的执行过程中,会遇到一些无法立即处理的任务,比如: 102 | 103 | - 计时完成后需要执行的任务:setTimeout、setInterval 104 | - 网络通信完成后需要执行的任务:XMLHttpRequest、Fetch 105 | - 用户点击后需要执行的任务:onclick、onmouseover、onkeydown、等等... 106 | 107 | 如果让渲染主线程等待这些任务完成,就会导致主线程长期处于「阻塞」状态,导致浏览器「卡死」 108 | 109 | 渲染主线程承担着极其重要的工作,无论如何都不能阻塞!\ 110 | 因此,浏览器选择异步来解决这个问题 111 | 112 | 使用异步的方式,渲染主线程永不阻塞 113 | 114 | 总结: 115 | 116 | - JS 是一门单线程语言,因为它运行在浏览器的 `渲染主线程` 中,而渲染主线程只有一个 117 | - 但是渲染主线程承担很多工作,比如:渲染页面、执行 JS 代码等等 118 | - 如果使用 `同步` 的方式,就极其很有可能导致主线程产生 `阻塞`,从而导致 `消息队列` 中的很多其他任务无法执行 119 | - 这样会导致主线程消耗时间,导致页面无法及时更新,给页面造成 `卡死` 现象 120 | - 所以浏览器采用以下 `异步` 的方式来避免: 121 | - 当某些任务发生时,比如:计时器、网络请求、事件监听,主线程将任务交给其他线程去处理,自身立即结束任务的执行,继续执行后续代码 122 | - 当其他线程完成时,将之前传递的 `回调函数`「包装成任务」,加入到消息队列的末尾排队,等待主线程 `调度执行` 123 | - 在这种异步的模式下,浏览器将会永不阻塞,从而最大限度的保证了单线程的流畅运行 124 | 125 | ## 四、任务有优先级吗? 126 | 127 | 任务是没有优先级的,在消息队列中 `先进先出` 128 | 129 | 但是 `消息队列` 有「优先级」 130 | 131 | 过去的解释是:任务有两个队列:一个宏任务,一个微任务 132 | 133 | 现在根据 W3C 的最新解释 - [原文链接](https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint): 134 | 135 | - 每个任务都有一个 `任务类型`,同一个类型的任务必须在一个队列,不同类型的任务可以分属于不同的队列。在一次事件循环中,浏览器可以根据实际情况从不同的队列中取出任务执行 136 | - 浏览器必须准备好一个微队列,微队列中的任务优先所有其他任务执行 137 | 138 | > 随着浏览器的复杂度急剧提升,W3C 不在使用宏队列的说法 139 | 140 | 在目前 Chrome 的实现中,至少包含了以下队列: 141 | 142 | - 延时队列 - 优先级中:存放计时器到达后产生的回调任务 143 | - 交互队列 - 优先级高:存放用户操作后产生的事件处理任务 144 | - 微队列 - 优先级最高:存放需要最快执行的任务(如:Promise、MutationObserver) 145 | 146 | ## 五、总结 147 | 148 | 总结事件循环: 149 | 150 | - 事件循环又叫作消息循环(官方的描述是 `event loop`,浏览器的代码实现是 `message_loop`),是浏览器渲染主线程的工作方式 151 | - 在 Chrome 的源码中,它会开启一个不会结束的 for 循环(`for (;;) {}`),每次循环会从消息队列中取出第一个任务执行,而其他线程会在合适的时候把任务加入到队列末尾 152 | - 过去把消息队列分为 `宏队列` 和 `微队列`,但是这种说法已经无法满足现在复杂的浏览器环境,取而代之的是一种更加灵活多变的处理方式 153 | - 根据 W3C 官方解释: 154 | - 每个任务有不同的类型,同类型任务必须在同一个队列,不同的任务可以属于不同的队列 155 | - 不同任务队列有不同的优先级,在一次事件循环中,由浏览器自行决定取哪一个队列的任务 156 | - 但浏览器必须有一个微队列,微队列的任务一定具有最高的优先级,必须优先调度执行 157 | 158 | 事件循环是异步的实现方式,而单线程是异步产生的原因 159 | 160 | 完。 161 | -------------------------------------------------------------------------------- /006_EventLoop/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heycn/code-more/73e066b22d3dbb455bf59447f205f8e03aa3ed07/006_EventLoop/images/.DS_Store -------------------------------------------------------------------------------- /006_EventLoop/images/message_queue1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heycn/code-more/73e066b22d3dbb455bf59447f205f8e03aa3ed07/006_EventLoop/images/message_queue1.png -------------------------------------------------------------------------------- /007_Vue2Reactivity/README.md: -------------------------------------------------------------------------------- 1 | # 实现一个简版 Vue2 响应式原理 2 | -------------------------------------------------------------------------------- /007_Vue2Reactivity/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |文字文字1
47 |文字文字2
48 | 49 |文字文字3
50 |文字文字4
51 |文字文字5
52 |文字文字6
53 |文字文字7
54 |文字文字8
55 |文字文字9
56 |文字文字10
57 |文字文字11
58 |