bun_plugins 1.2.4 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/{src/PluginManager.d.ts → PluginManager.d.ts} +9 -16
- package/dist/PluginManager.d.ts.map +1 -0
- package/dist/{src/PluginManager.js → PluginManager.js} +188 -187
- package/dist/PluginManager.js.map +1 -0
- package/dist/{src/index.d.ts → index.d.ts} +1 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/{src/index.js → index.js} +0 -2
- package/dist/index.js.map +1 -0
- package/dist/{src/managers → managers}/ContextFactory.d.ts +1 -1
- package/dist/managers/ContextFactory.d.ts.map +1 -0
- package/dist/{src/managers → managers}/ContextFactory.js +29 -52
- package/dist/managers/ContextFactory.js.map +1 -0
- package/dist/managers/DependencyManager.d.ts.map +1 -0
- package/dist/{src/managers → managers}/DependencyManager.js +5 -7
- package/dist/managers/DependencyManager.js.map +1 -0
- package/dist/{src/managers → managers}/HooksManager.d.ts +1 -4
- package/dist/managers/HooksManager.d.ts.map +1 -0
- package/dist/{src/managers → managers}/HooksManager.js +8 -36
- package/dist/managers/HooksManager.js.map +1 -0
- package/dist/managers/ResourceManager.d.ts.map +1 -0
- package/dist/{src/managers → managers}/ResourceManager.js +3 -3
- package/dist/managers/ResourceManager.js.map +1 -0
- package/dist/{src/storage → storage}/JsonPluginStorage.d.ts +1 -2
- package/dist/storage/JsonPluginStorage.d.ts.map +1 -0
- package/dist/storage/JsonPluginStorage.js +63 -0
- package/dist/storage/JsonPluginStorage.js.map +1 -0
- package/dist/{src/types.d.ts → types.d.ts} +19 -60
- package/dist/types.d.ts.map +1 -0
- package/dist/{src/types.js → types.js} +0 -7
- package/dist/types.js.map +1 -0
- package/dist/utils/errorParser.d.ts.map +1 -0
- package/dist/{src/utils → utils}/errorParser.js +5 -2
- package/dist/utils/errorParser.js.map +1 -0
- package/dist/utils/pluginValidator.d.ts +93 -0
- package/dist/utils/pluginValidator.d.ts.map +1 -0
- package/dist/{src/utils → utils}/pluginValidator.js +14 -12
- package/dist/utils/pluginValidator.js.map +1 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/worker/WorkerRunner.d.ts.map +1 -0
- package/dist/{src/worker → worker}/WorkerRunner.js +13 -33
- package/dist/worker/WorkerRunner.js.map +1 -0
- package/package.json +7 -18
- package/LICENSE +0 -9
- package/dist/plugins/ActionRegistryPlugin.d.ts +0 -23
- package/dist/plugins/ActionRegistryPlugin.d.ts.map +0 -1
- package/dist/plugins/ActionRegistryPlugin.js +0 -56
- package/dist/plugins/ActionRegistryPlugin.js.map +0 -1
- package/dist/plugins/DynamicJSActionsPlugin.d.ts +0 -21
- package/dist/plugins/DynamicJSActionsPlugin.d.ts.map +0 -1
- package/dist/plugins/DynamicJSActionsPlugin.js +0 -57
- package/dist/plugins/DynamicJSActionsPlugin.js.map +0 -1
- package/dist/plugins/DynamicMathActionsPlugin.d.ts +0 -22
- package/dist/plugins/DynamicMathActionsPlugin.d.ts.map +0 -1
- package/dist/plugins/DynamicMathActionsPlugin.js +0 -64
- package/dist/plugins/DynamicMathActionsPlugin.js.map +0 -1
- package/dist/plugins/DynamicTextActionsPlugin.d.ts +0 -22
- package/dist/plugins/DynamicTextActionsPlugin.d.ts.map +0 -1
- package/dist/plugins/DynamicTextActionsPlugin.js +0 -58
- package/dist/plugins/DynamicTextActionsPlugin.js.map +0 -1
- package/dist/plugins/DynamicUtilityActionsPlugin.d.ts +0 -22
- package/dist/plugins/DynamicUtilityActionsPlugin.d.ts.map +0 -1
- package/dist/plugins/DynamicUtilityActionsPlugin.js +0 -75
- package/dist/plugins/DynamicUtilityActionsPlugin.js.map +0 -1
- package/dist/plugins/LifecycleDemoPlugin.d.ts +0 -20
- package/dist/plugins/LifecycleDemoPlugin.d.ts.map +0 -1
- package/dist/plugins/LifecycleDemoPlugin.js +0 -34
- package/dist/plugins/LifecycleDemoPlugin.js.map +0 -1
- package/dist/plugins/MathPlugin.d.ts +0 -16
- package/dist/plugins/MathPlugin.d.ts.map +0 -1
- package/dist/plugins/MathPlugin.js +0 -25
- package/dist/plugins/MathPlugin.js.map +0 -1
- package/dist/plugins/MyJSPlugin.d.ts +0 -7
- package/dist/plugins/MyJSPlugin.d.ts.map +0 -1
- package/dist/plugins/MyJSPlugin.js +0 -12
- package/dist/plugins/MyJSPlugin.js.map +0 -1
- package/dist/plugins/arktype/index.d.ts +0 -8
- package/dist/plugins/arktype/index.d.ts.map +0 -1
- package/dist/plugins/arktype/index.js +0 -25
- package/dist/plugins/arktype/index.js.map +0 -1
- package/dist/src/Plugin.d.ts +0 -28
- package/dist/src/Plugin.d.ts.map +0 -1
- package/dist/src/Plugin.js +0 -36
- package/dist/src/Plugin.js.map +0 -1
- package/dist/src/PluginManager.d.ts.map +0 -1
- package/dist/src/PluginManager.js.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/logger/LoggerAdapter.d.ts +0 -77
- package/dist/src/logger/LoggerAdapter.d.ts.map +0 -1
- package/dist/src/logger/LoggerAdapter.js +0 -242
- package/dist/src/logger/LoggerAdapter.js.map +0 -1
- package/dist/src/logger/LoggerFactory.d.ts +0 -73
- package/dist/src/logger/LoggerFactory.d.ts.map +0 -1
- package/dist/src/logger/LoggerFactory.js +0 -99
- package/dist/src/logger/LoggerFactory.js.map +0 -1
- package/dist/src/logger/index.d.ts +0 -3
- package/dist/src/logger/index.d.ts.map +0 -1
- package/dist/src/logger/index.js +0 -3
- package/dist/src/logger/index.js.map +0 -1
- package/dist/src/managers/ContextFactory.d.ts.map +0 -1
- package/dist/src/managers/ContextFactory.js.map +0 -1
- package/dist/src/managers/DependencyManager.d.ts.map +0 -1
- package/dist/src/managers/DependencyManager.js.map +0 -1
- package/dist/src/managers/HooksManager.d.ts.map +0 -1
- package/dist/src/managers/HooksManager.js.map +0 -1
- package/dist/src/managers/ResourceManager.d.ts.map +0 -1
- package/dist/src/managers/ResourceManager.js.map +0 -1
- package/dist/src/storage/JsonPluginStorage.d.ts.map +0 -1
- package/dist/src/storage/JsonPluginStorage.js +0 -75
- package/dist/src/storage/JsonPluginStorage.js.map +0 -1
- package/dist/src/types/arktype_converter.d.ts +0 -19
- package/dist/src/types/arktype_converter.d.ts.map +0 -1
- package/dist/src/types/arktype_converter.js +0 -73
- package/dist/src/types/arktype_converter.js.map +0 -1
- package/dist/src/types/generator.d.ts +0 -9
- package/dist/src/types/generator.d.ts.map +0 -1
- package/dist/src/types/generator.js +0 -9
- package/dist/src/types/generator.js.map +0 -1
- package/dist/src/types/interfaces.d.ts +0 -55
- package/dist/src/types/interfaces.d.ts.map +0 -1
- package/dist/src/types/interfaces.js +0 -5
- package/dist/src/types/interfaces.js.map +0 -1
- package/dist/src/types/plugin-registry-base.d.ts +0 -78
- package/dist/src/types/plugin-registry-base.d.ts.map +0 -1
- package/dist/src/types/plugin-registry-base.js +0 -6
- package/dist/src/types/plugin-registry-base.js.map +0 -1
- package/dist/src/types/plugin-registry.d.ts +0 -2
- package/dist/src/types/plugin-registry.d.ts.map +0 -1
- package/dist/src/types/plugin-registry.js +0 -4
- package/dist/src/types/plugin-registry.js.map +0 -1
- package/dist/src/types/plugin_generator.d.ts +0 -62
- package/dist/src/types/plugin_generator.d.ts.map +0 -1
- package/dist/src/types/plugin_generator.js +0 -700
- package/dist/src/types/plugin_generator.js.map +0 -1
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/types.js.map +0 -1
- package/dist/src/utils/errorParser.d.ts.map +0 -1
- package/dist/src/utils/errorParser.js.map +0 -1
- package/dist/src/utils/pluginValidator.d.ts +0 -17
- package/dist/src/utils/pluginValidator.d.ts.map +0 -1
- package/dist/src/utils/pluginValidator.js.map +0 -1
- package/dist/src/utils/security.d.ts.map +0 -1
- package/dist/src/utils/security.js.map +0 -1
- package/dist/src/worker/WorkerRunner.d.ts.map +0 -1
- package/dist/src/worker/WorkerRunner.js.map +0 -1
- package/plugin-types/index.d.ts +0 -20
- package/plugin-types/plugin-registry.d.ts +0 -148
- /package/dist/{src/managers → managers}/DependencyManager.d.ts +0 -0
- /package/dist/{src/managers → managers}/ResourceManager.d.ts +0 -0
- /package/dist/{src/utils → utils}/errorParser.d.ts +0 -0
- /package/dist/{src/utils → utils}/security.d.ts +0 -0
- /package/dist/{src/utils → utils}/security.js +0 -0
- /package/dist/{src/worker → worker}/WorkerRunner.d.ts +0 -0
|
@@ -1,700 +0,0 @@
|
|
|
1
|
-
import { readdir, readFile, writeFile, mkdir } from "node:fs/promises";
|
|
2
|
-
import { join, extname } from "node:path";
|
|
3
|
-
import ts from "typescript";
|
|
4
|
-
import { ArkTypeConverter } from "./arktype_converter";
|
|
5
|
-
/**
|
|
6
|
-
* Main generator for handling conversion between classes and arktype schemas.
|
|
7
|
-
* Provides dynamic typing and autocomplete without static KnownPluginNames.
|
|
8
|
-
*/
|
|
9
|
-
export class PluginTypeGenerator {
|
|
10
|
-
pluginsDir;
|
|
11
|
-
outputDir;
|
|
12
|
-
packageName;
|
|
13
|
-
compilerOptions;
|
|
14
|
-
constructor(options) {
|
|
15
|
-
this.pluginsDir = options.pluginsDir;
|
|
16
|
-
this.outputDir = options.outputDir;
|
|
17
|
-
this.packageName = options.packageName || "bun_plugins";
|
|
18
|
-
this.compilerOptions = this.getCompilerOptions();
|
|
19
|
-
}
|
|
20
|
-
getCompilerOptions() {
|
|
21
|
-
const configPath = join(process.cwd(), "tsconfig.json");
|
|
22
|
-
try {
|
|
23
|
-
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
24
|
-
if (configFile.error) {
|
|
25
|
-
return this.getDefaultOptions();
|
|
26
|
-
}
|
|
27
|
-
const { options } = ts.parseJsonConfigFileContent(configFile.config, ts.sys, process.cwd());
|
|
28
|
-
return options;
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
return this.getDefaultOptions();
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
getDefaultOptions() {
|
|
35
|
-
return {
|
|
36
|
-
target: ts.ScriptTarget.ESNext,
|
|
37
|
-
module: ts.ModuleKind.ESNext,
|
|
38
|
-
strict: true,
|
|
39
|
-
esModuleInterop: true,
|
|
40
|
-
skipLibCheck: true,
|
|
41
|
-
noEmit: true
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
async scanPlugins() {
|
|
45
|
-
const pluginFiles = await this.scanDirectory(this.pluginsDir);
|
|
46
|
-
const plugins = [];
|
|
47
|
-
const seenClasses = new Set();
|
|
48
|
-
for (const filePath of pluginFiles) {
|
|
49
|
-
try {
|
|
50
|
-
const content = await readFile(filePath, "utf-8");
|
|
51
|
-
const pluginInfo = this.parsePlugin(filePath, content);
|
|
52
|
-
if (pluginInfo && pluginInfo.className && !seenClasses.has(pluginInfo.className)) {
|
|
53
|
-
seenClasses.add(pluginInfo.className);
|
|
54
|
-
plugins.push(pluginInfo);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
catch (err) {
|
|
58
|
-
console.warn(`Warning: Failed to parse ${filePath}: ${err}`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return plugins;
|
|
62
|
-
}
|
|
63
|
-
async scanDirectory(dir) {
|
|
64
|
-
const files = [];
|
|
65
|
-
try {
|
|
66
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
67
|
-
for (const entry of entries) {
|
|
68
|
-
const fullPath = join(dir, entry.name);
|
|
69
|
-
if (entry.isDirectory()) {
|
|
70
|
-
if (entry.name !== "node_modules" &&
|
|
71
|
-
entry.name !== "dist" &&
|
|
72
|
-
entry.name !== "build" &&
|
|
73
|
-
entry.name !== ".git" &&
|
|
74
|
-
!entry.name.startsWith(".")) {
|
|
75
|
-
files.push(...(await this.scanDirectory(fullPath)));
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
else if (entry.isFile()) {
|
|
79
|
-
const ext = extname(entry.name);
|
|
80
|
-
if (ext === ".ts" || ext === ".js") {
|
|
81
|
-
files.push(fullPath);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
console.warn(`Warning: Could not read directory ${dir}`);
|
|
88
|
-
}
|
|
89
|
-
return files;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Extracts the properties and methods from a TypeScript class.
|
|
93
|
-
*/
|
|
94
|
-
extractClassProperties(sourceFile) {
|
|
95
|
-
const properties = [];
|
|
96
|
-
const visit = (node) => {
|
|
97
|
-
if (ts.isClassDeclaration(node)) {
|
|
98
|
-
node.members.forEach(member => {
|
|
99
|
-
if (ts.isPropertyDeclaration(member) && member.name && ts.isIdentifier(member.name)) {
|
|
100
|
-
const propName = member.name.text;
|
|
101
|
-
const propInfo = this.extractPropertyType(member, sourceFile);
|
|
102
|
-
if (propInfo) {
|
|
103
|
-
properties.push(propInfo);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
if (ts.isMethodDeclaration(member) && member.name && ts.isIdentifier(member.name)) {
|
|
107
|
-
const methodInfo = this.extractMethodInfo(member, sourceFile);
|
|
108
|
-
if (methodInfo) {
|
|
109
|
-
properties.push(methodInfo);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (ts.isConstructorDeclaration(member)) {
|
|
113
|
-
member.parameters.forEach(param => {
|
|
114
|
-
if (ts.isIdentifier(param.name) && param.type) {
|
|
115
|
-
const propInfo = {
|
|
116
|
-
name: param.name.text,
|
|
117
|
-
type: param.type.getText(sourceFile),
|
|
118
|
-
isOptional: param.questionToken !== undefined,
|
|
119
|
-
isArray: this.isArrayType(param.type, sourceFile),
|
|
120
|
-
nestedType: this.extractNestedType(param.type, sourceFile)
|
|
121
|
-
};
|
|
122
|
-
properties.push(propInfo);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
ts.forEachChild(node, visit);
|
|
129
|
-
};
|
|
130
|
-
ts.forEachChild(sourceFile, visit);
|
|
131
|
-
return properties;
|
|
132
|
-
}
|
|
133
|
-
extractMethodInfo(node, sourceFile) {
|
|
134
|
-
const name = node.name.getText(sourceFile);
|
|
135
|
-
if (name.startsWith("_") || name.startsWith("#")) {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
// Filter out lifecycle methods and getApi (internal plugin methods)
|
|
139
|
-
const lifecycleMethods = ["onLoad", "onUnload", "onEnable", "onDisable", "onReload", "getApi"];
|
|
140
|
-
if (lifecycleMethods.includes(name)) {
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
const params = [];
|
|
144
|
-
node.parameters.forEach(param => {
|
|
145
|
-
if (ts.isIdentifier(param.name)) {
|
|
146
|
-
params.push({
|
|
147
|
-
name: param.name.text,
|
|
148
|
-
type: param.type ? param.type.getText(sourceFile) : "any",
|
|
149
|
-
isOptional: param.questionToken !== undefined
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
const returnType = node.type ? node.type.getText(sourceFile) : "void";
|
|
154
|
-
return {
|
|
155
|
-
name,
|
|
156
|
-
type: returnType,
|
|
157
|
-
isOptional: false,
|
|
158
|
-
isArray: false,
|
|
159
|
-
isMethod: true,
|
|
160
|
-
params
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
extractPropertyType(node, sourceFile) {
|
|
164
|
-
if (!node.name || !ts.isIdentifier(node.name)) {
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
const name = node.name.text;
|
|
168
|
-
if (name.startsWith("_") || name.startsWith("#")) {
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
let type = "any";
|
|
172
|
-
let isOptional = node.questionToken !== undefined || node.initializer !== undefined;
|
|
173
|
-
let isArray = false;
|
|
174
|
-
let nestedType;
|
|
175
|
-
if (node.type) {
|
|
176
|
-
type = node.type.getText(sourceFile);
|
|
177
|
-
isArray = this.isArrayType(node.type, sourceFile);
|
|
178
|
-
nestedType = this.extractNestedType(node.type, sourceFile);
|
|
179
|
-
}
|
|
180
|
-
else if (node.initializer) {
|
|
181
|
-
type = this.inferTypeFromInitializer(node.initializer, sourceFile);
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
name,
|
|
185
|
-
type: this.mapTypeName(type),
|
|
186
|
-
isOptional,
|
|
187
|
-
isArray,
|
|
188
|
-
nestedType
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
isArrayType(typeNode, sourceFile) {
|
|
192
|
-
if (ts.isArrayTypeNode(typeNode)) {
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
if (ts.isUnionTypeNode(typeNode)) {
|
|
196
|
-
return typeNode.types.some(t => this.isArrayType(t, sourceFile));
|
|
197
|
-
}
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
extractNestedType(typeNode, sourceFile) {
|
|
201
|
-
if (ts.isTypeReferenceNode(typeNode)) {
|
|
202
|
-
const typeName = typeNode.typeName.getText(sourceFile);
|
|
203
|
-
const nestedProperties = this.findTypeProperties(typeName, sourceFile);
|
|
204
|
-
if (nestedProperties.length > 0) {
|
|
205
|
-
return {
|
|
206
|
-
schemaName: typeName,
|
|
207
|
-
schemaDefinition: "",
|
|
208
|
-
typeDefinition: "",
|
|
209
|
-
properties: nestedProperties
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
if (ts.isTypeLiteralNode(typeNode)) {
|
|
214
|
-
const properties = [];
|
|
215
|
-
typeNode.members.forEach(member => {
|
|
216
|
-
if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {
|
|
217
|
-
const propInfo = {
|
|
218
|
-
name: member.name.text,
|
|
219
|
-
type: member.type ? member.type.getText(sourceFile) : "any",
|
|
220
|
-
isOptional: member.questionToken !== undefined,
|
|
221
|
-
isArray: member.type ? this.isArrayType(member.type, sourceFile) : false
|
|
222
|
-
};
|
|
223
|
-
properties.push(propInfo);
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
return {
|
|
227
|
-
schemaName: "InlineType",
|
|
228
|
-
schemaDefinition: "",
|
|
229
|
-
typeDefinition: "",
|
|
230
|
-
properties
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
return undefined;
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Generate a type string for public methods of a plugin class.
|
|
237
|
-
*/
|
|
238
|
-
generatePublicMethodsType(p) {
|
|
239
|
-
if (p.arkTypeSchema && p.arkTypeSchema.properties.length > 0) {
|
|
240
|
-
const props = p.arkTypeSchema.properties
|
|
241
|
-
.filter(prop => !prop.name.startsWith("_") && !prop.name.startsWith("#"))
|
|
242
|
-
.map(prop => {
|
|
243
|
-
if (prop.isMethod) {
|
|
244
|
-
const params = prop.params?.map(param => `${param.name}: ${param.type}`).join(", ") || "";
|
|
245
|
-
return ` ${prop.name}(${params}): ${prop.type};`;
|
|
246
|
-
}
|
|
247
|
-
return ` ${prop.name}${prop.isOptional ? "?" : ""}: ${prop.type};`;
|
|
248
|
-
})
|
|
249
|
-
.join("\n");
|
|
250
|
-
return `{\n${props}\n }`;
|
|
251
|
-
}
|
|
252
|
-
return p.className;
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Generate an inline type definition for a plugin's API.
|
|
256
|
-
* If the plugin has an API interface defined, it extracts the interface definition.
|
|
257
|
-
* Otherwise, it generates the type from public methods.
|
|
258
|
-
*/
|
|
259
|
-
generateInlineApiType(p, fallbackType) {
|
|
260
|
-
// If the plugin has an API interface, try to extract its definition
|
|
261
|
-
if (p.apiInterface && p.arkTypeSchema) {
|
|
262
|
-
const props = p.arkTypeSchema.properties
|
|
263
|
-
.filter(prop => !prop.name.startsWith("_") && !prop.name.startsWith("#"))
|
|
264
|
-
.map(prop => {
|
|
265
|
-
if (prop.isMethod) {
|
|
266
|
-
const params = prop.params?.map(param => `${param.name}: ${param.type}`).join(", ") || "";
|
|
267
|
-
return ` ${prop.name}(${params}): ${prop.type};`;
|
|
268
|
-
}
|
|
269
|
-
return ` ${prop.name}${prop.isOptional ? "?" : ""}: ${prop.type};`;
|
|
270
|
-
})
|
|
271
|
-
.join("\n");
|
|
272
|
-
if (props) {
|
|
273
|
-
return `{\n${props}\n }`;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
// Fallback: use the provided type (either interface name or public methods)
|
|
277
|
-
return fallbackType;
|
|
278
|
-
}
|
|
279
|
-
findTypeProperties(typeName, sourceFile) {
|
|
280
|
-
const properties = [];
|
|
281
|
-
const visit = (node) => {
|
|
282
|
-
if (ts.isInterfaceDeclaration(node) && node.name.text === typeName) {
|
|
283
|
-
node.members.forEach(member => {
|
|
284
|
-
if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {
|
|
285
|
-
const propInfo = {
|
|
286
|
-
name: member.name.text,
|
|
287
|
-
type: member.type ? this.mapTypeName(member.type.getText(sourceFile)) : "any",
|
|
288
|
-
isOptional: member.questionToken !== undefined,
|
|
289
|
-
isArray: member.type ? this.isArrayType(member.type, sourceFile) : false
|
|
290
|
-
};
|
|
291
|
-
properties.push(propInfo);
|
|
292
|
-
}
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
if (ts.isTypeAliasDeclaration(node) && node.name.text === typeName) {
|
|
296
|
-
if (ts.isTypeLiteralNode(node.type)) {
|
|
297
|
-
node.type.members.forEach(member => {
|
|
298
|
-
if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {
|
|
299
|
-
const propInfo = {
|
|
300
|
-
name: member.name.text,
|
|
301
|
-
type: member.type ? this.mapTypeName(member.type.getText(sourceFile)) : "any",
|
|
302
|
-
isOptional: member.questionToken !== undefined,
|
|
303
|
-
isArray: member.type ? this.isArrayType(member.type, sourceFile) : false
|
|
304
|
-
};
|
|
305
|
-
properties.push(propInfo);
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
ts.forEachChild(node, visit);
|
|
311
|
-
};
|
|
312
|
-
ts.forEachChild(sourceFile, visit);
|
|
313
|
-
return properties;
|
|
314
|
-
}
|
|
315
|
-
mapTypeName(type) {
|
|
316
|
-
const typeMap = {
|
|
317
|
-
"string": "string",
|
|
318
|
-
"String": "string",
|
|
319
|
-
"number": "number",
|
|
320
|
-
"Number": "number",
|
|
321
|
-
"boolean": "boolean",
|
|
322
|
-
"Boolean": "boolean",
|
|
323
|
-
"any": "any",
|
|
324
|
-
"unknown": "unknown",
|
|
325
|
-
"void": "void",
|
|
326
|
-
"null": "null",
|
|
327
|
-
"Date": "Date",
|
|
328
|
-
"Promise": "Promise",
|
|
329
|
-
"Array": "Array",
|
|
330
|
-
"Record": "Record"
|
|
331
|
-
};
|
|
332
|
-
const baseType = type.split("<")[0]?.split("|")[0]?.trim() || type;
|
|
333
|
-
return typeMap[baseType] || baseType;
|
|
334
|
-
}
|
|
335
|
-
inferTypeFromInitializer(initializer, sourceFile) {
|
|
336
|
-
if (ts.isStringLiteral(initializer)) {
|
|
337
|
-
return "string";
|
|
338
|
-
}
|
|
339
|
-
if (ts.isNumericLiteral(initializer)) {
|
|
340
|
-
return "number";
|
|
341
|
-
}
|
|
342
|
-
if (ts.isIdentifier(initializer)) {
|
|
343
|
-
const symbol = this.getSymbolAtLocation(initializer, sourceFile);
|
|
344
|
-
if (symbol) {
|
|
345
|
-
return symbol;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
return "any";
|
|
349
|
-
}
|
|
350
|
-
getSymbolAtLocation(node, sourceFile) {
|
|
351
|
-
const typeChecker = this.getTypeChecker();
|
|
352
|
-
const symbol = typeChecker.getSymbolAtLocation(node);
|
|
353
|
-
if (symbol && symbol.declarations && symbol.declarations.length > 0) {
|
|
354
|
-
const decl = symbol.declarations[0];
|
|
355
|
-
if (decl && (ts.isTypeAliasDeclaration(decl) || ts.isInterfaceDeclaration(decl))) {
|
|
356
|
-
return decl.name.text;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
return undefined;
|
|
360
|
-
}
|
|
361
|
-
getTypeChecker() {
|
|
362
|
-
const program = ts.createProgram([join(process.cwd(), "src/types/plugin_generator.ts")], this.compilerOptions);
|
|
363
|
-
return program.getTypeChecker();
|
|
364
|
-
}
|
|
365
|
-
parseTypeScriptPlugin(filePath, source) {
|
|
366
|
-
const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);
|
|
367
|
-
let pluginName = "";
|
|
368
|
-
let pluginVersion = "1.0.0";
|
|
369
|
-
let className = "";
|
|
370
|
-
let apiInterface;
|
|
371
|
-
let dependencies;
|
|
372
|
-
let arkTypeSchema;
|
|
373
|
-
// Store interface definitions for later lookup
|
|
374
|
-
const interfaceDefinitions = new Map();
|
|
375
|
-
const self = this;
|
|
376
|
-
function visit(node) {
|
|
377
|
-
// Extract interface definitions
|
|
378
|
-
if (ts.isInterfaceDeclaration(node)) {
|
|
379
|
-
const interfaceName = node.name.text;
|
|
380
|
-
const properties = [];
|
|
381
|
-
node.members.forEach(member => {
|
|
382
|
-
if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {
|
|
383
|
-
const propName = member.name.text;
|
|
384
|
-
if (!propName.startsWith("_") && !propName.startsWith("#")) {
|
|
385
|
-
const propInfo = {
|
|
386
|
-
name: propName,
|
|
387
|
-
type: member.type ? member.type.getText(sourceFile) : "any",
|
|
388
|
-
isOptional: member.questionToken !== undefined,
|
|
389
|
-
isArray: member.type ? self.isArrayType(member.type, sourceFile) : false
|
|
390
|
-
};
|
|
391
|
-
properties.push(propInfo);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
else if (ts.isMethodSignature(member) && member.name && ts.isIdentifier(member.name)) {
|
|
395
|
-
const methodName = member.name.getText(sourceFile);
|
|
396
|
-
if (!methodName.startsWith("_") && !methodName.startsWith("#")) {
|
|
397
|
-
const params = [];
|
|
398
|
-
member.parameters.forEach(param => {
|
|
399
|
-
if (ts.isIdentifier(param.name)) {
|
|
400
|
-
params.push({
|
|
401
|
-
name: param.name.text,
|
|
402
|
-
type: param.type ? param.type.getText(sourceFile) : "any",
|
|
403
|
-
isOptional: param.questionToken !== undefined
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
const returnType = member.type ? member.type.getText(sourceFile) : "void";
|
|
408
|
-
properties.push({
|
|
409
|
-
name: methodName,
|
|
410
|
-
type: returnType,
|
|
411
|
-
isOptional: false,
|
|
412
|
-
isArray: false,
|
|
413
|
-
isMethod: true,
|
|
414
|
-
params
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
if (properties.length > 0) {
|
|
420
|
-
interfaceDefinitions.set(interfaceName, properties);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
if (ts.isClassDeclaration(node)) {
|
|
424
|
-
if (node.name) {
|
|
425
|
-
className = node.name.text;
|
|
426
|
-
const converter = new PluginTypeGenerator({
|
|
427
|
-
pluginsDir: "",
|
|
428
|
-
outputDir: ""
|
|
429
|
-
});
|
|
430
|
-
const properties = converter.extractClassProperties(sourceFile);
|
|
431
|
-
if (properties.length > 0) {
|
|
432
|
-
const schemaName = className + "Schema";
|
|
433
|
-
arkTypeSchema = {
|
|
434
|
-
schemaName,
|
|
435
|
-
schemaDefinition: ArkTypeConverter.classToArkType(className, properties),
|
|
436
|
-
typeDefinition: "",
|
|
437
|
-
properties
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
if (ts.isPropertyDeclaration(node)) {
|
|
443
|
-
const name = node.name.getText(sourceFile);
|
|
444
|
-
if (name === "name" && node.initializer) {
|
|
445
|
-
pluginName = node.initializer.getText(sourceFile).replace(/['"]/g, "");
|
|
446
|
-
}
|
|
447
|
-
if (name === "version" && node.initializer) {
|
|
448
|
-
pluginVersion = node.initializer.getText(sourceFile).replace(/['"]/g, "");
|
|
449
|
-
}
|
|
450
|
-
if (name === "dependencies" && node.initializer) {
|
|
451
|
-
try {
|
|
452
|
-
const depsText = node.initializer.getText(sourceFile);
|
|
453
|
-
dependencies = eval(`(${depsText})`);
|
|
454
|
-
}
|
|
455
|
-
catch {
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
if (ts.isMethodDeclaration(node)) {
|
|
460
|
-
const name = node.name.getText(sourceFile);
|
|
461
|
-
if (name === "getApi" && node.type) {
|
|
462
|
-
const returnType = node.type.getText(sourceFile);
|
|
463
|
-
const match = returnType.match(/:\s*(\w+Api)/);
|
|
464
|
-
if (match) {
|
|
465
|
-
apiInterface = match[1];
|
|
466
|
-
// If we found an API interface, use its properties for the schema
|
|
467
|
-
if (apiInterface) {
|
|
468
|
-
const apiProperties = interfaceDefinitions.get(apiInterface);
|
|
469
|
-
if (apiProperties) {
|
|
470
|
-
arkTypeSchema = {
|
|
471
|
-
schemaName: apiInterface + "Schema",
|
|
472
|
-
schemaDefinition: ArkTypeConverter.classToArkType(apiInterface, apiProperties),
|
|
473
|
-
typeDefinition: "",
|
|
474
|
-
properties: apiProperties
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
ts.forEachChild(node, visit);
|
|
482
|
-
}
|
|
483
|
-
ts.forEachChild(sourceFile, visit);
|
|
484
|
-
const fileName = filePath.split(/[/\\]/).pop()?.replace(/\.(ts|js)$/, "") || "";
|
|
485
|
-
const name = pluginName || fileName.toLowerCase().replace(/plugin$/i, "");
|
|
486
|
-
if (!name)
|
|
487
|
-
return null;
|
|
488
|
-
return {
|
|
489
|
-
name,
|
|
490
|
-
version: pluginVersion,
|
|
491
|
-
className,
|
|
492
|
-
filePath,
|
|
493
|
-
isTypeScript: true,
|
|
494
|
-
apiInterface,
|
|
495
|
-
dependencies,
|
|
496
|
-
arkTypeSchema
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
parseJavaScriptPlugin(filePath, source) {
|
|
500
|
-
const fileName = filePath.split(/[/\\]/).pop()?.replace(/\.(ts|js)$/, "") || "";
|
|
501
|
-
const classMatch = source.match(/export\s+class\s+(\w+)/);
|
|
502
|
-
const className = classMatch?.[1] || fileName;
|
|
503
|
-
const nameMatch = source.match(/this\.name\s*=\s*["']([^"']+)["']/) ||
|
|
504
|
-
source.match(/name\s*=\s*["']([^"']+)["']/);
|
|
505
|
-
const name = nameMatch?.[1] || fileName.toLowerCase().replace(/plugin$/i, "");
|
|
506
|
-
const versionMatch = source.match(/version\s*=\s*["']([^"']+)["']/);
|
|
507
|
-
const version = versionMatch?.[1] || "1.0.0";
|
|
508
|
-
const hasSharedApi = /getApi\s*\(/.test(source);
|
|
509
|
-
if (!name)
|
|
510
|
-
return null;
|
|
511
|
-
return {
|
|
512
|
-
name,
|
|
513
|
-
version,
|
|
514
|
-
className,
|
|
515
|
-
filePath,
|
|
516
|
-
isTypeScript: false,
|
|
517
|
-
apiInterface: hasSharedApi ? `${className}Api` : undefined
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
parsePlugin(filePath, content) {
|
|
521
|
-
const ext = extname(filePath);
|
|
522
|
-
if (ext === ".ts") {
|
|
523
|
-
return this.parseTypeScriptPlugin(filePath, content);
|
|
524
|
-
}
|
|
525
|
-
else if (ext === ".js") {
|
|
526
|
-
return this.parseJavaScriptPlugin(filePath, content);
|
|
527
|
-
}
|
|
528
|
-
return null;
|
|
529
|
-
}
|
|
530
|
-
/**
|
|
531
|
-
* Generates dynamic type declarations using a factory pattern.
|
|
532
|
-
* No static KnownPluginNames - types are computed at compile time.
|
|
533
|
-
*
|
|
534
|
-
* The API type includes:
|
|
535
|
-
* - Base plugin properties (name, version)
|
|
536
|
-
* - Public methods from the class
|
|
537
|
-
* - Shared API methods if getApi is defined
|
|
538
|
-
*/
|
|
539
|
-
generateDeclarations(plugins, baseApiInterface = "BasePluginApi") {
|
|
540
|
-
// Note: We don't import plugin classes here because they are not distributed with the package
|
|
541
|
-
// The class names are used only for type information
|
|
542
|
-
// Dynamic plugin factory map - each plugin is indexed by name
|
|
543
|
-
const pluginFactoryEntries = plugins.map(p => {
|
|
544
|
-
// Generate public methods type from the class
|
|
545
|
-
const publicMethodsType = this.generatePublicMethodsType(p);
|
|
546
|
-
// Use the shared API interface if available, otherwise use the public methods
|
|
547
|
-
const apiType = p.apiInterface ? p.apiInterface : publicMethodsType;
|
|
548
|
-
// Generate inline type definition for the API
|
|
549
|
-
// This ensures that the API type is fully defined without external dependencies
|
|
550
|
-
const inlineApiType = this.generateInlineApiType(p, apiType);
|
|
551
|
-
// Fix relative imports for distributed types
|
|
552
|
-
const sanitizedApiType = inlineApiType
|
|
553
|
-
.replace(/PluginContext/g, 'any')
|
|
554
|
-
.replace(/EngineActionHandler/g, 'any')
|
|
555
|
-
.replace(/ActionRegistry/g, 'any')
|
|
556
|
-
.replace(/import\("\.\.\/\.\.\/src"\)\./g, 'import("bun_plugins/src").')
|
|
557
|
-
.replace(/import\("\.\.\/src"\)\./g, 'import("bun_plugins/src").');
|
|
558
|
-
return ` "${p.name}": {
|
|
559
|
-
name: "${p.name}";
|
|
560
|
-
version: "${p.version}";
|
|
561
|
-
class: ${p.className};
|
|
562
|
-
api: ${sanitizedApiType};
|
|
563
|
-
dependencies?: ${p.dependencies ? `Record<${JSON.stringify(Object.keys(p.dependencies))}, string>` : "undefined"};
|
|
564
|
-
}`;
|
|
565
|
-
}).join(",\n");
|
|
566
|
-
return `import type { PluginFactory as BasePluginFactory, BasePluginApi } from "${this.packageName}/src/types/plugin-registry-base";
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* Extend the PluginFactory interface with discovered plugins.
|
|
570
|
-
* Users can also extend this interface with their own plugins using declaration merging.
|
|
571
|
-
*
|
|
572
|
-
* Example:
|
|
573
|
-
* \`\`\`typescript
|
|
574
|
-
* declare module "bun_plugins" {
|
|
575
|
-
* export interface PluginFactory {
|
|
576
|
-
* "my-plugin": {
|
|
577
|
-
* name: "my-plugin";
|
|
578
|
-
* version: "1.0.0";
|
|
579
|
-
* class: MyPlugin;
|
|
580
|
-
* api: MyPluginApi;
|
|
581
|
-
* };
|
|
582
|
-
* }
|
|
583
|
-
* }
|
|
584
|
-
* \`\`\`
|
|
585
|
-
*/
|
|
586
|
-
export interface PluginFactory extends BasePluginFactory {
|
|
587
|
-
${pluginFactoryEntries}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
/**
|
|
591
|
-
* Re-export base types for convenience.
|
|
592
|
-
* These types support dynamic plugin discovery and user extension.
|
|
593
|
-
*/
|
|
594
|
-
export type {
|
|
595
|
-
PluginClassType,
|
|
596
|
-
GetPluginApi,
|
|
597
|
-
GetPluginClass,
|
|
598
|
-
IsValidPlugin,
|
|
599
|
-
PluginFromFactory,
|
|
600
|
-
PluginInstanceType
|
|
601
|
-
} from "${this.packageName}/src/types/plugin-registry-base";
|
|
602
|
-
|
|
603
|
-
// Re-export BasePluginApi (already imported at the top)
|
|
604
|
-
export type { BasePluginApi };
|
|
605
|
-
|
|
606
|
-
// Define PluginNames directly from the extended PluginFactory
|
|
607
|
-
// For development, we allow any string to be used as plugin name
|
|
608
|
-
export type PluginNames = keyof PluginFactory | string;
|
|
609
|
-
|
|
610
|
-
// Define PluginApiType directly from the extended PluginFactory
|
|
611
|
-
export type PluginApiType<T extends string> =
|
|
612
|
-
T extends keyof PluginFactory
|
|
613
|
-
? PluginFactory[T]["api"]
|
|
614
|
-
: BasePluginApi;
|
|
615
|
-
`;
|
|
616
|
-
}
|
|
617
|
-
generateModuleExports(plugins, baseApiInterface = "BasePluginApi") {
|
|
618
|
-
// Note: We don't export plugin classes here because they are not distributed with the package
|
|
619
|
-
return `
|
|
620
|
-
|
|
621
|
-
export type {
|
|
622
|
-
PluginNames,
|
|
623
|
-
PluginApiType,
|
|
624
|
-
PluginClassType,
|
|
625
|
-
GetPluginApi,
|
|
626
|
-
GetPluginClass,
|
|
627
|
-
IsValidPlugin,
|
|
628
|
-
PluginFromFactory,
|
|
629
|
-
PluginFactory
|
|
630
|
-
} from "${this.packageName}/plugin-types/plugin-registry";
|
|
631
|
-
|
|
632
|
-
export interface ${baseApiInterface} {
|
|
633
|
-
name: string;
|
|
634
|
-
version: string;
|
|
635
|
-
actions?: string[];
|
|
636
|
-
type?: string;
|
|
637
|
-
loaded?: string;
|
|
638
|
-
}
|
|
639
|
-
`;
|
|
640
|
-
}
|
|
641
|
-
async generate() {
|
|
642
|
-
await mkdir(this.outputDir, { recursive: true });
|
|
643
|
-
const plugins = await this.scanPlugins();
|
|
644
|
-
const baseApiInterface = "BasePluginApi";
|
|
645
|
-
const declarations = this.generateDeclarations(plugins, baseApiInterface);
|
|
646
|
-
const moduleExports = this.generateModuleExports(plugins);
|
|
647
|
-
const dtsPath = join(this.outputDir, "plugin-registry.d.ts");
|
|
648
|
-
const indexPath = join(this.outputDir, "index.d.ts");
|
|
649
|
-
await writeFile(dtsPath, declarations, "utf-8");
|
|
650
|
-
await writeFile(indexPath, moduleExports, "utf-8");
|
|
651
|
-
console.log(`Generated ${dtsPath} with ${plugins.length} plugins`);
|
|
652
|
-
console.log(`Generated ${indexPath}`);
|
|
653
|
-
return plugins;
|
|
654
|
-
}
|
|
655
|
-
async getPlugins() {
|
|
656
|
-
return this.scanPlugins();
|
|
657
|
-
}
|
|
658
|
-
static async convertClassToArkType(classFilePath) {
|
|
659
|
-
try {
|
|
660
|
-
const content = await readFile(classFilePath, "utf-8");
|
|
661
|
-
const sourceFile = ts.createSourceFile(classFilePath, content, ts.ScriptTarget.Latest, true);
|
|
662
|
-
let className = "";
|
|
663
|
-
let properties = [];
|
|
664
|
-
const visit = (node) => {
|
|
665
|
-
if (ts.isClassDeclaration(node) && node.name) {
|
|
666
|
-
className = node.name.text;
|
|
667
|
-
const tempGenerator = new PluginTypeGenerator({
|
|
668
|
-
pluginsDir: "",
|
|
669
|
-
outputDir: ""
|
|
670
|
-
});
|
|
671
|
-
properties = tempGenerator.extractClassProperties(sourceFile);
|
|
672
|
-
}
|
|
673
|
-
ts.forEachChild(node, visit);
|
|
674
|
-
};
|
|
675
|
-
ts.forEachChild(sourceFile, visit);
|
|
676
|
-
if (!className || properties.length === 0) {
|
|
677
|
-
return null;
|
|
678
|
-
}
|
|
679
|
-
const schemaName = className + "Schema";
|
|
680
|
-
return {
|
|
681
|
-
schemaName,
|
|
682
|
-
schemaDefinition: ArkTypeConverter.classToArkType(className, properties),
|
|
683
|
-
typeDefinition: "",
|
|
684
|
-
properties
|
|
685
|
-
};
|
|
686
|
-
}
|
|
687
|
-
catch (error) {
|
|
688
|
-
console.error(`Error converting class to ArkType: ${error}`);
|
|
689
|
-
return null;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
/**
|
|
694
|
-
* Generates plugin types from a plugins directory.
|
|
695
|
-
*/
|
|
696
|
-
export async function generatePluginTypes(pluginsDir = join(process.cwd(), "plugins"), outputDir = join(process.cwd(), "plugin-types"), packageName = "bun_plugins") {
|
|
697
|
-
const generator = new PluginTypeGenerator({ pluginsDir, outputDir, packageName });
|
|
698
|
-
return generator.generate();
|
|
699
|
-
}
|
|
700
|
-
//# sourceMappingURL=plugin_generator.js.map
|