aoye 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1120 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ function Queue() {
6
+ return {
7
+ len: 0,
8
+ push: Queue_$$$_push,
9
+ shift: Queue_$$$_shift,
10
+ get first() {
11
+ var _a;
12
+ return (_a = this._first) === null || _a === void 0 ? void 0 : _a.v;
13
+ },
14
+ get last() {
15
+ var _a;
16
+ return (_a = this._last) === null || _a === void 0 ? void 0 : _a.v;
17
+ }
18
+ };
19
+ }
20
+ function Queue_$$$_push(it) {
21
+ this.len++;
22
+ const {
23
+ _last: last
24
+ } = this;
25
+ const item = {
26
+ v: it
27
+ };
28
+ if (!last) {
29
+ this._first = this._last = item;
30
+ return;
31
+ }
32
+ item.prev = this._last;
33
+ last.next = item;
34
+ this._last = item;
35
+ }
36
+ function Queue_$$$_shift() {
37
+ const {
38
+ _first: first
39
+ } = this;
40
+ if (!first) return undefined;
41
+ this.len--;
42
+ const {
43
+ next
44
+ } = first;
45
+ first.next = undefined;
46
+ if (next) {
47
+ next.prev = undefined;
48
+ } else {
49
+ this._last = undefined;
50
+ }
51
+ this._first = next;
52
+ return first.v;
53
+ }
54
+ function SortMap() {
55
+ return {
56
+ data: {},
57
+ clear: SortMap_$$$_clear,
58
+ add: SortMap_$$$_add
59
+ };
60
+ }
61
+ // const queue = new Queue([1,2,3,4]);
62
+ // queue.shift()
63
+ // queue.pop()
64
+ // // @ts-ignore
65
+ // queue.unshift('a')
66
+ // // @ts-ignore
67
+ // queue.push('b')
68
+ // queue.shift()
69
+ // queue.pop()
70
+ // queue.shift()
71
+ // queue.pop()
72
+ // queue.shift()
73
+ // queue.pop()
74
+ // queue.push(10)
75
+ // queue.array();
76
+ function SortMap_$$$_clear() {
77
+ this.data = {};
78
+ }
79
+ function SortMap_$$$_add(key, value) {
80
+ const {
81
+ data
82
+ } = this;
83
+ let list = data[key];
84
+ if (!list) {
85
+ list = [];
86
+ data[key] = list;
87
+ }
88
+ list.push(value);
89
+ }
90
+
91
+ const G = {
92
+ /** 原子 signal 更新次数 */
93
+ version: 0,
94
+ id: 0,
95
+ /** scope 销毁任务序号 */
96
+ scopeDisposeI: 0
97
+ };
98
+ const dirtyLeafs = SortMap();
99
+ var State;
100
+ (function (State) {
101
+ State[State["Clean"] = 0] = "Clean";
102
+ /** 仅用于 scope 节点是否 abort */
103
+ State[State["ScopeAbort"] = 32] = "ScopeAbort";
104
+ State[State["OutLink"] = 16] = "OutLink";
105
+ State[State["Unknown"] = 8] = "Unknown";
106
+ State[State["Dirty"] = 4] = "Dirty";
107
+ State[State["Check"] = 2] = "Check";
108
+ State[State["ScopeReady"] = 1] = "ScopeReady";
109
+ })(State || (State = {}));
110
+ const DirtyState = State.Unknown | State.Dirty;
111
+
112
+ exports.Scheduler = void 0;
113
+ (function (Scheduler) {
114
+ Scheduler["Sync"] = "__Sync_";
115
+ Scheduler["Layout"] = "__Layout_";
116
+ Scheduler["Micro"] = "__Micro_";
117
+ Scheduler["Macro"] = "__Macro_";
118
+ })(exports.Scheduler || (exports.Scheduler = {}));
119
+ const _scheduler = {
120
+ [exports.Scheduler.Sync]: defaultScheduler,
121
+ [exports.Scheduler.Micro]: microScheduler,
122
+ [exports.Scheduler.Macro]: macroScheduler,
123
+ [exports.Scheduler.Layout]: schedulerLayout
124
+ };
125
+ const scheduler = (key, value) => _scheduler[key] = value;
126
+ function defaultScheduler(effects) {
127
+ for (const effect of effects) {
128
+ effect.runIfDirty();
129
+ }
130
+ }
131
+ const p = Promise.resolve();
132
+ let hasMicroTask = false;
133
+ function microScheduler(effects) {
134
+ if (hasMicroTask) return;
135
+ p.then(() => {
136
+ defaultScheduler(effects);
137
+ hasMicroTask = false;
138
+ });
139
+ hasMicroTask = true;
140
+ }
141
+ let channel, macroQueue;
142
+ if (globalThis.MessageChannel) {
143
+ channel = new MessageChannel();
144
+ macroQueue = Queue();
145
+ channel.port2.onmessage = () => {
146
+ while (macroQueue.first) {
147
+ macroQueue.shift()();
148
+ }
149
+ };
150
+ }
151
+ function macroScheduler(effects) {
152
+ if (channel) {
153
+ macroQueue.push(() => defaultScheduler(effects));
154
+ channel.port1.postMessage('');
155
+ }
156
+ setTimeout(() => {
157
+ defaultScheduler(effects);
158
+ });
159
+ }
160
+ function schedulerLayout(effects) {
161
+ requestAnimationFrame(() => {
162
+ defaultScheduler(effects);
163
+ });
164
+ }
165
+
166
+ const DefaultDFSOpt = {
167
+ isUp: false,
168
+ begin: undefined,
169
+ complete: undefined,
170
+ breakStack: [],
171
+ breakLine: undefined,
172
+ breakNode: undefined
173
+ };
174
+ function dfs(root, opt = {}) {
175
+ const {
176
+ isUp,
177
+ begin,
178
+ complete,
179
+ breakStack: lineStack,
180
+ breakLine
181
+ } = {
182
+ ...DefaultDFSOpt,
183
+ ...opt
184
+ };
185
+ let node = opt.breakNode || root;
186
+ let line = breakLine;
187
+ const listKey = isUp ? 'recStart' : 'emitStart';
188
+ const nodeKey = isUp ? 'upstream' : 'downstream';
189
+ // 向上意味着要找所有节点的入度
190
+ const nextLineKey = isUp ? 'nextRecLine' : 'nextEmitLine';
191
+ const reverseNodeKey = isUp ? 'downstream' : 'upstream';
192
+ while (1) {
193
+ let notGoDeep = begin === null || begin === void 0 ? void 0 : begin({
194
+ node: node,
195
+ lineFromUp: line,
196
+ walkedLine: lineStack
197
+ });
198
+ lineStack.push(line);
199
+ line = node[listKey];
200
+ if (line && !notGoDeep) {
201
+ const firstChild = line[nodeKey];
202
+ node = firstChild;
203
+ continue;
204
+ }
205
+ while (1) {
206
+ const noGoSibling = complete === null || complete === void 0 ? void 0 : complete({
207
+ node: node,
208
+ lineToDeep: line,
209
+ walkedLine: lineStack,
210
+ notGoDeep
211
+ });
212
+ // 只对当前不下钻的节点生效
213
+ // notGoDeep = false;
214
+ line = lineStack.pop();
215
+ // 递归出口,回到起点
216
+ if (node === root) {
217
+ return;
218
+ }
219
+ notGoDeep = false;
220
+ const nextLine = line[nextLineKey];
221
+ // 有兄弟节点, 进入外循环,向下遍历兄弟节点
222
+ if (!noGoSibling && nextLine) {
223
+ // 外层循环后会把 sibling line 入栈,这里不需要处理
224
+ line = nextLine;
225
+ node = nextLine[nodeKey];
226
+ break;
227
+ }
228
+ // 没有兄弟节点就上浮
229
+ node = line[reverseNodeKey];
230
+ }
231
+ }
232
+ }
233
+
234
+ function Line_$$$_link(v1, v2) {
235
+ let {
236
+ emitEnd
237
+ } = v1,
238
+ {
239
+ recEnd,
240
+ recStart
241
+ } = v2,
242
+ noRecEnd = !recEnd,
243
+ /** 模拟头节点 */
244
+ head = {
245
+ nextRecLine: recStart
246
+ },
247
+ line;
248
+ recEnd = recEnd || head;
249
+ const {
250
+ nextRecLine
251
+ } = recEnd || {};
252
+ // 没有下一个收到的线
253
+ if (!nextRecLine) {
254
+ line = Line();
255
+ // 内部会处理空链表的情况,即同步头部
256
+ Line.emit_line(v1, line);
257
+ Line.rec_line(v2, line);
258
+ emitEnd && Line.line_line_emit(emitEnd, line);
259
+ !noRecEnd && Line.line_line_rec(recEnd, line);
260
+ }
261
+ // 复用
262
+ else if (nextRecLine.upstream === v1) {
263
+ v2.recEnd = nextRecLine;
264
+ // TODO: link 版本标记
265
+ }
266
+ // 插入(这么做): v1 和 下一个 入度(订阅)节点不同
267
+ // TODO: v2上次真依赖了 v1 只是没检查出来,需要删除原依赖
268
+ else {
269
+ line = Line();
270
+ Line.emit_line(v1, line);
271
+ Line.rec_line(v2, line);
272
+ emitEnd && Line.line_line_emit(emitEnd, line);
273
+ Line.insert_line_rec(recEnd, nextRecLine, line);
274
+ }
275
+ // 消除 head
276
+ for (const key in head) {
277
+ head[key] = undefined;
278
+ }
279
+ }
280
+ Line.link = Line_$$$_link;
281
+ function Line_$$$_unlink(line) {
282
+ let {
283
+ prevEmitLine,
284
+ nextEmitLine,
285
+ prevRecLine,
286
+ nextRecLine,
287
+ upstream,
288
+ downstream
289
+ } = line;
290
+ line.prevEmitLine = undefined;
291
+ line.nextEmitLine = undefined;
292
+ line.prevRecLine = undefined;
293
+ line.nextRecLine = undefined;
294
+ line.upstream = undefined;
295
+ line.downstream = undefined;
296
+ /** 上游节点发出的线 前一条 关联 后一条 */
297
+ if (prevEmitLine) {
298
+ prevEmitLine.nextEmitLine = nextEmitLine;
299
+ } else {
300
+ // 删除的是首个节点
301
+ upstream.emitStart = nextEmitLine;
302
+ }
303
+ if (nextEmitLine) {
304
+ nextEmitLine.prevEmitLine = prevEmitLine;
305
+ } else {
306
+ // 删除尾节点
307
+ upstream.emitEnd = prevEmitLine;
308
+ }
309
+ /** 下游节点接收的线,我们从 recEnd 开始删除的,
310
+ * 接收信息,不需要设置 recEnd ,
311
+ * 因为 recStart ~ recEnd 是经过上级 get 确认的有用依赖
312
+ * */
313
+ if (prevRecLine) {
314
+ prevRecLine.nextRecLine = nextRecLine;
315
+ } else {
316
+ // 删除的是首个节点,大概率不可能从有依赖 变成无依赖
317
+ downstream.recStart = nextRecLine;
318
+ }
319
+ if (nextRecLine) {
320
+ nextRecLine.prevRecLine = prevRecLine;
321
+ } else {
322
+ // 删除尾节点
323
+ downstream.recEnd = prevRecLine;
324
+ }
325
+ }
326
+ Line.unlink = Line_$$$_unlink;
327
+ function Line_$$$_unlinkRec(line) {
328
+ // 作为下游,执行完 get 上游节点已经完成了依赖更新,把 recEnd 后的依赖删除即可
329
+ let toDel = line;
330
+ while (toDel) {
331
+ const memoNext = toDel.nextRecLine;
332
+ Line.unlink(toDel);
333
+ toDel = memoNext;
334
+ }
335
+ }
336
+ Line.unlinkRec = Line_$$$_unlinkRec;
337
+ function Line_$$$_unlinkEmit(line) {
338
+ // 作为下游,执行完 get 上游节点已经完成了依赖更新,把 recEnd 后的依赖删除即可
339
+ let toDel = line;
340
+ while (toDel) {
341
+ const memoNext = toDel.nextEmitLine;
342
+ Line.unlink(toDel);
343
+ toDel = memoNext;
344
+ }
345
+ }
346
+ Line.unlinkEmit = Line_$$$_unlinkEmit;
347
+ function Line_$$$_emit_line(upstream, line) {
348
+ if (!upstream.emitStart) {
349
+ upstream.emitStart = line;
350
+ }
351
+ upstream.emitEnd = line;
352
+ line.upstream = upstream;
353
+ }
354
+ Line.emit_line = Line_$$$_emit_line;
355
+ function Line_$$$_rec_line(downstream, line) {
356
+ if (!downstream.recStart) {
357
+ downstream.recStart = line;
358
+ }
359
+ downstream.recEnd = line;
360
+ line.downstream = downstream;
361
+ }
362
+ Line.rec_line = Line_$$$_rec_line;
363
+ function Line_$$$_line_line_emit(l1, l2) {
364
+ if (!l1 || !l2) return;
365
+ l1.nextEmitLine = l2;
366
+ l2.prevEmitLine = l1;
367
+ }
368
+ Line.line_line_emit = Line_$$$_line_line_emit;
369
+ function Line_$$$_line_line_rec(l1, l2) {
370
+ if (!l1 || !l2) return;
371
+ l1.nextRecLine = l2;
372
+ l2.prevRecLine = l1;
373
+ }
374
+ Line.line_line_rec = Line_$$$_line_line_rec;
375
+ function Line_$$$_insert_line_emit(l1, l2, ins) {
376
+ l1.nextEmitLine = ins;
377
+ ins.prevEmitLine = l1;
378
+ l2.prevEmitLine = ins;
379
+ ins.nextEmitLine = l2;
380
+ }
381
+ Line.insert_line_emit = Line_$$$_insert_line_emit;
382
+ function Line_$$$_insert_line_rec(l1, l2, ins) {
383
+ l1.nextRecLine = ins;
384
+ ins.prevRecLine = l1;
385
+ l2.prevRecLine = ins;
386
+ ins.nextRecLine = l2;
387
+ }
388
+ Line.insert_line_rec = Line_$$$_insert_line_rec;
389
+ function Line() {
390
+ return {
391
+ upstream: null,
392
+ prevEmitLine: null,
393
+ nextEmitLine: null,
394
+ downstream: null,
395
+ prevRecLine: null,
396
+ nextRecLine: null
397
+ };
398
+ }
399
+
400
+ /**
401
+ * 这是一个优先队列 (满足子节点总是比父节点大)
402
+ * 1
403
+ *
404
+ * 10 20
405
+ *
406
+ * 15 30 25 30
407
+ *
408
+ * 17
409
+ * 现在插入 7 , 会按广度优先的顺序插入在数组尾部
410
+ * 1
411
+ *
412
+ * 10 20
413
+ *
414
+ * 15 30 25 30
415
+ *
416
+ * 17 7
417
+ * 接着我们只需要将 7 逐层与上门的父节点比较, 7 较小则两者交互,一直让 7 上浮到适合的位置
418
+ *
419
+ * 0
420
+ *
421
+ * 1 2 2^0 得到第二层第一个索引
422
+ *
423
+ * 3 4 5 6 2^0 + 2^1 。。。 + 2^n + x = y
424
+ *
425
+ * 7 8
426
+ * 上浮后我们得到以上的树
427
+ */
428
+ // 父子节点的关系
429
+ // 计算一个节点的 index 公式 ① 2^0 + 2^1 。。。 + 2^n + y = x 已知
430
+ // 节点的左子节点 index ② 2^0 + 2^1 。。。 + 2^n + 2^(n+1) + z = res 求 res
431
+ // ② - ① 得到 2^(n+1) + (z-y) = res - x
432
+ // 2^(n+1) + (z-y) + x = res
433
+ // 而 z 和 y 的关系是,③ z = 2y
434
+ const leakI = (y, max) => y < 0 || y >= max ? null : y;
435
+ const getLeft = (x, max) => leakI(x * 2 + 1, max);
436
+ const getRight = (x, max) => leakI(x * 2 + 2, max);
437
+ const getParent = (x, max) => leakI(x - 1 >>> 1, max);
438
+ const exchange = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]];
439
+ function PriorityQueue(aIsUrgent) {
440
+ return {
441
+ aIsUrgent: aIsUrgent,
442
+ arr: [],
443
+ goUp: (arr, current, len) => {
444
+ let i = len - 1;
445
+ while (i > 0) {
446
+ const item = arr[i];
447
+ const pI = getParent(i, len);
448
+ const parent = arr[pI];
449
+ if (this.aIsUrgent(item, parent)) {
450
+ // console.log(`交换 parent:${parent} -> child:${item} `);
451
+ exchange(arr, i, pI);
452
+ // this.logTree();
453
+ i = pI;
454
+ } else {
455
+ // console.log(`parent:${parent} child:${item} 不需要交换 \n`);
456
+ break;
457
+ }
458
+ }
459
+ },
460
+ goDown: (arr, i) => {
461
+ const len = this.size();
462
+ const half = len >>> 1;
463
+ while (i < half) {
464
+ const lI = getLeft(i, len);
465
+ const rI = getRight(i, len);
466
+ let point = i;
467
+ if (lI != null && this.aIsUrgent(arr[lI], arr[point])) {
468
+ point = lI;
469
+ }
470
+ if (rI != null && this.aIsUrgent(arr[rI], arr[point])) {
471
+ point = rI;
472
+ }
473
+ if (point === i) {
474
+ break;
475
+ }
476
+ // console.log(`交换 parent:${arr[i]} -> child:${arr[point]} `);
477
+ exchange(arr, i, point);
478
+ // this.logTree();
479
+ i = point;
480
+ }
481
+ },
482
+ _add: PriorityQueue_$$$__add,
483
+ add: PriorityQueue_$$$_add,
484
+ poll: PriorityQueue_$$$_poll,
485
+ peek: PriorityQueue_$$$_peek,
486
+ size: PriorityQueue_$$$_size,
487
+ logTree: PriorityQueue_$$$_logTree
488
+ };
489
+ }
490
+ // case 1
491
+ // const pq = new PriorityQueue((a, b) => a - b)
492
+ // pq.add(5)
493
+ // pq.add(3)
494
+ // pq.add(1)
495
+ // pq.add(4)
496
+ // pq.add(2)
497
+ // const result = []
498
+ // while (pq.size() > 0) {
499
+ // result.push(pq.poll())
500
+ // }
501
+ // console.log(result);
502
+ // [1,2,3,4,5]
503
+ // case 2
504
+ // const pq = new PriorityQueue((a, b) => b - a)
505
+ // pq.add(1)
506
+ // pq.add(3)
507
+ // pq.add(4)
508
+ // pq.add(5)
509
+ // pq.add(2)
510
+ // const result = []
511
+ // while (pq.size() > 0) {
512
+ // result.push(pq.poll())
513
+ // }
514
+ // console.log(result);
515
+ // [5,4,3,2,1]
516
+ function PriorityQueue_$$$__add(current) {
517
+ // console.log(`加入 ${current}`);
518
+ this.arr.push(current);
519
+ const len = this.size();
520
+ // this.logTree();
521
+ if (len === 1) {
522
+ return;
523
+ }
524
+ this.goUp(this.arr, current, len);
525
+ }
526
+ function PriorityQueue_$$$_add(...items) {
527
+ items.forEach(it => this._add(it));
528
+ }
529
+ function PriorityQueue_$$$_poll() {
530
+ const {
531
+ arr
532
+ } = this;
533
+ // console.log(`弹出 ${arr[0]} 把 ${arr[arr.length - 1]} 放置到队头 `);
534
+ const len = this.size();
535
+ if (len <= 2) {
536
+ return arr.shift();
537
+ }
538
+ const last = arr.pop();
539
+ const first = arr[0];
540
+ arr[0] = last;
541
+ // this.logTree();
542
+ this.goDown(this.arr, 0);
543
+ return first;
544
+ }
545
+ function PriorityQueue_$$$_peek() {
546
+ return this.arr[0];
547
+ }
548
+ function PriorityQueue_$$$_size() {
549
+ return this.arr.length;
550
+ }
551
+ function PriorityQueue_$$$_logTree() {
552
+ const {
553
+ arr
554
+ } = this;
555
+ let i = 0;
556
+ let j = 1;
557
+ let level = 0;
558
+ const matrix = [];
559
+ do {
560
+ matrix.push(arr.slice(i, j));
561
+ i = i * 2 + 1;
562
+ j = i + Math.pow(2, level) + 1;
563
+ level++;
564
+ } while (i < arr.length);
565
+ const last = Math.pow(2, matrix.length - 1);
566
+ const arrStr = JSON.stringify(last);
567
+ const halfLen = arrStr.length >>> 1;
568
+ matrix.forEach(it => {
569
+ const str = JSON.stringify(it);
570
+ const halfIt = str.length >>> 1;
571
+ console.log(str.padStart(halfLen + halfIt, ' '));
572
+ });
573
+ console.log('\n');
574
+ }
575
+
576
+ function TaskQueue_$$$_create({
577
+ callbackAble,
578
+ aIsUrgent
579
+ }) {
580
+ const queue = TaskQueue(callbackAble, aIsUrgent);
581
+ queue.taskQueue = PriorityQueue(aIsUrgent);
582
+ return queue;
583
+ }
584
+ TaskQueue.create = TaskQueue_$$$_create;
585
+ function TaskQueue(callbackAble, aIsUrgent) {
586
+ return {
587
+ callbackAble: callbackAble,
588
+ aIsUrgent: aIsUrgent,
589
+ isScheduling: false,
590
+ pushTask: TaskQueue_$$$_pushTask,
591
+ scheduleTask: TaskQueue_$$$_scheduleTask
592
+ };
593
+ }
594
+ function TaskQueue_$$$_pushTask(task) {
595
+ const {
596
+ taskQueue,
597
+ isScheduling
598
+ } = this;
599
+ taskQueue._add(task);
600
+ if (!isScheduling) {
601
+ this.callbackAble(this.scheduleTask.bind(this));
602
+ this.isScheduling = true;
603
+ }
604
+ }
605
+ function TaskQueue_$$$_scheduleTask() {
606
+ const {
607
+ taskQueue
608
+ } = this;
609
+ // console.log('调度 dispose');
610
+ const fn = taskQueue.peek();
611
+ if (!fn) return this.isScheduling = false;
612
+ const hasRemain = fn();
613
+ // 未完成
614
+ if (hasRemain) {
615
+ this.callbackAble(this.scheduleTask.bind(this));
616
+ return;
617
+ }
618
+ // 完成
619
+ taskQueue.poll();
620
+ if (taskQueue.size() === 0) return this.isScheduling = false;
621
+ // 任务列表中还有任务
622
+ this.callbackAble(this.scheduleTask.bind(this));
623
+ }
624
+
625
+ const ide = globalThis.requestIdleCallback || (globalThis.requestAnimationFrame ? fn => globalThis.requestAnimationFrame(() => {
626
+ setTimeout(() => {
627
+ fn();
628
+ });
629
+ }) : globalThis.setTimeout);
630
+ const now = () => {
631
+ const timer = globalThis.performance || globalThis.Date;
632
+ return timer.now();
633
+ };
634
+
635
+ // export class IdeScheduler {
636
+ // constructor() {}
637
+ // isScheduling = false;
638
+ // taskQueue = new Queue<Function>();
639
+ // pushTask(task: Function) {
640
+ // const { taskQueue, isScheduling } = this;
641
+ // taskQueue.push(task);
642
+ // if (!isScheduling) {
643
+ // ide(this.scheduleTask.bind(this));
644
+ // this.isScheduling = true;
645
+ // }
646
+ // }
647
+ // scheduleTask() {
648
+ // const { taskQueue } = this;
649
+ // // console.log('调度 dispose');
650
+ // const fn = taskQueue.first;
651
+ // if (!fn) return (this.isScheduling = false);
652
+ // const hasRemain = fn();
653
+ // // 未完成
654
+ // if (hasRemain) {
655
+ // ide(this.scheduleTask.bind(this));
656
+ // return;
657
+ // }
658
+ // // 完成
659
+ // taskQueue.shift();
660
+ // if (taskQueue.len === 0) return (this.isScheduling = false);
661
+ // // 任务列表中还有任务
662
+ // ide(this.scheduleTask.bind(this));
663
+ // }
664
+ // }
665
+ /** scope 捕获,引用外部 signal 孤岛 */
666
+ const unTrackIsland = signal => {
667
+ // 原来是孤岛,且被 scope 管理的要恢复
668
+ if (signal.emitStart && signal.emitStart.downstream === signal.scope) {
669
+ Line.unlink(signal.emitStart);
670
+ }
671
+ };
672
+ /** scope 释放,被重新连接的孤岛 */
673
+ const trackIsland = signal => {
674
+ const line = Line();
675
+ // 上游节点处于孤岛状态,切有引用外部信号,需要被 scope 管理来删除外部依赖
676
+ if (!signal.emitStart && signal.state & State.OutLink) {
677
+ const {
678
+ recEnd
679
+ } = signal.scope;
680
+ Line.emit_line(signal, line);
681
+ Line.rec_line(signal.scope, line);
682
+ Line.line_line_rec(recEnd, line);
683
+ }
684
+ };
685
+ const markOutLink = (signal, downstream) => {
686
+ // 上游是外部节点,或者上游引用了外部节点的, 做传播
687
+ if (signal.scope !== downstream.scope || signal.state & State.OutLink) {
688
+ downstream.state |= State.OutLink;
689
+ }
690
+ // else {
691
+ // downstream.state &= ~State.OutLink;
692
+ // }
693
+ };
694
+ const BreakErr = '_ERR_BREAK_';
695
+ let remain = {
696
+ stack: null,
697
+ node: null,
698
+ line: null
699
+ };
700
+ const ideScheduler = TaskQueue.create({
701
+ callbackAble: ide,
702
+ aIsUrgent(a, b) {
703
+ return a.index < b.index;
704
+ }
705
+ });
706
+ function handleOneTask(s, breakStack) {
707
+ breakStack = remain.stack || breakStack;
708
+ // 将 s 同步到 remainRoot
709
+ let lineToRemove = null;
710
+ const startTime = now();
711
+ try {
712
+ dfs(s, {
713
+ breakStack,
714
+ breakNode: remain.node,
715
+ breakLine: remain.line,
716
+ isUp: true,
717
+ begin: ({
718
+ walkedLine,
719
+ node,
720
+ lineFromUp
721
+ }) => {
722
+ if (lineToRemove) {
723
+ Line.unlink(lineToRemove);
724
+ lineToRemove = null;
725
+ }
726
+ if (now() - startTime > 5) {
727
+ remain = {
728
+ stack: walkedLine,
729
+ node: node,
730
+ line: lineFromUp
731
+ };
732
+ throw BreakErr;
733
+ }
734
+ if (!(node.state & State.OutLink)) {
735
+ return true;
736
+ }
737
+ // 对于嵌套作用域不允许重复进入
738
+ node.state &= ~State.OutLink;
739
+ },
740
+ complete: ({
741
+ node,
742
+ notGoDeep,
743
+ walkedLine
744
+ }) => {
745
+ if (lineToRemove) {
746
+ Line.unlink(lineToRemove);
747
+ lineToRemove = null;
748
+ }
749
+ if (notGoDeep) {
750
+ const last = walkedLine[walkedLine.length - 1];
751
+ const downstream = last === null || last === void 0 ? void 0 : last.downstream;
752
+ // 节点没被标记 OutLink 但是发现与下游节点的 scope 不一致,是需要解除 link 的位置
753
+ if (downstream && downstream.scope !== node.scope) {
754
+ lineToRemove = last;
755
+ }
756
+ }
757
+ }
758
+ });
759
+ remain = {
760
+ stack: null,
761
+ node: null,
762
+ line: null
763
+ };
764
+ } catch (error) {
765
+ if (error === BreakErr) return true;
766
+ remain = {
767
+ stack: null,
768
+ node: null,
769
+ line: null
770
+ };
771
+ throw error;
772
+ }
773
+ }
774
+ function unlinkRecWithScope(line) {
775
+ // 作为下游,执行完 get 上游节点已经完成了依赖更新,把 recEnd 后的依赖删除即可
776
+ let toDel = line;
777
+ while (toDel) {
778
+ const memoNext = toDel.nextRecLine;
779
+ const upstream = toDel.upstream;
780
+ Line.unlink(toDel);
781
+ // 删除完后看看是否要被 scope 管理
782
+ trackIsland(upstream);
783
+ toDel = memoNext;
784
+ }
785
+ }
786
+
787
+ function Signal_$$$_create(nextValue, {
788
+ customPull,
789
+ isScope,
790
+ ...rest
791
+ }) {
792
+ const s = Signal(nextValue, customPull);
793
+ s.pull = s.customPull || s.DEFAULT_PULL;
794
+ Object.assign(s, rest);
795
+ if (isScope) {
796
+ s.scope = s;
797
+ }
798
+ return s;
799
+ }
800
+ Signal.create = Signal_$$$_create;
801
+ const markDeep = signal => {
802
+ let level = 0;
803
+ dfs(signal, {
804
+ isUp: false,
805
+ begin: ({
806
+ node
807
+ }) => {
808
+ /**
809
+ * 1. 当前节点在预检 应该跳过
810
+ * 2. 当前节点 已标记
811
+ * 3. 当前节点 已放弃
812
+ */
813
+ // console.log('markBegin', node.id);
814
+ if (node.state & (State.Check | State.Unknown | State.Dirty) || node.isAbort()) {
815
+ return true;
816
+ }
817
+ const isEffect = level > 0;
818
+ const isLeaf = !node.emitStart || node.emitStart.downstream['scope'] === node.emitStart.downstream;
819
+ if (isEffect) {
820
+ node.state |= State.Unknown;
821
+ } else {
822
+ node.state |= State.Dirty;
823
+ }
824
+ if (isLeaf && isEffect) {
825
+ dirtyLeafs.add(node.scheduler, node);
826
+ }
827
+ level++;
828
+ }
829
+ });
830
+ for (const key in dirtyLeafs.data) {
831
+ const effects = dirtyLeafs.data[key];
832
+ const scheduler = _scheduler[key];
833
+ scheduler(effects);
834
+ }
835
+ dirtyLeafs.clear();
836
+ };
837
+ function Signal(nextValue,
838
+ /** 为什么是 shallow,因为 pullDeep 会把
839
+ * 上游节点 get 执行完成,让其可以直接拿到缓存值
840
+ */
841
+ customPull) {
842
+ return {
843
+ nextValue: nextValue,
844
+ customPull: customPull,
845
+ version: -1,
846
+ id: G.id++,
847
+ state: State.Clean,
848
+ scope: Signal.Pulling,
849
+ recEnd: null,
850
+ recStart: null,
851
+ emitStart: null,
852
+ emitEnd: null,
853
+ scheduler: null,
854
+ value: null,
855
+ pull: null,
856
+ DEFAULT_PULL: Signal_$$$_DEFAULT_PULL,
857
+ pullRecurse: Signal_$$$_pullRecurse,
858
+ pullDeep: Signal_$$$_pullDeep,
859
+ get: Signal_$$$_get,
860
+ markDownStreamsDirty: Signal_$$$_markDownStreamsDirty,
861
+ set: Signal_$$$_set,
862
+ run: Signal_$$$_run,
863
+ runIfDirty: Signal_$$$_runIfDirty,
864
+ isAbort: Signal_$$$_isAbort
865
+ };
866
+ }
867
+ function Signal_$$$_DEFAULT_PULL() {
868
+ return this.nextValue;
869
+ }
870
+ function Signal_$$$_pullRecurse(shouldLink = true) {
871
+ var _a;
872
+ let downstream = Signal.Pulling;
873
+ if (shouldLink && downstream) {
874
+ // 如果上游节点被 scope 管理了,解除管理
875
+ unTrackIsland(this);
876
+ Line.link(this, downstream);
877
+ }
878
+ try {
879
+ if (this.version === G.version) {
880
+ return this.value;
881
+ }
882
+ this.state &= ~State.OutLink;
883
+ // 进 pullShallow 前重置 recEnd,让子 getter 重构订阅链表
884
+ this.recEnd = undefined;
885
+ Signal.Pulling = this;
886
+ const v = this.pull();
887
+ // 如果使用了 DEFAULT_PULL,处理一次 set 的取值后,替换回 customPull,如果有的话
888
+ this.pull = this.customPull || this.DEFAULT_PULL;
889
+ this.value = v;
890
+ // 依赖上游的 版本号
891
+ this.version = G.version;
892
+ // if (this.value !== v) {
893
+ // }
894
+ return this.value;
895
+ } catch (error) {
896
+ console.error('计算属性报错这次不触发,后续状态可能出错', error);
897
+ return this.value;
898
+ } finally {
899
+ // 本 getter 执行完成时上游 getter 通过 link,完成对下游 recLines 的更新
900
+ const toDel = (_a = this.recEnd) === null || _a === void 0 ? void 0 : _a.nextRecLine;
901
+ unlinkRecWithScope(toDel);
902
+ if (shouldLink && downstream) {
903
+ // 用于 scope 指示哪些节点依赖 scope 外部
904
+ markOutLink(this, downstream);
905
+ }
906
+ Signal.Pulling = downstream;
907
+ }
908
+ }
909
+ function Signal_$$$_pullDeep() {
910
+ /*----------------- 有上游节点,通过 dfs 重新计算结果 -----------------*/
911
+ const signal = this;
912
+ // 优化执行
913
+ if (!(signal.state & DirtyState)) {
914
+ return this.value;
915
+ }
916
+ dfs(signal, {
917
+ isUp: true,
918
+ begin: ({
919
+ node
920
+ }) => {
921
+ // console.log('begin', node.id);
922
+ /**
923
+ * 不需要检查
924
+ * 1. 正在查
925
+ * 2. 干净
926
+ * 3. 放弃 或者为 scope 节点
927
+ */
928
+ if (node.state & State.Check || !(node.state & DirtyState) || node.isAbort()) {
929
+ return true;
930
+ }
931
+ node.state |= State.Check;
932
+ // 交给下游重新计算是否 引用外部节点
933
+ node.state &= ~State.OutLink;
934
+ },
935
+ complete: ({
936
+ node,
937
+ notGoDeep: currentClean,
938
+ walkedLine
939
+ }) => {
940
+ let noGoSibling = false;
941
+ const last = walkedLine[walkedLine.length - 1];
942
+ const downstream = last === null || last === void 0 ? void 0 : last.downstream;
943
+ // 当前正在检查,生成检查屏障,同时避免重新标记 和
944
+ if (currentClean) ;
945
+ // 当前节点需要重新计算
946
+ else if (node.state & State.Dirty) {
947
+ // 优化:源节点变化,直接让下游节点重新计算
948
+ if (!node.recStart && node.value !== node.nextValue) {
949
+ node.markDownStreamsDirty();
950
+ node.state &= ~State.Dirty;
951
+ node.state &= ~State.Check;
952
+ return;
953
+ }
954
+ // 预检数据
955
+ else {
956
+ const prevPulling = Signal.Pulling;
957
+ Signal.Pulling = downstream;
958
+ const prevValue = node.value;
959
+ // 递归转用递归拉取,且不需要重建 link 因为dfs的前提就是上游节点依赖于 本节点
960
+ node.pullRecurse(false);
961
+ // dirty 传播, 由于本节点值已被计算出,因此消除 dirty
962
+ if (prevValue !== node.value) {
963
+ node.markDownStreamsDirty();
964
+ }
965
+ node.state &= ~State.Dirty;
966
+ Signal.Pulling = prevPulling;
967
+ // 立刻返回父节点重新计算
968
+ noGoSibling = true;
969
+ }
970
+ }
971
+ // 没被上游节点标记为 Dirty,说明是干净的
972
+ else if (node.state & State.Unknown) {
973
+ node.state &= ~State.Unknown;
974
+ }
975
+ node.version = G.version;
976
+ node.state &= ~State.Check;
977
+ if (downstream) {
978
+ markOutLink(node, downstream);
979
+ }
980
+ return noGoSibling;
981
+ }
982
+ });
983
+ return this.value;
984
+ }
985
+ function Signal_$$$_get() {
986
+ if (this.isAbort()) {
987
+ return this.value;
988
+ }
989
+ // 没有上游节点,应该通过递归重新建立
990
+ if (!this.recStart) {
991
+ return this.pullRecurse(true);
992
+ }
993
+ // 有上游节点则采用 dfs 直接遍历,查看情况
994
+ return this.pullDeep();
995
+ }
996
+ function Signal_$$$_markDownStreamsDirty() {
997
+ let point = this.emitStart;
998
+ while (point != null) {
999
+ const downstream = point.downstream;
1000
+ downstream.state |= State.Dirty;
1001
+ downstream.state &= ~State.Unknown;
1002
+ point = point.nextEmitLine;
1003
+ }
1004
+ }
1005
+ function Signal_$$$_set(v) {
1006
+ if (this.isAbort() || this.nextValue === v) {
1007
+ return;
1008
+ }
1009
+ this.nextValue = v;
1010
+ // 手动设值后,采用默认拉取,能拉取到设置的值,拉取完成后在替换回 customPull
1011
+ this.pull = this.DEFAULT_PULL;
1012
+ G.version++;
1013
+ markDeep(this);
1014
+ }
1015
+ function Signal_$$$_run(...args) {
1016
+ if (args.length) {
1017
+ return this.set(args[0]);
1018
+ }
1019
+ return this.get();
1020
+ }
1021
+ function Signal_$$$_runIfDirty() {
1022
+ this.state & (State.Unknown | State.Dirty) && this.run();
1023
+ }
1024
+ function Signal_$$$_isAbort() {
1025
+ return (
1026
+ // scope 被取消
1027
+ this.scope && this.scope.state & State.ScopeAbort ||
1028
+ // 是 scope 节点,且处于 ready 状态,不需要重复执行
1029
+ this === this.scope && this.state & (State.ScopeAbort | State.ScopeReady)
1030
+ );
1031
+ }
1032
+ Signal.Pulling = null;
1033
+ function runWithPulling(fn, signal) {
1034
+ const prevPulling = Signal.Pulling;
1035
+ Signal.Pulling = signal;
1036
+ fn();
1037
+ Signal.Pulling = prevPulling;
1038
+ }
1039
+
1040
+ const DefaultCustomSignalOpt = {
1041
+ scheduler: exports.Scheduler.Sync,
1042
+ isScope: false
1043
+ };
1044
+ const $ = (init, opt = {}) => {
1045
+ let intiValue, pull;
1046
+ if (init instanceof Function) {
1047
+ intiValue = undefined;
1048
+ pull = init;
1049
+ } else {
1050
+ intiValue = init;
1051
+ }
1052
+ const signalOpt = {
1053
+ ...DefaultCustomSignalOpt,
1054
+ ...opt,
1055
+ customPull: pull
1056
+ };
1057
+ const s = Signal.create(intiValue, signalOpt);
1058
+ const bound = s.run.bind(s);
1059
+ bound.ins = s;
1060
+ Object.defineProperty(bound, 'v', {
1061
+ get() {
1062
+ return s.get();
1063
+ },
1064
+ set(v) {
1065
+ return s.set(v);
1066
+ }
1067
+ });
1068
+ return bound;
1069
+ };
1070
+ const watch = (values, watcher, opt) => {
1071
+ let mounted = false;
1072
+ const get = $(() => {
1073
+ for (const get of values) {
1074
+ get();
1075
+ }
1076
+ if (mounted) {
1077
+ runWithPulling(watcher, undefined);
1078
+ }
1079
+ mounted = true;
1080
+ }, opt);
1081
+ get();
1082
+ return get;
1083
+ };
1084
+ const scope = fn => {
1085
+ const s = Signal.create(undefined, {
1086
+ customPull: fn,
1087
+ isScope: true
1088
+ });
1089
+ s.get();
1090
+ s.state |= State.ScopeReady;
1091
+ function dispose() {
1092
+ s.state |= State.ScopeAbort;
1093
+ const bound = handleOneTask.bind(undefined, s, []);
1094
+ bound.index = G.scopeDisposeI++;
1095
+ ideScheduler.pushTask(bound);
1096
+ }
1097
+ dispose.ins = s;
1098
+ return dispose;
1099
+ };
1100
+ /**
1101
+ * 数据变化时,自定义 触发订阅函数的时机
1102
+ * @param {CustomSignalOpt} opt 配置如下:
1103
+ * @prop scheduler: (runIfDirty, effect) => void 执行 runIfDirty 定制触发 effect 时机
1104
+ * @prop scope: 用于统一释放 effect link 的作用域 默认是 defaultScope 可以全局获取
1105
+ */
1106
+ const customSignal = opt => {
1107
+ return (init, innerOpt = {}) => {
1108
+ const s = $(init, {
1109
+ ...opt,
1110
+ ...innerOpt
1111
+ });
1112
+ return s;
1113
+ };
1114
+ };
1115
+
1116
+ exports.$ = $;
1117
+ exports.customSignal = customSignal;
1118
+ exports.scheduler = scheduler;
1119
+ exports.scope = scope;
1120
+ exports.watch = watch;