bun_plugins 1.1.2 → 1.2.1

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.
Files changed (150) hide show
  1. package/README.md +2 -2
  2. package/dist/plugins/ActionRegistryPlugin.d.ts +23 -0
  3. package/dist/plugins/ActionRegistryPlugin.d.ts.map +1 -0
  4. package/dist/plugins/ActionRegistryPlugin.js +56 -0
  5. package/dist/plugins/ActionRegistryPlugin.js.map +1 -0
  6. package/dist/plugins/DynamicJSActionsPlugin.d.ts +21 -0
  7. package/dist/plugins/DynamicJSActionsPlugin.d.ts.map +1 -0
  8. package/dist/plugins/DynamicJSActionsPlugin.js +57 -0
  9. package/dist/plugins/DynamicJSActionsPlugin.js.map +1 -0
  10. package/dist/plugins/DynamicMathActionsPlugin.d.ts +22 -0
  11. package/dist/plugins/DynamicMathActionsPlugin.d.ts.map +1 -0
  12. package/dist/plugins/DynamicMathActionsPlugin.js +64 -0
  13. package/dist/plugins/DynamicMathActionsPlugin.js.map +1 -0
  14. package/dist/plugins/DynamicTextActionsPlugin.d.ts +22 -0
  15. package/dist/plugins/DynamicTextActionsPlugin.d.ts.map +1 -0
  16. package/dist/plugins/DynamicTextActionsPlugin.js +58 -0
  17. package/dist/plugins/DynamicTextActionsPlugin.js.map +1 -0
  18. package/dist/plugins/DynamicUtilityActionsPlugin.d.ts +22 -0
  19. package/dist/plugins/DynamicUtilityActionsPlugin.d.ts.map +1 -0
  20. package/dist/plugins/DynamicUtilityActionsPlugin.js +75 -0
  21. package/dist/plugins/DynamicUtilityActionsPlugin.js.map +1 -0
  22. package/dist/plugins/ExamplePlugin.d.ts +3 -0
  23. package/dist/plugins/ExamplePlugin.d.ts.map +1 -0
  24. package/dist/plugins/ExamplePlugin.js +41 -0
  25. package/dist/plugins/ExamplePlugin.js.map +1 -0
  26. package/dist/plugins/LifecycleDemoPlugin.d.ts +20 -0
  27. package/dist/plugins/LifecycleDemoPlugin.d.ts.map +1 -0
  28. package/dist/plugins/LifecycleDemoPlugin.js +34 -0
  29. package/dist/plugins/LifecycleDemoPlugin.js.map +1 -0
  30. package/dist/plugins/MathPlugin.d.ts +16 -0
  31. package/dist/plugins/MathPlugin.d.ts.map +1 -0
  32. package/dist/plugins/MathPlugin.js +25 -0
  33. package/dist/plugins/MathPlugin.js.map +1 -0
  34. package/dist/plugins/MyJSPlugin.d.ts +7 -0
  35. package/dist/plugins/MyJSPlugin.d.ts.map +1 -0
  36. package/dist/plugins/MyJSPlugin.js +12 -0
  37. package/dist/plugins/MyJSPlugin.js.map +1 -0
  38. package/dist/plugins/arktype/index.d.ts +8 -0
  39. package/dist/plugins/arktype/index.d.ts.map +1 -0
  40. package/dist/plugins/arktype/index.js +25 -0
  41. package/dist/plugins/arktype/index.js.map +1 -0
  42. package/dist/src/Plugin.d.ts +28 -0
  43. package/dist/src/Plugin.d.ts.map +1 -0
  44. package/dist/src/Plugin.js +36 -0
  45. package/dist/src/Plugin.js.map +1 -0
  46. package/dist/{PluginManager.d.ts → src/PluginManager.d.ts} +5 -0
  47. package/dist/src/PluginManager.d.ts.map +1 -0
  48. package/dist/{PluginManager.js → src/PluginManager.js} +104 -43
  49. package/dist/src/PluginManager.js.map +1 -0
  50. package/dist/{index.d.ts → src/index.d.ts} +2 -0
  51. package/dist/src/index.d.ts.map +1 -0
  52. package/dist/{index.js → src/index.js} +2 -0
  53. package/dist/src/index.js.map +1 -0
  54. package/dist/src/logger/LoggerAdapter.d.ts +77 -0
  55. package/dist/src/logger/LoggerAdapter.d.ts.map +1 -0
  56. package/dist/src/logger/LoggerAdapter.js +242 -0
  57. package/dist/src/logger/LoggerAdapter.js.map +1 -0
  58. package/dist/src/logger/LoggerFactory.d.ts +73 -0
  59. package/dist/src/logger/LoggerFactory.d.ts.map +1 -0
  60. package/dist/src/logger/LoggerFactory.js +99 -0
  61. package/dist/src/logger/LoggerFactory.js.map +1 -0
  62. package/dist/src/logger/index.d.ts +3 -0
  63. package/dist/src/logger/index.d.ts.map +1 -0
  64. package/dist/src/logger/index.js +3 -0
  65. package/dist/src/logger/index.js.map +1 -0
  66. package/dist/src/managers/ContextFactory.d.ts.map +1 -0
  67. package/dist/{managers → src/managers}/ContextFactory.js +51 -27
  68. package/dist/src/managers/ContextFactory.js.map +1 -0
  69. package/dist/src/managers/DependencyManager.d.ts.map +1 -0
  70. package/dist/{managers → src/managers}/DependencyManager.js +2 -1
  71. package/dist/src/managers/DependencyManager.js.map +1 -0
  72. package/dist/{managers → src/managers}/HooksManager.d.ts +4 -1
  73. package/dist/src/managers/HooksManager.d.ts.map +1 -0
  74. package/dist/{managers → src/managers}/HooksManager.js +36 -8
  75. package/dist/src/managers/HooksManager.js.map +1 -0
  76. package/dist/src/managers/ResourceManager.d.ts.map +1 -0
  77. package/dist/{managers → src/managers}/ResourceManager.js +2 -1
  78. package/dist/src/managers/ResourceManager.js.map +1 -0
  79. package/dist/src/storage/JsonPluginStorage.d.ts.map +1 -0
  80. package/dist/{storage → src/storage}/JsonPluginStorage.js +3 -2
  81. package/dist/src/storage/JsonPluginStorage.js.map +1 -0
  82. package/dist/src/types/arktype_converter.d.ts +19 -0
  83. package/dist/src/types/arktype_converter.d.ts.map +1 -0
  84. package/dist/src/types/arktype_converter.js +73 -0
  85. package/dist/src/types/arktype_converter.js.map +1 -0
  86. package/dist/src/types/generator.d.ts +8 -0
  87. package/dist/src/types/generator.d.ts.map +1 -0
  88. package/dist/src/types/generator.js +9 -0
  89. package/dist/src/types/generator.js.map +1 -0
  90. package/dist/src/types/interfaces.d.ts +55 -0
  91. package/dist/src/types/interfaces.d.ts.map +1 -0
  92. package/dist/src/types/interfaces.js +5 -0
  93. package/dist/src/types/interfaces.js.map +1 -0
  94. package/dist/src/types/plugin-registry.d.ts +21 -0
  95. package/dist/src/types/plugin-registry.d.ts.map +1 -0
  96. package/dist/src/types/plugin-registry.js +4 -0
  97. package/dist/src/types/plugin-registry.js.map +1 -0
  98. package/dist/src/types/plugin_generator.d.ts +56 -0
  99. package/dist/src/types/plugin_generator.d.ts.map +1 -0
  100. package/dist/src/types/plugin_generator.js +659 -0
  101. package/dist/src/types/plugin_generator.js.map +1 -0
  102. package/dist/{types.d.ts → src/types.d.ts} +29 -10
  103. package/dist/src/types.d.ts.map +1 -0
  104. package/dist/{types.js → src/types.js} +4 -1
  105. package/dist/src/types.js.map +1 -0
  106. package/dist/src/utils/errorParser.d.ts.map +1 -0
  107. package/dist/src/utils/errorParser.js.map +1 -0
  108. package/dist/src/utils/pluginValidator.d.ts.map +1 -0
  109. package/dist/{utils → src/utils}/pluginValidator.js +1 -1
  110. package/dist/src/utils/pluginValidator.js.map +1 -0
  111. package/dist/src/utils/security.d.ts.map +1 -0
  112. package/dist/src/utils/security.js.map +1 -0
  113. package/dist/src/worker/WorkerRunner.d.ts.map +1 -0
  114. package/dist/{worker → src/worker}/WorkerRunner.js +21 -9
  115. package/dist/src/worker/WorkerRunner.js.map +1 -0
  116. package/package.json +6 -4
  117. package/dist/PluginManager.d.ts.map +0 -1
  118. package/dist/PluginManager.js.map +0 -1
  119. package/dist/index.d.ts.map +0 -1
  120. package/dist/index.js.map +0 -1
  121. package/dist/managers/ContextFactory.d.ts.map +0 -1
  122. package/dist/managers/ContextFactory.js.map +0 -1
  123. package/dist/managers/DependencyManager.d.ts.map +0 -1
  124. package/dist/managers/DependencyManager.js.map +0 -1
  125. package/dist/managers/HooksManager.d.ts.map +0 -1
  126. package/dist/managers/HooksManager.js.map +0 -1
  127. package/dist/managers/ResourceManager.d.ts.map +0 -1
  128. package/dist/managers/ResourceManager.js.map +0 -1
  129. package/dist/storage/JsonPluginStorage.d.ts.map +0 -1
  130. package/dist/storage/JsonPluginStorage.js.map +0 -1
  131. package/dist/types.d.ts.map +0 -1
  132. package/dist/types.js.map +0 -1
  133. package/dist/utils/errorParser.d.ts.map +0 -1
  134. package/dist/utils/errorParser.js.map +0 -1
  135. package/dist/utils/pluginValidator.d.ts.map +0 -1
  136. package/dist/utils/pluginValidator.js.map +0 -1
  137. package/dist/utils/security.d.ts.map +0 -1
  138. package/dist/utils/security.js.map +0 -1
  139. package/dist/worker/WorkerRunner.d.ts.map +0 -1
  140. package/dist/worker/WorkerRunner.js.map +0 -1
  141. /package/dist/{managers → src/managers}/ContextFactory.d.ts +0 -0
  142. /package/dist/{managers → src/managers}/DependencyManager.d.ts +0 -0
  143. /package/dist/{managers → src/managers}/ResourceManager.d.ts +0 -0
  144. /package/dist/{storage → src/storage}/JsonPluginStorage.d.ts +0 -0
  145. /package/dist/{utils → src/utils}/errorParser.d.ts +0 -0
  146. /package/dist/{utils → src/utils}/errorParser.js +0 -0
  147. /package/dist/{utils → src/utils}/pluginValidator.d.ts +0 -0
  148. /package/dist/{utils → src/utils}/security.d.ts +0 -0
  149. /package/dist/{utils → src/utils}/security.js +0 -0
  150. /package/dist/{worker → src/worker}/WorkerRunner.d.ts +0 -0
@@ -0,0 +1,659 @@
1
+ import { readdir, readFile, writeFile, mkdir } from "node:fs/promises";
2
+ import { join, relative, 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
+ const lifecycleMethods = ["onLoad", "onUnload", "onEnable", "onDisable", "onReload"];
139
+ if (lifecycleMethods.includes(name)) {
140
+ return null;
141
+ }
142
+ const params = [];
143
+ node.parameters.forEach(param => {
144
+ if (ts.isIdentifier(param.name)) {
145
+ params.push({
146
+ name: param.name.text,
147
+ type: param.type ? param.type.getText(sourceFile) : "any",
148
+ isOptional: param.questionToken !== undefined
149
+ });
150
+ }
151
+ });
152
+ const returnType = node.type ? node.type.getText(sourceFile) : "void";
153
+ return {
154
+ name,
155
+ type: returnType,
156
+ isOptional: false,
157
+ isArray: false,
158
+ isMethod: true,
159
+ params
160
+ };
161
+ }
162
+ extractPropertyType(node, sourceFile) {
163
+ if (!node.name || !ts.isIdentifier(node.name)) {
164
+ return null;
165
+ }
166
+ const name = node.name.text;
167
+ if (name.startsWith("_") || name.startsWith("#")) {
168
+ return null;
169
+ }
170
+ let type = "any";
171
+ let isOptional = node.questionToken !== undefined || node.initializer !== undefined;
172
+ let isArray = false;
173
+ let nestedType;
174
+ if (node.type) {
175
+ type = node.type.getText(sourceFile);
176
+ isArray = this.isArrayType(node.type, sourceFile);
177
+ nestedType = this.extractNestedType(node.type, sourceFile);
178
+ }
179
+ else if (node.initializer) {
180
+ type = this.inferTypeFromInitializer(node.initializer, sourceFile);
181
+ }
182
+ return {
183
+ name,
184
+ type: this.mapTypeName(type),
185
+ isOptional,
186
+ isArray,
187
+ nestedType
188
+ };
189
+ }
190
+ isArrayType(typeNode, sourceFile) {
191
+ if (ts.isArrayTypeNode(typeNode)) {
192
+ return true;
193
+ }
194
+ if (ts.isUnionTypeNode(typeNode)) {
195
+ return typeNode.types.some(t => this.isArrayType(t, sourceFile));
196
+ }
197
+ return false;
198
+ }
199
+ extractNestedType(typeNode, sourceFile) {
200
+ if (ts.isTypeReferenceNode(typeNode)) {
201
+ const typeName = typeNode.typeName.getText(sourceFile);
202
+ const nestedProperties = this.findTypeProperties(typeName, sourceFile);
203
+ if (nestedProperties.length > 0) {
204
+ return {
205
+ schemaName: typeName,
206
+ schemaDefinition: "",
207
+ typeDefinition: "",
208
+ properties: nestedProperties
209
+ };
210
+ }
211
+ }
212
+ if (ts.isTypeLiteralNode(typeNode)) {
213
+ const properties = [];
214
+ typeNode.members.forEach(member => {
215
+ if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {
216
+ const propInfo = {
217
+ name: member.name.text,
218
+ type: member.type ? member.type.getText(sourceFile) : "any",
219
+ isOptional: member.questionToken !== undefined,
220
+ isArray: member.type ? this.isArrayType(member.type, sourceFile) : false
221
+ };
222
+ properties.push(propInfo);
223
+ }
224
+ });
225
+ return {
226
+ schemaName: "InlineType",
227
+ schemaDefinition: "",
228
+ typeDefinition: "",
229
+ properties
230
+ };
231
+ }
232
+ return undefined;
233
+ }
234
+ /**
235
+ * Generate a type string for public methods of a plugin class.
236
+ */
237
+ generatePublicMethodsType(p) {
238
+ if (p.arkTypeSchema && p.arkTypeSchema.properties.length > 0) {
239
+ const props = p.arkTypeSchema.properties
240
+ .filter(prop => !prop.name.startsWith("_") && !prop.name.startsWith("#"))
241
+ .map(prop => {
242
+ if (prop.isMethod) {
243
+ const params = prop.params?.map(param => `${param.name}: ${param.type}`).join(", ") || "";
244
+ return ` ${prop.name}(${params}): ${prop.type};`;
245
+ }
246
+ return ` ${prop.name}${prop.isOptional ? "?" : ""}: ${prop.type};`;
247
+ })
248
+ .join("\n");
249
+ return `{\n${props}\n }`;
250
+ }
251
+ return p.className;
252
+ }
253
+ findTypeProperties(typeName, sourceFile) {
254
+ const properties = [];
255
+ const visit = (node) => {
256
+ if (ts.isInterfaceDeclaration(node) && node.name.text === typeName) {
257
+ node.members.forEach(member => {
258
+ if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {
259
+ const propInfo = {
260
+ name: member.name.text,
261
+ type: member.type ? this.mapTypeName(member.type.getText(sourceFile)) : "any",
262
+ isOptional: member.questionToken !== undefined,
263
+ isArray: member.type ? this.isArrayType(member.type, sourceFile) : false
264
+ };
265
+ properties.push(propInfo);
266
+ }
267
+ });
268
+ }
269
+ if (ts.isTypeAliasDeclaration(node) && node.name.text === typeName) {
270
+ if (ts.isTypeLiteralNode(node.type)) {
271
+ node.type.members.forEach(member => {
272
+ if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {
273
+ const propInfo = {
274
+ name: member.name.text,
275
+ type: member.type ? this.mapTypeName(member.type.getText(sourceFile)) : "any",
276
+ isOptional: member.questionToken !== undefined,
277
+ isArray: member.type ? this.isArrayType(member.type, sourceFile) : false
278
+ };
279
+ properties.push(propInfo);
280
+ }
281
+ });
282
+ }
283
+ }
284
+ ts.forEachChild(node, visit);
285
+ };
286
+ ts.forEachChild(sourceFile, visit);
287
+ return properties;
288
+ }
289
+ mapTypeName(type) {
290
+ const typeMap = {
291
+ "string": "string",
292
+ "String": "string",
293
+ "number": "number",
294
+ "Number": "number",
295
+ "boolean": "boolean",
296
+ "Boolean": "boolean",
297
+ "any": "any",
298
+ "unknown": "unknown",
299
+ "void": "void",
300
+ "null": "null",
301
+ "Date": "Date",
302
+ "Promise": "Promise",
303
+ "Array": "Array",
304
+ "Record": "Record"
305
+ };
306
+ const baseType = type.split("<")[0]?.split("|")[0]?.trim() || type;
307
+ return typeMap[baseType] || baseType;
308
+ }
309
+ inferTypeFromInitializer(initializer, sourceFile) {
310
+ if (ts.isStringLiteral(initializer)) {
311
+ return "string";
312
+ }
313
+ if (ts.isNumericLiteral(initializer)) {
314
+ return "number";
315
+ }
316
+ if (ts.isIdentifier(initializer)) {
317
+ const symbol = this.getSymbolAtLocation(initializer, sourceFile);
318
+ if (symbol) {
319
+ return symbol;
320
+ }
321
+ }
322
+ return "any";
323
+ }
324
+ getSymbolAtLocation(node, sourceFile) {
325
+ const typeChecker = this.getTypeChecker();
326
+ const symbol = typeChecker.getSymbolAtLocation(node);
327
+ if (symbol && symbol.declarations && symbol.declarations.length > 0) {
328
+ const decl = symbol.declarations[0];
329
+ if (decl && (ts.isTypeAliasDeclaration(decl) || ts.isInterfaceDeclaration(decl))) {
330
+ return decl.name.text;
331
+ }
332
+ }
333
+ return undefined;
334
+ }
335
+ getTypeChecker() {
336
+ const program = ts.createProgram([join(process.cwd(), "src/types/plugin_generator.ts")], this.compilerOptions);
337
+ return program.getTypeChecker();
338
+ }
339
+ parseTypeScriptPlugin(filePath, source) {
340
+ const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);
341
+ let pluginName = "";
342
+ let pluginVersion = "1.0.0";
343
+ let className = "";
344
+ let apiInterface;
345
+ let dependencies;
346
+ let arkTypeSchema;
347
+ function visit(node) {
348
+ if (ts.isClassDeclaration(node)) {
349
+ if (node.name) {
350
+ className = node.name.text;
351
+ const converter = new PluginTypeGenerator({
352
+ pluginsDir: "",
353
+ outputDir: ""
354
+ });
355
+ const properties = converter.extractClassProperties(sourceFile);
356
+ if (properties.length > 0) {
357
+ const schemaName = className + "Schema";
358
+ arkTypeSchema = {
359
+ schemaName,
360
+ schemaDefinition: ArkTypeConverter.classToArkType(className, properties),
361
+ typeDefinition: "",
362
+ properties
363
+ };
364
+ }
365
+ }
366
+ }
367
+ if (ts.isPropertyDeclaration(node)) {
368
+ const name = node.name.getText(sourceFile);
369
+ if (name === "name" && node.initializer) {
370
+ pluginName = node.initializer.getText(sourceFile).replace(/['"]/g, "");
371
+ }
372
+ if (name === "version" && node.initializer) {
373
+ pluginVersion = node.initializer.getText(sourceFile).replace(/['"]/g, "");
374
+ }
375
+ if (name === "dependencies" && node.initializer) {
376
+ try {
377
+ const depsText = node.initializer.getText(sourceFile);
378
+ dependencies = eval(`(${depsText})`);
379
+ }
380
+ catch {
381
+ }
382
+ }
383
+ }
384
+ if (ts.isMethodDeclaration(node)) {
385
+ const name = node.name.getText(sourceFile);
386
+ if (name === "getApi" && node.type) {
387
+ const returnType = node.type.getText(sourceFile);
388
+ const match = returnType.match(/:\s*(\w+Api)/);
389
+ if (match) {
390
+ apiInterface = match[1];
391
+ }
392
+ }
393
+ }
394
+ ts.forEachChild(node, visit);
395
+ }
396
+ ts.forEachChild(sourceFile, visit);
397
+ if (!className) {
398
+ const exportDefaultMatch = source.match(/export\s+default\s+definePlugin\s*\(/);
399
+ if (exportDefaultMatch) {
400
+ className = "DefaultPlugin";
401
+ }
402
+ }
403
+ const fileName = filePath.split(/[/\\]/).pop()?.replace(/\.(ts|js)$/, "") || "";
404
+ const name = pluginName || fileName.toLowerCase().replace(/plugin$/i, "");
405
+ if (!name)
406
+ return null;
407
+ return {
408
+ name,
409
+ version: pluginVersion,
410
+ className,
411
+ filePath,
412
+ isTypeScript: true,
413
+ apiInterface,
414
+ dependencies,
415
+ arkTypeSchema
416
+ };
417
+ }
418
+ parseJavaScriptPlugin(filePath, source) {
419
+ const fileName = filePath.split(/[/\\]/).pop()?.replace(/\.(ts|js)$/, "") || "";
420
+ const classMatch = source.match(/export\s+class\s+(\w+)/);
421
+ const className = classMatch?.[1] || fileName;
422
+ const nameMatch = source.match(/this\.name\s*=\s*["']([^"']+)["']/) ||
423
+ source.match(/name\s*=\s*["']([^"']+)["']/);
424
+ const name = nameMatch?.[1] || fileName.toLowerCase().replace(/plugin$/i, "");
425
+ const versionMatch = source.match(/version\s*=\s*["']([^"']+)["']/);
426
+ const version = versionMatch?.[1] || "1.0.0";
427
+ const hasSharedApi = /getApi\s*\(/.test(source);
428
+ if (!name)
429
+ return null;
430
+ return {
431
+ name,
432
+ version,
433
+ className,
434
+ filePath,
435
+ isTypeScript: false,
436
+ apiInterface: hasSharedApi ? `${className}Api` : undefined
437
+ };
438
+ }
439
+ parsePlugin(filePath, content) {
440
+ const ext = extname(filePath);
441
+ if (ext === ".ts") {
442
+ return this.parseTypeScriptPlugin(filePath, content);
443
+ }
444
+ else if (ext === ".js") {
445
+ return this.parseJavaScriptPlugin(filePath, content);
446
+ }
447
+ return null;
448
+ }
449
+ /**
450
+ * Generates dynamic type declarations using a factory pattern.
451
+ * No static KnownPluginNames - types are computed at compile time.
452
+ *
453
+ * The API type includes:
454
+ * - Base plugin properties (name, version)
455
+ * - Public methods from the class
456
+ * - Shared API methods if getApi is defined
457
+ */
458
+ generateDeclarations(plugins, baseApiInterface = "BasePluginApi") {
459
+ // Dynamic plugin factory map - each plugin is indexed by name
460
+ const pluginFactoryEntries = plugins.map(p => {
461
+ // Generate public methods type from the class
462
+ const publicMethodsType = this.generatePublicMethodsType(p);
463
+ // Use the shared API interface if available, otherwise use the public methods
464
+ const apiType = p.apiInterface ? p.apiInterface : publicMethodsType;
465
+ return ` "${p.name}": {
466
+ name: "${p.name}";
467
+ version: "${p.version}";
468
+ class: ${p.className};
469
+ api: ${apiType};
470
+ dependencies?: ${p.dependencies ? `Record<${JSON.stringify(Object.keys(p.dependencies))}, string>` : "undefined"};
471
+ }`;
472
+ }).join(",\n");
473
+ // Dynamic type lookup using the factory map
474
+ const typeLookups = plugins.map(p => {
475
+ const apiType = p.apiInterface || baseApiInterface;
476
+ return ` T extends "${p.name}" ? ${apiType} :`;
477
+ }).join("\n");
478
+ // Dynamic class lookups
479
+ const classLookups = plugins.map(p => {
480
+ return ` T extends "${p.name}" ? ${p.className} :`;
481
+ }).join("\n");
482
+ // Plugin names as tuple for autocomplete
483
+ const pluginNamesTuple = plugins.map(p => `"${p.name}"`).join(" | ");
484
+ return `import type { IPlugin } from "${this.packageName}/types";
485
+
486
+ // Plugin namespace for type-safe plugin access
487
+ export namespace bun_plugins {
488
+ export interface ${baseApiInterface} {
489
+ name: string;
490
+ version: string;
491
+ actions?: string[];
492
+ type?: string;
493
+ loaded?: string;
494
+ }
495
+
496
+ /**
497
+ * Dynamic plugin factory map - all plugins are indexed here.
498
+ * This replaces the static KnownPluginNames type.
499
+ */
500
+ export interface PluginFactory {
501
+ ${pluginFactoryEntries}
502
+ }
503
+
504
+ /**
505
+ * Registry that aggregates all plugin types for global availability.
506
+ * This enables autocomplete without explicit imports.
507
+ */
508
+ export interface PluginTypeRegistry {
509
+ /** All discovered plugin names */
510
+ PluginNames: PluginNames;
511
+ /** Get API type for a plugin */
512
+ GetPluginApi: GetPluginApi;
513
+ /** Get class type for a plugin */
514
+ GetPluginClass: GetPluginClass;
515
+ /** Type-safe plugin factory */
516
+ PluginFactory: PluginFactory;
517
+ /** Check if a plugin name is valid */
518
+ IsValidPlugin: IsValidPlugin;
519
+ }
520
+
521
+ /**
522
+ * Union type of all plugin names for autocomplete.
523
+ * Generated dynamically from discovered plugins.
524
+ */
525
+ export type PluginNames = ${pluginNamesTuple};
526
+
527
+ /**
528
+ * Type lookup using the factory map for autocomplete.
529
+ */
530
+ export type PluginApiType<T extends PluginNames> =
531
+ T extends keyof PluginFactory ? PluginFactory[T]["api"] : ${baseApiInterface};
532
+
533
+ /**
534
+ * Class type lookup using the factory map.
535
+ */
536
+ export type PluginClassType<T extends PluginNames> =
537
+ T extends keyof PluginFactory ? PluginFactory[T]["class"] : IPlugin;
538
+
539
+ /**
540
+ * Get the API type for a specific plugin.
541
+ */
542
+ export type GetPluginApi<T extends PluginNames> = PluginApiType<T>;
543
+
544
+ /**
545
+ * Get the class type for a specific plugin.
546
+ */
547
+ export type GetPluginClass<T extends PluginNames> = PluginClassType<T>;
548
+
549
+ /**
550
+ * Helper to check if a plugin name is valid.
551
+ */
552
+ export type IsValidPlugin<T extends string> = T extends PluginNames ? true : false;
553
+
554
+ /**
555
+ * Type-safe plugin retrieval from the factory.
556
+ */
557
+ export type PluginFromFactory<T extends PluginNames> = PluginFactory[T];
558
+ }
559
+
560
+ // Export types outside namespace for easier import
561
+ export type PluginNames = bun_plugins.PluginNames;
562
+ export type PluginApiType<T extends bun_plugins.PluginNames> = bun_plugins.PluginApiType<T>;
563
+ export type PluginClassType<T extends bun_plugins.PluginNames> = bun_plugins.PluginClassType<T>;
564
+ export type GetPluginApi<T extends bun_plugins.PluginNames> = bun_plugins.GetPluginApi<T>;
565
+ export type GetPluginClass<T extends bun_plugins.PluginNames> = bun_plugins.GetPluginClass<T>;
566
+ export type IsValidPlugin<T extends string> = bun_plugins.IsValidPlugin<T>;
567
+ export type PluginFromFactory<T extends bun_plugins.PluginNames> = bun_plugins.PluginFromFactory<T>;
568
+ export type PluginFactory = bun_plugins.PluginFactory;
569
+ `;
570
+ }
571
+ generateModuleExports(plugins, baseApiInterface = "BasePluginApi") {
572
+ const pluginExports = plugins.map(p => {
573
+ const relPath = relative(this.outputDir, p.filePath);
574
+ return `export { ${p.className} } from "./${relPath.replace(/\\/g, '/').replace(/\.(ts|js)$/, "")}";`;
575
+ }).join("\n");
576
+ return `import type { IPlugin } from "${this.packageName}/types";
577
+
578
+ export type {
579
+ PluginNames,
580
+ PluginApiType,
581
+ PluginClassType,
582
+ GetPluginApi,
583
+ GetPluginClass,
584
+ IsValidPlugin,
585
+ PluginFromFactory,
586
+ PluginFactory
587
+ } from "./plugin-registry";
588
+
589
+ export interface ${baseApiInterface} {
590
+ name: string;
591
+ version: string;
592
+ actions?: string[];
593
+ type?: string;
594
+ loaded?: string;
595
+ }
596
+
597
+ ${pluginExports}
598
+ `;
599
+ }
600
+ async generate() {
601
+ await mkdir(this.outputDir, { recursive: true });
602
+ const plugins = await this.scanPlugins();
603
+ const baseApiInterface = "BasePluginApi";
604
+ const declarations = this.generateDeclarations(plugins, baseApiInterface);
605
+ const moduleExports = this.generateModuleExports(plugins);
606
+ const dtsPath = join(this.outputDir, "plugin-registry.d.ts");
607
+ const indexPath = join(this.outputDir, "index.d.ts");
608
+ await writeFile(dtsPath, declarations, "utf-8");
609
+ await writeFile(indexPath, moduleExports, "utf-8");
610
+ console.log(`Generated ${dtsPath} with ${plugins.length} plugins`);
611
+ console.log(`Generated ${indexPath}`);
612
+ return plugins;
613
+ }
614
+ async getPlugins() {
615
+ return this.scanPlugins();
616
+ }
617
+ static async convertClassToArkType(classFilePath) {
618
+ try {
619
+ const content = await readFile(classFilePath, "utf-8");
620
+ const sourceFile = ts.createSourceFile(classFilePath, content, ts.ScriptTarget.Latest, true);
621
+ let className = "";
622
+ let properties = [];
623
+ const visit = (node) => {
624
+ if (ts.isClassDeclaration(node) && node.name) {
625
+ className = node.name.text;
626
+ const tempGenerator = new PluginTypeGenerator({
627
+ pluginsDir: "",
628
+ outputDir: ""
629
+ });
630
+ properties = tempGenerator.extractClassProperties(sourceFile);
631
+ }
632
+ ts.forEachChild(node, visit);
633
+ };
634
+ ts.forEachChild(sourceFile, visit);
635
+ if (!className || properties.length === 0) {
636
+ return null;
637
+ }
638
+ const schemaName = className + "Schema";
639
+ return {
640
+ schemaName,
641
+ schemaDefinition: ArkTypeConverter.classToArkType(className, properties),
642
+ typeDefinition: "",
643
+ properties
644
+ };
645
+ }
646
+ catch (error) {
647
+ console.error(`Error converting class to ArkType: ${error}`);
648
+ return null;
649
+ }
650
+ }
651
+ }
652
+ /**
653
+ * Generates plugin types from a plugins directory.
654
+ */
655
+ export async function generatePluginTypes(pluginsDir = join(process.cwd(), "plugins"), outputDir = join(process.cwd(), "plugin-types"), packageName = "bun_plugins") {
656
+ const generator = new PluginTypeGenerator({ pluginsDir, outputDir, packageName });
657
+ return generator.generate();
658
+ }
659
+ //# sourceMappingURL=plugin_generator.js.map