Skip to content

Commit

Permalink
feat: print warning on use of deprecated API (#4200)
Browse files Browse the repository at this point in the history
* feat: `warnDeprecatedApi()`

* refactor: fixes and tweaks

* refactor: tweaks and improvements

* refactor: further work

* refactor

* fix

* tweaks

* tweak

* tweak

* tweaks

* tweak

* add test

* tweaks

* make compatible with Deploy

* tweak

* fix
  • Loading branch information
iuioiua authored Jan 22, 2024
1 parent 9959b88 commit 88b5f47
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 1 deletion.
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"automation/": "https://raw.githubusercontent.com/denoland/automation/0.10.0/"
},
"tasks": {
"test": "deno test --doc --unstable --allow-all --parallel --coverage --trace-ops",
"test": "DENO_NO_DEPRECATION_WARNINGS=1 deno test --doc --unstable --allow-all --parallel --coverage --trace-ops",
"test:browser": "git grep --name-only \"This module is browser compatible.\" | grep -v deno.json | grep -v .github/workflows | grep -v _tools | xargs deno check --config browser-compat.tsconfig.json",
"fmt:licence-headers": "deno run --allow-read --allow-write ./_tools/check_licence.ts",
"lint:deprecations": "deno run --allow-read --allow-net --allow-env=HOME ./_tools/check_deprecation.ts",
Expand Down
9 changes: 9 additions & 0 deletions internal/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

/**
* Internal utilities for the public API of the Deno Standard Library.
*
* Note: for internal use only.
*
* @module
*/
97 changes: 97 additions & 0 deletions internal/warn_on_deprecated_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

// deno-lint-ignore no-explicit-any
const { Deno } = globalThis as any;

const ALREADY_WARNED_DEPRECATED = new Set<string>();
const ENV_VAR_KEY = "DENO_NO_DEPRECATION_WARNINGS";
const shouldDisableDeprecatedApiWarning =
Deno?.permissions.querySync?.({ name: "env", variable: ENV_VAR_KEY })
.state === "granted" && Deno?.env.get(ENV_VAR_KEY) === "1";

interface WarnDeprecatedApiConfig {
/** The name of the deprecated API. */
apiName: string;
/** The stack trace of the deprecated API. */
stack: string;
/** The version in which the API will be removed. */
removalVersion: string;
/** An optional message to print. */
suggestion?: string;
}

/**
* Prints a warning message to the console for the given deprecated API.
*
* These warnings can be disabled by setting `DENO_NO_DEPRECATION_WARNINGS=1`
* in the current process.
*
* Mostly copied from
* {@link https://github.com/denoland/deno/blob/c62615bfe5a070c2517f3af3208d4308c72eb054/runtime/js/99_main.js#L101}.
*/
export function warnOnDeprecatedApi(config: WarnDeprecatedApiConfig) {
if (shouldDisableDeprecatedApiWarning) return;

const key = config.apiName + config.stack;
if (ALREADY_WARNED_DEPRECATED.has(key)) return;

// If we haven't warned yet, let's do some processing of the stack trace
// to make it more useful.
const stackLines = config.stack.split("\n");
stackLines.shift();

let isFromRemoteDependency = false;
const firstStackLine = stackLines[0];
if (firstStackLine && !firstStackLine.includes("file:")) {
isFromRemoteDependency = true;
}

ALREADY_WARNED_DEPRECATED.add(key);
console.log(
"%cWarning",
"color: yellow; font-weight: bold;",
);
console.log(
`%c\u251c Use of deprecated "${config.apiName}" API.`,
"color: yellow;",
);
console.log("%c\u2502", "color: yellow;");
console.log(
`%c\u251c This API will be removed in version ${config.removalVersion} of the Deno Standard Library.`,
"color: yellow;",
);
console.log("%c\u2502", "color: yellow;");
console.log(
`%c\u251c Suggestion: ${config.suggestion}`,
"color: yellow;",
);
if (isFromRemoteDependency) {
console.log("%c\u2502", "color: yellow;");
console.log(
`%c\u251c Suggestion: It appears this API is used by a remote dependency.`,
"color: yellow;",
);
console.log(
"%c\u2502 Try upgrading to the latest version of that dependency.",
"color: yellow;",
);
}

console.log("%c\u2502", "color: yellow;");
console.log(
"%c\u251c Set `DENO_NO_DEPRECATION_WARNINGS=1` to disable these deprecation warnings.",
"color: yellow;",
);
console.log("%c\u2502", "color: yellow;");
console.log("%c\u2514 Stack trace:", "color: yellow;");
for (let i = 0; i < stackLines.length; i++) {
console.log(
`%c ${i == stackLines.length - 1 ? "\u2514" : "\u251c"}\u2500 ${
stackLines[i].trim()
}`,
"color: yellow;",
);
}
console.log();
}
49 changes: 49 additions & 0 deletions internal/warn_on_deprecated_api_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assertEquals } from "../assert/assert_equals.ts";
import { warnOnDeprecatedApi } from "./warn_on_deprecated_api.ts";

Deno.test("warnDeprecatedApi()", async () => {
const command = new Deno.Command(Deno.execPath(), {
args: ["run", "--quiet", "--no-lock", import.meta.url],
stderr: "inherit",
});
const { success, stdout } = await command.output();
const output = new TextDecoder().decode(stdout);

assertEquals(success, true);
assertEquals(
output,
`Warning
├ Use of deprecated "fn()" API.
├ This API will be removed in version 1.0.0 of the Deno Standard Library.
├ Suggestion: Do something else instead.
├ Set \`DENO_NO_DEPRECATION_WARNINGS=1\` to disable these deprecation warnings.
└ Stack trace:
├─ at fn (${import.meta.url}:39:12)
└─ at ${import.meta.url}:47:31
Hello, world!
Hello, world!
END
`,
);
});

function fn() {
warnOnDeprecatedApi({
apiName: "fn()",
stack: new Error().stack!,
removalVersion: "1.0.0",
suggestion: "Do something else instead.",
});
console.log("Hello, world!");
}

if (import.meta.main) {
for (let i = 0; i < 2; i++) fn();
console.log("END");
}
13 changes: 13 additions & 0 deletions streams/read_all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
readAllSync as _readAllSync,
} from "../io/read_all.ts";
import type { Reader, ReaderSync } from "../io/types.ts";
import { warnOnDeprecatedApi } from "../internal/warn_on_deprecated_api.ts";

/**
* Read {@linkcode Reader} `r` until EOF (`null`) and resolve to the content as
Expand Down Expand Up @@ -33,6 +34,12 @@ import type { Reader, ReaderSync } from "../io/types.ts";
* @deprecated (will be removed in 0.214.0) Import from {@link https://deno.land/std/io/read_all.ts} instead.
*/
export async function readAll(r: Reader): Promise<Uint8Array> {
warnOnDeprecatedApi({
apiName: "readAll()",
stack: new Error().stack!,
removalVersion: "0.214.0",
suggestion: "Import from `https://deno.land/std/io/read_all.ts` instead.",
});
return await _readAll(r);
}

Expand Down Expand Up @@ -62,5 +69,11 @@ export async function readAll(r: Reader): Promise<Uint8Array> {
* @deprecated (will be removed in 0.214.0) Import from {@link https://deno.land/std/io/read_all.ts} instead.
*/
export function readAllSync(r: ReaderSync): Uint8Array {
warnOnDeprecatedApi({
apiName: "readAllSync()",
stack: new Error().stack!,
removalVersion: "0.214.0",
suggestion: "Import from `https://deno.land/std/io/read_all.ts` instead.",
});
return _readAllSync(r);
}

0 comments on commit 88b5f47

Please sign in to comment.