refactor: improve JSON schema handling and type inference

This commit is contained in:
twwu 2025-04-02 14:46:21 +08:00
parent 268364a3e8
commit 5e8334a3db
4 changed files with 38 additions and 14 deletions

View File

@ -116,6 +116,7 @@ const JsonSchemaConfig: FC<JsonSchemaConfigProps> = ({
else if (currentTab === SchemaView.VisualEditor) { else if (currentTab === SchemaView.VisualEditor) {
if (advancedEditing || isAddingNewField) if (advancedEditing || isAddingNewField)
emit('quitEditing', { callback: (backup: SchemaRoot) => setJson(JSON.stringify(backup || jsonSchema, null, 2)) }) emit('quitEditing', { callback: (backup: SchemaRoot) => setJson(JSON.stringify(backup || jsonSchema, null, 2)) })
setJson(JSON.stringify(jsonSchema, null, 2))
} }
setCurrentTab(value) setCurrentTab(value)

View File

@ -152,9 +152,15 @@ const EditCard: FC<EditCardProps> = ({
}, [isAdvancedEditing, emitPropertyOptionsChange, currentFields]) }, [isAdvancedEditing, emitPropertyOptionsChange, currentFields])
const handleAdvancedOptionsChange = useCallback((options: AdvancedOptionsType) => { const handleAdvancedOptionsChange = useCallback((options: AdvancedOptionsType) => {
let enumValue: SchemaEnumType = options.enum.replace(/\s/g, '').split(',') let enumValue: any = options.enum
if (currentFields.type === Type.number) if (enumValue === '') {
enumValue = enumValue.map(value => Number(value)).filter(num => !Number.isNaN(num)) enumValue = undefined
}
else {
enumValue = options.enum.replace(/\s/g, '').split(',')
if (currentFields.type === Type.number)
enumValue = (enumValue as SchemaEnumType).map(value => Number(value)).filter(num => !Number.isNaN(num))
}
setCurrentFields(prev => ({ ...prev, enum: enumValue })) setCurrentFields(prev => ({ ...prev, enum: enumValue }))
if (isAdvancedEditing) return if (isAdvancedEditing) return
emitPropertyOptionsChange({ description: currentFields.description, enum: enumValue }) emitPropertyOptionsChange({ description: currentFields.description, enum: enumValue })

View File

@ -39,7 +39,10 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
useSubscribe('quitEditing', (params) => { useSubscribe('quitEditing', (params) => {
const { callback } = params as any const { callback } = params as any
callback?.(backupSchema) callback?.(backupSchema)
emit('restoreSchema') if (backupSchema) {
onChange(backupSchema)
setBackupSchema(null)
}
isAddingNewField && setIsAddingNewField(false) isAddingNewField && setIsAddingNewField(false)
advancedEditing && setAdvancedEditing(false) advancedEditing && setAdvancedEditing(false)
setHoveringProperty(null) setHoveringProperty(null)

View File

@ -27,13 +27,27 @@ export const getHasChildren = (schema: Field) => {
return schema.items && schema.items.type === Type.object && schema.items.properties && Object.keys(schema.items.properties).length > 0 return schema.items && schema.items.type === Type.object && schema.items.properties && Object.keys(schema.items.properties).length > 0
} }
export const getTypeOf = (target: any) => {
if (target === null) return 'null'
if (typeof target !== 'object') {
return typeof target
}
else {
return Object.prototype.toString
.call(target)
.slice(8, -1)
.toLocaleLowerCase()
}
}
export const inferType = (value: any): Type => { export const inferType = (value: any): Type => {
if (Array.isArray(value)) return Type.array const type = getTypeOf(value)
if (type === 'array') return Type.array
// type boolean will be treated as string // type boolean will be treated as string
if (typeof value === 'boolean') return Type.string if (type === 'boolean') return Type.string
if (typeof value === 'number') return Type.number if (type === 'number') return Type.number
if (typeof value === 'string') return Type.string if (type === 'string') return Type.string
if (typeof value === 'object') return Type.object if (type === 'object') return Type.object
return Type.string return Type.string
} }
@ -60,16 +74,16 @@ export const jsonToSchema = (json: any): Field => {
} }
export const checkJsonDepth = (json: any) => { export const checkJsonDepth = (json: any) => {
if (!json || typeof json !== 'object') if (!json || getTypeOf(json) !== 'object')
return 0 return 0
let maxDepth = 0 let maxDepth = 0
if (Array.isArray(json)) { if (getTypeOf(json) === 'array') {
if (json[0] && typeof json[0] === 'object') if (json[0] && getTypeOf(json[0]) === 'object')
maxDepth = checkJsonDepth(json[0]) maxDepth = checkJsonDepth(json[0])
} }
else if (typeof json === 'object') { else if (getTypeOf(json) === 'object') {
const propertyDepths = Object.values(json).map(value => checkJsonDepth(value)) const propertyDepths = Object.values(json).map(value => checkJsonDepth(value))
maxDepth = propertyDepths.length ? Math.max(...propertyDepths) + 1 : 1 maxDepth = propertyDepths.length ? Math.max(...propertyDepths) + 1 : 1
} }
@ -78,7 +92,7 @@ export const checkJsonDepth = (json: any) => {
} }
export const checkJsonSchemaDepth = (schema: Field) => { export const checkJsonSchemaDepth = (schema: Field) => {
if (!schema || typeof schema !== 'object') if (!schema || getTypeOf(schema) !== 'object')
return 0 return 0
let maxDepth = 0 let maxDepth = 0