form-data-encoder
Advanced tools
Comparing version
@@ -1,10 +0,1 @@ | ||
interface RawHeaders { | ||
"Content-Type": string; | ||
"Content-Length"?: string; | ||
} | ||
interface FormDataEncoderHeaders extends RawHeaders { | ||
"content-type": string; | ||
"content-length"?: string; | ||
} | ||
interface FileLike { | ||
@@ -74,2 +65,11 @@ /** | ||
interface RawHeaders { | ||
"Content-Type": string; | ||
"Content-Length"?: string; | ||
} | ||
interface FormDataEncoderHeaders extends RawHeaders { | ||
"content-type": string; | ||
"content-length"?: string; | ||
} | ||
interface FormDataEncoderOptions { | ||
@@ -278,2 +278,2 @@ /** | ||
export { FileLike, FormDataEncoder, FormDataEncoderOptions, FormDataEntryValue, FormDataLike, isFile, isFormData }; | ||
export { type FileLike, FormDataEncoder, type FormDataEncoderOptions, type FormDataEntryValue, type FormDataLike, isFile, isFormData }; |
150
lib/index.js
@@ -1,30 +0,10 @@ | ||
var __accessCheck = (obj, member, msg) => { | ||
if (!member.has(obj)) | ||
throw TypeError("Cannot " + msg); | ||
var __typeError = (msg) => { | ||
throw TypeError(msg); | ||
}; | ||
var __privateGet = (obj, member, getter) => { | ||
__accessCheck(obj, member, "read from private field"); | ||
return getter ? getter.call(obj) : member.get(obj); | ||
}; | ||
var __privateAdd = (obj, member, value) => { | ||
if (member.has(obj)) | ||
throw TypeError("Cannot add the same private member more than once"); | ||
member instanceof WeakSet ? member.add(obj) : member.set(obj, value); | ||
}; | ||
var __privateSet = (obj, member, value, setter) => { | ||
__accessCheck(obj, member, "write to private field"); | ||
setter ? setter.call(obj, value) : member.set(obj, value); | ||
return value; | ||
}; | ||
var __privateMethod = (obj, member, method) => { | ||
__accessCheck(obj, member, "access private method"); | ||
return method; | ||
}; | ||
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); | ||
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); | ||
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); | ||
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); | ||
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method); | ||
// src/util/isFunction.ts | ||
var isFunction = (value) => typeof value === "function"; | ||
// src/util/isAsyncIterable.ts | ||
var isAsyncIterable = (value) => isFunction(value[Symbol.asyncIterator]); | ||
// src/util/chunk.ts | ||
@@ -46,2 +26,25 @@ var MAX_CHUNK_SIZE = 65536; | ||
// src/util/createBoundary.ts | ||
var alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; | ||
function createBoundary() { | ||
let size = 16; | ||
let res = ""; | ||
while (size--) { | ||
res += alphabet[Math.random() * alphabet.length << 0]; | ||
} | ||
return res; | ||
} | ||
// src/util/escapeName.ts | ||
var escapeName = (name) => String(name).replace(/\r/g, "%0D").replace(/\n/g, "%0A").replace(/"/g, "%22"); | ||
// src/util/isFunction.ts | ||
var isFunction = (value) => typeof value === "function"; | ||
// src/util/isReadableStreamFallback.ts | ||
var isReadableStreamFallback = (value) => !!value && typeof value === "object" && !Array.isArray(value) && isFunction(value.getReader); | ||
// src/util/isAsyncIterable.ts | ||
var isAsyncIterable = (value) => isFunction(value[Symbol.asyncIterator]); | ||
// src/util/getStreamIterator.ts | ||
@@ -67,3 +70,3 @@ async function* readStream(readable) { | ||
} | ||
if (isFunction(source.getReader)) { | ||
if (isReadableStreamFallback(source)) { | ||
return chunkStream(readStream(source)); | ||
@@ -76,20 +79,11 @@ } | ||
// src/util/createBoundary.ts | ||
var alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; | ||
function createBoundary() { | ||
let size = 16; | ||
let res = ""; | ||
while (size--) { | ||
res += alphabet[Math.random() * alphabet.length << 0]; | ||
} | ||
return res; | ||
} | ||
// src/util/isFile.ts | ||
var isFile = (value) => Boolean( | ||
value && typeof value === "object" && isFunction(value.constructor) && value[Symbol.toStringTag] === "File" && isFunction(value.stream) && value.name != null | ||
); | ||
// src/util/normalizeValue.ts | ||
var normalizeValue = (value) => String(value).replace(/\r|\n/g, (match, i, str) => { | ||
if (match === "\r" && str[i + 1] !== "\n" || match === "\n" && str[i - 1] !== "\r") { | ||
return "\r\n"; | ||
} | ||
return match; | ||
}); | ||
// src/util/isFormData.ts | ||
var isFormData = (value) => Boolean( | ||
value && isFunction(value.constructor) && value[Symbol.toStringTag] === "FormData" && isFunction(value.append) && isFunction(value.getAll) && isFunction(value.entries) && isFunction(value[Symbol.iterator]) | ||
); | ||
@@ -106,6 +100,13 @@ // src/util/isPlainObject.ts | ||
} | ||
const Ctor = pp.constructor && pp.constructor.toString(); | ||
return Ctor === Object.toString(); | ||
return pp.constructor?.toString?.() === Object.toString(); | ||
} | ||
// src/util/normalizeValue.ts | ||
var normalizeValue = (value) => String(value).replace(/\r|\n/g, (match, i, str) => { | ||
if (match === "\r" && str[i + 1] !== "\n" || match === "\n" && str[i - 1] !== "\r") { | ||
return "\r\n"; | ||
} | ||
return match; | ||
}); | ||
// src/util/proxyHeaders.ts | ||
@@ -130,15 +131,2 @@ function getProperty(target, prop) { | ||
// src/util/isFormData.ts | ||
var isFormData = (value) => Boolean( | ||
value && isFunction(value.constructor) && value[Symbol.toStringTag] === "FormData" && isFunction(value.append) && isFunction(value.getAll) && isFunction(value.entries) && isFunction(value[Symbol.iterator]) | ||
); | ||
// src/util/escapeName.ts | ||
var escapeName = (name) => String(name).replace(/\r/g, "%0D").replace(/\n/g, "%0A").replace(/"/g, "%22"); | ||
// src/util/isFile.ts | ||
var isFile = (value) => Boolean( | ||
value && typeof value === "object" && isFunction(value.constructor) && value[Symbol.toStringTag] === "File" && isFunction(value.stream) && value.name != null | ||
); | ||
// src/FormDataEncoder.ts | ||
@@ -149,13 +137,9 @@ var defaultOptions = { | ||
var readonlyProp = { writable: false, configurable: false }; | ||
var _CRLF, _CRLF_BYTES, _CRLF_BYTES_LENGTH, _DASHES, _encoder, _footer, _form, _options, _getFieldHeader, getFieldHeader_fn, _getContentLength, getContentLength_fn; | ||
var _CRLF, _CRLF_BYTES, _CRLF_BYTES_LENGTH, _DASHES, _encoder, _footer, _form, _options, _FormDataEncoder_instances, getFieldHeader_fn, getContentLength_fn; | ||
var FormDataEncoder = class { | ||
constructor(form, boundaryOrOptions, options) { | ||
__privateAdd(this, _getFieldHeader); | ||
/** | ||
* Returns form-data content length | ||
*/ | ||
__privateAdd(this, _getContentLength); | ||
__privateAdd(this, _FormDataEncoder_instances); | ||
__privateAdd(this, _CRLF, "\r\n"); | ||
__privateAdd(this, _CRLF_BYTES, void 0); | ||
__privateAdd(this, _CRLF_BYTES_LENGTH, void 0); | ||
__privateAdd(this, _CRLF_BYTES); | ||
__privateAdd(this, _CRLF_BYTES_LENGTH); | ||
__privateAdd(this, _DASHES, "-".repeat(2)); | ||
@@ -169,11 +153,11 @@ /** | ||
*/ | ||
__privateAdd(this, _footer, void 0); | ||
__privateAdd(this, _footer); | ||
/** | ||
* FormData instance | ||
*/ | ||
__privateAdd(this, _form, void 0); | ||
__privateAdd(this, _form); | ||
/** | ||
* Instance options | ||
*/ | ||
__privateAdd(this, _options, void 0); | ||
__privateAdd(this, _options); | ||
if (!isFormData(form)) { | ||
@@ -189,3 +173,3 @@ throw new TypeError("Expected first argument to be a FormData instance."); | ||
if (!boundary) { | ||
boundary = createBoundary(); | ||
boundary = `form-data-encoder-${createBoundary()}`; | ||
} | ||
@@ -202,3 +186,3 @@ if (typeof boundary !== "string") { | ||
__privateSet(this, _CRLF_BYTES_LENGTH, __privateGet(this, _CRLF_BYTES).byteLength); | ||
this.boundary = `form-data-boundary-${boundary}`; | ||
this.boundary = boundary; | ||
this.contentType = `multipart/form-data; boundary=${this.boundary}`; | ||
@@ -211,3 +195,3 @@ __privateSet(this, _footer, __privateGet(this, _encoder).encode( | ||
}; | ||
const contentLength = __privateMethod(this, _getContentLength, getContentLength_fn).call(this); | ||
const contentLength = __privateMethod(this, _FormDataEncoder_instances, getContentLength_fn).call(this); | ||
if (contentLength) { | ||
@@ -265,6 +249,4 @@ this.contentLength = contentLength; | ||
for (const [name, raw] of __privateGet(this, _form)) { | ||
const value = isFile(raw) ? raw : __privateGet(this, _encoder).encode( | ||
normalizeValue(raw) | ||
); | ||
yield __privateMethod(this, _getFieldHeader, getFieldHeader_fn).call(this, name, value); | ||
const value = isFile(raw) ? raw : __privateGet(this, _encoder).encode(normalizeValue(raw)); | ||
yield __privateMethod(this, _FormDataEncoder_instances, getFieldHeader_fn).call(this, name, value); | ||
yield value; | ||
@@ -338,3 +320,3 @@ yield __privateGet(this, _CRLF_BYTES); | ||
_options = new WeakMap(); | ||
_getFieldHeader = new WeakSet(); | ||
_FormDataEncoder_instances = new WeakSet(); | ||
getFieldHeader_fn = function(name, value) { | ||
@@ -356,9 +338,9 @@ let header = ""; | ||
}; | ||
_getContentLength = new WeakSet(); | ||
/** | ||
* Returns form-data content length | ||
*/ | ||
getContentLength_fn = function() { | ||
let length = 0; | ||
for (const [name, raw] of __privateGet(this, _form)) { | ||
const value = isFile(raw) ? raw : __privateGet(this, _encoder).encode( | ||
normalizeValue(raw) | ||
); | ||
const value = isFile(raw) ? raw : __privateGet(this, _encoder).encode(normalizeValue(raw)); | ||
const size = isFile(value) ? value.size : value.byteLength; | ||
@@ -368,3 +350,3 @@ if (size == null || isNaN(size)) { | ||
} | ||
length += __privateMethod(this, _getFieldHeader, getFieldHeader_fn).call(this, name, value).byteLength; | ||
length += __privateMethod(this, _FormDataEncoder_instances, getFieldHeader_fn).call(this, name, value).byteLength; | ||
length += size; | ||
@@ -371,0 +353,0 @@ length += __privateGet(this, _CRLF_BYTES_LENGTH); |
@@ -5,3 +5,3 @@ { | ||
"description": "Encode FormData content into the multipart/form-data format", | ||
"version": "4.0.2", | ||
"version": "4.1.0", | ||
"author": "Nick K.", | ||
@@ -11,3 +11,2 @@ "license": "MIT", | ||
"sideEffects": false, | ||
"packageManager": "pnpm@8.5.1", | ||
"engines": { | ||
@@ -25,2 +24,5 @@ "node": ">= 18" | ||
], | ||
"files": [ | ||
"lib" | ||
], | ||
"main": "./lib/index.js", | ||
@@ -43,40 +45,27 @@ "module": "./lib/index.js", | ||
"devDependencies": { | ||
"@changesets/changelog-github": "0.4.8", | ||
"@changesets/cli": "2.26.2", | ||
"@octetstream/eslint-config": "7.2.1", | ||
"@types/mime-types": "2.1.1", | ||
"@types/node": "20.2.1", | ||
"@types/sinon": "10.0.15", | ||
"@typescript-eslint/eslint-plugin": "5.59.6", | ||
"@typescript-eslint/parser": "5.59.6", | ||
"ava": "5.2.0", | ||
"c8": "7.13.0", | ||
"@biomejs/biome": "1.8.3", | ||
"@changesets/changelog-github": "0.5.0", | ||
"@changesets/cli": "2.27.6", | ||
"@types/mime-types": "2.1.4", | ||
"@types/node": "20.14.2", | ||
"@types/sinon": "17.0.3", | ||
"ava": "6.1.3", | ||
"c8": "10.1.2", | ||
"cross-env": "7.0.3", | ||
"del-cli": "5.0.0", | ||
"eslint": "8.40.0", | ||
"eslint-config-airbnb-typescript": "17.0.0", | ||
"eslint-import-resolver-typescript": "3.5.5", | ||
"eslint-plugin-ava": "14.0.0", | ||
"eslint-plugin-import": "2.27.5", | ||
"eslint-plugin-jsx-a11y": "6.7.1", | ||
"eslint-plugin-react": "7.32.2", | ||
"formdata-node": "6.0.2", | ||
"husky": "8.0.3", | ||
"lint-staged": "13.2.2", | ||
"node-fetch": "^3.3.2", | ||
"pinst": "3.0.0", | ||
"sinon": "15.0.4", | ||
"ts-expect": "^1.3.0", | ||
"ts-node": "10.9.1", | ||
"tsup": "7.2.0", | ||
"ttypescript": "1.5.15", | ||
"typescript": "5.0.4", | ||
"undici": "^5.26.5", | ||
"web-streams-polyfill": "4.0.0-beta.3" | ||
"del-cli": "5.1.0", | ||
"formdata-node": "6.0.3", | ||
"husky": "9.0.11", | ||
"lint-staged": "15.2.7", | ||
"node-fetch": "3.3.2", | ||
"sinon": "18.0.0", | ||
"ts-expect": "1.3.0", | ||
"ts-node": "10.9.2", | ||
"tsup": "8.1.0", | ||
"typescript": "5.5.2", | ||
"undici": "6.19.2", | ||
"web-streams-polyfill": "4.0.0" | ||
}, | ||
"scripts": { | ||
"eslint": "eslint src/**/*.ts", | ||
"lint:types": "tsc --noEmit", | ||
"lint": "pnpm eslint && pnpm lint:types", | ||
"staged": "lint-staged", | ||
"lint:types": "tsc --project tsconfig.json --noEmit", | ||
"lint": "biome lint --write --no-errors-on-unmatched . && pnpm lint:types", | ||
"coverage": "c8 pnpm test", | ||
@@ -86,4 +75,5 @@ "ci": "c8 pnpm test && c8 report --reporter=json", | ||
"test": "cross-env NODE_OPTIONS=\"--no-warnings --experimental-fetch --loader=ts-node/esm\" ava", | ||
"report:html": "c8 -r=html pnpm test", | ||
"release": "pnpm build && pnpm changeset publish" | ||
} | ||
} |
@@ -212,3 +212,3 @@ # form-data-encoder | ||
// Note that node-fetch@2 performs more strictness tests for Blob objects, so you may need to do extra steps before you set up request body (like, maybe you'll need to instaniate a Blob with BlobDataItem as one of its blobPart) | ||
const blob = new BlobDataItem(enocoder) // or new Blob([new BlobDataItem(enocoder)], {type: encoder.contentType}) | ||
const blob = new BlobDataItem(encoder) // or new Blob([new BlobDataItem(encoder)], {type: encoder.contentType}) | ||
@@ -215,0 +215,0 @@ const options = { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
21
-34.37%59380
-0.6%966
-3.78%