diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index ec3b0a8bf503fb..298b0be3647a8c 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -794,8 +794,8 @@ TSC for further discussion. #### How are LTS Branches Managed? -There are multiple LTS branches, e.g. `v8.x` and `v6.x`. Each of these is paired -with a staging branch: `v8.x-staging` and `v6.x-staging`. +There are multiple LTS branches, e.g. `v10.x, `v8.x` and `v6.x`. Each of these is paired +with a staging branch: `v10.x-staging`, `v8.x-staging` and `v6.x-staging`. As commits land on the master branch, they are cherry-picked back to each staging branch as appropriate. If the commit applies only to the LTS branch, the @@ -817,10 +817,18 @@ on backporting, please see the [backporting guide][]. Several LTS related issue and PR labels have been provided: +* `lts-watch-v10.x` - tells the LTS WG that the issue/PR needs to be considered + for landing in the `v10.x-staging` branch. +* `lts-watch-v8.x` - tells the LTS WG that the issue/PR needs to be considered + for landing in the `v8.x-staging` branch. * `lts-watch-v6.x` - tells the LTS WG that the issue/PR needs to be considered for landing in the `v6.x-staging` branch. * `lts-watch-v4.x` - tells the LTS WG that the issue/PR needs to be considered for landing in the `v4.x-staging` branch. +* `land-on-v10.x` - tells the release team that the commit should be landed + in a future v10.x release +* `land-on-v8.x` - tells the release team that the commit should be landed + in a future v8.x release * `land-on-v6.x` - tells the release team that the commit should be landed in a future v6.x release * `land-on-v4.x` - tells the release team that the commit should be landed diff --git a/doc/api/util.md b/doc/api/util.md index 89cfc94da38e64..b687eaf362f35e 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1,4 +1,4 @@ -# Util +# Util @@ -421,7 +421,7 @@ changes: * `depth` {number} Specifies the number of times to recurse while formatting the `object`. This is useful for inspecting large complicated objects. To make it recurse up to the maximum call stack size pass `Infinity` or `null`. - **Default:** `20`. + **Default:** `2`. * `colors` {boolean} If `true`, the output will be styled with ANSI color codes. Colors are customizable, see [Customizing `util.inspect` colors][]. **Default:** `false`. @@ -478,23 +478,12 @@ util.inspect(new Bar()); // 'Bar {}' util.inspect(baz); // '[foo] {}' ``` -The following example limits the inspected output of the `paths` property: +The following example inspects all properties of the `util` object: ```js const util = require('util'); -console.log(util.inspect(module, { depth: 0 })); -// Instead of showing all entries in `paths` `[Array]` is used to limit the -// output for readability: - -// Module { -// id: '', -// exports: {}, -// parent: undefined, -// filename: null, -// loaded: false, -// children: [], -// paths: [Array] } +console.log(util.inspect(util, { showHidden: true, depth: null })); ``` The following example highlights the difference with the `compact` option: @@ -510,7 +499,7 @@ const o = { 'foo']], 4], b: new Map([['za', 1], ['zb', 'test']]) }; -console.log(util.inspect(o, { compact: true, breakLength: 80 })); +console.log(util.inspect(o, { compact: true, depth: 5, breakLength: 80 })); // This will print @@ -524,7 +513,7 @@ console.log(util.inspect(o, { compact: true, breakLength: 80 })); // b: Map { 'za' => 1, 'zb' => 'test' } } // Setting `compact` to false changes the output to be more reader friendly. -console.log(util.inspect(o, { compact: false, breakLength: 80 })); +console.log(util.inspect(o, { compact: false, depth: 5, breakLength: 80 })); // { // a: [ diff --git a/lib/_http_server.js b/lib/_http_server.js index 3b2d7f50419127..96f05f5819d3a8 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -47,6 +47,7 @@ const { IncomingMessage } = require('_http_incoming'); const { ERR_HTTP_HEADERS_SENT, ERR_HTTP_INVALID_STATUS_CODE, + ERR_INVALID_ARG_TYPE, ERR_INVALID_CHAR } = require('internal/errors').codes; const Buffer = require('buffer').Buffer; @@ -281,6 +282,8 @@ function Server(options, requestListener) { options = {}; } else if (options == null || typeof options === 'object') { options = util._extend({}, options); + } else { + throw new ERR_INVALID_ARG_TYPE('options', 'object', options); } this[kIncomingMessage] = options.IncomingMessage || IncomingMessage; diff --git a/lib/internal/priority_queue.js b/lib/internal/priority_queue.js index 2f1db934b43cc8..ec8bbaea412761 100644 --- a/lib/internal/priority_queue.js +++ b/lib/internal/priority_queue.js @@ -28,25 +28,13 @@ module.exports = class PriorityQueue { insert(value) { const heap = this[kHeap]; - let pos = ++this[kSize]; + const pos = ++this[kSize]; + heap[pos] = value; if (heap.length === pos) heap.length *= 2; - const compare = this[kCompare]; - const setPosition = this[kSetPosition]; - while (pos > 1) { - const parent = heap[pos / 2 | 0]; - if (compare(parent, value) <= 0) - break; - heap[pos] = parent; - if (setPosition !== undefined) - setPosition(parent, pos); - pos = pos / 2 | 0; - } - heap[pos] = value; - if (setPosition !== undefined) - setPosition(value, pos); + this.percolateUp(pos); } peek() { @@ -77,18 +65,37 @@ module.exports = class PriorityQueue { setPosition(item, pos); } + percolateUp(pos) { + const heap = this[kHeap]; + const compare = this[kCompare]; + const setPosition = this[kSetPosition]; + const item = heap[pos]; + + while (pos > 1) { + const parent = heap[pos / 2 | 0]; + if (compare(parent, item) <= 0) + break; + heap[pos] = parent; + if (setPosition !== undefined) + setPosition(parent, pos); + pos = pos / 2 | 0; + } + heap[pos] = item; + if (setPosition !== undefined) + setPosition(item, pos); + } + removeAt(pos) { const heap = this[kHeap]; const size = --this[kSize]; heap[pos] = heap[size + 1]; heap[size + 1] = undefined; - if (size > 0) { - // If not removing the last item, update the shifted item's position. - if (pos <= size && this[kSetPosition] !== undefined) - this[kSetPosition](heap[pos], pos); - - this.percolateDown(1); + if (size > 0 && pos <= size) { + if (pos > 1 && this[kCompare](heap[pos / 2 | 0], heap[pos]) > 0) + this.percolateUp(pos); + else + this.percolateDown(pos); } } diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index bd35c4bb3b80f4..c3cad0e2f49d18 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -92,7 +92,7 @@ const hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty); const inspectDefaultOptions = Object.seal({ showHidden: false, - depth: 20, + depth: 2, colors: false, customInspect: true, showProxy: false, diff --git a/lib/repl.js b/lib/repl.js index 3391a94396db11..cd341978cb6f71 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -130,9 +130,8 @@ function hasOwnProperty(obj, prop) { // and it can be overridden by custom print functions, such as `probe` or // `eyes.js`. const writer = exports.writer = (obj) => util.inspect(obj, writer.options); -writer.options = Object.assign({}, - util.inspect.defaultOptions, - { showProxy: true, depth: 2 }); +writer.options = + Object.assign({}, util.inspect.defaultOptions, { showProxy: true }); exports._builtinLibs = builtinLibs; diff --git a/lib/zlib.js b/lib/zlib.js index c833afff14f4b9..559f6c2d5f3056 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -350,8 +350,7 @@ Object.defineProperty(Zlib.prototype, 'bytesRead', { // `params()` function should not happen while a write is currently in progress // on the threadpool. function paramsAfterFlushCallback(level, strategy, callback) { - if (!this._handle) - assert(false, 'zlib binding closed'); + assert(this._handle, 'zlib binding closed'); this._handle.params(level, strategy); if (!this._hadError) { this._level = level; @@ -507,8 +506,8 @@ function processChunkSync(self, chunk, flushFlag) { else buffers.push(out); nread += out.byteLength; - } else if (have < 0) { - assert(false, 'have should not go down'); + } else { + assert(have === 0, 'have should not go down'); } // exhausted the output buffer, or used all the input create a new one. @@ -545,8 +544,7 @@ function processChunkSync(self, chunk, flushFlag) { function processChunk(self, chunk, flushFlag, cb) { var handle = self._handle; - if (!handle) - assert(false, 'zlib binding closed'); + assert(handle, 'zlib binding closed'); handle.buffer = chunk; handle.cb = cb; @@ -593,8 +591,8 @@ function processCallback() { var out = self._outBuffer.slice(self._outOffset, self._outOffset + have); self._outOffset += have; self.push(out); - } else if (have < 0) { - assert(false, 'have should not go down'); + } else { + assert(have === 0, 'have should not go down'); } if (self.destroyed) { diff --git a/test/parallel/test-console-table.js b/test/parallel/test-console-table.js index e5b56ced8435ea..3a4d6fefbbc8f1 100644 --- a/test/parallel/test-console-table.js +++ b/test/parallel/test-console-table.js @@ -168,6 +168,14 @@ test({ a: { a: 1, b: 2, c: 3 } }, ` └─────────┴───┴───┴───┘ `); +test({ a: { a: { a: 1, b: 2, c: 3 } } }, ` +┌─────────┬──────────┐ +│ (index) │ a │ +├─────────┼──────────┤ +│ a │ [Object] │ +└─────────┴──────────┘ +`); + test({ a: [1, 2] }, ` ┌─────────┬───┬───┐ │ (index) │ 0 │ 1 │ diff --git a/test/parallel/test-http-server.js b/test/parallel/test-http-server.js index d46e25bdf6c558..f591cd59fc63c2 100644 --- a/test/parallel/test-http-server.js +++ b/test/parallel/test-http-server.js @@ -27,6 +27,19 @@ const http = require('http'); const url = require('url'); const qs = require('querystring'); +// TODO: documentation does not allow Array as an option, so testing that +// should fail, but currently http.Server does not typecheck further than +// if `option` is `typeof object` - so we don't test that here right now +const invalid_options = [ 'foo', 42, true ]; + +invalid_options.forEach((option) => { + assert.throws(() => { + new http.Server(option); + }, { + code: 'ERR_INVALID_ARG_TYPE' + }); +}); + let request_number = 0; let requests_sent = 0; let server_response = ''; diff --git a/test/parallel/test-priority-queue.js b/test/parallel/test-priority-queue.js index 702b5528ba9611..f8526e6521c24b 100644 --- a/test/parallel/test-priority-queue.js +++ b/test/parallel/test-priority-queue.js @@ -131,3 +131,33 @@ const PriorityQueue = require('internal/priority_queue'); assert.strictEqual(queue.shift(), undefined); } + + +{ + // Checks that removeAt respects binary heap properties + const queue = new PriorityQueue((a, b) => { + return a.value - b.value; + }, (node, pos) => (node.position = pos)); + + const i3 = { value: 3, position: null }; + const i7 = { value: 7, position: null }; + const i8 = { value: 8, position: null }; + + queue.insert({ value: 1, position: null }); + queue.insert({ value: 6, position: null }); + queue.insert({ value: 2, position: null }); + queue.insert(i7); + queue.insert(i8); + queue.insert(i3); + + assert.strictEqual(i7.position, 4); + queue.removeAt(4); + + // 3 should percolate up to swap with 6 (up) + assert.strictEqual(i3.position, 2); + + queue.removeAt(2); + + // 8 should swap places with 6 (down) + assert.strictEqual(i8.position, 4); +} diff --git a/test/parallel/test-stream-buffer-list.js b/test/parallel/test-stream-buffer-list.js index 1d3d7dd903d4bb..d7728d1171caa3 100644 --- a/test/parallel/test-stream-buffer-list.js +++ b/test/parallel/test-stream-buffer-list.js @@ -3,7 +3,6 @@ require('../common'); const assert = require('assert'); const BufferList = require('internal/streams/buffer_list'); -const util = require('util'); // Test empty buffer list. const emptyList = new BufferList(); @@ -31,11 +30,3 @@ assert.strictEqual(list.join(','), 'foo'); const shifted = list.shift(); assert.strictEqual(shifted, buf); assert.deepStrictEqual(list, new BufferList()); - -const tmp = util.inspect.defaultOptions.colors; -util.inspect.defaultOptions = { colors: true }; -assert.strictEqual( - util.inspect(list), - 'BufferList { head: \u001b[1mnull\u001b[22m, tail: \u001b[1mnull\u001b[22m,' + - ' length: \u001b[33m0\u001b[39m }'); -util.inspect.defaultOptions = { colors: tmp }; diff --git a/test/parallel/test-util-inspect-proxy.js b/test/parallel/test-util-inspect-proxy.js index 45f7abba213596..b3438a625240a2 100644 --- a/test/parallel/test-util-inspect-proxy.js +++ b/test/parallel/test-util-inspect-proxy.js @@ -50,17 +50,13 @@ const expected1 = 'Proxy [ {}, {} ]'; const expected2 = 'Proxy [ Proxy [ {}, {} ], {} ]'; const expected3 = 'Proxy [ Proxy [ Proxy [ {}, {} ], {} ], Proxy [ {}, {} ] ]'; const expected4 = 'Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [ {}, {} ], {} ] ]'; -const expected5 = 'Proxy [ Proxy [ Proxy [ Proxy [ {}, {} ], {} ],' + +const expected5 = 'Proxy [ Proxy [ Proxy [ Proxy [Array], {} ],' + ' Proxy [ {}, {} ] ],\n Proxy [ Proxy [ {}, {} ]' + - ', Proxy [ Proxy [ {}, {} ], {} ] ] ]'; -const expected6 = 'Proxy [ Proxy [ Proxy [ Proxy [ Proxy [ {}, {} ], {} ], ' + - 'Proxy [ {}, {} ] ],\n' + - ' Proxy [ Proxy [ {}, {} ], ' + - 'Proxy [ Proxy [ {}, {} ], {} ] ] ],\n' + - ' Proxy [ Proxy [ Proxy [ Proxy [ {}, {} ], {} ], ' + - 'Proxy [ {}, {} ] ],\n' + - ' Proxy [ Proxy [ {}, {} ], ' + - 'Proxy [ Proxy [ {}, {} ], {} ] ] ] ]'; + ', Proxy [ Proxy [Array], {} ] ] ]'; +const expected6 = 'Proxy [ Proxy [ Proxy [ Proxy [Array], Proxy [Array]' + + ' ],\n Proxy [ Proxy [Array], Proxy [Array] ] ],\n' + + ' Proxy [ Proxy [ Proxy [Array], Proxy [Array] ],\n' + + ' Proxy [ Proxy [Array], Proxy [Array] ] ] ]'; assert.strictEqual( util.inspect(proxy1, { showProxy: true, depth: null }), expected1); diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 713bf047ddd345..c0fc3219ce736f 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -71,7 +71,7 @@ assert.strictEqual(util.inspect({ a: 1, b: 2 }), '{ a: 1, b: 2 }'); assert.strictEqual(util.inspect({ 'a': {} }), '{ a: {} }'); assert.strictEqual(util.inspect({ 'a': { 'b': 2 } }), '{ a: { b: 2 } }'); assert.strictEqual(util.inspect({ 'a': { 'b': { 'c': { 'd': 2 } } } }), - '{ a: { b: { c: { d: 2 } } } }'); + '{ a: { b: { c: [Object] } } }'); assert.strictEqual( util.inspect({ 'a': { 'b': { 'c': { 'd': 2 } } } }, false, null), '{ a: { b: { c: { d: 2 } } } }'); @@ -110,7 +110,7 @@ assert.strictEqual(util.inspect((new JSStream())._externalStream), assert.strictEqual(util.inspect({ a: regexp }, false, 0), '{ a: /regexp/ }'); } -assert(!/Object/.test( +assert(/Object/.test( util.inspect({ a: { a: { a: { a: {} } } } }, undefined, undefined, true) )); assert(!/Object/.test( @@ -1055,15 +1055,15 @@ if (typeof Symbol !== 'undefined') { // Empty and circular before depth. { const arr = [[[[]]]]; - assert.strictEqual(util.inspect(arr, { depth: 2 }), '[ [ [ [] ] ] ]'); + assert.strictEqual(util.inspect(arr), '[ [ [ [] ] ] ]'); arr[0][0][0][0] = []; - assert.strictEqual(util.inspect(arr, { depth: 2 }), '[ [ [ [Array] ] ] ]'); + assert.strictEqual(util.inspect(arr), '[ [ [ [Array] ] ] ]'); arr[0][0][0] = {}; - assert.strictEqual(util.inspect(arr, { depth: 2 }), '[ [ [ {} ] ] ]'); + assert.strictEqual(util.inspect(arr), '[ [ [ {} ] ] ]'); arr[0][0][0] = { a: 2 }; - assert.strictEqual(util.inspect(arr, { depth: 2 }), '[ [ [ [Object] ] ] ]'); + assert.strictEqual(util.inspect(arr), '[ [ [ [Object] ] ] ]'); arr[0][0][0] = arr; - assert.strictEqual(util.inspect(arr, { depth: 2 }), '[ [ [ [Circular] ] ] ]'); + assert.strictEqual(util.inspect(arr), '[ [ [ [Circular] ] ] ]'); } // Corner cases. @@ -1160,10 +1160,10 @@ if (typeof Symbol !== 'undefined') { assert(!/1 more item/.test(util.inspect(arr))); util.inspect.defaultOptions.maxArrayLength = oldOptions.maxArrayLength; assert(/1 more item/.test(util.inspect(arr))); - util.inspect.defaultOptions.depth = 2; - assert(/Object/.test(util.inspect(obj))); - util.inspect.defaultOptions.depth = oldOptions.depth; + util.inspect.defaultOptions.depth = null; assert(!/Object/.test(util.inspect(obj))); + util.inspect.defaultOptions.depth = oldOptions.depth; + assert(/Object/.test(util.inspect(obj))); assert.strictEqual( JSON.stringify(util.inspect.defaultOptions), JSON.stringify(oldOptions) @@ -1175,7 +1175,7 @@ if (typeof Symbol !== 'undefined') { assert(/Object/.test(util.inspect(obj))); util.inspect.defaultOptions = oldOptions; assert(/1 more item/.test(util.inspect(arr))); - assert(!/Object/.test(util.inspect(obj))); + assert(/Object/.test(util.inspect(obj))); assert.strictEqual( JSON.stringify(util.inspect.defaultOptions), JSON.stringify(oldOptions) @@ -1561,19 +1561,11 @@ util.inspect(process); let head = list; // A linked list of length 100k should be inspectable in some way, even though // the real cutoff value is much lower than 100k. - for (let i = 0; i < 100000; i++) { + for (let i = 0; i < 100000; i++) head = head.next = {}; - } - - const res = Array(15) - .fill(0) - .map((_, i) => `{ next:\n${' '.repeat(i + 1)}`) - .join('') + - '{ next: { next: { next: { next: { next: { next:' + - ' [Object] } } } } } } } } } } } } } } } } } } } } }'; assert.strictEqual( util.inspect(list), - res + '{ next: { next: { next: [Object] } } }' ); const longList = util.inspect(list, { depth: Infinity }); const match = longList.match(/next/g); diff --git a/test/parallel/test-vm-basic.js b/test/parallel/test-vm-basic.js index df0c7df1062c14..29e2a8b5251934 100644 --- a/test/parallel/test-vm-basic.js +++ b/test/parallel/test-vm-basic.js @@ -209,6 +209,20 @@ const vm = require('vm'); } ); + // Testing for non Array type-based failures + [Boolean(), Number(), null, Object(), Symbol(), {}].forEach( + (value) => { + common.expectsError(() => { + vm.compileFunction('', value); + }, { + type: TypeError, + code: 'ERR_INVALID_ARG_TYPE', + message: 'The "params" argument must be of type Array. ' + + `Received type ${typeof value}` + }); + } + ); + assert.strictEqual( vm.compileFunction( 'return a;',