Skip to content
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

feat: print warning on use of deprecated API #4200

Merged
merged 17 commits into from
Jan 22, 2024
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;

Check warning on line 37 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L36-L37

Added lines #L36 - L37 were not covered by tests

// 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();

Check warning on line 42 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L39-L42

Added lines #L39 - L42 were not covered by tests

let isFromRemoteDependency = false;
const firstStackLine = stackLines[0];

Check warning on line 45 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L44-L45

Added lines #L44 - L45 were not covered by tests
if (firstStackLine && !firstStackLine.includes("file:")) {
isFromRemoteDependency = true;
}

Check warning on line 48 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L47-L48

Added lines #L47 - L48 were not covered by tests

ALREADY_WARNED_DEPRECATED.add(key);
console.log(
"%cWarning",
"color: yellow; font-weight: bold;",

Check warning on line 53 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L50-L53

Added lines #L50 - L53 were not covered by tests
);
console.log(
`%c\u251c Use of deprecated "${config.apiName}" API.`,
"color: yellow;",

Check warning on line 57 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L55-L57

Added lines #L55 - L57 were not covered by tests
);
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;",

Check warning on line 62 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L59-L62

Added lines #L59 - L62 were not covered by tests
);
console.log("%c\u2502", "color: yellow;");
console.log(
`%c\u251c Suggestion: ${config.suggestion}`,
"color: yellow;",

Check warning on line 67 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L64-L67

Added lines #L64 - L67 were not covered by tests
);
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;",

Check warning on line 73 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L69-L73

Added lines #L69 - L73 were not covered by tests
);
console.log(
"%c\u2502 Try upgrading to the latest version of that dependency.",
"color: yellow;",

Check warning on line 77 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L75-L77

Added lines #L75 - L77 were not covered by tests
);
}

Check warning on line 79 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L79

Added line #L79 was not covered by tests

console.log("%c\u2502", "color: yellow;");
console.log(
"%c\u251c Set `DENO_NO_DEPRECATION_WARNINGS=1` to disable these deprecation warnings.",
"color: yellow;",

Check warning on line 84 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L81-L84

Added lines #L81 - L84 were not covered by tests
);
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;",

Check warning on line 93 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L86-L93

Added lines #L86 - L93 were not covered by tests
);
}
console.log();

Check warning on line 96 in internal/warn_on_deprecated_api.ts

View check run for this annotation

Codecov / codecov/patch

internal/warn_on_deprecated_api.ts#L95-L96

Added lines #L95 - L96 were not covered by tests
}
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);
}