113 lines
3.2 KiB
TypeScript
113 lines
3.2 KiB
TypeScript
function isDirty(
|
||
obj1: Record<string, unknown> | null | undefined,
|
||
obj2: Record<string, unknown> | null | undefined
|
||
): boolean {
|
||
const actualObj1 = obj1 ?? {}
|
||
const actualObj2 = obj2 ?? {}
|
||
|
||
const filteredObj1 = filterIgnored(actualObj1)
|
||
const filteredObj2 = filterIgnored(actualObj2)
|
||
|
||
const allKeys = new Set([...Object.keys(filteredObj1), ...Object.keys(filteredObj2)])
|
||
|
||
for (const key of allKeys) {
|
||
const hasKey1 = Object.hasOwn(filteredObj1, key)
|
||
const hasKey2 = Object.hasOwn(filteredObj2, key)
|
||
|
||
// Различие в наличии ключа
|
||
if (hasKey1 !== hasKey2) return true
|
||
|
||
if (hasKey1 && hasKey2) {
|
||
const val1 = filteredObj1[key]
|
||
const val2 = filteredObj2[key]
|
||
|
||
// Сравнение массивов
|
||
if (Array.isArray(val1) && Array.isArray(val2)) {
|
||
if (val1.length !== val2.length) return true
|
||
const set2 = new Set(val2)
|
||
if (!val1.every(item => set2.has(item))) return true
|
||
}
|
||
// Один массив, другой - нет
|
||
else if (Array.isArray(val1) || Array.isArray(val2)) {
|
||
return true
|
||
}
|
||
// Сравнение строк
|
||
else if (typeof val1 === 'string' && typeof val2 === 'string') {
|
||
if (val1.trim() !== val2.trim()) return true
|
||
}
|
||
// Сравнение примитивов
|
||
else if (val1 !== val2) {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
function filterIgnored(obj: Record<string, unknown>): Record<string, string | number | boolean | (string | number)[]> {
|
||
const filtered: Record<string, string | number | boolean | (string | number)[]> = {}
|
||
|
||
for (const key in obj) {
|
||
const value = obj[key]
|
||
|
||
// Обработка массивов
|
||
if (Array.isArray(value)) {
|
||
// Отбрасываем пустые массивы
|
||
if (value.length === 0) continue
|
||
|
||
// Фильтруем массивы с некорректными элементами
|
||
if (value.every(item =>
|
||
typeof item === 'string' ||
|
||
typeof item === 'number'
|
||
)) {
|
||
filtered[key] = value
|
||
}
|
||
continue
|
||
}
|
||
|
||
// Обработка примитивов
|
||
if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {
|
||
continue
|
||
}
|
||
|
||
// Обработка строк
|
||
if (typeof value === 'string') {
|
||
const trimmed = value.trim()
|
||
if (trimmed === '') continue
|
||
filtered[key] = trimmed
|
||
}
|
||
// Обработка чисел и boolean
|
||
else if (value !== 0 && value !== false) {
|
||
filtered[key] = value
|
||
}
|
||
}
|
||
|
||
return filtered
|
||
}
|
||
|
||
function parseIntString (s: string | string[] | undefined) :number | null {
|
||
if (typeof s !== 'string') return null
|
||
const regex = /^[+-]?\d+$/
|
||
return regex.test(s) ? Number(s) : null
|
||
}
|
||
|
||
// Функция для преобразования пустых строк в null
|
||
function convertEmptyStringsToNull<T extends Record<string, unknown>>(obj: T): T {
|
||
const result = { ...obj } as Record<string, unknown>
|
||
|
||
Object.keys(result).forEach(key => {
|
||
if (result[key] === '') {
|
||
result[key] = null
|
||
}
|
||
})
|
||
|
||
return result as T
|
||
}
|
||
|
||
|
||
export {
|
||
isDirty,
|
||
parseIntString,
|
||
convertEmptyStringsToNull
|
||
} |