@@ -6,12 +6,14 @@ import { getDetails } from './script-handler.js';
66import { registry as defaultRegistry , prefixes , configs } from './interpreters.js' ;
77import { getRuntimeID } from './loader.js' ;
88import { addAllListeners } from './listeners.js' ;
9- import { Hook , XWorker } from './xworker.js' ;
9+ import { Hook , XWorker as XW } from './xworker.js' ;
1010import { polluteJS , js as jsHooks , code as codeHooks } from './hooks.js' ;
1111import workerURL from './worker/url.js' ;
1212
1313export const CUSTOM_SELECTORS = [ ] ;
1414
15+ export const customObserver = new Map ( ) ;
16+
1517/**
1618 * @typedef {Object } Runtime custom configuration
1719 * @prop {object } interpreter the bootstrapped interpreter
@@ -30,131 +32,137 @@ const waitList = new Map();
3032/**
3133 * @param {Element } node any DOM element registered via define.
3234 */
33- export const handleCustomType = ( node ) => {
35+ export const handleCustomType = async ( node ) => {
3436 for ( const selector of CUSTOM_SELECTORS ) {
3537 if ( node . matches ( selector ) ) {
3638 const type = types . get ( selector ) ;
3739 const details = registry . get ( type ) ;
3840 const { resolve } = waitList . get ( type ) ;
3941 const { options, known } = details ;
40- if ( ! known . has ( node ) ) {
41- known . add ( node ) ;
42- const {
43- interpreter : runtime ,
44- configURL,
45- config,
46- version,
47- env,
48- onerror,
49- hooks,
50- } = options ;
51-
52- let error ;
53- try {
54- const worker = workerURL ( node ) ;
55- if ( worker ) {
56- const xworker = XWorker . call ( new Hook ( null , hooks ) , worker , {
57- ...nodeInfo ( node , type ) ,
58- version,
59- configURL,
60- type : runtime ,
61- custom : type ,
62- config : node . getAttribute ( 'config' ) || config || { } ,
63- async : node . hasAttribute ( 'async' )
64- } ) ;
65- defineProperty ( node , 'xworker' , { value : xworker } ) ;
66- resolve ( { type, xworker } ) ;
67- return ;
68- }
69- }
70- // let the custom type handle errors via its `io`
71- catch ( workerError ) {
72- error = workerError ;
42+
43+ if ( known . has ( node ) ) return ;
44+ known . add ( node ) ;
45+
46+ for ( const [ selector , callback ] of customObserver ) {
47+ if ( node . matches ( selector ) ) await callback ( node ) ;
48+ }
49+
50+ const {
51+ interpreter : runtime ,
52+ configURL,
53+ config,
54+ version,
55+ env,
56+ onerror,
57+ hooks,
58+ } = options ;
59+
60+ let error ;
61+ try {
62+ const worker = workerURL ( node ) ;
63+ if ( worker ) {
64+ const xworker = XW . call ( new Hook ( null , hooks ) , worker , {
65+ ...nodeInfo ( node , type ) ,
66+ version,
67+ configURL,
68+ type : runtime ,
69+ custom : type ,
70+ config : node . getAttribute ( 'config' ) || config || { } ,
71+ async : node . hasAttribute ( 'async' )
72+ } ) ;
73+ defineProperty ( node , 'xworker' , { value : xworker } ) ;
74+ resolve ( { type, xworker } ) ;
75+ return ;
7376 }
77+ }
78+ // let the custom type handle errors via its `io`
79+ catch ( workerError ) {
80+ error = workerError ;
81+ }
82+
83+ const name = getRuntimeID ( runtime , version ) ;
84+ const id = env || `${ name } ${ config ? `|${ config } ` : '' } ` ;
85+ const { interpreter : engine , XWorker : Worker } = getDetails (
86+ type ,
87+ id ,
88+ name ,
89+ version ,
90+ config ,
91+ configURL ,
92+ runtime
93+ ) ;
94+
95+ const interpreter = await engine ;
7496
75- const name = getRuntimeID ( runtime , version ) ;
76- const id = env || `${ name } ${ config ? `|${ config } ` : '' } ` ;
77- const { interpreter : engine , XWorker : Worker } = getDetails (
97+ const module = create ( defaultRegistry . get ( runtime ) ) ;
98+
99+ const hook = new Hook ( interpreter , hooks ) ;
100+
101+ const XWorker = function XWorker ( ...args ) {
102+ return Worker . apply ( hook , args ) ;
103+ } ;
104+
105+ const resolved = {
106+ ...createResolved (
107+ module ,
78108 type ,
79- id ,
80- name ,
81- version ,
82- config ,
83- configURL ,
84- runtime
85- ) ;
86- engine . then ( ( interpreter ) => {
87- const module = create ( defaultRegistry . get ( runtime ) ) ;
88-
89- const hook = new Hook ( interpreter , hooks ) ;
90-
91- const XWorker = function XWorker ( ...args ) {
92- return Worker . apply ( hook , args ) ;
93- } ;
94-
95- const resolved = {
96- ...createResolved (
97- module ,
98- type ,
99- structuredClone ( configs . get ( name ) ) ,
100- interpreter ,
101- ) ,
102- XWorker,
103- } ;
104-
105- registerJSModules ( runtime , module , interpreter , JSModules ) ;
106- module . registerJSModule ( interpreter , 'polyscript' , {
107- XWorker,
108- currentScript : type . startsWith ( '_' ) ? null : node ,
109- js_modules : JSModules ,
110- } ) ;
109+ structuredClone ( configs . get ( name ) ) ,
110+ interpreter ,
111+ ) ,
112+ XWorker,
113+ } ;
111114
112- // patch methods accordingly to hooks (and only if needed)
113- for ( const suffix of [ 'Run' , 'RunAsync' ] ) {
114- let before = '' ;
115- let after = '' ;
116-
117- for ( const key of codeHooks ) {
118- const value = hooks ?. main ?. [ key ] ;
119- if ( value && key . endsWith ( suffix ) ) {
120- if ( key . startsWith ( 'codeBefore' ) )
121- before = dedent ( value ( ) ) ;
122- else
123- after = dedent ( value ( ) ) ;
124- }
125- }
126-
127- if ( before || after ) {
128- createOverload (
129- module ,
130- `r${ suffix . slice ( 1 ) } ` ,
131- before ,
132- after ,
133- ) ;
134- }
135-
136- let beforeCB , afterCB ;
137- // ignore onReady and onWorker
138- for ( let i = 2 ; i < jsHooks . length ; i ++ ) {
139- const key = jsHooks [ i ] ;
140- const value = hooks ?. main ?. [ key ] ;
141- if ( value && key . endsWith ( suffix ) ) {
142- if ( key . startsWith ( 'onBefore' ) )
143- beforeCB = value ;
144- else
145- afterCB = value ;
146- }
147- }
148- polluteJS ( module , resolved , node , suffix . endsWith ( 'Async' ) , beforeCB , afterCB ) ;
115+ registerJSModules ( runtime , module , interpreter , JSModules ) ;
116+ module . registerJSModule ( interpreter , 'polyscript' , {
117+ XWorker,
118+ currentScript : type . startsWith ( '_' ) ? null : node ,
119+ js_modules : JSModules ,
120+ } ) ;
121+
122+ // patch methods accordingly to hooks (and only if needed)
123+ for ( const suffix of [ 'Run' , 'RunAsync' ] ) {
124+ let before = '' ;
125+ let after = '' ;
126+
127+ for ( const key of codeHooks ) {
128+ const value = hooks ?. main ?. [ key ] ;
129+ if ( value && key . endsWith ( suffix ) ) {
130+ if ( key . startsWith ( 'codeBefore' ) )
131+ before = dedent ( value ( ) ) ;
132+ else
133+ after = dedent ( value ( ) ) ;
149134 }
135+ }
150136
151- details . queue = details . queue . then ( ( ) => {
152- resolve ( resolved ) ;
153- if ( error ) onerror ?. ( error , node ) ;
154- return hooks ?. main ?. onReady ?. ( resolved , node ) ;
155- } ) ;
156- } ) ;
137+ if ( before || after ) {
138+ createOverload (
139+ module ,
140+ `r${ suffix . slice ( 1 ) } ` ,
141+ before ,
142+ after ,
143+ ) ;
144+ }
145+
146+ let beforeCB , afterCB ;
147+ // ignore onReady and onWorker
148+ for ( let i = 2 ; i < jsHooks . length ; i ++ ) {
149+ const key = jsHooks [ i ] ;
150+ const value = hooks ?. main ?. [ key ] ;
151+ if ( value && key . endsWith ( suffix ) ) {
152+ if ( key . startsWith ( 'onBefore' ) )
153+ beforeCB = value ;
154+ else
155+ afterCB = value ;
156+ }
157+ }
158+ polluteJS ( module , resolved , node , suffix . endsWith ( 'Async' ) , beforeCB , afterCB ) ;
157159 }
160+
161+ details . queue = details . queue . then ( ( ) => {
162+ resolve ( resolved ) ;
163+ if ( error ) onerror ?. ( error , node ) ;
164+ return hooks ?. main ?. onReady ?. ( resolved , node ) ;
165+ } ) ;
158166 }
159167 }
160168} ;
0 commit comments