UNPKG

hackmud-script-manager

Version:

Script manager for game hackmud, with minification, TypeScript support, and player script type definition generation.

721 lines (720 loc) 26.4 kB
import babelTraverse from "@babel/traverse" import t from "@babel/types" import { assert } from "@samual/lib/assert" import { clearObject } from "@samual/lib/clearObject" import { validDBMethods } from "../constants.js" import { getReferencePathsToGlobal } from "./shared.js" const { default: traverse } = babelTraverse, globalFunctionsUnder7Characters = [ "Map", "Set", "Date", "JSON", "Math", "Array", "Error", "isNaN", "Number", "Object", "RegExp", "String", "Symbol", "BigInt" ] function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scriptName, seclevel = 4 }) { const warnings = [], topFunctionName = `_${uniqueId}_SCRIPT_` let program traverse(file, { Program(path) { program = path path.skip() } }) if (program.scope.hasGlobal("_SOURCE")) for (const referencePath of getReferencePathsToGlobal("_SOURCE", program)) referencePath.replaceWith(t.stringLiteral(sourceCode)) if (program.scope.hasGlobal("_BUILD_DATE")) for (const referencePath of getReferencePathsToGlobal("_BUILD_DATE", program)) referencePath.replaceWith(t.numericLiteral(Date.now())) let uniqueIdScriptUserNeeded = !1 if (program.scope.hasGlobal("_SCRIPT_USER")) for (const referencePath of getReferencePathsToGlobal("_SCRIPT_USER", program)) if (null == scriptUser) { uniqueIdScriptUserNeeded = !0 referencePath.replaceWith(t.identifier(`_${uniqueId}_SCRIPT_USER_`)) } else referencePath.replaceWith(t.stringLiteral(1 == scriptUser ? `$${uniqueId}$SCRIPT_USER$` : scriptUser)) if (program.scope.hasGlobal("_SCRIPT_NAME")) { warnings.push({ message: "Global _SCRIPT_NAME is deprecated and will be removed in the next minor release of HSM, use _SCRIPT_SUBNAME instead" }) for (const referencePath of getReferencePathsToGlobal("_SCRIPT_NAME", program)) referencePath.replaceWith(t.stringLiteral(1 == scriptName ? `$${uniqueId}$SCRIPT_NAME$` : scriptName)) } if (program.scope.hasGlobal("_SCRIPT_SUBNAME")) for (const referencePath of getReferencePathsToGlobal("_SCRIPT_SUBNAME", program)) referencePath.replaceWith(t.stringLiteral(1 == scriptName ? `$${uniqueId}$SCRIPT_NAME$` : scriptName)) if (program.scope.hasGlobal("_FULL_SCRIPT_NAME")) for (const referencePath of getReferencePathsToGlobal("_FULL_SCRIPT_NAME", program)) if (1 == scriptUser || 1 == scriptName) referencePath.replaceWith(t.stringLiteral(`$${uniqueId}$FULL_SCRIPT_NAME$`)) else if (null == scriptUser) { uniqueIdScriptUserNeeded = !0 referencePath.replaceWith( t.binaryExpression( "+", t.identifier(`_${uniqueId}_SCRIPT_USER_`), t.stringLiteral("." + scriptName) ) ) } else referencePath.replaceWith(t.stringLiteral(`${scriptUser}.${scriptName}`)) let functionDotPrototypeIsReferencedMultipleTimes = !1 if (program.scope.hasGlobal("Function")) { const FunctionReferencePaths = getReferencePathsToGlobal("Function", program) if (1 == FunctionReferencePaths.length) { const referencePath = FunctionReferencePaths[0] assert( "MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:111:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible" ) assert( "Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:116:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible" ) assert( "prototype" == referencePath.parent.property.name, "src/processScript/transform.ts:121:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible" ) referencePath.parentPath.replaceWith(createGetFunctionPrototypeNode()) } else { for (const referencePath of FunctionReferencePaths) { assert( "MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:129:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible" ) assert( "Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:134:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible" ) assert( "prototype" == referencePath.parent.property.name, "src/processScript/transform.ts:139:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible" ) functionDotPrototypeIsReferencedMultipleTimes = !0 referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_FUNCTION_DOT_PROTOTYPE_`)) } functionDotPrototypeIsReferencedMultipleTimes = !0 } } const neededSubscriptLets = new Map() let detectedSeclevel = 4 program.scope.hasGlobal("$s") && warnings.push({ message: "Subscripts in the form of $s.foo.bar() and #s.foo.bar() are deprecated. Use explicit seclevels instead." }) for (const fakeSubscriptObjectName of ["$fs", "$4s", "$s"]) program.scope.hasGlobal(fakeSubscriptObjectName) && processFakeSubscriptObject(fakeSubscriptObjectName, 4) for (const fakeSubscriptObjectName of ["$hs", "$3s"]) if (program.scope.hasGlobal(fakeSubscriptObjectName)) { detectedSeclevel = 3 processFakeSubscriptObject(fakeSubscriptObjectName, 3) } for (const fakeSubscriptObjectName of ["$ms", "$2s"]) if (program.scope.hasGlobal(fakeSubscriptObjectName)) { detectedSeclevel = 2 processFakeSubscriptObject(fakeSubscriptObjectName, 2) } for (const fakeSubscriptObjectName of ["$ls", "$1s"]) if (program.scope.hasGlobal(fakeSubscriptObjectName)) { detectedSeclevel = 1 processFakeSubscriptObject(fakeSubscriptObjectName, 1) } for (const fakeSubscriptObjectName of ["$ns", "$0s"]) if (program.scope.hasGlobal(fakeSubscriptObjectName)) { detectedSeclevel = 0 processFakeSubscriptObject(fakeSubscriptObjectName, 0) } seclevel = Math.min(seclevel, detectedSeclevel) const neededDbMethodLets = new Set() if (program.scope.hasGlobal("$db")) for (const referencePath of getReferencePathsToGlobal("$db", program)) { assert("MemberExpression" == referencePath.parentPath.node.type, "src/processScript/transform.ts:199:69") assert("Identifier" == referencePath.parentPath.node.property.type, "src/processScript/transform.ts:200:72") const databaseOpMethodName = referencePath.parentPath.node.property.name assert( validDBMethods.includes(databaseOpMethodName), `src/processScript/transform.ts:206:8 invalid db method "${databaseOpMethodName}", valid db methods are "${validDBMethods.join('", "')}"` ) if ("CallExpression" == referencePath.parentPath.parentPath?.type) referencePath.parentPath.replaceWith(t.identifier(`$${uniqueId}$DB$${databaseOpMethodName}$`)) else { referencePath.parentPath.replaceWith( t.identifier(`_${uniqueId}_CONSOLE_METHOD_${databaseOpMethodName}_`) ) neededDbMethodLets.add(databaseOpMethodName) } } let needDebugLet = !1 if (program.scope.hasGlobal("$D")) for (const referencePath of getReferencePathsToGlobal("$D", program)) if ("CallExpression" == referencePath.parentPath.type) referencePath.replaceWith(t.identifier(`$${uniqueId}$DEBUG$`)) else { referencePath.replaceWith(t.identifier(`_${uniqueId}_DEBUG_`)) needDebugLet = !0 } if (program.scope.hasGlobal("$FMCL")) for (const referencePath of getReferencePathsToGlobal("$FMCL", program)) referencePath.replaceWith(t.identifier(`$${uniqueId}$FMCL$`)) let needG = program.scope.hasGlobal("$G") if (needG) for (const referencePath of getReferencePathsToGlobal("$G", program)) referencePath.replaceWith(t.identifier(`_${uniqueId}_G_`)) if (program.scope.hasGlobal("_SECLEVEL")) for (const referencePath of getReferencePathsToGlobal("_SECLEVEL", program)) referencePath.replaceWith(t.numericLiteral(seclevel)) let needGetPrototypeOf = !1, needHasOwn = !1 if (program.scope.hasGlobal("Object")) for (const referencePath of getReferencePathsToGlobal("Object", program)) if ("MemberExpression" == referencePath.parent.type && !referencePath.parent.computed) { assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:256:64") if ("getPrototypeOf" == referencePath.parent.property.name) { referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_GET_PROTOTYPE_OF_`)) needGetPrototypeOf = !0 } else if ("hasOwn" == referencePath.parent.property.name) { referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_HAS_OWN_`)) needHasOwn = !0 } } const consoleMethodsReferenced = new Set() if (program.scope.hasGlobal("console")) for (const referencePath of getReferencePathsToGlobal("console", program)) if ("MemberExpression" == referencePath.parent.type && !referencePath.parent.computed) { assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:274:64") referencePath.parentPath.replaceWith( t.identifier(`_${uniqueId}_CONSOLE_METHOD_${referencePath.parent.property.name}_`) ) consoleMethodsReferenced.add(referencePath.parent.property.name) } const lastStatement = program.node.body.at(-1) let exportDefaultName assert(lastStatement, "src/processScript/transform.ts:288:27 program is empty") if ("ExportNamedDeclaration" == lastStatement.type) { program.node.body.pop() for (const specifier of lastStatement.specifiers) { assert( "ExportSpecifier" == specifier.type, `src/processScript/transform.ts:294:51 ${specifier.type} is currently unsupported` ) if ( "default" != ("Identifier" == specifier.exported.type ? specifier.exported.name : specifier.exported.value) ) throw Error("Only default exports are supported") exportDefaultName = specifier.local.name } } const globalBlock = t.blockStatement([]) let mainFunction for (const statement of program.node.body) if ("VariableDeclaration" == statement.type) for (const declarator of statement.declarations) if ( "Identifier" != declarator.id.type || declarator.id.name != exportDefaultName || !declarator.init || ("FunctionExpression" != declarator.init.type && "ArrowFunctionExpression" != declarator.init.type) || declarator.init.async || declarator.init.generator ) { for (const identifierName in t.getBindingIdentifiers(declarator.id)) { identifierName == exportDefaultName && (mainFunction = t.functionDeclaration( t.identifier(topFunctionName), [t.identifier("context"), t.identifier("args")], t.blockStatement([ t.returnStatement(t.callExpression(t.identifier(exportDefaultName), [])) ]) )) globalBlock.body.push( t.variableDeclaration("let", [t.variableDeclarator(t.identifier(identifierName))]) ) } declarator.init && globalBlock.body.push( t.expressionStatement(t.assignmentExpression("=", declarator.id, declarator.init)) ) } else mainFunction = t.functionDeclaration( t.identifier(topFunctionName), declarator.init.params, "BlockStatement" == declarator.init.body.type ? declarator.init.body : t.blockStatement([t.returnStatement(declarator.init.body)]) ) else "FunctionDeclaration" == statement.type ? statement.id.name == exportDefaultName ? (mainFunction = statement) : globalBlock.body.push( t.variableDeclaration("let", [ t.variableDeclarator( statement.id, t.functionExpression( void 0, statement.params, statement.body, statement.generator, statement.async ) ) ]) ) : globalBlock.body.push(statement) mainFunction ||= t.functionDeclaration( t.identifier(topFunctionName), [t.identifier("context"), t.identifier("args")], t.blockStatement([]) ) if (uniqueIdScriptUserNeeded) { const mainFunctionParams = mainFunction.params mainFunction.params = [t.restElement(t.identifier(`_${uniqueId}_PARAMS_`))] mainFunction.body.body.unshift( t.variableDeclaration("let", [ t.variableDeclarator(t.arrayPattern(mainFunctionParams), t.identifier(`_${uniqueId}_PARAMS_`)), t.variableDeclarator( t.arrayPattern([t.identifier(`_${uniqueId}_SCRIPT_USER_`)]), t.callExpression( t.memberExpression( t.memberExpression( t.memberExpression(t.identifier(`_${uniqueId}_PARAMS_`), t.numericLiteral(0), !0), t.identifier("this_script") ), t.identifier("split") ), [t.stringLiteral(".")] ) ) ]) ) } program.node.body = [mainFunction] if (globalBlock.body.length) { program.scope.crawl() const globalBlockVariables = new Set() let hoistedGlobalBlockFunctions = 0 for (const [globalBlockIndex, globalBlockStatement] of [...globalBlock.body.entries()].reverse()) if ("VariableDeclaration" == globalBlockStatement.type) { assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:408:59") const declarator = globalBlockStatement.declarations[0] assert( "Identifier" == declarator.id.type, `src/processScript/transform.ts:412:51 declarator.id.type was "${declarator.id.type}"` ) program.scope.crawl() if (program.scope.hasGlobal(declarator.id.name)) { globalBlock.body.splice(globalBlockIndex, 1) const [globalBlockPath] = program.unshiftContainer("body", globalBlock), [globalBlockStatementPath] = program.unshiftContainer("body", globalBlockStatement) program.scope.crawl() if ( !declarator.init || ("FunctionExpression" != declarator.init.type && "ArrowFunctionExpression" != declarator.init.type) || Object.keys(program.scope.globals).some(global => globalBlockVariables.has(global)) ) { const binding = program.scope.getBinding(declarator.id.name) assert(binding, "src/processScript/transform.ts:431:23") for (const referencePath of binding.referencePaths) { assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:434:56") referencePath.replaceWith( t.memberExpression( t.identifier(`_${uniqueId}_G_`), t.identifier(referencePath.node.name) ) ) needG = !0 } for (const referencePath of binding.constantViolations) if ("AssignmentExpression" == referencePath.node.type) for (const [name, node] of Object.entries(t.getBindingIdentifiers(referencePath.node))) if (name == declarator.id.name) { clearObject(node) Object.assign( node, t.memberExpression(t.identifier(`_${uniqueId}_G_`), t.identifier(name)) ) needG = !0 } globalBlockPath.remove() globalBlockStatementPath.remove() if (declarator.init) { globalBlock.body.splice( globalBlockIndex, 0, t.expressionStatement( t.assignmentExpression( "=", t.memberExpression( t.identifier(`_${uniqueId}_G_`), t.identifier(declarator.id.name) ), declarator.init ) ) ) needG = !0 } } else { globalBlockPath.remove() globalBlockStatementPath.remove() mainFunction.body.body.unshift(globalBlockStatement) hoistedGlobalBlockFunctions++ } } else globalBlockVariables.add(declarator.id.name) } else if ("ClassDeclaration" == globalBlockStatement.type) { program.scope.crawl() assert(globalBlockStatement.id, "src/processScript/transform.ts:491:37") if (program.scope.hasGlobal(globalBlockStatement.id.name)) { globalBlock.body.splice(globalBlockIndex, 1) const [globalBlockPath] = program.unshiftContainer("body", globalBlock), [globalBlockStatementPath] = program.unshiftContainer("body", globalBlockStatement) program.scope.crawl() const binding = program.scope.getBinding(globalBlockStatement.id.name) assert(binding, "src/processScript/transform.ts:503:22") for (const referencePath of binding.referencePaths) { assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:506:55") referencePath.replaceWith( t.memberExpression(t.identifier(`_${uniqueId}_G_`), t.identifier(referencePath.node.name)) ) needG = !0 } globalBlockPath.remove() globalBlockStatementPath.remove() globalBlock.body.splice( globalBlockIndex, 0, t.expressionStatement( t.assignmentExpression( "=", t.memberExpression( t.identifier(`_${uniqueId}_G_`), t.identifier(globalBlockStatement.id.name) ), t.classExpression( void 0, globalBlockStatement.superClass, globalBlockStatement.body, globalBlockStatement.decorators ) ) ) ) needG = !0 } } globalBlock.body.length && mainFunction.body.body.splice( hoistedGlobalBlockFunctions, 0, t.ifStatement(t.unaryExpression("!", t.identifier(`$${uniqueId}$FMCL$`)), globalBlock) ) } functionDotPrototypeIsReferencedMultipleTimes && mainFunction.body.body.unshift( t.variableDeclaration("let", [ t.variableDeclarator( t.identifier(`_${uniqueId}_FUNCTION_DOT_PROTOTYPE_`), createGetFunctionPrototypeNode() ) ]) ) needGetPrototypeOf && mainFunction.body.body.unshift( t.variableDeclaration("let", [ t.variableDeclarator( t.objectPattern([ t.objectProperty(t.identifier("get"), t.identifier(`_${uniqueId}_DUNDER_PROTO_GETTER_`)) ]), t.callExpression( t.memberExpression(t.identifier("Object"), t.identifier("getOwnPropertyDescriptor")), [ t.memberExpression(t.identifier("Object"), t.identifier("prototype")), t.stringLiteral("__proto__") ] ) ), t.variableDeclarator( t.identifier(`_${uniqueId}_GET_PROTOTYPE_OF_`), t.callExpression( t.memberExpression( t.memberExpression( t.identifier( globalFunctionsUnder7Characters.find(name => !program.scope.hasOwnBinding(name)) ), t.identifier("call") ), t.identifier("bind") ), [t.identifier(`_${uniqueId}_DUNDER_PROTO_GETTER_`)] ) ) ]) ) needHasOwn && mainFunction.body.body.unshift( t.variableDeclaration("let", [ t.variableDeclarator( t.identifier(`_${uniqueId}_HAS_OWN_`), t.callExpression( t.memberExpression( t.memberExpression( t.identifier( globalFunctionsUnder7Characters.find(name => !program.scope.hasOwnBinding(name)) ), t.identifier("call") ), t.identifier("bind") ), [ t.memberExpression( t.memberExpression(t.identifier("Object"), t.identifier("prototype")), t.identifier("hasOwnProperty") ) ] ) ) ]) ) consoleMethodsReferenced.size && mainFunction.body.body.unshift( t.variableDeclaration( "let", [...consoleMethodsReferenced].map(name => t.variableDeclarator( t.identifier(`_${uniqueId}_CONSOLE_METHOD_${name}_`), t.arrowFunctionExpression( [t.restElement(t.identifier("args"))], t.unaryExpression( "void", t.callExpression(t.identifier(`$${uniqueId}$DEBUG$`), [t.identifier("args")]) ) ) ) ) ) ) neededDbMethodLets.size && mainFunction.body.body.unshift( t.variableDeclaration( "let", [...neededDbMethodLets].map(name => { const getArgs = () => "ObjectId" == name ? [] : "i" == name || "r" == name ? [t.identifier("a")] : [t.identifier("a"), t.identifier("b")] return t.variableDeclarator( t.identifier(`_${uniqueId}_CONSOLE_METHOD_${name}_`), t.arrowFunctionExpression( getArgs(), t.callExpression(t.identifier(`$${uniqueId}$DB$${name}$`), getArgs()) ) ) }) ) ) needDebugLet && mainFunction.body.body.unshift( t.variableDeclaration("let", [ t.variableDeclarator( t.identifier(`_${uniqueId}_DEBUG_`), t.callExpression(t.identifier(`$${uniqueId}$DEBUG$`), [t.identifier("a")]) ) ]) ) neededSubscriptLets.size && mainFunction.body.body.unshift( t.variableDeclaration( "let", [...neededSubscriptLets].map(([name, seclevel]) => t.variableDeclarator( t.identifier(`_${uniqueId}_SUBSCRIPT_${name}_`), t.arrowFunctionExpression( [t.restElement(t.identifier("args"))], t.callExpression(t.identifier(`$${uniqueId}$${seclevel}$SUBSCRIPT$${name}$`), [ t.spreadElement(t.identifier("args")) ]) ) ) ) ) ) needG && mainFunction.body.body.unshift( t.variableDeclaration("let", [ t.variableDeclarator(t.identifier(`_${uniqueId}_G_`), t.identifier(`$${uniqueId}$GLOBAL$`)) ]) ) traverse(file, { BlockStatement({ node: blockStatement }) { for (const [index, functionDeclaration] of blockStatement.body.entries()) if ("FunctionDeclaration" == functionDeclaration.type && !functionDeclaration.generator) { blockStatement.body.splice(index, 1) blockStatement.body.unshift( t.variableDeclaration("let", [ t.variableDeclarator( functionDeclaration.id, t.arrowFunctionExpression( functionDeclaration.params, functionDeclaration.body, functionDeclaration.async ) ) ]) ) } }, ClassBody({ node: classBody, scope, parent }) { assert(t.isClass(parent), "src/processScript/transform.ts:701:30") let thisIsReferenced = !1 for (const classMethod of classBody.body) { if ("ClassMethod" != classMethod.type) continue let methodReferencesThis = !1 traverse( classMethod.body, { ThisExpression(path) { methodReferencesThis = !0 thisIsReferenced = !0 path.replaceWith(t.identifier(`_${uniqueId}_THIS_`)) }, Function(path) { "ArrowFunctionExpression" != path.node.type && path.skip() } }, scope ) if (methodReferencesThis) if ("constructor" != classMethod.kind) classMethod.body.body.unshift( t.variableDeclaration("let", [ t.variableDeclarator( t.identifier(`_${uniqueId}_THIS_`), t.callExpression(t.memberExpression(t.super(), t.identifier("valueOf")), []) ) ]) ) else { const superCalls = [] traverse( classMethod.body, { CallExpression(path) { "Super" == path.node.callee.type && superCalls.push(path) } }, scope ) if (superCalls.length) if ( 1 == superCalls.length && "ExpressionStatement" == superCalls[0].parent.type && superCalls[0].parentPath.parentPath.parent == classMethod ) superCalls[0].parentPath.replaceWith( t.variableDeclaration("let", [ t.variableDeclarator(t.identifier(`_${uniqueId}_THIS_`), superCalls[0].node) ]) ) else { for (const path of superCalls) path.replaceWith( t.assignmentExpression("=", t.identifier(`_${uniqueId}_THIS_`), path.node) ) classMethod.body.body.unshift( t.variableDeclaration("let", [ t.variableDeclarator(t.identifier(`_${uniqueId}_THIS_`)) ]) ) } else classMethod.body.body.unshift( t.variableDeclaration("let", [ t.variableDeclarator( t.identifier(`_${uniqueId}_THIS_`), t.callExpression(t.super(), []) ) ]) ) } } !parent.superClass && thisIsReferenced && (parent.superClass = t.identifier("Object")) }, VariableDeclaration({ node: variableDeclaration }) { "const" == variableDeclaration.kind && (variableDeclaration.kind = "let") }, ThisExpression: path => { path.replaceWith(t.identifier("undefined")) }, BigIntLiteral(path) { const bigIntAsNumber = Number(path.node.value) path.replaceWith( t.callExpression(t.identifier("BigInt"), [ BigInt(bigIntAsNumber) == BigInt(path.node.value) ? t.numericLiteral(bigIntAsNumber) : t.stringLiteral(path.node.value) ]) ) } }) return { file, seclevel, warnings } function createGetFunctionPrototypeNode() { const name = globalFunctionsUnder7Characters.find(name => !program.scope.hasOwnBinding(name)) return t.memberExpression( name ? t.identifier(name) : t.arrowFunctionExpression([t.identifier("_")], t.identifier("_")), t.identifier("__proto__") ) } function processFakeSubscriptObject(fakeSubscriptObjectName, seclevel) { for (const referencePath of getReferencePathsToGlobal(fakeSubscriptObjectName, program)) { assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:811:60") assert("Identifier" == referencePath.parent.property.type) assert( "MemberExpression" == referencePath.parentPath.parentPath?.node.type, "src/processScript/transform.ts:813:81" ) assert( "Identifier" == referencePath.parentPath.parentPath.node.property.type, "src/processScript/transform.ts:814:83" ) assert( /^[_a-z][\d_a-z]{0,24}$/.test(referencePath.parent.property.name), `src/processScript/transform.ts:818:8 invalid user "${referencePath.parent.property.name}" in subscript` ) assert( /^[_a-z][\d_a-z]{0,24}$/.test(referencePath.parentPath.parentPath.node.property.name), `src/processScript/transform.ts:823:8 invalid script name "${referencePath.parentPath.parentPath.node.property.name}" in subscript` ) if ("CallExpression" == referencePath.parentPath.parentPath.parentPath?.type) referencePath.parentPath.parentPath.replaceWith( t.identifier( `$${uniqueId}$${seclevel}$SUBSCRIPT$${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}$` ) ) else { const name = `${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}` referencePath.parentPath.parentPath.replaceWith(t.identifier(`_${uniqueId}_SUBSCRIPT_${name}_`)) const maxSecLevel = Math.max(neededSubscriptLets.get(name) || 0, seclevel) neededSubscriptLets.set(name, maxSecLevel) } } } } export { transform }