Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions packages/basic/src/init/dataTypes/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -356,6 +357,24 @@ function unorderedArrayEqual<T>(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);
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
32 changes: 32 additions & 0 deletions packages/basic/src/init/dataTypes/types.ts
Original file line number Diff line number Diff line change
@@ -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;
};