From 87b2b448c5889a7b0144b3d3b512eec6ce8b1af6 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 9 Jan 2023 21:38:36 -0800 Subject: [PATCH] tools: add `prefer-proto` rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixup: add support for `Object.create(null)` fixup: extend to any 1-argument Object.create call fixup: add tests PR-URL: https://github.com/nodejs/node/pull/46083 Reviewed-By: Colin Ihrig Reviewed-By: Geoffrey Booth Reviewed-By: Yagiz Nizipli Reviewed-By: Mohammed Keyvanzadeh Reviewed-By: Darshan Sen Reviewed-By: Michaël Zasso Reviewed-By: Jacob Smith Reviewed-By: Antoine du Hamel --- .eslintrc.js | 1 + benchmark/es/map-bench.js | 4 +- doc/api/assert.md | 8 +-- 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/assert/assertion_error.js | 3 +- lib/internal/bootstrap/loaders.js | 5 +- lib/internal/cluster/round_robin_handle.js | 3 +- lib/internal/console/constructor.js | 3 +- lib/internal/console/global.js | 3 +- lib/internal/dns/utils.js | 3 +- lib/internal/encoding.js | 7 +- 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/repl.js | 3 +- lib/internal/source_map/source_map_cache.js | 3 +- lib/internal/timers.js | 3 +- lib/internal/url.js | 9 ++- lib/internal/util.js | 9 ++- lib/internal/util/debuglog.js | 3 +- lib/internal/util/inspect.js | 3 +- lib/internal/vm/module.js | 3 +- lib/internal/webstreams/util.js | 20 ++---- lib/internal/worker.js | 3 +- lib/internal/worker/io.js | 2 +- lib/net.js | 7 +- lib/querystring.js | 3 +- lib/repl.js | 3 +- lib/timers.js | 3 +- lib/url.js | 5 +- test/async-hooks/verify-graph.js | 2 +- test/js-native-api/test_object/test.js | 4 +- test/parallel/test-abortcontroller.js | 4 +- test/parallel/test-assert-deep.js | 2 +- test/parallel/test-blob.js | 2 +- test/parallel/test-buffer-from.js | 2 +- ...est-common-must-not-mutate-object-deep.mjs | 2 +- test/parallel/test-crypto-x509.js | 6 +- .../test-error-value-type-detection.mjs | 2 +- test/parallel/test-eslint-prefer-proto.js | 71 +++++++++++++++++++ .../test-event-emitter-emit-context.js | 2 +- test/parallel/test-fs-read-stream-inherit.js | 18 ++--- test/parallel/test-http-multiple-headers.js | 2 +- test/parallel/test-http-mutable-headers.js | 2 +- ...tp-outgoing-internal-headernames-getter.js | 2 +- ...est-http2-compat-serverresponse-headers.js | 2 +- test/parallel/test-http2-multiheaders-raw.js | 2 +- test/parallel/test-http2-multiheaders.js | 2 +- .../test-http2-request-response-proto.js | 4 +- .../parallel/test-http2-response-splitting.js | 2 +- test/parallel/test-http2-util-asserts.js | 2 +- test/parallel/test-http2-util-headers-list.js | 2 +- test/parallel/test-instanceof.js | 2 +- test/parallel/test-mime-api.js | 2 +- test/parallel/test-module-multi-extensions.js | 14 ++-- test/parallel/test-parse-args.mjs | 2 +- test/parallel/test-querystring.js | 2 +- test/parallel/test-tls-external-accessor.js | 4 +- .../test-tls-translate-peer-certificate.js | 4 +- test/parallel/test-trace-events-fs-async.js | 2 +- test/parallel/test-trace-events-fs-sync.js | 2 +- test/parallel/test-url-parse-query.js | 2 +- test/parallel/test-util-format.js | 4 +- test/parallel/test-util-inspect.js | 22 +++--- test/parallel/test-util-types.js | 26 +++---- test/parallel/test-util.js | 10 +-- test/parallel/test-vm-inherited_properties.js | 4 +- test/parallel/test-vm-module-basic.js | 2 +- test/parallel/test-x509-escaping.js | 4 +- test/pummel/test-stream-pipe-multi.js | 2 +- tools/doc/html.mjs | 6 +- tools/eslint-rules/prefer-proto.js | 53 ++++++++++++++ 86 files changed, 306 insertions(+), 229 deletions(-) create mode 100644 test/parallel/test-eslint-prefer-proto.js 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/benchmark/es/map-bench.js b/benchmark/es/map-bench.js index 7e5e8824bfecb5..c81cf57e5da66c 100644 --- a/benchmark/es/map-bench.js +++ b/benchmark/es/map-bench.js @@ -25,7 +25,7 @@ function runObject(n) { } function runNullProtoObject(n) { - const m = Object.create(null); + const m = { __proto__: null }; bench.start(); for (let i = 0; i < n; i++) { m[`i${i}`] = i; @@ -51,7 +51,7 @@ function runNullProtoLiteralObject(n) { } function StorageObject() {} -StorageObject.prototype = Object.create(null); +StorageObject.prototype = { __proto__: null }; function runStorageObject(n) { const m = new StorageObject(); diff --git a/doc/api/assert.md b/doc/api/assert.md index d90dd1577b7cd8..d40300cc3fdb1b 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -664,7 +664,7 @@ const obj3 = { b: 1, }, }; -const obj4 = Object.create(obj1); +const obj4 = { __proto__: obj1 }; assert.deepEqual(obj1, obj1); // OK @@ -699,7 +699,7 @@ const obj3 = { b: 1, }, }; -const obj4 = Object.create(obj1); +const obj4 = { __proto__: obj1 }; assert.deepEqual(obj1, obj1); // OK @@ -1623,7 +1623,7 @@ const obj3 = { b: 1, }, }; -const obj4 = Object.create(obj1); +const obj4 = { __proto__: obj1 }; assert.notDeepEqual(obj1, obj1); // AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } } @@ -1656,7 +1656,7 @@ const obj3 = { b: 1, }, }; -const obj4 = Object.create(obj1); +const obj4 = { __proto__: obj1 }; assert.notDeepEqual(obj1, obj1); // AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } } 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 84d7c83ac1e60b..1a3a4750bf90a6 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; @@ -764,7 +763,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 4cad911c6bc8e6..3d65432406c9ac 100644 --- a/lib/events.js +++ b/lib/events.js @@ -33,7 +33,6 @@ const { FunctionPrototypeBind, FunctionPrototypeCall, NumberIsNaN, - ObjectCreate, ObjectDefineProperty, ObjectDefineProperties, ObjectGetPrototypeOf, @@ -338,7 +337,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; } @@ -547,7 +546,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 @@ -685,7 +684,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) @@ -740,11 +739,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]; } @@ -758,7 +757,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/assert/assertion_error.js b/lib/internal/assert/assertion_error.js index 17e261bd4cb1ef..65d076b68c06b5 100644 --- a/lib/internal/assert/assertion_error.js +++ b/lib/internal/assert/assertion_error.js @@ -6,7 +6,6 @@ const { Error, ErrorCaptureStackTrace, MathMax, - ObjectCreate, ObjectDefineProperty, ObjectGetPrototypeOf, ObjectKeys, @@ -48,7 +47,7 @@ const kMaxShortLength = 12; function copyError(source) { const keys = ObjectKeys(source); - const target = ObjectCreate(ObjectGetPrototypeOf(source)); + const target = { __proto__: ObjectGetPrototypeOf(source) }; for (const key of keys) { target[key] = source[key]; } 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/console/global.js b/lib/internal/console/global.js index dd293b9f195fe9..10952859a0ebf2 100644 --- a/lib/internal/console/global.js +++ b/lib/internal/console/global.js @@ -14,7 +14,6 @@ const { FunctionPrototypeBind, - ObjectCreate, ReflectDefineProperty, ReflectGetOwnPropertyDescriptor, ReflectOwnKeys, @@ -24,7 +23,7 @@ const { Console } = require('internal/console/constructor'); -const globalConsole = ObjectCreate({}); +const globalConsole = { __proto__: {} }; // Since Console is not on the prototype chain of the global console, // the symbol properties on Console.prototype have to be looked up from 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/encoding.js b/lib/internal/encoding.js index e14a8c74918623..6222bcffece15e 100644 --- a/lib/internal/encoding.js +++ b/lib/internal/encoding.js @@ -5,7 +5,6 @@ const { Boolean, - ObjectCreate, ObjectDefineProperties, ObjectGetOwnPropertyDescriptors, ObjectSetPrototypeOf, @@ -350,9 +349,9 @@ class TextEncoder { if (typeof depth === 'number' && depth < 0) return this; const ctor = getConstructorOf(this); - const obj = ObjectCreate({ + const obj = { __proto__: { constructor: ctor === null ? TextEncoder : ctor - }); + } }; obj.encoding = this.encoding; // Lazy to avoid circular dependency return require('internal/util/inspect').inspect(obj, opts); @@ -571,7 +570,7 @@ const sharedProperties = ObjectGetOwnPropertyDescriptors({ if (typeof depth === 'number' && depth < 0) return this; const constructor = getConstructorOf(this) || TextDecoder; - const obj = ObjectCreate({ constructor }); + const obj = { __proto__: { constructor } }; obj.encoding = this.encoding; obj.fatal = this.fatal; obj.ignoreBOM = this.ignoreBOM; 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 9fb2f1b72a5e39..80b931ef70825c 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -38,7 +38,6 @@ const { Boolean, Error, JSONParse, - ObjectCreate, ObjectDefineProperty, ObjectFreeze, ObjectGetOwnPropertyDescriptor, @@ -146,7 +145,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; @@ -208,9 +207,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 9a422e8f70f1ce..0c29938673a46a 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -10,7 +10,6 @@ const { ArrayPrototypePush, FunctionPrototypeCall, ObjectAssign, - ObjectCreate, ObjectDefineProperty, ObjectSetPrototypeOf, RegExpPrototypeExec, @@ -785,7 +784,7 @@ class ESMLoader { async resolve( originalSpecifier, parentURL, - importAssertions = ObjectCreate(null), + importAssertions = { __proto__: null }, ) { const isMain = parentURL === undefined; 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/repl.js b/lib/internal/repl.js index 5eeb2e349031b2..491049ebfeb1e5 100644 --- a/lib/internal/repl.js +++ b/lib/internal/repl.js @@ -4,13 +4,12 @@ const { Number, NumberIsNaN, NumberParseInt, - ObjectCreate, } = primordials; const REPL = require('repl'); const { kStandaloneREPL } = require('internal/repl/utils'); -module.exports = ObjectCreate(REPL); +module.exports = { __proto__: REPL }; module.exports.createInternalRepl = createRepl; function createRepl(env, opts, cb) { 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/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/url.js b/lib/internal/url.js index 40b25f6890b5db..47d540f8f30840 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -10,7 +10,6 @@ const { FunctionPrototypeBind, Int8Array, Number, - ObjectCreate, ObjectDefineProperties, ObjectDefineProperty, ObjectGetOwnPropertySymbols, @@ -673,7 +672,7 @@ class URL { return this; const constructor = getConstructorOf(this) || URL; - const obj = ObjectCreate({ constructor }); + const obj = { __proto__: { constructor } }; obj.href = this.href; obj.origin = this.origin; @@ -1295,7 +1294,7 @@ function merge(out, start, mid, end, lBuffer, rBuffer) { // https://heycam.github.io/webidl/#dfn-default-iterator-object function createSearchParamsIterator(target, kind) { - const iterator = ObjectCreate(URLSearchParamsIteratorPrototype); + const iterator = { __proto__: URLSearchParamsIteratorPrototype }; iterator[context] = { target, kind, @@ -1305,7 +1304,7 @@ function createSearchParamsIterator(target, kind) { } // https://heycam.github.io/webidl/#dfn-iterator-prototype-object -const URLSearchParamsIteratorPrototype = ObjectCreate(IteratorPrototype); +const URLSearchParamsIteratorPrototype = { __proto__: IteratorPrototype }; defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParams Iterator', { next() { @@ -1585,7 +1584,7 @@ function constructUrl(flags, protocol, username, password, ctx.fragment = fragment; ctx.host = host; - const url = ObjectCreate(URL.prototype); + const url = { __proto__: URL.prototype }; url[context] = ctx; const params = new URLSearchParams(); url[searchParams] = params; 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/vm/module.js b/lib/internal/vm/module.js index 91d489fc4c7cdd..e36b729e1a19ea 100644 --- a/lib/internal/vm/module.js +++ b/lib/internal/vm/module.js @@ -6,7 +6,6 @@ const { ArrayPrototypeForEach, ArrayPrototypeIndexOf, ArrayPrototypeSome, - ObjectCreate, ObjectDefineProperty, ObjectGetPrototypeOf, ObjectSetPrototypeOf, @@ -234,7 +233,7 @@ class Module { return this; const constructor = getConstructorOf(this) || Module; - const o = ObjectCreate({ constructor }); + const o = { __proto__: { constructor } }; o.status = this.status; o.identifier = this.identifier; o.context = this.context; diff --git a/lib/internal/webstreams/util.js b/lib/internal/webstreams/util.js index fe1202ec00bce3..a7273833d1f180 100644 --- a/lib/internal/webstreams/util.js +++ b/lib/internal/webstreams/util.js @@ -8,7 +8,6 @@ const { FunctionPrototypeCall, MathMax, NumberIsNaN, - ObjectCreate, PromisePrototypeThen, PromiseResolve, PromiseReject, @@ -54,20 +53,11 @@ const { const kState = Symbol('kState'); const kType = Symbol('kType'); -const AsyncIterator = ObjectCreate(AsyncIteratorPrototype, { - next: { - __proto__: null, - configurable: true, - enumerable: true, - writable: true, - }, - return: { - __proto__: null, - configurable: true, - enumerable: true, - writable: true, - }, -}); +const AsyncIterator = { + __proto__: AsyncIteratorPrototype, + next: undefined, + return: undefined, +}; function extractHighWaterMark(value, defaultHWM) { if (value === undefined) return defaultHWM; 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/internal/worker/io.js b/lib/internal/worker/io.js index 61f9a5363716a8..94722ac81edcbd 100644 --- a/lib/internal/worker/io.js +++ b/lib/internal/worker/io.js @@ -278,7 +278,7 @@ ObjectDefineProperty(MessagePort.prototype, inspect.custom, { // e.g. when accessing the prototype directly. ref = FunctionPrototypeCall(MessagePortPrototype.hasRef, this); } catch { return this; } - return ObjectAssign(ObjectCreate(MessagePort.prototype), + return ObjectAssign({ __proto__: MessagePort.prototype }, ref === undefined ? { active: false, } : { 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 4d7374a8e3f358..b1c6fe16d7c97d 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/test/async-hooks/verify-graph.js b/test/async-hooks/verify-graph.js index 61d1849f21ef48..bb55f61867fdf6 100644 --- a/test/async-hooks/verify-graph.js +++ b/test/async-hooks/verify-graph.js @@ -100,7 +100,7 @@ module.exports = function verifyGraph(hooks, graph) { assert.strictEqual(errors.length, 0); // Verify that all expected types are present (but more/others are allowed) - const expTypes = Object.create(null); + const expTypes = { __proto__: null }; for (let i = 0; i < graph.length; i++) { if (expTypes[graph[i].type] == null) expTypes[graph[i].type] = 0; expTypes[graph[i].type]++; diff --git a/test/js-native-api/test_object/test.js b/test/js-native-api/test_object/test.js index d5b9ab8423b7a5..74d73482943cfa 100644 --- a/test/js-native-api/test_object/test.js +++ b/test/js-native-api/test_object/test.js @@ -235,9 +235,9 @@ assert.strictEqual(newObject.test_string, 'test string'); // i.e.: includes prototypes, only enumerable properties, skips symbols, // and includes indices and converts them to strings. - const object = Object.create({ + const object = { __proto__: { inherited: 1 - }); + } }; const fooSymbol = Symbol('foo'); diff --git a/test/parallel/test-abortcontroller.js b/test/parallel/test-abortcontroller.js index c32edcd72c5c6c..097d632afa7d1c 100644 --- a/test/parallel/test-abortcontroller.js +++ b/test/parallel/test-abortcontroller.js @@ -103,7 +103,7 @@ const { setTimeout: sleep } = require('timers/promises'); NaN, true, 'AbortController', - Object.create(AbortController.prototype), + { __proto__: AbortController.prototype }, ]; for (const badController of badAbortControllers) { throws( @@ -134,7 +134,7 @@ const { setTimeout: sleep } = require('timers/promises'); NaN, true, 'AbortSignal', - Object.create(AbortSignal.prototype), + { __proto__: AbortSignal.prototype }, ]; for (const badSignal of badAbortSignals) { throws( diff --git a/test/parallel/test-assert-deep.js b/test/parallel/test-assert-deep.js index a52fee3b7b0914..013c7985f51d2a 100644 --- a/test/parallel/test-assert-deep.js +++ b/test/parallel/test-assert-deep.js @@ -1190,7 +1190,7 @@ assert.throws( }); assertNotDeepOrStrict(a, b); - a = Object.create(null); + a = { __proto__: null }; b = new RangeError('abc'); Object.defineProperty(a, Symbol.toStringTag, { value: 'Error' diff --git a/test/parallel/test-blob.js b/test/parallel/test-blob.js index 588fc0bfff0d49..9ffa31ccdd56e3 100644 --- a/test/parallel/test-blob.js +++ b/test/parallel/test-blob.js @@ -290,7 +290,7 @@ assert.throws(() => new Blob({}), { { // Testing the defaults - [undefined, null, Object.create(null), { type: undefined }, { + [undefined, null, { __proto__: null }, { type: undefined }, { get type() {}, // eslint-disable-line getter-return }].forEach((options) => { assert.strictEqual( diff --git a/test/parallel/test-buffer-from.js b/test/parallel/test-buffer-from.js index b513f4080a2054..04f52b3f325637 100644 --- a/test/parallel/test-buffer-from.js +++ b/test/parallel/test-buffer-from.js @@ -40,7 +40,7 @@ deepStrictEqual( { valueOf() { return null; } }, { valueOf() { return undefined; } }, { valueOf: null }, - Object.create(null), + { __proto__: null }, new Number(true), new MyBadPrimitive(), Symbol(), diff --git a/test/parallel/test-common-must-not-mutate-object-deep.mjs b/test/parallel/test-common-must-not-mutate-object-deep.mjs index 535406ade38985..926a03870562d0 100644 --- a/test/parallel/test-common-must-not-mutate-object-deep.mjs +++ b/test/parallel/test-common-must-not-mutate-object-deep.mjs @@ -192,7 +192,7 @@ function setPrototypeOfQuux(root) { // Test various supported types, directly and nested: [ undefined, null, false, true, 42, 42n, Symbol('42'), NaN, Infinity, {}, [], - () => {}, async () => {}, Promise.resolve(), Math, Object.create(null), + () => {}, async () => {}, Promise.resolve(), Math, { __proto__: null }, ].forEach((target) => { assert.deepStrictEqual(mustNotMutateObjectDeep(target), target); assert.deepStrictEqual(mustNotMutateObjectDeep({ target }), { target }); diff --git a/test/parallel/test-crypto-x509.js b/test/parallel/test-crypto-x509.js index 6d92e97115fd53..cc02f40c75ba6e 100644 --- a/test/parallel/test-crypto-x509.js +++ b/test/parallel/test-crypto-x509.js @@ -211,7 +211,7 @@ const der = Buffer.from( // Verify that legacy encoding works const legacyObjectCheck = { - subject: Object.assign(Object.create(null), { + subject: Object.assign({ __proto__: null }, { C: 'US', ST: 'CA', L: 'SF', @@ -220,7 +220,7 @@ const der = Buffer.from( CN: 'agent1', emailAddress: 'ry@tinyclouds.org', }), - issuer: Object.assign(Object.create(null), { + issuer: Object.assign({ __proto__: null }, { C: 'US', ST: 'CA', L: 'SF', @@ -229,7 +229,7 @@ const der = Buffer.from( CN: 'ca1', emailAddress: 'ry@tinyclouds.org', }), - infoAccess: Object.assign(Object.create(null), { + infoAccess: Object.assign({ __proto__: null }, { 'OCSP - URI': ['http://ocsp.nodejs.org/'], 'CA Issuers - URI': ['http://ca.nodejs.org/ca.cert'] }), diff --git a/test/parallel/test-error-value-type-detection.mjs b/test/parallel/test-error-value-type-detection.mjs index 75e6493a9bbd09..b0e418ab5129ab 100644 --- a/test/parallel/test-error-value-type-detection.mjs +++ b/test/parallel/test-error-value-type-detection.mjs @@ -33,7 +33,7 @@ strictEqual( ); strictEqual( - determineSpecificType(Object.create(null)), + determineSpecificType({ __proto__: null }), '[Object: null prototype] {}', ); diff --git a/test/parallel/test-eslint-prefer-proto.js b/test/parallel/test-eslint-prefer-proto.js new file mode 100644 index 00000000000000..fbcf08fbd73e43 --- /dev/null +++ b/test/parallel/test-eslint-prefer-proto.js @@ -0,0 +1,71 @@ +'use strict'; + +const common = require('../common'); +if ((!common.hasCrypto) || (!common.hasIntl)) { + common.skip('ESLint tests require crypto and Intl'); +} + +common.skipIfEslintMissing(); + +const RuleTester = require('../../tools/node_modules/eslint').RuleTester; +const rule = require('../../tools/eslint-rules/prefer-proto'); + +new RuleTester({ + parserOptions: { ecmaVersion: 2022 } +}).run('prefer-common-mustsucceed', rule, { + valid: [ + '({ __proto__: null })', + 'const x = { __proto__: null };', + ` + class X { + field = { __proto__: null }; + + constructor() { + this.x = { __proto__: X }; + } + } + `, + 'foo({ __proto__: Array.prototype })', + '({ "__proto__": null })', + "({ '__proto__': null })", + 'ObjectCreate(null, undefined)', + 'Object.create(null, undefined)', + 'Object.create(null, undefined, undefined)', + 'ObjectCreate(null, descriptors)', + 'Object.create(null, descriptors)', + 'ObjectCreate(Foo.prototype, descriptors)', + 'Object.create(Foo.prototype, descriptors)', + ], + invalid: [ + { + code: 'ObjectCreate(null)', + output: '{ __proto__: null }', + errors: [{ messageId: 'error', data: { value: 'null' } }], + }, + { + code: 'Object.create(null)', + output: '{ __proto__: null }', + errors: [{ messageId: 'error', data: { value: 'null' } }], + }, + { + code: 'ObjectCreate(null,)', + output: '{ __proto__: null }', + errors: [{ messageId: 'error', data: { value: 'null' } }], + }, + { + code: 'Object.create(null,)', + output: '{ __proto__: null }', + errors: [{ messageId: 'error', data: { value: 'null' } }], + }, + { + code: 'ObjectCreate(Foo)', + output: '{ __proto__: Foo }', + errors: [{ messageId: 'error', data: { value: 'Foo' } }], + }, + { + code: 'Object.create(Foo)', + output: '{ __proto__: Foo }', + errors: [{ messageId: 'error', data: { value: 'Foo' } }], + }, + ] +}); diff --git a/test/parallel/test-event-emitter-emit-context.js b/test/parallel/test-event-emitter-emit-context.js index 82e4b595185a59..e4c73cadc559ba 100644 --- a/test/parallel/test-event-emitter-emit-context.js +++ b/test/parallel/test-event-emitter-emit-context.js @@ -8,7 +8,7 @@ const EE = new EventEmitter(); // Works as expected if the context has no `constructor.name` { - const ctx = Object.create(null); + const ctx = { __proto__: null }; assert.throws( () => EE.emit.call(ctx, 'error', new Error('foo')), common.expectsError({ name: 'Error', message: 'foo' }) diff --git a/test/parallel/test-fs-read-stream-inherit.js b/test/parallel/test-fs-read-stream-inherit.js index 46a22281abfb42..ec090465d4d97e 100644 --- a/test/parallel/test-fs-read-stream-inherit.js +++ b/test/parallel/test-fs-read-stream-inherit.js @@ -50,7 +50,7 @@ const rangeFile = fixtures.path('x.txt'); } { - const file = fs.createReadStream(fn, Object.create({ encoding: 'utf8' })); + const file = fs.createReadStream(fn, { __proto__: { encoding: 'utf8' } }); file.length = 0; file.on('data', function(data) { assert.strictEqual(typeof data, 'string'); @@ -68,7 +68,7 @@ const rangeFile = fixtures.path('x.txt'); } { - const options = Object.create({ bufferSize: 1, start: 1, end: 2 }); + const options = { __proto__: { bufferSize: 1, start: 1, end: 2 } }; const file = fs.createReadStream(rangeFile, options); assert.strictEqual(file.start, 1); assert.strictEqual(file.end, 2); @@ -82,7 +82,7 @@ const rangeFile = fixtures.path('x.txt'); } { - const options = Object.create({ bufferSize: 1, start: 1 }); + const options = { __proto__: { bufferSize: 1, start: 1 } }; const file = fs.createReadStream(rangeFile, options); assert.strictEqual(file.start, 1); file.data = ''; @@ -96,7 +96,7 @@ const rangeFile = fixtures.path('x.txt'); // https://github.com/joyent/node/issues/2320 { - const options = Object.create({ bufferSize: 1.23, start: 1 }); + const options = { __proto__: { bufferSize: 1.23, start: 1 } }; const file = fs.createReadStream(rangeFile, options); assert.strictEqual(file.start, 1); file.data = ''; @@ -115,7 +115,7 @@ const rangeFile = fixtures.path('x.txt'); assert.throws( () => { - fs.createReadStream(rangeFile, Object.create({ start: 10, end: 2 })); + fs.createReadStream(rangeFile, { __proto__: { start: 10, end: 2 } }); }, { code: 'ERR_OUT_OF_RANGE', @@ -125,7 +125,7 @@ const rangeFile = fixtures.path('x.txt'); } { - const options = Object.create({ start: 0, end: 0 }); + const options = { __proto__: { start: 0, end: 0 } }; const stream = fs.createReadStream(rangeFile, options); assert.strictEqual(stream.start, 0); assert.strictEqual(stream.end, 0); @@ -150,7 +150,7 @@ const rangeFile = fixtures.path('x.txt'); { let data = ''; let file = - fs.createReadStream(rangeFile, Object.create({ autoClose: false })); + fs.createReadStream(rangeFile, { __proto__: { autoClose: false } }); assert.strictEqual(file.autoClose, false); file.on('data', (chunk) => { data += chunk; }); file.on('end', common.mustCall(function() { @@ -164,7 +164,7 @@ const rangeFile = fixtures.path('x.txt'); function fileNext() { // This will tell us if the fd is usable again or not. - file = fs.createReadStream(null, Object.create({ fd: file.fd, start: 0 })); + file = fs.createReadStream(null, { __proto__: { fd: file.fd, start: 0 } }); file.data = ''; file.on('data', function(data) { file.data += data; @@ -181,7 +181,7 @@ const rangeFile = fixtures.path('x.txt'); // Just to make sure autoClose won't close the stream because of error. { - const options = Object.create({ fd: 13337, autoClose: false }); + const options = { __proto__: { fd: 13337, autoClose: false } }; const file = fs.createReadStream(null, options); file.on('data', common.mustNotCall()); file.on('error', common.mustCall()); diff --git a/test/parallel/test-http-multiple-headers.js b/test/parallel/test-http-multiple-headers.js index 1ebd290a614b1b..8f52f817273c52 100644 --- a/test/parallel/test-http-multiple-headers.js +++ b/test/parallel/test-http-multiple-headers.js @@ -81,7 +81,7 @@ const server = createServer( ['X-Res-a', 'X-Res-b', 'Connection', 'x-res-c', 'x-res-d'] ); - const headers = Object.create(null); + const headers = { __proto__: null }; Object.assign(headers, { 'x-res-a': [ 'AAA', 'BBB', 'CCC' ], 'x-res-b': [ 'DDD', 'EEE', 'FFF', 'GGG' ], diff --git a/test/parallel/test-http-mutable-headers.js b/test/parallel/test-http-mutable-headers.js index 9b31dd44dda0ef..dc01d9ff9b284b 100644 --- a/test/parallel/test-http-mutable-headers.js +++ b/test/parallel/test-http-mutable-headers.js @@ -44,7 +44,7 @@ const s = http.createServer(common.mustCall((req, res) => { case 'headers': { // Check that header-related functions work before setting any headers const headers = res.getHeaders(); - const exoticObj = Object.create(null); + const exoticObj = { __proto__: null }; assert.deepStrictEqual(headers, exoticObj); assert.deepStrictEqual(res.getHeaderNames(), []); assert.deepStrictEqual(res.getRawHeaderNames(), []); diff --git a/test/parallel/test-http-outgoing-internal-headernames-getter.js b/test/parallel/test-http-outgoing-internal-headernames-getter.js index 2d8238066e0cd4..15c3f299eb25c2 100644 --- a/test/parallel/test-http-outgoing-internal-headernames-getter.js +++ b/test/parallel/test-http-outgoing-internal-headernames-getter.js @@ -17,7 +17,7 @@ common.expectWarning('DeprecationWarning', warn, 'DEP0066'); // Tests _headerNames getter result after setting a header. const outgoingMessage = new OutgoingMessage(); outgoingMessage.setHeader('key', 'value'); - const expect = Object.create(null); + const expect = { __proto__: null }; expect.key = 'key'; assert.deepStrictEqual(outgoingMessage._headerNames, expect); } diff --git a/test/parallel/test-http2-compat-serverresponse-headers.js b/test/parallel/test-http2-compat-serverresponse-headers.js index 8b9b6d69278c60..6065a9f8f28e16 100644 --- a/test/parallel/test-http2-compat-serverresponse-headers.js +++ b/test/parallel/test-http2-compat-serverresponse-headers.js @@ -102,7 +102,7 @@ server.listen(0, common.mustCall(function() { response.setHeader(real, expectedValue); const expectedHeaderNames = [real]; assert.deepStrictEqual(response.getHeaderNames(), expectedHeaderNames); - const expectedHeaders = Object.create(null); + const expectedHeaders = { __proto__: null }; expectedHeaders[real] = expectedValue; assert.deepStrictEqual(response.getHeaders(), expectedHeaders); diff --git a/test/parallel/test-http2-multiheaders-raw.js b/test/parallel/test-http2-multiheaders-raw.js index 9bd48a9528eab3..71277353dc84a8 100644 --- a/test/parallel/test-http2-multiheaders-raw.js +++ b/test/parallel/test-http2-multiheaders-raw.js @@ -8,7 +8,7 @@ const http2 = require('http2'); const server = http2.createServer(); -const src = Object.create(null); +const src = { __proto__: null }; src['www-authenticate'] = 'foo'; src['WWW-Authenticate'] = 'bar'; src['WWW-AUTHENTICATE'] = 'baz'; diff --git a/test/parallel/test-http2-multiheaders.js b/test/parallel/test-http2-multiheaders.js index 8171df52507350..379a5d6003a771 100644 --- a/test/parallel/test-http2-multiheaders.js +++ b/test/parallel/test-http2-multiheaders.js @@ -8,7 +8,7 @@ const http2 = require('http2'); const server = http2.createServer(); -const src = Object.create(null); +const src = { __proto__: null }; src.accept = [ 'abc', 'def' ]; src.Accept = 'ghijklmnop'; src['www-authenticate'] = 'foo'; diff --git a/test/parallel/test-http2-request-response-proto.js b/test/parallel/test-http2-request-response-proto.js index 9f84f9f475a1a2..49b15dfc703372 100644 --- a/test/parallel/test-http2-request-response-proto.js +++ b/test/parallel/test-http2-request-response-proto.js @@ -11,8 +11,8 @@ const { Http2ServerResponse, } = http2; -const protoRequest = Object.create(Http2ServerRequest.prototype); -const protoResponse = Object.create(Http2ServerResponse.prototype); +const protoRequest = { __proto__: Http2ServerRequest.prototype }; +const protoResponse = { __proto__: Http2ServerResponse.prototype }; assert.strictEqual(protoRequest instanceof Http2ServerRequest, true); assert.strictEqual(protoResponse instanceof Http2ServerResponse, true); diff --git a/test/parallel/test-http2-response-splitting.js b/test/parallel/test-http2-response-splitting.js index 791c3d74c21213..f91026704b3d97 100644 --- a/test/parallel/test-http2-response-splitting.js +++ b/test/parallel/test-http2-response-splitting.js @@ -30,7 +30,7 @@ function makeUrl(headers) { const server = http2.createServer(); server.on('stream', common.mustCall((stream, headers) => { - const obj = Object.create(null); + const obj = { __proto__: null }; switch (remaining--) { case 3: { const url = new URL(makeUrl(headers)); diff --git a/test/parallel/test-http2-util-asserts.js b/test/parallel/test-http2-util-asserts.js index 29ba8180494a3c..10caa61fd06795 100644 --- a/test/parallel/test-http2-util-asserts.js +++ b/test/parallel/test-http2-util-asserts.js @@ -11,7 +11,7 @@ const { [ undefined, {}, - Object.create(null), + { __proto__: null }, new Date(), new (class Foo {})(), ].forEach((input) => { diff --git a/test/parallel/test-http2-util-headers-list.js b/test/parallel/test-http2-util-headers-list.js index 322323960e545d..f4221f5c17e589 100644 --- a/test/parallel/test-http2-util-headers-list.js +++ b/test/parallel/test-http2-util-headers-list.js @@ -149,7 +149,7 @@ const { { // Only own properties are used const base = { 'abc': 1 }; - const headers = Object.create(base); + const headers = { __proto__: base }; headers[':status'] = 200; headers.xyz = [1, 2, 3, 4]; headers.foo = []; diff --git a/test/parallel/test-instanceof.js b/test/parallel/test-instanceof.js index 658f1e29c7a60f..5a8b588e7d0bef 100644 --- a/test/parallel/test-instanceof.js +++ b/test/parallel/test-instanceof.js @@ -8,4 +8,4 @@ const assert = require('assert'); // https://github.com/nodejs/node/issues/7592 const F = () => {}; F.prototype = {}; -assert(Object.create(F.prototype) instanceof F); +assert({ __proto__: F.prototype } instanceof F); diff --git a/test/parallel/test-mime-api.js b/test/parallel/test-mime-api.js index 56f8795c4b90fe..0510ddaed20267 100644 --- a/test/parallel/test-mime-api.js +++ b/test/parallel/test-mime-api.js @@ -12,7 +12,7 @@ const NOT_HTTP_QUOTED_STRING_CODE_POINT = '\n'; const mime = new MIMEType('application/ecmascript; '); const mime_descriptors = Object.getOwnPropertyDescriptors(mime); const mime_proto = Object.getPrototypeOf(mime); -const mime_impersonator = Object.create(mime_proto); +const mime_impersonator = { __proto__: mime_proto }; for (const key of Object.keys(mime_descriptors)) { const descriptor = mime_descriptors[key]; if (descriptor.get) { diff --git a/test/parallel/test-module-multi-extensions.js b/test/parallel/test-module-multi-extensions.js index 1257854115a5b5..01789a6c496fd4 100644 --- a/test/parallel/test-module-multi-extensions.js +++ b/test/parallel/test-module-multi-extensions.js @@ -26,7 +26,7 @@ fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); delete require.cache[file]; delete require.extensions['.bar']; delete require.extensions['.foo.bar']; - Module._pathCache = Object.create(null); + Module._pathCache = { __proto__: null }; } { @@ -40,7 +40,7 @@ fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); require(`${modulePath}.foo.bar`); delete require.cache[file]; delete require.extensions['.foo.bar']; - Module._pathCache = Object.create(null); + Module._pathCache = { __proto__: null }; } { @@ -50,7 +50,7 @@ fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); (err) => err.message.startsWith(`Cannot find module '${modulePath}'`) ); delete require.cache[file]; - Module._pathCache = Object.create(null); + Module._pathCache = { __proto__: null }; } { @@ -61,7 +61,7 @@ fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); delete require.cache[file]; delete require.extensions['.bar']; delete require.extensions['.foo.bar']; - Module._pathCache = Object.create(null); + Module._pathCache = { __proto__: null }; } { @@ -72,7 +72,7 @@ fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); (err) => err.message.startsWith(`Cannot find module '${modulePath}'`) ); delete require.extensions['.foo.bar']; - Module._pathCache = Object.create(null); + Module._pathCache = { __proto__: null }; } { @@ -80,7 +80,7 @@ fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); require(dotfile); delete require.cache[dotfile]; delete require.extensions['.bar']; - Module._pathCache = Object.create(null); + Module._pathCache = { __proto__: null }; } { @@ -90,5 +90,5 @@ fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); delete require.cache[dotfileWithExtension]; delete require.extensions['.bar']; delete require.extensions['.foo.bar']; - Module._pathCache = Object.create(null); + Module._pathCache = { __proto__: null }; } diff --git a/test/parallel/test-parse-args.mjs b/test/parallel/test-parse-args.mjs index ae39869cd36101..98c162643e64ff 100644 --- a/test/parallel/test-parse-args.mjs +++ b/test/parallel/test-parse-args.mjs @@ -973,7 +973,7 @@ test('tokens:true should not include the default options after the args input', test('proto as default value must be ignored', () => { const args = []; - const options = Object.create(null); + const options = { __proto__: null }; // eslint-disable-next-line no-proto options.__proto__ = { type: 'string', default: 'HELLO' }; diff --git a/test/parallel/test-querystring.js b/test/parallel/test-querystring.js index eda94bf8df9164..b24ec5b569bd03 100644 --- a/test/parallel/test-querystring.js +++ b/test/parallel/test-querystring.js @@ -28,7 +28,7 @@ const inspect = require('util').inspect; const qs = require('querystring'); function createWithNoPrototype(properties) { - const noProto = Object.create(null); + const noProto = { __proto__: null }; properties.forEach((property) => { noProto[property.key] = property.value; }); diff --git a/test/parallel/test-tls-external-accessor.js b/test/parallel/test-tls-external-accessor.js index 07d79ef64a5167..ea138d8dc4e968 100644 --- a/test/parallel/test-tls-external-accessor.js +++ b/test/parallel/test-tls-external-accessor.js @@ -10,13 +10,13 @@ const tls = require('tls'); // Ensure accessing ._external doesn't hit an assert in the accessor method. { const pctx = tls.createSecureContext().context; - const cctx = Object.create(pctx); + const cctx = { __proto__: pctx }; assert.throws(() => cctx._external, TypeError); pctx._external; // eslint-disable-line no-unused-expressions } { const pctx = tls.createSecurePair().credentials.context; - const cctx = Object.create(pctx); + const cctx = { __proto__: pctx }; assert.throws(() => cctx._external, TypeError); pctx._external; // eslint-disable-line no-unused-expressions } diff --git a/test/parallel/test-tls-translate-peer-certificate.js b/test/parallel/test-tls-translate-peer-certificate.js index a14308ab87b762..de11567b138b15 100644 --- a/test/parallel/test-tls-translate-peer-certificate.js +++ b/test/parallel/test-tls-translate-peer-certificate.js @@ -53,7 +53,7 @@ deepStrictEqual( } deepStrictEqual(translatePeerCertificate({ infoAccess: '' }), - { infoAccess: Object.create(null) }); + { infoAccess: { __proto__: null } }); deepStrictEqual(translatePeerCertificate({ infoAccess: null }), { infoAccess: null }); { @@ -61,7 +61,7 @@ deepStrictEqual(translatePeerCertificate({ infoAccess: null }), '__proto__:mostly harmless\n' + 'hasOwnProperty:not a function\n' + 'OCSP - URI:file:///etc/passwd\n'; - const expected = Object.create(null); + const expected = { __proto__: null }; expected.__proto__ = ['mostly harmless']; expected.hasOwnProperty = ['not a function']; expected['OCSP - URI'] = ['file:///etc/passwd']; diff --git a/test/parallel/test-trace-events-fs-async.js b/test/parallel/test-trace-events-fs-async.js index 693214832a9167..469da286a34d3b 100644 --- a/test/parallel/test-trace-events-fs-async.js +++ b/test/parallel/test-trace-events-fs-async.js @@ -6,7 +6,7 @@ const fs = require('fs'); const path = require('path'); const util = require('util'); -const tests = Object.create(null); +const tests = { __proto__: null }; let gid = 1; let uid = 1; diff --git a/test/parallel/test-trace-events-fs-sync.js b/test/parallel/test-trace-events-fs-sync.js index 14c6a122dd299f..d945e7f38239e6 100644 --- a/test/parallel/test-trace-events-fs-sync.js +++ b/test/parallel/test-trace-events-fs-sync.js @@ -6,7 +6,7 @@ const fs = require('fs'); const path = require('path'); const util = require('util'); -const tests = Object.create(null); +const tests = { __proto__: null }; let gid = 1; let uid = 1; diff --git a/test/parallel/test-url-parse-query.js b/test/parallel/test-url-parse-query.js index f9174d599ad01b..ac05ed10aa7a54 100644 --- a/test/parallel/test-url-parse-query.js +++ b/test/parallel/test-url-parse-query.js @@ -4,7 +4,7 @@ const assert = require('assert'); const url = require('url'); function createWithNoPrototype(properties = []) { - const noProto = Object.create(null); + const noProto = { __proto__: null }; properties.forEach((property) => { noProto[property.key] = property.value; }); diff --git a/test/parallel/test-util-format.js b/test/parallel/test-util-format.js index ab0d50f743fd98..12e7833bb24457 100644 --- a/test/parallel/test-util-format.js +++ b/test/parallel/test-util-format.js @@ -219,7 +219,7 @@ assert.strictEqual(util.format('%s', -Infinity), '-Infinity'); function D() { C.call(this); } - D.prototype = Object.create(C.prototype); + D.prototype = { __proto__: C.prototype }; assert.strictEqual( util.format('%s', new B()), @@ -264,7 +264,7 @@ assert.strictEqual(util.format('%s', -Infinity), '-Infinity'); ); assert.strictEqual( - util.format('%s', Object.create(null)), + util.format('%s', { __proto__: null }), '[Object: null prototype] {}' ); } diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 2e0d726d3dcecb..4c9e0d683fe7d0 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -100,7 +100,7 @@ assert.strictEqual( `"${Array(75).fill(1)}'\\n" +\n '\\x1D\\n' +\n '\\x03\\x85\\x7F~\\x9F '` ); assert.strictEqual(util.inspect([]), '[]'); -assert.strictEqual(util.inspect(Object.create([])), 'Array {}'); +assert.strictEqual(util.inspect({ __proto__: [] }), 'Array {}'); assert.strictEqual(util.inspect([1, 2]), '[ 1, 2 ]'); assert.strictEqual(util.inspect([1, [2, 3]]), '[ 1, [ 2, 3 ] ]'); assert.strictEqual(util.inspect({}), '{}'); @@ -796,7 +796,7 @@ assert.strictEqual(util.inspect(-5e-324), '-5e-324'); }); // https://github.com/nodejs/node-v0.x-archive/issues/1941 -assert.strictEqual(util.inspect(Object.create(Date.prototype)), 'Date {}'); +assert.strictEqual(util.inspect({ __proto__: Date.prototype }), 'Date {}'); // https://github.com/nodejs/node-v0.x-archive/issues/1944 { @@ -1467,7 +1467,7 @@ if (typeof Symbol !== 'undefined') { } { - const x = Object.create(null); + const x = { __proto__: null }; assert.strictEqual(util.inspect(x), '[Object: null prototype] {}'); } @@ -1631,7 +1631,7 @@ util.inspect(process); "Foo [bar] { foo: 'bar' }"); assert.strictEqual( - util.inspect(Object.create(Object.create(Foo.prototype), { + util.inspect(Object.create({ __proto__: Foo.prototype }, { foo: { value: 'bar', enumerable: true } })), "Foo [bar] { foo: 'bar' }"); @@ -2396,7 +2396,7 @@ assert.strictEqual( ); function StorageObject() {} - StorageObject.prototype = Object.create(null); + StorageObject.prototype = { __proto__: null }; assert.strictEqual( util.inspect(new StorageObject()), 'StorageObject <[Object: null prototype] {}> {}' @@ -2406,17 +2406,17 @@ assert.strictEqual( Object.setPrototypeOf(obj, Number.prototype); assert.strictEqual(inspect(obj), "Number { '0': 1, '1': 2, '2': 3 }"); - Object.setPrototypeOf(obj, Object.create(null)); + Object.setPrototypeOf(obj, { __proto__: null }); assert.strictEqual( inspect(obj), "Array <[Object: null prototype] {}> { '0': 1, '1': 2, '2': 3 }" ); - StorageObject.prototype = Object.create(null); - Object.setPrototypeOf(StorageObject.prototype, Object.create(null)); + StorageObject.prototype = { __proto__: null }; + Object.setPrototypeOf(StorageObject.prototype, { __proto__: null }); Object.setPrototypeOf( Object.getPrototypeOf(StorageObject.prototype), - Object.create(null) + { __proto__: null } ); assert.strictEqual( util.inspect(new StorageObject()), @@ -2991,7 +2991,7 @@ assert.strictEqual( '}' ); - const obj = Object.create({ abc: true, def: 5, toString() {} }); + const obj = { __proto__: { abc: true, def: 5, toString() {} } }; assert.strictEqual( inspect(obj, { showHidden: true, colors: true }), '{ \x1B[2mabc: \x1B[33mtrue\x1B[39m\x1B[22m, ' + @@ -3107,7 +3107,7 @@ assert.strictEqual( return this.stylized; } }) - `, Object.create(null)); + `, { __proto__: null }); assert.strictEqual(target.ctx, undefined); { diff --git a/test/parallel/test-util-types.js b/test/parallel/test-util-types.js index 60380dca09a298..f8cafa531c98a1 100644 --- a/test/parallel/test-util-types.js +++ b/test/parallel/test-util-types.js @@ -132,19 +132,19 @@ for (const [ value, _method ] of [ const bigInt64Array = new BigInt64Array(arrayBuffer); const bigUint64Array = new BigUint64Array(arrayBuffer); - const fakeBuffer = Object.create(Buffer.prototype); - const fakeDataView = Object.create(DataView.prototype); - const fakeUint8Array = Object.create(Uint8Array.prototype); - const fakeUint8ClampedArray = Object.create(Uint8ClampedArray.prototype); - const fakeUint16Array = Object.create(Uint16Array.prototype); - const fakeUint32Array = Object.create(Uint32Array.prototype); - const fakeInt8Array = Object.create(Int8Array.prototype); - const fakeInt16Array = Object.create(Int16Array.prototype); - const fakeInt32Array = Object.create(Int32Array.prototype); - const fakeFloat32Array = Object.create(Float32Array.prototype); - const fakeFloat64Array = Object.create(Float64Array.prototype); - const fakeBigInt64Array = Object.create(BigInt64Array.prototype); - const fakeBigUint64Array = Object.create(BigUint64Array.prototype); + const fakeBuffer = { __proto__: Buffer.prototype }; + const fakeDataView = { __proto__: DataView.prototype }; + const fakeUint8Array = { __proto__: Uint8Array.prototype }; + const fakeUint8ClampedArray = { __proto__: Uint8ClampedArray.prototype }; + const fakeUint16Array = { __proto__: Uint16Array.prototype }; + const fakeUint32Array = { __proto__: Uint32Array.prototype }; + const fakeInt8Array = { __proto__: Int8Array.prototype }; + const fakeInt16Array = { __proto__: Int16Array.prototype }; + const fakeInt32Array = { __proto__: Int32Array.prototype }; + const fakeFloat32Array = { __proto__: Float32Array.prototype }; + const fakeFloat64Array = { __proto__: Float64Array.prototype }; + const fakeBigInt64Array = { __proto__: BigInt64Array.prototype }; + const fakeBigUint64Array = { __proto__: BigUint64Array.prototype }; const stealthyDataView = Object.setPrototypeOf(new DataView(arrayBuffer), Uint8Array.prototype); diff --git a/test/parallel/test-util.js b/test/parallel/test-util.js index 6b26f3398fa0b7..9a8b885647a31e 100644 --- a/test/parallel/test-util.js +++ b/test/parallel/test-util.js @@ -38,7 +38,7 @@ assert.strictEqual(util.isArray({}), false); assert.strictEqual(util.isArray({ push: function() {} }), false); assert.strictEqual(util.isArray(/regexp/), false); assert.strictEqual(util.isArray(new Error()), false); -assert.strictEqual(util.isArray(Object.create(Array.prototype)), false); +assert.strictEqual(util.isArray({ __proto__: Array.prototype }), false); // isRegExp assert.strictEqual(util.isRegExp(/regexp/), true); @@ -48,7 +48,7 @@ assert.strictEqual(util.isRegExp(context('RegExp')()), true); assert.strictEqual(util.isRegExp({}), false); assert.strictEqual(util.isRegExp([]), false); assert.strictEqual(util.isRegExp(new Date()), false); -assert.strictEqual(util.isRegExp(Object.create(RegExp.prototype)), false); +assert.strictEqual(util.isRegExp({ __proto__: RegExp.prototype }), false); // isDate assert.strictEqual(util.isDate(new Date()), true); @@ -58,7 +58,7 @@ assert.strictEqual(util.isDate(Date()), false); assert.strictEqual(util.isDate({}), false); assert.strictEqual(util.isDate([]), false); assert.strictEqual(util.isDate(new Error()), false); -assert.strictEqual(util.isDate(Object.create(Date.prototype)), false); +assert.strictEqual(util.isDate({ __proto__: Date.prototype }), false); // isError assert.strictEqual(util.isError(new Error()), true); @@ -70,7 +70,7 @@ assert.strictEqual(util.isError(new (context('SyntaxError'))()), true); assert.strictEqual(util.isError({}), false); assert.strictEqual(util.isError({ name: 'Error', message: '' }), false); assert.strictEqual(util.isError([]), false); -assert.strictEqual(util.isError(Object.create(Error.prototype)), true); +assert.strictEqual(util.isError({ __proto__: Error.prototype }), true); // isObject assert.strictEqual(util.isObject({}), true); @@ -170,7 +170,7 @@ assert.strictEqual(util.toUSVString('string\ud801'), 'string\ufffd'); ); assert.strictEqual(util.types.isNativeError([]), false); assert.strictEqual( - util.types.isNativeError(Object.create(Error.prototype)), + util.types.isNativeError({ __proto__: Error.prototype }), false ); assert.strictEqual( diff --git a/test/parallel/test-vm-inherited_properties.js b/test/parallel/test-vm-inherited_properties.js index 53087e1596e5c8..0a1d06cbdf093b 100644 --- a/test/parallel/test-vm-inherited_properties.js +++ b/test/parallel/test-vm-inherited_properties.js @@ -21,11 +21,11 @@ let result = vm.runInContext('Object.hasOwnProperty(this, "propBase");', assert.strictEqual(result, false); // Ref: https://github.com/nodejs/node/issues/5350 -base = Object.create(null); +base = { __proto__: null }; base.x = 1; base.y = 2; -sandbox = Object.create(base); +sandbox = { __proto__: base }; sandbox.z = 3; assert.deepStrictEqual(Object.keys(sandbox), ['z']); diff --git a/test/parallel/test-vm-module-basic.js b/test/parallel/test-vm-module-basic.js index d162f1bebd744c..b563fd6de2bbd8 100644 --- a/test/parallel/test-vm-module-basic.js +++ b/test/parallel/test-vm-module-basic.js @@ -85,7 +85,7 @@ const util = require('util'); assert.strictEqual(util.inspect(m, { depth: -1 }), '[SourceTextModule]'); assert.throws( - () => m[util.inspect.custom].call(Object.create(null)), + () => m[util.inspect.custom].call({ __proto__: null }), { code: 'ERR_VM_MODULE_NOT_MODULE', message: 'Provided module is not an instance of Module' diff --git a/test/parallel/test-x509-escaping.js b/test/parallel/test-x509-escaping.js index 170103fd9c973d..e6ae4d886908cb 100644 --- a/test/parallel/test-x509-escaping.js +++ b/test/parallel/test-x509-escaping.js @@ -239,7 +239,7 @@ const { hasOpenSSL3 } = common; checkServerIdentity: (hostname, peerCert) => { assert.strictEqual(hostname, 'example.com'); assert.deepStrictEqual(peerCert.infoAccess, - Object.assign(Object.create(null), + Object.assign({ __proto__: null }, expected.legacy)); // toLegacyObject() should also produce the same properties. However, @@ -352,7 +352,7 @@ const { hasOpenSSL3 } = common; servername: 'example.com', checkServerIdentity: (hostname, peerCert) => { assert.strictEqual(hostname, 'example.com'); - const expectedObject = Object.assign(Object.create(null), + const expectedObject = Object.assign({ __proto__: null }, expected.legacy); assert.deepStrictEqual(peerCert.subject, expectedObject); // The issuer MUST be the same as the subject since the cert is diff --git a/test/pummel/test-stream-pipe-multi.js b/test/pummel/test-stream-pipe-multi.js index f8fb7c9cc89cc2..3be69ee721573a 100644 --- a/test/pummel/test-stream-pipe-multi.js +++ b/test/pummel/test-stream-pipe-multi.js @@ -42,7 +42,7 @@ function FakeStream() { this.readable = true; } -FakeStream.prototype = Object.create(Stream.prototype); +FakeStream.prototype = { __proto__: Stream.prototype }; FakeStream.prototype.write = function(chunk) { console.error(this.ID, 'write', this.wait); diff --git a/tools/doc/html.mjs b/tools/doc/html.mjs index 339a48ce762c44..86df5162f58000 100644 --- a/tools/doc/html.mjs +++ b/tools/doc/html.mjs @@ -35,7 +35,7 @@ import * as common from './common.mjs'; import * as typeParser from './type-parser.mjs'; import buildCSSForFlavoredJS from './buildCSSForFlavoredJS.mjs'; -const dynamicSizes = Object.create(null); +const dynamicSizes = { __proto__: null }; const { highlight, getLanguage } = highlightJs; @@ -398,8 +398,8 @@ function versionSort(a, b) { const DEPRECATION_HEADING_PATTERN = /^DEP\d+:/; export function buildToc({ filename, apilinks }) { return (tree, file) => { - const idCounters = Object.create(null); - const legacyIdCounters = Object.create(null); + const idCounters = { __proto__: null }; + const legacyIdCounters = { __proto__: null }; let toc = ''; let depth = 0; diff --git a/tools/eslint-rules/prefer-proto.js b/tools/eslint-rules/prefer-proto.js new file mode 100644 index 00000000000000..7273c1af294b02 --- /dev/null +++ b/tools/eslint-rules/prefer-proto.js @@ -0,0 +1,53 @@ +/** + * @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'; + +// Cribbed from `eslint-module-utils/declaredScope` +function declaredScope(context, name) { + const references = context.getScope().references; + const reference = references.find((x) => x.identifier.name === name); + if (!reference) return undefined; + return reference.resolved.scope.type; +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + fixable: 'code', + messages: { + error: 'Use `{ __proto__: {{value}} }` instead of `ObjectCreate({{value}})` or `Object.create({{value}})`.', + }, + }, + create(context) { + return { + /* eslint max-len: 0 */ + 'CallExpression[arguments.length=1]:matches(\ + [callee.type="Identifier"][callee.name="ObjectCreate"],\ + [callee.type="MemberExpression"][callee.object.name="Object"][callee.property.name="create"]\ + )'(node) { + if (node.callee.type === 'MemberExpression') { + const scope = declaredScope(context, node.callee.object); + if (scope && scope !== 'module' && scope !== 'global') { + return; + } + } + const value = context.getSourceCode().getText(node.arguments[0]); + context.report({ + node, + messageId: 'error', + data: { value }, + fix(fixer) { + return fixer.replaceText(node, `{ __proto__: ${value} }`); + }, + }); + }, + }; + }, +};