aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/undici/lib/web/fetch/formdata.js
diff options
context:
space:
mode:
Diffstat (limited to 'vanilla/node_modules/undici/lib/web/fetch/formdata.js')
-rw-r--r--vanilla/node_modules/undici/lib/web/fetch/formdata.js259
1 files changed, 259 insertions, 0 deletions
diff --git a/vanilla/node_modules/undici/lib/web/fetch/formdata.js b/vanilla/node_modules/undici/lib/web/fetch/formdata.js
new file mode 100644
index 0000000..c21fb06
--- /dev/null
+++ b/vanilla/node_modules/undici/lib/web/fetch/formdata.js
@@ -0,0 +1,259 @@
+'use strict'
+
+const { iteratorMixin } = require('./util')
+const { kEnumerableProperty } = require('../../core/util')
+const { webidl } = require('../webidl')
+const nodeUtil = require('node:util')
+
+// https://xhr.spec.whatwg.org/#formdata
+class FormData {
+ #state = []
+
+ constructor (form = undefined) {
+ webidl.util.markAsUncloneable(this)
+
+ if (form !== undefined) {
+ throw webidl.errors.conversionFailed({
+ prefix: 'FormData constructor',
+ argument: 'Argument 1',
+ types: ['undefined']
+ })
+ }
+ }
+
+ append (name, value, filename = undefined) {
+ webidl.brandCheck(this, FormData)
+
+ const prefix = 'FormData.append'
+ webidl.argumentLengthCheck(arguments, 2, prefix)
+
+ name = webidl.converters.USVString(name)
+
+ if (arguments.length === 3 || webidl.is.Blob(value)) {
+ value = webidl.converters.Blob(value, prefix, 'value')
+
+ if (filename !== undefined) {
+ filename = webidl.converters.USVString(filename)
+ }
+ } else {
+ value = webidl.converters.USVString(value)
+ }
+
+ // 1. Let value be value if given; otherwise blobValue.
+
+ // 2. Let entry be the result of creating an entry with
+ // name, value, and filename if given.
+ const entry = makeEntry(name, value, filename)
+
+ // 3. Append entry to this’s entry list.
+ this.#state.push(entry)
+ }
+
+ delete (name) {
+ webidl.brandCheck(this, FormData)
+
+ const prefix = 'FormData.delete'
+ webidl.argumentLengthCheck(arguments, 1, prefix)
+
+ name = webidl.converters.USVString(name)
+
+ // The delete(name) method steps are to remove all entries whose name
+ // is name from this’s entry list.
+ this.#state = this.#state.filter(entry => entry.name !== name)
+ }
+
+ get (name) {
+ webidl.brandCheck(this, FormData)
+
+ const prefix = 'FormData.get'
+ webidl.argumentLengthCheck(arguments, 1, prefix)
+
+ name = webidl.converters.USVString(name)
+
+ // 1. If there is no entry whose name is name in this’s entry list,
+ // then return null.
+ const idx = this.#state.findIndex((entry) => entry.name === name)
+ if (idx === -1) {
+ return null
+ }
+
+ // 2. Return the value of the first entry whose name is name from
+ // this’s entry list.
+ return this.#state[idx].value
+ }
+
+ getAll (name) {
+ webidl.brandCheck(this, FormData)
+
+ const prefix = 'FormData.getAll'
+ webidl.argumentLengthCheck(arguments, 1, prefix)
+
+ name = webidl.converters.USVString(name)
+
+ // 1. If there is no entry whose name is name in this’s entry list,
+ // then return the empty list.
+ // 2. Return the values of all entries whose name is name, in order,
+ // from this’s entry list.
+ return this.#state
+ .filter((entry) => entry.name === name)
+ .map((entry) => entry.value)
+ }
+
+ has (name) {
+ webidl.brandCheck(this, FormData)
+
+ const prefix = 'FormData.has'
+ webidl.argumentLengthCheck(arguments, 1, prefix)
+
+ name = webidl.converters.USVString(name)
+
+ // The has(name) method steps are to return true if there is an entry
+ // whose name is name in this’s entry list; otherwise false.
+ return this.#state.findIndex((entry) => entry.name === name) !== -1
+ }
+
+ set (name, value, filename = undefined) {
+ webidl.brandCheck(this, FormData)
+
+ const prefix = 'FormData.set'
+ webidl.argumentLengthCheck(arguments, 2, prefix)
+
+ name = webidl.converters.USVString(name)
+
+ if (arguments.length === 3 || webidl.is.Blob(value)) {
+ value = webidl.converters.Blob(value, prefix, 'value')
+
+ if (filename !== undefined) {
+ filename = webidl.converters.USVString(filename)
+ }
+ } else {
+ value = webidl.converters.USVString(value)
+ }
+
+ // The set(name, value) and set(name, blobValue, filename) method steps
+ // are:
+
+ // 1. Let value be value if given; otherwise blobValue.
+
+ // 2. Let entry be the result of creating an entry with name, value, and
+ // filename if given.
+ const entry = makeEntry(name, value, filename)
+
+ // 3. If there are entries in this’s entry list whose name is name, then
+ // replace the first such entry with entry and remove the others.
+ const idx = this.#state.findIndex((entry) => entry.name === name)
+ if (idx !== -1) {
+ this.#state = [
+ ...this.#state.slice(0, idx),
+ entry,
+ ...this.#state.slice(idx + 1).filter((entry) => entry.name !== name)
+ ]
+ } else {
+ // 4. Otherwise, append entry to this’s entry list.
+ this.#state.push(entry)
+ }
+ }
+
+ [nodeUtil.inspect.custom] (depth, options) {
+ const state = this.#state.reduce((a, b) => {
+ if (a[b.name]) {
+ if (Array.isArray(a[b.name])) {
+ a[b.name].push(b.value)
+ } else {
+ a[b.name] = [a[b.name], b.value]
+ }
+ } else {
+ a[b.name] = b.value
+ }
+
+ return a
+ }, { __proto__: null })
+
+ options.depth ??= depth
+ options.colors ??= true
+
+ const output = nodeUtil.formatWithOptions(options, state)
+
+ // remove [Object null prototype]
+ return `FormData ${output.slice(output.indexOf(']') + 2)}`
+ }
+
+ /**
+ * @param {FormData} formData
+ */
+ static getFormDataState (formData) {
+ return formData.#state
+ }
+
+ /**
+ * @param {FormData} formData
+ * @param {any[]} newState
+ */
+ static setFormDataState (formData, newState) {
+ formData.#state = newState
+ }
+}
+
+const { getFormDataState, setFormDataState } = FormData
+Reflect.deleteProperty(FormData, 'getFormDataState')
+Reflect.deleteProperty(FormData, 'setFormDataState')
+
+iteratorMixin('FormData', FormData, getFormDataState, 'name', 'value')
+
+Object.defineProperties(FormData.prototype, {
+ append: kEnumerableProperty,
+ delete: kEnumerableProperty,
+ get: kEnumerableProperty,
+ getAll: kEnumerableProperty,
+ has: kEnumerableProperty,
+ set: kEnumerableProperty,
+ [Symbol.toStringTag]: {
+ value: 'FormData',
+ configurable: true
+ }
+})
+
+/**
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#create-an-entry
+ * @param {string} name
+ * @param {string|Blob} value
+ * @param {?string} filename
+ * @returns
+ */
+function makeEntry (name, value, filename) {
+ // 1. Set name to the result of converting name into a scalar value string.
+ // Note: This operation was done by the webidl converter USVString.
+
+ // 2. If value is a string, then set value to the result of converting
+ // value into a scalar value string.
+ if (typeof value === 'string') {
+ // Note: This operation was done by the webidl converter USVString.
+ } else {
+ // 3. Otherwise:
+
+ // 1. If value is not a File object, then set value to a new File object,
+ // representing the same bytes, whose name attribute value is "blob"
+ if (!webidl.is.File(value)) {
+ value = new File([value], 'blob', { type: value.type })
+ }
+
+ // 2. If filename is given, then set value to a new File object,
+ // representing the same bytes, whose name attribute is filename.
+ if (filename !== undefined) {
+ /** @type {FilePropertyBag} */
+ const options = {
+ type: value.type,
+ lastModified: value.lastModified
+ }
+
+ value = new File([value], filename, options)
+ }
+ }
+
+ // 4. Return an entry whose name is name and whose value is value.
+ return { name, value }
+}
+
+webidl.is.FormData = webidl.util.MakeTypeAssertion(FormData)
+
+module.exports = { FormData, makeEntry, setFormDataState }