rekwest
Version:
The robust request library that humanity deserves 🌐
178 lines (177 loc) • 6.42 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FormData = void 0;
var _nodeBuffer = require("node:buffer");
var _nodeCrypto = require("node:crypto");
var _nodeHttp = _interopRequireDefault(require("node:http2"));
var _nodeUtil = require("node:util");
var _mediatypes = require("./mediatypes");
var _utils = require("./utils");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const CRLF = '\r\n';
const {
HTTP2_HEADER_CONTENT_DISPOSITION,
HTTP2_HEADER_CONTENT_TYPE
} = _nodeHttp.default.constants;
class FormData {
static actuate(fd) {
const boundary = (0, _nodeCrypto.randomBytes)(24).toString('hex');
const contentType = `${_mediatypes.MULTIPART_FORM_DATA}; boundary=${boundary}`;
const prefix = `--${boundary}${CRLF}${HTTP2_HEADER_CONTENT_DISPOSITION}: form-data`;
const escape = str => str.replace(/\n/g, '%0A').replace(/\r/g, '%0D').replace(/"/g, '%22');
const redress = str => str.replace(/\r?\n|\r/g, CRLF);
return {
contentType,
async *[Symbol.asyncIterator]() {
const encoder = new TextEncoder();
for (const [name, value] of fd) {
if (value.constructor === String) {
yield encoder.encode(`${prefix}; name="${escape(redress(name))}"${CRLF.repeat(2)}${redress(value)}${CRLF}`);
} else {
yield encoder.encode(`${prefix}; name="${escape(redress(name))}"${value.name ? `; filename="${escape(value.name)}"` : ''}${CRLF}${HTTP2_HEADER_CONTENT_TYPE}: ${value.type || _mediatypes.APPLICATION_OCTET_STREAM}${CRLF.repeat(2)}`);
yield* (0, _utils.tap)(value);
yield new Uint8Array([13, 10]);
}
}
yield encoder.encode(`--${boundary}--`);
}
};
}
static alike(instance) {
return FormData.name === instance?.[Symbol.toStringTag];
}
static #enfoldEntry(name, value, filename) {
name = (0, _nodeUtil.toUSVString)(name);
filename &&= (0, _nodeUtil.toUSVString)(filename);
if ((0, _utils.isFileLike)(value)) {
filename ??= value.name || 'blob';
value = new _nodeBuffer.File([value], filename, value);
} else if (this.#ensureInstance(value)) {
value.name = filename;
} else {
value = (0, _nodeUtil.toUSVString)(value);
}
return {
name,
value
};
}
static #ensureInstance(value) {
return (0, _utils.isFileLike)(value) || value === Object(value) && Reflect.has(value, Symbol.asyncIterator);
}
#entries = [];
get [Symbol.toStringTag]() {
return this.constructor.name;
}
constructor(input) {
if (input === Object(input) && (input?.constructor === Object || Reflect.has(input, Symbol.iterator))) {
if (input.constructor !== Object) {
input = Array.from(input);
}
if (Array.isArray(input)) {
if (!input.every(it => Array.isArray(it))) {
throw new TypeError(`Failed to construct '${this[Symbol.toStringTag]}': The provided value cannot be converted to a sequence.`);
} else if (!input.every(it => it.length === 2)) {
throw new TypeError(`Failed to construct '${this[Symbol.toStringTag]}': Sequence initializer must only contain pair elements.`);
}
}
if (input.constructor === Object) {
input = Object.entries(input);
}
for (const [key, value] of input) {
this.append(key, value);
}
}
}
#ensureArgs(args, expected, method) {
if (args.length < expected) {
throw new TypeError(`Failed to execute '${method}' on '${this[Symbol.toStringTag]}': ${expected} arguments required, but only ${args.length} present.`);
}
if (['append', 'set'].includes(method)) {
if (args.length === 3 && !this.constructor.#ensureInstance(args[1])) {
throw new TypeError(`Failed to execute '${method}' on '${this[Symbol.toStringTag]}': parameter ${expected} is not of type 'Blob'.`);
}
}
if (method === 'forEach') {
if (args[0]?.constructor !== Function) {
throw new TypeError(`Failed to execute '${method}' on '${this[Symbol.toStringTag]}': parameter ${expected} is not of type 'Function'.`);
}
}
}
append(...args) {
(0, _utils.brandCheck)(this, FormData);
this.#ensureArgs(args, 2, 'append');
this.#entries.push(this.constructor.#enfoldEntry(...args));
}
delete(...args) {
(0, _utils.brandCheck)(this, FormData);
this.#ensureArgs(args, 1, 'delete');
const name = (0, _nodeUtil.toUSVString)(args[0]);
this.#entries = this.#entries.filter(it => it.name !== name);
}
forEach(...args) {
(0, _utils.brandCheck)(this, FormData);
this.#ensureArgs(args, 1, 'forEach');
const [callback, thisArg] = args;
for (const entry of this) {
Reflect.apply(callback, thisArg, [...entry.reverse(), this]);
}
}
get(...args) {
(0, _utils.brandCheck)(this, FormData);
this.#ensureArgs(args, 1, 'get');
const name = (0, _nodeUtil.toUSVString)(args[0]);
return (this.#entries.find(it => it.name === name) ?? {}).value ?? null;
}
getAll(...args) {
(0, _utils.brandCheck)(this, FormData);
this.#ensureArgs(args, 1, 'getAll');
const name = (0, _nodeUtil.toUSVString)(args[0]);
return this.#entries.filter(it => it.name === name).map(it => it.value);
}
has(...args) {
(0, _utils.brandCheck)(this, FormData);
this.#ensureArgs(args, 1, 'has');
const name = (0, _nodeUtil.toUSVString)(args[0]);
return !!this.#entries.find(it => it.name === name);
}
set(...args) {
(0, _utils.brandCheck)(this, FormData);
this.#ensureArgs(args, 2, 'set');
const entry = this.constructor.#enfoldEntry(...args);
const idx = this.#entries.findIndex(it => it.name === entry.name);
if (idx !== -1) {
this.#entries.splice(idx, 1, entry);
} else {
this.#entries.push(entry);
}
}
*entries() {
(0, _utils.brandCheck)(this, FormData);
for (const {
name,
value
} of this.#entries) {
yield [name, value];
}
}
*keys() {
(0, _utils.brandCheck)(this, FormData);
for (const [name] of this) {
yield name;
}
}
*values() {
(0, _utils.brandCheck)(this, FormData);
for (const [, value] of this) {
yield value;
}
}
[Symbol.iterator]() {
(0, _utils.brandCheck)(this, FormData);
return this.entries();
}
}
exports.FormData = FormData;