-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathextract-types.cjs
More file actions
141 lines (119 loc) · 4.35 KB
/
Copy pathextract-types.cjs
File metadata and controls
141 lines (119 loc) · 4.35 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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
const ts = require("typescript");
const fs = require("fs");
const path = require("path");
function extractTypesFromModule(filePath) {
const program = ts.createProgram([filePath], {});
const checker = program.getTypeChecker();
const sourceFile = program.getSourceFile(filePath);
const seenTypes = new Set();
const typeInfo = [];
function visit(node) {
if (ts.isModuleDeclaration(node) && node.name.text === "vue-data-ui") {
ts.forEachChild(node.body, visit);
}
if (ts.isInterfaceDeclaration(node)) {
const interfaceName = node.name.text;
const members = extractInterfaceMembers(node);
typeInfo.push({
kind: "interface",
name: interfaceName,
members: members,
});
} else if (ts.isTypeAliasDeclaration(node)) {
const typeName = node.name.text;
const type = checker.getTypeAtLocation(node);
const typeString = checker.typeToString(type);
typeInfo.push({
kind: "type",
name: typeName,
type: typeString,
details: extractTypeDetails(type),
});
} else if (ts.isEnumDeclaration(node)) {
const enumName = node.name.text;
const members = node.members.map((member) => member.name.getText());
typeInfo.push({
kind: "enum",
name: enumName,
members: members,
});
}
}
function extractInterfaceMembers(node) {
const members = [];
node.members.forEach((member) => {
const memberName = member.name.getText();
const memberType = checker.getTypeAtLocation(member);
const memberTypeString = checker.typeToString(memberType);
const details = extractTypeDetails(memberType);
members.push({
name: memberName,
type: memberTypeString,
optional: member.questionToken ? true : false,
isReadonly:
member.modifiers?.some(
(mod) => mod.kind === ts.SyntaxKind.ReadonlyKeyword,
) || false,
details: details,
});
});
return members;
}
function extractTypeDetails(type) {
const typeId = checker.typeToString(type);
if (seenTypes.has(typeId)) {
return { name: typeId, circular: true };
}
seenTypes.add(typeId);
if (type.flags & ts.TypeFlags.Union) {
return {
kind: "union",
types: type.types.map((t) => checker.typeToString(t)),
};
} else if (type.flags & ts.TypeFlags.Intersection) {
return {
kind: "intersection",
types: type.types.map((t) => checker.typeToString(t)),
};
} else if (type.flags & ts.TypeFlags.Object) {
return extractObjectTypeDetails(type);
}
return { name: checker.typeToString(type) };
}
function extractObjectTypeDetails(type) {
const properties = type.getProperties();
const details = [];
properties.forEach((prop) => {
const propType = checker.getTypeOfSymbolAtLocation(
prop,
prop.valueDeclaration,
);
const propTypeString = checker.typeToString(propType);
const optional = prop.flags & ts.SymbolFlags.Optional;
details.push({
name: prop.getName(),
type: propTypeString,
optional: optional,
details: extractTypeDetails(propType),
});
});
return { kind: "object", properties: details };
}
ts.forEachChild(sourceFile, visit);
return typeInfo;
}
const filePath = path.resolve(
__dirname,
"node_modules/vue-data-ui/dist/types/vue-data-ui.d.ts",
);
if (!fs.existsSync(filePath)) {
console.error("File does not exist:", filePath);
process.exit(1);
}
const types = extractTypesFromModule(filePath);
if (types.length === 0) {
console.warn("No types found in the .d.ts file");
} else {
fs.writeFileSync("types.json", JSON.stringify(types, null, 2));
console.log("Type information extracted and written to types.json");
}