rooklang 0.3.1 → 0.3.2
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.
- package/README.md +17 -4
- package/README.ru.md +17 -4
- package/dist/ast/expressions.d.ts +16 -1
- package/dist/ast/markup.d.ts +6 -1
- package/dist/browser.d.ts +5 -0
- package/dist/browser.js +1 -0
- package/dist/checker/base.js +4 -4
- package/dist/checker/builtins.js +4 -35
- package/dist/checker/bytes.d.ts +2 -2
- package/dist/checker/bytes.js +2 -2
- package/dist/checker/channels.d.ts +3 -0
- package/dist/checker/channels.js +39 -1
- package/dist/checker/expressions.d.ts +2 -0
- package/dist/checker/expressions.js +4 -0
- package/dist/checker/helpers.js +2 -0
- package/dist/checker/queues.d.ts +6 -0
- package/dist/checker/queues.js +24 -0
- package/dist/checker/resolution.js +6 -2
- package/dist/checker/transfer.js +4 -1
- package/dist/checker/types/printing.js +7 -0
- package/dist/checker/types/queue.d.ts +6 -0
- package/dist/checker/types/queue.js +42 -0
- package/dist/checker/types/relations.js +12 -1
- package/dist/checker/types.d.ts +1 -0
- package/dist/checker/types.js +1 -0
- package/dist/checker/untyped-globals.d.ts +1 -0
- package/dist/checker/untyped-globals.js +47 -0
- package/dist/codegen/attributes.js +0 -1
- package/dist/codegen/calls.d.ts +9 -0
- package/dist/codegen/calls.js +41 -1
- package/dist/codegen/component-values.js +0 -1
- package/dist/codegen/components.js +0 -1
- package/dist/codegen/control-flow.js +0 -3
- package/dist/codegen/control-statements.js +0 -4
- package/dist/codegen/creation.d.ts +6 -8
- package/dist/codegen/creation.js +1 -10
- package/dist/codegen/early-returns.js +0 -1
- package/dist/codegen/elements.js +0 -3
- package/dist/codegen/emitter.d.ts +3 -5
- package/dist/codegen/emitter.js +0 -2
- package/dist/codegen/expressions.d.ts +4 -1
- package/dist/codegen/expressions.js +9 -13
- package/dist/codegen/functions.js +0 -2
- package/dist/codegen/js.d.ts +0 -7
- package/dist/codegen/js.js +33 -59
- package/dist/codegen/parallel.js +2 -4
- package/dist/codegen/refs.js +0 -1
- package/dist/codegen/runtime.d.ts +15 -0
- package/dist/codegen/runtime.js +99 -0
- package/dist/codegen/simple-statements.js +3 -1
- package/dist/codegen/styles.d.ts +1 -1
- package/dist/codegen/styles.js +2 -2
- package/dist/codegen/web-components.js +0 -1
- package/dist/compile.d.ts +7 -0
- package/dist/compile.js +1 -0
- package/dist/completion.js +2 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/loader.js +8 -0
- package/dist/parser/base.d.ts +3 -1
- package/dist/parser/expressions.js +9 -2
- package/dist/parser/literals.d.ts +7 -0
- package/dist/parser/literals.js +45 -1
- package/dist/parser/simple-statements.js +3 -0
- package/dist/parser/types.d.ts +1 -1
- package/dist/parser/types.js +10 -3
- package/dist/runtime/sources.d.ts +2 -0
- package/dist/runtime/sources.js +14 -0
- package/dist/ts-types.js +9 -1
- package/dist/vite.js +7 -1
- package/dist/walk-types.js +1 -0
- package/dist/walk.js +9 -0
- package/package.json +6 -4
- package/src/runtime/chan.js +277 -0
- package/src/runtime/core.js +23 -0
- package/src/runtime/go.js +334 -0
- package/src/runtime/index.js +13 -0
- package/src/runtime/markup.js +336 -0
- package/src/runtime/queue.js +118 -0
- package/src/runtime/select.js +170 -0
- package/src/runtime/streams.js +61 -0
- package/src/runtime/threads.js +240 -0
- package/src/runtime/timers.js +27 -0
- package/dist/codegen/chan-helpers.d.ts +0 -2
- package/dist/codegen/chan-helpers.js +0 -253
- package/dist/codegen/go-helpers.d.ts +0 -9
- package/dist/codegen/go-helpers.js +0 -307
- package/dist/codegen/helpers.d.ts +0 -10
- package/dist/codegen/helpers.js +0 -356
- package/dist/codegen/select-helpers.d.ts +0 -2
- package/dist/codegen/select-helpers.js +0 -135
- package/dist/codegen/thread-helpers.d.ts +0 -2
- package/dist/codegen/thread-helpers.js +0 -198
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
// `select`. Its cases may wait in channels of several threads; a channel that can go on with a case
|
|
2
|
-
// asks the thread of the select to lock it first, so that only one case goes on, as Go locks the
|
|
3
|
-
// channels of a select.
|
|
4
|
-
export const SELECT_HELPERS = {
|
|
5
|
-
select: [
|
|
6
|
-
'// `select`: the index of the case that went on, and what it received. A case is { channel } to',
|
|
7
|
-
'// receive or { channel, value } to send; from another thread, { channel, send, value }. One that',
|
|
8
|
-
'// can go on at once wins, a random one as in Go; else `default`, -1, if there is one; else the',
|
|
9
|
-
'// first that can go on later. A case with a null channel never goes on.',
|
|
10
|
-
'async function $$select(cases, hasDefault) {',
|
|
11
|
-
' const registry = $$registry();',
|
|
12
|
-
' const all = cases.map((each, i) => ({',
|
|
13
|
-
' i,',
|
|
14
|
-
' id: typeof each.channel === "string" ? each.channel : (each.channel?.$$chan ?? null),',
|
|
15
|
-
' send: each.send ?? "value" in each,',
|
|
16
|
-
' value: each.value,',
|
|
17
|
-
' }));',
|
|
18
|
-
' const live = all.filter(({ id }) => id !== null);',
|
|
19
|
-
' const owners = new Set(live.map(({ id }) => $$ownerOf(id)));',
|
|
20
|
-
' // The channels of one other thread: the select runs there.',
|
|
21
|
-
' if (owners.size === 1 && !owners.has(registry.key)) {',
|
|
22
|
-
' const [owner] = owners;',
|
|
23
|
-
' return $$ask(owner, { op: "select", cases: all.map(({ id: channel, send, value }) => ({ channel, send, value })), hasDefault });',
|
|
24
|
-
' }',
|
|
25
|
-
' const order = live.map(({ i }) => i).sort(() => Math.random() - 0.5);',
|
|
26
|
-
' for (const i of order) {',
|
|
27
|
-
' const { id, send, value } = all[i];',
|
|
28
|
-
' const owner = $$ownerOf(id);',
|
|
29
|
-
' const ready =',
|
|
30
|
-
' owner === registry.key',
|
|
31
|
-
' ? $$try(id, send, value)',
|
|
32
|
-
' : await $$ask(owner, { op: "try", channel: id, send, value });',
|
|
33
|
-
' if (ready) return [i, ...ready];',
|
|
34
|
-
' }',
|
|
35
|
-
' if (hasDefault) return [-1];',
|
|
36
|
-
' return new Promise((resolve, reject) => {',
|
|
37
|
-
' const sid = registry.asks++;',
|
|
38
|
-
' const channels = new Map();',
|
|
39
|
-
' registry.selects.set(sid, { locked: false, resolve, reject, channels });',
|
|
40
|
-
' live.forEach(({ i, id, send, value }) => {',
|
|
41
|
-
' const owner = $$ownerOf(id);',
|
|
42
|
-
' if (!channels.has(owner)) channels.set(owner, []);',
|
|
43
|
-
' channels.get(owner).push(id);',
|
|
44
|
-
' if (owner === registry.key) {',
|
|
45
|
-
' const entry = { select: { key: owner, sid }, case: i, value };',
|
|
46
|
-
' registry.states.get(id)[send ? "senders" : "receivers"].push(entry);',
|
|
47
|
-
' } else {',
|
|
48
|
-
' $$post(owner, { op: "wait", sid, case: i, channel: id, send, value });',
|
|
49
|
-
' }',
|
|
50
|
-
' });',
|
|
51
|
-
' for (const owner of channels.keys()) if (owner !== registry.key) $$pin(owner, 1);',
|
|
52
|
-
' for (const id of channels.get(registry.key) ?? []) $$pump(id);',
|
|
53
|
-
' });',
|
|
54
|
-
'}',
|
|
55
|
-
'',
|
|
56
|
-
'// What a case of a select gets at once, if it can go on: [] for a send, [value, ok] for a receive.',
|
|
57
|
-
'// A receiver or sender that a select of another thread waits with is left to $$pump.',
|
|
58
|
-
'function $$try(id, send, value) {',
|
|
59
|
-
' const state = $$registry().states.get(id);',
|
|
60
|
-
' if (!state) throw $$stopped();',
|
|
61
|
-
' if (state.busy) return null;',
|
|
62
|
-
' if (send && state.closed) throw new Error("send on a closed channel");',
|
|
63
|
-
' if (!send && state.buffer.length > 0) {',
|
|
64
|
-
' const received = state.buffer.shift();',
|
|
65
|
-
' $$pump(id);',
|
|
66
|
-
' return [received, true];',
|
|
67
|
-
' }',
|
|
68
|
-
' const queue = send ? state.receivers : state.senders;',
|
|
69
|
-
' while (queue.length > 0) {',
|
|
70
|
-
' const [entry] = queue;',
|
|
71
|
-
' if (entry.select && entry.select.key !== $$registry().key) break;',
|
|
72
|
-
' const lock = entry.select ? $$lock(entry.select.sid) : "locked";',
|
|
73
|
-
' if (lock === "busy") break;',
|
|
74
|
-
' queue.shift();',
|
|
75
|
-
' if (lock === "done") continue;',
|
|
76
|
-
' if (!send) {',
|
|
77
|
-
' $$finish(entry);',
|
|
78
|
-
' return [entry.value, true];',
|
|
79
|
-
' }',
|
|
80
|
-
' $$finish(entry, [value, true]);',
|
|
81
|
-
' return [];',
|
|
82
|
-
' }',
|
|
83
|
-
' if (send && state.buffer.length < state.size) {',
|
|
84
|
-
' state.buffer.push(value);',
|
|
85
|
-
' $$pump(id);',
|
|
86
|
-
' return [];',
|
|
87
|
-
' }',
|
|
88
|
-
' return !send && state.closed ? [Array.isArray(state.zero) ? [] : state.zero, false] : null;',
|
|
89
|
-
'}',
|
|
90
|
-
'',
|
|
91
|
-
'// The thread of a select decides which of its cases goes on: a channel locks the select, then',
|
|
92
|
-
'// commits a case or unlocks it.',
|
|
93
|
-
'function $$lock(sid) {',
|
|
94
|
-
' const select = $$registry().selects.get(sid);',
|
|
95
|
-
' if (!select) return "done";',
|
|
96
|
-
' if (select.locked) return "busy";',
|
|
97
|
-
' select.locked = true;',
|
|
98
|
-
' return "locked";',
|
|
99
|
-
'}',
|
|
100
|
-
'',
|
|
101
|
-
'function $$unlock(sid) {',
|
|
102
|
-
' const select = $$registry().selects.get(sid);',
|
|
103
|
-
' if (select) select.locked = false;',
|
|
104
|
-
'}',
|
|
105
|
-
'',
|
|
106
|
-
'function $$commit(sid, i, result, error) {',
|
|
107
|
-
' const registry = $$registry();',
|
|
108
|
-
' const select = registry.selects.get(sid);',
|
|
109
|
-
' if (!select) return;',
|
|
110
|
-
' registry.selects.delete(sid);',
|
|
111
|
-
' // The other cases leave the queues of their channels.',
|
|
112
|
-
' for (const [owner, channels] of select.channels) {',
|
|
113
|
-
' if (owner === registry.key) {',
|
|
114
|
-
' $$unwait({ key: owner, sid }, channels);',
|
|
115
|
-
' } else {',
|
|
116
|
-
' $$post(owner, { op: "cancel", sid, channels });',
|
|
117
|
-
' $$pin(owner, -1);',
|
|
118
|
-
' }',
|
|
119
|
-
' }',
|
|
120
|
-
' if (error) select.reject(error);',
|
|
121
|
-
' else select.resolve([i, ...(result ?? [])]);',
|
|
122
|
-
'}',
|
|
123
|
-
'',
|
|
124
|
-
'function $$unwait(select, channels) {',
|
|
125
|
-
' const { states } = $$registry();',
|
|
126
|
-
' const other = (entry) => entry.select?.key !== select.key || entry.select.sid !== select.sid;',
|
|
127
|
-
' for (const id of channels) {',
|
|
128
|
-
' const state = states.get(id);',
|
|
129
|
-
' if (!state) continue;',
|
|
130
|
-
' state.receivers = state.receivers.filter(other);',
|
|
131
|
-
' state.senders = state.senders.filter(other);',
|
|
132
|
-
' }',
|
|
133
|
-
'}',
|
|
134
|
-
],
|
|
135
|
-
};
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
// What threads share: a channel is data, `{ $$chan: id, size, zero }`, copied to other threads like
|
|
2
|
-
// any value, and what it holds lives in the thread that made it, whose key starts its id. Each
|
|
3
|
-
// thread has a registry of its channels and of its ports to the other threads, shared by its
|
|
4
|
-
// modules; the operations of a thread on the channels of another go straight to that thread
|
|
5
|
-
// through a MessagePort, which the main thread sets up on the first need (go-helpers.ts).
|
|
6
|
-
export const THREAD_HELPERS = {
|
|
7
|
-
threads: [
|
|
8
|
-
'// The state of this thread that its modules share: the channels it made, its ports to the other',
|
|
9
|
-
'// threads by their keys, and the requests that wait for an answer.',
|
|
10
|
-
'function $$registry() {',
|
|
11
|
-
' return (globalThis[Symbol.for("rook.threads")] ??= {',
|
|
12
|
-
' key: Math.random().toString(36).slice(2),',
|
|
13
|
-
' channels: 0,',
|
|
14
|
-
' states: new Map(),',
|
|
15
|
-
' held: new FinalizationRegistry((id) => $$hold(id, -1)),',
|
|
16
|
-
' ports: new Map(),',
|
|
17
|
-
' pins: new Map(),',
|
|
18
|
-
' idle: null,',
|
|
19
|
-
' waiting: new Map(),',
|
|
20
|
-
' gone: new Set(),',
|
|
21
|
-
' main: null,',
|
|
22
|
-
' requests: new Map(),',
|
|
23
|
-
' asks: 0,',
|
|
24
|
-
' selects: new Map(),',
|
|
25
|
-
' moved: new WeakSet(),',
|
|
26
|
-
' cancels: new WeakMap(),',
|
|
27
|
-
' handle: null,',
|
|
28
|
-
' });',
|
|
29
|
-
'}',
|
|
30
|
-
'',
|
|
31
|
-
'// The key of the thread that made a channel, which keeps what it holds.',
|
|
32
|
-
'function $$ownerOf(id) {',
|
|
33
|
-
' return id.slice(0, id.lastIndexOf(":"));',
|
|
34
|
-
'}',
|
|
35
|
-
'',
|
|
36
|
-
'// Sends a message to a thread. The channels in it are counted first, as the thread gets copies,',
|
|
37
|
-
'// and the buffers of transfer() move there. A message waits for the port of a thread that has just',
|
|
38
|
-
'// started.',
|
|
39
|
-
'function $$post(key, message) {',
|
|
40
|
-
' const registry = $$registry();',
|
|
41
|
-
' if (registry.gone.has(key)) return;',
|
|
42
|
-
' const { channels, moved } = $$walk(message);',
|
|
43
|
-
' for (const channel of channels) $$hold(channel.$$chan, 1);',
|
|
44
|
-
' const port = registry.ports.get(key);',
|
|
45
|
-
' if (port) return port.postMessage(message, moved);',
|
|
46
|
-
' if (!registry.waiting.has(key)) registry.waiting.set(key, []);',
|
|
47
|
-
' registry.waiting.get(key).push([message, moved]);',
|
|
48
|
-
'}',
|
|
49
|
-
'',
|
|
50
|
-
'// A request to a thread, answered by a message with its number.',
|
|
51
|
-
'function $$ask(key, message) {',
|
|
52
|
-
' const registry = $$registry();',
|
|
53
|
-
' if (registry.gone.has(key)) return Promise.reject($$stopped());',
|
|
54
|
-
' $$pin(key, 1);',
|
|
55
|
-
' return new Promise((resolve, reject) => {',
|
|
56
|
-
' const ask = registry.asks++;',
|
|
57
|
-
' registry.requests.set(ask, { resolve, reject, key });',
|
|
58
|
-
' $$post(key, { ...message, ask });',
|
|
59
|
-
' });',
|
|
60
|
-
'}',
|
|
61
|
-
'',
|
|
62
|
-
'// A thread that this one waits for keeps the program running: in Node, its worker or port is',
|
|
63
|
-
'// referenced while some request or select waits for it.',
|
|
64
|
-
'function $$pin(key, count) {',
|
|
65
|
-
' const registry = $$registry();',
|
|
66
|
-
' const pins = (registry.pins.get(key) ?? 0) + count;',
|
|
67
|
-
' registry.pins.set(key, pins);',
|
|
68
|
-
' const port = registry.ports.get(key);',
|
|
69
|
-
' if (pins > 0) port?.ref?.();',
|
|
70
|
-
' else if (registry.idle) registry.idle(key);',
|
|
71
|
-
' else port?.unref?.();',
|
|
72
|
-
'}',
|
|
73
|
-
'',
|
|
74
|
-
'function $$stopped() {',
|
|
75
|
-
' return new Error("the goroutine that made the channel has stopped");',
|
|
76
|
-
'}',
|
|
77
|
-
'',
|
|
78
|
-
'// A port to a thread: messages that waited for it go now.',
|
|
79
|
-
'function $$connect(key, port, listen) {',
|
|
80
|
-
' const registry = $$registry();',
|
|
81
|
-
' registry.ports.set(key, port);',
|
|
82
|
-
' if (registry.pins.get(key) > 0) port.ref?.();',
|
|
83
|
-
' if (listen) {',
|
|
84
|
-
' const receive = (data) => $$incoming(key, data);',
|
|
85
|
-
' if (port.on) {',
|
|
86
|
-
' port.on("message", receive);',
|
|
87
|
-
' if (!(registry.pins.get(key) > 0)) port.unref?.();',
|
|
88
|
-
' } else {',
|
|
89
|
-
' port.onmessage = (event) => receive(event.data);',
|
|
90
|
-
' }',
|
|
91
|
-
' }',
|
|
92
|
-
' for (const [message, moved] of registry.waiting.get(key) ?? []) port.postMessage(message, moved);',
|
|
93
|
-
' registry.waiting.delete(key);',
|
|
94
|
-
'}',
|
|
95
|
-
'',
|
|
96
|
-
'// A thread has stopped: what waits for it fails, and what it waited for is dropped.',
|
|
97
|
-
'function $$gone(key) {',
|
|
98
|
-
' const registry = $$registry();',
|
|
99
|
-
' registry.gone.add(key);',
|
|
100
|
-
' registry.ports.get(key)?.close?.();',
|
|
101
|
-
' registry.ports.delete(key);',
|
|
102
|
-
' registry.waiting.delete(key);',
|
|
103
|
-
' for (const [ask, request] of registry.requests) {',
|
|
104
|
-
' if (request.key !== key) continue;',
|
|
105
|
-
' registry.requests.delete(ask);',
|
|
106
|
-
' request.reject($$stopped());',
|
|
107
|
-
' }',
|
|
108
|
-
' for (const [id, state] of registry.states) {',
|
|
109
|
-
' const alive = (entry) => (entry.select?.key ?? entry.from) !== key;',
|
|
110
|
-
' state.receivers = state.receivers.filter(alive);',
|
|
111
|
-
' state.senders = state.senders.filter(alive);',
|
|
112
|
-
' registry.handle?.pump(id);',
|
|
113
|
-
' }',
|
|
114
|
-
'}',
|
|
115
|
-
'',
|
|
116
|
-
'// A message from another thread: an answer to a request, or an operation on a channel of this one.',
|
|
117
|
-
'function $$incoming(key, data) {',
|
|
118
|
-
' const registry = $$registry();',
|
|
119
|
-
' $$adopt(data);',
|
|
120
|
-
' if ("answer" in data) {',
|
|
121
|
-
' const request = registry.requests.get(data.answer);',
|
|
122
|
-
' registry.requests.delete(data.answer);',
|
|
123
|
-
' if (request) $$pin(request.key, -1);',
|
|
124
|
-
' if ("error" in data) request?.reject(data.error);',
|
|
125
|
-
' else request?.resolve(data.value);',
|
|
126
|
-
' } else if (data.op === "hold") {',
|
|
127
|
-
' $$hold(data.channel, data.count);',
|
|
128
|
-
' } else if ("op" in data) {',
|
|
129
|
-
' registry.handle.message(key, data);',
|
|
130
|
-
' }',
|
|
131
|
-
'}',
|
|
132
|
-
'',
|
|
133
|
-
'// Each value of a channel, in any thread, holds it: the thread that made it forgets it when none',
|
|
134
|
-
'// is left. A thread counts the channels of a value before a copy of it goes to another thread, and',
|
|
135
|
-
'// a copy lets go of them when it is collected.',
|
|
136
|
-
'function $$hold(id, count) {',
|
|
137
|
-
' const registry = $$registry();',
|
|
138
|
-
' const owner = $$ownerOf(id);',
|
|
139
|
-
' if (owner !== registry.key) return $$post(owner, { op: "hold", channel: id, count });',
|
|
140
|
-
' const state = registry.states.get(id);',
|
|
141
|
-
' if (!state) return;',
|
|
142
|
-
' state.holders += count;',
|
|
143
|
-
' if (state.holders <= 0) registry.states.delete(id);',
|
|
144
|
-
'}',
|
|
145
|
-
'',
|
|
146
|
-
'function $$adopt(value) {',
|
|
147
|
-
' const { held } = $$registry();',
|
|
148
|
-
' for (const channel of $$walk(value).channels) held.register(channel, channel.$$chan);',
|
|
149
|
-
'}',
|
|
150
|
-
'',
|
|
151
|
-
'// A copy in this thread. One that `own` the runtime, such as the arguments of `go` that wait for',
|
|
152
|
-
'// a worker, moves its buffers on.',
|
|
153
|
-
'function $$copy(value, own = false) {',
|
|
154
|
-
' const { channels, moved } = $$walk(value);',
|
|
155
|
-
' for (const channel of channels) $$hold(channel.$$chan, 1);',
|
|
156
|
-
' const copy = structuredClone(value, { transfer: moved });',
|
|
157
|
-
' const { held } = $$registry();',
|
|
158
|
-
' for (const channel of $$walk(copy, own).channels) held.register(channel, channel.$$chan);',
|
|
159
|
-
' return copy;',
|
|
160
|
-
'}',
|
|
161
|
-
'',
|
|
162
|
-
'// `transfer(x)`: the buffer of x moves to the thread that a value with it goes to, instead of a',
|
|
163
|
-
'// copy; here it is left empty.',
|
|
164
|
-
'function $$transfer(value) {',
|
|
165
|
-
' $$registry().moved.add(ArrayBuffer.isView(value) ? value.buffer : value);',
|
|
166
|
-
' return value;',
|
|
167
|
-
'}',
|
|
168
|
-
'',
|
|
169
|
-
'// The channels in a value, each of which becomes a copy in the thread that gets the value, and the',
|
|
170
|
-
'// buffers that move there.',
|
|
171
|
-
'function $$walk(value, own = false, found = { channels: new Set(), moved: [] }, seen = new Set()) {',
|
|
172
|
-
' if (typeof value !== "object" || value === null || seen.has(value)) return found;',
|
|
173
|
-
' seen.add(value);',
|
|
174
|
-
' const buffer =',
|
|
175
|
-
' value instanceof ArrayBuffer ? value : ArrayBuffer.isView(value) ? value.buffer : null;',
|
|
176
|
-
' // A SharedArrayBuffer is shared with the other thread, not moved.',
|
|
177
|
-
' if (buffer && !(buffer instanceof ArrayBuffer)) return found;',
|
|
178
|
-
' if (buffer) {',
|
|
179
|
-
' const { moved } = $$registry();',
|
|
180
|
-
' if (own) moved.add(buffer);',
|
|
181
|
-
' if (moved.has(buffer) && !found.moved.includes(buffer)) found.moved.push(buffer);',
|
|
182
|
-
' return found;',
|
|
183
|
-
' }',
|
|
184
|
-
' if (typeof value.$$chan === "string") {',
|
|
185
|
-
' found.channels.add(value);',
|
|
186
|
-
' return found;',
|
|
187
|
-
' }',
|
|
188
|
-
' const items =',
|
|
189
|
-
' value instanceof Map',
|
|
190
|
-
' ? [...value.keys(), ...value.values()]',
|
|
191
|
-
' : value instanceof Set || Array.isArray(value)',
|
|
192
|
-
' ? value',
|
|
193
|
-
' : Object.values(value);',
|
|
194
|
-
' for (const item of items) $$walk(item, own, found, seen);',
|
|
195
|
-
' return found;',
|
|
196
|
-
'}',
|
|
197
|
-
],
|
|
198
|
-
};
|