From c24517d1741ece71f9c827eeb2ade58e2577708a Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 3 Jan 2023 12:43:21 -0800 Subject: [PATCH] tools: add `prefer-proto` rule --- .eslintrc.js | 1 + lib/_http_agent.js | 7 ++-- lib/_http_outgoing.js | 9 +++-- lib/_tls_common.js | 3 +- lib/buffer.js | 5 ++- lib/diagnostics_channel.js | 3 +- lib/events.js | 13 ++++---- lib/internal/bootstrap/loaders.js | 5 ++- lib/internal/cluster/round_robin_handle.js | 3 +- lib/internal/console/constructor.js | 3 +- lib/internal/dns/utils.js | 3 +- lib/internal/error_serdes.js | 2 +- lib/internal/http2/compat.js | 9 +++-- lib/internal/http2/core.js | 11 +++---- lib/internal/http2/util.js | 5 ++- lib/internal/modules/cjs/loader.js | 9 +++-- lib/internal/modules/esm/assert.js | 3 +- .../modules/esm/create_dynamic_module.js | 5 ++- lib/internal/modules/esm/loader.js | 3 +- lib/internal/modules/esm/module_job.js | 3 +- lib/internal/modules/esm/module_map.js | 3 +- lib/internal/modules/run_main.js | 3 +- lib/internal/policy/manifest.js | 9 +++-- lib/internal/source_map/source_map_cache.js | 3 +- lib/internal/test_runner/utils.js | 3 +- lib/internal/timers.js | 3 +- lib/internal/util.js | 9 +++-- lib/internal/util/debuglog.js | 3 +- lib/internal/util/inspect.js | 3 +- lib/internal/webstreams/readablestream.js | 7 +--- lib/internal/worker.js | 3 +- lib/net.js | 7 ++-- lib/querystring.js | 3 +- lib/repl.js | 3 +- lib/timers.js | 3 +- lib/url.js | 5 ++- tools/eslint-rules/prefer-proto.js | 33 +++++++++++++++++++ 37 files changed, 102 insertions(+), 106 deletions(-) create mode 100644 tools/eslint-rules/prefer-proto.js diff --git a/.eslintrc.js b/.eslintrc.js index b96b2b5690a2c0..e1961de42dea0a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -314,6 +314,7 @@ module.exports = { // Custom rules from eslint-plugin-node-core 'node-core/no-unescaped-regexp-dot': 'error', 'node-core/no-duplicate-requires': 'error', + 'node-core/prefer-proto': 'error', }, globals: { ByteLengthQueuingStrategy: 'readable', diff --git a/lib/_http_agent.js b/lib/_http_agent.js index 14096361760657..418996fefc1825 100644 --- a/lib/_http_agent.js +++ b/lib/_http_agent.js @@ -32,7 +32,6 @@ const { FunctionPrototypeCall, NumberIsNaN, NumberParseInt, - ObjectCreate, ObjectKeys, ObjectSetPrototypeOf, ObjectValues, @@ -111,9 +110,9 @@ function Agent(options) { // Don't confuse net and make it think that we're connecting to a pipe this.options.path = null; - this.requests = ObjectCreate(null); - this.sockets = ObjectCreate(null); - this.freeSockets = ObjectCreate(null); + this.requests = { __proto__: null }; + this.sockets = { __proto__: null }; + this.freeSockets = { __proto__: null }; this.keepAliveMsecs = this.options.keepAliveMsecs || 1000; this.keepAlive = this.options.keepAlive || false; this.maxSockets = this.options.maxSockets || Agent.defaultMaxSockets; diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 8c80eabaec9e74..5bffbd6a949fcd 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -28,7 +28,6 @@ const { MathAbs, MathFloor, NumberPrototypeToString, - ObjectCreate, ObjectDefineProperty, ObjectKeys, ObjectValues, @@ -217,7 +216,7 @@ ObjectDefineProperty(OutgoingMessage.prototype, '_headers', { if (val == null) { this[kOutHeaders] = null; } else if (typeof val === 'object') { - const headers = this[kOutHeaders] = ObjectCreate(null); + const headers = this[kOutHeaders] = { __proto__: null }; const keys = ObjectKeys(val); // Retain for(;;) loop for performance reasons // Refs: https://github.com/nodejs/node/pull/30958 @@ -244,7 +243,7 @@ ObjectDefineProperty(OutgoingMessage.prototype, '_headerNames', { get: internalUtil.deprecate(function() { const headers = this[kOutHeaders]; if (headers !== null) { - const out = ObjectCreate(null); + const out = { __proto__: null }; const keys = ObjectKeys(headers); // Retain for(;;) loop for performance reasons // Refs: https://github.com/nodejs/node/pull/30958 @@ -667,7 +666,7 @@ OutgoingMessage.prototype.setHeader = function setHeader(name, value) { let headers = this[kOutHeaders]; if (headers === null) - this[kOutHeaders] = headers = ObjectCreate(null); + this[kOutHeaders] = headers = { __proto__: null }; headers[StringPrototypeToLowerCase(name)] = [name, value]; return this; @@ -742,7 +741,7 @@ OutgoingMessage.prototype.getRawHeaderNames = function getRawHeaderNames() { // Returns a shallow copy of the current outgoing headers. OutgoingMessage.prototype.getHeaders = function getHeaders() { const headers = this[kOutHeaders]; - const ret = ObjectCreate(null); + const ret = { __proto__: null }; if (headers) { const keys = ObjectKeys(headers); // Retain for(;;) loop for performance reasons diff --git a/lib/_tls_common.js b/lib/_tls_common.js index 373286fe6742b6..16c6a647cc29b4 100644 --- a/lib/_tls_common.js +++ b/lib/_tls_common.js @@ -26,7 +26,6 @@ const tls = require('tls'); const { ArrayPrototypePush, JSONParse, - ObjectCreate, RegExpPrototypeSymbolReplace, } = primordials; @@ -131,7 +130,7 @@ function translatePeerCertificate(c) { } if (c.infoAccess != null) { const info = c.infoAccess; - c.infoAccess = ObjectCreate(null); + c.infoAccess = { __proto__: null }; // XXX: More key validation? RegExpPrototypeSymbolReplace(/([^\n:]*):([^\n]*)(?:\n|$)/g, info, diff --git a/lib/buffer.js b/lib/buffer.js index 65709ca5ed56a2..6b5f72c6570f78 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -33,7 +33,6 @@ const { NumberIsNaN, NumberMAX_SAFE_INTEGER, NumberMIN_SAFE_INTEGER, - ObjectCreate, ObjectDefineProperties, ObjectDefineProperty, ObjectSetPrototypeOf, @@ -146,7 +145,7 @@ const constants = ObjectDefineProperties({}, { Buffer.poolSize = 8 * 1024; let poolSize, poolOffset, allocPool; -const encodingsMap = ObjectCreate(null); +const encodingsMap = { __proto__: null }; for (let i = 0; i < encodings.length; ++i) encodingsMap[encodings[i]] = i; @@ -845,7 +844,7 @@ Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) { if (ctx) { let extras = false; const filter = ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE; - const obj = ObjectCreate(null); + const obj = { __proto__: null }; ArrayPrototypeForEach(getOwnNonIndexProperties(this, filter), (key) => { extras = true; diff --git a/lib/diagnostics_channel.js b/lib/diagnostics_channel.js index 9d2d805bf25052..90d3316f8c30bf 100644 --- a/lib/diagnostics_channel.js +++ b/lib/diagnostics_channel.js @@ -4,7 +4,6 @@ const { ArrayPrototypeIndexOf, ArrayPrototypePush, ArrayPrototypeSplice, - ObjectCreate, ObjectGetPrototypeOf, ObjectSetPrototypeOf, SymbolHasInstance, @@ -92,7 +91,7 @@ class Channel { publish() {} } -const channels = ObjectCreate(null); +const channels = { __proto__: null }; function channel(name) { let channel; diff --git a/lib/events.js b/lib/events.js index efce9b9c228c97..3f3e3d295ce570 100644 --- a/lib/events.js +++ b/lib/events.js @@ -35,7 +35,6 @@ const { FunctionPrototypeCall, NumberIsNaN, NumberMAX_SAFE_INTEGER, - ObjectCreate, ObjectDefineProperty, ObjectDefineProperties, ObjectGetPrototypeOf, @@ -344,7 +343,7 @@ EventEmitter.init = function(opts) { if (this._events === undefined || this._events === ObjectGetPrototypeOf(this)._events) { - this._events = ObjectCreate(null); + this._events = { __proto__: null }; this._eventsCount = 0; } @@ -553,7 +552,7 @@ function _addListener(target, type, listener, prepend) { events = target._events; if (events === undefined) { - events = target._events = ObjectCreate(null); + events = target._events = { __proto__: null }; target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before @@ -691,7 +690,7 @@ EventEmitter.prototype.removeListener = if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) - this._events = ObjectCreate(null); + this._events = { __proto__: null }; else { delete events[type]; if (events.removeListener) @@ -746,11 +745,11 @@ EventEmitter.prototype.removeAllListeners = // Not listening for removeListener, no need to emit if (events.removeListener === undefined) { if (arguments.length === 0) { - this._events = ObjectCreate(null); + this._events = { __proto__: null }; this._eventsCount = 0; } else if (events[type] !== undefined) { if (--this._eventsCount === 0) - this._events = ObjectCreate(null); + this._events = { __proto__: null }; else delete events[type]; } @@ -764,7 +763,7 @@ EventEmitter.prototype.removeAllListeners = this.removeAllListeners(key); } this.removeAllListeners('removeListener'); - this._events = ObjectCreate(null); + this._events = { __proto__: null }; this._eventsCount = 0; return this; } diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index 47bd830570fa9f..2bd26e1a2668fd 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -49,7 +49,6 @@ const { ArrayPrototypePush, ArrayPrototypeSlice, Error, - ObjectCreate, ObjectDefineProperty, ObjectKeys, ObjectPrototypeHasOwnProperty, @@ -129,7 +128,7 @@ const schemelessBlockList = new SafeSet([ // Set up process.binding() and process._linkedBinding(). { - const bindingObj = ObjectCreate(null); + const bindingObj = { __proto__: null }; process.binding = function binding(module) { module = String(module); @@ -167,7 +166,7 @@ const schemelessBlockList = new SafeSet([ */ let internalBinding; { - const bindingObj = ObjectCreate(null); + const bindingObj = { __proto__: null }; // eslint-disable-next-line no-global-assign internalBinding = function internalBinding(module) { let mod = bindingObj[module]; diff --git a/lib/internal/cluster/round_robin_handle.js b/lib/internal/cluster/round_robin_handle.js index 29a87e716e8f21..7ba28d7f4e6a51 100644 --- a/lib/internal/cluster/round_robin_handle.js +++ b/lib/internal/cluster/round_robin_handle.js @@ -3,7 +3,6 @@ const { ArrayIsArray, Boolean, - ObjectCreate, SafeMap, } = primordials; @@ -19,7 +18,7 @@ function RoundRobinHandle(key, address, { port, fd, flags, backlog, readableAll, this.key = key; this.all = new SafeMap(); this.free = new SafeMap(); - this.handles = init(ObjectCreate(null)); + this.handles = init({ __proto__: null }); this.handle = null; this.server = net.createServer(assert.fail); diff --git a/lib/internal/console/constructor.js b/lib/internal/console/constructor.js index ae7357f938dc56..6d2f3a34562ab1 100644 --- a/lib/internal/console/constructor.js +++ b/lib/internal/console/constructor.js @@ -15,7 +15,6 @@ const { MathFloor, Number, NumberPrototypeToFixed, - ObjectCreate, ObjectDefineProperties, ObjectDefineProperty, ObjectKeys, @@ -572,7 +571,7 @@ const consoleMethods = { return final([iterKey, valuesKey], [getIndexArray(length), values]); } - const map = ObjectCreate(null); + const map = { __proto__: null }; let hasPrimitives = false; const valuesKeyArray = []; const indexKeyArray = ObjectKeys(tabularData); diff --git a/lib/internal/dns/utils.js b/lib/internal/dns/utils.js index 006dcd978e99b6..aacf4bc4dcd506 100644 --- a/lib/internal/dns/utils.js +++ b/lib/internal/dns/utils.js @@ -9,7 +9,6 @@ const { NumberParseInt, RegExpPrototypeExec, RegExpPrototypeSymbolReplace, - ObjectCreate, Symbol, } = primordials; @@ -286,7 +285,7 @@ function setDefaultResultOrder(value) { } function createResolverClass(resolver) { - const resolveMap = ObjectCreate(null); + const resolveMap = { __proto__: null }; class Resolver extends ResolverBase {} diff --git a/lib/internal/error_serdes.js b/lib/internal/error_serdes.js index 68576c1c24d7a7..dbc5e03fea028b 100644 --- a/lib/internal/error_serdes.js +++ b/lib/internal/error_serdes.js @@ -33,7 +33,7 @@ const errors = { const errorConstructorNames = new SafeSet(ObjectKeys(errors)); function TryGetAllProperties(object, target = object) { - const all = ObjectCreate(null); + const all = { __proto__: null }; if (object === null) return all; ObjectAssign(all, diff --git a/lib/internal/http2/compat.js b/lib/internal/http2/compat.js index 8ece2d912c6e9d..dec5b734a2490f 100644 --- a/lib/internal/http2/compat.js +++ b/lib/internal/http2/compat.js @@ -6,7 +6,6 @@ const { Boolean, FunctionPrototypeBind, ObjectAssign, - ObjectCreate, ObjectKeys, ObjectPrototypeHasOwnProperty, Proxy, @@ -483,8 +482,8 @@ class Http2ServerResponse extends Stream { sendDate: true, statusCode: HTTP_STATUS_OK, }; - this[kHeaders] = ObjectCreate(null); - this[kTrailers] = ObjectCreate(null); + this[kHeaders] = { __proto__: null }; + this[kTrailers] = { __proto__: null }; this[kStream] = stream; stream[kProxySocket] = null; stream[kResponse] = this; @@ -603,7 +602,7 @@ class Http2ServerResponse extends Stream { } getHeaders() { - const headers = ObjectCreate(null); + const headers = { __proto__: null }; return ObjectAssign(headers, this[kHeaders]); } @@ -851,7 +850,7 @@ class Http2ServerResponse extends Stream { writeEarlyHints(hints) { validateObject(hints, 'hints'); - const headers = ObjectCreate(null); + const headers = { __proto__: null }; const linkHeaderValue = validateLinkHeaderValue(hints.link); diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index 6ddc1f609cf2fb..48b73ae54ce9f6 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -12,7 +12,6 @@ const { FunctionPrototypeCall, MathMin, ObjectAssign, - ObjectCreate, ObjectKeys, ObjectDefineProperty, ObjectPrototypeHasOwnProperty, @@ -1753,7 +1752,7 @@ class ClientHttp2Session extends Http2Session { assertIsObject(headers, 'headers'); assertIsObject(options, 'options'); - headers = ObjectAssign(ObjectCreate(null), headers); + headers = ObjectAssign({ __proto__: null }, headers); options = { ...options }; if (headers[HTTP2_HEADER_METHOD] === undefined) @@ -2252,7 +2251,7 @@ class Http2Stream extends Duplex { throw new ERR_HTTP2_TRAILERS_NOT_READY(); assertIsObject(headers, 'headers'); - headers = ObjectAssign(ObjectCreate(null), headers); + headers = ObjectAssign({ __proto__: null }, headers); debugStreamObj(this, 'sending trailers'); @@ -2420,7 +2419,7 @@ function callStreamClose(stream) { function processHeaders(oldHeaders, options) { assertIsObject(oldHeaders, 'headers'); - const headers = ObjectCreate(null); + const headers = { __proto__: null }; if (oldHeaders !== null && oldHeaders !== undefined) { // This loop is here for performance reason. Do not change. @@ -2696,7 +2695,7 @@ class ServerHttp2Stream extends Http2Stream { options.endStream = !!options.endStream; assertIsObject(headers, 'headers'); - headers = ObjectAssign(ObjectCreate(null), headers); + headers = ObjectAssign({ __proto__: null }, headers); if (headers[HTTP2_HEADER_METHOD] === undefined) headers[HTTP2_HEADER_METHOD] = HTTP2_METHOD_GET; @@ -2931,7 +2930,7 @@ class ServerHttp2Stream extends Http2Stream { throw new ERR_HTTP2_HEADERS_AFTER_RESPOND(); assertIsObject(headers, 'headers'); - headers = ObjectAssign(ObjectCreate(null), headers); + headers = ObjectAssign({ __proto__: null }, headers); debugStreamObj(this, 'sending additional headers'); diff --git a/lib/internal/http2/util.js b/lib/internal/http2/util.js index ecb943c9b8e37d..54f9f032a0ff50 100644 --- a/lib/internal/http2/util.js +++ b/lib/internal/http2/util.js @@ -8,7 +8,6 @@ const { Error, MathMax, Number, - ObjectCreate, ObjectDefineProperty, ObjectKeys, SafeSet, @@ -279,7 +278,7 @@ function updateOptionsBuffer(options) { function getDefaultSettings() { settingsBuffer[IDX_SETTINGS_FLAGS] = 0; binding.refreshDefaultSettings(); - const holder = ObjectCreate(null); + const holder = { __proto__: null }; const flags = settingsBuffer[IDX_SETTINGS_FLAGS]; @@ -588,7 +587,7 @@ const assertWithinRange = hideStackFrames( ); function toHeaderObject(headers, sensitiveHeaders) { - const obj = ObjectCreate(null); + const obj = { __proto__: null }; for (let n = 0; n < headers.length; n += 2) { const name = headers[n]; let value = headers[n + 1]; diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 092e9545b43563..46e58400fb34b5 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -37,7 +37,6 @@ const { Boolean, Error, JSONParse, - ObjectCreate, ObjectDefineProperty, ObjectFreeze, ObjectGetOwnPropertyDescriptor, @@ -145,7 +144,7 @@ const { const { kEvaluated } = internalBinding('module_wrap'); const isWindows = process.platform === 'win32'; -const relativeResolveCache = ObjectCreate(null); +const relativeResolveCache = { __proto__: null }; let requireDepth = 0; let statCache = null; @@ -207,9 +206,9 @@ function Module(id = '', parent) { this.children = []; } -Module._cache = ObjectCreate(null); -Module._pathCache = ObjectCreate(null); -Module._extensions = ObjectCreate(null); +Module._cache = { __proto__: null }; +Module._pathCache = { __proto__: null }; +Module._extensions = { __proto__: null }; let modulePaths = []; Module.globalPaths = []; diff --git a/lib/internal/modules/esm/assert.js b/lib/internal/modules/esm/assert.js index 4402306b934af7..caa2845475f6c7 100644 --- a/lib/internal/modules/esm/assert.js +++ b/lib/internal/modules/esm/assert.js @@ -3,7 +3,6 @@ const { ArrayPrototypeFilter, ArrayPrototypeIncludes, - ObjectCreate, ObjectValues, ObjectPrototypeHasOwnProperty, } = primordials; @@ -53,7 +52,7 @@ const supportedAssertionTypes = ArrayPrototypeFilter( * @throws {TypeError} If the format and assertion type are incompatible. */ function validateAssertions(url, format, - importAssertions = ObjectCreate(null)) { + importAssertions = { __proto__: null }) { const validType = formatTypeMap[format]; switch (validType) { diff --git a/lib/internal/modules/esm/create_dynamic_module.js b/lib/internal/modules/esm/create_dynamic_module.js index 1abb909f58526b..26ccd38be1ad6f 100644 --- a/lib/internal/modules/esm/create_dynamic_module.js +++ b/lib/internal/modules/esm/create_dynamic_module.js @@ -4,7 +4,6 @@ const { ArrayPrototypeJoin, ArrayPrototypeMap, JSONStringify, - ObjectCreate, SafeSet, } = primordials; @@ -40,12 +39,12 @@ import.meta.done(); const readyfns = new SafeSet(); const reflect = { - exports: ObjectCreate(null), + exports: { __proto__: null }, onReady: (cb) => { readyfns.add(cb); }, }; if (imports.length) - reflect.imports = ObjectCreate(null); + reflect.imports = { __proto__: null }; const { setCallbackForWrap } = require('internal/modules/esm/utils'); setCallbackForWrap(m, { initializeImportMeta: (meta, wrap) => { diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 5c4ee53542b4e6..04982ca94a9221 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -7,7 +7,6 @@ const { Array, ArrayIsArray, FunctionPrototypeCall, - ObjectCreate, ObjectSetPrototypeOf, SafePromiseAllReturnArrayLike, SafeWeakMap, @@ -303,7 +302,7 @@ class ESMLoader { async resolve( originalSpecifier, parentURL, - importAssertions = ObjectCreate(null), + importAssertions = { __proto__: null }, ) { if (this.#hooks) { return this.#hooks.resolve(originalSpecifier, parentURL, importAssertions); diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index ddf574b07a8e8a..eeafd086073ebb 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -5,7 +5,6 @@ const { ArrayPrototypePush, ArrayPrototypeSome, FunctionPrototype, - ObjectCreate, ObjectSetPrototypeOf, PromiseResolve, PromisePrototypeThen, @@ -51,7 +50,7 @@ const isCommonJSGlobalLikeNotDefinedError = (errorMessage) => class ModuleJob { // `loader` is the Loader instance used for loading dependencies. // `moduleProvider` is a function - constructor(loader, url, importAssertions = ObjectCreate(null), + constructor(loader, url, importAssertions = { __proto__: null }, moduleProvider, isMain, inspectBrk) { this.loader = loader; this.importAssertions = importAssertions; diff --git a/lib/internal/modules/esm/module_map.js b/lib/internal/modules/esm/module_map.js index 7280f052fef59a..ac6d95445ae757 100644 --- a/lib/internal/modules/esm/module_map.js +++ b/lib/internal/modules/esm/module_map.js @@ -2,7 +2,6 @@ const { kImplicitAssertType } = require('internal/modules/esm/assert'); const { - ObjectCreate, SafeMap, } = primordials; let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { @@ -31,7 +30,7 @@ class ModuleMap extends SafeMap { debug(`Storing ${url} (${ type === kImplicitAssertType ? 'implicit type' : type }) in ModuleMap`); - const cachedJobsForUrl = super.get(url) ?? ObjectCreate(null); + const cachedJobsForUrl = super.get(url) ?? { __proto__: null }; cachedJobsForUrl[type] = job; return super.set(url, cachedJobsForUrl); } diff --git a/lib/internal/modules/run_main.js b/lib/internal/modules/run_main.js index c948eaf4ae4437..0bfe7b11241416 100644 --- a/lib/internal/modules/run_main.js +++ b/lib/internal/modules/run_main.js @@ -1,7 +1,6 @@ 'use strict'; const { - ObjectCreate, StringPrototypeEndsWith, } = primordials; @@ -54,7 +53,7 @@ function runMainESM(mainPath) { handleMainPromise(loadESM((esmLoader) => { const main = path.isAbsolute(mainPath) ? pathToFileURL(mainPath).href : mainPath; - return esmLoader.import(main, undefined, ObjectCreate(null)); + return esmLoader.import(main, undefined, { __proto__: null }); })); } diff --git a/lib/internal/policy/manifest.js b/lib/internal/policy/manifest.js index 86368628b44e86..4e383c8b12e3ec 100644 --- a/lib/internal/policy/manifest.js +++ b/lib/internal/policy/manifest.js @@ -4,7 +4,6 @@ const { ArrayIsArray, ArrayPrototypeSort, - ObjectCreate, ObjectEntries, ObjectFreeze, ObjectKeys, @@ -178,7 +177,7 @@ class DependencyMapperInstance { /** * @type {Record} */ - const normalizedDependencyMap = ObjectCreate(null); + const normalizedDependencyMap = { __proto__: null }; for (let specifier in dependencies) { const target = dependencies[specifier]; specifier = canonicalizeSpecifier(specifier, manifest.href); @@ -443,10 +442,10 @@ class Manifest { this.#reaction = reaction; const jsonResourcesEntries = ObjectEntries( - obj.resources ?? ObjectCreate(null) + obj.resources ?? { __proto__: null } ); - const jsonScopesEntries = ObjectEntries(obj.scopes ?? ObjectCreate(null)); - const defaultDependencies = obj.dependencies ?? ObjectCreate(null); + const jsonScopesEntries = ObjectEntries(obj.scopes ?? { __proto__: null }); + const defaultDependencies = obj.dependencies ?? { __proto__: null }; this.#defaultDependencies = new DependencyMapperInstance( 'default', diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index 2faf4489059b1e..f1601a5d4ecdae 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -3,7 +3,6 @@ const { ArrayPrototypeMap, JSONParse, - ObjectCreate, ObjectKeys, ObjectGetOwnPropertyDescriptor, ObjectPrototypeHasOwnProperty, @@ -280,7 +279,7 @@ function sourcesToAbsolute(baseURL, data) { // Get serialized representation of source-map cache, this is used // to persist a cache of source-maps to disk when NODE_V8_COVERAGE is enabled. function sourceMapCacheToObject() { - const obj = ObjectCreate(null); + const obj = { __proto__: null }; for (const { 0: k, 1: v } of esmSourceMapCache) { obj[k] = v; diff --git a/lib/internal/test_runner/utils.js b/lib/internal/test_runner/utils.js index 3fc99ce37cc33a..b9c9b4b677fef4 100644 --- a/lib/internal/test_runner/utils.js +++ b/lib/internal/test_runner/utils.js @@ -1,7 +1,6 @@ 'use strict'; const { ArrayPrototypePush, - ObjectCreate, ObjectGetOwnPropertyDescriptor, SafePromiseAllReturnArrayLike, RegExp, @@ -114,7 +113,7 @@ async function getReportersMap(reporters, destinations) { parentURL = 'file:///'; } const { esmLoader } = require('internal/process/esm_loader'); - let reporter = await esmLoader.import(reporterSpecifier, parentURL, ObjectCreate(null)); + let reporter = await esmLoader.import(reporterSpecifier, parentURL, { __proto__: null }); if (reporter?.default) { reporter = reporter.default; diff --git a/lib/internal/timers.js b/lib/internal/timers.js index 0f8bdef9dfeb8b..dac5938eabd7df 100644 --- a/lib/internal/timers.js +++ b/lib/internal/timers.js @@ -77,7 +77,6 @@ const { MathTrunc, NumberIsFinite, NumberMIN_SAFE_INTEGER, - ObjectCreate, ReflectApply, Symbol, } = primordials; @@ -154,7 +153,7 @@ const timerListQueue = new PriorityQueue(compareTimersLists, setPosition); // // - key = time in milliseconds // - value = linked list -const timerListMap = ObjectCreate(null); +const timerListMap = { __proto__: null }; function initAsyncResource(resource, type) { const asyncId = resource[async_id_symbol] = newAsyncId(); diff --git a/lib/internal/util.js b/lib/internal/util.js index 0d769e061fe448..58f344f61e1c43 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -9,7 +9,6 @@ const { ArrayPrototypeSort, Error, FunctionPrototypeCall, - ObjectCreate, ObjectDefineProperties, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, @@ -289,7 +288,7 @@ function getSignalsToNamesMapping() { if (signalsToNamesMapping !== undefined) return signalsToNamesMapping; - signalsToNamesMapping = ObjectCreate(null); + signalsToNamesMapping = { __proto__: null }; for (const key in signals) { signalsToNamesMapping[signals[key]] = key; } @@ -610,14 +609,14 @@ const lazyDOMException = hideStackFrames((message, name) => { return new _DOMException(message, name); }); -const kEnumerableProperty = ObjectCreate(null); +const kEnumerableProperty = { __proto__: null }; kEnumerableProperty.enumerable = true; ObjectFreeze(kEnumerableProperty); -const kEmptyObject = ObjectFreeze(ObjectCreate(null)); +const kEmptyObject = ObjectFreeze({ __proto__: null }); function filterOwnProperties(source, keys) { - const filtered = ObjectCreate(null); + const filtered = { __proto__: null }; for (let i = 0; i < keys.length; i++) { const key = keys[i]; if (ObjectPrototypeHasOwnProperty(source, key)) { diff --git a/lib/internal/util/debuglog.js b/lib/internal/util/debuglog.js index de39457db2b47b..fdb5acca5a46f3 100644 --- a/lib/internal/util/debuglog.js +++ b/lib/internal/util/debuglog.js @@ -1,7 +1,6 @@ 'use strict'; const { - ObjectCreate, ObjectDefineProperty, RegExp, RegExpPrototypeExec, @@ -20,7 +19,7 @@ let testEnabled; // `debugEnv` is initial value of process.env.NODE_DEBUG function initializeDebugEnv(debugEnv) { - debugImpls = ObjectCreate(null); + debugImpls = { __proto__: null }; if (debugEnv) { // This is run before any user code, it's OK not to use primordials. debugEnv = debugEnv.replace(/[|\\{}()[\]^$+?.]/g, '\\$&') diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index abbb0d9c8ebc86..b03a2c0a66bdbf 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -43,7 +43,6 @@ const { NumberPrototypeValueOf, Object, ObjectAssign, - ObjectCreate, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, ObjectGetOwnPropertyNames, @@ -460,7 +459,7 @@ defineColorAlias('doubleunderline', 'doubleUnderline'); // TODO(BridgeAR): Add function style support for more complex styles. // Don't use 'blue' not visible on cmd.exe -inspect.styles = ObjectAssign(ObjectCreate(null), { +inspect.styles = ObjectAssign({ __proto__: null }, { special: 'cyan', number: 'yellow', bigint: 'yellow', diff --git a/lib/internal/webstreams/readablestream.js b/lib/internal/webstreams/readablestream.js index 5344785b90cd3e..d847288240c690 100644 --- a/lib/internal/webstreams/readablestream.js +++ b/lib/internal/webstreams/readablestream.js @@ -13,7 +13,6 @@ const { FunctionPrototypeCall, MathMin, NumberIsInteger, - ObjectCreate, ObjectDefineProperties, ObjectSetPrototypeOf, Promise, @@ -1199,11 +1198,7 @@ function createTeeReadableStream(start, pull, cancel) { }; setupReadableStreamDefaultControllerFromSource( this, - ObjectCreate(null, { - start: { __proto__: null, value: start }, - pull: { __proto__: null, value: pull }, - cancel: { __proto__: null, value: cancel } - }), + { __proto__: null }, 1, () => 1); return makeTransferable(this); diff --git a/lib/internal/worker.js b/lib/internal/worker.js index 3cc589c996703c..5351fd5d28afbc 100644 --- a/lib/internal/worker.js +++ b/lib/internal/worker.js @@ -8,7 +8,6 @@ const { FunctionPrototypeBind, JSONStringify, MathMax, - ObjectCreate, ObjectEntries, Promise, PromiseResolve, @@ -173,7 +172,7 @@ class Worker extends EventEmitter { let env; if (typeof options.env === 'object' && options.env !== null) { - env = ObjectCreate(null); + env = { __proto__: null }; ArrayPrototypeForEach( ObjectEntries(options.env), ({ 0: key, 1: value }) => { env[key] = `${value}`; } diff --git a/lib/net.js b/lib/net.js index 22ecc52ddf8fc7..6f821651d1ce29 100644 --- a/lib/net.js +++ b/lib/net.js @@ -34,7 +34,6 @@ const { ObjectDefineProperty, ObjectSetPrototypeOf, Symbol, - ObjectCreate, } = primordials; const EventEmitter = require('events'); @@ -1977,16 +1976,16 @@ function onconnection(err, clientHandle) { if (self.maxConnections && self._connections >= self.maxConnections) { if (clientHandle.getsockname || clientHandle.getpeername) { - const data = ObjectCreate(null); + const data = { __proto__: null }; if (clientHandle.getsockname) { - const localInfo = ObjectCreate(null); + const localInfo = { __proto__: null }; clientHandle.getsockname(localInfo); data.localAddress = localInfo.address; data.localPort = localInfo.port; data.localFamily = localInfo.family; } if (clientHandle.getpeername) { - const remoteInfo = ObjectCreate(null); + const remoteInfo = { __proto__: null }; clientHandle.getpeername(remoteInfo); data.remoteAddress = remoteInfo.address; data.remotePort = remoteInfo.port; diff --git a/lib/querystring.js b/lib/querystring.js index 9bcc9be6cc4851..a4f4f5ec77f413 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -29,7 +29,6 @@ const { Int8Array, MathAbs, NumberIsFinite, - ObjectCreate, ObjectKeys, String, StringPrototypeCharCodeAt, @@ -316,7 +315,7 @@ function addKeyVal(obj, key, value, keyEncoded, valEncoded, decode) { * @returns {Record} */ function parse(qs, sep, eq, options) { - const obj = ObjectCreate(null); + const obj = { __proto__: null }; if (typeof qs !== 'string' || qs.length === 0) { return obj; diff --git a/lib/repl.js b/lib/repl.js index 1db587bbba3b4e..40851e4dcd6fcf 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -66,7 +66,6 @@ const { NumberIsNaN, NumberParseFloat, ObjectAssign, - ObjectCreate, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, ObjectGetOwnPropertyNames, @@ -773,7 +772,7 @@ function REPLServer(prompt, self.resetContext(); - this.commands = ObjectCreate(null); + this.commands = { __proto__: null }; defineDefaultCommands(this); // Figure out which "writer" function to use diff --git a/lib/timers.js b/lib/timers.js index b2126d9711fc8e..4e3e0dc360f859 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -23,7 +23,6 @@ const { MathTrunc, - ObjectCreate, ObjectDefineProperty, SymbolToPrimitive } = primordials; @@ -72,7 +71,7 @@ const { // This stores all the known timer async ids to allow users to clearTimeout and // clearInterval using those ids, to match the spec and the rest of the web // platform. -const knownTimersById = ObjectCreate(null); +const knownTimersById = { __proto__: null }; // Remove a timer. Cancels the timeout and resets the relevant timer properties. function unenroll(item) { diff --git a/lib/url.js b/lib/url.js index b9ce18f3ba4ca3..6598aae2802796 100644 --- a/lib/url.js +++ b/lib/url.js @@ -23,7 +23,6 @@ const { Int8Array, - ObjectCreate, ObjectKeys, SafeSet, StringPrototypeCharCodeAt, @@ -267,7 +266,7 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { } } else if (parseQueryString) { this.search = null; - this.query = ObjectCreate(null); + this.query = { __proto__: null }; } return this; } @@ -477,7 +476,7 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { } else if (parseQueryString) { // No query string, but parseQueryString still requested this.search = null; - this.query = ObjectCreate(null); + this.query = { __proto__: null }; } const useQuestionIdx = diff --git a/tools/eslint-rules/prefer-proto.js b/tools/eslint-rules/prefer-proto.js new file mode 100644 index 00000000000000..fa7b06014a884c --- /dev/null +++ b/tools/eslint-rules/prefer-proto.js @@ -0,0 +1,33 @@ +/** + * @fileoverview null objects can be created with `ObjectCreate(null)`, or with + * syntax: `{ __proto__: null }`. This linter rule forces use of + * syntax over ObjectCreate. + * @author Jordan Harband + */ +'use strict'; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + fixable: 'code', + messages: { + error: 'Use `{ __proto__: null }` instead of `ObjectCreate(null)`.', + }, + }, + create(context) { + return { + 'CallExpression[callee.name="ObjectCreate"][arguments.0.type="Literal"][arguments.0.value=null]'(node) { + context.report({ + node, + messageId: 'error', + fix(fixer) { + return fixer.replaceText(node, '{ __proto__: null }'); + }, + }); + }, + }; + }, +};