mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
* feat(utils): add record guards and pure helpers to @sim/utils Add isRecordLike (loose, non-prototype-checked record guard) and sortObjectKeysDeep; relocate isPlainRecord (strict) and normalizeEmail into @sim/utils so they are reusable across apps and packages. Unit tests cover the loose-vs-strict distinction, deep key sorting, and email normalization. * refactor(sim): consolidate record guards and normalize helpers onto @sim/utils Replace ~55 re-implemented loose record guards with the canonical @sim/utils isRecordLike (and one strict site with isPlainRecord), and dedupe three normalize clusters: sortObjectKeysDeep (sanitization + copilot builders), normalizeToken (salesforce + servicenow triggers), and normalizeEmail. Array-allowing guards and domain-specific normalizers are intentionally left untouched. Pure refactor — identical predicates and transforms, no behavior change.
72 lines
2.0 KiB
TypeScript
72 lines
2.0 KiB
TypeScript
/**
|
|
* @vitest-environment node
|
|
*/
|
|
import { describe, expect, it } from 'vitest'
|
|
import { isPlainRecord, isRecordLike, sortObjectKeysDeep } from './object.js'
|
|
|
|
class Sample {
|
|
value = 1
|
|
}
|
|
|
|
describe('isRecordLike', () => {
|
|
it('returns true for plain objects, Date, and class instances', () => {
|
|
expect(isRecordLike({})).toBe(true)
|
|
expect(isRecordLike(new Date())).toBe(true)
|
|
expect(isRecordLike(new Sample())).toBe(true)
|
|
})
|
|
|
|
it('returns false for arrays, null, and primitives', () => {
|
|
expect(isRecordLike([])).toBe(false)
|
|
expect(isRecordLike(null)).toBe(false)
|
|
expect(isRecordLike('not-a-record')).toBe(false)
|
|
expect(isRecordLike(42)).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('isPlainRecord', () => {
|
|
it('returns true for plain objects', () => {
|
|
expect(isPlainRecord({})).toBe(true)
|
|
expect(isPlainRecord(Object.create(null))).toBe(true)
|
|
})
|
|
|
|
it('returns false for Date, class instances, arrays, and null', () => {
|
|
expect(isPlainRecord(new Date())).toBe(false)
|
|
expect(isPlainRecord(new Sample())).toBe(false)
|
|
expect(isPlainRecord([])).toBe(false)
|
|
expect(isPlainRecord(null)).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('sortObjectKeysDeep', () => {
|
|
it('sorts keys deeply and recurses into array elements', () => {
|
|
const input = {
|
|
b: 1,
|
|
a: { d: 4, c: 3 },
|
|
list: [{ z: 26, y: 25 }],
|
|
}
|
|
const sorted = sortObjectKeysDeep(input)
|
|
expect(JSON.stringify(sorted)).toBe(
|
|
JSON.stringify({ a: { c: 3, d: 4 }, b: 1, list: [{ y: 25, z: 26 }] })
|
|
)
|
|
})
|
|
|
|
it('returns primitives and null unchanged', () => {
|
|
expect(sortObjectKeysDeep(null)).toBe(null)
|
|
expect(sortObjectKeysDeep(42)).toBe(42)
|
|
expect(sortObjectKeysDeep('x')).toBe('x')
|
|
})
|
|
|
|
it('preserves array order while sorting element keys', () => {
|
|
const sorted = sortObjectKeysDeep([
|
|
{ b: 1, a: 2 },
|
|
{ d: 3, c: 4 },
|
|
])
|
|
expect(JSON.stringify(sorted)).toBe(
|
|
JSON.stringify([
|
|
{ a: 2, b: 1 },
|
|
{ c: 4, d: 3 },
|
|
])
|
|
)
|
|
})
|
|
})
|