Repository navigation
Expand file tree
/
Copy pathindex.js
More file actions
95 lines (89 loc) · 3.07 KB
/
Copy pathindex.js
File metadata and controls
95 lines (89 loc) · 3.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
export function createAsPipes() {
const stack = [];
// Symbol to mark objects as pipe tokens
const PIPE_TOKEN = Symbol('aspipes.token');
const asPipe = (fnOrObj) => {
// If it's an object, return a proxy that makes all methods pipeable
if (typeof fnOrObj === 'object' && fnOrObj !== null && typeof fnOrObj !== 'function') {
return new Proxy({}, {
get(_, prop) {
if (typeof fnOrObj[prop] === 'function') {
// Don't bind prototype methods - they need the actual value as 'this'
if (fnOrObj.constructor === Object ||
fnOrObj === Array.prototype ||
fnOrObj.constructor === Function) {
return asPipe(fnOrObj[prop]);
}
return asPipe(fnOrObj[prop].bind(fnOrObj));
}
return fnOrObj[prop];
}
});
}
// Original function behavior
const fn = fnOrObj;
return new Proxy(function () {}, {
get(_, prop) {
if (prop === Symbol.toPrimitive)
return () => (
stack.at(-1).steps.push(async (v) => {
const before = stack.length;
const result = await Promise.resolve(fn(v));
if (result === 0 && stack.length > before) {
const ctx = stack.pop();
return await ctx.steps.reduce(
(p, f) => p.then(f),
Promise.resolve(ctx.v),
);
}
// Only auto-execute if it's actually a pipe token
if (result && result[PIPE_TOKEN] && typeof result.run === 'function')
return await result.run();
return result;
}),
0
);
},
apply(_, __, args) {
const t = function () {};
t[Symbol.toPrimitive] = () => (
stack.at(-1).steps.push(async (v) => {
const before = stack.length;
const result = await Promise.resolve(fn(v, ...args));
if (result === 0 && stack.length > before) {
const ctx = stack.pop();
return await ctx.steps.reduce(
(p, f) => p.then(f),
Promise.resolve(ctx.v),
);
}
// Only auto-execute if it's actually a pipe token
if (result && result[PIPE_TOKEN] && typeof result.run === 'function')
return await result.run();
return result;
}),
0
);
return t;
},
});
};
const pipe = (x) => {
const ctx = { v: x, steps: [], token: null };
const token = {
[PIPE_TOKEN]: true, // Mark this as a pipe token
[Symbol.toPrimitive]: () => (stack.push(ctx), 0),
async run() {
return ctx.steps.reduce((p, f) => p.then(f), Promise.resolve(ctx.v));
},
};
ctx.token = token;
return token;
};
// fångar den pipeline som just byggdes av ett |-uttryck
const take = (_ignored) => {
const ctx = stack.pop();
return ctx?.token ?? _ignored; // om inget på stacken, returnera originalet
};
return { pipe, asPipe, take };
}