-
Notifications
You must be signed in to change notification settings - Fork 0
/
be-computed.ts
129 lines (108 loc) · 4 KB
/
be-computed.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import {BE, propDefaults, propInfo} from 'be-enhanced/BE.js';
import {BEConfig} from 'be-enhanced/types';
import {XE} from 'xtal-element/XE.js';
import {Actions, AllProps, AP, PAP, ProPAP, POA} from './types';
import {register} from 'be-hive/register.js';
import {rewrite} from './rewrite.js';
import {parse} from 'be-exporting/be-exporting.js';
import { ComputationObserver } from './ComputationObserver.js';
const cache = new Map<string, {}>();
const prsOnValuesCache = new Map<string, {}>();
const prsOnActionsCache = new Map<string, {}>();
export class BeComputed extends BE<AP, Actions> implements Actions{
static override get beConfig(){
return {
parse: true,
cache,
parseAndCamelize: true,
isParsedProp: 'isParsed'
} as BEConfig
}
#computationObservers: Array<ComputationObserver> = [];
override detach(detachedElement: Element): void {
for(const co of this.#computationObservers){
co.disconnect();
}
}
async onFrom(self: this) {
const {parsedFrom} = self;
let parsed = prsOnValuesCache.get(parsedFrom);
if(parsed === undefined){
const {prsFrom} = await import('./prsFrom.js');
parsed = prsFrom(self);
prsOnValuesCache.set(parsedFrom, parsed);
}
return parsed as PAP;
}
async hydrate(self: this){
const {fromStatements, enhancedElement} = self;
for(const fromStatement of fromStatements!){
let {
attrContainingExpression, args, previousElementScriptElement,
onloadOrPreviousElementScriptElement, importName
} = fromStatement;
if(args === undefined) throw 'NI';
let scriptText: string | null = null;
if(attrContainingExpression === undefined && !previousElementScriptElement){
if(onloadOrPreviousElementScriptElement){
if(enhancedElement.hasAttribute('onload')){
attrContainingExpression = 'onload';
}else{
previousElementScriptElement = true;
}
}else{
throw 400;
}
}
if(previousElementScriptElement){
const {upSearch} = await import('trans-render/lib/upSearch.js');
const scriptElement = upSearch(enhancedElement, 'script');
if(!(scriptElement instanceof HTMLScriptElement)) throw 404;
scriptText = scriptElement.innerHTML;
}else{
scriptText = enhancedElement.getAttribute(attrContainingExpression!);
if(scriptText === null) throw 404;
}
const rewritten = rewrite(scriptText!, args.map(x => x.remoteProp!));
const parsedJavaScript = await parse(rewritten);
const expr = parsedJavaScript[importName || 'expr'];
this.#computationObservers.push(
new ComputationObserver(expr, fromStatement, args, enhancedElement, self
));
}
return {
resolved: true
}
}
}
export interface BeComputed extends AllProps{}
const tagName = 'be-computed';
const ifWantsToBe = 'computed';
const upgrade = '*';
const xe = new XE<AP, Actions>({
config: {
tagName,
isEnh: true,
propDefaults:{
...propDefaults,
scriptRef: 'previousElementSibling',
nameOfExport: 'expr'
},
propInfo: {
...propInfo
},
actions:{
onFrom: {
ifAllOf: ['isParsed', 'from'],
},
// importSymbols: {
// ifAllOf: ['isParsed', 'nameOfExport', 'instructions', 'scriptRef']
// },
hydrate:{
ifAllOf: ['fromStatements']
}
}
},
superclass: BeComputed
});
register(ifWantsToBe, upgrade, tagName);