mirror of
https://github.com/titaniumnetwork-dev/Ultraviolet.git
synced 2025-05-14 12:20:01 -04:00
122 lines
No EOL
3.9 KiB
JavaScript
122 lines
No EOL
3.9 KiB
JavaScript
import { parseScript } from 'meriyah';
|
|
// import { parse } from 'acorn-hammerhead';
|
|
import { generate } from 'esotope-hammerhead';
|
|
import EventEmitter from './events.js';
|
|
|
|
class JS extends EventEmitter {
|
|
constructor() {
|
|
super();
|
|
/*
|
|
this.parseOptions = {
|
|
allowReturnOutsideFunction: true,
|
|
allowImportExportEverywhere: true,
|
|
ecmaVersion: 2021,
|
|
};
|
|
*/
|
|
this.parseOptions = {
|
|
ranges: true,
|
|
module: true,
|
|
globalReturn: true,
|
|
};
|
|
this.generationOptions = {
|
|
format: {
|
|
quotes: 'double',
|
|
escapeless: true,
|
|
compact: true,
|
|
},
|
|
};
|
|
this.parse = parseScript /*parse*/;
|
|
this.generate = generate;
|
|
};
|
|
rewrite(str, data = {}) {
|
|
return this.recast(str, data, 'rewrite');
|
|
};
|
|
source(str, data = {}) {
|
|
return this.recast(str, data, 'source');
|
|
};
|
|
recast(str, data = {}, type = '') {
|
|
try {
|
|
const output = [];
|
|
const ast = this.parse(str, this.parseOptions);
|
|
const meta = {
|
|
data,
|
|
changes: [],
|
|
input: str,
|
|
ast,
|
|
get slice() {
|
|
return slice;
|
|
},
|
|
};
|
|
let slice = 0;
|
|
|
|
this.iterate(ast, (node, parent = null) => {
|
|
if (parent && parent.inTransformer) node.isTransformer = true;
|
|
node.parent = parent;
|
|
|
|
this.emit(node.type, node, meta, type);
|
|
});
|
|
|
|
meta.changes.sort((a, b) => (a.start - b.start) || (a.end - b.end));
|
|
|
|
for (const change of meta.changes) {
|
|
if ('start' in change && typeof change.start === 'number') output.push(str.slice(slice, change.start));
|
|
if (change.node) output.push(typeof change.node === 'string' ? change.node : generate(change.node, this.generationOptions));
|
|
if ('end' in change && typeof change.end === 'number') slice = change.end;
|
|
};
|
|
output.push(str.slice(slice));
|
|
return output.join('');
|
|
} catch(e) {
|
|
return str;
|
|
};
|
|
};
|
|
iterate(ast, handler) {
|
|
if (typeof ast != 'object' || !handler) return;
|
|
walk(ast, null, handler);
|
|
function walk(node, parent, handler) {
|
|
if (typeof node != 'object' || !handler) return;
|
|
handler(node, parent, handler);
|
|
for (const child in node) {
|
|
if (child === 'parent') continue;
|
|
if (Array.isArray(node[child])) {
|
|
node[child].forEach(entry => {
|
|
if (entry) walk(entry, node, handler)
|
|
});
|
|
} else {
|
|
if (node[child]) walk(node[child], node, handler);
|
|
};
|
|
};
|
|
if (typeof node.iterateEnd === 'function') node.iterateEnd();
|
|
};
|
|
};
|
|
};
|
|
|
|
class NodeEvent extends EventEmitter {
|
|
constructor(node, parent = null) {
|
|
super();
|
|
this._node = node;
|
|
for (let key in node) {
|
|
Object.defineProperty(this, key, {
|
|
get: () => node[key],
|
|
sel: val => node[key] = val,
|
|
});
|
|
};
|
|
this.parent = parent;
|
|
};
|
|
iterate(handler) {
|
|
for (const key in this._node) {
|
|
if (key === 'parent') continue;
|
|
if (Array.isArray(this._node[key])) {
|
|
this._node[key].forEach(entry => {
|
|
const child = new this.constructor(entry, this._node);
|
|
handler(child);
|
|
});
|
|
} else {
|
|
const child = new this.constructor(entry, this._node);
|
|
walk(this._node[key], this._node, handler);
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
export default JS;
|
|
export { NodeEvent }; |