Skip to content

remove eval calls introduced by depd wrapped functions #410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/long-items-poke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@opennextjs/cloudflare": patch
---

remove `eval` calls introduced by `depd` wrapped functions

Some dependencies of Next.js (`raw-body` and `send`) use `depd` to deprecate some of their functions,
`depd` uses `eval` to generate a deprecated version of such functions, this causes `eval` warnings in
the terminal even if these functions are never called, the changes here by patching the depd `wrapfunction`
function so that it still retains the same type of behavior but without using `eval`
2 changes: 2 additions & 0 deletions packages/cloudflare/src/cli/build/bundle-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { inlineFindDir } from "./patches/plugins/find-dir.js";
import { patchLoadInstrumentation } from "./patches/plugins/load-instrumentation.js";
import { inlineLoadManifest } from "./patches/plugins/load-manifest.js";
import { handleOptionalDependencies } from "./patches/plugins/optional-deps.js";
import { patchDepdDeprecations } from "./patches/plugins/patch-depd-deprecations.js";
import { fixRequire } from "./patches/plugins/require.js";
import { shimRequireHook } from "./patches/plugins/require-hook.js";
import { inlineRequirePage } from "./patches/plugins/require-page.js";
Expand Down Expand Up @@ -97,6 +98,7 @@ export async function bundleServer(buildOpts: BuildOptions): Promise<void> {
inlineFindDir(updater, buildOpts),
inlineLoadManifest(updater, buildOpts),
inlineBuildId(updater),
patchDepdDeprecations(updater),
// Apply updater updaters, must be the last plugin
updater.plugin,
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { describe, expect, test } from "vitest";

import { patchCode } from "../ast/util.js";
import { rule } from "./patch-depd-deprecations.js";

describe("patchDepdDeprecations", () => {
test("patch", () => {
const code = `
function prepareObjectStackTrace(e,t){
return t
}
function wrapfunction(fn,message){
if(typeof fn!=="function"){
throw new TypeError("argument fn must be a function")
}
var args=createArgumentsString(fn.length);
var deprecate=this;
var stack=getStack();
var site=callSiteLocation(stack[1]);
site.name=fn.name;
var deprecatedfn=eval("(function ("+args+") {\\n"+'"use strict"\\n'+"log.call(deprecate, message, site)\\n"+"return fn.apply(this, arguments)\\n"+"})");
return deprecatedfn;
}`;

expect(patchCode(code, rule)).toMatchInlineSnapshot(`
"function prepareObjectStackTrace(e,t){
return t
}
function wrapfunction(fn, message) { if(typeof fn !== 'function') throw new Error("argument fn must be a function"); return function deprecated_fn(...args) { console.warn(message); return fn(...args); } }"
`);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { patchCode } from "../ast/util.js";
import type { ContentUpdater } from "./content-updater.js";

/**
* Some dependencies of Next.js use depd to deprecate some of their functions, depd uses `eval` to generate
* a deprecated version of such functions, this causes `eval` warnings in the terminal even if these functions
* are never called, this function fixes that by patching the depd `wrapfunction` function so that it still
* retains the same type of behavior but without using `eval`
*/
export function patchDepdDeprecations(updater: ContentUpdater) {
return updater.updateContent(
"patch-depd-deprecations",
{ filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/, contentFilter: /argument fn must be a function/ },
({ contents }) => patchCode(contents, rule)
);
}

export const rule = `
rule:
kind: function_declaration
pattern: function wrapfunction($FN, $MESSAGE) { $$$ }
all:
- has:
kind: variable_declarator
stopBy: end
has:
field: name
pattern: deprecatedfn
- has:
kind: call_expression
stopBy: end
has:
kind: identifier
pattern: eval
fix:
function wrapfunction($FN, $MESSAGE) {
if(typeof $FN !== 'function') throw new Error("argument fn must be a function");
return function deprecated_$FN(...args) {
console.warn($MESSAGE);
return $FN(...args);
}
}
`;