@tanstack/form-core 1.19.2 → 1.19.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/FieldApi.cjs +80 -24
- package/dist/cjs/FieldApi.cjs.map +1 -1
- package/dist/cjs/FieldApi.d.cts +11 -8
- package/dist/cjs/FormApi.cjs +31 -15
- package/dist/cjs/FormApi.cjs.map +1 -1
- package/dist/cjs/FormApi.d.cts +16 -8
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/types.d.cts +8 -0
- package/dist/cjs/utils.cjs +7 -0
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +5 -0
- package/dist/esm/FieldApi.d.ts +11 -8
- package/dist/esm/FieldApi.js +81 -25
- package/dist/esm/FieldApi.js.map +1 -1
- package/dist/esm/FormApi.d.ts +16 -8
- package/dist/esm/FormApi.js +32 -16
- package/dist/esm/FormApi.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/types.d.ts +8 -0
- package/dist/esm/utils.d.ts +5 -0
- package/dist/esm/utils.js +7 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/FieldApi.ts +86 -25
- package/src/FormApi.ts +45 -15
- package/src/types.ts +8 -0
- package/src/utils.ts +15 -0
package/dist/esm/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import { defaultValidationLogic } from './ValidationLogic'\nimport type { ValidationLogicProps } from './ValidationLogic'\nimport type { FieldValidators } from './FieldApi'\nimport type { FormValidators } from './FormApi'\nimport type {\n GlobalFormValidationError,\n ValidationCause,\n ValidationError,\n ValidationSource,\n} from './types'\n\nexport type UpdaterFn<TInput, TOutput = TInput> = (input: TInput) => TOutput\n\nexport type Updater<TInput, TOutput = TInput> =\n | TOutput\n | UpdaterFn<TInput, TOutput>\n\n/**\n * @private\n */\nexport function functionalUpdate<TInput, TOutput = TInput>(\n updater: Updater<TInput, TOutput>,\n input: TInput,\n): TOutput {\n return typeof updater === 'function'\n ? (updater as UpdaterFn<TInput, TOutput>)(input)\n : updater\n}\n\n/**\n * Get a value from an object using a path, including dot notation.\n * @private\n */\nexport function getBy(obj: any, path: any) {\n const pathObj = makePathArray(path)\n return pathObj.reduce((current: any, pathPart: any) => {\n if (current === null) return null\n if (typeof current !== 'undefined') {\n return current[pathPart]\n }\n return undefined\n }, obj)\n}\n\n/**\n * Set a value on an object using a path, including dot notation.\n * @private\n */\nexport function setBy(obj: any, _path: any, updater: Updater<any>) {\n const path = makePathArray(_path)\n\n function doSet(parent?: any): any {\n if (!path.length) {\n return functionalUpdate(updater, parent)\n }\n\n const key = path.shift()\n\n if (\n typeof key === 'string' ||\n (typeof key === 'number' && !Array.isArray(parent))\n ) {\n if (typeof parent === 'object') {\n if (parent === null) {\n parent = {}\n }\n return {\n ...parent,\n [key]: doSet(parent[key]),\n }\n }\n return {\n [key]: doSet(),\n }\n }\n\n if (Array.isArray(parent) && typeof key === 'number') {\n const prefix = parent.slice(0, key)\n return [\n ...(prefix.length ? prefix : new Array(key)),\n doSet(parent[key]),\n ...parent.slice(key + 1),\n ]\n }\n return [...new Array(key), doSet()]\n }\n\n return doSet(obj)\n}\n\n/**\n * Delete a field on an object using a path, including dot notation.\n * @private\n */\nexport function deleteBy(obj: any, _path: any) {\n const path = makePathArray(_path)\n\n function doDelete(parent: any): any {\n if (!parent) return\n if (path.length === 1) {\n const finalPath = path[0]!\n if (Array.isArray(parent) && typeof finalPath === 'number') {\n return parent.filter((_, i) => i !== finalPath)\n }\n const { [finalPath]: remove, ...rest } = parent\n return rest\n }\n\n const key = path.shift()\n\n if (typeof key === 'string') {\n if (typeof parent === 'object') {\n return {\n ...parent,\n [key]: doDelete(parent[key]),\n }\n }\n }\n\n if (typeof key === 'number') {\n if (Array.isArray(parent)) {\n if (key >= parent.length) {\n return parent\n }\n const prefix = parent.slice(0, key)\n return [\n ...(prefix.length ? prefix : new Array(key)),\n doDelete(parent[key]),\n ...parent.slice(key + 1),\n ]\n }\n }\n\n throw new Error('It seems we have created an infinite loop in deleteBy. ')\n }\n\n return doDelete(obj)\n}\n\nconst reLineOfOnlyDigits = /^(\\d+)$/gm\n// the second dot must be in a lookahead or the engine\n// will skip subsequent numbers (like foo.0.1.)\nconst reDigitsBetweenDots = /\\.(\\d+)(?=\\.)/gm\nconst reStartWithDigitThenDot = /^(\\d+)\\./gm\nconst reDotWithDigitsToEnd = /\\.(\\d+$)/gm\nconst reMultipleDots = /\\.{2,}/gm\n\nconst intPrefix = '__int__'\nconst intReplace = `${intPrefix}$1`\n\n/**\n * @private\n */\nexport function makePathArray(str: string | Array<string | number>) {\n if (Array.isArray(str)) {\n return [...str]\n }\n\n if (typeof str !== 'string') {\n throw new Error('Path must be a string.')\n }\n\n return (\n str\n // Leading `[` may lead to wrong parsing down the line\n // (Example: '[0][1]' should be '0.1', not '.0.1')\n .replace(/(^\\[)|]/gm, '')\n .replace(/\\[/g, '.')\n .replace(reLineOfOnlyDigits, intReplace)\n .replace(reDigitsBetweenDots, `.${intReplace}.`)\n .replace(reStartWithDigitThenDot, `${intReplace}.`)\n .replace(reDotWithDigitsToEnd, `.${intReplace}`)\n .replace(reMultipleDots, '.')\n .split('.')\n .map((d) => {\n if (d.startsWith(intPrefix)) {\n const numStr = d.substring(intPrefix.length)\n const num = parseInt(numStr, 10)\n\n if (String(num) === numStr) {\n return num\n }\n return numStr\n }\n return d\n })\n )\n}\n\n/**\n * @private\n */\nexport function concatenatePaths(path1: string, path2: string): string {\n if (path1.length === 0) return path2\n if (path2.length === 0) return path1\n\n if (path2.startsWith('[')) {\n return path1 + path2\n }\n\n // In cases where parent and child withFieldGroup forms are both nested\n if (path2.startsWith('.')) {\n return path1 + path2\n }\n\n return `${path1}.${path2}`\n}\n\n/**\n * @private\n */\nexport function isNonEmptyArray(obj: any) {\n return !(Array.isArray(obj) && obj.length === 0)\n}\n\ninterface AsyncValidatorArrayPartialOptions<T> {\n validators?: T\n asyncDebounceMs?: number\n}\n\n/**\n * @private\n */\nexport interface AsyncValidator<T> {\n cause: ValidationCause\n validate: T\n debounceMs: number\n}\n\ninterface SyncValidatorArrayPartialOptions<T> {\n validators?: T\n}\n\n/**\n * @private\n */\nexport interface SyncValidator<T> {\n cause: ValidationCause\n validate: T\n}\n\n/**\n * @private\n */\nexport function getSyncValidatorArray<T>(\n cause: ValidationCause,\n options: SyncValidatorArrayPartialOptions<T> & {\n validationLogic?: any\n form?: any\n },\n): T extends FieldValidators<\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>\n ? Array<\n SyncValidator<\n | T['onChange']\n | T['onBlur']\n | T['onSubmit']\n | T['onMount']\n | T['onDynamic']\n >\n >\n : T extends FormValidators<any, any, any, any, any, any, any, any, any, any>\n ? Array<\n SyncValidator<\n | T['onChange']\n | T['onBlur']\n | T['onSubmit']\n | T['onMount']\n | T['onDynamic']\n >\n >\n : never {\n const runValidation = (\n props: Parameters<ValidationLogicProps['runValidation']>[0],\n ) => {\n return props.validators.filter(Boolean).map((validator) => {\n return {\n cause: validator!.cause,\n validate: validator!.fn,\n }\n })\n }\n\n return options.validationLogic({\n form: options.form,\n validators: options.validators,\n event: { type: cause, async: false },\n runValidation,\n })\n}\n\n/**\n * @private\n */\nexport function getAsyncValidatorArray<T>(\n cause: ValidationCause,\n options: AsyncValidatorArrayPartialOptions<T> & {\n validationLogic?: any\n form?: any\n },\n): T extends FieldValidators<\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>\n ? Array<\n AsyncValidator<\n | T['onChangeAsync']\n | T['onBlurAsync']\n | T['onSubmitAsync']\n | T['onDynamicAsync']\n >\n >\n : T extends FormValidators<any, any, any, any, any, any, any, any, any, any>\n ? Array<\n AsyncValidator<\n | T['onChangeAsync']\n | T['onBlurAsync']\n | T['onSubmitAsync']\n | T['onDynamicAsync']\n >\n >\n : never {\n const { asyncDebounceMs } = options\n const {\n onBlurAsyncDebounceMs,\n onChangeAsyncDebounceMs,\n onDynamicAsyncDebounceMs,\n } = (options.validators || {}) as\n | FieldValidators<\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any\n >\n | FormValidators<any, any, any, any, any, any, any, any, any, any>\n\n const defaultDebounceMs = asyncDebounceMs ?? 0\n\n const runValidation = (\n props: Parameters<ValidationLogicProps['runValidation']>[0],\n ) => {\n return props.validators.filter(Boolean).map((validator) => {\n const validatorCause = validator?.cause || cause\n\n let debounceMs = defaultDebounceMs\n\n switch (validatorCause) {\n case 'change':\n debounceMs = onChangeAsyncDebounceMs ?? defaultDebounceMs\n break\n case 'blur':\n debounceMs = onBlurAsyncDebounceMs ?? defaultDebounceMs\n break\n case 'dynamic':\n debounceMs = onDynamicAsyncDebounceMs ?? defaultDebounceMs\n break\n case 'submit':\n debounceMs = 0 // submit validators are always run immediately\n break\n default:\n break\n }\n\n if (cause === 'submit') {\n debounceMs = 0\n }\n\n return {\n cause: validatorCause,\n validate: validator!.fn,\n debounceMs: debounceMs,\n }\n })\n }\n\n return options.validationLogic({\n form: options.form,\n validators: options.validators,\n event: { type: cause, async: true },\n runValidation,\n })\n}\n\nexport const isGlobalFormValidationError = (\n error: unknown,\n): error is GlobalFormValidationError<unknown> => {\n return !!error && typeof error === 'object' && 'fields' in error\n}\n\nexport function evaluate<T>(objA: T, objB: T) {\n if (Object.is(objA, objB)) {\n return true\n }\n\n if (\n typeof objA !== 'object' ||\n objA === null ||\n typeof objB !== 'object' ||\n objB === null\n ) {\n return false\n }\n\n if (objA instanceof Map && objB instanceof Map) {\n if (objA.size !== objB.size) return false\n for (const [k, v] of objA) {\n if (!objB.has(k) || !Object.is(v, objB.get(k))) return false\n }\n return true\n }\n\n if (objA instanceof Set && objB instanceof Set) {\n if (objA.size !== objB.size) return false\n for (const v of objA) {\n if (!objB.has(v)) return false\n }\n return true\n }\n\n const keysA = Object.keys(objA)\n const keysB = Object.keys(objB)\n\n if (keysA.length !== keysB.length) {\n return false\n }\n\n for (const key of keysA) {\n // performs recursive search down the object tree\n\n if (\n !keysB.includes(key) ||\n !evaluate(objA[key as keyof T], objB[key as keyof T])\n ) {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Determines the logic for determining the error source and value to set on the field meta within the form level sync/async validation.\n * @private\n */\nexport const determineFormLevelErrorSourceAndValue = ({\n newFormValidatorError,\n isPreviousErrorFromFormValidator,\n previousErrorValue,\n}: {\n newFormValidatorError: ValidationError\n isPreviousErrorFromFormValidator: boolean\n previousErrorValue: ValidationError\n}): {\n newErrorValue: ValidationError\n newSource: ValidationSource | undefined\n} => {\n // All falsy values are not considered errors\n if (newFormValidatorError) {\n return { newErrorValue: newFormValidatorError, newSource: 'form' }\n }\n\n // Clears form level error since it's now stale\n if (isPreviousErrorFromFormValidator) {\n return { newErrorValue: undefined, newSource: undefined }\n }\n\n // At this point, we have a preivous error which must have been set by the field validator, keep as is\n if (previousErrorValue) {\n return { newErrorValue: previousErrorValue, newSource: 'field' }\n }\n\n // No new or previous error, clear the error\n return { newErrorValue: undefined, newSource: undefined }\n}\n\n/**\n * Determines the logic for determining the error source and value to set on the field meta within the field level sync/async validation.\n * @private\n */\nexport const determineFieldLevelErrorSourceAndValue = ({\n formLevelError,\n fieldLevelError,\n}: {\n formLevelError: ValidationError\n fieldLevelError: ValidationError\n}): {\n newErrorValue: ValidationError\n newSource: ValidationSource | undefined\n} => {\n // At field level, we prioritize the field level error\n if (fieldLevelError) {\n return { newErrorValue: fieldLevelError, newSource: 'field' }\n }\n\n // If there is no field level error, and there is a form level error, we set the form level error\n if (formLevelError) {\n return { newErrorValue: formLevelError, newSource: 'form' }\n }\n\n return { newErrorValue: undefined, newSource: undefined }\n}\n\nexport function createFieldMap<T>(values: Readonly<T>): { [K in keyof T]: K } {\n const output: { [K in keyof T]: K } = {} as any\n\n for (const key in values) {\n output[key] = key\n }\n\n return output\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import { defaultValidationLogic } from './ValidationLogic'\nimport type { ValidationLogicProps } from './ValidationLogic'\nimport type { FieldValidators } from './FieldApi'\nimport type { FormValidators } from './FormApi'\nimport type {\n GlobalFormValidationError,\n ValidationCause,\n ValidationError,\n ValidationSource,\n} from './types'\n\nexport type UpdaterFn<TInput, TOutput = TInput> = (input: TInput) => TOutput\n\nexport type Updater<TInput, TOutput = TInput> =\n | TOutput\n | UpdaterFn<TInput, TOutput>\n\n/**\n * @private\n */\nexport function functionalUpdate<TInput, TOutput = TInput>(\n updater: Updater<TInput, TOutput>,\n input: TInput,\n): TOutput {\n return typeof updater === 'function'\n ? (updater as UpdaterFn<TInput, TOutput>)(input)\n : updater\n}\n\n/**\n * Get a value from an object using a path, including dot notation.\n * @private\n */\nexport function getBy(obj: any, path: any) {\n const pathObj = makePathArray(path)\n return pathObj.reduce((current: any, pathPart: any) => {\n if (current === null) return null\n if (typeof current !== 'undefined') {\n return current[pathPart]\n }\n return undefined\n }, obj)\n}\n\n/**\n * Set a value on an object using a path, including dot notation.\n * @private\n */\nexport function setBy(obj: any, _path: any, updater: Updater<any>) {\n const path = makePathArray(_path)\n\n function doSet(parent?: any): any {\n if (!path.length) {\n return functionalUpdate(updater, parent)\n }\n\n const key = path.shift()\n\n if (\n typeof key === 'string' ||\n (typeof key === 'number' && !Array.isArray(parent))\n ) {\n if (typeof parent === 'object') {\n if (parent === null) {\n parent = {}\n }\n return {\n ...parent,\n [key]: doSet(parent[key]),\n }\n }\n return {\n [key]: doSet(),\n }\n }\n\n if (Array.isArray(parent) && typeof key === 'number') {\n const prefix = parent.slice(0, key)\n return [\n ...(prefix.length ? prefix : new Array(key)),\n doSet(parent[key]),\n ...parent.slice(key + 1),\n ]\n }\n return [...new Array(key), doSet()]\n }\n\n return doSet(obj)\n}\n\n/**\n * Delete a field on an object using a path, including dot notation.\n * @private\n */\nexport function deleteBy(obj: any, _path: any) {\n const path = makePathArray(_path)\n\n function doDelete(parent: any): any {\n if (!parent) return\n if (path.length === 1) {\n const finalPath = path[0]!\n if (Array.isArray(parent) && typeof finalPath === 'number') {\n return parent.filter((_, i) => i !== finalPath)\n }\n const { [finalPath]: remove, ...rest } = parent\n return rest\n }\n\n const key = path.shift()\n\n if (typeof key === 'string') {\n if (typeof parent === 'object') {\n return {\n ...parent,\n [key]: doDelete(parent[key]),\n }\n }\n }\n\n if (typeof key === 'number') {\n if (Array.isArray(parent)) {\n if (key >= parent.length) {\n return parent\n }\n const prefix = parent.slice(0, key)\n return [\n ...(prefix.length ? prefix : new Array(key)),\n doDelete(parent[key]),\n ...parent.slice(key + 1),\n ]\n }\n }\n\n throw new Error('It seems we have created an infinite loop in deleteBy. ')\n }\n\n return doDelete(obj)\n}\n\nconst reLineOfOnlyDigits = /^(\\d+)$/gm\n// the second dot must be in a lookahead or the engine\n// will skip subsequent numbers (like foo.0.1.)\nconst reDigitsBetweenDots = /\\.(\\d+)(?=\\.)/gm\nconst reStartWithDigitThenDot = /^(\\d+)\\./gm\nconst reDotWithDigitsToEnd = /\\.(\\d+$)/gm\nconst reMultipleDots = /\\.{2,}/gm\n\nconst intPrefix = '__int__'\nconst intReplace = `${intPrefix}$1`\n\n/**\n * @private\n */\nexport function makePathArray(str: string | Array<string | number>) {\n if (Array.isArray(str)) {\n return [...str]\n }\n\n if (typeof str !== 'string') {\n throw new Error('Path must be a string.')\n }\n\n return (\n str\n // Leading `[` may lead to wrong parsing down the line\n // (Example: '[0][1]' should be '0.1', not '.0.1')\n .replace(/(^\\[)|]/gm, '')\n .replace(/\\[/g, '.')\n .replace(reLineOfOnlyDigits, intReplace)\n .replace(reDigitsBetweenDots, `.${intReplace}.`)\n .replace(reStartWithDigitThenDot, `${intReplace}.`)\n .replace(reDotWithDigitsToEnd, `.${intReplace}`)\n .replace(reMultipleDots, '.')\n .split('.')\n .map((d) => {\n if (d.startsWith(intPrefix)) {\n const numStr = d.substring(intPrefix.length)\n const num = parseInt(numStr, 10)\n\n if (String(num) === numStr) {\n return num\n }\n return numStr\n }\n return d\n })\n )\n}\n\n/**\n * @private\n */\nexport function concatenatePaths(path1: string, path2: string): string {\n if (path1.length === 0) return path2\n if (path2.length === 0) return path1\n\n if (path2.startsWith('[')) {\n return path1 + path2\n }\n\n // In cases where parent and child withFieldGroup forms are both nested\n if (path2.startsWith('.')) {\n return path1 + path2\n }\n\n return `${path1}.${path2}`\n}\n\n/**\n * @private\n */\nexport function isNonEmptyArray(obj: any) {\n return !(Array.isArray(obj) && obj.length === 0)\n}\n\ninterface AsyncValidatorArrayPartialOptions<T> {\n validators?: T\n asyncDebounceMs?: number\n}\n\n/**\n * @private\n */\nexport interface AsyncValidator<T> {\n cause: ValidationCause\n validate: T\n debounceMs: number\n}\n\ninterface SyncValidatorArrayPartialOptions<T> {\n validators?: T\n}\n\n/**\n * @private\n */\nexport interface SyncValidator<T> {\n cause: ValidationCause\n validate: T\n}\n\n/**\n * @private\n */\nexport function getSyncValidatorArray<T>(\n cause: ValidationCause,\n options: SyncValidatorArrayPartialOptions<T> & {\n validationLogic?: any\n form?: any\n },\n): T extends FieldValidators<\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>\n ? Array<\n SyncValidator<\n | T['onChange']\n | T['onBlur']\n | T['onSubmit']\n | T['onMount']\n | T['onDynamic']\n >\n >\n : T extends FormValidators<any, any, any, any, any, any, any, any, any, any>\n ? Array<\n SyncValidator<\n | T['onChange']\n | T['onBlur']\n | T['onSubmit']\n | T['onMount']\n | T['onDynamic']\n >\n >\n : never {\n const runValidation = (\n props: Parameters<ValidationLogicProps['runValidation']>[0],\n ) => {\n return props.validators.filter(Boolean).map((validator) => {\n return {\n cause: validator!.cause,\n validate: validator!.fn,\n }\n })\n }\n\n return options.validationLogic({\n form: options.form,\n validators: options.validators,\n event: { type: cause, async: false },\n runValidation,\n })\n}\n\n/**\n * @private\n */\nexport function getAsyncValidatorArray<T>(\n cause: ValidationCause,\n options: AsyncValidatorArrayPartialOptions<T> & {\n validationLogic?: any\n form?: any\n },\n): T extends FieldValidators<\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>\n ? Array<\n AsyncValidator<\n | T['onChangeAsync']\n | T['onBlurAsync']\n | T['onSubmitAsync']\n | T['onDynamicAsync']\n >\n >\n : T extends FormValidators<any, any, any, any, any, any, any, any, any, any>\n ? Array<\n AsyncValidator<\n | T['onChangeAsync']\n | T['onBlurAsync']\n | T['onSubmitAsync']\n | T['onDynamicAsync']\n >\n >\n : never {\n const { asyncDebounceMs } = options\n const {\n onBlurAsyncDebounceMs,\n onChangeAsyncDebounceMs,\n onDynamicAsyncDebounceMs,\n } = (options.validators || {}) as\n | FieldValidators<\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any\n >\n | FormValidators<any, any, any, any, any, any, any, any, any, any>\n\n const defaultDebounceMs = asyncDebounceMs ?? 0\n\n const runValidation = (\n props: Parameters<ValidationLogicProps['runValidation']>[0],\n ) => {\n return props.validators.filter(Boolean).map((validator) => {\n const validatorCause = validator?.cause || cause\n\n let debounceMs = defaultDebounceMs\n\n switch (validatorCause) {\n case 'change':\n debounceMs = onChangeAsyncDebounceMs ?? defaultDebounceMs\n break\n case 'blur':\n debounceMs = onBlurAsyncDebounceMs ?? defaultDebounceMs\n break\n case 'dynamic':\n debounceMs = onDynamicAsyncDebounceMs ?? defaultDebounceMs\n break\n case 'submit':\n debounceMs = 0 // submit validators are always run immediately\n break\n default:\n break\n }\n\n if (cause === 'submit') {\n debounceMs = 0\n }\n\n return {\n cause: validatorCause,\n validate: validator!.fn,\n debounceMs: debounceMs,\n }\n })\n }\n\n return options.validationLogic({\n form: options.form,\n validators: options.validators,\n event: { type: cause, async: true },\n runValidation,\n })\n}\n\nexport const isGlobalFormValidationError = (\n error: unknown,\n): error is GlobalFormValidationError<unknown> => {\n return !!error && typeof error === 'object' && 'fields' in error\n}\n\nexport function evaluate<T>(objA: T, objB: T) {\n if (Object.is(objA, objB)) {\n return true\n }\n\n if (\n typeof objA !== 'object' ||\n objA === null ||\n typeof objB !== 'object' ||\n objB === null\n ) {\n return false\n }\n\n if (objA instanceof Map && objB instanceof Map) {\n if (objA.size !== objB.size) return false\n for (const [k, v] of objA) {\n if (!objB.has(k) || !Object.is(v, objB.get(k))) return false\n }\n return true\n }\n\n if (objA instanceof Set && objB instanceof Set) {\n if (objA.size !== objB.size) return false\n for (const v of objA) {\n if (!objB.has(v)) return false\n }\n return true\n }\n\n const keysA = Object.keys(objA)\n const keysB = Object.keys(objB)\n\n if (keysA.length !== keysB.length) {\n return false\n }\n\n for (const key of keysA) {\n // performs recursive search down the object tree\n\n if (\n !keysB.includes(key) ||\n !evaluate(objA[key as keyof T], objB[key as keyof T])\n ) {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Determines the logic for determining the error source and value to set on the field meta within the form level sync/async validation.\n * @private\n */\nexport const determineFormLevelErrorSourceAndValue = ({\n newFormValidatorError,\n isPreviousErrorFromFormValidator,\n previousErrorValue,\n}: {\n newFormValidatorError: ValidationError\n isPreviousErrorFromFormValidator: boolean\n previousErrorValue: ValidationError\n}): {\n newErrorValue: ValidationError\n newSource: ValidationSource | undefined\n} => {\n // All falsy values are not considered errors\n if (newFormValidatorError) {\n return { newErrorValue: newFormValidatorError, newSource: 'form' }\n }\n\n // Clears form level error since it's now stale\n if (isPreviousErrorFromFormValidator) {\n return { newErrorValue: undefined, newSource: undefined }\n }\n\n // At this point, we have a preivous error which must have been set by the field validator, keep as is\n if (previousErrorValue) {\n return { newErrorValue: previousErrorValue, newSource: 'field' }\n }\n\n // No new or previous error, clear the error\n return { newErrorValue: undefined, newSource: undefined }\n}\n\n/**\n * Determines the logic for determining the error source and value to set on the field meta within the field level sync/async validation.\n * @private\n */\nexport const determineFieldLevelErrorSourceAndValue = ({\n formLevelError,\n fieldLevelError,\n}: {\n formLevelError: ValidationError\n fieldLevelError: ValidationError\n}): {\n newErrorValue: ValidationError\n newSource: ValidationSource | undefined\n} => {\n // At field level, we prioritize the field level error\n if (fieldLevelError) {\n return { newErrorValue: fieldLevelError, newSource: 'field' }\n }\n\n // If there is no field level error, and there is a form level error, we set the form level error\n if (formLevelError) {\n return { newErrorValue: formLevelError, newSource: 'form' }\n }\n\n return { newErrorValue: undefined, newSource: undefined }\n}\n\nexport function createFieldMap<T>(values: Readonly<T>): { [K in keyof T]: K } {\n const output: { [K in keyof T]: K } = {} as any\n\n for (const key in values) {\n output[key] = key\n }\n\n return output\n}\n\n/**\n * Merge the first parameter with the given overrides.\n * @private\n */\nexport function mergeOpts<T>(\n originalOpts: T | undefined | null,\n overrides: T,\n): T {\n if (originalOpts === undefined || originalOpts === null) {\n return overrides\n }\n\n return { ...originalOpts, ...overrides }\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/form-core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.4",
|
|
4
4
|
"description": "Powerful, type-safe, framework agnostic forms.",
|
|
5
5
|
"author": "tannerlinsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"src"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@tanstack/store": "^0.7.
|
|
40
|
+
"@tanstack/store": "^0.7.4"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"arktype": "^2.1.20",
|
package/src/FieldApi.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
getAsyncValidatorArray,
|
|
10
10
|
getBy,
|
|
11
11
|
getSyncValidatorArray,
|
|
12
|
+
mergeOpts,
|
|
12
13
|
} from './utils'
|
|
13
14
|
import { defaultValidationLogic } from './ValidationLogic'
|
|
14
15
|
import type { DeepKeys, DeepValue, UnwrapOneLevelOfArray } from './util-types'
|
|
@@ -1350,11 +1351,19 @@ export class FieldApi<
|
|
|
1350
1351
|
* Sets the field value and run the `change` validator.
|
|
1351
1352
|
*/
|
|
1352
1353
|
setValue = (updater: Updater<TData>, options?: UpdateMetaOptions) => {
|
|
1353
|
-
this.form.setFieldValue(
|
|
1354
|
+
this.form.setFieldValue(
|
|
1355
|
+
this.name,
|
|
1356
|
+
updater as never,
|
|
1357
|
+
mergeOpts(options, { dontRunListeners: true, dontValidate: true }),
|
|
1358
|
+
)
|
|
1354
1359
|
|
|
1355
|
-
|
|
1360
|
+
if (!options?.dontRunListeners) {
|
|
1361
|
+
this.triggerOnChangeListener()
|
|
1362
|
+
}
|
|
1356
1363
|
|
|
1357
|
-
|
|
1364
|
+
if (!options?.dontValidate) {
|
|
1365
|
+
this.validate('change')
|
|
1366
|
+
}
|
|
1358
1367
|
}
|
|
1359
1368
|
|
|
1360
1369
|
getMeta = () => this.store.state.meta
|
|
@@ -1400,11 +1409,17 @@ export class FieldApi<
|
|
|
1400
1409
|
*/
|
|
1401
1410
|
pushValue = (
|
|
1402
1411
|
value: TData extends any[] ? TData[number] : never,
|
|
1403
|
-
|
|
1412
|
+
options?: UpdateMetaOptions,
|
|
1404
1413
|
) => {
|
|
1405
|
-
this.form.pushFieldValue(
|
|
1414
|
+
this.form.pushFieldValue(
|
|
1415
|
+
this.name,
|
|
1416
|
+
value as any,
|
|
1417
|
+
mergeOpts(options, { dontRunListeners: true }),
|
|
1418
|
+
)
|
|
1406
1419
|
|
|
1407
|
-
|
|
1420
|
+
if (!options?.dontRunListeners) {
|
|
1421
|
+
this.triggerOnChangeListener()
|
|
1422
|
+
}
|
|
1408
1423
|
}
|
|
1409
1424
|
|
|
1410
1425
|
/**
|
|
@@ -1413,11 +1428,18 @@ export class FieldApi<
|
|
|
1413
1428
|
insertValue = (
|
|
1414
1429
|
index: number,
|
|
1415
1430
|
value: TData extends any[] ? TData[number] : never,
|
|
1416
|
-
|
|
1431
|
+
options?: UpdateMetaOptions,
|
|
1417
1432
|
) => {
|
|
1418
|
-
this.form.insertFieldValue(
|
|
1433
|
+
this.form.insertFieldValue(
|
|
1434
|
+
this.name,
|
|
1435
|
+
index,
|
|
1436
|
+
value as any,
|
|
1437
|
+
mergeOpts(options, { dontRunListeners: true }),
|
|
1438
|
+
)
|
|
1419
1439
|
|
|
1420
|
-
|
|
1440
|
+
if (!options?.dontRunListeners) {
|
|
1441
|
+
this.triggerOnChangeListener()
|
|
1442
|
+
}
|
|
1421
1443
|
}
|
|
1422
1444
|
|
|
1423
1445
|
/**
|
|
@@ -1426,47 +1448,83 @@ export class FieldApi<
|
|
|
1426
1448
|
replaceValue = (
|
|
1427
1449
|
index: number,
|
|
1428
1450
|
value: TData extends any[] ? TData[number] : never,
|
|
1429
|
-
|
|
1451
|
+
options?: UpdateMetaOptions,
|
|
1430
1452
|
) => {
|
|
1431
|
-
this.form.replaceFieldValue(
|
|
1453
|
+
this.form.replaceFieldValue(
|
|
1454
|
+
this.name,
|
|
1455
|
+
index,
|
|
1456
|
+
value as any,
|
|
1457
|
+
mergeOpts(options, { dontRunListeners: true }),
|
|
1458
|
+
)
|
|
1432
1459
|
|
|
1433
|
-
|
|
1460
|
+
if (!options?.dontRunListeners) {
|
|
1461
|
+
this.triggerOnChangeListener()
|
|
1462
|
+
}
|
|
1434
1463
|
}
|
|
1435
1464
|
|
|
1436
1465
|
/**
|
|
1437
1466
|
* Removes a value at the specified index.
|
|
1438
1467
|
*/
|
|
1439
|
-
removeValue = (index: number,
|
|
1440
|
-
this.form.removeFieldValue(
|
|
1468
|
+
removeValue = (index: number, options?: UpdateMetaOptions) => {
|
|
1469
|
+
this.form.removeFieldValue(
|
|
1470
|
+
this.name,
|
|
1471
|
+
index,
|
|
1472
|
+
mergeOpts(options, { dontRunListeners: true }),
|
|
1473
|
+
)
|
|
1441
1474
|
|
|
1442
|
-
|
|
1475
|
+
if (!options?.dontRunListeners) {
|
|
1476
|
+
this.triggerOnChangeListener()
|
|
1477
|
+
}
|
|
1443
1478
|
}
|
|
1444
1479
|
|
|
1445
1480
|
/**
|
|
1446
1481
|
* Swaps the values at the specified indices.
|
|
1447
1482
|
*/
|
|
1448
|
-
swapValues = (
|
|
1449
|
-
|
|
1483
|
+
swapValues = (
|
|
1484
|
+
aIndex: number,
|
|
1485
|
+
bIndex: number,
|
|
1486
|
+
options?: UpdateMetaOptions,
|
|
1487
|
+
) => {
|
|
1488
|
+
this.form.swapFieldValues(
|
|
1489
|
+
this.name,
|
|
1490
|
+
aIndex,
|
|
1491
|
+
bIndex,
|
|
1492
|
+
mergeOpts(options, { dontRunListeners: true }),
|
|
1493
|
+
)
|
|
1450
1494
|
|
|
1451
|
-
|
|
1495
|
+
if (!options?.dontRunListeners) {
|
|
1496
|
+
this.triggerOnChangeListener()
|
|
1497
|
+
}
|
|
1452
1498
|
}
|
|
1453
1499
|
|
|
1454
1500
|
/**
|
|
1455
1501
|
* Moves the value at the first specified index to the second specified index.
|
|
1456
1502
|
*/
|
|
1457
|
-
moveValue = (aIndex: number, bIndex: number,
|
|
1458
|
-
this.form.moveFieldValues(
|
|
1503
|
+
moveValue = (aIndex: number, bIndex: number, options?: UpdateMetaOptions) => {
|
|
1504
|
+
this.form.moveFieldValues(
|
|
1505
|
+
this.name,
|
|
1506
|
+
aIndex,
|
|
1507
|
+
bIndex,
|
|
1508
|
+
mergeOpts(options, { dontRunListeners: true }),
|
|
1509
|
+
)
|
|
1459
1510
|
|
|
1460
|
-
|
|
1511
|
+
if (!options?.dontRunListeners) {
|
|
1512
|
+
this.triggerOnChangeListener()
|
|
1513
|
+
}
|
|
1461
1514
|
}
|
|
1462
1515
|
|
|
1463
1516
|
/**
|
|
1464
1517
|
* Clear all values from the array.
|
|
1465
1518
|
*/
|
|
1466
|
-
clearValues = (
|
|
1467
|
-
this.form.clearFieldValues(
|
|
1519
|
+
clearValues = (options?: UpdateMetaOptions) => {
|
|
1520
|
+
this.form.clearFieldValues(
|
|
1521
|
+
this.name,
|
|
1522
|
+
mergeOpts(options, { dontRunListeners: true }),
|
|
1523
|
+
)
|
|
1468
1524
|
|
|
1469
|
-
|
|
1525
|
+
if (!options?.dontRunListeners) {
|
|
1526
|
+
this.triggerOnChangeListener()
|
|
1527
|
+
}
|
|
1470
1528
|
}
|
|
1471
1529
|
|
|
1472
1530
|
/**
|
|
@@ -1936,7 +1994,10 @@ export class FieldApi<
|
|
|
1936
1994
|
}
|
|
1937
1995
|
}
|
|
1938
1996
|
|
|
1939
|
-
|
|
1997
|
+
/**
|
|
1998
|
+
* @private
|
|
1999
|
+
*/
|
|
2000
|
+
triggerOnChangeListener() {
|
|
1940
2001
|
const formDebounceMs = this.form.options.listeners?.onChangeDebounceMs
|
|
1941
2002
|
if (formDebounceMs && formDebounceMs > 0) {
|
|
1942
2003
|
if (this.timeoutIds.formListeners.change) {
|
package/src/FormApi.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
getSyncValidatorArray,
|
|
10
10
|
isGlobalFormValidationError,
|
|
11
11
|
isNonEmptyArray,
|
|
12
|
+
mergeOpts,
|
|
12
13
|
setBy,
|
|
13
14
|
} from './utils'
|
|
14
15
|
import { defaultValidationLogic } from './ValidationLogic'
|
|
@@ -35,6 +36,7 @@ import type {
|
|
|
35
36
|
FieldManipulator,
|
|
36
37
|
FormValidationError,
|
|
37
38
|
FormValidationErrorMap,
|
|
39
|
+
ListenerCause,
|
|
38
40
|
UpdateMetaOptions,
|
|
39
41
|
ValidationCause,
|
|
40
42
|
ValidationError,
|
|
@@ -934,6 +936,15 @@ export class FormApi<
|
|
|
934
936
|
*/
|
|
935
937
|
prevTransformArray: unknown[] = []
|
|
936
938
|
|
|
939
|
+
/**
|
|
940
|
+
*
|
|
941
|
+
*/
|
|
942
|
+
timeoutIds: {
|
|
943
|
+
validations: Record<ValidationCause, ReturnType<typeof setTimeout> | null>
|
|
944
|
+
listeners: Record<ListenerCause, ReturnType<typeof setTimeout> | null>
|
|
945
|
+
formListeners: Record<ListenerCause, ReturnType<typeof setTimeout> | null>
|
|
946
|
+
}
|
|
947
|
+
|
|
937
948
|
/**
|
|
938
949
|
* Constructs a new `FormApi` instance with the given form options.
|
|
939
950
|
*/
|
|
@@ -953,6 +964,12 @@ export class FormApi<
|
|
|
953
964
|
TSubmitMeta
|
|
954
965
|
>,
|
|
955
966
|
) {
|
|
967
|
+
this.timeoutIds = {
|
|
968
|
+
validations: {} as Record<ValidationCause, never>,
|
|
969
|
+
listeners: {} as Record<ListenerCause, never>,
|
|
970
|
+
formListeners: {} as Record<ListenerCause, never>,
|
|
971
|
+
}
|
|
972
|
+
|
|
956
973
|
this.baseStore = new Store(
|
|
957
974
|
getDefaultFormState({
|
|
958
975
|
...(opts?.defaultState as any),
|
|
@@ -2072,6 +2089,8 @@ export class FormApi<
|
|
|
2072
2089
|
opts?: UpdateMetaOptions,
|
|
2073
2090
|
) => {
|
|
2074
2091
|
const dontUpdateMeta = opts?.dontUpdateMeta ?? false
|
|
2092
|
+
const dontRunListeners = opts?.dontRunListeners ?? false
|
|
2093
|
+
const dontValidate = opts?.dontValidate ?? false
|
|
2075
2094
|
|
|
2076
2095
|
batch(() => {
|
|
2077
2096
|
if (!dontUpdateMeta) {
|
|
@@ -2094,6 +2113,14 @@ export class FormApi<
|
|
|
2094
2113
|
}
|
|
2095
2114
|
})
|
|
2096
2115
|
})
|
|
2116
|
+
|
|
2117
|
+
if (!dontRunListeners) {
|
|
2118
|
+
this.getFieldInfo(field).instance?.triggerOnChangeListener()
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
if (!dontValidate) {
|
|
2122
|
+
this.validateField(field, 'change')
|
|
2123
|
+
}
|
|
2097
2124
|
}
|
|
2098
2125
|
|
|
2099
2126
|
deleteField = <TField extends DeepKeys<TFormData>>(field: TField) => {
|
|
@@ -2125,14 +2152,13 @@ export class FormApi<
|
|
|
2125
2152
|
value: DeepValue<TFormData, TField> extends any[]
|
|
2126
2153
|
? DeepValue<TFormData, TField>[number]
|
|
2127
2154
|
: never,
|
|
2128
|
-
|
|
2155
|
+
options?: UpdateMetaOptions,
|
|
2129
2156
|
) => {
|
|
2130
2157
|
this.setFieldValue(
|
|
2131
2158
|
field,
|
|
2132
2159
|
(prev) => [...(Array.isArray(prev) ? prev : []), value] as any,
|
|
2133
|
-
|
|
2160
|
+
options,
|
|
2134
2161
|
)
|
|
2135
|
-
this.validateField(field, 'change')
|
|
2136
2162
|
}
|
|
2137
2163
|
|
|
2138
2164
|
insertFieldValue = async <TField extends DeepKeysOfType<TFormData, any[]>>(
|
|
@@ -2141,7 +2167,7 @@ export class FormApi<
|
|
|
2141
2167
|
value: DeepValue<TFormData, TField> extends any[]
|
|
2142
2168
|
? DeepValue<TFormData, TField>[number]
|
|
2143
2169
|
: never,
|
|
2144
|
-
|
|
2170
|
+
options?: UpdateMetaOptions,
|
|
2145
2171
|
) => {
|
|
2146
2172
|
this.setFieldValue(
|
|
2147
2173
|
field,
|
|
@@ -2152,7 +2178,7 @@ export class FormApi<
|
|
|
2152
2178
|
...(prev as DeepValue<TFormData, TField>[]).slice(index),
|
|
2153
2179
|
] as any
|
|
2154
2180
|
},
|
|
2155
|
-
|
|
2181
|
+
mergeOpts(options, { dontValidate: true }),
|
|
2156
2182
|
)
|
|
2157
2183
|
|
|
2158
2184
|
// Validate the whole array + all fields that have shifted
|
|
@@ -2173,7 +2199,7 @@ export class FormApi<
|
|
|
2173
2199
|
value: DeepValue<TFormData, TField> extends any[]
|
|
2174
2200
|
? DeepValue<TFormData, TField>[number]
|
|
2175
2201
|
: never,
|
|
2176
|
-
|
|
2202
|
+
options?: UpdateMetaOptions,
|
|
2177
2203
|
) => {
|
|
2178
2204
|
this.setFieldValue(
|
|
2179
2205
|
field,
|
|
@@ -2182,7 +2208,7 @@ export class FormApi<
|
|
|
2182
2208
|
i === index ? value : d,
|
|
2183
2209
|
) as any
|
|
2184
2210
|
},
|
|
2185
|
-
|
|
2211
|
+
mergeOpts(options, { dontValidate: true }),
|
|
2186
2212
|
)
|
|
2187
2213
|
|
|
2188
2214
|
// Validate the whole array + all fields that have shifted
|
|
@@ -2196,7 +2222,7 @@ export class FormApi<
|
|
|
2196
2222
|
removeFieldValue = async <TField extends DeepKeysOfType<TFormData, any[]>>(
|
|
2197
2223
|
field: TField,
|
|
2198
2224
|
index: number,
|
|
2199
|
-
|
|
2225
|
+
options?: UpdateMetaOptions,
|
|
2200
2226
|
) => {
|
|
2201
2227
|
const fieldValue = this.getFieldValue(field)
|
|
2202
2228
|
|
|
@@ -2211,7 +2237,7 @@ export class FormApi<
|
|
|
2211
2237
|
(_d, i) => i !== index,
|
|
2212
2238
|
) as any
|
|
2213
2239
|
},
|
|
2214
|
-
|
|
2240
|
+
mergeOpts(options, { dontValidate: true }),
|
|
2215
2241
|
)
|
|
2216
2242
|
|
|
2217
2243
|
// Shift up all meta
|
|
@@ -2234,7 +2260,7 @@ export class FormApi<
|
|
|
2234
2260
|
field: TField,
|
|
2235
2261
|
index1: number,
|
|
2236
2262
|
index2: number,
|
|
2237
|
-
|
|
2263
|
+
options?: UpdateMetaOptions,
|
|
2238
2264
|
) => {
|
|
2239
2265
|
this.setFieldValue(
|
|
2240
2266
|
field,
|
|
@@ -2243,7 +2269,7 @@ export class FormApi<
|
|
|
2243
2269
|
const prev2 = prev[index2]!
|
|
2244
2270
|
return setBy(setBy(prev, `${index1}`, prev2), `${index2}`, prev1)
|
|
2245
2271
|
},
|
|
2246
|
-
|
|
2272
|
+
mergeOpts(options, { dontValidate: true }),
|
|
2247
2273
|
)
|
|
2248
2274
|
|
|
2249
2275
|
// Swap meta
|
|
@@ -2263,7 +2289,7 @@ export class FormApi<
|
|
|
2263
2289
|
field: TField,
|
|
2264
2290
|
index1: number,
|
|
2265
2291
|
index2: number,
|
|
2266
|
-
|
|
2292
|
+
options?: UpdateMetaOptions,
|
|
2267
2293
|
) => {
|
|
2268
2294
|
this.setFieldValue(
|
|
2269
2295
|
field,
|
|
@@ -2272,7 +2298,7 @@ export class FormApi<
|
|
|
2272
2298
|
next.splice(index2, 0, next.splice(index1, 1)[0])
|
|
2273
2299
|
return next
|
|
2274
2300
|
},
|
|
2275
|
-
|
|
2301
|
+
mergeOpts(options, { dontValidate: true }),
|
|
2276
2302
|
)
|
|
2277
2303
|
|
|
2278
2304
|
// Move meta between index1 and index2
|
|
@@ -2290,7 +2316,7 @@ export class FormApi<
|
|
|
2290
2316
|
*/
|
|
2291
2317
|
clearFieldValues = <TField extends DeepKeysOfType<TFormData, any[]>>(
|
|
2292
2318
|
field: TField,
|
|
2293
|
-
|
|
2319
|
+
options?: UpdateMetaOptions,
|
|
2294
2320
|
) => {
|
|
2295
2321
|
const fieldValue = this.getFieldValue(field)
|
|
2296
2322
|
|
|
@@ -2298,7 +2324,11 @@ export class FormApi<
|
|
|
2298
2324
|
? Math.max((fieldValue as unknown[]).length - 1, 0)
|
|
2299
2325
|
: null
|
|
2300
2326
|
|
|
2301
|
-
this.setFieldValue(
|
|
2327
|
+
this.setFieldValue(
|
|
2328
|
+
field,
|
|
2329
|
+
[] as any,
|
|
2330
|
+
mergeOpts(options, { dontValidate: true }),
|
|
2331
|
+
)
|
|
2302
2332
|
|
|
2303
2333
|
if (lastIndex !== null) {
|
|
2304
2334
|
for (let i = 0; i <= lastIndex; i++) {
|
package/src/types.ts
CHANGED
|
@@ -134,6 +134,14 @@ export interface UpdateMetaOptions {
|
|
|
134
134
|
* @default false
|
|
135
135
|
*/
|
|
136
136
|
dontUpdateMeta?: boolean
|
|
137
|
+
/**
|
|
138
|
+
* @default false
|
|
139
|
+
*/
|
|
140
|
+
dontValidate?: boolean
|
|
141
|
+
/**
|
|
142
|
+
* @default false
|
|
143
|
+
*/
|
|
144
|
+
dontRunListeners?: boolean
|
|
137
145
|
}
|
|
138
146
|
|
|
139
147
|
/**
|
package/src/utils.ts
CHANGED
|
@@ -539,3 +539,18 @@ export function createFieldMap<T>(values: Readonly<T>): { [K in keyof T]: K } {
|
|
|
539
539
|
|
|
540
540
|
return output
|
|
541
541
|
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Merge the first parameter with the given overrides.
|
|
545
|
+
* @private
|
|
546
|
+
*/
|
|
547
|
+
export function mergeOpts<T>(
|
|
548
|
+
originalOpts: T | undefined | null,
|
|
549
|
+
overrides: T,
|
|
550
|
+
): T {
|
|
551
|
+
if (originalOpts === undefined || originalOpts === null) {
|
|
552
|
+
return overrides
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return { ...originalOpts, ...overrides }
|
|
556
|
+
}
|