From 9b4cfb45dacd57fd43d742f6347dbbeffb91181c Mon Sep 17 00:00:00 2001 From: Sg Date: Mon, 23 Jun 2025 18:38:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B0=86=E5=90=8E=E7=BB=AD=E7=9A=84?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=BC=95=E7=94=A8=E8=A7=A3=E6=9E=90=E3=80=81?= =?UTF-8?q?=E6=B3=9B=E5=9E=8B=E7=B1=BB=E5=9E=8B=E8=A7=A3=E6=9E=90=E7=A7=BB?= =?UTF-8?q?=E6=A4=8D=E5=9B=9E=E6=97=A7=E7=89=88=E6=9C=AC=E4=BB=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=B1=BB=E5=9E=8B=E5=8C=B9=E9=85=8D=20(#60)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 添加类型引用解析功能以支持类型匹配 * fix * fix * fix --- packages/basic/src/init/dataTypes/tools.ts | 43 ++++++++++++++++++++++ packages/basic/src/init/dataTypes/types.ts | 32 ++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 packages/basic/src/init/dataTypes/types.ts diff --git a/packages/basic/src/init/dataTypes/tools.ts b/packages/basic/src/init/dataTypes/tools.ts index 36605111..fb1adada 100644 --- a/packages/basic/src/init/dataTypes/tools.ts +++ b/packages/basic/src/init/dataTypes/tools.ts @@ -4,6 +4,7 @@ import moment from "moment"; import { flatMap, xor } from "lodash"; import { getAppTimezone, safeNewDate } from "../utils"; +import { type TypeAnnotation } from "./types"; import Config from "../../config"; function tryJSONParse(str) { @@ -356,6 +357,24 @@ function unorderedArrayEqual(a: T[], b: T[]) { return xor(a, b).length === 0; } +/** + * 解析类型引用到实际的类型定义 + * @param typeAnnotation 需要解析的类型标注 + * @returns 如果解析成功则返回解析后的类型属性,解析失败返回undefined + */ +function resolveTypeReference(typeAnnotation: TypeAnnotation) { + if (typeAnnotation.typeKind === "reference") { + const typeKey = genSortedTypeKey(typeAnnotation); + const candidateDef = typeDefinitionMap[typeKey]; + // 如果仍然是type reference,那么视作失败 + if (candidateDef?.concept === "TypeAnnotation" && candidateDef.typeKind === "reference") { + return undefined; + } + return candidateDef; + } + return undefined; +} + function exactMatchShapeAgainstDef(value, def: any): boolean { function isMatchForPrimitive(value, ty) { const valueTypeStr = Object.prototype.toString.call(value); @@ -387,6 +406,25 @@ function exactMatchShapeAgainstDef(value, def: any): boolean { } return false; } else if (def.typeKind === "generic") { + if (def.typeName === "List" && def.typeNamespace === "nasl.collection") { + const targetTy: TypeAnnotation = def.typeArguments[0]; + if (!targetTy || !Array.isArray(value)) { + return false; + } + return value.every((item) => exactMatchShapeAgainstDef(item, targetTy)); + } else if (def.typeName === "Map" && def.typeNamespace === "nasl.collection") { + const keyTy = def.typeArguments[0]; + const valueTy = def.typeArguments[1]; + if (!keyTy || !valueTy || typeof value !== "object" || value === null || Array.isArray(value)) { + return false; + } + for (const [k, v] of Object.entries(value)) { + if (!exactMatchShapeAgainstDef(k, keyTy) || !exactMatchShapeAgainstDef(v, valueTy)) { + return false; + } + } + return true; + } return isInstanceOf(value, genSortedTypeKey(def)); } else if (def.properties) { const properties = def.properties; @@ -410,6 +448,11 @@ function exactMatchShapeAgainstDef(value, def: any): boolean { } } return false; + } else if (def.typeKind === "reference") { + const resolved = resolveTypeReference(def); + if (resolved) { + return exactMatchShapeAgainstDef(value, resolved); + } } return false; } diff --git a/packages/basic/src/init/dataTypes/types.ts b/packages/basic/src/init/dataTypes/types.ts new file mode 100644 index 00000000..131d7db0 --- /dev/null +++ b/packages/basic/src/init/dataTypes/types.ts @@ -0,0 +1,32 @@ +export type TypeAnnotation = + | { + typeKind: "primitive"; + typeNamespace: string; + typeName: string; + concept: "TypeAnnotation"; + } + | { typeKind: "reference"; typeName: string; typeNamespace: string; concept: "TypeAnnotation" } + | { + typeKind: "union"; + typeArguments: TypeAnnotation[]; + typeName: string; + typeNamespace: string; + concept: "TypeAnnotation"; + } + | { + typeKind: "anonymousStructure"; + properties: TypeAnnotation[]; + typeName: undefined; + typeNamespace: undefined; + concept: "TypeAnnotation"; + } + | { + typeKind: "generic"; + typeArguments: TypeAnnotation[]; + typeName: string; + typeNamespace: string; + concept: "TypeAnnotation"; + }; +type DefaultValue = { + expression: { concept: "StringLiteral"; value: string | null | undefined } | {} | null; +};