@whatwg-node/node-fetch
Version:
Fetch API implementation for Node
139 lines (138 loc) • 4.75 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PonyfillFormData = void 0;
exports.getStreamFromFormData = getStreamFromFormData;
const node_buffer_1 = require("node:buffer");
const IteratorObject_js_1 = require("./IteratorObject.js");
const ReadableStream_js_1 = require("./ReadableStream.js");
class PonyfillFormData {
map = new Map();
append(name, value, fileName) {
let values = this.map.get(name);
if (!values) {
values = [];
this.map.set(name, values);
}
const entry = isBlob(value)
? getNormalizedFile(name, value, fileName)
: value;
values.push(entry);
}
delete(name) {
this.map.delete(name);
}
get(name) {
const values = this.map.get(name);
return values ? values[0] : null;
}
getAll(name) {
return this.map.get(name) || [];
}
has(name) {
return this.map.has(name);
}
set(name, value, fileName) {
const entry = isBlob(value)
? getNormalizedFile(name, value, fileName)
: value;
this.map.set(name, [entry]);
}
[Symbol.iterator]() {
return this._entries();
}
*_entries() {
for (const [key, values] of this.map) {
for (const value of values) {
yield [key, value];
}
}
}
entries() {
return new IteratorObject_js_1.PonyfillIteratorObject(this._entries(), 'FormDataIterator');
}
_keys() {
return this.map.keys();
}
keys() {
return new IteratorObject_js_1.PonyfillIteratorObject(this._keys(), 'FormDataIterator');
}
*_values() {
for (const values of this.map.values()) {
for (const value of values) {
yield value;
}
}
}
values() {
return new IteratorObject_js_1.PonyfillIteratorObject(this._values(), 'FormDataIterator');
}
forEach(callback) {
for (const [key, value] of this) {
callback(value, key, this);
}
}
}
exports.PonyfillFormData = PonyfillFormData;
function getStreamFromFormData(formData, boundary = '---') {
const entries = [];
let sentInitialHeader = false;
return new ReadableStream_js_1.PonyfillReadableStream({
start: controller => {
formData.forEach((value, key) => {
if (!sentInitialHeader) {
controller.enqueue(node_buffer_1.Buffer.from(`--${boundary}\r\n`));
sentInitialHeader = true;
}
entries.push([key, value]);
});
if (!sentInitialHeader) {
controller.enqueue(node_buffer_1.Buffer.from(`--${boundary}--\r\n`));
controller.close();
}
},
pull: async (controller) => {
const entry = entries.shift();
if (entry) {
const [key, value] = entry;
if (typeof value === 'string') {
controller.enqueue(node_buffer_1.Buffer.from(`Content-Disposition: form-data; name="${key}"\r\n\r\n`));
controller.enqueue(node_buffer_1.Buffer.from(value));
}
else {
let filenamePart = '';
if (value.name) {
filenamePart = `; filename="${value.name}"`;
}
controller.enqueue(node_buffer_1.Buffer.from(`Content-Disposition: form-data; name="${key}"${filenamePart}\r\n`));
controller.enqueue(node_buffer_1.Buffer.from(`Content-Type: ${value.type || 'application/octet-stream'}\r\n\r\n`));
const entryStream = value.stream();
for await (const chunk of entryStream) {
controller.enqueue(chunk);
}
}
if (entries.length === 0) {
controller.enqueue(node_buffer_1.Buffer.from(`\r\n--${boundary}--\r\n`));
controller.close();
}
else {
controller.enqueue(node_buffer_1.Buffer.from(`\r\n--${boundary}\r\n`));
}
}
else {
controller.enqueue(node_buffer_1.Buffer.from(`\r\n--${boundary}--\r\n`));
controller.close();
}
},
});
}
function getNormalizedFile(name, blob, fileName) {
Object.defineProperty(blob, 'name', {
configurable: true,
enumerable: true,
value: fileName || blob.name || name,
});
return blob;
}
function isBlob(value) {
return value?.arrayBuffer != null;
}