diff --git a/lib/.eslintrc.yaml b/lib/.eslintrc.yaml index 5810faa6616761..80d70f48c02ee5 100644 --- a/lib/.eslintrc.yaml +++ b/lib/.eslintrc.yaml @@ -5,3 +5,7 @@ rules: node-core/no-let-in-for-declaration: error node-core/lowercase-name-for-primitive: error node-core/non-ascii-character: error + + # Possible Errors + # http://eslint.org/docs/rules/#possible-errors + no-prototype-builtins: error diff --git a/lib/assert.js b/lib/assert.js index 67c658d9e68bb3..e0f32dae924a63 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -31,6 +31,7 @@ const { parseExpressionAt } = require('internal/deps/acorn/dist/acorn'); const { inspect } = require('util'); const { EOL } = require('os'); const nativeModule = require('native_module'); +const { ObjectIsPrototypeOf } = require('primordials'); // Escape control characters but not \n and \t to keep the line breaks and // indentation intact. @@ -400,7 +401,7 @@ function expectedException(actual, expected, msg) { if (expected.prototype !== undefined && actual instanceof expected) { return true; } - if (Error.isPrototypeOf(expected)) { + if (ObjectIsPrototypeOf(Error, expected)) { return false; } return expected.call({}, actual) === true; diff --git a/lib/internal/async_hooks.js b/lib/internal/async_hooks.js index dc720a223052bf..72ac386178d946 100644 --- a/lib/internal/async_hooks.js +++ b/lib/internal/async_hooks.js @@ -1,7 +1,9 @@ 'use strict'; +const { ObjectHasOwnProperty } = require('primordials'); const errors = require('internal/errors'); const async_wrap = process.binding('async_wrap'); + /* async_hook_fields is a Uint32Array wrapping the uint32_t array of * Environment::AsyncHooks::fields_[]. Each index tracks the number of active * hooks for each type. @@ -252,7 +254,7 @@ function newAsyncId() { } function getOrSetAsyncId(object) { - if (object.hasOwnProperty(async_id_symbol)) { + if (ObjectHasOwnProperty(object, async_id_symbol)) { return object[async_id_symbol]; } diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap_node.js index f85e557d5efdf8..55f74c68592708 100644 --- a/lib/internal/bootstrap_node.js +++ b/lib/internal/bootstrap_node.js @@ -10,6 +10,7 @@ (function(process) { let internalBinding; const exceptionHandlerState = { captureFn: null }; + const primordials = makePrimordials(); function startup() { const EventEmitter = NativeModule.require('events'); @@ -411,7 +412,7 @@ addCommandLineAPI('require', makeRequireFunction(consoleAPIModule)); const config = {}; for (const key of Object.keys(wrappedConsole)) { - if (!originalConsole.hasOwnProperty(key)) + if (!primordials.ObjectHasOwnProperty(originalConsole, key)) continue; // If global console has the same method as inspector console, // then wrap these two methods into one. Native wrapper will preserve @@ -422,7 +423,7 @@ config); } for (const key of Object.keys(originalConsole)) { - if (wrappedConsole.hasOwnProperty(key)) + if (primordials.ObjectHasOwnProperty(wrappedConsole, key)) continue; wrappedConsole[key] = originalConsole[key]; } @@ -601,6 +602,8 @@ NativeModule.require = function(id) { if (id === 'native_module') { return NativeModule; + } else if (id === 'primordials') { + return primordials; } const cached = NativeModule.getCached(id); @@ -643,7 +646,7 @@ }; NativeModule.exists = function(id) { - return NativeModule._source.hasOwnProperty(id); + return primordials.ObjectHasOwnProperty(NativeModule._source, id); }; if (config.exposeInternals) { @@ -704,4 +707,38 @@ }; startup(); + + function makePrimordials() { + const ReflectApply = Reflect.apply; + + // This function is borrowed from the function with the same name on V8 + // Extras' `utils` object. V8 implements Reflect.apply very efficiently in + // conjunction with the spread syntax, such that no additional special case + // is needed for function calls w/o arguments. + // Refs: https://git.io/vAOyO + function uncurryThis(func) { + return (thisArg, ...args) => ReflectApply(func, thisArg, args); + } + + return { + uncurryThis, + + ArrayJoin: uncurryThis(Array.prototype.join), + ArrayMap: uncurryThis(Array.prototype.map), + + FunctionBind: uncurryThis(Function.prototype.bind), + + JSONParse: JSON.parse, + + ObjectIsPrototypeOf: uncurryThis(Object.prototype.isPrototypeOf), + ObjectHasOwnProperty: uncurryThis(Object.prototype.hasOwnProperty), + ObjectKeys: Object.keys, + + ReflectApply, + ReflectHas: Reflect.has, + + StringReplace: uncurryThis(String.prototype.replace), + StringStartsWith: uncurryThis(String.prototype.startsWith), + }; + } }); diff --git a/lib/internal/crypto/sig.js b/lib/internal/crypto/sig.js index 9f1938290f70cf..b81d4c5c2111c1 100644 --- a/lib/internal/crypto/sig.js +++ b/lib/internal/crypto/sig.js @@ -16,6 +16,7 @@ const { const { isArrayBufferView } = require('internal/util/types'); const { Writable } = require('stream'); const { inherits } = require('util'); +const { ObjectHasOwnProperty } = require('primordials'); function Sign(algorithm, options) { if (!(this instanceof Sign)) @@ -55,7 +56,7 @@ Sign.prototype.sign = function sign(options, encoding) { // Options specific to RSA var rsaPadding = RSA_PKCS1_PADDING; - if (options.hasOwnProperty('padding')) { + if (ObjectHasOwnProperty(options, 'padding')) { if (options.padding === options.padding >> 0) { rsaPadding = options.padding; } else { @@ -66,7 +67,7 @@ Sign.prototype.sign = function sign(options, encoding) { } var pssSaltLength = RSA_PSS_SALTLEN_AUTO; - if (options.hasOwnProperty('saltLength')) { + if (ObjectHasOwnProperty(options, 'saltLength')) { if (options.saltLength === options.saltLength >> 0) { pssSaltLength = options.saltLength; } else { @@ -114,7 +115,7 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { // Options specific to RSA var rsaPadding = RSA_PKCS1_PADDING; - if (options.hasOwnProperty('padding')) { + if (ObjectHasOwnProperty(options, 'padding')) { if (options.padding === options.padding >> 0) { rsaPadding = options.padding; } else { @@ -125,7 +126,7 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { } var pssSaltLength = RSA_PSS_SALTLEN_AUTO; - if (options.hasOwnProperty('saltLength')) { + if (ObjectHasOwnProperty(options, 'saltLength')) { if (options.saltLength === options.saltLength >> 0) { pssSaltLength = options.saltLength; } else { diff --git a/lib/internal/loader/CreateDynamicModule.js b/lib/internal/loader/CreateDynamicModule.js index f2596de04bfcb3..4f40dca413a054 100644 --- a/lib/internal/loader/CreateDynamicModule.js +++ b/lib/internal/loader/CreateDynamicModule.js @@ -2,8 +2,7 @@ const { ModuleWrap } = internalBinding('module_wrap'); const debug = require('util').debuglog('esm'); -const ArrayJoin = Function.call.bind(Array.prototype.join); -const ArrayMap = Function.call.bind(Array.prototype.map); +const { ArrayJoin, ArrayMap } = require('primordials'); const createDynamicModule = (exports, url = '', evaluate) => { debug( diff --git a/lib/internal/loader/DefaultResolve.js b/lib/internal/loader/DefaultResolve.js index d815be87dd8954..d5b291f0c15392 100644 --- a/lib/internal/loader/DefaultResolve.js +++ b/lib/internal/loader/DefaultResolve.js @@ -9,7 +9,7 @@ const { realpathSync } = require('fs'); const preserveSymlinks = !!process.binding('config').preserveSymlinks; const errors = require('internal/errors'); const { resolve: moduleWrapResolve } = internalBinding('module_wrap'); -const StringStartsWith = Function.call.bind(String.prototype.startsWith); +const { StringStartsWith } = require('primordials'); const { getURLFromFilePath, getPathFromURL } = require('internal/url'); const realpathCache = new Map(); diff --git a/lib/internal/loader/Loader.js b/lib/internal/loader/Loader.js index f0edbbf921f40f..9fa34518028063 100644 --- a/lib/internal/loader/Loader.js +++ b/lib/internal/loader/Loader.js @@ -6,8 +6,7 @@ const ModuleJob = require('internal/loader/ModuleJob'); const defaultResolve = require('internal/loader/DefaultResolve'); const createDynamicModule = require('internal/loader/CreateDynamicModule'); const translators = require('internal/loader/Translators'); - -const FunctionBind = Function.call.bind(Function.prototype.bind); +const { FunctionBind } = require('primordials'); const debug = require('util').debuglog('esm'); diff --git a/lib/internal/loader/Translators.js b/lib/internal/loader/Translators.js index 18b1b12fd15854..b3a1e0b0af59fe 100644 --- a/lib/internal/loader/Translators.js +++ b/lib/internal/loader/Translators.js @@ -13,8 +13,7 @@ const { URL } = require('url'); const debug = require('util').debuglog('esm'); const readFileAsync = require('util').promisify(fs.readFile); const readFileSync = fs.readFileSync; -const StringReplace = Function.call.bind(String.prototype.replace); -const JsonParse = JSON.parse; +const { StringReplace, JSONParse } = require('primordials'); const translators = new SafeMap(); module.exports = translators; @@ -82,7 +81,7 @@ translators.set('json', async (url) => { const pathname = internalURLModule.getPathFromURL(new URL(url)); const content = readFileSync(pathname, 'utf8'); try { - const exports = JsonParse(internalCJSModule.stripBOM(content)); + const exports = JSONParse(internalCJSModule.stripBOM(content)); reflect.exports.default.set(exports); } catch (err) { err.message = pathname + ': ' + err.message; diff --git a/lib/internal/util/types.js b/lib/internal/util/types.js index c990bea6db4605..46acadcac443f8 100644 --- a/lib/internal/util/types.js +++ b/lib/internal/util/types.js @@ -1,15 +1,6 @@ 'use strict'; -const ReflectApply = Reflect.apply; - -// This function is borrowed from the function with the same name on V8 Extras' -// `utils` object. V8 implements Reflect.apply very efficiently in conjunction -// with the spread syntax, such that no additional special case is needed for -// function calls w/o arguments. -// Refs: https://github.com/v8/v8/blob/d6ead37d265d7215cf9c5f768f279e21bd170212/src/js/prologue.js#L152-L156 -function uncurryThis(func) { - return (thisArg, ...args) => ReflectApply(func, thisArg, args); -} +const { uncurryThis } = require('primordials'); const TypedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);