Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
titaniumnetwork-dev
GitHub Repository: titaniumnetwork-dev/Ultraviolet
Path: blob/main/src/rewrite/rewrite.script.js
304 views
1
/**
2
* @typedef {import('./index').default} Ultraviolet
3
*/
4
5
/**
6
*
7
* @param {Ultraviolet} ctx
8
*/
9
function property(ctx) {
10
const { js } = ctx;
11
js.on("MemberExpression", (node, data, type) => {
12
if (node.object.type === "Super") return false;
13
14
if (type === "rewrite" && computedProperty(node)) {
15
data.changes.push({
16
node: "__uv.$wrap((",
17
start: node.property.start,
18
end: node.property.start,
19
});
20
node.iterateEnd = function () {
21
data.changes.push({
22
node: "))",
23
start: node.property.end,
24
end: node.property.end,
25
});
26
};
27
}
28
29
if (
30
(!node.computed &&
31
node.property.name === "location" &&
32
type === "rewrite") ||
33
(node.property.name === "__uv$location" && type === "source")
34
) {
35
data.changes.push({
36
start: node.property.start,
37
end: node.property.end,
38
node:
39
type === "rewrite"
40
? "__uv$setSource(__uv).__uv$location"
41
: "location",
42
});
43
}
44
45
if (
46
(!node.computed && node.property.name === "top" && type === "rewrite") ||
47
(node.property.name === "__uv$top" && type === "source")
48
) {
49
data.changes.push({
50
start: node.property.start,
51
end: node.property.end,
52
node: type === "rewrite" ? "__uv$setSource(__uv).__uv$top" : "top",
53
});
54
}
55
56
if (
57
(!node.computed &&
58
node.property.name === "parent" &&
59
type === "rewrite") ||
60
(node.property.name === "__uv$parent" && type === "source")
61
) {
62
data.changes.push({
63
start: node.property.start,
64
end: node.property.end,
65
node:
66
type === "rewrite" ? "__uv$setSource(__uv).__uv$parent" : "parent",
67
});
68
}
69
70
if (
71
!node.computed &&
72
node.property.name === "postMessage" &&
73
type === "rewrite"
74
) {
75
data.changes.push({
76
start: node.property.start,
77
end: node.property.end,
78
node: "__uv$setSource(__uv).postMessage",
79
});
80
}
81
82
if (
83
(!node.computed && node.property.name === "eval" && type === "rewrite") ||
84
(node.property.name === "__uv$eval" && type === "source")
85
) {
86
data.changes.push({
87
start: node.property.start,
88
end: node.property.end,
89
node: type === "rewrite" ? "__uv$setSource(__uv).__uv$eval" : "eval",
90
});
91
}
92
93
if (
94
!node.computed &&
95
node.property.name === "__uv$setSource" &&
96
type === "source" &&
97
node.parent.type === "CallExpression"
98
) {
99
const { parent, property } = node;
100
data.changes.push({
101
start: property.start - 1,
102
end: parent.end,
103
});
104
105
node.iterateEnd = function () {
106
data.changes.push({
107
start: property.start,
108
end: parent.end,
109
});
110
};
111
}
112
});
113
}
114
115
/**
116
*
117
* @param {Ultraviolet} ctx
118
*/
119
function identifier(ctx) {
120
const { js } = ctx;
121
js.on("Identifier", (node, data, type) => {
122
if (type !== "rewrite") return false;
123
const { parent } = node;
124
if (!["location", "eval", "parent", "top"].includes(node.name))
125
return false;
126
if (parent.type === "VariableDeclarator" && parent.id === node)
127
return false;
128
if (
129
(parent.type === "AssignmentExpression" ||
130
parent.type === "AssignmentPattern") &&
131
parent.left === node
132
)
133
return false;
134
if (
135
(parent.type === "FunctionExpression" ||
136
parent.type === "FunctionDeclaration") &&
137
parent.id === node
138
)
139
return false;
140
if (
141
parent.type === "MemberExpression" &&
142
parent.property === node &&
143
!parent.computed
144
)
145
return false;
146
if (
147
node.name === "eval" &&
148
parent.type === "CallExpression" &&
149
parent.callee === node
150
)
151
return false;
152
if (parent.type === "Property" && parent.key === node) return false;
153
if (parent.type === "Property" && parent.value === node && parent.shorthand)
154
return false;
155
if (
156
parent.type === "UpdateExpression" &&
157
(parent.operator === "++" || parent.operator === "--")
158
)
159
return false;
160
if (
161
(parent.type === "FunctionExpression" ||
162
parent.type === "FunctionDeclaration" ||
163
parent.type === "ArrowFunctionExpression") &&
164
parent.params.indexOf(node) !== -1
165
)
166
return false;
167
if (parent.type === "MethodDefinition") return false;
168
if (parent.type === "ClassDeclaration") return false;
169
if (parent.type === "RestElement") return false;
170
if (parent.type === "ExportSpecifier") return false;
171
if (parent.type === "ImportSpecifier") return false;
172
173
data.changes.push({
174
start: node.start,
175
end: node.end,
176
node: "__uv.$get(" + node.name + ")",
177
});
178
});
179
}
180
181
/**
182
*
183
* @param {Ultraviolet} ctx
184
*/
185
function wrapEval(ctx) {
186
const { js } = ctx;
187
js.on("CallExpression", (node, data, type) => {
188
if (type !== "rewrite") return false;
189
if (!node.arguments.length) return false;
190
if (node.callee.type !== "Identifier") return false;
191
if (node.callee.name !== "eval") return false;
192
193
const [script] = node.arguments;
194
195
data.changes.push({
196
node: "__uv.js.rewrite(",
197
start: script.start,
198
end: script.start,
199
});
200
node.iterateEnd = function () {
201
data.changes.push({
202
node: ")",
203
start: script.end,
204
end: script.end,
205
});
206
};
207
});
208
}
209
210
/**
211
*
212
* @param {Ultraviolet} ctx
213
*/
214
function importDeclaration(ctx) {
215
const { js } = ctx;
216
js.on("Literal", (node, data, type) => {
217
if (
218
!(
219
(node.parent.type === "ImportDeclaration" ||
220
node.parent.type === "ExportAllDeclaration" ||
221
node.parent.type === "ExportNamedDeclaration") &&
222
node.parent.source === node
223
)
224
)
225
return false;
226
227
data.changes.push({
228
start: node.start + 1,
229
end: node.end - 1,
230
node:
231
type === "rewrite"
232
? ctx.rewriteUrl(node.value)
233
: ctx.sourceUrl(node.value),
234
});
235
});
236
}
237
238
/**
239
*
240
* @param {Ultraviolet} ctx
241
*/
242
function dynamicImport(ctx) {
243
const { js } = ctx;
244
js.on("ImportExpression", (node, data, type) => {
245
if (type !== "rewrite") return false;
246
data.changes.push({
247
// pass script URL to dynamicImport
248
// import() is always relative to script URL
249
node: `__uv.rewriteImport(${JSON.stringify(ctx.meta.url)},`,
250
start: node.source.start,
251
end: node.source.start,
252
});
253
node.iterateEnd = function () {
254
data.changes.push({
255
node: ")",
256
start: node.source.end,
257
end: node.source.end,
258
});
259
};
260
});
261
}
262
263
/**
264
* @param {Ultraviolet} ctx
265
*/
266
function importMeta(ctx) {
267
const { js } = ctx;
268
js.on("MemberExpression", (node, data, type) => {
269
if (
270
node.object.type == "MetaProperty" &&
271
node.property.type === "Identifier" &&
272
node.property.name === "url"
273
) {
274
if (type === "rewrite") {
275
data.changes.push({
276
start: node.start,
277
end: node.end,
278
node: `__uv.sourceUrl(import.meta.url)`,
279
});
280
} else if (type === "source") {
281
data.changes.push({
282
start: node.start,
283
end: node.end,
284
node: `import.meta.url`,
285
});
286
}
287
}
288
});
289
}
290
291
/**
292
*
293
* @param {Ultraviolet} ctx
294
*/
295
function unwrap(ctx) {
296
const { js } = ctx;
297
js.on("CallExpression", (node, data, type) => {
298
if (type !== "source") return false;
299
if (!isWrapped(node.callee)) return false;
300
301
switch (node.callee.property.name) {
302
case "$wrap":
303
{
304
if (
305
!node.arguments ||
306
node.parent.type !== "MemberExpression" ||
307
node.parent.property !== node
308
)
309
return false;
310
const [property] = node.arguments;
311
312
data.changes.push({
313
start: node.callee.start,
314
end: property.start,
315
});
316
317
node.iterateEnd = function () {
318
data.changes.push({
319
start: node.end - 2,
320
end: node.end,
321
});
322
};
323
}
324
break;
325
case "$get":
326
case "rewriteUrl":
327
{
328
const [arg] = node.arguments;
329
330
data.changes.push({
331
start: node.callee.start,
332
end: arg.start,
333
});
334
335
node.iterateEnd = function () {
336
data.changes.push({
337
start: node.end - 1,
338
end: node.end,
339
});
340
};
341
}
342
break;
343
case "rewrite":
344
{
345
const [script] = node.arguments;
346
data.changes.push({
347
start: node.callee.start,
348
end: script.start,
349
});
350
node.iterateEnd = function () {
351
data.changes.push({
352
start: node.end - 1,
353
end: node.end,
354
});
355
};
356
}
357
break;
358
}
359
});
360
}
361
362
function isWrapped(node) {
363
if (node.type !== "MemberExpression") return false;
364
if (node.property.name === "rewrite" && isWrapped(node.object)) return true;
365
if (node.object.type !== "Identifier" || node.object.name !== "__uv")
366
return false;
367
if (!["js", "$get", "$wrap", "rewriteUrl"].includes(node.property.name))
368
return false;
369
return true;
370
}
371
372
function computedProperty(parent) {
373
if (!parent.computed) return false;
374
const { property: node } = parent;
375
if (node.type === "Literal" && !["location", "top", "parent"]) return false;
376
return true;
377
}
378
379
export {
380
property,
381
wrapEval,
382
dynamicImport,
383
importDeclaration,
384
importMeta,
385
identifier,
386
unwrap,
387
};
388
389