Created
January 26, 2024 01:50
-
-
Save mnikn/bc7ec4d7e7011d38d1d31fb2a57c0f18 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dayjs, { Dayjs } from 'dayjs'; | |
import { get } from 'lodash'; | |
type FormatOptions = { | |
reliable: boolean; | |
}; | |
type BaseSchemaField = { | |
type: SchemaFieldType; | |
source?: ((parentSourceData: any, rootSourceData: any) => any) | string; | |
optional?: boolean; | |
customConvert?: (fieldData: any, parentSourceData: any, rootSourceData: any) => any; | |
}; | |
type SchemaFieldType = 'string' | 'number' | 'enum' | 'boolean' | 'date' | 'array' | 'object'; | |
type NumberSchemaField = BaseSchemaField & { | |
type: 'number'; | |
defaultValue?: number; | |
}; | |
type EnumSchemaField = BaseSchemaField & { | |
type: 'enum'; | |
enumType: Record<string, string | number>; | |
defaultValue?: number | string; | |
}; | |
type StringSchemaField = BaseSchemaField & { | |
type: 'string'; | |
defaultValue?: string; | |
}; | |
type BooleanSchemaField = BaseSchemaField & { | |
type: 'boolean'; | |
defaultValue?: boolean; | |
}; | |
type DateSchemaField = BaseSchemaField & { | |
type: 'date'; | |
defaultValue?: Dayjs; | |
isUnixTime?: boolean; | |
}; | |
type ObjectSchemaField = BaseSchemaField & { | |
type: 'object'; | |
defaultValue?: object; | |
fields?: Record<string, SchemaField>; | |
}; | |
type ArraySchemaField = BaseSchemaField & { | |
type: 'array'; | |
defaultValue?: any[]; | |
itemSchema?: SchemaField; | |
}; | |
export type SchemaField = | |
| StringSchemaField | |
| NumberSchemaField | |
| BooleanSchemaField | |
| EnumSchemaField | |
| DateSchemaField | |
| ObjectSchemaField | |
| ArraySchemaField; | |
// type MapToSchemaField<T extends SchemaFieldType> = T extends 'string' | |
// ? StringSchemaField | |
// : T extends 'number' | |
// ? NumberSchemaField | |
// : T extends 'enum' | |
// ? EnumSchemaField | |
// : T extends 'boolean' | |
// ? BooleanSchemaField | |
// : T extends 'date' | |
// ? DateSchemaField | |
// : T extends 'object' | |
// ? ObjectSchemaField | |
// : T extends 'array' | |
// ? ArraySchemaField | |
// : ObjectSchemaField; | |
type GetSchemaFormatValue<T extends SchemaField> = T extends ObjectSchemaField | |
? Record<keyof T['fields'], any> | |
: T extends ArraySchemaField | |
? any[] | |
: T extends StringSchemaField | |
? string | |
: T extends NumberSchemaField | |
? number | |
: T extends EnumSchemaField | |
? string | number | |
: T extends BooleanSchemaField | |
? boolean | |
: undefined; | |
export function generateDefaultJson<T extends SchemaField>( | |
schemaField: T, | |
options: FormatOptions = { reliable: true } | |
) { | |
return formatJson(null, schemaField, options); | |
} | |
export function formatJson<T extends SchemaField>( | |
data: Array<unknown> | Record<string, unknown> | null, | |
schemaField: T, | |
options: FormatOptions = { reliable: true } | |
) { | |
return doFormatFieldData(data, schemaField, options, null, data); | |
} | |
function doFormatFieldData<T extends SchemaField>( | |
data: any, | |
schemaField: T, | |
options: FormatOptions = { reliable: true }, | |
parentSourceData?: any, | |
rootSourceData?: any | |
): GetSchemaFormatValue<T> { | |
let fieldValue: any = schemaField.defaultValue; | |
if (schemaField.customConvert) { | |
fieldValue = schemaField.customConvert(data, parentSourceData, rootSourceData); | |
} else { | |
if (schemaField.type === 'string') { | |
const finalSchemaField = schemaField as StringSchemaField; | |
fieldValue = doCovnertString(data, finalSchemaField, options); | |
} | |
if (schemaField.type === 'number') { | |
const finalSchemaField = schemaField as NumberSchemaField; | |
fieldValue = doCovnertNumber(data, finalSchemaField, options); | |
} | |
if (schemaField.type === 'boolean') { | |
const finalSchemaField = schemaField as BooleanSchemaField; | |
fieldValue = doCovnertBoolean(data, finalSchemaField, options); | |
} | |
if (schemaField.type === 'enum') { | |
const finalSchemaField = schemaField as EnumSchemaField; | |
fieldValue = doCovnertEnum(data, finalSchemaField, options); | |
} | |
if (schemaField.type === 'date') { | |
const finalSchemaField = schemaField as DateSchemaField; | |
fieldValue = doCovnertDate(data, finalSchemaField, options); | |
} | |
if (schemaField.type === 'object') { | |
const finalSchemaField = schemaField as ObjectSchemaField; | |
if (!((data === undefined && schemaField.optional) || !options.reliable)) { | |
fieldValue = Object.keys(finalSchemaField?.fields || {}).reduce((res, key) => { | |
let subFieldData: unknown; | |
// const subFieldSchema = toSchemaField(finalSchemaField.fields[key]); | |
const subFieldSchema = (finalSchemaField?.fields || {})[key]; | |
if (subFieldSchema.source instanceof Function) { | |
subFieldData = subFieldSchema.source(data, rootSourceData); | |
} else if (subFieldSchema.source && get(data, subFieldSchema.source, undefined) !== undefined) { | |
subFieldData = get(data, subFieldSchema.source, undefined); | |
} else if (get(data, key, undefined) !== undefined) { | |
subFieldData = get(data, key, undefined); | |
} | |
res[key] = doFormatFieldData(subFieldData, subFieldSchema, options, data, rootSourceData); | |
return res; | |
}, {} as any); | |
} | |
} | |
if (schemaField.type === 'array') { | |
const finalSchemaField = schemaField as ArraySchemaField; | |
const itemSchema = finalSchemaField.itemSchema; | |
if (itemSchema && !((data === undefined && schemaField.optional) || !options.reliable)) { | |
const arr = data || []; | |
fieldValue = arr.map((item: any) => { | |
return doFormatFieldData(item, itemSchema, options, data, rootSourceData); | |
}); | |
} | |
} | |
} | |
return fieldValue; | |
} | |
function doCovnertNumber(sourceData: any, schema: NumberSchemaField, options?: FormatOptions) { | |
if (typeof sourceData === 'number') { | |
return sourceData; | |
} | |
let val = 'defaultValue' in schema ? schema.defaultValue : undefined; | |
if ((val === undefined || val === null) && options?.reliable && !schema.optional) { | |
val = 0; | |
} | |
return val; | |
} | |
function doCovnertString(sourceData: any, schema: StringSchemaField, options?: FormatOptions) { | |
if (typeof sourceData === 'string') { | |
return sourceData; | |
} | |
let val = 'defaultValue' in schema ? schema.defaultValue : undefined; | |
if ((val === undefined || val === null) && options?.reliable && !schema.optional) { | |
val = ''; | |
} | |
return val; | |
} | |
function doCovnertBoolean(sourceData: any, schema: BooleanSchemaField, options?: FormatOptions) { | |
if (typeof sourceData === 'number') { | |
return sourceData === 1; | |
} | |
if (typeof sourceData === 'boolean') { | |
return sourceData; | |
} | |
let val = 'defaultValue' in schema ? schema.defaultValue : undefined; | |
if ((val === undefined || val === null) && options?.reliable && !schema.optional) { | |
val = false; | |
} | |
return val; | |
} | |
function doCovnertEnum(sourceData: any, schema: EnumSchemaField, options?: FormatOptions) { | |
if (sourceData in schema.enumType) { | |
return sourceData; | |
} | |
let val = 'defaultValue' in schema ? schema.defaultValue : undefined; | |
if ((val === undefined || val === null) && options?.reliable && !schema.optional) { | |
if (typeof schema.enumType === 'string') { | |
val = ''; | |
} else { | |
val = 0; | |
} | |
} | |
return val; | |
} | |
function doCovnertDate(sourceData: any, schema: DateSchemaField, options?: FormatOptions) { | |
if (typeof sourceData === 'string' || typeof sourceData === 'number') { | |
if (schema.isUnixTime && typeof sourceData === 'number') { | |
return dayjs(sourceData * 1000); | |
} | |
return dayjs(sourceData); | |
} | |
let val = 'defaultValue' in schema ? schema.defaultValue : undefined; | |
if ((val === undefined || val === null) && options?.reliable && !schema.optional) { | |
val = dayjs(); | |
} | |
return val; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment