Skip to content

Commit e322401

Browse files
committed
fix(@schematics/angular): use null objects and callbacks in karma-to-vitest migration
The karma-to-vitest migration schematic previously used plain JavaScript objects as dictionaries when processing custom build options and analyzing Karma AST configurations. In environments where the input workspace files contain custom keys such as "__proto__", these assignments would leak properties onto the global Object prototype.
1 parent 11a4438 commit e322401

3 files changed

Lines changed: 13 additions & 5 deletions

File tree

packages/schematics/angular/migrations/migrate-karma-to-vitest/karma-config-analyzer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export function analyzeKarmaConfig(content: string): KarmaConfigAnalysis {
142142
case ts.SyntaxKind.ArrayLiteralExpression:
143143
return (node as ts.ArrayLiteralExpression).elements.map(extractValue);
144144
case ts.SyntaxKind.ObjectLiteralExpression: {
145-
const obj: { [key: string]: KarmaConfigValue } = {};
145+
const obj: { [key: string]: KarmaConfigValue } = Object.create(null);
146146
for (const prop of (node as ts.ObjectLiteralExpression).properties) {
147147
if (isSupportedPropertyAssignment(prop)) {
148148
// Recursively extract values for nested objects.

packages/schematics/angular/migrations/migrate-karma-to-vitest/karma-config-comparer.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,10 @@ export async function generateDefaultKarmaConfig(
4646

4747
// TODO: Replace this with the actual schematic templating logic.
4848
template = template
49-
.replace(
50-
/<%= relativePathToWorkspaceRoot %>/g,
49+
.replace(/<%= relativePathToWorkspaceRoot %>/g, () =>
5150
path.normalize(relativePathToWorkspaceRoot).replace(/\\/g, '/'),
5251
)
53-
.replace(/<%= folderName %>/g, projectName);
52+
.replace(/<%= folderName %>/g, () => projectName);
5453

5554
const devkitPluginRegex = /<% if \(needDevkitPlugin\) { %>(.*?)<% } %>/gs;
5655
const replacement = needDevkitPlugin ? '$1' : '';

packages/schematics/angular/migrations/migrate-karma-to-vitest/migration.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ async function processTestTargetOptions(
3232
let needsIstanbul = false;
3333
for (const [configName, options] of allTargetOptions(testTarget, false)) {
3434
const configKey = configName || '';
35+
if (configKey === '__proto__' || configKey === 'constructor') {
36+
continue;
37+
}
3538
if (!customBuildOptions[configKey]) {
3639
// Match Karma behavior where AOT was disabled by default
3740
customBuildOptions[configKey] = {
@@ -276,7 +279,10 @@ function updateProjects(tree: Tree, context: SchematicContext): Rule {
276279
tsConfigsToUpdate.add(join(project.root, 'tsconfig.spec.json'));
277280

278281
// Store custom build options to move to a new build configuration if needed
279-
const customBuildOptions: Record<string, Record<string, json.JsonValue | undefined>> = {};
282+
const customBuildOptions: Record<
283+
string,
284+
Record<string, json.JsonValue | undefined>
285+
> = Object.create(null);
280286

281287
const projectCoverageInfo = await processTestTargetOptions(
282288
testTarget,
@@ -300,6 +306,9 @@ function updateProjects(tree: Tree, context: SchematicContext): Rule {
300306
const baseOptions = buildTarget.options || {};
301307

302308
for (const [configKey, configOptions] of Object.entries(customBuildOptions)) {
309+
if (configKey === '__proto__' || configKey === 'constructor') {
310+
continue;
311+
}
303312
const finalConfig: Record<string, json.JsonValue | undefined> = {};
304313

305314
// Omit options that already have the same value in the base build options.

0 commit comments

Comments
 (0)