11const 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 ]*/
44const stringy = x => JSON . stringify ( x ) ,
55error = ( ...x ) => { throw new Error ( x ) } ,
66is_fn = x => x instanceof Function ,
@@ -10,57 +10,50 @@ is_object=v=>v&& typeof v=='object'&&!Array.isArray(v),
1010is_js_method = ( o , k ) => is_fn ( Object . getPrototypeOf ( o ) [ k ] ) ,
1111is_global_fn = name => is_fn ( globalThis [ name ] ) ,
1212loop_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+ } ,
1329chute_lib = { } , //Holds chute's own functions: log, tap, do, if
1430PLACEHOLDER = { } , //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
4539chute_lib . log = ( { args, data} ) => {
4640 if ( args . length > 0 ) { console . log ( ...args , data ) }
4741 else console . log ( data )
4842 return data
4943}
5044chute_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}
6558const 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}
174163function 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} )
272259function 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