Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
formdata.js253 linesDownload Raw Back to fetch
1'use strict'
2
3const { isBlobLike, iteratorMixin } = require('./util')
4const { kState } = require('./symbols')
5const { kEnumerableProperty } = require('../../core/util')
6const { FileLike, isFileLike } = require('./file')
7const { webidl } = require('./webidl')
8const { File: NativeFile } = require('node:buffer')
9const nodeUtil = require('node:util')
10
11/** @type {globalThis['File']} */
12const File = globalThis.File ?? NativeFile
13
14// https://xhr.spec.whatwg.org/#formdata
15class FormData {
16  constructor (form) {
17    webidl.util.markAsUncloneable(this)
18
19    if (form !== undefined) {
20      throw webidl.errors.conversionFailed({
21        prefix: 'FormData constructor',
22        argument: 'Argument 1',
23        types: ['undefined']
24      })
25    }
26
27    this[kState] = []
28  }
29
30  append (name, value, filename = undefined) {
31    webidl.brandCheck(this, FormData)
32
33    const prefix = 'FormData.append'
34    webidl.argumentLengthCheck(arguments, 2, prefix)
35
36    if (arguments.length === 3 && !isBlobLike(value)) {
37      throw new TypeError(
38        "Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'"
39      )
40    }
41
42    // 1. Let value be value if given; otherwise blobValue.
43
44    name = webidl.converters.USVString(name, prefix, 'name')
45    value = isBlobLike(value)
46      ? webidl.converters.Blob(value, prefix, 'value', { strict: false })
47      : webidl.converters.USVString(value, prefix, 'value')
48    filename = arguments.length === 3
49      ? webidl.converters.USVString(filename, prefix, 'filename')
50      : undefined
51
52    // 2. Let entry be the result of creating an entry with
53    // name, value, and filename if given.
54    const entry = makeEntry(name, value, filename)
55
56    // 3. Append entry to this’s entry list.
57    this[kState].push(entry)
58  }
59
60  delete (name) {
61    webidl.brandCheck(this, FormData)
62
63    const prefix = 'FormData.delete'
64    webidl.argumentLengthCheck(arguments, 1, prefix)
65
66    name = webidl.converters.USVString(name, prefix, 'name')
67
68    // The delete(name) method steps are to remove all entries whose name
69    // is name from this’s entry list.
70    this[kState] = this[kState].filter(entry => entry.name !== name)
71  }
72
73  get (name) {
74    webidl.brandCheck(this, FormData)
75
76    const prefix = 'FormData.get'
77    webidl.argumentLengthCheck(arguments, 1, prefix)
78
79    name = webidl.converters.USVString(name, prefix, 'name')
80
81    // 1. If there is no entry whose name is name in this’s entry list,
82    // then return null.
83    const idx = this[kState].findIndex((entry) => entry.name === name)
84    if (idx === -1) {
85      return null
86    }
87
88    // 2. Return the value of the first entry whose name is name from
89    // this’s entry list.
90    return this[kState][idx].value
91  }
92
93  getAll (name) {
94    webidl.brandCheck(this, FormData)
95
96    const prefix = 'FormData.getAll'
97    webidl.argumentLengthCheck(arguments, 1, prefix)
98
99    name = webidl.converters.USVString(name, prefix, 'name')
100
101    // 1. If there is no entry whose name is name in this’s entry list,
102    // then return the empty list.
103    // 2. Return the values of all entries whose name is name, in order,
104    // from this’s entry list.
105    return this[kState]
106      .filter((entry) => entry.name === name)
107      .map((entry) => entry.value)
108  }
109
110  has (name) {
111    webidl.brandCheck(this, FormData)
112
113    const prefix = 'FormData.has'
114    webidl.argumentLengthCheck(arguments, 1, prefix)
115
116    name = webidl.converters.USVString(name, prefix, 'name')
117
118    // The has(name) method steps are to return true if there is an entry
119    // whose name is name in this’s entry list; otherwise false.
120    return this[kState].findIndex((entry) => entry.name === name) !== -1
121  }
122
123  set (name, value, filename = undefined) {
124    webidl.brandCheck(this, FormData)
125
126    const prefix = 'FormData.set'
127    webidl.argumentLengthCheck(arguments, 2, prefix)
128
129    if (arguments.length === 3 && !isBlobLike(value)) {
130      throw new TypeError(
131        "Failed to execute 'set' on 'FormData': parameter 2 is not of type 'Blob'"
132      )
133    }
134
135    // The set(name, value) and set(name, blobValue, filename) method steps
136    // are:
137
138    // 1. Let value be value if given; otherwise blobValue.
139
140    name = webidl.converters.USVString(name, prefix, 'name')
141    value = isBlobLike(value)
142      ? webidl.converters.Blob(value, prefix, 'name', { strict: false })
143      : webidl.converters.USVString(value, prefix, 'name')
144    filename = arguments.length === 3
145      ? webidl.converters.USVString(filename, prefix, 'name')
146      : undefined
147
148    // 2. Let entry be the result of creating an entry with name, value, and
149    // filename if given.
150    const entry = makeEntry(name, value, filename)
151
152    // 3. If there are entries in this’s entry list whose name is name, then
153    // replace the first such entry with entry and remove the others.
154    const idx = this[kState].findIndex((entry) => entry.name === name)
155    if (idx !== -1) {
156      this[kState] = [
157        ...this[kState].slice(0, idx),
158        entry,
159        ...this[kState].slice(idx + 1).filter((entry) => entry.name !== name)
160      ]
161    } else {
162      // 4. Otherwise, append entry to this’s entry list.
163      this[kState].push(entry)
164    }
165  }
166
167  [nodeUtil.inspect.custom] (depth, options) {
168    const state = this[kState].reduce((a, b) => {
169      if (a[b.name]) {
170        if (Array.isArray(a[b.name])) {
171          a[b.name].push(b.value)
172        } else {
173          a[b.name] = [a[b.name], b.value]
174        }
175      } else {
176        a[b.name] = b.value
177      }
178
179      return a
180    }, { __proto__: null })
181
182    options.depth ??= depth
183    options.colors ??= true
184
185    const output = nodeUtil.formatWithOptions(options, state)
186
187    // remove [Object null prototype]
188    return `FormData ${output.slice(output.indexOf(']') + 2)}`
189  }
190}
191
192iteratorMixin('FormData', FormData, kState, 'name', 'value')
193
194Object.defineProperties(FormData.prototype, {
195  append: kEnumerableProperty,
196  delete: kEnumerableProperty,
197  get: kEnumerableProperty,
198  getAll: kEnumerableProperty,
199  has: kEnumerableProperty,
200  set: kEnumerableProperty,
201  [Symbol.toStringTag]: {
202    value: 'FormData',
203    configurable: true
204  }
205})
206
207/**
208 * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#create-an-entry
209 * @param {string} name
210 * @param {string|Blob} value
211 * @param {?string} filename
212 * @returns
213 */
214function makeEntry (name, value, filename) {
215  // 1. Set name to the result of converting name into a scalar value string.
216  // Note: This operation was done by the webidl converter USVString.
217
218  // 2. If value is a string, then set value to the result of converting
219  //    value into a scalar value string.
220  if (typeof value === 'string') {
221    // Note: This operation was done by the webidl converter USVString.
222  } else {
223    // 3. Otherwise:
224
225    // 1. If value is not a File object, then set value to a new File object,
226    //    representing the same bytes, whose name attribute value is "blob"
227    if (!isFileLike(value)) {
228      value = value instanceof Blob
229        ? new File([value], 'blob', { type: value.type })
230        : new FileLike(value, 'blob', { type: value.type })
231    }
232
233    // 2. If filename is given, then set value to a new File object,
234    //    representing the same bytes, whose name attribute is filename.
235    if (filename !== undefined) {
236      /** @type {FilePropertyBag} */
237      const options = {
238        type: value.type,
239        lastModified: value.lastModified
240      }
241
242      value = value instanceof NativeFile
243        ? new File([value], filename, options)
244        : new FileLike(value, filename, options)
245    }
246  }
247
248  // 4. Return an entry whose name is name and whose value is value.
249  return { name, value }
250}
251
252module.exports = { FormData, makeEntry }
253 
codekingpro/portable-devtools · Team Ai