Skip to content

chore: code mod to refactor test dir#5068

Draft
WilcoFiers wants to merge 1 commit intodevelopfrom
test-refactor
Draft

chore: code mod to refactor test dir#5068
WilcoFiers wants to merge 1 commit intodevelopfrom
test-refactor

Conversation

@WilcoFiers
Copy link
Copy Markdown
Contributor

We need to clean up that old test dir. Figured I'd have Cursor generate a code mod for us to do it.

@WilcoFiers WilcoFiers requested a review from a team as a code owner April 10, 2026 12:58
Copilot AI review requested due to automatic review settings April 10, 2026 12:58
@WilcoFiers WilcoFiers marked this pull request as draft April 10, 2026 12:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Node-based codemod intended to modernize legacy Karma/Mocha test files under test/ by performing automated AST-driven refactors.

Changes:

  • Adds a new CLI codemod (build/codemods/modernize-test-files.mjs) to transform test sources (arrow conversions, var->let/const, string concat->template literals, remove 'use strict').
  • Wires the codemod into package.json scripts (codemod:modernize-tests).
  • Introduces recast as a dev dependency to preserve formatting while printing transformed files.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
package.json Adds a codemod npm script and adds recast to support AST printing.
build/codemods/modernize-test-files.mjs New codemod CLI implementing multiple source-to-source transformations for test files.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +360 to +375
/** Leading space inside opening backtick (Prettier-friendly padding). */
let buffer = ' ';

for (const part of parts) {
if (t.isStringLiteral(part)) {
buffer += escapeTemplateQuasiText(part.value);
continue;
}
const raw = buffer;
buffer = '';
quasis.push(t.templateElement({ raw, cooked: raw }, false));
expressions.push(part);
}
/** Trailing space inside closing backtick. */
buffer += ' ';
quasis.push(t.templateElement({ raw: buffer, cooked: buffer }, true));
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

partsToTemplateLiteral unconditionally injects a leading and trailing space inside the generated template literal (let buffer = ' ' and buffer += ' '), which changes runtime string values (e.g., "a" + b becomes a template that yields " a${b} "). A codemod that is meant to be behavior-preserving should not add extra characters; consider removing the padding or only applying it when the original concatenation already begins/ends with whitespace and/or when the chain is clearly multiline HTML.

Copilot uses AI. Check for mistakes.
Comment on lines +144 to +189
/**
* Whether converting this `var` to `let`/`const` preserves behavior. `var` in nested
* blocks hoists to the function; `let`/`const` does not — only convert when the
* declaration sits in the direct body of a function or method (not `if`/`for`/`try`,
* not `for (var ...)`, not top-level script `var`).
*
* @param {import('@babel/traverse').NodePath<import('@babel/types').VariableDeclaration>} varPath
*/
function canSafelyConvertVarDeclaration(varPath) {
const parent = varPath.parentPath;
if (!parent) {
return false;
}

if (
parent.isForStatement() ||
parent.isForOfStatement() ||
parent.isForInStatement()
) {
return false;
}

if (!parent.isBlockStatement()) {
return false;
}

const block = parent;
const container = block.parentPath;
if (!container) {
return false;
}

if (
container.isFunctionDeclaration() ||
container.isFunctionExpression() ||
container.isArrowFunctionExpression()
) {
return container.get('body') === block;
}

if (container.isClassMethod() || container.isObjectMethod()) {
return container.get('body') === block;
}

return false;
}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The var -> let/const transform only checks that the declaration is in a function/method body, but it doesn't account for var hoisting vs. let/const TDZ. If any binding is referenced before the declaration, converting will change behavior (from undefined to ReferenceError). This needs an additional safety check (e.g., ensure all reference locations occur after the declaration, or restrict conversion to declarations that are already at the top of the function body).

Copilot uses AI. Check for mistakes.
Comment on lines +380 to +390
/**
* @param {string} source
* @param {string} filename
*/
/**
* Parse with recast so `recast.print` can reuse original formatting (including blank
* lines). `tokens: true` helps recast reprint accurately.
*
* @param {string} source
* @param {string} filename
*/
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an extra/empty JSDoc block immediately before the real parseSource docstring (the @param {string} source / @param {string} filename block at lines 380-383). It looks like a leftover and can confuse generated docs and readers; remove the stray block so only the full parseSource comment remains.

Copilot uses AI. Check for mistakes.
Comment on lines 176 to 180
"outdent": "^0.8.0",
"patch-package": "^8.0.0",
"prettier": "^3.0.3",
"recast": "^0.23.11",
"revalidator": "^0.3.1",
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build/codemods/modernize-test-files.mjs imports @babel/parser, @babel/traverse, and @babel/types, but those packages are not listed in devDependencies (currently only @babel/core/plugins are). Relying on transitive dependencies is brittle; add these as explicit devDependencies so the codemod keeps working if Babel’s internal dependency graph changes.

Copilot uses AI. Check for mistakes.
} else if (a === '--prettier') {
args.prettier = true;
} else if (!a.startsWith('-')) {
args.globs.push(a);
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseArgs silently ignores unknown flags (any arg starting with - that isn't recognized). For a CLI codemod, this makes typos hard to notice; consider treating unknown options as an error (print help + set non-zero exit code) to avoid accidentally running with unintended defaults.

Suggested change
args.globs.push(a);
args.globs.push(a);
} else {
console.error(`Unknown option: ${a}`);
printHelp();
process.exit(1);

Copilot uses AI. Check for mistakes.
Comment on lines 176 to 180
"outdent": "^0.8.0",
"patch-package": "^8.0.0",
"prettier": "^3.0.3",
"recast": "^0.23.11",
"revalidator": "^0.3.1",
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recast was added to devDependencies, but package-lock.json is not updated in this PR. If CI or contributors use npm ci (which this repo does in release tooling), the lockfile needs to be regenerated/committed to keep installs reproducible.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants