@secondlayer/cli 0.1.0

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/dist/index.js ADDED
@@ -0,0 +1,342 @@
1
+ // src/utils/config.ts
2
+ import { transformSync } from "esbuild";
3
+
4
+ // src/core/plugin-manager.ts
5
+ import { format } from "prettier";
6
+ import { promises as fs } from "fs";
7
+ import path from "path";
8
+ import { validateStacksAddress } from "@stacks/transactions";
9
+ var PluginManager = class {
10
+ constructor() {
11
+ this.plugins = [];
12
+ this.logger = this.createLogger();
13
+ this.utils = this.createUtils();
14
+ this.executionContext = {
15
+ phase: "config",
16
+ startTime: Date.now(),
17
+ results: /* @__PURE__ */ new Map()
18
+ };
19
+ }
20
+ /**
21
+ * Register a plugin
22
+ */
23
+ register(plugin) {
24
+ if (!plugin.name || !plugin.version) {
25
+ throw new Error("Plugin must have a name and version");
26
+ }
27
+ const existing = this.plugins.find((p) => p.name === plugin.name);
28
+ if (existing) {
29
+ throw new Error(
30
+ `Plugin "${plugin.name}" is already registered (version ${existing.version})`
31
+ );
32
+ }
33
+ this.plugins.push(plugin);
34
+ this.logger.debug(`Registered plugin: ${plugin.name}@${plugin.version}`);
35
+ }
36
+ /**
37
+ * Get all registered plugins
38
+ */
39
+ getPlugins() {
40
+ return [...this.plugins];
41
+ }
42
+ /**
43
+ * Transform user config through all plugins
44
+ */
45
+ async transformConfig(config) {
46
+ this.executionContext.phase = "config";
47
+ let transformedConfig = { ...config };
48
+ for (const plugin of this.plugins) {
49
+ if (plugin.transformConfig) {
50
+ this.executionContext.currentPlugin = plugin;
51
+ try {
52
+ const result = await plugin.transformConfig(transformedConfig);
53
+ transformedConfig = result;
54
+ this.recordHookResult(plugin.name, "transformConfig", {
55
+ success: true
56
+ });
57
+ } catch (error) {
58
+ const err = error;
59
+ this.recordHookResult(plugin.name, "transformConfig", {
60
+ success: false,
61
+ error: err
62
+ });
63
+ throw new Error(
64
+ `Plugin "${plugin.name}" failed during config transformation: ${err.message}`
65
+ );
66
+ }
67
+ }
68
+ }
69
+ const resolvedConfig = {
70
+ ...transformedConfig,
71
+ plugins: this.plugins
72
+ };
73
+ return resolvedConfig;
74
+ }
75
+ /**
76
+ * Transform contracts through all plugins
77
+ */
78
+ async transformContracts(contracts, _config) {
79
+ const processedContracts = [];
80
+ for (let contract of contracts) {
81
+ if (contract._clarinetSource && contract.abi) {
82
+ const address = typeof contract.address === "string" ? contract.address : "";
83
+ const [contractAddress, contractName] = address.split(".");
84
+ const processed = {
85
+ name: contract.name || contractName,
86
+ address: contractAddress,
87
+ contractName,
88
+ abi: contract.abi,
89
+ source: "local",
90
+ metadata: { source: "clarinet" }
91
+ };
92
+ processedContracts.push(processed);
93
+ continue;
94
+ }
95
+ for (const plugin of this.plugins) {
96
+ if (plugin.transformContract) {
97
+ this.executionContext.currentPlugin = plugin;
98
+ try {
99
+ contract = await plugin.transformContract(contract);
100
+ this.recordHookResult(plugin.name, "transformContract", {
101
+ success: true
102
+ });
103
+ } catch (error) {
104
+ const err = error;
105
+ this.recordHookResult(plugin.name, "transformContract", {
106
+ success: false,
107
+ error: err
108
+ });
109
+ this.logger.warn(
110
+ `Plugin "${plugin.name}" failed to transform contract: ${err.message}`
111
+ );
112
+ }
113
+ }
114
+ }
115
+ if (contract.abi) {
116
+ const processed = {
117
+ name: contract.name || "unknown",
118
+ address: typeof contract.address === "string" ? contract.address.split(".")[0] : "unknown",
119
+ contractName: contract.name || "unknown",
120
+ abi: contract.abi,
121
+ source: "api",
122
+ // Use "api" as default for plugin-processed contracts
123
+ metadata: contract.metadata
124
+ };
125
+ processedContracts.push(processed);
126
+ }
127
+ }
128
+ return processedContracts;
129
+ }
130
+ /**
131
+ * Execute lifecycle hooks
132
+ */
133
+ async executeHook(hookName, context) {
134
+ for (const plugin of this.plugins) {
135
+ const hook = plugin[hookName];
136
+ if (typeof hook === "function") {
137
+ this.executionContext.currentPlugin = plugin;
138
+ try {
139
+ await hook.call(plugin, context);
140
+ this.recordHookResult(plugin.name, hookName, {
141
+ success: true
142
+ });
143
+ } catch (error) {
144
+ const err = error;
145
+ this.recordHookResult(plugin.name, hookName, {
146
+ success: false,
147
+ error: err
148
+ });
149
+ this.logger.error(
150
+ `Plugin "${plugin.name}" failed during ${hookName}: ${err.message}`
151
+ );
152
+ }
153
+ }
154
+ }
155
+ }
156
+ /**
157
+ * Execute generation phase with full context
158
+ */
159
+ async executeGeneration(contracts, config) {
160
+ this.executionContext.phase = "generate";
161
+ const outputs = /* @__PURE__ */ new Map();
162
+ const context = {
163
+ config,
164
+ logger: this.logger,
165
+ utils: this.utils,
166
+ contracts,
167
+ outputs,
168
+ augment: (outputKey, contractName, content) => {
169
+ this.augmentOutput(outputs, outputKey, contractName, content);
170
+ },
171
+ addOutput: (key, output) => {
172
+ outputs.set(key, output);
173
+ }
174
+ };
175
+ await this.executeHook("beforeGenerate", context);
176
+ await this.executeHook("generate", context);
177
+ await this.executeHook("afterGenerate", context);
178
+ return outputs;
179
+ }
180
+ /**
181
+ * Transform outputs through plugins
182
+ */
183
+ async transformOutputs(outputs) {
184
+ this.executionContext.phase = "output";
185
+ const transformedOutputs = /* @__PURE__ */ new Map();
186
+ for (const [key, output] of outputs) {
187
+ let transformedContent = output.content;
188
+ for (const plugin of this.plugins) {
189
+ if (plugin.transformOutput) {
190
+ this.executionContext.currentPlugin = plugin;
191
+ try {
192
+ transformedContent = await plugin.transformOutput(
193
+ transformedContent,
194
+ output.type || "other"
195
+ );
196
+ this.recordHookResult(plugin.name, "transformOutput", {
197
+ success: true
198
+ });
199
+ } catch (error) {
200
+ const err = error;
201
+ this.recordHookResult(plugin.name, "transformOutput", {
202
+ success: false,
203
+ error: err
204
+ });
205
+ this.logger.warn(
206
+ `Plugin "${plugin.name}" failed to transform output: ${err.message}`
207
+ );
208
+ }
209
+ }
210
+ }
211
+ transformedOutputs.set(key, {
212
+ ...output,
213
+ content: transformedContent
214
+ });
215
+ }
216
+ return transformedOutputs;
217
+ }
218
+ /**
219
+ * Write outputs to disk
220
+ */
221
+ async writeOutputs(outputs) {
222
+ for (const [, output] of outputs) {
223
+ try {
224
+ const resolvedPath = path.resolve(process.cwd(), output.path);
225
+ await this.utils.ensureDir(path.dirname(resolvedPath));
226
+ await this.utils.writeFile(resolvedPath, output.content);
227
+ } catch (error) {
228
+ const err = error;
229
+ this.logger.error(`Failed to write ${output.path}: ${err.message}`);
230
+ throw err;
231
+ }
232
+ }
233
+ }
234
+ /**
235
+ * Get execution results for debugging
236
+ */
237
+ getExecutionResults() {
238
+ return new Map(this.executionContext.results);
239
+ }
240
+ /**
241
+ * Augment existing output with additional content
242
+ */
243
+ augmentOutput(outputs, outputKey, contractName, content) {
244
+ const existing = outputs.get(outputKey);
245
+ if (!existing) {
246
+ this.logger.warn(`Cannot augment non-existent output: ${outputKey}`);
247
+ return;
248
+ }
249
+ const augmentedContent = `${existing.content}
250
+
251
+ // Augmented by plugin for ${contractName}
252
+ ${JSON.stringify(content, null, 2)}`;
253
+ outputs.set(outputKey, {
254
+ ...existing,
255
+ content: augmentedContent
256
+ });
257
+ }
258
+ /**
259
+ * Record hook execution result
260
+ */
261
+ recordHookResult(pluginName, hookName, result) {
262
+ const key = `${pluginName}:${hookName}`;
263
+ const existing = this.executionContext.results.get(key) || [];
264
+ existing.push({ ...result, plugin: pluginName });
265
+ this.executionContext.results.set(key, existing);
266
+ }
267
+ /**
268
+ * Create logger instance
269
+ */
270
+ createLogger() {
271
+ return {
272
+ info: (message) => console.log(`\u2139\uFE0F ${message}`),
273
+ warn: (message) => console.warn(`\u26A0\uFE0F ${message}`),
274
+ error: (message) => console.error(`\u274C ${message}`),
275
+ debug: (message) => {
276
+ if (process.env.DEBUG) {
277
+ console.log(`\u{1F41B} ${message}`);
278
+ }
279
+ },
280
+ success: (message) => console.log(`\u2705 ${message}`)
281
+ };
282
+ }
283
+ /**
284
+ * Create utils instance
285
+ */
286
+ createUtils() {
287
+ return {
288
+ toCamelCase: (str) => {
289
+ return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
290
+ },
291
+ toKebabCase: (str) => {
292
+ return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
293
+ },
294
+ validateAddress: (address) => {
295
+ return validateStacksAddress(address.split(".")[0]);
296
+ },
297
+ parseContractId: (contractId) => {
298
+ const [address, contractName] = contractId.split(".");
299
+ return { address, contractName };
300
+ },
301
+ formatCode: async (code) => {
302
+ return format(code, {
303
+ parser: "typescript",
304
+ singleQuote: true,
305
+ semi: true,
306
+ printWidth: 100,
307
+ trailingComma: "es5"
308
+ });
309
+ },
310
+ resolvePath: (relativePath) => {
311
+ return path.resolve(process.cwd(), relativePath);
312
+ },
313
+ fileExists: async (filePath) => {
314
+ try {
315
+ await fs.access(filePath);
316
+ return true;
317
+ } catch {
318
+ return false;
319
+ }
320
+ },
321
+ readFile: async (filePath) => {
322
+ return fs.readFile(filePath, "utf-8");
323
+ },
324
+ writeFile: async (filePath, content) => {
325
+ await fs.writeFile(filePath, content, "utf-8");
326
+ },
327
+ ensureDir: async (dirPath) => {
328
+ await fs.mkdir(dirPath, { recursive: true });
329
+ }
330
+ };
331
+ }
332
+ };
333
+
334
+ // src/utils/config.ts
335
+ function defineConfig(configOrDefiner) {
336
+ return configOrDefiner;
337
+ }
338
+ export {
339
+ PluginManager,
340
+ defineConfig
341
+ };
342
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/config.ts","../src/core/plugin-manager.ts"],"sourcesContent":["import { promises as fs } from \"fs\";\nimport path from \"path\";\nimport { pathToFileURL } from \"url\";\nimport { createRequire } from \"module\";\nimport { transformSync } from \"esbuild\";\nimport type { StacksConfig, ConfigDefiner } from \"../types/config.js\";\nimport type { ResolvedConfig } from \"../types/plugin.js\";\nimport { PluginManager } from \"../core/plugin-manager.js\";\n\n/**\n * Config file utilities\n */\n\nconst CONFIG_FILE_NAMES = [\n \"stacks.config.ts\",\n \"stacks.config.js\",\n \"stacks.config.mjs\",\n];\n\nexport async function findConfigFile(cwd: string): Promise<string | null> {\n for (const fileName of CONFIG_FILE_NAMES) {\n const filePath = path.join(cwd, fileName);\n try {\n await fs.access(filePath);\n return filePath;\n } catch {\n // File doesn't exist, continue\n }\n }\n return null;\n}\n\nexport async function loadConfig(configPath?: string): Promise<ResolvedConfig> {\n const cwd = process.cwd();\n\n const resolvedPath = configPath\n ? path.resolve(cwd, configPath)\n : await findConfigFile(cwd);\n\n if (!resolvedPath) {\n throw new Error(\n \"No config file found. Create a stacks.config.ts file or specify a path with --config\"\n );\n }\n\n let config: any;\n\n if (resolvedPath.endsWith(\".ts\")) {\n const code = await fs.readFile(resolvedPath, \"utf-8\");\n\n // Transform TypeScript to JavaScript, replacing the @stacks/codegen import\n // For development/linked packages, we need to resolve to the actual package location\n // This will work both for published packages and local development\n let replacementPath: string;\n\n try {\n // Try to resolve @stacks/codegen as if it were a normal package\n const require = createRequire(import.meta.url);\n const packagePath = require.resolve(\"@stacks/codegen\");\n replacementPath = pathToFileURL(packagePath).href;\n } catch {\n // Fallback: resolve relative to current module (for development)\n const currentModuleDir = path.dirname(new URL(import.meta.url).pathname);\n const indexPath = path.resolve(currentModuleDir, \"../index.js\");\n replacementPath = pathToFileURL(indexPath).href;\n }\n\n const transformedCode = code.replace(\n /from\\s+[\"']@stacks\\/cli[\"']/g,\n `from '${replacementPath}'`\n );\n\n const result = transformSync(transformedCode, {\n format: \"esm\",\n target: \"node18\",\n loader: \"ts\",\n });\n\n const tempPath = resolvedPath.replace(/\\.ts$/, \".mjs\");\n await fs.writeFile(tempPath, result.code);\n\n try {\n const fileUrl = pathToFileURL(tempPath).href;\n const module = await import(fileUrl);\n config = module.default;\n } finally {\n await fs.unlink(tempPath).catch(() => {});\n }\n } else {\n const fileUrl = pathToFileURL(resolvedPath).href;\n const module = await import(fileUrl);\n config = module.default;\n }\n\n if (!config) {\n throw new Error(\"Config file must export a default configuration\");\n }\n\n if (typeof config === \"function\") {\n config = config({} as StacksConfig);\n }\n\n validateConfig(config);\n\n // Process plugins if they exist\n const pluginManager = new PluginManager();\n\n if (config.plugins && Array.isArray(config.plugins)) {\n for (const plugin of config.plugins) {\n pluginManager.register(plugin);\n }\n }\n\n // Transform config through plugins\n const resolvedConfig = await pluginManager.transformConfig(config);\n\n return resolvedConfig;\n}\n\nexport function validateConfig(\n config: unknown\n): asserts config is StacksConfig {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"Config must be an object\");\n }\n\n const c = config as any;\n\n // Contracts are optional now since plugins can provide them\n if (c.contracts && !Array.isArray(c.contracts)) {\n throw new Error(\"Config contracts must be an array\");\n }\n\n if (!c.out || typeof c.out !== \"string\") {\n throw new Error(\"Config out must be a string path\");\n }\n\n // Validate contracts if they exist\n if (c.contracts) {\n for (const contract of c.contracts) {\n if (!contract.address && !contract.source) {\n throw new Error(\"Each contract must have either an address or source\");\n }\n }\n }\n\n // Validate plugins if they exist\n if (c.plugins && !Array.isArray(c.plugins)) {\n throw new Error(\"Config plugins must be an array\");\n }\n}\n\nexport function defineConfig(config: StacksConfig): StacksConfig;\nexport function defineConfig(definer: ConfigDefiner): ConfigDefiner;\nexport function defineConfig(configOrDefiner: StacksConfig | ConfigDefiner) {\n return configOrDefiner;\n}\n","/**\n * Plugin Manager for @stacks/codegen\n * Handles plugin registration, lifecycle execution, and output management\n */\n\nimport { format } from \"prettier\";\nimport { promises as fs } from \"fs\";\nimport path from \"path\";\nimport { validateStacksAddress } from \"@stacks/transactions\";\nimport type {\n StacksCodegenPlugin,\n UserConfig,\n ResolvedConfig,\n GenerateContext,\n Logger,\n PluginUtils,\n GeneratedOutput,\n ProcessedContract,\n ContractConfig,\n HookResult,\n PluginExecutionContext,\n} from \"../types/plugin.js\";\n\n/**\n * Core plugin manager that orchestrates plugin execution\n */\nexport class PluginManager {\n private plugins: StacksCodegenPlugin[] = [];\n private logger: Logger;\n private utils: PluginUtils;\n private executionContext: PluginExecutionContext;\n\n constructor() {\n this.logger = this.createLogger();\n this.utils = this.createUtils();\n this.executionContext = {\n phase: \"config\",\n startTime: Date.now(),\n results: new Map(),\n };\n }\n\n /**\n * Register a plugin\n */\n register(plugin: StacksCodegenPlugin): void {\n // Validate plugin\n if (!plugin.name || !plugin.version) {\n throw new Error(\"Plugin must have a name and version\");\n }\n\n // Check for duplicate plugin names\n const existing = this.plugins.find((p) => p.name === plugin.name);\n if (existing) {\n throw new Error(\n `Plugin \"${plugin.name}\" is already registered (version ${existing.version})`\n );\n }\n\n this.plugins.push(plugin);\n this.logger.debug(`Registered plugin: ${plugin.name}@${plugin.version}`);\n }\n\n /**\n * Get all registered plugins\n */\n getPlugins(): StacksCodegenPlugin[] {\n return [...this.plugins];\n }\n\n /**\n * Transform user config through all plugins\n */\n async transformConfig(config: UserConfig): Promise<ResolvedConfig> {\n this.executionContext.phase = \"config\";\n let transformedConfig = { ...config };\n\n for (const plugin of this.plugins) {\n if (plugin.transformConfig) {\n this.executionContext.currentPlugin = plugin;\n try {\n const result = await plugin.transformConfig(transformedConfig);\n transformedConfig = result;\n this.recordHookResult(plugin.name, \"transformConfig\", {\n success: true,\n });\n } catch (error) {\n const err = error as Error;\n this.recordHookResult(plugin.name, \"transformConfig\", {\n success: false,\n error: err,\n });\n throw new Error(\n `Plugin \"${plugin.name}\" failed during config transformation: ${err.message}`\n );\n }\n }\n }\n\n // Add plugins array to resolved config\n const resolvedConfig: ResolvedConfig = {\n ...transformedConfig,\n plugins: this.plugins,\n };\n\n return resolvedConfig;\n }\n\n /**\n * Transform contracts through all plugins\n */\n async transformContracts(\n contracts: ContractConfig[],\n _config: ResolvedConfig\n ): Promise<ProcessedContract[]> {\n const processedContracts: ProcessedContract[] = [];\n\n for (let contract of contracts) {\n // Handle special case for Clarinet plugin contracts\n if ((contract as any)._clarinetSource && contract.abi) {\n // Convert Clarinet contracts directly to ProcessedContract format\n const address =\n typeof contract.address === \"string\" ? contract.address : \"\";\n const [contractAddress, contractName] = address.split(\".\");\n const processed: ProcessedContract = {\n name: contract.name || contractName,\n address: contractAddress,\n contractName: contractName,\n abi: contract.abi,\n source: \"local\" as const,\n metadata: { source: \"clarinet\" },\n };\n processedContracts.push(processed);\n continue;\n }\n\n // Transform through each plugin\n for (const plugin of this.plugins) {\n if (plugin.transformContract) {\n this.executionContext.currentPlugin = plugin;\n try {\n contract = await plugin.transformContract(contract);\n this.recordHookResult(plugin.name, \"transformContract\", {\n success: true,\n });\n } catch (error) {\n const err = error as Error;\n this.recordHookResult(plugin.name, \"transformContract\", {\n success: false,\n error: err,\n });\n this.logger.warn(\n `Plugin \"${plugin.name}\" failed to transform contract: ${err.message}`\n );\n }\n }\n }\n\n // Convert to ProcessedContract\n if (contract.abi) {\n const processed: ProcessedContract = {\n name: contract.name || \"unknown\",\n address:\n typeof contract.address === \"string\"\n ? contract.address.split(\".\")[0]\n : \"unknown\",\n contractName: contract.name || \"unknown\",\n abi: contract.abi,\n source: \"api\" as const, // Use \"api\" as default for plugin-processed contracts\n metadata: contract.metadata,\n };\n processedContracts.push(processed);\n }\n }\n\n return processedContracts;\n }\n\n /**\n * Execute lifecycle hooks\n */\n async executeHook(\n hookName: keyof StacksCodegenPlugin,\n context: any\n ): Promise<void> {\n for (const plugin of this.plugins) {\n const hook = plugin[hookName];\n if (typeof hook === \"function\") {\n this.executionContext.currentPlugin = plugin;\n try {\n await (hook as any).call(plugin, context);\n this.recordHookResult(plugin.name, hookName as string, {\n success: true,\n });\n } catch (error) {\n const err = error as Error;\n this.recordHookResult(plugin.name, hookName as string, {\n success: false,\n error: err,\n });\n this.logger.error(\n `Plugin \"${plugin.name}\" failed during ${hookName as string}: ${err.message}`\n );\n // Don't throw - allow other plugins to continue\n }\n }\n }\n }\n\n /**\n * Execute generation phase with full context\n */\n async executeGeneration(\n contracts: ProcessedContract[],\n config: ResolvedConfig\n ): Promise<Map<string, GeneratedOutput>> {\n this.executionContext.phase = \"generate\";\n const outputs = new Map<string, GeneratedOutput>();\n\n // Create generation context\n const context: GenerateContext = {\n config,\n logger: this.logger,\n utils: this.utils,\n contracts,\n outputs,\n augment: (outputKey: string, contractName: string, content: any) => {\n this.augmentOutput(outputs, outputKey, contractName, content);\n },\n addOutput: (key: string, output: GeneratedOutput) => {\n outputs.set(key, output);\n },\n };\n\n // Execute beforeGenerate hooks\n await this.executeHook(\"beforeGenerate\", context);\n\n // Execute generate hooks\n await this.executeHook(\"generate\", context);\n\n // Execute afterGenerate hooks\n await this.executeHook(\"afterGenerate\", context);\n\n return outputs;\n }\n\n /**\n * Transform outputs through plugins\n */\n async transformOutputs(\n outputs: Map<string, GeneratedOutput>\n ): Promise<Map<string, GeneratedOutput>> {\n this.executionContext.phase = \"output\";\n const transformedOutputs = new Map<string, GeneratedOutput>();\n\n for (const [key, output] of outputs) {\n let transformedContent = output.content;\n\n for (const plugin of this.plugins) {\n if (plugin.transformOutput) {\n this.executionContext.currentPlugin = plugin;\n try {\n transformedContent = await plugin.transformOutput(\n transformedContent,\n output.type || \"other\"\n );\n this.recordHookResult(plugin.name, \"transformOutput\", {\n success: true,\n });\n } catch (error) {\n const err = error as Error;\n this.recordHookResult(plugin.name, \"transformOutput\", {\n success: false,\n error: err,\n });\n this.logger.warn(\n `Plugin \"${plugin.name}\" failed to transform output: ${err.message}`\n );\n }\n }\n }\n\n transformedOutputs.set(key, {\n ...output,\n content: transformedContent,\n });\n }\n\n return transformedOutputs;\n }\n\n /**\n * Write outputs to disk\n */\n async writeOutputs(outputs: Map<string, GeneratedOutput>): Promise<void> {\n for (const [, output] of outputs) {\n try {\n const resolvedPath = path.resolve(process.cwd(), output.path);\n await this.utils.ensureDir(path.dirname(resolvedPath));\n await this.utils.writeFile(resolvedPath, output.content);\n // Don't log here - let the main command handle success messaging\n } catch (error) {\n const err = error as Error;\n this.logger.error(`Failed to write ${output.path}: ${err.message}`);\n throw err;\n }\n }\n }\n\n /**\n * Get execution results for debugging\n */\n getExecutionResults(): Map<string, HookResult[]> {\n return new Map(this.executionContext.results);\n }\n\n /**\n * Augment existing output with additional content\n */\n private augmentOutput(\n outputs: Map<string, GeneratedOutput>,\n outputKey: string,\n contractName: string,\n content: any\n ): void {\n const existing = outputs.get(outputKey);\n if (!existing) {\n this.logger.warn(`Cannot augment non-existent output: ${outputKey}`);\n return;\n }\n\n // Simple augmentation - append content\n // In a real implementation, this would be more sophisticated\n const augmentedContent = `${existing.content}\\n\\n// Augmented by plugin for ${contractName}\\n${JSON.stringify(content, null, 2)}`;\n\n outputs.set(outputKey, {\n ...existing,\n content: augmentedContent,\n });\n }\n\n /**\n * Record hook execution result\n */\n private recordHookResult(\n pluginName: string,\n hookName: string,\n result: Omit<HookResult, \"plugin\">\n ): void {\n const key = `${pluginName}:${hookName}`;\n const existing = this.executionContext.results.get(key) || [];\n existing.push({ ...result, plugin: pluginName });\n this.executionContext.results.set(key, existing);\n }\n\n /**\n * Create logger instance\n */\n private createLogger(): Logger {\n return {\n info: (message: string) => console.log(`ℹ️ ${message}`),\n warn: (message: string) => console.warn(`⚠️ ${message}`),\n error: (message: string) => console.error(`❌ ${message}`),\n debug: (message: string) => {\n if (process.env.DEBUG) {\n console.log(`🐛 ${message}`);\n }\n },\n success: (message: string) => console.log(`✅ ${message}`),\n };\n }\n\n /**\n * Create utils instance\n */\n private createUtils(): PluginUtils {\n return {\n toCamelCase: (str: string) => {\n return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\n },\n\n toKebabCase: (str: string) => {\n return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n },\n\n validateAddress: (address: string) => {\n return validateStacksAddress(address.split(\".\")[0]);\n },\n\n parseContractId: (contractId: string) => {\n const [address, contractName] = contractId.split(\".\");\n return { address, contractName };\n },\n\n formatCode: async (code: string) => {\n return format(code, {\n parser: \"typescript\",\n singleQuote: true,\n semi: true,\n printWidth: 100,\n trailingComma: \"es5\",\n });\n },\n\n resolvePath: (relativePath: string) => {\n return path.resolve(process.cwd(), relativePath);\n },\n\n fileExists: async (filePath: string) => {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n },\n\n readFile: async (filePath: string) => {\n return fs.readFile(filePath, \"utf-8\");\n },\n\n writeFile: async (filePath: string, content: string) => {\n await fs.writeFile(filePath, content, \"utf-8\");\n },\n\n ensureDir: async (dirPath: string) => {\n await fs.mkdir(dirPath, { recursive: true });\n },\n };\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Configuration types for @stacks/codegen
3
+ */
4
+ type NetworkName = "mainnet" | "testnet" | "devnet";
5
+ interface ContractSource {
6
+ /**
7
+ * Contract identifier (address.name) for deployed contracts
8
+ */
9
+ address?: string | Partial<Record<NetworkName, string>>;
10
+ /**
11
+ * Path to local Clarity file
12
+ */
13
+ source?: string;
14
+ /**
15
+ * Optional name to use in generated code
16
+ */
17
+ name?: string;
18
+ }
19
+ interface StacksConfig {
20
+ /**
21
+ * Contracts to generate interfaces for (optional - plugins can provide these)
22
+ */
23
+ contracts?: ContractSource[];
24
+ /**
25
+ * Output file path
26
+ */
27
+ out: string;
28
+ /**
29
+ * Plugins to use for generation
30
+ */
31
+ plugins?: any[];
32
+ /**
33
+ * Network to use for fetching contracts
34
+ */
35
+ network?: NetworkName;
36
+ /**
37
+ * API key for Stacks API (if required)
38
+ */
39
+ apiKey?: string;
40
+ /**
41
+ * Base URL for Stacks API (optional override)
42
+ */
43
+ apiUrl?: string;
44
+ }
45
+ interface ResolvedContract {
46
+ name: string;
47
+ address: string;
48
+ contractName: string;
49
+ abi: any;
50
+ source: "api" | "local";
51
+ }
52
+ type ConfigDefiner = (config: StacksConfig) => StacksConfig;
53
+
54
+ /**
55
+ * Plugin system types for @stacks/codegen
56
+ */
57
+
58
+ /**
59
+ * Core plugin interface that all plugins must implement
60
+ */
61
+ interface StacksCodegenPlugin {
62
+ /** Plugin name (should be unique) */
63
+ name: string;
64
+ /** Plugin version */
65
+ version: string;
66
+ /** Called after config is resolved but before generation starts */
67
+ configResolved?: (config: ResolvedConfig) => void | Promise<void>;
68
+ /** Called before generation starts */
69
+ beforeGenerate?: (context: GenerateContext) => void | Promise<void>;
70
+ /** Called during generation phase - plugins can add their own outputs */
71
+ generate?: (context: GenerateContext) => void | Promise<void>;
72
+ /** Called after all generation is complete */
73
+ afterGenerate?: (context: GenerateContext) => void | Promise<void>;
74
+ /** Transform user config before resolution */
75
+ transformConfig?: (config: UserConfig) => UserConfig | Promise<UserConfig>;
76
+ /** Transform individual contracts during processing */
77
+ transformContract?: (contract: ContractConfig) => ContractConfig | Promise<ContractConfig>;
78
+ /** Transform generated output before writing to disk */
79
+ transformOutput?: (output: string, type: OutputType) => string | Promise<string>;
80
+ }
81
+ /**
82
+ * User configuration (before plugin transformations)
83
+ */
84
+ type UserConfig = StacksConfig;
85
+ /**
86
+ * Resolved configuration (after plugin transformations)
87
+ */
88
+ interface ResolvedConfig extends StacksConfig {
89
+ /** Resolved plugins array */
90
+ plugins: StacksCodegenPlugin[];
91
+ }
92
+ /**
93
+ * Contract configuration that can be transformed by plugins
94
+ */
95
+ interface ContractConfig {
96
+ name?: string;
97
+ address?: string | Partial<Record<NetworkName, string>>;
98
+ source?: string;
99
+ abi?: any;
100
+ metadata?: Record<string, any>;
101
+ }
102
+ /**
103
+ * Processed contract with resolved ABI and metadata
104
+ */
105
+ interface ProcessedContract extends ResolvedContract {
106
+ /** Additional metadata added by plugins */
107
+ metadata?: Record<string, any>;
108
+ }
109
+ /**
110
+ * Generated output from plugins
111
+ */
112
+ interface GeneratedOutput {
113
+ /** File path where output should be written */
114
+ path: string;
115
+ /** Generated content */
116
+ content: string;
117
+ /** Output type for transformation hooks */
118
+ type?: OutputType;
119
+ /** Whether this output should overwrite existing files */
120
+ overwrite?: boolean;
121
+ }
122
+ /**
123
+ * Types of outputs that can be generated
124
+ */
125
+ type OutputType = "contracts" | "hooks" | "actions" | "types" | "utils" | "config" | "other";
126
+ /**
127
+ * Base context available to all plugin hooks
128
+ */
129
+ interface PluginContext {
130
+ /** Resolved configuration */
131
+ config: ResolvedConfig;
132
+ /** Logger for plugin output */
133
+ logger: Logger;
134
+ /** Utility functions for plugins */
135
+ utils: PluginUtils;
136
+ }
137
+ /**
138
+ * Context available during generation phase
139
+ */
140
+ interface GenerateContext extends PluginContext {
141
+ /** Processed contracts ready for generation */
142
+ contracts: ProcessedContract[];
143
+ /** Map of output keys to generated content */
144
+ outputs: Map<string, GeneratedOutput>;
145
+ /** Function to augment existing outputs */
146
+ augment: (outputKey: string, contractName: string, content: any) => void;
147
+ /** Function to add new outputs */
148
+ addOutput: (key: string, output: GeneratedOutput) => void;
149
+ }
150
+ /**
151
+ * Logger interface for plugin output
152
+ */
153
+ interface Logger {
154
+ info: (message: string) => void;
155
+ warn: (message: string) => void;
156
+ error: (message: string) => void;
157
+ debug: (message: string) => void;
158
+ success: (message: string) => void;
159
+ }
160
+ /**
161
+ * Utility functions available to plugins
162
+ */
163
+ interface PluginUtils {
164
+ /** Convert kebab-case to camelCase */
165
+ toCamelCase: (str: string) => string;
166
+ /** Convert camelCase to kebab-case */
167
+ toKebabCase: (str: string) => string;
168
+ /** Validate Stacks address format */
169
+ validateAddress: (address: string) => boolean;
170
+ /** Parse contract identifier (address.contract-name) */
171
+ parseContractId: (contractId: string) => {
172
+ address: string;
173
+ contractName: string;
174
+ };
175
+ /** Format TypeScript code using prettier */
176
+ formatCode: (code: string) => Promise<string>;
177
+ /** Resolve file path relative to project root */
178
+ resolvePath: (relativePath: string) => string;
179
+ /** Check if file exists */
180
+ fileExists: (path: string) => Promise<boolean>;
181
+ /** Read file content */
182
+ readFile: (path: string) => Promise<string>;
183
+ /** Write file content */
184
+ writeFile: (path: string, content: string) => Promise<void>;
185
+ /** Create directory recursively */
186
+ ensureDir: (path: string) => Promise<void>;
187
+ }
188
+ /**
189
+ * Plugin factory function type for creating plugins with options
190
+ */
191
+ type PluginFactory<TOptions = any> = (options?: TOptions) => StacksCodegenPlugin;
192
+ /**
193
+ * Plugin options base interface
194
+ */
195
+ interface PluginOptions {
196
+ /** Include only specific contracts/functions */
197
+ include?: string[];
198
+ /** Exclude specific contracts/functions */
199
+ exclude?: string[];
200
+ /** Enable debug output */
201
+ debug?: boolean;
202
+ }
203
+ /**
204
+ * Hook execution result
205
+ */
206
+ interface HookResult<T = any> {
207
+ /** Whether the hook was successful */
208
+ success: boolean;
209
+ /** Result data from the hook */
210
+ data?: T;
211
+ /** Error if hook failed */
212
+ error?: Error;
213
+ /** Plugin that executed the hook */
214
+ plugin: string;
215
+ }
216
+
217
+ /**
218
+ * Plugin Manager for @stacks/codegen
219
+ * Handles plugin registration, lifecycle execution, and output management
220
+ */
221
+
222
+ /**
223
+ * Core plugin manager that orchestrates plugin execution
224
+ */
225
+ declare class PluginManager {
226
+ private plugins;
227
+ private logger;
228
+ private utils;
229
+ private executionContext;
230
+ constructor();
231
+ /**
232
+ * Register a plugin
233
+ */
234
+ register(plugin: StacksCodegenPlugin): void;
235
+ /**
236
+ * Get all registered plugins
237
+ */
238
+ getPlugins(): StacksCodegenPlugin[];
239
+ /**
240
+ * Transform user config through all plugins
241
+ */
242
+ transformConfig(config: UserConfig): Promise<ResolvedConfig>;
243
+ /**
244
+ * Transform contracts through all plugins
245
+ */
246
+ transformContracts(contracts: ContractConfig[], _config: ResolvedConfig): Promise<ProcessedContract[]>;
247
+ /**
248
+ * Execute lifecycle hooks
249
+ */
250
+ executeHook(hookName: keyof StacksCodegenPlugin, context: any): Promise<void>;
251
+ /**
252
+ * Execute generation phase with full context
253
+ */
254
+ executeGeneration(contracts: ProcessedContract[], config: ResolvedConfig): Promise<Map<string, GeneratedOutput>>;
255
+ /**
256
+ * Transform outputs through plugins
257
+ */
258
+ transformOutputs(outputs: Map<string, GeneratedOutput>): Promise<Map<string, GeneratedOutput>>;
259
+ /**
260
+ * Write outputs to disk
261
+ */
262
+ writeOutputs(outputs: Map<string, GeneratedOutput>): Promise<void>;
263
+ /**
264
+ * Get execution results for debugging
265
+ */
266
+ getExecutionResults(): Map<string, HookResult[]>;
267
+ /**
268
+ * Augment existing output with additional content
269
+ */
270
+ private augmentOutput;
271
+ /**
272
+ * Record hook execution result
273
+ */
274
+ private recordHookResult;
275
+ /**
276
+ * Create logger instance
277
+ */
278
+ private createLogger;
279
+ /**
280
+ * Create utils instance
281
+ */
282
+ private createUtils;
283
+ }
284
+
285
+ export { type ConfigDefiner as C, type GenerateContext as G, type Logger as L, type NetworkName as N, type OutputType as O, type PluginFactory as P, type ResolvedConfig as R, type StacksConfig as S, type UserConfig as U, type ContractSource as a, type StacksCodegenPlugin as b, type PluginOptions as c, type PluginContext as d, type PluginUtils as e, type GeneratedOutput as f, type ProcessedContract as g, type ContractConfig as h, PluginManager as i };