{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { type JSONValue, type JSONValidMap, type JSONValidObject } from \"json-types2\";\r\n\r\nexport * from \"maps-diff\";\r\n\r\n// export const getValueSymbol: symbol = Symbol(\"getValue\");\r\n\r\nexport interface IFormToSerializableOptions {\r\n\tmutator?: IFormMapMutatorFunction;\r\n\tappend?: IFormAppend;\r\n\tprepend?: IFormAppend;\r\n}\r\n\r\nexport const formDataToObject = (fd: FormData) =>\r\n\tObject.fromEntries(\r\n\t\tArray.from(fd.keys()).map((key) => {\r\n\t\t\tconst fdAll = fd.getAll(key);\r\n\t\t\treturn [key, fdAll.length > 1 ? fdAll : fd.get(key)];\r\n\t\t})\r\n\t);\r\n\r\nexport const formById = (formId: string) => document.getElementById(formId) as HTMLFormElement;\r\n\r\nexport const formDataToJson = (fd: FormData) => JSON.stringify(formDataToObject(fd));\r\n\r\nexport const formToJson = (form: HTMLFormElement) => formDataToJson(new FormData(form));\r\n\r\nexport const formToJsonById = (formId: string) => formToJson(formById(formId));\r\n\r\n// export const FormToObject = (form: HTMLFormElement) => FormDataToObject(new FormData(form));\r\n\r\n// export const FormToObjectById = (formId: string) => FormToObject(FormById(formId));\r\n\r\nexport const mapToObject = Object.fromEntries;\r\n\r\nexport const formToObject = (form: HTMLFormElement, options?: IFormToSerializableOptions) =>\r\n\tmapToObject(formToMap(form, options));\r\n\r\nexport const formToObjectById = (formId: string, options?: IFormToSerializableOptions) =>\r\n\tformToObject(formById(formId), options);\r\n\r\nexport const formToMapById = (formId: string, options?: IFormToSerializableOptions) => formToMap(formById(formId), options);\r\n\r\n/**\r\n * Represents a function that mutates a key-value pair. The function **must** return a value, or the key-value pair will be deleted.\r\n * The value is also deleted if the function returns `undefined`.\r\n * @param key - The key to be mutated.\r\n * @param value - The value to be mutated.\r\n * @returns The mutated value.\r\n */\r\nexport type IFormMapMutatorFunction = (key: string, value: JSONValue) => JSONValue;\r\n\r\nexport type IFormAppend = JSONValidMap | JSONValidObject;\r\n\r\n/**\r\n * Converts an HTML form element into a Map object, where the keys are the names of the form inputs\r\n * and the values are the corresponding values of the form inputs.\r\n *\r\n * @param formElement - The HTML form element to be converted.\r\n * @param options - (Optional) An object containing the following options:\r\n *   - mutator: A function that mutates key-value pairs. The function **must** return a value, or all the key-value pairs will be deleted.\r\n *     The value is also deleted if the function returns `undefined`.\r\n *   - append: A map or object containing additional key-value pairs to be appended to the resulting map.\r\n *   - prepend: A map or object containing additional key-value pairs to be prepended to the resulting map.\r\n * @returns A Map object containing the form input names as keys and their corresponding values as values.\r\n *\r\n * @remarks\r\n * This function supports the following:\r\n * - HTML form elements names.\r\n * - Text inputs, text-areas, checkboxes, radio buttons, and select elements.\r\n * - Multiple select elements (returns an array of selected values).\r\n * - Custom mutator function to modify the values before they are added to the map.\r\n * - Appending additional key-value pairs to the resulting map.\r\n * - Prepending additional key-value pairs to the resulting map.\r\n * - Custom form elements with a `getValue()` method that returns the value of the element.\r\n *\r\n * This function does not support the following:\r\n * - HTML form inputs without a `name` attribute.\r\n * - File inputs (returns an empty string for file inputs).\r\n *\r\n * If the form element contains multiple inputs with the same name, the values will be added to the map as an array.\r\n *\r\n * It also supports and tries to call a `getValue()` method on the form's children, if it exists.\r\n * This is useful for custom form elements that need to do some processing before returning their value.\r\n * The value returned by `getValue()` should be JSON-serializable.\r\n *\r\n * @example\r\n * // Example 1: Converting a simple form with text inputs\r\n * const formElement = document.getElementById(\"myForm\") as HTMLFormElement;\r\n * const formMap = FormToMap(formElement);\r\n * // Output: Map { \"firstName\" => \"John\", \"lastName\" => \"Doe\" }\r\n *\r\n * @example\r\n * // Example 2: Converting a form with checkboxes and radio buttons\r\n * const formElement = document.getElementById(\"myForm\") as HTMLFormElement;\r\n * const formMap = FormToMap(formElement);\r\n * // Output: Map { \"color\" => \"blue\", \"size\" => \"medium\", \"agree\" => true }\r\n *\r\n * @example\r\n * // Example 3: Converting a form with a multiple select element\r\n * const formElement = document.getElementById(\"myForm\") as HTMLFormElement;\r\n * const formMap = FormToMap(formElement);\r\n * // Output: Map { \"fruits\" => [\"apple\", \"banana\", \"orange\"] }\r\n *\r\n * @example\r\n * // Example 4: Using a custom mutator function\r\n * const formElement = document.getElementById(\"myForm\") as HTMLFormElement;\r\n * const mutator = (key: string, value: string | string[]) => typeof value === \"string\" ? value.toUpperCase() : value;\r\n * const formMap = FormToMap(formElement, { mutator });\r\n * // Output: Map { \"firstName\" => \"JOHN\", \"lastName\" => \"DOE\" }\r\n *\r\n * @example\r\n * // Example 5: Appending additional key-value pairs\r\n * const formElement = document.getElementById(\"myForm\") as HTMLFormElement;\r\n * const append = { additionalKey: \"additionalValue\" };\r\n * const formMap = FormToMap(formElement, { append });\r\n * // Output: Map { \"firstName\" => \"John\", \"lastName\" => \"Doe\", \"additionalKey\" => \"additionalValue\" }\r\n *\r\n * @example\r\n * // Example 6: Prepending additional key-value pairs\r\n * const formElement = document.getElementById(\"myForm\") as HTMLFormElement;\r\n * const append = { additionalKey: \"additionalValue\" };\r\n * const formMap = FormToMap(formElement, { prepend });\r\n * // Output: Map { \"additionalKey\" => \"additionalValue\", \"firstName\" => \"John\", \"lastName\" => \"Doe\" }\r\n */\r\nexport function formToMap(\r\n\tformElement: HTMLFormElement,\r\n\t{ mutator, append, prepend }: IFormToSerializableOptions = {}\r\n): JSONValidMap {\r\n\tif (!formElement || !(formElement instanceof HTMLFormElement)) {\r\n\t\tthrow new Error(\"The form element must be an HTMLFormElement.\");\r\n\t}\r\n\r\n\tconst data = new Map<string, JSONValue>();\r\n\r\n\tif (prepend) {\r\n\t\tif (prepend instanceof Map) {\r\n\t\t\tprepend.forEach((value, key) => {\r\n\t\t\t\tdata.set(key, value);\r\n\t\t\t});\r\n\t\t} else if (typeof prepend === \"object\") {\r\n\t\t\tObject.entries(prepend).forEach(([key, value]) => {\r\n\t\t\t\tdata.set(key, value);\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tconst children = [\r\n\t\t...formElement.querySelectorAll(\r\n\t\t\t// \"input[name]:enabled:not([type=button]):not([type=reset]), select[name]:enabled, textarea[name]:enabled, keygen[name]:enabled\",\r\n\t\t\t// \":is(input, select, textarea)[name]:enabled:not(:is([type=submit], [type=button], [type=reset]))\",\r\n\t\t\t\":is(input, select, textarea)[name]:enabled\"\r\n\t\t),\r\n\t];\r\n\r\n\tconst childrenLength = children.length;\r\n\r\n\tfor (let i = 0; i < childrenLength; i++) {\r\n\t\tconst child = children[i] as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\r\n\r\n\t\tif (!child) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t/* if (\r\n\t\t\tQ![\"input\", \"select\", \"textarea\"].includes(child.tagName.toLowerCase()) ||\r\n\t\t\t[\"submit\", \"button\", \"reset\"].includes(child.type.toLowerCase()) ||\r\n\t\t\tchild.disabled ||\r\n\t\t\tQ!child.name\r\n\t\t) {\r\n\t\t\tcontinue;\r\n\t\t} */\r\n\r\n\t\tif ([\"submit\", \"button\", \"reset\", \"file\"].includes(child.type.toLowerCase())) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst childName = child.name;\r\n\t\tconst childValue = getChildValue(child);\r\n\r\n\t\tconst previousValue = data.get(childName);\r\n\r\n\t\tif (previousValue == null) {\r\n\t\t\tdata.set(childName, childValue);\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (childValue == null) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (Array.isArray(previousValue)) {\r\n\t\t\tif (Array.isArray(childValue)) {\r\n\t\t\t\tpreviousValue.push(...childValue);\r\n\t\t\t} else {\r\n\t\t\t\tpreviousValue.push(childValue);\r\n\t\t\t}\r\n\t\t\tdata.set(childName, previousValue);\r\n\t\t} else {\r\n\t\t\tif (Array.isArray(childValue)) {\r\n\t\t\t\tdata.set(childName, [previousValue, ...childValue]);\r\n\t\t\t} else {\r\n\t\t\t\tdata.set(childName, [previousValue, childValue]);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif (append) {\r\n\t\tif (append instanceof Map) {\r\n\t\t\tappend.forEach((value, key) => {\r\n\t\t\t\tdata.set(key, value);\r\n\t\t\t});\r\n\t\t} else if (typeof append === \"object\") {\r\n\t\t\tObject.entries(append).forEach(([key, value]) => {\r\n\t\t\t\tdata.set(key, value);\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tif (mutator) {\r\n\t\tdata.forEach((value, key) => {\r\n\t\t\tconst newValue = mutator(key, value);\r\n\r\n\t\t\tif (newValue === undefined) {\r\n\t\t\t\tdata.delete(key);\r\n\t\t\t} else if (newValue !== value) {\r\n\t\t\t\tdata.set(key, newValue);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\treturn data;\r\n}\r\n\r\nfunction getChildValue(child: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement) {\r\n\tif (\"getValue\" in child && typeof child.getValue === \"function\") {\r\n\t\treturn child.getValue() as JSONValue;\r\n\t}\r\n\r\n\tlet childValue: string | string[] = child.value;\r\n\r\n\t// If the child is a select-multiple element, get the values of the selected options\r\n\tif (child instanceof HTMLSelectElement && child.multiple) {\r\n\t\tchildValue = Array.from(child.selectedOptions).map((option) => option.value);\r\n\t}\r\n\r\n\tconst isInputCheckable = child instanceof HTMLInputElement && [\"checkbox\", \"radio\"].includes(child.type.toLowerCase());\r\n\r\n\tif (isInputCheckable) {\r\n\t\t// Only add the value if it's checked\r\n\t\t/* if (!child.checked) {\r\n\t\t\tcontinue;\r\n\t\t} */\r\n\r\n\t\t// Add a falsy value if it's not checked\r\n\t\tchildValue = child.checked ? childValue : null;\r\n\t}\r\n\r\n\treturn childValue;\r\n}\r\n"],"names":["formDataToObject","fd","Object","fromEntries","Array","from","keys","map","key","fdAll","getAll","length","get","formById","formId","document","getElementById","formDataToJson","JSON","stringify","formToJson","form","FormData","mapToObject","formToObject","options","formToMap","formElement","_temp","_ref","mutator","append","prepend","HTMLFormElement","Error","data","Map","forEach","value","set","entries","_ref2","children","concat","querySelectorAll","childrenLength","i","child","includes","type","toLowerCase","childName","name","childValue","getChildValue","previousValue","isArray","push","apply","_ref3","newValue","undefined","getValue","HTMLSelectElement","multiple","selectedOptions","option","HTMLInputElement","checked"],"mappings":"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"}