Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[Fix] babel's "loose mode" class transform enbrittles BufferList (#428)
```js
Object.defineProperty(Object.prototype, util.inspect.custom, {
  set(v) { throw 'this should not happen inside readable-stream'; }
});
```

With this change, I believe the output will use [[Define]] instead of [[Set]] for https://github.com/nodejs/node/blob/c101251a95cc82142bee4637f8db6cc360a06d82/lib/internal/streams/buffer_list.js#L167, and thus no longer fail when Object.prototype is modified.
  • Loading branch information
ljharb committed Feb 13, 2020
1 parent 7783afa commit 3bbf2d6
Show file tree
Hide file tree
Showing 26 changed files with 1,458 additions and 1,044 deletions.
6 changes: 0 additions & 6 deletions .babelrc
Expand Up @@ -13,11 +13,5 @@
],
"debug": true
}]
],
"plugins": [
// Included in the preset, but we can't specify per-plugin options there
["@babel/plugin-transform-classes", {
"loose": true
}]
]
}
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -15,7 +15,7 @@ npm install --save readable-stream

This package is a mirror of the streams implementations in Node.js.

Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v10.18.1/docs/api/stream.html).
Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v10.19.0/docs/api/stream.html).

If you want to guarantee a stable streams base, regardless of what version of
Node you, or the users of your libraries are using, use **readable-stream** *only* and avoid the *"stream"* module in Node-core, for background see [this blogpost](http://r.va.gg/2014/06/why-i-dont-use-nodes-core-stream-module.html).
Expand Down
309 changes: 164 additions & 145 deletions lib/internal/streams/buffer_list.js
Expand Up @@ -6,6 +6,12 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

var _require = require('buffer'),
Buffer = _require.Buffer;

Expand All @@ -22,170 +28,183 @@ module.exports =
/*#__PURE__*/
function () {
function BufferList() {
_classCallCheck(this, BufferList);

this.head = null;
this.tail = null;
this.length = 0;
}

var _proto = BufferList.prototype;

_proto.push = function push(v) {
var entry = {
data: v,
next: null
};
if (this.length > 0) this.tail.next = entry;else this.head = entry;
this.tail = entry;
++this.length;
};

_proto.unshift = function unshift(v) {
var entry = {
data: v,
next: this.head
};
if (this.length === 0) this.tail = entry;
this.head = entry;
++this.length;
};

_proto.shift = function shift() {
if (this.length === 0) return;
var ret = this.head.data;
if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next;
--this.length;
return ret;
};

_proto.clear = function clear() {
this.head = this.tail = null;
this.length = 0;
};

_proto.join = function join(s) {
if (this.length === 0) return '';
var p = this.head;
var ret = '' + p.data;

while (p = p.next) {
ret += s + p.data;
_createClass(BufferList, [{
key: "push",
value: function push(v) {
var entry = {
data: v,
next: null
};
if (this.length > 0) this.tail.next = entry;else this.head = entry;
this.tail = entry;
++this.length;
}

return ret;
};

_proto.concat = function concat(n) {
if (this.length === 0) return Buffer.alloc(0);
var ret = Buffer.allocUnsafe(n >>> 0);
var p = this.head;
var i = 0;

while (p) {
copyBuffer(p.data, ret, i);
i += p.data.length;
p = p.next;
}, {
key: "unshift",
value: function unshift(v) {
var entry = {
data: v,
next: this.head
};
if (this.length === 0) this.tail = entry;
this.head = entry;
++this.length;
}

return ret;
} // Consumes a specified amount of bytes or characters from the buffered data.
;

_proto.consume = function consume(n, hasStrings) {
var ret;

if (n < this.head.data.length) {
// `slice` is the same for buffers and strings.
ret = this.head.data.slice(0, n);
this.head.data = this.head.data.slice(n);
} else if (n === this.head.data.length) {
// First chunk is a perfect match.
ret = this.shift();
} else {
// Result spans more than one buffer.
ret = hasStrings ? this._getString(n) : this._getBuffer(n);
}, {
key: "shift",
value: function shift() {
if (this.length === 0) return;
var ret = this.head.data;
if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next;
--this.length;
return ret;
}
}, {
key: "clear",
value: function clear() {
this.head = this.tail = null;
this.length = 0;
}
}, {
key: "join",
value: function join(s) {
if (this.length === 0) return '';
var p = this.head;
var ret = '' + p.data;

while (p = p.next) {
ret += s + p.data;
}

return ret;
};

_proto.first = function first() {
return this.head.data;
} // Consumes a specified amount of characters from the buffered data.
;

_proto._getString = function _getString(n) {
var p = this.head;
var c = 1;
var ret = p.data;
n -= ret.length;

while (p = p.next) {
var str = p.data;
var nb = n > str.length ? str.length : n;
if (nb === str.length) ret += str;else ret += str.slice(0, n);
n -= nb;

if (n === 0) {
if (nb === str.length) {
++c;
if (p.next) this.head = p.next;else this.head = this.tail = null;
} else {
this.head = p;
p.data = str.slice(nb);
}
return ret;
}
}, {
key: "concat",
value: function concat(n) {
if (this.length === 0) return Buffer.alloc(0);
var ret = Buffer.allocUnsafe(n >>> 0);
var p = this.head;
var i = 0;

while (p) {
copyBuffer(p.data, ret, i);
i += p.data.length;
p = p.next;
}

break;
return ret;
} // Consumes a specified amount of bytes or characters from the buffered data.

}, {
key: "consume",
value: function consume(n, hasStrings) {
var ret;

if (n < this.head.data.length) {
// `slice` is the same for buffers and strings.
ret = this.head.data.slice(0, n);
this.head.data = this.head.data.slice(n);
} else if (n === this.head.data.length) {
// First chunk is a perfect match.
ret = this.shift();
} else {
// Result spans more than one buffer.
ret = hasStrings ? this._getString(n) : this._getBuffer(n);
}

++c;
return ret;
}
}, {
key: "first",
value: function first() {
return this.head.data;
} // Consumes a specified amount of characters from the buffered data.

}, {
key: "_getString",
value: function _getString(n) {
var p = this.head;
var c = 1;
var ret = p.data;
n -= ret.length;

while (p = p.next) {
var str = p.data;
var nb = n > str.length ? str.length : n;
if (nb === str.length) ret += str;else ret += str.slice(0, n);
n -= nb;

if (n === 0) {
if (nb === str.length) {
++c;
if (p.next) this.head = p.next;else this.head = this.tail = null;
} else {
this.head = p;
p.data = str.slice(nb);
}

break;
}

this.length -= c;
return ret;
} // Consumes a specified amount of bytes from the buffered data.
;

_proto._getBuffer = function _getBuffer(n) {
var ret = Buffer.allocUnsafe(n);
var p = this.head;
var c = 1;
p.data.copy(ret);
n -= p.data.length;

while (p = p.next) {
var buf = p.data;
var nb = n > buf.length ? buf.length : n;
buf.copy(ret, ret.length - n, 0, nb);
n -= nb;

if (n === 0) {
if (nb === buf.length) {
++c;
if (p.next) this.head = p.next;else this.head = this.tail = null;
} else {
this.head = p;
p.data = buf.slice(nb);
++c;
}

this.length -= c;
return ret;
} // Consumes a specified amount of bytes from the buffered data.

}, {
key: "_getBuffer",
value: function _getBuffer(n) {
var ret = Buffer.allocUnsafe(n);
var p = this.head;
var c = 1;
p.data.copy(ret);
n -= p.data.length;

while (p = p.next) {
var buf = p.data;
var nb = n > buf.length ? buf.length : n;
buf.copy(ret, ret.length - n, 0, nb);
n -= nb;

if (n === 0) {
if (nb === buf.length) {
++c;
if (p.next) this.head = p.next;else this.head = this.tail = null;
} else {
this.head = p;
p.data = buf.slice(nb);
}

break;
}

break;
++c;
}

++c;
this.length -= c;
return ret;
} // Make sure the linked list only shows the minimal necessary information.

}, {
key: custom,
value: function value(_, options) {
return inspect(this, _objectSpread({}, options, {
// Only inspect one level.
depth: 0,
// It should not recurse.
customInspect: false
}));
}

this.length -= c;
return ret;
} // Make sure the linked list only shows the minimal necessary information.
;

_proto[custom] = function (_, options) {
return inspect(this, _objectSpread({}, options, {
// Only inspect one level.
depth: 0,
// It should not recurse.
customInspect: false
}));
};
}]);

return BufferList;
}();

0 comments on commit 3bbf2d6

Please sign in to comment.