@webqit/oohtml 2.1.52 → 2.1.53
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/README.md +14 -18
- package/dist/bindings-api.js +1 -1
- package/dist/bindings-api.js.map +3 -3
- package/dist/context-api.js +1 -1
- package/dist/context-api.js.map +3 -3
- package/dist/html-bracelets.js +2 -0
- package/dist/html-bracelets.js.map +7 -0
- package/dist/html-imports.js +1 -1
- package/dist/html-imports.js.map +3 -3
- package/dist/html-namespaces.js +2 -0
- package/dist/html-namespaces.js.map +7 -0
- package/dist/main.js +16 -24
- package/dist/main.js.map +3 -3
- package/dist/scoped-css.js +2 -2
- package/dist/scoped-css.js.map +3 -3
- package/dist/scoped-js.js +15 -23
- package/dist/scoped-js.js.map +3 -3
- package/package.json +7 -7
- package/src/bindings-api/_HTMLBindingsProvider.js +38 -0
- package/src/bindings-api/index.js +49 -26
- package/src/context-api/ContextReturnValue.js +22 -0
- package/src/context-api/HTMLContext.js +14 -6
- package/src/context-api/HTMLContextProvider.js +27 -10
- package/src/context-api/_ContextRequestEvent.js +2 -2
- package/src/context-api/index.js +26 -10
- package/src/html-bracelets/AttrBracelet.js +109 -0
- package/src/html-bracelets/Bracelet.js +78 -0
- package/src/html-bracelets/HTMLBracelets.js +67 -0
- package/src/html-bracelets/TextBracelet.js +69 -0
- package/src/html-bracelets/index.js +71 -0
- package/src/html-bracelets/targets.browser.js +10 -0
- package/src/html-imports/_HTMLExportsManager.js +2 -2
- package/src/html-imports/_HTMLImportsProvider.js +3 -9
- package/src/html-imports/index.js +8 -8
- package/src/{namespace-api → html-namespaces}/index.js +25 -25
- package/src/index.js +14 -12
- package/src/scoped-js/Hash.js +26 -0
- package/src/scoped-js/index.js +63 -63
- package/test/index.js +1 -1
- package/test/modules.test.js +1 -1
- package/test/scoped-js.test.js +1 -1
- package/dist/namespace-api.js +0 -2
- package/dist/namespace-api.js.map +0 -7
- package/src/scoped-js/Compiler.js +0 -299
- /package/src/{namespace-api → html-namespaces}/targets.browser.js +0 -0
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
export default class Compiler {
|
|
3
|
-
|
|
4
|
-
// Unique ID generator
|
|
5
|
-
static hashTable = new Map;
|
|
6
|
-
static uniqId = () => (0|Math.random()*9e6).toString(36);
|
|
7
|
-
|
|
8
|
-
// Hash of anything generator
|
|
9
|
-
static toHash( val ) {
|
|
10
|
-
let hash;
|
|
11
|
-
if ( !( hash = this.hashTable.get( val ) ) ) {
|
|
12
|
-
hash = this.uniqId();
|
|
13
|
-
this.hashTable.set( val, hash );
|
|
14
|
-
}
|
|
15
|
-
return hash;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Value of any hash
|
|
19
|
-
static fromHash( hash ) {
|
|
20
|
-
let val;
|
|
21
|
-
this.hashTable.forEach( ( _hash, _val ) => {
|
|
22
|
-
if ( _hash === hash ) val = _val;
|
|
23
|
-
} );
|
|
24
|
-
return val;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Set window property
|
|
28
|
-
constructor( window, config, executeCallback ) {
|
|
29
|
-
this.window = window;
|
|
30
|
-
this.config = config;
|
|
31
|
-
// This is a global function
|
|
32
|
-
window.webqit.oohtml.Script.run = execHash => {
|
|
33
|
-
const exec = this.constructor.fromHash( execHash );
|
|
34
|
-
if ( !exec ) throw new Error( `Argument must be a valid exec hash.` );
|
|
35
|
-
const { script, compiledScript, thisContext } = exec;
|
|
36
|
-
if ( thisContext instanceof window.Element && script.scoped ) {
|
|
37
|
-
if ( !thisContext.scripts ) { Object.defineProperty( thisContext, 'scripts', { value: new Set } ); }
|
|
38
|
-
thisContext.scripts.add( script );
|
|
39
|
-
}
|
|
40
|
-
switch ( config.script.retention ) {
|
|
41
|
-
case 'dispose':
|
|
42
|
-
script.remove();
|
|
43
|
-
break;
|
|
44
|
-
case 'hidden':
|
|
45
|
-
script.textContent = `"source hidden"`;
|
|
46
|
-
break;
|
|
47
|
-
default:
|
|
48
|
-
script.textContent = compiledScript.function.originalSource;
|
|
49
|
-
}
|
|
50
|
-
return executeCallback.call( window, compiledScript, thisContext, script );
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Compile scipt
|
|
55
|
-
compile( script, thisContext ) {
|
|
56
|
-
const _static = this.constructor;
|
|
57
|
-
const { webqit: { oohtml, ReflexFunction } } = this.window;
|
|
58
|
-
const cache = oohtml.Script.compileCache[ script.reflex ? 0 : 1 ];
|
|
59
|
-
const textContent = ( script._ = script.textContent.trim() ) && script._.startsWith( '/*@oohtml*/if(false){' ) && script._.endsWith( '}/*@oohtml*/' ) ? script._.slice( 21, -12 ) : script.textContent;
|
|
60
|
-
const sourceHash = _static.toHash( textContent );
|
|
61
|
-
// Script instances are parsed only once
|
|
62
|
-
let source = textContent, compiledScript;
|
|
63
|
-
if ( !( compiledScript = cache.get( sourceHash ) ) ) {
|
|
64
|
-
// Are there "import" (and "await") statements? Then, we need to rewrite that
|
|
65
|
-
let imports = [], meta = {};
|
|
66
|
-
let targetKeywords = [];
|
|
67
|
-
if ( script.type === 'module' ) targetKeywords.push( 'import ' );
|
|
68
|
-
if ( script.type === 'module' && !script.reflex ) targetKeywords.push( 'await ' );
|
|
69
|
-
if ( targetKeywords.length && ( new RegExp( targetKeywords.join( '|' ) ) ).test( source ) ) {
|
|
70
|
-
[ imports, source, meta ] = this.parse( source );
|
|
71
|
-
if ( imports.length ) {
|
|
72
|
-
source = `\n\t${ this.rewriteImportStmts( imports ).join( `\n\t` ) }\n\t${ source }\n`;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// Let's obtain a material functions
|
|
76
|
-
let _Function, { parserParams, compilerParams, runtimeParams } = this.config.advanced;
|
|
77
|
-
if ( script.reflex ) {
|
|
78
|
-
parserParams = { ...parserParams, allowAwaitOutsideFunction: script.type === 'module' };
|
|
79
|
-
runtimeParams = { ...runtimeParams, async: script.type === 'module' };
|
|
80
|
-
_Function = ReflexFunction( source, { compilerParams, parserParams, runtimeParams, } );
|
|
81
|
-
Object.defineProperty( script, 'properties', { configurable: true, value: ReflexFunction.inspect( _Function ) } );
|
|
82
|
-
} else {
|
|
83
|
-
const isAsync = script.type === 'module'//meta.topLevelAwait || imports.length;
|
|
84
|
-
const _FunctionConstructor = isAsync ? Object.getPrototypeOf( async function() {} ).constructor : Function;
|
|
85
|
-
_Function = runtimeParams?.compileFunction
|
|
86
|
-
? runtimeParams.compileFunction( source )
|
|
87
|
-
: new _FunctionConstructor( source );
|
|
88
|
-
}
|
|
89
|
-
Object.defineProperty( _Function, 'originalSource', { configurable: true, value: textContent } );
|
|
90
|
-
// Save material function to compile cache
|
|
91
|
-
compiledScript = Object.defineProperty( script.cloneNode(), 'function', { value: _Function } );
|
|
92
|
-
script.scoped && Object.defineProperty( compiledScript, 'scoped', Object.getOwnPropertyDescriptor( script, 'scoped') );
|
|
93
|
-
script.reflex && Object.defineProperty( compiledScript, 'reflex', Object.getOwnPropertyDescriptor( script, 'reflex') );
|
|
94
|
-
cache.set( sourceHash, compiledScript );
|
|
95
|
-
}
|
|
96
|
-
const execHash = _static.toHash( { script, compiledScript, thisContext } );
|
|
97
|
-
if ( script.handling === 'manual' ) {
|
|
98
|
-
webqit.oohtml.Script.run( execHash );
|
|
99
|
-
} else {
|
|
100
|
-
script.textContent = `webqit.oohtml.Script.run( '${ execHash }' );`;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Match import statements
|
|
105
|
-
// and detect top-level await
|
|
106
|
-
parse( source ) {
|
|
107
|
-
const [ tokens, meta ] = this.tokenize( source, ( $tokens, event, char, meta, i, isLastChar ) => {
|
|
108
|
-
|
|
109
|
-
if ( event === 'start-enclosure' && char === '{' && !meta.openAsync?.type && meta.openEnclosures.length === meta.openAsync?.scopeId ) {
|
|
110
|
-
meta.openAsync.type = 'block';
|
|
111
|
-
} else if ( event === 'end-enclosure' && char === '}' && meta.openAsync?.type === 'block' && meta.openEnclosures.length === meta.openAsync.scopeId ) {
|
|
112
|
-
meta.openAsync = null;
|
|
113
|
-
} else if ( event === 'start-quote' && !meta.openEnclosures.length && [ 'starting', 'from' ].includes( meta.openImport ) ) {
|
|
114
|
-
meta.openImport = 'url';
|
|
115
|
-
} else if ( event === 'end-quote' && meta.openImport === 'url' ) {
|
|
116
|
-
meta.openImport = 'closing';
|
|
117
|
-
} else if ( event === 'char' ) {
|
|
118
|
-
|
|
119
|
-
if ( meta.openImport === 'closing' && (
|
|
120
|
-
char === ';'/* explicit */ || ![ ' ', `\n` ].includes( char )/* implicit */ || isLastChar
|
|
121
|
-
) ) {
|
|
122
|
-
if ( char === ';' || isLastChar ) {
|
|
123
|
-
$tokens[ 0 ] += char;
|
|
124
|
-
$tokens.unshift( '' );
|
|
125
|
-
} else { $tokens.unshift( char ); }
|
|
126
|
-
meta.openImport = null;
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
let remainder = source.substring( i - 1 );
|
|
131
|
-
|
|
132
|
-
if ( !meta.openImport && /^[\W]?import[ ]*[^\(]/.test( remainder ) ) {
|
|
133
|
-
meta.openImport = 'starting';
|
|
134
|
-
$tokens.unshift( '' );
|
|
135
|
-
return 6;
|
|
136
|
-
}
|
|
137
|
-
if ( meta.openImport === 'starting' && /^[\W]?from /.test( remainder ) ) {
|
|
138
|
-
meta.openImport = 'from';
|
|
139
|
-
return 4;
|
|
140
|
-
}
|
|
141
|
-
if ( !meta.openAsync ) {
|
|
142
|
-
if ( /^[\W]?async /.test( remainder ) ) {
|
|
143
|
-
meta.openAsync = { scopeId: meta.openEnclosures.length };
|
|
144
|
-
return 5;
|
|
145
|
-
}
|
|
146
|
-
if ( /^[\W]?await /.test( remainder ) ) {
|
|
147
|
-
meta.topLevelAwait = true;
|
|
148
|
-
return 5;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if ( meta.openAsync ) {
|
|
152
|
-
if ( !meta.openAsync.type && /.?\=\>[ ]*?\{/.test( remainder ) ) {
|
|
153
|
-
meta.openAsync.type = 'inline-arrow';
|
|
154
|
-
} else if ( meta.openAsync.type === 'inline-arrow' && [ `\n`, ';' ].includes( char ) && meta.openEnclosures.length === meta.openAsync.scopeId ) {
|
|
155
|
-
meta.openAsync = null;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
} );
|
|
162
|
-
// Hoist all import statements
|
|
163
|
-
let imports = [], body = '', _str;
|
|
164
|
-
for ( const str of tokens.reverse() ) {
|
|
165
|
-
if ( ( _str = str.trim() ).startsWith( 'import ' ) ) {
|
|
166
|
-
imports.push( str );
|
|
167
|
-
} else if ( _str ) { body += str; }
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return [ imports, body, meta ];
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Rewrite import statements
|
|
174
|
-
rewriteImportStmts( imports ) {
|
|
175
|
-
const importSpecs = [], importPromises = [];
|
|
176
|
-
imports.forEach( ( $import, i ) => {
|
|
177
|
-
$import = parseImportStmt( $import );
|
|
178
|
-
// Identify whole imports and individual imports
|
|
179
|
-
const [ wholeImport, individualImports ] = $import.items.reduce( ( [ whole, parts ], item ) => {
|
|
180
|
-
return item.id === '*' ? [ item.alias, parts ] : [ whole, parts.concat( item ) ];
|
|
181
|
-
}, [ null, [] ] );
|
|
182
|
-
if ( wholeImport ) {
|
|
183
|
-
// const main = await import("url");
|
|
184
|
-
importSpecs.push( `const ${ wholeImport } = __$imports$__[${ i }];` );
|
|
185
|
-
}
|
|
186
|
-
if ( individualImports.length ) {
|
|
187
|
-
// const { aa: bb, cc } = await import("url");
|
|
188
|
-
const individualImportsSpec = individualImports.map( item => `${ item.id }${ item.id !== item.alias ? `: ${ item.alias }` : '' }` ).join( ', ' );
|
|
189
|
-
importSpecs.push( `const { ${ individualImportsSpec } } = __$imports$__[${ i }];` );
|
|
190
|
-
}
|
|
191
|
-
importPromises.push( `import("${ $import.url }")` );
|
|
192
|
-
} );
|
|
193
|
-
return [
|
|
194
|
-
`\n\tconst __$imports$__ = await Promise.all([\n\t\t${ importPromises.join( `,\n\t\t` ) }\n\t]);`,
|
|
195
|
-
importSpecs.join( `\n\t` ),
|
|
196
|
-
];
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Parse import statements
|
|
200
|
-
parseImportStmt( str ) {
|
|
201
|
-
const getUrl = str => {
|
|
202
|
-
let quo = /^[`'"]/.exec( str );
|
|
203
|
-
return quo && str.substring( 1, str.lastIndexOf( quo[ 0 ] ) );
|
|
204
|
-
}
|
|
205
|
-
let $import = { items: [ { id: '' } ] }, _str = str.replace( 'import', '' ).trim();
|
|
206
|
-
if ( !( $import.url = getUrl( _str ) ) ) {
|
|
207
|
-
this.tokenize( _str, ( $tokens, event, char, meta, i, isLastChar ) => {
|
|
208
|
-
if ( [ 'start-quote', 'ongoing-quote', 'end-quote', 'char' ].includes( event ) ) {
|
|
209
|
-
if ( $import.url ) return;
|
|
210
|
-
if ( !meta.openQuote ) {
|
|
211
|
-
let remainder = _str.substring( i );
|
|
212
|
-
if ( char === ',' ) {
|
|
213
|
-
$import.items.unshift( { id: '' } );
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
if ( remainder.startsWith( ' as ' ) ) {
|
|
217
|
-
$import.items[ 0 ].alias = '';
|
|
218
|
-
return 3;
|
|
219
|
-
}
|
|
220
|
-
if ( remainder.startsWith( ' from ' ) ) {
|
|
221
|
-
$import.url = getUrl( remainder.replace( 'from', '' ).trim() );
|
|
222
|
-
return remainder.length;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
if ( 'alias' in $import.items[ 0 ] ) {
|
|
226
|
-
$import.items[ 0 ].alias += char;
|
|
227
|
-
} else {
|
|
228
|
-
$import.items[ 0 ].id += char;
|
|
229
|
-
if ( meta.openEnclosures.length ) {
|
|
230
|
-
$import.items[ 0 ].enclosed = true;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
} );
|
|
235
|
-
}
|
|
236
|
-
$import.items = $import.items
|
|
237
|
-
.map( item => ( {
|
|
238
|
-
id: item.id && !item.alias && !item.enclosed ? 'default' : item.id.trim(),
|
|
239
|
-
alias: item.alias ? item.alias.trim() : item.id.trim(),
|
|
240
|
-
} ) )
|
|
241
|
-
.filter( item => item.id )
|
|
242
|
-
.reverse();
|
|
243
|
-
return $import;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Token JavaScript source
|
|
247
|
-
tokenize( source, _callback ) {
|
|
248
|
-
const lastI = source.length - 1;
|
|
249
|
-
return [ ...source ].reduce( ( [ $tokens, meta, skip ], char, i ) => {
|
|
250
|
-
|
|
251
|
-
if ( skip ) {
|
|
252
|
-
$tokens[ 0 ] += char;
|
|
253
|
-
return [ $tokens, meta, --skip ];
|
|
254
|
-
}
|
|
255
|
-
let callbackReturn;
|
|
256
|
-
|
|
257
|
-
if ( meta.openQuote || meta.openComment ) {
|
|
258
|
-
if ( char === meta.openQuote ) {
|
|
259
|
-
meta.openQuote = null;
|
|
260
|
-
callbackReturn = _callback( $tokens, 'end-quote', char, meta, i, i === lastI );
|
|
261
|
-
} else if ( meta.openQuote ) {
|
|
262
|
-
callbackReturn = _callback( $tokens, 'ongoing-quote', char, meta, i, i === lastI );
|
|
263
|
-
} else if ( meta.openComment ) {
|
|
264
|
-
if ( ( meta.openComment === '//' && char === `\n` ) || ( meta.openComment === '/*' && $tokens[ 0 ].substr( -1 ) === '*' && char === '/' ) ) {
|
|
265
|
-
meta.openComment = null;
|
|
266
|
-
callbackReturn = _callback( $tokens, 'end-comment', char, meta, i, i === lastI );
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
if ( callbackReturn !== false ) {
|
|
270
|
-
$tokens[ 0 ] += char;
|
|
271
|
-
}
|
|
272
|
-
return [ $tokens, meta, typeof callbackReturn === 'number' ? callbackReturn : skip ];
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
let enclosure;
|
|
276
|
-
if ( enclosure = [ '()', '{}', '[]' ].filter( pair => char === pair[ 0 ] )[ 0 ] ) {
|
|
277
|
-
callbackReturn = _callback( $tokens, 'start-enclosure', char, meta, i, i === lastI );
|
|
278
|
-
meta.openEnclosures.unshift( enclosure );
|
|
279
|
-
} else if ( meta.openEnclosures.length && char === meta.openEnclosures[ 0 ][ 1 ] ) {
|
|
280
|
-
meta.openEnclosures.shift();
|
|
281
|
-
callbackReturn = _callback( $tokens, 'end-enclosure', char, meta, i, i === lastI );
|
|
282
|
-
} else if ( [ '"', "'", "`" ].includes( char ) ) {
|
|
283
|
-
callbackReturn = _callback( $tokens, 'start-quote', char, meta, i, i === lastI );
|
|
284
|
-
meta.openQuote = char;
|
|
285
|
-
} else if ( !meta.openComment && [ '/*', '//' ].includes( source.substr( i, 2 ) ) ) {
|
|
286
|
-
callbackReturn = _callback( $tokens, 'start-comment', char, meta, i, i === lastI );
|
|
287
|
-
meta.openComment = source.substr( i, 2 );
|
|
288
|
-
} else {
|
|
289
|
-
callbackReturn = _callback( $tokens, 'char', char, meta, i, i === lastI );
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if ( callbackReturn !== false ) {
|
|
293
|
-
$tokens[ 0 ] += char;
|
|
294
|
-
}
|
|
295
|
-
return [ $tokens, meta, typeof callbackReturn === 'number' ? callbackReturn : skip ];
|
|
296
|
-
|
|
297
|
-
}, [ [ '' ], { openEnclosures: [], }, 0 ] );
|
|
298
|
-
}
|
|
299
|
-
}
|
|
File without changes
|