UNPKG

@uppercod/form-tools

Version:
104 lines (100 loc) 2.71 kB
/** * instance to identify a value * @param {*} value */ function Value(value) { this.value = value; } /** * returns a property path from an expression * @param {string} path * @returns {string[]} */ export const getPath = (path) => path.match(/(\[\d+\]|\w+)/g); /** * create an object from a path * @param {string[]} path * @param {*} value * @returns {[string,any]} */ export const createObjectFromPath = (path, value) => // @ts-ignore path.reverse().reduce((value, prop) => [prop, value], new Value(value)); /** * @template {Object<string,any>} T * @param {T} [defaultData] * @returns {(target:HTMLFormElement)=>any} */ /** * * @param {*} parent * @param {[string,any]} next */ export function extend(parent, [name, value]) { if (value instanceof Value) { parent[name] = value.value; } else { const [nextName, nextValue] = value; const test = nextName.match(/^\[(\d+)\]$/); let current = parent[name]; if (test) { const [, index] = test; value = [index, nextValue]; } if (current == null) { current = test ? [] : {}; extend(current, value); } else { extend(current, value); } parent[name] = test ? current.filter((value) => value) : current; } return parent; } /** * * @param {string} name * @param {Element & {type?:string, value?:string,checked?:boolean}} input * @returns {number|string|boolean} */ export const getValueFromInput = (name, input) => { const isRadioList = input instanceof RadioNodeList; const withvalue = isRadioList ? true : input.hasAttribute("value"); const { type, value, checked } = input; const isSwitch = type == "radio" || type == "checkbox"; const isNumber = type == "number"; return isSwitch ? withvalue ? checked ? value : null : checked : isRadioList && value === "" ? null : isNumber ? Number(value) : value; }; export const formToObject = (defaultData) => (target) => { const elements = Object.entries(target.elements).filter( ([prop]) => !/^\d+$/.test(prop) ); const data = elements.reduce( /** * * @param {Object<string,any>} data * @param {[string,HTMLInputElement]} entry * @returns */ (data, [name, input]) => extend( data, createObjectFromPath( getPath(name), getValueFromInput(name, input) ) ), { ...defaultData } ); return data; };