this repo has no description

LunAST: Fix some misc issues

+49 -25
+11 -6
packages/core/src/patch.ts
··· 75 75 } 76 76 77 77 for (const [id, func] of Object.entries(entry)) { 78 + if (func.__moonlight === true) continue; 78 79 let moduleString = Object.hasOwn(moduleCache, id) 79 80 ? moduleCache[id] 80 81 : func.toString().replace(/\n/g, ""); ··· 150 151 } 151 152 } 152 153 153 - let parsed = moonlight.lunast.parseScript(id, `(${moduleString})`); 154 - if (parsed != null) { 155 - // parseScript adds an extra ; for some reason 156 - parsed = parsed.trimEnd().substring(0, parsed.lastIndexOf(";")); 157 - if (patchModule(id, "lunast", parsed)) { 158 - moduleString = parsed; 154 + try { 155 + let parsed = moonlight.lunast.parseScript(id, `(\n${moduleString}\n)`); 156 + if (parsed != null) { 157 + // parseScript adds an extra ; for some reason 158 + parsed = parsed.trimEnd().substring(0, parsed.lastIndexOf(";")); 159 + if (patchModule(id, "lunast", parsed)) { 160 + moduleString = parsed; 161 + } 159 162 } 163 + } catch (e) { 164 + logger.error("Failed to parse script for LunAST", id, e); 160 165 } 161 166 162 167 if (moonlightNode.config.patchAll === true) {
+4
packages/lunast/TODO.md
··· 2 2 3 3 - [ ] Experiment more! We need to know what's bad with this 4 4 - [ ] Write utility functions for imports, exports, etc. 5 + - [ ] Imports 6 + - [ ] Exports 7 + - [ ] Constant bindings for an object 5 8 - [ ] Map Z/ZP to default 6 9 - [x] Steal Webpack require and use it in our LunAST instance 7 10 - [ ] Map `import` statements to LunAST ··· 11 14 - [ ] Run in parallel with service workers 12 15 - This is gonna require making Webpack entrypoint async and us doing kickoff ourselves 13 16 - [ ] Support lazy loaded chunks 17 + - Works right now, but will break when caching is implemented 14 18 - [ ] Split into a new repo on GitHub, publish to NPM maybe 15 19 - [ ] Implement caching based off of the client build and LunAST commit 16 20 - Means you only have to have a long client start once per client build
+2 -4
packages/lunast/src/index.ts
··· 1 1 import { RemapField, RemapModule, RemapType } from "./types"; 2 2 import { Remapped } from "./modules"; 3 - import { getProcessors } from "./utils"; 4 - import { parse } from "meriyah"; 3 + import { getProcessors, parseFixed } from "./utils"; 5 4 import { Processor, ProcessorState } from "./remap"; 6 5 import { generate } from "astring"; 7 6 ··· 51 50 ); 52 51 if (available.length === 0) return null; 53 52 54 - const module = parse(code); 53 + const module = parseFixed(code); 55 54 let dirty = false; 56 55 const state: ProcessorState = { 57 56 id, 58 - // @ts-expect-error The ESTree types are mismatched with estree-toolkit, but ESTree is a standard so this is fine 59 57 ast: module, 60 58 lunast: this, 61 59 markDirty: () => {
+12 -4
packages/lunast/src/modules/test.ts
··· 8 8 find: "marginCenterHorz:", 9 9 process({ ast }) { 10 10 const exports = getExports(ast); 11 - // eslint-disable-next-line no-console 12 - console.log(exports); 11 + // console.log(exports); 13 12 return Object.keys(exports).length > 0; 14 13 } 15 14 }); ··· 39 38 }, 40 39 "balls" 41 40 )`)!; 42 - for (const node of Object.values(getters)) { 41 + for (const data of Object.values(getters)) { 42 + if (!is.identifier(data.argument)) continue; 43 + 44 + const node = data.scope.getOwnBinding(data.argument.name); 45 + if (!node) continue; 46 + 43 47 const body = node.path.get<BlockStatement>("body"); 44 48 body.replaceWith(replacement); 45 49 } ··· 56 60 const getters = getPropertyGetters(ast); 57 61 const fields = []; 58 62 59 - for (const [name, node] of Object.entries(getters)) { 63 + for (const [name, data] of Object.entries(getters)) { 64 + if (!is.identifier(data.argument)) continue; 65 + const node = data.scope.getOwnBinding(data.argument.name); 66 + if (!node) continue; 67 + 60 68 let isSupportsCopy = false; 61 69 traverse(node.path.node!, { 62 70 MemberExpression(path) {
+20 -11
packages/lunast/src/utils.ts
··· 1 1 import type { Processor } from "./remap"; 2 - import { traverse, is, Binding } from "estree-toolkit"; 2 + import { traverse, is, Scope } from "estree-toolkit"; 3 3 // FIXME something's fishy with these types 4 4 import type { 5 + Expression, 5 6 ExpressionStatement, 6 7 ObjectExpression, 7 8 Program, ··· 86 87 return ret; 87 88 } 88 89 90 + export type PropertyGetter = { 91 + argument: Expression; 92 + scope: Scope; 93 + }; 94 + 95 + // TODO: util function to resolve the value of an expression 89 96 export function getPropertyGetters(ast: Program) { 90 - const ret: Record<string, Binding> = {}; 97 + const ret: Record<string, PropertyGetter> = {}; 91 98 92 99 traverse(ast, { 93 100 $: { scope: true }, 94 101 CallExpression(path) { 102 + if (path.scope == null) return; 95 103 if (!is.callExpression(path.node)) return; 96 104 if (!is.memberExpression(path.node.callee)) return; 97 105 if (!is.identifier(path.node?.callee?.property)) return; ··· 111 119 const returnStatement = property.value.body.body.find( 112 120 (node): node is ReturnStatement => is.returnStatement(node) 113 121 ); 114 - if (!returnStatement) continue; 115 - if (!is.identifier(returnStatement.argument)) continue; 116 - 117 - const binding = path.scope?.getOwnBinding( 118 - returnStatement.argument.name 119 - ); 120 - if (!binding) continue; 121 - if (!binding.path.node) continue; 122 - ret[property.key.name] = binding; 122 + if (!returnStatement || !returnStatement.argument) continue; 123 + ret[property.key.name] = { 124 + argument: returnStatement.argument, 125 + scope: path.scope 126 + }; 123 127 } 124 128 125 129 this.stop(); ··· 127 131 }); 128 132 129 133 return ret; 134 + } 135 + 136 + // The ESTree types are mismatched with estree-toolkit, but ESTree is a standard so this is fine 137 + export function parseFixed(code: string): Program { 138 + return parse(code) as any as Program; 130 139 } 131 140 132 141 export function magicAST(code: string) {