-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgetTypeVariant.ts
More file actions
64 lines (56 loc) · 2.23 KB
/
Copy pathgetTypeVariant.ts
File metadata and controls
64 lines (56 loc) · 2.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import ts from "typescript";
import {createCompilerHost, getSharedTypeDeclarations} from "../utils";
import {DataType} from "@code0-tech/sagittarius-graphql-types";
export enum DataTypeVariant {
PRIMITIVE,
TYPE,
ARRAY,
OBJECT,
}
/**
* Determines the variant of a given TypeScript type string using the TS compiler.
*/
export const getTypeVariant = (
type: string,
dataTypes: DataType[]
): DataTypeVariant => {
const typeDefs = getSharedTypeDeclarations(dataTypes);
// We declare a variable with the type to probe it
const sourceCode = `
${typeDefs}
type TargetType = ${type};
const val: TargetType = {} as any;
`;
const fileName = `index.ts`;
const host = createCompilerHost(fileName, sourceCode);
const sourceFile = host.getSourceFile(fileName)!;
const program = host.languageService.getProgram()!;
const checker = program.getTypeChecker();
let discoveredVariant: DataTypeVariant = DataTypeVariant.TYPE;
const visit = (node: ts.Node) => {
if (ts.isVariableDeclaration(node) && node.name.getText() === "val") {
const type = checker.getTypeAtLocation(node);
if (checker.isArrayType(type)) {
discoveredVariant = DataTypeVariant.ARRAY;
} else if (
type.isStringLiteral() ||
type.isNumberLiteral() ||
(type.getFlags() & (ts.TypeFlags.String | ts.TypeFlags.Number | ts.TypeFlags.Boolean | ts.TypeFlags.EnumLiteral | ts.TypeFlags.BigInt | ts.TypeFlags.ESSymbol)) !== 0
) {
discoveredVariant = DataTypeVariant.PRIMITIVE;
} else if (type.isClassOrInterface() || (type.getFlags() & ts.TypeFlags.Object) !== 0) {
// Check if it's literally just a type alias to something else or a complex object
if (type.getProperties().length > 0) {
discoveredVariant = DataTypeVariant.OBJECT;
} else {
discoveredVariant = DataTypeVariant.TYPE;
}
} else {
discoveredVariant = DataTypeVariant.TYPE;
}
}
ts.forEachChild(node, visit);
};
visit(sourceFile);
return discoveredVariant;
};