99 PromiseReject,
1010 SafePromisePrototypeFinally,
1111 ReflectConstruct,
12+ RegExpPrototypeSymbolReplace,
1213 RegExpPrototypeTest,
1314 StringPrototypeToLowerCase,
1415 StringPrototypeSplit,
@@ -24,7 +25,10 @@ const {
2425 getDataObject,
2526} = internalBinding ( 'blob' ) ;
2627
27- const { TextDecoder } = require ( 'internal/encoding' ) ;
28+ const {
29+ TextDecoder,
30+ TextEncoder,
31+ } = require ( 'internal/encoding' ) ;
2832
2933const {
3034 makeTransferable,
@@ -48,6 +52,7 @@ const {
4852 AbortError,
4953 codes : {
5054 ERR_INVALID_ARG_TYPE ,
55+ ERR_INVALID_ARG_VALUE ,
5156 ERR_INVALID_THIS ,
5257 ERR_BUFFER_TOO_LARGE ,
5358 }
@@ -68,10 +73,11 @@ const kMaxChunkSize = 65536;
6873
6974const disallowedTypeCharacters = / [ ^ \u{0020} - \u{007E} ] / u;
7075
71- let Buffer ;
7276let ReadableStream ;
7377let URL ;
78+ let EOL ;
7479
80+ const enc = new TextEncoder ( ) ;
7581
7682// Yes, lazy loading is annoying but because of circular
7783// references between the url, internal/blob, and buffer
@@ -82,29 +88,35 @@ function lazyURL(id) {
8288 return new URL ( id ) ;
8389}
8490
85- function lazyBuffer ( ) {
86- Buffer ??= require ( 'buffer' ) . Buffer ;
87- return Buffer ;
88- }
89-
9091function lazyReadableStream ( options ) {
9192 ReadableStream ??=
9293 require ( 'internal/webstreams/readablestream' ) . ReadableStream ;
9394 return new ReadableStream ( options ) ;
9495}
9596
97+ // TODO(@jasnell): This is annoying but this has to be lazy because
98+ // requiring the 'os' module too early causes building Node.js to
99+ // fail with an unknown reference failure.
100+ function lazyEOL ( ) {
101+ EOL ??= require ( 'os' ) . EOL ;
102+ return EOL ;
103+ }
104+
96105function isBlob ( object ) {
97106 return object ?. [ kHandle ] !== undefined ;
98107}
99108
100- function getSource ( source , encoding ) {
109+ function getSource ( source , endings ) {
101110 if ( isBlob ( source ) )
102111 return [ source . size , source [ kHandle ] ] ;
103112
104113 if ( isAnyArrayBuffer ( source ) ) {
105114 source = new Uint8Array ( source ) ;
106115 } else if ( ! isArrayBufferView ( source ) ) {
107- source = lazyBuffer ( ) . from ( `${ source } ` , encoding ) ;
116+ source = `${ source } ` ;
117+ if ( endings === 'native' )
118+ source = RegExpPrototypeSymbolReplace ( / \n | \r \n / g, source , lazyEOL ( ) ) ;
119+ source = enc . encode ( source ) ;
108120 }
109121
110122 // We copy into a new Uint8Array because the underlying
@@ -116,6 +128,16 @@ function getSource(source, encoding) {
116128}
117129
118130class Blob {
131+ /**
132+ * @typedef {string|ArrayBuffer|ArrayBufferView|Blob } SourcePart
133+ *
134+ * @param {SourcePart[] } [sources]
135+ * @param {{
136+ * endings? : string,
137+ * type? : string,
138+ * }} [options]
139+ * @returns
140+ */
119141 constructor ( sources = [ ] , options = { } ) {
120142 emitExperimentalWarning ( 'buffer.Blob' ) ;
121143 if ( sources === null ||
@@ -124,12 +146,18 @@ class Blob {
124146 throw new ERR_INVALID_ARG_TYPE ( 'sources' , 'Iterable' , sources ) ;
125147 }
126148 validateObject ( options , 'options' ) ;
127- const { encoding = 'utf8' } = options ;
128- let { type = '' } = options ;
149+ let {
150+ type = '' ,
151+ endings = 'transparent' ,
152+ } = options ;
153+
154+ endings = `${ endings } ` ;
155+ if ( endings !== 'transparent' && endings !== 'native' )
156+ throw new ERR_INVALID_ARG_VALUE ( 'options.endings' , endings ) ;
129157
130158 let length = 0 ;
131159 const sources_ = ArrayFrom ( sources , ( source ) => {
132- const { 0 : len , 1 : src } = getSource ( source , encoding ) ;
160+ const { 0 : len , 1 : src } = getSource ( source , endings ) ;
133161 length += len ;
134162 return src ;
135163 } ) ;
0 commit comments