Skip to content

Commit 683f743

Browse files
jasnelladdaleax
authored andcommitted
buffer: support boxed strings and toPrimitive
Add support for `Buffer.from(new String('...'))` and `Buffer.from({[Symbol.toPrimitive](){return '...'}})` PR-URL: #13725 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent 70f3935 commit 683f743

File tree

3 files changed

+111
-2
lines changed

3 files changed

+111
-2
lines changed

‎doc/api/buffer.md‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,44 @@ console.log(buf2.toString());
908908

909909
A `TypeError` will be thrown if `str` is not a string.
910910

911+
### Class Method: Buffer.from(object[, offsetOrEncoding[, length]])
912+
<!-- YAML
913+
added: REPLACEME
914+
-->
915+
916+
*`object`{Object} An object supporting `Symbol.toPrimitive` or `valueOf()`
917+
*`offsetOrEncoding`{number|string} A byte-offset or encoding, depending on
918+
the value returned either by `object.valueOf()` or
919+
`object[Symbol.toPrimitive]()`.
920+
*`length`{number} A length, depending on the value returned either by
921+
`object.valueOf()` or `object[Symbol.toPrimitive]()`.
922+
923+
For objects whose `valueOf()` function returns a value not strictly equal to
924+
`object`, returns `Buffer.from(object.valueOf(), offsetOrEncoding, length)`.
925+
926+
For example:
927+
928+
```js
929+
constbuf=Buffer.from(newString('this is a test'));
930+
// <Buffer 74 68 69 73 20 69 73 20 61 20 74 65 73 74>
931+
```
932+
933+
For objects that support `Symbol.toPrimitive`, returns
934+
`Buffer.from(object[Symbol.toPrimitive](), offsetOrEncoding, length)`.
935+
936+
For example:
937+
938+
```js
939+
classFoo{
940+
[Symbol.toPrimitive](){
941+
return'this is a test';
942+
}
943+
}
944+
945+
constbuf=Buffer.from(newFoo(), 'utf8');
946+
// <Buffer 74 68 69 73 20 69 73 20 61 20 74 65 73 74>
947+
```
948+
911949
### Class Method: Buffer.isBuffer(obj)
912950
<!-- YAML
913951
added: v0.1.101

‎lib/buffer.js‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,26 @@ Buffer.from = function(value, encodingOrOffset, length){
175175
if(isAnyArrayBuffer(value))
176176
returnfromArrayBuffer(value,encodingOrOffset,length);
177177

178+
if(value==null)
179+
thrownewTypeError(kFromErrorMsg);
180+
181+
if(typeofvalue==='number')
182+
thrownewTypeError('"value" argument must not be a number');
183+
184+
constvalueOf=value.valueOf&&value.valueOf();
185+
if(valueOf!=null&&valueOf!==value)
186+
returnBuffer.from(valueOf,encodingOrOffset,length);
187+
178188
varb=fromObject(value);
179189
if(b)
180190
returnb;
181191

182-
if(typeofvalue==='number')
183-
thrownewTypeError('"value" argument must not be a number');
192+
if(typeofvalue[Symbol.toPrimitive]==='function'){
193+
returnBuffer.from(value[Symbol.toPrimitive]('string'),
194+
encodingOrOffset,
195+
length);
196+
}
197+
184198
thrownewTypeError(kFromErrorMsg);
185199
};
186200

‎test/parallel/test-buffer-from.js‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
'use strict';
2+
3+
require('../common');
4+
const{ deepStrictEqual, throws }=require('assert');
5+
const{ Buffer }=require('buffer');
6+
const{ runInNewContext }=require('vm');
7+
8+
constcheckString='test';
9+
10+
constcheck=Buffer.from(checkString);
11+
12+
classMyStringextendsString{
13+
constructor(){
14+
super(checkString);
15+
}
16+
}
17+
18+
classMyPrimitive{
19+
[Symbol.toPrimitive](){
20+
returncheckString;
21+
}
22+
}
23+
24+
classMyBadPrimitive{
25+
[Symbol.toPrimitive](){
26+
return1;
27+
}
28+
}
29+
30+
deepStrictEqual(Buffer.from(newString(checkString)),check);
31+
deepStrictEqual(Buffer.from(newMyString()),check);
32+
deepStrictEqual(Buffer.from(newMyPrimitive()),check);
33+
deepStrictEqual(Buffer.from(
34+
runInNewContext('new String(checkString)',{checkString})),
35+
check);
36+
37+
consterr=newRegExp('^TypeError: First argument must be a string, Buffer, '+
38+
'ArrayBuffer, Array, or array-like object\\.$');
39+
40+
[
41+
{},
42+
newBoolean(true),
43+
{valueOf(){returnnull;}},
44+
{valueOf(){returnundefined;}},
45+
{valueOf: null},
46+
Object.create(null)
47+
].forEach((input)=>{
48+
throws(()=>Buffer.from(input),err);
49+
});
50+
51+
[
52+
newNumber(true),
53+
newMyBadPrimitive()
54+
].forEach((input)=>{
55+
throws(()=>Buffer.from(input),
56+
/^TypeError:"value"argumentmustnotbeanumber$/);
57+
});

0 commit comments

Comments
(0)