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

fix(node/util): adapt dynamic type checking to Node.js behavior #21014

Merged
merged 8 commits into from
Nov 1, 2023
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
11 changes: 6 additions & 5 deletions cli/tests/unit_node/util_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ Deno.test({
name: "[util] isBoolean",
fn() {
assert(util.isBoolean(true));
assert(util.isBoolean(new Boolean()));
assert(util.isBoolean(new Boolean(true)));
assert(!util.isBoolean(new Boolean()));
assert(!util.isBoolean(new Boolean(true)));
assert(util.isBoolean(false));
assert(!util.isBoolean("deno"));
assert(!util.isBoolean("true"));
Expand Down Expand Up @@ -80,7 +80,7 @@ Deno.test({
name: "[util] isNumber",
fn() {
assert(util.isNumber(666));
assert(util.isNumber(new Number(666)));
assert(!util.isNumber(new Number(666)));
assert(!util.isNumber("999"));
assert(!util.isNumber(null));
},
Expand All @@ -90,7 +90,7 @@ Deno.test({
name: "[util] isString",
fn() {
assert(util.isString("deno"));
assert(util.isString(new String("DIO")));
assert(!util.isString(new String("DIO")));
assert(!util.isString(1337));
},
});
Expand All @@ -99,6 +99,7 @@ Deno.test({
name: "[util] isSymbol",
fn() {
assert(util.isSymbol(Symbol()));
assert(!util.isSymbol(Object(Symbol())));
assert(!util.isSymbol(123));
assert(!util.isSymbol("string"));
},
Expand Down Expand Up @@ -128,7 +129,7 @@ Deno.test({
name: "[util] isError",
fn() {
const java = new Error();
const nodejs = new TypeError();
const nodejs = Reflect.construct(Error, [], Object);
const deno = "Future";
assert(util.isError(java));
assert(util.isError(nodejs));
Expand Down
84 changes: 51 additions & 33 deletions ext/node/polyfills/util.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials

import { promisify } from "ext:deno_node/internal/util.mjs";
import { callbackify } from "ext:deno_node/_util/_util_callbackify.ts";
import { debuglog } from "ext:deno_node/internal/util/debuglog.ts";
Expand All @@ -18,6 +15,30 @@ import { Buffer } from "node:buffer";
import { isDeepStrictEqual } from "ext:deno_node/internal/util/comparisons.ts";
import process from "node:process";
import { validateString } from "ext:deno_node/internal/validators.mjs";
const primordials = globalThis.__bootstrap.primordials;
const {
ArrayIsArray,
ArrayPrototypeJoin,
Date,
DatePrototypeGetDate,
DatePrototypeGetHours,
DatePrototypeGetMinutes,
DatePrototypeGetMonth,
DatePrototypeGetSeconds,
ErrorPrototype,
NumberPrototypeToString,
ObjectDefineProperty,
ObjectKeys,
ObjectPrototypeIsPrototypeOf,
ObjectPrototypeToString,
ObjectSetPrototypeOf,
ReflectApply,
ReflectConstruct,
SafeSet,
SetPrototypeAdd,
SetPrototypeHas,
StringPrototypePadStart,
} = primordials;

export {
callbackify,
Expand All @@ -31,13 +52,11 @@ export {
};

/** @deprecated - use `Array.isArray()` instead. */
export function isArray(value: unknown): boolean {
return Array.isArray(value);
}
export const isArray = ArrayIsArray;

/** @deprecated - use `typeof value === "boolean" || value instanceof Boolean` instead. */
/** @deprecated - use `typeof value === "boolean" instead. */
export function isBoolean(value: unknown): boolean {
return typeof value === "boolean" || value instanceof Boolean;
return typeof value === "boolean";
}

/** @deprecated - use `value === null` instead. */
Expand All @@ -50,14 +69,14 @@ export function isNullOrUndefined(value: unknown): boolean {
return value === null || value === undefined;
}

/** @deprecated - use `typeof value === "number" || value instanceof Number` instead. */
/** @deprecated - use `typeof value === "number" instead. */
export function isNumber(value: unknown): boolean {
return typeof value === "number" || value instanceof Number;
return typeof value === "number";
}

/** @deprecated - use `typeof value === "string" || value instanceof String` instead. */
/** @deprecated - use `typeof value === "string" instead. */
export function isString(value: unknown): boolean {
return typeof value === "string" || value instanceof String;
return typeof value === "string";
}

/** @deprecated - use `typeof value === "symbol"` instead. */
Expand All @@ -77,7 +96,8 @@ export function isObject(value: unknown): boolean {

/** @deprecated - use `e instanceof Error` instead. */
export function isError(e: unknown): boolean {
return e instanceof Error;
return ObjectPrototypeToString(e) === "[object Error]" ||
ObjectPrototypeIsPrototypeOf(ErrorPrototype, e);
}

/** @deprecated - use `typeof value === "function"` instead. */
Expand All @@ -103,9 +123,7 @@ export function isPrimitive(value: unknown): boolean {
}

/** @deprecated Use Buffer.isBuffer() instead. */
export function isBuffer(value: unknown): boolean {
return Buffer.isBuffer(value);
}
export const isBuffer = Buffer.isBuffer;

/** @deprecated Use Object.assign() instead. */
export function _extend(
Expand All @@ -115,7 +133,7 @@ export function _extend(
// Don't do anything if source isn't an object
if (source === null || typeof source !== "object") return target;

const keys = Object.keys(source!);
const keys = ObjectKeys(source!);
let i = keys.length;
while (i--) {
target[keys[i]] = (source as Record<string, unknown>)[keys[i]];
Expand Down Expand Up @@ -147,12 +165,12 @@ export function inherits<T, U>(
superCtor.prototype,
);
}
Object.defineProperty(ctor, "super_", {
ObjectDefineProperty(ctor, "super_", {
value: superCtor,
writable: true,
configurable: true,
});
Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
ObjectSetPrototypeOf(ctor.prototype, superCtor.prototype);
}

import {
Expand All @@ -170,7 +188,7 @@ export type TextEncoder = import("./_utils.ts")._TextEncoder;
export const TextEncoder = _TextEncoder;

function pad(n: number) {
return n.toString().padStart(2, "0");
return StringPrototypePadStart(NumberPrototypeToString(n), 2, "0");
}

const months = [
Expand All @@ -193,12 +211,12 @@ const months = [
*/
function timestamp(): string {
const d = new Date();
const t = [
pad(d.getHours()),
pad(d.getMinutes()),
pad(d.getSeconds()),
].join(":");
return `${(d.getDate())} ${months[d.getMonth()]} ${t}`;
const t = ArrayPrototypeJoin([
pad(DatePrototypeGetHours(d)),
pad(DatePrototypeGetMinutes(d)),
pad(DatePrototypeGetSeconds(d)),
], ":");
return `${DatePrototypeGetDate(d)} ${months[DatePrototypeGetMonth(d)]} ${t}`;
}

/**
Expand All @@ -207,12 +225,12 @@ function timestamp(): string {
*/
// deno-lint-ignore no-explicit-any
export function log(...args: any[]) {
console.log("%s - %s", timestamp(), format(...args));
console.log("%s - %s", timestamp(), ReflectApply(format, undefined, args));
}

// Keep a list of deprecation codes that have been warned on so we only warn on
// each one once.
const codesWarned = new Set();
const codesWarned = new SafeSet();

// Mark that a method should not be used.
// Returns a modified function which warns once by default.
Expand All @@ -233,23 +251,23 @@ export function deprecate(fn: any, msg: string, code?: any) {
if (!warned) {
warned = true;
if (code !== undefined) {
if (!codesWarned.has(code)) {
if (!SetPrototypeHas(codesWarned, code)) {
process.emitWarning(msg, "DeprecationWarning", code, deprecated);
codesWarned.add(code);
SetPrototypeAdd(codesWarned, code);
}
} else {
// deno-lint-ignore no-explicit-any
process.emitWarning(msg, "DeprecationWarning", deprecated as any);
}
}
if (new.target) {
return Reflect.construct(fn, args, new.target);
return ReflectConstruct(fn, args, new.target);
}
return Reflect.apply(fn, this, args);
return ReflectApply(fn, this, args);
}

// The wrapper will keep the same prototype as fn to maintain prototype chain
Object.setPrototypeOf(deprecated, fn);
ObjectSetPrototypeOf(deprecated, fn);
if (fn.prototype) {
// Setting this (rather than using Object.setPrototype, as above) ensures
// that calling the unwrapped constructor gives an instanceof the wrapped
Expand Down
2 changes: 1 addition & 1 deletion tools/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export { delay } from "../test_util/std/async/delay.ts";
// [toolName] --version output
const versions = {
"dprint": "dprint 0.40.0",
"dlint": "dlint 0.51.0",
"dlint": "dlint 0.52.2",
};

export const ROOT_PATH = dirname(dirname(fromFileUrl(import.meta.url)));
Expand Down