Skip to content

Commit

Permalink
Rename top level require functions in CommonJS WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Dec 23, 2023
1 parent c354cef commit 44feaf8
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 3 deletions.
12 changes: 11 additions & 1 deletion lib/init/getScopeId.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

'use strict';

const {defineProperties, getOwnPropertyDescriptors} = Object;
const {defineProperty, defineProperties, getOwnPropertyDescriptors} = Object;

// Exports

Expand All @@ -23,6 +23,7 @@ let nextScopeId = 1;

// Add additional static methods
getScopeId.toRest = toRest;
getScopeId.renameRequireAlias = renameRequireAlias;

/**
* Convert object to array.
Expand All @@ -33,3 +34,12 @@ getScopeId.toRest = toRest;
function toRest(obj) {
return defineProperties([], getOwnPropertyDescriptors(obj));
}

/**
* Set name property of a function to 'require'.
* @param {Function} req - Function
* @returns {Function} - Input function
*/
function renameRequireAlias(req) {
return defineProperty(req, 'name', {value: 'require'});
}
3 changes: 2 additions & 1 deletion lib/instrument/internalVars.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ module.exports = {
createTempVarNode,
createFnInfoVarNode,
checkInternalVarNameClash,
renameInternalVars
renameInternalVars,
addToInternalVars
};

/*
Expand Down
28 changes: 28 additions & 0 deletions lib/instrument/modify.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ function modifyAst(ast, filename, isCommonJs, isStrict, sources, evalState) {
trackerVarNode: undefined,
getScopeIdVarNode: undefined,
getSourcesNode: undefined,
requireAliasTempVarNode: undefined,
functions: [],
fileContainsFunctionsOrEval: false,
secondPass: (fn, ...params) => secondPassQueue.push({fn, params})
Expand Down Expand Up @@ -198,6 +199,7 @@ function modifySecondPass(ast, secondPassQueue, isEvalCode, sources, state) {
processQueue(secondPassQueue, state);
insertBlockVarsIntoBlockStatement(state.programBlock, programNode, state);
insertFunctionInfoFunctions(programNode, isEvalCode, sources, state);
insertRequireAlias(programNode, state);
}

if (!isEvalCode) insertImportStatement(programNode, state);
Expand Down Expand Up @@ -295,6 +297,32 @@ function insertFunctionInfoFunctions(programNode, isEvalCode, sources, state) {
}
}

/**
* Insert alias reassignment for `require`.
* If CommonJS code containing top-level function declaration(s) called 'require',
* they've been renamed to a temporary name earlier in instrumentation.
* Insert `var` statement at top of file to restore the binding.
* @param {Object} programNode - Program AST node
* @param {Object} state - State object
* @returns {undefined}
*/
function insertRequireAlias(programNode, state) {
if (!state.requireAliasTempVarNode) return;

// `var require = livepack_getScopeId.renameRequireAlias(livepack_temp_3);`
programNode.body.unshift(
t.variableDeclaration('var', [
t.variableDeclarator(
t.identifier('require'),
t.callExpression(
t.memberExpression(state.getScopeIdVarNode, t.identifier('renameRequireAlias')),
[state.requireAliasTempVarNode]
)
)
])
);
}

/**
* Get current AST node, to get location where instrumentation failed and threw error.
* Uses current function node and trail to get node. If no node at that trail, get parent node.
Expand Down
28 changes: 27 additions & 1 deletion lib/instrument/visitors/function.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const Statement = require('./statement.js'),
createNewTargetBinding, getOrCreateExternalVar
} = require('../blocks.js'),
{insertTrackerCodeIntoFunction} = require('../tracking.js'),
{createFnInfoVarNode} = require('../internalVars.js'),
{createFnInfoVarNode, createTempVarNode, addToInternalVars} = require('../internalVars.js'),
{insertComment, hasUseStrictDirective, stringLiteralWithSingleQuotes} = require('../utils.js'),
{combineArraysWithDedup} = require('../../shared/functions.js'),
{
Expand Down Expand Up @@ -109,6 +109,12 @@ function FunctionDeclaration(node, state, parent, key) {

// Insert tracker comment
insertFunctionDeclarationOrExpressionTrackerComment(fn, node, state);

// If top-level function declaration called 'require' in CommonJS, rename it in 2nd pass
if (
fnName === 'require' && block === state.programBlock
&& state.programBlock.parent.bindings.has('require')
) state.secondPass(renameRequireFunctionDeclaration, node, state);
}

/**
Expand Down Expand Up @@ -691,6 +697,26 @@ function insertArrowFunctionTrackerComment(fn, node, state) {
);
}

/**
* Rename top-level function declaration in CommonJS file called `require` to a temp name.
* Otherwise, this prevents loading Livepack's `init` code.
* At end of instrumentation, a `var require =` statement will be added at top of file
* to restore the binding.
* @param {Object} fnNode - Function declaration AST node
* @param {Object} state - State object
* @returns {undefined}
*/
function renameRequireFunctionDeclaration(fnNode, state) {
// Use same temp var name for all `require` functions in this file
const tempVarNode = state.requireAliasTempVarNode
|| (state.requireAliasTempVarNode = createTempVarNode(state));

// Set `name` of existing identifier, rather than replacing with `tempVarNode`
// to preserve any attached comments (including tracker comment)
fnNode.id.name = tempVarNode.name;
addToInternalVars(fnNode.id, state);
}

/**
* Insert tracker comment.
* @param {number} fnId - Function ID
Expand Down

0 comments on commit 44feaf8

Please sign in to comment.