Files
overleaf-cep/services/web/transform/vitest/codemods/replaceSandboxedModuleWithDoMock.js
Andrew Rumble 6f732c8513 Merge pull request #27958 from overleaf/ar-change-esm-codemod-to-use-vitest-and-general-refactor
[web] change esm codemod to use vitest and general refactor

GitOrigin-RevId: 7f8c699b160ee0b7ff991d6284cb126165694c4f
2025-09-17 08:04:57 +00:00

106 lines
2.9 KiB
JavaScript

module.exports = function (fileInfo, api) {
const j = api.jscodeshift
const root = j(fileInfo.source)
let shouldAddViImport = false
let shouldRemoveSandboxedModule = false
root
.find(j.CallExpression, {
callee: {
object: { name: 'SandboxedModule' },
property: { name: 'require' },
},
})
.forEach(path => {
shouldRemoveSandboxedModule = true
const args = path.node.arguments
if (args.length > 0) {
const assignmentStatement = path.parentPath.parentPath
const firstArg = args[0]
// Check if there's a second argument with a 'requires' property
if (args.length > 1 && args[1].type === 'ObjectExpression') {
const requiresProp = args[1].properties.find(
prop =>
prop.key.name === 'requires' || prop.key.value === 'requires'
)
if (requiresProp) {
shouldAddViImport = true
const mocks = requiresProp.value.properties.map(mock => {
const depPath =
mock.key.type === 'Literal' ? mock.key.value : mock.key.name
return j.expressionStatement(
j.callExpression(j.identifier('vi.doMock'), [
j.literal(depPath),
j.arrowFunctionExpression(
[],
j.objectExpression([
j.objectProperty(j.identifier('default'), mock.value),
])
),
])
)
})
j(assignmentStatement).insertBefore(mocks)
}
}
// Create an expression to await the import of the module under test
const awaitExpression = j.memberExpression(
j.awaitExpression(
j.callExpression(j.identifier('import'), [firstArg])
),
j.identifier('default')
)
j(path).replaceWith(awaitExpression)
// Find the closest function and make it async
let functionPath = path
while ((functionPath = functionPath.parent)) {
if (
functionPath.node.type === 'FunctionDeclaration' ||
functionPath.node.type === 'FunctionExpression' ||
functionPath.node.type === 'ArrowFunctionExpression'
) {
functionPath.node.async = true
break
}
}
}
})
const alreadyHasViImport =
root
.find(j.ImportDeclaration, {
source: { value: 'vitest' },
})
.size() > 0
if (shouldAddViImport && !alreadyHasViImport) {
root
.get()
.node.program.body.unshift(
j.importDeclaration(
[j.importSpecifier(j.identifier('vi'))],
j.literal('vitest')
)
)
}
if (shouldRemoveSandboxedModule) {
root
.find(j.ImportDeclaration, {
source: { value: 'sandboxed-module' },
})
.remove()
}
return root.toSource({
quote: 'single',
})
}