- ✅ Ticket 1.1: Estructura Clean Architecture en backend - ✅ Ticket 1.2: Schemas Zod compartidos - ✅ Ticket 1.3: Refactorización drugs.ts (1362 → 8 archivos modulares) - ✅ Ticket 1.4: Refactorización procedures.ts (3583 → 6 archivos modulares) - ✅ Ticket 1.5: Eliminación de duplicidades (~50 líneas) Cambios principales: - Creada estructura Clean Architecture en backend/src/ - Schemas Zod compartidos en backend/src/shared/schemas/ - Refactorización modular de drugs y procedures - Utilidades genéricas en src/utils/ (filter, validation) - Eliminados scripts obsoletos y documentación antigua - Corregidos errores: QueryClient, import test-error-handling - Build verificado y funcionando correctamente
249 lines
7.8 KiB
JavaScript
249 lines
7.8 KiB
JavaScript
import Blob from '../file/Blob.js';
|
|
import * as PropertySymbol from '../PropertySymbol.js';
|
|
import File from '../file/File.js';
|
|
import DOMExceptionNameEnum from '../exception/DOMExceptionNameEnum.js';
|
|
/**
|
|
* FormData.
|
|
*
|
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/FormData
|
|
*/
|
|
export default class FormData {
|
|
#entries = [];
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param [form] Form.
|
|
* @param [submitter] The element that triggered the submission if this came from a form submit.
|
|
*/
|
|
constructor(form, submitter) {
|
|
if (!form) {
|
|
return;
|
|
}
|
|
if (submitter) {
|
|
const formProxy = form[PropertySymbol.proxy] ? form[PropertySymbol.proxy] : form;
|
|
if (submitter.form !== formProxy) {
|
|
throw new this[PropertySymbol.window].DOMException('The specified element is not owned by this form element', DOMExceptionNameEnum.notFoundError);
|
|
}
|
|
const isSubmitButton = (submitter[PropertySymbol.tagName] === 'INPUT' &&
|
|
(submitter.type === 'submit' || submitter.type === 'image')) ||
|
|
(submitter[PropertySymbol.tagName] === 'BUTTON' && submitter.type === 'submit');
|
|
if (!isSubmitButton) {
|
|
throw new this[PropertySymbol.window].TypeError('The specified element is not a submit button');
|
|
}
|
|
}
|
|
const items = form[PropertySymbol.getFormControlItems]();
|
|
for (const item of items) {
|
|
const name = item.name;
|
|
if (name) {
|
|
switch (item[PropertySymbol.tagName]) {
|
|
case 'INPUT':
|
|
if (item.disabled) {
|
|
break;
|
|
}
|
|
switch (item.type) {
|
|
case 'file':
|
|
if (item[PropertySymbol.files].length === 0) {
|
|
this.append(name, new File([], '', { type: 'application/octet-stream' }));
|
|
}
|
|
else {
|
|
for (const file of item[PropertySymbol.files]) {
|
|
this.append(name, file);
|
|
}
|
|
}
|
|
break;
|
|
case 'checkbox':
|
|
case 'radio':
|
|
if (item.checked) {
|
|
this.append(name, item.value);
|
|
}
|
|
break;
|
|
case 'submit':
|
|
case 'reset':
|
|
case 'button':
|
|
if (item === submitter && item.value) {
|
|
this.append(name, item.value);
|
|
}
|
|
break;
|
|
default:
|
|
this.append(name, item.value);
|
|
break;
|
|
}
|
|
break;
|
|
case 'BUTTON':
|
|
if (item === submitter && item.value) {
|
|
this.append(name, item.value);
|
|
}
|
|
break;
|
|
case 'TEXTAREA':
|
|
case 'SELECT':
|
|
this.append(name, item.value);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* For each.
|
|
*
|
|
* @param callback Callback.
|
|
* @param thisArg thisArg.
|
|
*/
|
|
forEach(callback, thisArg) {
|
|
for (const entry of this.#entries) {
|
|
callback.call(thisArg, entry.value, entry.name, this);
|
|
}
|
|
}
|
|
/**
|
|
* Appends a new value onto an existing key.
|
|
*
|
|
* @param name Name.
|
|
* @param value Value.
|
|
* @param [filename] Filename.
|
|
*/
|
|
append(name, value, filename) {
|
|
if (filename && !(value instanceof Blob)) {
|
|
throw new this[PropertySymbol.window].TypeError('Failed to execute "append" on "FormData": parameter 2 is not of type "Blob".');
|
|
}
|
|
this.#entries.push({
|
|
name,
|
|
value: this.#parseValue(value, filename)
|
|
});
|
|
}
|
|
/**
|
|
* Removes a value.
|
|
*
|
|
* @param name Name.
|
|
*/
|
|
delete(name) {
|
|
const newEntries = [];
|
|
for (const entry of this.#entries) {
|
|
if (entry.name !== name) {
|
|
newEntries.push(entry);
|
|
}
|
|
}
|
|
this.#entries = newEntries;
|
|
}
|
|
/**
|
|
* Returns value.
|
|
*
|
|
* @param name Name.
|
|
* @returns Value.
|
|
*/
|
|
get(name) {
|
|
for (const entry of this.#entries) {
|
|
if (entry.name === name) {
|
|
return entry.value;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
/**
|
|
* Returns all values associated with the given name.
|
|
*
|
|
* @param name Name.
|
|
* @returns Values.
|
|
*/
|
|
getAll(name) {
|
|
const values = [];
|
|
for (const entry of this.#entries) {
|
|
if (entry.name === name) {
|
|
values.push(entry.value);
|
|
}
|
|
}
|
|
return values;
|
|
}
|
|
/**
|
|
* Returns whether a FormData object contains a certain key.
|
|
*
|
|
* @param name Name.
|
|
* @returns "true" if the FormData object contains the key.
|
|
*/
|
|
has(name) {
|
|
for (const entry of this.#entries) {
|
|
if (entry.name === name) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* Sets a new value for an existing key inside a FormData object, or adds the key/value if it does not already exist.
|
|
*
|
|
* @param name Name.
|
|
* @param value Value.
|
|
* @param [filename] Filename.
|
|
*/
|
|
set(name, value, filename) {
|
|
for (const entry of this.#entries) {
|
|
if (entry.name === name) {
|
|
entry.value = this.#parseValue(value, filename);
|
|
return;
|
|
}
|
|
}
|
|
this.append(name, value);
|
|
}
|
|
/**
|
|
* Returns an iterator, allowing you to go through all keys of the key/value pairs contained in this object.
|
|
*
|
|
* @returns Iterator.
|
|
*/
|
|
*keys() {
|
|
for (const entry of this.#entries) {
|
|
yield entry.name;
|
|
}
|
|
}
|
|
/**
|
|
* Returns an iterator, allowing you to go through all values of the key/value pairs contained in this object.
|
|
*
|
|
* @returns Iterator.
|
|
*/
|
|
*values() {
|
|
for (const entry of this.#entries) {
|
|
yield entry.value;
|
|
}
|
|
}
|
|
/**
|
|
* Returns an iterator, allowing you to go through all key/value pairs contained in this object.
|
|
*
|
|
* @returns Iterator.
|
|
*/
|
|
*entries() {
|
|
for (const entry of this.#entries) {
|
|
yield [entry.name, entry.value];
|
|
}
|
|
}
|
|
/**
|
|
* Iterator.
|
|
*
|
|
* @returns Iterator.
|
|
*/
|
|
*[Symbol.iterator]() {
|
|
for (const entry of this.#entries) {
|
|
yield [entry.name, entry.value];
|
|
}
|
|
}
|
|
/**
|
|
* Parses a value.
|
|
*
|
|
* @param value Value.
|
|
* @param [filename] Filename.
|
|
* @returns Parsed value.
|
|
*/
|
|
#parseValue(value, filename) {
|
|
if (value instanceof File) {
|
|
if (filename) {
|
|
const file = new File([], filename, { type: value.type, lastModified: value.lastModified });
|
|
file[PropertySymbol.buffer] = value[PropertySymbol.buffer];
|
|
return file;
|
|
}
|
|
return value;
|
|
}
|
|
if (value instanceof Blob) {
|
|
const file = new File([], 'blob', { type: value.type });
|
|
file[PropertySymbol.buffer] = value[PropertySymbol.buffer];
|
|
return file;
|
|
}
|
|
return String(value);
|
|
}
|
|
}
|
|
//# sourceMappingURL=FormData.js.map
|