@@ -9,18 +9,16 @@ import type {
99 Operation ,
1010 Scope ,
1111} from "./types.ts" ;
12- import type { ScopeInternal } from "./scope-internal.ts" ;
1312import { Children } from "./contexts.ts" ;
1413import { Ok } from "./result.ts" ;
1514
1615export interface ApiInternal < A > extends Api < A > {
1716 context : Context < {
18- max : Partial < Around < A > > [ ] ;
19- min : Partial < Around < A > > [ ] ;
17+ local : Decorator < A > ;
18+ total : Decorator < A > ;
19+ handle : A ;
2020 } > ;
2121 core : A ;
22- cache : WeakMap < Scope , A > ;
23- invalidate ( scope : Scope ) : void ;
2422}
2523
2624export function createApiInternal < A extends { } > (
@@ -31,27 +29,13 @@ export function createApiInternal<A extends {}>(
3129
3230 let context = createContext ( `api::${ name } ` ) as ApiInternal < A > [ "context" ] ;
3331
34- let cache = new WeakMap < Scope , A > ( ) ;
35-
3632 let api : ApiInternal < A > = {
3733 core,
3834 context,
39- cache,
40- invalidate ( scope : Scope ) {
41- cache . delete ( scope ) ;
42- let children = scope . get ( Children ) ;
43- if ( children ) {
44- for ( let child of children ) {
45- api . invalidate ( child ) ;
46- }
47- }
48- } ,
35+
4936 invoke : ( scope , key , args ) => {
50- let handle = cache . get ( scope ) ;
51- if ( ! handle ) {
52- handle = createHandle ( api , scope as ScopeInternal ) ;
53- cache . set ( scope , handle ) ;
54- }
37+ let handle = scope . get ( api . context ) ?. handle ?? core ;
38+
5539 let member = handle [ key ] ;
5640 if ( typeof member === "function" ) {
5741 return member ( ...args ) ;
@@ -62,7 +46,7 @@ export function createApiInternal<A extends {}>(
6246 around : ( decorator , options = { at : "max" } ) => ( {
6347 * [ Symbol . iterator ] ( ) {
6448 let scope = ( yield GetScope ) as Scope ;
65- scope . around ( api , decorator , options ) ;
49+ decorateApi ( scope , api , decorator , options ) ;
6650 } ,
6751 } ) ,
6852 operations : fields . reduce ( ( sum , field ) => {
@@ -93,50 +77,107 @@ export function createApiInternal<A extends {}>(
9377 return api ;
9478}
9579
96- function createHandle < A extends { } > (
80+ export function decorateApi < A > (
81+ scope : Scope ,
9782 api : ApiInternal < A > ,
98- scope : ScopeInternal ,
99- ) : A {
100- // there is no middleware at all for this api, so the handle _is_ the core.
101- if ( ! scope . get ( api . context ) ) {
102- return api . core ;
83+ decorator : Partial < Around < A > > ,
84+ options ?: {
85+ at : "min" | "max" ;
86+ } ,
87+ ) {
88+ // read existing total and local
89+ let current = scope . get ( api . context ) ?? { total : { } , local : { } } ;
90+
91+ let local = decorate ( current . local , {
92+ [ options ?. at ?? "max" ] : decorator ,
93+ } ) ;
94+
95+ if ( ! scope . hasOwn ( api . context ) ) {
96+ scope . set ( api . context , {
97+ local,
98+ total : current . total ,
99+ handle : api . core ,
100+ } ) ;
101+ } else {
102+ current . local = local ;
103103 }
104104
105- let handle = Object . create ( api . core ) ;
105+ install ( scope , api , current . total ) ;
106+ }
106107
107- for ( let key of Object . keys ( api . core ) as Array < keyof A > ) {
108- let { min, max } = scope . reduce ( api . context , ( sum , current ) => {
109- let min = current . min . flatMap ( ( around ) =>
110- around [ key ] ? [ around [ key ] ] : [ ]
111- ) ;
112- let max = current . max . flatMap ( ( around ) =>
113- around [ key ] ? [ around [ key ] ] : [ ]
114- ) ;
108+ function decorate < A > ( base : Decorator < A > , next : Decorator < A > ) : Decorator < A > {
109+ return {
110+ max : base . max ? next . max ? append ( base . max , next . max ) : base . max : next . max ,
111+ min : next . min ? base . min ? append ( next . min , base . min ) : next . min : base . min ,
112+ } ;
113+ }
115114
116- sum . min . push ( ...min ) ;
117- sum . max . unshift ( ...max ) ;
115+ function append < A > (
116+ outer : Partial < Around < A > > ,
117+ inner : Partial < Around < A > > ,
118+ ) : Partial < Around < A > > {
119+ let result : Partial < Around < A > > = { ...outer } ;
120+ for ( let key of Object . keys ( inner ) as ( keyof A ) [ ] ) {
121+ let current = outer [ key ] ;
122+ let decoration = inner [ key ] ;
123+ if ( ! current ) {
124+ result [ key ] = decoration ;
125+ } else {
126+ let pair = [ current , decoration ] as Middleware < unknown [ ] , unknown > [ ] ;
127+ result [ key ] = combine ( pair ) as Around < A > [ keyof A ] ;
128+ }
129+ }
130+ return result ;
131+ }
118132
119- return sum ;
120- } , {
121- min : [ ] as Around < A > [ typeof key ] [ ] ,
122- max : [ ] as Around < A > [ typeof key ] [ ] ,
123- } ) ;
133+ function install < A > (
134+ scope : Scope ,
135+ api : ApiInternal < A > ,
136+ total : Decorator < A > ,
137+ ) : void {
138+ if ( scope . hasOwn ( api . context ) ) {
139+ let context = scope . expect ( api . context ) ;
140+
141+ context . total = total ;
142+
143+ total = decorate ( context . total , context . local ) ;
144+
145+ context . handle = createApiHandle ( total , api . core ) ;
146+ }
124147
125- let stack = combine ( max . concat ( min ) as Middleware < unknown [ ] , unknown > [ ] ) ;
148+ for ( let child of scope . expect ( Children ) ) {
149+ install ( child , api , total ) ;
150+ }
151+ }
126152
127- if ( typeof api . core [ key ] === "function" ) {
128- handle [ key ] = ( ...args : unknown [ ] ) =>
129- stack ( args , api . core [ key ] as ( ...args : unknown [ ] ) => unknown ) ;
153+ function createApiHandle < A > ( decoration : Decorator < A > , core : A ) : A {
154+ let around = decoration . max
155+ ? decoration . min ? append ( decoration . max , decoration . min ) : decoration . max
156+ : decoration . min ;
157+ if ( ! around ) {
158+ return core ;
159+ }
160+ let handle : A = { } as A ;
161+ for ( let key of Object . keys ( core as object ) as Array < keyof A > ) {
162+ let middleware = around [ key ] as Middleware < unknown [ ] , unknown > | undefined ;
163+ if ( middleware ) {
164+ if ( typeof core [ key ] === "function" ) {
165+ handle [ key ] = ( ( ...args : unknown [ ] ) =>
166+ middleware ( args , core [ key ] as ( ...args : unknown [ ] ) => unknown ) ) as A [
167+ keyof A
168+ ] ;
169+ } else {
170+ Object . defineProperty ( handle , key , {
171+ enumerable : true ,
172+ get ( ) {
173+ return middleware ( [ ] , ( ) => core [ key ] ) ;
174+ } ,
175+ } ) ;
176+ }
130177 } else {
131- Object . defineProperty ( handle , key , {
132- enumerable : true ,
133- get ( ) {
134- return stack ( [ ] , ( ) => api . core [ key ] ) ;
135- } ,
136- } ) ;
178+ handle [ key ] = core [ key ] ;
137179 }
138180 }
139-
140181 return handle ;
141182}
142183
@@ -165,6 +206,11 @@ function combine<TArgs extends unknown[], TReturn>(
165206 ) ;
166207}
167208
209+ interface Decorator < A > {
210+ min ?: Partial < Around < A > > ;
211+ max ?: Partial < Around < A > > ;
212+ }
213+
168214const GetScope : Effect < Scope > = {
169215 description : "Fast, non-typesafe lookup of co-routine scope" ,
170216 enter : ( resolve , routine ) => {
0 commit comments