Skip to content

Commit f0bc2e2

Browse files
authored
Add files via upload
1 parent c74e0e9 commit f0bc2e2

File tree

3 files changed

+83
-103
lines changed

3 files changed

+83
-103
lines changed

chute.js

Lines changed: 80 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const chute = (()=>{
2-
/* https://gregabbott.github.io/chute By + Copyright Greg Abbott
3-
[V1=2024-11-27][V=2024-12-07.2]*/
2+
/* https://gregabbott.github.io/chute By + (C) Greg Abbott
3+
[V1=2024-11-27][V=2024-12-07.3]*/
44
const stringy=x=>JSON.stringify(x),
55
error=(...x)=>{throw new Error(x)},
66
is_fn=x=>x instanceof Function,
@@ -10,57 +10,50 @@ is_object=v=>v&& typeof v=='object'&&!Array.isArray(v),
1010
is_js_method=(o,k)=>is_fn(Object.getPrototypeOf(o)[k]),
1111
is_global_fn=name=>is_fn(globalThis[name]),
1212
loop_o=f=>o=>{for(let k in o)if(f(k,o[k],o)===!1)break},
13+
lift_a_library =(k,v)=>{
14+
if(!is_object(v))return
15+
CHUTE.library[k]=v
16+
CHUTE.lifted_libraries.push(v)
17+
},
18+
lift_libraries=o=>{// hoist
19+
if(!is_object(o))error(`give .lift 1 object`)
20+
loop_o(lift_a_library)(o)
21+
},
22+
load_a_feed_item=(k,v)=>{
23+
if(is_fn(v)||is_object(v))CHUTE.library[k]=v
24+
},
25+
load_feed_items=o=>{
26+
if(!is_object(o))error(`give .feed 1 object`)
27+
loop_o(load_a_feed_item)(o)
28+
},
1329
chute_lib={},//Holds chute's own functions: log, tap, do, if
1430
PLACEHOLDER = {},//Sets data argument position in .fn calls.
15-
chutes=(seed,...args)=>new_chute({seed,args})//Becomes chute FN
16-
//`chute(seed)` calls chutes, returns new chute setup with seed
17-
chutes.x=PLACEHOLDER//Gives user access via `(chute_fn_name).x`
18-
chutes.library={}//Holds Fns FEED/LIFT gave to ALL chutes
19-
chutes.lifted_libraries=[]//Holds libs LIFT gives to all chutes
31+
CHUTE=(seed,...args)=>new_chute({seed,args})//Becomes chute FN
32+
//`chute(seed)` calls CHUTE, returns new chute setup with seed
33+
CHUTE.x=PLACEHOLDER//Gives user access via `(chute_fn_name).x`
34+
CHUTE.library={}//Holds Fns FEED/LIFT gave to ALL CHUTE
35+
CHUTE.lifted_libraries=[]//Holds libs LIFT gives to all CHUTE
2036
//lifted_libraries can call ".fn_name" and ".lib_name.fn_name"
21-
const load_library_given_to_lift =(k,v)=>{
22-
if(!is_object(v))return
23-
chutes.library[k]=v
24-
chutes.lifted_libraries.push(v)
25-
}
26-
function load_lift(o){// hoist
27-
if(!is_object(o)) error(`give .lift 1 object`)
28-
loop_o(load_library_given_to_lift)(o)
29-
}
30-
chutes.lift= load_lift
31-
const load_item_given_to_feed=(k,v)=>{
32-
if(is_fn(v)||is_object(v))chutes.library[k]=v
33-
}
34-
function load_feed(o){
35-
if(!is_object(o))error(`feed accepts an objects`)
36-
loop_o(load_item_given_to_feed)(o)
37-
}
38-
chutes.feed=load_feed
39-
function make_memoizer(a_chute){return f=>{
40-
let n = f.name,
41-
keep=n&&!is_global_fn(n)&&!a_chute.fns_seen[n]
42-
if(keep)a_chute.fns_seen[n]=f
43-
return f
44-
}}
37+
CHUTE.lift=lift_libraries
38+
CHUTE.feed=load_feed_items
4539
chute_lib.log=({args,data})=>{
4640
if(args.length>0){console.log(...args,data)}
4741
else console.log(data)
4842
return data
4943
}
5044
chute_lib.do=({args,data,a_chute})=>{//[f1,f2,f3]->f3(f2(f1(x)))
51-
if(args.length==0)error('.do needs 1+ arguments')
45+
if(args.length==0)error('give .do >0 arguments')//.log.do.log
5246
return args.reduce((data,arg)=>{
53-
if(arg==='log'){
54-
console.log(data)
55-
return data
56-
}
57-
else if(is_fn(arg)){
58-
a_chute.keep(arg)
59-
return arg(data)
60-
}
47+
if(arg==='log'){console.log(data);return data}
48+
else if(is_fn(arg)){a_chute.keep(arg);return arg(data)}
6149
return arg//Likely an expression result: `.do(variable*5)`
62-
}
63-
,data)
50+
},data)
51+
}
52+
const make_memoizer=a_chute=>f=>{
53+
let n = f.name
54+
let keep=n&&!is_global_fn(n)&&!a_chute.fns_seen[n]
55+
if(keep)a_chute.fns_seen[n]=f
56+
return f
6457
}
6558
const call_a_function=({fn,data,args})=>{
6659
if(args.length===0)return fn(data)
@@ -80,7 +73,7 @@ const chain_stopping_methods=new Set([
8073
'push',//returns new length
8174
'unshift',//returns new length
8275
])
83-
function is_condition_block(o){
76+
const is_condition_block=o=>{
8477
//Has {if:[q,a]} and any else_ifs have valid [q,a] pairs
8578
if(!is_object(o))return false
8679
if(!'if' in o)return false
@@ -98,7 +91,7 @@ function is_condition_block(o){
9891
//console.log(results)
9992
return Object.keys(results.invalid).length===0
10093
}
101-
function process_condition_block(c,data,a_chute) {
94+
const process_condition_block=(c,data,a_chute)=>{
10295
//Code below allows a user to provide `undefined` as a 'Then'
10396
//User may pass in non-global functions, in Ifs and or Thens:
10497
//Memoize these for dot-style calling in the same chute.
@@ -109,18 +102,14 @@ function process_condition_block(c,data,a_chute) {
109102
if(is_fn(q))a_chute.keep(q)
110103
if(is_fn(a))a_chute.keep(a)
111104
})
112-
function evaluate({condition,data}){
113-
if(is_fn(condition))return condition(data)
114-
return condition
105+
function evaluate({q,data}){
106+
if(is_fn(q))return q(data)
107+
return q
115108
}
116109
//Return returnable of first truthy match
117-
if(evaluate({condition:c.if[0],data})){
118-
return c.if[1]
119-
}
110+
if(evaluate({q:c.if[0],data}))return c.if[1]//answer
120111
if('else_if' in c){
121-
for (const [condition,then] of c.else_if){
122-
if (evaluate({condition,data})) return then
123-
}
112+
for(let[q,a] of c.else_if)if(evaluate({q,data}))return a
124113
}
125114
if('else' in c){
126115
if(is_fn(c.else))a_chute.keep(c.else)
@@ -166,17 +155,18 @@ chute_lib.with=({args,data,a_chute})=>{//configure a chute
166155
config=config[0]//settings object
167156
if(config.sync)load_sync_fn(config.sync,a_chute)
168157
if(config.skip_void)a_chute.skip_void=!!config.skip_void
169-
if(config.feed)load_feed(config.feed)
170-
if(config.lift)load_lift(config.lift)
158+
if(config.feed)load_feed_items(config.feed)
159+
if(config.lift)lift_libraries(config.lift)
171160
if(config.path)a_chute.treat_dots_as_paths=!!config.path
172161
return data//Leaves data unchanged
173162
}
174163
function load_sync_fn(o,a_chute){
175-
if(!is_fn(o))error(`"sync" takes "v=>external_variable=v"`)
164+
if(!is_fn(o))error(`give SYNC FN: "v=>user_variable=v"`)
176165
a_chute.sync_data=o
177-
a_chute.sync_data(a_chute.get_data())//Define external_variable
166+
a_chute.sync_data(a_chute.get_data())//Make user_variable!null
178167
}
179-
function handle_nested_access({keys,args,a_chute}){
168+
function handle_nested_access(a_chute,args){
169+
let dot_list = a_chute.dot_list
180170
let data = a_chute.get_data()
181171
let skip_void = a_chute.skip_void
182172
// This finds break points in a dot sequence.
@@ -197,20 +187,20 @@ function handle_nested_access({keys,args,a_chute}){
197187
if(seeded_chute)return['the_current_data',a.data]
198188
let memoised=a_chute.fns_seen[key]
199189
if(memoised)return['memoized_function',a_chute.fns_seen]
200-
if(chutes.library[key])return ['Feed_lib',chutes.library]
201-
let lifted_lib=chutes.lifted_libraries.find(lib=>lib[key])
190+
//X
191+
if(CHUTE.library[key])return ['Feed_lib',CHUTE.library]
192+
let lifted_lib=CHUTE.lifted_libraries.find(lib=>lib[key])
202193
if(lifted_lib)return['Lift_lib',lifted_lib]
203194
let global_el=globalThis[key]!==undefined
204195
if(global_el)return ['global_this',globalThis]
205196
error(`"${key}" is not: ${desc}`)
206-
}
207-
/* globalThis.JSON.stringify(Args)
208-
\________/ \__/ \_______/
209-
| | |
210-
root context Fn */
197+
}/* globalThis.JSON.stringify(Args)
198+
\________/ \__/ \_______/
199+
| | |
200+
root context Fn*/
211201
let path_mode=a_chute.treat_dots_as_paths
212-
//^ if keys==[a.b.c] path_mode expects a[b][c] vs a|>b|>c
213-
return keys.reduce((a,key,i,l)=>{
202+
//^ if dot_list==[a.b.c] path_mode expects a[b][c] vs a|>b|>c
203+
return dot_list.reduce((a,key,i,l)=>{
214204
if(!a.path){
215205
([a.root_string,a.root]=setup_root(key,a))
216206
a.path = a.root//a new path starts with the root
@@ -220,7 +210,7 @@ function handle_nested_access({keys,args,a_chute}){
220210
a.path=a.path[key]//e.g. GlobalThis['JSON']
221211
let is_last_key=i==l.length-1
222212
if(is_last_key)return try_do({fn:a.path,key,a,args})
223-
let next_key=keys[i+1]
213+
let next_key=dot_list[i+1]
224214
let found_last_in_current_path=a.path[next_key]===undefined
225215
if(found_last_in_current_path){
226216
if(path_mode)error(`"${key}" lacks "${next_key}"`)
@@ -238,19 +228,15 @@ function handle_nested_access({keys,args,a_chute}){
238228
//console.log(`RUN ${a.root_string}'s '"${key}"`)
239229
// Dot-style-calls use functions Chute can access already:
240230
// no need to memoize fn, but inspect the arguments for fns
241-
if(!is_fn(a.path)){
242-
error(`${a.root_string}'s … "${key}" is not a FN`)
243-
}
231+
if(!is_fn(a.path))error(`${a.root_string}…"${key}" not ƒ`)
244232
let rv
245233
if(a.root==chute_lib)rv=fn({args,data:a.data,a_chute})
246234
else if(
247235
a.root===globalThis
248236
||a.root==a_chute.fns_seen
249-
||a.root==chutes.library
237+
||a.root==CHUTE.library
250238
||a.root_string=='Lift_lib'
251-
){
252-
rv = call_a_function({fn,data:a.data,args})
253-
}
239+
){ rv = call_a_function({fn,data:a.data,args}) }
254240
else {//current_data.a.b.c.fn(),
255241
//Call any function the current_data contains.
256242
//To restrict to native methods (e.g. .map .reduce),
@@ -268,6 +254,7 @@ const blank_chute=()=>({
268254
treat_dots_as_paths:false,//.log.reverse vs .log().reverse()
269255
sync_data:null,//Receives `x=>user_variable=x` to send data
270256
skip_void:true,//Default
257+
dot_list:[],//^.a.b.c collected until '()'
271258
})
272259
function new_chute({seed,args}){
273260
let a_chute=blank_chute()
@@ -283,37 +270,30 @@ function new_chute({seed,args}){
283270
if(args.length>0){
284271
a_chute.set_data(chute_lib.do({args,data:seed,a_chute}))
285272
}
286-
const target=()=>{}
287-
const keys=[]//i.e call_list
288-
//^current keys (named calls) in this chute
289273
function get(target,key){
290-
keys.push(key)//collect all keys until user calls with '()'
274+
a_chute.dot_list.push(key)//store all keys pre '()' apply
291275
return proxy
292276
}
293277
function apply(target,this_arg, args){
294-
let named_end_chute=['_end','_$'].includes(keys.at(-1))
295-
if(named_end_chute)keys.pop()
296-
let nameless_call=keys.length==0
297-
let nameless_do_call=nameless_call&&args.length>0
298-
let nameless_end_chute = nameless_call&&args.length===0
299-
let named_call=keys.length>0
300-
let end_chute = nameless_end_chute || named_end_chute
301-
if(nameless_do_call){
302-
a_chute.set_data(
303-
chute_lib.do({args, data:a_chute.get_data(), a_chute})
304-
)
305-
}
306-
if(named_call){// .x(anything) x==anything except "_end"
307-
a_chute.set_data(
308-
handle_nested_access({keys, a_chute, args})
309-
)
278+
let named_end_chute=['_end','_$']
279+
.includes(a_chute.dot_list.at(-1))
280+
if(named_end_chute)a_chute.dot_list.pop()
281+
let is_nameless_call = a_chute.dot_list.length==0,
282+
is_nameless_do_call = is_nameless_call && args.length>0,
283+
is_nameless_end_chute = is_nameless_call && args.length===0,
284+
is_named_call = a_chute.dot_list.length>0,
285+
should_end_chute = is_nameless_end_chute || named_end_chute,
286+
rv
287+
if(is_nameless_do_call){
288+
rv=chute_lib.do({args, data:a_chute.get_data(), a_chute})
310289
}
311-
//processed all keys
312-
keys.length=0
313-
return end_chute?a_chute.get_data():proxy
290+
else if(is_named_call)rv=handle_nested_access(a_chute, args)
291+
if(rv)a_chute.set_data(rv)
292+
a_chute.dot_list.length=0//Reset : processed all call keys
293+
return should_end_chute?a_chute.get_data():proxy
314294
}
315-
let proxy = new Proxy(target, {get,apply})
295+
let proxy = new Proxy(()=>{}/*target*/,{get,apply})
316296
return proxy
317297
}
318-
return chutes
298+
return CHUTE
319299
})()

0 commit comments

Comments
 (0)