import { Schema } from '..'; import { basicTypeMap, getBasicTypeRef } from './basicTypes'; import { dataTypesMap } from './dataTypes'; import { getGenericTypeRef } from './genericTypes'; import { cloneDeep } from 'lodash'; /** * 会改变原来的结构,最好自己做深拷贝 * @param schema * @param root * @example RefType - 用于前端界面的类型描述 * { * asset: { * type: 'object', * propertyList: [ * { name: 'id', $ref: '#/basicType/Long' }, * { name: 'name', $ref: '#/basicType/String' }, * ], * }, * assetType: { * type: 'enum', * enumItemList: [ * { value: 'COMPUTER', label: '台式机' }, * { value: 'TABLET', label: '平板电脑' }, * { value: 'MOBILE', label: '移动电话' }, * }, * }, * assets: { * isArray: true, * $ref: '#/xxxx/entity/asset' * }, * test: { $ref: '#/basicType/Date' } * } */ export function convert2RefType(schema: Schema): Schema { if (!schema) return schema; if (schema.type === 'object') { if (schema.properties) { schema.propertyList = Object.keys(schema.properties).map((name) => { const property = schema.properties[name]; property.name = name; return property; }); delete schema.properties; } schema.propertyList = !schema.propertyList ? [] : schema.propertyList.map((property) => convert2RefType(property)); } else if (schema.type === 'enum') { if (schema.enumItems) { schema.enumItemList = Object.keys(schema.enumItems).map((value) => ({ level: 'enumItem', label: schema.enumItems[value], value, })); } delete schema.enumItems; } else if (schema.type === 'array') { schema.isArray = true; // 转成泛型 const listSchema = dataTypesMap['#/genericTypes/List']; if (listSchema) { const genericSchema = { type: 'genericType', typeKey: '#/genericTypes/List', typeInstantiation: { typeName: 'List', typeParams: (listSchema.typeParams || []).map((param: any) => { const tempParam = Object.assign({}, param); tempParam.typeParamValue = convert2RefType(schema.items); tempParam.type = 'typeParam'; return tempParam; }), }, }; delete schema.items; Object.assign(schema, genericSchema); } } else if (schema.type === 'genericType') { if (schema.typeInstantiation) { schema.typeKey = getGenericTypeRef(schema.typeInstantiation.typeName); schema.typeInstantiation.typeParams.forEach((typeParam) => { typeParam.type = 'typeParam'; convert2RefType(typeParam.typeParamValue); }); } } else if (schema.type) { schema.typeKey = getBasicTypeRef(schema.type, schema.format); } else if (schema.$ref) { if (schema.$ref.startsWith('#/basicTypes')) { //兼容错误缓存情况 schema.typeKey = schema.$ref; Object.assign(schema, dataTypesMap[schema.$ref]); delete schema.$ref; } else { schema.typeKey = schema.$ref; delete schema.type; delete schema.format; } } return schema; } /** * 会改变原来的结构,最好自己做深拷贝 * @param schema * @param root * @example SchemaType - 非标准的 JSON Schema 结构 * { * asset: { * type: 'object', * propertyList: [ * { type: 'int', format: 'long' }, * { type: 'string' }, * ], * }, * assetType: { * type: 'enum', * enumItemList: [ * { value: 'COMPUTER', label: '台式机' }, * { value: 'TABLET', label: '平板电脑' }, * { value: 'MOBILE', label: '移动电话' }, * }, * }, * assets: { * isArray: true, * items: { * $ref: '#/xxxx/entity/asset' * } * }, * test: { type: 'string', format: 'date' } * } */ export function convert2SchemaType(schema: Schema, options: { enum?: string } = {}) { if (!schema) return schema; if (schema.type === 'object') { schema.propertyList && schema.propertyList.forEach((property) => convert2SchemaType(property)); } else if (schema.type === 'enum') { // } else if (schema.isArray) { // 去除 // } else if (schema.$ref) { // 兼容老版本传$ref if (!schema.$ref.startsWith('#/basicTypes/')) { // 防止切换 type 时的污染 delete schema.type; delete schema.format; Object.assign(schema, { typeKey: schema.$ref }); } else { Object.assign(schema, { typeKey: schema.$ref }); Object.assign(schema, basicTypeMap[schema.$ref]); delete schema.$ref; } } else if (schema.typeKey) { // 从s-datatype-select中选择类型后只传typeKey if (schema.typeKey.startsWith('#/genericTypes')) { if (!schema.typeInstantiation) return schema; schema = { type: 'genericType', typeKey: `#/genericTypes/${schema.typeInstantiation.typeName}`, typeInstantiation: { typeName: schema.typeInstantiation.typeName, typeParams: schema.typeInstantiation.typeParams.map((typeParam: any) => { delete typeParam.tempColor; delete typeParam.tempText; typeParam.typeParamValue = convert2SchemaType(typeParam.typeParamValue); typeParam.type = 'typeParam'; return typeParam; }), }, }; } else if (!schema.typeKey.startsWith('#/basicTypes/')) { // { $ref: '', typeKey: ''} // 防止切换 type 时的污染 schema = { $ref: schema.typeKey, typeKey: schema.typeKey }; } else { schema = Object.assign({ typeKey: schema.typeKey }, basicTypeMap[schema.typeKey]); } } return schema; } /** * 根据 Ref Schema 生成子节点 * @param schema * @param code * @param dataTypesMap */ export function genSchemaChildren( schema: Schema, code: string = '', usedSchemaRefs: { [name: string]: boolean } = {}, ): Array { const typeKey = schema.typeKey; if (typeKey && usedSchemaRefs[typeKey]) return; // 理论上可以继续往下选,但这里先断掉! const next = dataTypesMap[typeKey]; usedSchemaRefs = Object.assign({}, usedSchemaRefs); if (typeKey && !(typeKey.startsWith('#/basicTypes/') || typeKey.startsWith('#/genericTypes/'))) usedSchemaRefs[typeKey] = true; if (schema.type === 'genericType') { const children: Array = []; const genericClass = dataTypesMap[schema.typeKey]; if (genericClass) { const propertyList = genericClass.propertyList; propertyList.forEach((property: any) => { let propertySchema = cloneDeep(property); if (property.type === 'genericParam' && schema.typeInstantiation) { const param = schema.typeInstantiation.typeParams.find((typeParam: any) => typeParam.typeParamName === property.typeParamName); if (param) { propertySchema = Object.assign({ name: property.name }, param.typeParamValue); } } else if (propertySchema.type === 'genericType' && schema.typeInstantiation) { if (propertySchema.typeInstantiation) { propertySchema.typeInstantiation.typeParams.forEach((typeParam: any) => { const param = schema.typeInstantiation.typeParams.find((typeParamTemp: any) => typeParamTemp.typeParamName === typeParam.typeParamName); if (param) { typeParam.typeParamValue = Object.assign({}, param.typeParamValue); } }); } } const item: any = { level: 'property', name: propertySchema.name, schema: propertySchema, code: property.id ? `${code}.ID_${property.id}` : `${code}.${property.name}`, }; if (schema.typeName === '#/genericTypes/List') { item.arrayLength = true; } item.children = genRefSchemaChildren(item.schema, item.code, usedSchemaRefs); item.isLeaf = !item.children; children.push(item); }); } return children; } else if (schema.type === 'object') { const children: Array = []; schema.propertyList && schema.propertyList.forEach((property: Schema) => { const item: any = { level: 'property', name: property.name, schema: property, code: code + '.' + (property.id ? 'ID_' + property.id : property.name), }; item.children = genSchemaChildren(item.schema, item.code, usedSchemaRefs); item.isLeaf = !item.children; children.push(item); }); return children; } else if (schema.isArray) { // } else if (typeKey && typeKey.startsWith('#/basicTypes')) { return undefined; } else if (next) { return genSchemaChildren(next, code, usedSchemaRefs); } } /** * 根据 Ref Schema 生成子节点 * @param schema * @param code */ export function genRefSchemaChildren( schema: Schema, code: string, usedSchemaRefs: { [name: string]: boolean } = {}, ): Array { if (!schema) return; const typeKey = schema.typeKey; if (typeKey && usedSchemaRefs[typeKey]) return; // 理论上可以继续往下选,但这里先断掉! const next = dataTypesMap[typeKey]; usedSchemaRefs = Object.assign({}, usedSchemaRefs); if (typeKey && !(typeKey.startsWith('#/basicTypes/') || typeKey.startsWith('#/genericTypes/'))) usedSchemaRefs[typeKey] = true; if (schema.type === 'genericType') { const children: Array = []; const genericClass = dataTypesMap[schema.typeKey]; if (genericClass) { const propertyList = genericClass.propertyList; propertyList.forEach((property: any) => { let propertySchema = cloneDeep(property); if (property.type === 'genericParam' && schema.typeInstantiation) { const param = schema.typeInstantiation.typeParams.find((typeParam: any) => typeParam.typeParamName === property.typeParamName); if (param) { propertySchema = Object.assign({ name: property.name }, param.typeParamValue); } } else if (propertySchema.type === 'genericType' && schema.typeInstantiation) { if (propertySchema.typeInstantiation) { propertySchema.typeInstantiation.typeParams.forEach((typeParam: any) => { const param = schema.typeInstantiation.typeParams.find((typeParamTemp: any) => typeParamTemp.typeParamName === typeParam.typeParamName); if (param) { typeParam.typeParamValue = Object.assign({}, param.typeParamValue); } }); } } const item: any = { level: 'refProperty', schema: propertySchema, code: property.id ? `${code}.ID_${property.id}` : `${code}.${property.name}`, }; if (schema.typeKey === '#/genericTypes/List') { item.arrayLength = true; } item.children = genRefSchemaChildren(item.schema, item.code, usedSchemaRefs); item.isLeaf = !item.children; children.push(item); }); } return children; } else if (schema.type === 'object') { const children: Array = []; schema.propertyList && schema.propertyList.forEach((property: Schema) => { const item: any = { level: 'refProperty', schema: property, code: property.id ? `${code}.ID_${property.id}` : `${code}.${property.name}`, }; item.children = genRefSchemaChildren(item.schema, item.code, usedSchemaRefs); item.isLeaf = !item.children; children.push(item); }); return children; } else if (schema.isArray) { // } else if (typeKey && typeKey.startsWith('#/basicTypes')) { return undefined; } else if (next) { return genRefSchemaChildren(next, code, usedSchemaRefs); } } /** * 根据 Ref Schema 生成子节点 * @param schema * @param code */ export function genFullRefSchemaChildren(schema: Schema, code: string, usedSchemaRefs: { [name: string]: boolean } = {}): Array { if (!schema) return; const typeKey = schema.typeKey; if (typeKey && usedSchemaRefs[typeKey]) return; // 理论上可以继续往下选,但这里先断掉! const next = dataTypesMap[typeKey]; usedSchemaRefs = Object.assign({}, usedSchemaRefs); if (typeKey && !(typeKey.startsWith('#/basicTypes/') || typeKey.startsWith('#/genericTypes/'))) usedSchemaRefs[typeKey] = true; if (schema.type === 'genericType') { let children: Array = []; if (schema.typeKey === '#/genericTypes/List') { children = genRefSchemaChildren(schema.typeInstantiation.typeParams[0].typeParamValue, code, usedSchemaRefs); } else { const genericClass = dataTypesMap[schema.typeKey]; if (genericClass) { const propertyList = genericClass.propertyList; propertyList.forEach((property: any) => { let propertySchema = cloneDeep(property); if (property.type === 'genericParam' && schema.typeInstantiation) { const param = schema.typeInstantiation.typeParams.find((typeParam: any) => typeParam.typeParamName === property.typeParamName); if (param) { propertySchema = Object.assign({ name: property.name }, param.typeParamValue); } } else if (propertySchema.type === 'genericType' && schema.typeInstantiation) { if (propertySchema.typeInstantiation) { propertySchema.typeInstantiation.typeParams.forEach((typeParam: any) => { const param = schema.typeInstantiation.typeParams.find((typeParamTemp: any) => typeParamTemp.typeParamName === typeParam.typeParamName); if (param) { typeParam.typeParamValue = Object.assign({}, param.typeParamValue); } }); } } const item: any = { level: 'refProperty', schema: propertySchema, code: property.id ? `${code}.ID_${property.id}` : `${code}.${property.name}`, }; item.children = genRefSchemaChildren(item.schema, item.code, usedSchemaRefs); item.isLeaf = !item.children; children.push(item); }); } } return children; } else if (schema.type === 'object') { const children: Array = []; schema.propertyList && schema.propertyList.forEach((property: Schema) => { const item: any = { level: 'refProperty', schema: property, code: `${code}.ID_${property.id}`, }; item.children = genFullRefSchemaChildren(item.schema, item.code, usedSchemaRefs); item.isLeaf = !item.children; children.push(item); }); return children; } else if (schema.isArray) { // } else if (typeKey && typeKey.startsWith('#/basicTypes')) { return undefined; } else if (next) { return genFullRefSchemaChildren(next, code, usedSchemaRefs); } } /** * 统一在 lcap-pc-template 中处理 */ export function genInitData(schema: Schema, relationship = 'None', usedSchemaRefs: { [name: string]: boolean } = {}): any { throw new Error('统一在 lcap-pc-template 中处理!'); }