@webqit/oohtml 2.1.5 → 2.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context-api.js +1 -1
- package/dist/context-api.js.map +2 -2
- package/dist/html-imports.js +1 -1
- package/dist/html-imports.js.map +2 -2
- package/dist/html-modules.js +1 -1
- package/dist/html-modules.js.map +2 -2
- package/dist/main.js +13 -13
- package/dist/main.js.map +3 -3
- package/dist/namespaced-html.js +1 -1
- package/dist/namespaced-html.js.map +2 -2
- package/dist/scoped-js.js +14 -14
- package/dist/scoped-js.js.map +3 -3
- package/dist/state-api.js +1 -1
- package/dist/state-api.js.map +2 -2
- package/package.json +2 -2
- package/src/html-modules/index.js +1 -0
- package/src/html-modules/targets.browser.js +1 -4
- package/src/index.js +1 -2
- package/src/namespaced-html/index.js +2 -0
- package/src/namespaced-html/targets.browser.js +1 -4
- package/src/scoped-js/Compiler.js +294 -0
- package/src/scoped-js/index.js +29 -318
- package/src/scoped-js/targets.browser.js +1 -5
- package/src/state-api/index.js +2 -0
- package/src/state-api/targets.browser.js +1 -4
- package/test/index.js +8 -32
- package/test/modules.test.js +1 -1
- package/test/{scoped-js.test2.js → scoped-js.test.js} +2 -2
- package/test/test.html +0 -71
package/src/scoped-js/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { resolveParams } from '@webqit/subscript/src/params.js';
|
|
6
6
|
import SubscriptFunction from '@webqit/subscript/src/SubscriptFunctionLite.js';
|
|
7
7
|
import Observer from '@webqit/observer';
|
|
8
|
+
import Compiler from './Compiler.js';
|
|
8
9
|
import wqDom from '@webqit/dom';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -15,14 +16,17 @@ import wqDom from '@webqit/dom';
|
|
|
15
16
|
export default function init( $params = {} ) {
|
|
16
17
|
const window = this, dom = wqDom.call( window );
|
|
17
18
|
if ( !window.wq ) { window.wq = {}; }
|
|
18
|
-
window.wq.
|
|
19
|
+
if ( !window.wq.oohtml ) { window.wq.oohtml = {}; }
|
|
20
|
+
window.wq.oohtml.Script = { compileCache: [ new Map, new Map, ] };
|
|
21
|
+
window.wq.SubscriptFunction = $params.SubscriptFunction/* allow for injection, e.g. from test runner */ || SubscriptFunction;
|
|
22
|
+
window.wq.Observer = Observer;
|
|
19
23
|
// -------
|
|
20
24
|
const params = dom.meta( 'oohtml' ).copyWithDefaults( $params, {
|
|
21
25
|
script: { retention: 'retain', mimeType: '' },
|
|
22
26
|
config: resolveParams( {
|
|
23
|
-
parserParams: { allowReturnOutsideFunction: false, allowSuperOutsideMethod: false },
|
|
24
|
-
compilerParams: { globalsNoObserve: [ 'alert' ] },
|
|
25
|
-
runtimeParams: { apiVersion: 2 },
|
|
27
|
+
parserParams: { allowReturnOutsideFunction: false, allowSuperOutsideMethod: false, ...( $params.parserParams || {} ) },
|
|
28
|
+
compilerParams: { globalsNoObserve: [ 'alert' ], ...( $params.compilerParams || {} ) },
|
|
29
|
+
runtimeParams: { apiVersion: 2, ...( $params.runtimeParams || {} ) },
|
|
26
30
|
} ),
|
|
27
31
|
} );
|
|
28
32
|
params.scriptSelector = ( Array.isArray( params.script.mimeType ) ? params.script.mimeType : [ params.script.mimeType ] ).reduce( ( selector, mm ) => {
|
|
@@ -38,54 +42,6 @@ export {
|
|
|
38
42
|
Observer,
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
/**
|
|
42
|
-
* Performs realtime capture of elements and builds their relationships.
|
|
43
|
-
*
|
|
44
|
-
* @param Object params
|
|
45
|
-
*
|
|
46
|
-
* @return Void
|
|
47
|
-
*/
|
|
48
|
-
function realtime( params ) {
|
|
49
|
-
const window = this, { dom } = window.wq;
|
|
50
|
-
// ---
|
|
51
|
-
window.wq.transformCache = new Map;
|
|
52
|
-
window.wq.compileCache = [ new Map, new Map, ];
|
|
53
|
-
// ---
|
|
54
|
-
const handled = () => {};
|
|
55
|
-
dom.realtime( window.document ).observe( params.scriptSelector, record => {
|
|
56
|
-
record.entrants.forEach( script => {
|
|
57
|
-
if ( 'contract' in script ) return handled( script );
|
|
58
|
-
Object.defineProperty( script, 'contract', { value: script.hasAttribute( 'contract' ) } );
|
|
59
|
-
if ( 'scoped' in script ) return handled( script );
|
|
60
|
-
Object.defineProperty( script, 'scoped', { value: script.hasAttribute( 'scoped' ) } );
|
|
61
|
-
// ---
|
|
62
|
-
const thisContext = script.scoped ? record.target : ( script.type === 'module' ? undefined : window );
|
|
63
|
-
compile.call( this, script, thisContext, params );
|
|
64
|
-
} );
|
|
65
|
-
}, { subtree: true, timing: 'intercept', generation: 'entrants' } );
|
|
66
|
-
// ---
|
|
67
|
-
window.wq.exec = ( execHash ) => {
|
|
68
|
-
const exec = fromHash( execHash );
|
|
69
|
-
if ( !exec ) throw new Error( `Argument must be a valid exec hash.` );
|
|
70
|
-
const { script, compiledScript, thisContext } = exec;
|
|
71
|
-
if ( thisContext instanceof window.Element && script.scoped ) {
|
|
72
|
-
if ( !thisContext.scripts ) { Object.defineProperty( thisContext, 'scripts', { value: new Set } ); }
|
|
73
|
-
thisContext.scripts.add( script );
|
|
74
|
-
}
|
|
75
|
-
switch ( params.script.retention ) {
|
|
76
|
-
case 'dispose':
|
|
77
|
-
script.remove();
|
|
78
|
-
break;
|
|
79
|
-
case 'hidden':
|
|
80
|
-
script.textContent = `"source hidden"`;
|
|
81
|
-
break;
|
|
82
|
-
default:
|
|
83
|
-
script.textContent = compiledScript.function.originalSource;
|
|
84
|
-
}
|
|
85
|
-
return execute.call( this, compiledScript, thisContext, script );
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
45
|
// ------------------
|
|
90
46
|
// Script runner
|
|
91
47
|
export function execute( compiledScript, thisContext, script ) {
|
|
@@ -123,273 +79,28 @@ export function execute( compiledScript, thisContext, script ) {
|
|
|
123
79
|
return script;
|
|
124
80
|
}
|
|
125
81
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
// Let's obtain a material functions
|
|
146
|
-
let _Function, { parserParams, compilerParams, runtimeParams } = params.config;
|
|
147
|
-
if ( script.contract ) {
|
|
148
|
-
parserParams = { ...parserParams, allowAwaitOutsideFunction: script.type === 'module' };
|
|
149
|
-
runtimeParams = { ...runtimeParams, async: script.type === 'module' };
|
|
150
|
-
_Function = SubscriptFunction( source, { compilerParams, parserParams, runtimeParams, } );
|
|
151
|
-
Object.defineProperty( script, 'properties', { configurable: true, value: SubscriptFunction.inspect( _Function, 'properties' ) } );
|
|
152
|
-
} else {
|
|
153
|
-
const isAsync = script.type === 'module'//meta.topLevelAwait || imports.length;
|
|
154
|
-
const _FunctionConstructor = isAsync ? Object.getPrototypeOf( async function() {} ).constructor : Function;
|
|
155
|
-
_Function = runtimeParams?.compileFunction
|
|
156
|
-
? runtimeParams.compileFunction( source )
|
|
157
|
-
: new _FunctionConstructor( source );
|
|
158
|
-
Object.defineProperty( _Function, 'originalSource', { configurable: true, value: script.textContent } );
|
|
159
|
-
}
|
|
160
|
-
// Save material function to compile cache
|
|
161
|
-
compiledScript = Object.defineProperty( script.cloneNode(), 'function', { value: _Function } );
|
|
162
|
-
script.scoped && Object.defineProperty( compiledScript, 'scoped', Object.getOwnPropertyDescriptor( script, 'scoped') );
|
|
163
|
-
script.contract && Object.defineProperty( compiledScript, 'contract', Object.getOwnPropertyDescriptor( script, 'contract') );
|
|
164
|
-
cache.set( sourceHash, compiledScript );
|
|
165
|
-
}
|
|
166
|
-
const execHash = toHash( { script, compiledScript, thisContext } );
|
|
167
|
-
script.textContent = `wq.exec('${ execHash }');`;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// ------------------
|
|
171
|
-
// Match import statements
|
|
172
|
-
// and detect top-level await
|
|
173
|
-
export function parse( source ) {
|
|
174
|
-
const [ tokens, meta ] = tokenize( source, ( $tokens, event, char, meta, i, isLastChar ) => {
|
|
175
|
-
|
|
176
|
-
if ( event === 'start-enclosure' && char === '{' && !meta.openAsync?.type && meta.openEnclosures.length === meta.openAsync?.scopeId ) {
|
|
177
|
-
meta.openAsync.type = 'block';
|
|
178
|
-
} else if ( event === 'end-enclosure' && char === '}' && meta.openAsync?.type === 'block' && meta.openEnclosures.length === meta.openAsync.scopeId ) {
|
|
179
|
-
meta.openAsync = null;
|
|
180
|
-
} else if ( event === 'start-quote' && !meta.openEnclosures.length && [ 'starting', 'from' ].includes( meta.openImport ) ) {
|
|
181
|
-
meta.openImport = 'url';
|
|
182
|
-
} else if ( event === 'end-quote' && meta.openImport === 'url' ) {
|
|
183
|
-
meta.openImport = 'closing';
|
|
184
|
-
} else if ( event === 'char' ) {
|
|
185
|
-
|
|
186
|
-
if ( meta.openImport === 'closing' && (
|
|
187
|
-
char === ';'/* explicit */ || ![ ' ', `\n` ].includes( char )/* implicit */ || isLastChar
|
|
188
|
-
) ) {
|
|
189
|
-
if ( char === ';' || isLastChar ) {
|
|
190
|
-
$tokens[ 0 ] += char;
|
|
191
|
-
$tokens.unshift( '' );
|
|
192
|
-
} else { $tokens.unshift( char ); }
|
|
193
|
-
meta.openImport = null;
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
let remainder = source.substring( i - 1 );
|
|
198
|
-
|
|
199
|
-
if ( !meta.openImport && /^[\W]?import[ ]*[^\(]/.test( remainder ) ) {
|
|
200
|
-
meta.openImport = 'starting';
|
|
201
|
-
$tokens.unshift( '' );
|
|
202
|
-
return 6;
|
|
203
|
-
}
|
|
204
|
-
if ( meta.openImport === 'starting' && /^[\W]?from /.test( remainder ) ) {
|
|
205
|
-
meta.openImport = 'from';
|
|
206
|
-
return 4;
|
|
207
|
-
}
|
|
208
|
-
if ( !meta.openAsync ) {
|
|
209
|
-
if ( /^[\W]?async /.test( remainder ) ) {
|
|
210
|
-
meta.openAsync = { scopeId: meta.openEnclosures.length };
|
|
211
|
-
return 5;
|
|
212
|
-
}
|
|
213
|
-
if ( /^[\W]?await /.test( remainder ) ) {
|
|
214
|
-
meta.topLevelAwait = true;
|
|
215
|
-
return 5;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
if ( meta.openAsync ) {
|
|
219
|
-
if ( !meta.openAsync.type && /.?\=\>[ ]*?\{/.test( remainder ) ) {
|
|
220
|
-
meta.openAsync.type = 'inline-arrow';
|
|
221
|
-
} else if ( meta.openAsync.type === 'inline-arrow' && [ `\n`, ';' ].includes( char ) && meta.openEnclosures.length === meta.openAsync.scopeId ) {
|
|
222
|
-
meta.openAsync = null;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
} );
|
|
229
|
-
// Hoist all import statements
|
|
230
|
-
let imports = [], body = '', _str;
|
|
231
|
-
for ( const str of tokens.reverse() ) {
|
|
232
|
-
if ( ( _str = str.trim() ).startsWith( 'import ' ) ) {
|
|
233
|
-
imports.push( str );
|
|
234
|
-
} else if ( _str ) { body += str; }
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return [ imports, body, meta ];
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// ------------------
|
|
241
|
-
// Rewrite import statements
|
|
242
|
-
export function rewriteImportStmts( imports ) {
|
|
243
|
-
const importSpecs = [], importPromises = [];
|
|
244
|
-
imports.forEach( ( $import, i ) => {
|
|
245
|
-
$import = parseImportStmt( $import );
|
|
246
|
-
// Identify whole imports and individual imports
|
|
247
|
-
const [ wholeImport, individualImports ] = $import.items.reduce( ( [ whole, parts ], item ) => {
|
|
248
|
-
return item.id === '*' ? [ item.alias, parts ] : [ whole, parts.concat( item ) ];
|
|
249
|
-
}, [ null, [] ] );
|
|
250
|
-
if ( wholeImport ) {
|
|
251
|
-
// const main = await import("url");
|
|
252
|
-
importSpecs.push( `const ${ wholeImport } = __$imports$__[${ i }];` );
|
|
253
|
-
}
|
|
254
|
-
if ( individualImports.length ) {
|
|
255
|
-
// const { aa: bb, cc } = await import("url");
|
|
256
|
-
const individualImportsSpec = individualImports.map( item => `${ item.id }${ item.id !== item.alias ? `: ${ item.alias }` : '' }` ).join( ', ' );
|
|
257
|
-
importSpecs.push( `const { ${ individualImportsSpec } } = __$imports$__[${ i }];` );
|
|
258
|
-
}
|
|
259
|
-
importPromises.push( `import("${ $import.url }")` );
|
|
260
|
-
} );
|
|
261
|
-
return [
|
|
262
|
-
`\n\tconst __$imports$__ = await Promise.all([\n\t\t${ importPromises.join( `,\n\t\t` ) }\n\t]);`,
|
|
263
|
-
importSpecs.join( `\n\t` ),
|
|
264
|
-
];
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// ------------------
|
|
268
|
-
// Parse import statements
|
|
269
|
-
export function parseImportStmt( str ) {
|
|
270
|
-
const getUrl = str => {
|
|
271
|
-
let quo = /^[`'"]/.exec( str );
|
|
272
|
-
return quo && str.substring( 1, str.lastIndexOf( quo[ 0 ] ) );
|
|
273
|
-
}
|
|
274
|
-
let $import = { items: [ { id: '' } ] }, _str = str.replace( 'import', '' ).trim();
|
|
275
|
-
if ( !( $import.url = getUrl( _str ) ) ) {
|
|
276
|
-
tokenize( _str, ( $tokens, event, char, meta, i, isLastChar ) => {
|
|
277
|
-
if ( [ 'start-quote', 'ongoing-quote', 'end-quote', 'char' ].includes( event ) ) {
|
|
278
|
-
if ( $import.url ) return;
|
|
279
|
-
if ( !meta.openQuote ) {
|
|
280
|
-
let remainder = _str.substring( i );
|
|
281
|
-
if ( char === ',' ) {
|
|
282
|
-
$import.items.unshift( { id: '' } );
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
if ( remainder.startsWith( ' as ' ) ) {
|
|
286
|
-
$import.items[ 0 ].alias = '';
|
|
287
|
-
return 3;
|
|
288
|
-
}
|
|
289
|
-
if ( remainder.startsWith( ' from ' ) ) {
|
|
290
|
-
$import.url = getUrl( remainder.replace( 'from', '' ).trim() );
|
|
291
|
-
return remainder.length;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
if ( 'alias' in $import.items[ 0 ] ) {
|
|
295
|
-
$import.items[ 0 ].alias += char;
|
|
296
|
-
} else {
|
|
297
|
-
$import.items[ 0 ].id += char;
|
|
298
|
-
if ( meta.openEnclosures.length ) {
|
|
299
|
-
$import.items[ 0 ].enclosed = true;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
82
|
+
/**
|
|
83
|
+
* Performs realtime capture of elements and builds their relationships.
|
|
84
|
+
*
|
|
85
|
+
* @param Object params
|
|
86
|
+
*
|
|
87
|
+
* @return Void
|
|
88
|
+
*/
|
|
89
|
+
function realtime( params ) {
|
|
90
|
+
const window = this, { dom } = window.wq;
|
|
91
|
+
const compiler = new Compiler( window, params, execute ), handled = () => {};
|
|
92
|
+
dom.realtime( window.document ).observe( params.scriptSelector, record => {
|
|
93
|
+
record.entrants.forEach( script => {
|
|
94
|
+
if ( 'contract' in script ) return handled( script );
|
|
95
|
+
Object.defineProperty( script, 'contract', { value: script.hasAttribute( 'contract' ) } );
|
|
96
|
+
if ( 'scoped' in script ) return handled( script );
|
|
97
|
+
Object.defineProperty( script, 'scoped', { value: script.hasAttribute( 'scoped' ) } );
|
|
98
|
+
// ---
|
|
99
|
+
const thisContext = script.scoped ? record.target : ( script.type === 'module' ? undefined : window );
|
|
100
|
+
compiler.compile( script, thisContext );
|
|
303
101
|
} );
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
.map( item => ( {
|
|
307
|
-
id: item.id && !item.alias && !item.enclosed ? 'default' : item.id.trim(),
|
|
308
|
-
alias: item.alias ? item.alias.trim() : item.id.trim(),
|
|
309
|
-
} ) )
|
|
310
|
-
.filter( item => item.id )
|
|
311
|
-
.reverse();
|
|
312
|
-
return $import;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// ------------------
|
|
316
|
-
// Token JavaScript source
|
|
317
|
-
export function tokenize( source, _callback ) {
|
|
318
|
-
const lastI = source.length - 1;
|
|
319
|
-
return [ ...source ].reduce( ( [ $tokens, meta, skip ], char, i ) => {
|
|
320
|
-
|
|
321
|
-
if ( skip ) {
|
|
322
|
-
$tokens[ 0 ] += char;
|
|
323
|
-
return [ $tokens, meta, --skip ];
|
|
324
|
-
}
|
|
325
|
-
let callbackReturn;
|
|
326
|
-
|
|
327
|
-
if ( meta.openQuote || meta.openComment ) {
|
|
328
|
-
if ( char === meta.openQuote ) {
|
|
329
|
-
meta.openQuote = null;
|
|
330
|
-
callbackReturn = _callback( $tokens, 'end-quote', char, meta, i, i === lastI );
|
|
331
|
-
} else if ( meta.openQuote ) {
|
|
332
|
-
callbackReturn = _callback( $tokens, 'ongoing-quote', char, meta, i, i === lastI );
|
|
333
|
-
} else if ( meta.openComment ) {
|
|
334
|
-
if ( ( meta.openComment === '//' && char === `\n` ) || ( meta.openComment === '/*' && $tokens[ 0 ].substr( -1 ) === '*' && char === '/' ) ) {
|
|
335
|
-
meta.openComment = null;
|
|
336
|
-
callbackReturn = _callback( $tokens, 'end-comment', char, meta, i, i === lastI );
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
if ( callbackReturn !== false ) {
|
|
340
|
-
$tokens[ 0 ] += char;
|
|
341
|
-
}
|
|
342
|
-
return [ $tokens, meta, typeof callbackReturn === 'number' ? callbackReturn : skip ];
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
let enclosure;
|
|
346
|
-
if ( enclosure = [ '()', '{}', '[]' ].filter( pair => char === pair[ 0 ] )[ 0 ] ) {
|
|
347
|
-
callbackReturn = _callback( $tokens, 'start-enclosure', char, meta, i, i === lastI );
|
|
348
|
-
meta.openEnclosures.unshift( enclosure );
|
|
349
|
-
} else if ( meta.openEnclosures.length && char === meta.openEnclosures[ 0 ][ 1 ] ) {
|
|
350
|
-
meta.openEnclosures.shift();
|
|
351
|
-
callbackReturn = _callback( $tokens, 'end-enclosure', char, meta, i, i === lastI );
|
|
352
|
-
} else if ( [ '"', "'", "`" ].includes( char ) ) {
|
|
353
|
-
callbackReturn = _callback( $tokens, 'start-quote', char, meta, i, i === lastI );
|
|
354
|
-
meta.openQuote = char;
|
|
355
|
-
} else if ( !meta.openComment && [ '/*', '//' ].includes( source.substr( i, 2 ) ) ) {
|
|
356
|
-
callbackReturn = _callback( $tokens, 'start-comment', char, meta, i, i === lastI );
|
|
357
|
-
meta.openComment = source.substr( i, 2 );
|
|
358
|
-
} else {
|
|
359
|
-
callbackReturn = _callback( $tokens, 'char', char, meta, i, i === lastI );
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if ( callbackReturn !== false ) {
|
|
363
|
-
$tokens[ 0 ] += char;
|
|
364
|
-
}
|
|
365
|
-
return [ $tokens, meta, typeof callbackReturn === 'number' ? callbackReturn : skip ];
|
|
366
|
-
|
|
367
|
-
}, [ [ '' ], { openEnclosures: [], }, 0 ] );
|
|
102
|
+
}, { subtree: true, timing: 'intercept', generation: 'entrants' } );
|
|
103
|
+
// ---
|
|
368
104
|
}
|
|
369
105
|
|
|
370
|
-
// ------------------
|
|
371
|
-
// Unique ID generator
|
|
372
|
-
const hashTable = new Map;
|
|
373
|
-
const uniqId = () => (0|Math.random()*9e6).toString(36);
|
|
374
106
|
const _await = ( value, callback ) => value instanceof Promise ? value.then( callback ) : callback( value );
|
|
375
|
-
|
|
376
|
-
// ------------------
|
|
377
|
-
// Hash of anything generator
|
|
378
|
-
export function toHash( val ) {
|
|
379
|
-
let hash;
|
|
380
|
-
if ( !( hash = hashTable.get( val ) ) ) {
|
|
381
|
-
hash = uniqId();
|
|
382
|
-
hashTable.set( val, hash );
|
|
383
|
-
}
|
|
384
|
-
return hash;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// ------------------
|
|
388
|
-
// Value of any hash
|
|
389
|
-
export function fromHash( hash ) {
|
|
390
|
-
let val;
|
|
391
|
-
hashTable.forEach( ( _hash, _val ) => {
|
|
392
|
-
if ( _hash === hash ) val = _val;
|
|
393
|
-
} );
|
|
394
|
-
return val;
|
|
395
|
-
}
|
package/src/state-api/index.js
CHANGED
|
@@ -13,6 +13,8 @@ import { _ } from '../util.js';
|
|
|
13
13
|
*/
|
|
14
14
|
export default function init( $params = {} ) {
|
|
15
15
|
const window = this, dom = wqDom.call( window );
|
|
16
|
+
if ( !window.wq ) { window.wq = {}; }
|
|
17
|
+
window.wq.Observer = Observer;
|
|
16
18
|
const params = dom.meta( 'oohtml' ).copyWithDefaults( $params, {
|
|
17
19
|
api: { state: 'state', },
|
|
18
20
|
} );
|
package/test/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { _internals } from '@webqit/util/js/index.js';
|
|
|
6
6
|
import { createContext, compileFunction, runInContext } from 'vm';
|
|
7
7
|
import jsdom from 'jsdom';
|
|
8
8
|
import init, { Observer } from '../src/index.js';
|
|
9
|
+
import { SubscriptFunction } from '@webqit/subscript';
|
|
9
10
|
import wqDom from '@webqit/dom';
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -14,10 +15,8 @@ import wqDom from '@webqit/dom';
|
|
|
14
15
|
* -------
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
export { Observer };
|
|
19
19
|
export const _ = ( el, ...args ) => _internals( el, 'oohtml', ...args );
|
|
20
|
-
|
|
21
20
|
export function delay( duration, callback = undefined ) {
|
|
22
21
|
return new Promise( res => {
|
|
23
22
|
setTimeout( () => res( callback && callback() ), duration );
|
|
@@ -25,14 +24,12 @@ export function delay( duration, callback = undefined ) {
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
export function createDocument( head = '', body = '', callback = null, ) {
|
|
28
|
-
// -------
|
|
29
27
|
const skeletonDoc = `
|
|
30
28
|
<!DOCTYPE html>
|
|
31
29
|
<html>
|
|
32
30
|
<head>${ head }</head>
|
|
33
31
|
<body>${ body }</body>
|
|
34
32
|
</html>`;
|
|
35
|
-
// --------
|
|
36
33
|
// TODO: Proper indentation for pretty-printing
|
|
37
34
|
const instance = new jsdom.JSDOM( skeletonDoc, {
|
|
38
35
|
url: 'http://localhost',
|
|
@@ -41,51 +38,45 @@ export function createDocument( head = '', body = '', callback = null, ) {
|
|
|
41
38
|
if ( callback ) callback( window, window.wq.dom );
|
|
42
39
|
}
|
|
43
40
|
} );
|
|
44
|
-
// --------
|
|
45
41
|
return instance.window;
|
|
46
42
|
}
|
|
47
43
|
|
|
48
44
|
export function createDocumentForScopedJS( head = '', body = '', callback = null, params = {} ) {
|
|
49
|
-
// -------
|
|
50
45
|
const skeletonDoc = `
|
|
51
46
|
<!DOCTYPE html>
|
|
52
47
|
<html>
|
|
53
48
|
<head>${ head }</head>
|
|
54
49
|
<body>${ body }</body>
|
|
55
50
|
</html>`;
|
|
56
|
-
// --------
|
|
57
51
|
const instance = new jsdom.JSDOM( skeletonDoc, {
|
|
58
|
-
url: 'http://localhost',
|
|
59
52
|
...params,
|
|
53
|
+
url: 'http://localhost',
|
|
60
54
|
beforeParse( window ) {
|
|
61
55
|
window.testRecords = [];
|
|
62
56
|
createContext( window );
|
|
63
|
-
// -----------------
|
|
64
57
|
// Running advanced scripts
|
|
65
|
-
|
|
58
|
+
init.call( window, { ScopedJS: {
|
|
59
|
+
SubscriptFunction,
|
|
66
60
|
runtimeParams: {
|
|
67
61
|
compileFunction: ( code, parameters ) => compileFunction( code, parameters, {
|
|
68
62
|
parsingContext: window,
|
|
69
63
|
} ),
|
|
70
64
|
}
|
|
71
|
-
};
|
|
72
|
-
init.call( window, { ScopedJS: subscriptParams } );
|
|
73
|
-
// -----------------
|
|
65
|
+
} } );
|
|
74
66
|
// Running basic scripts
|
|
75
67
|
const dom = wqDom.call( window );
|
|
76
68
|
if ( params.runScripts !== 'dangerously' ) {
|
|
77
69
|
dom.realtime( window.document ).observe( 'script', record => {
|
|
78
70
|
record.entrants.forEach( script => {
|
|
79
|
-
|
|
71
|
+
if ( !script.textContent.trim() ) return;
|
|
80
72
|
runInContext( script.textContent, window );
|
|
81
73
|
} );
|
|
82
74
|
}, { subtree: true } );
|
|
83
75
|
}
|
|
84
|
-
//
|
|
76
|
+
// Sync callback?
|
|
85
77
|
if ( callback ) callback( window, window.wq.dom );
|
|
86
78
|
}
|
|
87
79
|
} );
|
|
88
|
-
// --------
|
|
89
80
|
return instance.window;
|
|
90
81
|
};
|
|
91
82
|
|
|
@@ -101,19 +92,4 @@ export function mockRemoteFetch( window, contents, delay = 1000 ) {
|
|
|
101
92
|
}, delay );
|
|
102
93
|
} );
|
|
103
94
|
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function printDocument( document, desc = '' ) {
|
|
107
|
-
return; new Promise( res => {
|
|
108
|
-
setTimeout( () => {
|
|
109
|
-
console.log( '' );
|
|
110
|
-
console.log( '-------------' );
|
|
111
|
-
console.log( desc );
|
|
112
|
-
console.log( '-------------' );
|
|
113
|
-
console.log( document.documentElement.outerHTML );
|
|
114
|
-
console.log( '-------------' );
|
|
115
|
-
console.log( '' );
|
|
116
|
-
res();
|
|
117
|
-
}, 0 );
|
|
118
|
-
} );
|
|
119
95
|
}
|
package/test/modules.test.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { expect } from 'chai';
|
|
6
6
|
import Observer from '@webqit/observer';
|
|
7
|
-
import { delay, createDocument, mockRemoteFetch,
|
|
7
|
+
import { delay, createDocument, mockRemoteFetch, _ } from './index.js';
|
|
8
8
|
const getQueryPath = str => str.split( '/' ).join( '/modules/' ).split( '/' );
|
|
9
9
|
|
|
10
10
|
describe(`HTML Modules`, function() {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
5
|
import { expect } from 'chai';
|
|
6
|
-
import { delay, createDocumentForScopedJS
|
|
6
|
+
import { delay, createDocumentForScopedJS } from './index.js';
|
|
7
7
|
|
|
8
8
|
describe(`Test: Scoped JS`, function() {
|
|
9
9
|
|
|
@@ -50,7 +50,7 @@ describe(`Test: Scoped JS`, function() {
|
|
|
50
50
|
await delay( 60 );
|
|
51
51
|
expect( window.testRecords ).to.have.length( 1 );
|
|
52
52
|
expect( window.testRecords[ 0 ] ).to.eql( window.document.body );
|
|
53
|
-
//console.log('::::::::::::', window.
|
|
53
|
+
//console.log('::::::::::::', window.testRecords );
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
});
|
package/test/test.html
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta name="oohtml" content="script.retention=hidden" />
|
|
5
|
-
<script src="/oohtml/dist/main.js"></script>
|
|
6
|
-
<script>
|
|
7
|
-
window.extVar = 'External variable initial value.';
|
|
8
|
-
window.Observer = wq.Observer;
|
|
9
|
-
</script>
|
|
10
|
-
<template exportid="temp0">
|
|
11
|
-
<input exportid="#input" />
|
|
12
|
-
<template exportid="temp1">
|
|
13
|
-
<textarea exportid="#input" placeholder="This is to be rendered"></textarea>
|
|
14
|
-
<template exportid="temp2">
|
|
15
|
-
<select exportid="#input"></select>
|
|
16
|
-
</template>
|
|
17
|
-
<template exportid="temp2b" inherits="#input"></template>
|
|
18
|
-
<template exportid="temp2c">
|
|
19
|
-
<textarea exportid="#input"></textarea>
|
|
20
|
-
</template>
|
|
21
|
-
</template>
|
|
22
|
-
</template>
|
|
23
|
-
</head>
|
|
24
|
-
<body>
|
|
25
|
-
|
|
26
|
-
<div importscontext="temp0/temp1">
|
|
27
|
-
<textarea exportid="#input" placeholder="This is server-rendered"></textarea>
|
|
28
|
-
<!--<import module="#input"></import>-->
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<div id="div1">
|
|
32
|
-
[1]: Scoped contract script here! See the console.
|
|
33
|
-
<script type="module" scoped contract>
|
|
34
|
-
console.log( '[1]: Execution context: ' + this.tagName, this.someProp );
|
|
35
|
-
console.log( '[1]: Dependencies: ', ( await [ ...this.scripts ][ 0 ].properties ).dependencies );
|
|
36
|
-
console.log( `[1]: ${ extVar }` );
|
|
37
|
-
this.addEventListener( 'remove', e => { console.log( '[1]: Removing...' ); } );
|
|
38
|
-
setTimeout( () => { this.remove(); }, 10000 );
|
|
39
|
-
</script>
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<div id="div2">
|
|
43
|
-
[2]: Scoped contract script here! See the console.
|
|
44
|
-
<script type="module" scoped contract>
|
|
45
|
-
console.log( '[2]: Execution context: ', this.tagName );
|
|
46
|
-
console.log( '[2]: Dependencies: ', ( await [ ...this.scripts ][ 0 ].properties ).dependencies );
|
|
47
|
-
console.log( `[2]: ${ extVar }` );
|
|
48
|
-
this.addEventListener( 'remove', e => { console.log( '[2]: Removing...' ); } );
|
|
49
|
-
setTimeout( () => { this.remove(); }, 10000 );
|
|
50
|
-
</script>
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
<script>
|
|
54
|
-
const div1 = document.querySelector( '#div1' );
|
|
55
|
-
setTimeout( () => {
|
|
56
|
-
Observer.set( globalThis, 'extVar', 'External variable updated value!' );
|
|
57
|
-
Observer.set( div1, 'someProp', 'someProp value!' );
|
|
58
|
-
setTimeout( () => {
|
|
59
|
-
Observer.set( globalThis, 'extVar', 'External variable updated value again!' );
|
|
60
|
-
}, 6000 );
|
|
61
|
-
/*
|
|
62
|
-
extVar = 'External variable updated value!';
|
|
63
|
-
div1.scripts.forEach( script => {
|
|
64
|
-
script.rerender( [ 'extVar' ] );
|
|
65
|
-
} );
|
|
66
|
-
*/
|
|
67
|
-
}, 5000 );
|
|
68
|
-
</script>
|
|
69
|
-
|
|
70
|
-
</body>
|
|
71
|
-
</html>
|