@clarigen/cli 1.0.0-next.9 → 2.0.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.
- package/README.md +1 -31
- package/dist/index.cjs +1304 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +432 -0
- package/dist/index.js +1239 -17
- package/dist/index.js.map +1 -0
- package/dist/run-cli.cjs +1451 -0
- package/dist/run-cli.cjs.map +1 -0
- package/dist/run-cli.d.ts +1 -0
- package/dist/run-cli.js +1455 -0
- package/dist/run-cli.js.map +1 -0
- package/package.json +36 -51
- package/bin/run +0 -7
- package/dist/clarinet-config.js +0 -70
- package/dist/commands/index.js +0 -65
- package/dist/config.js +0 -54
- package/dist/generate/declaration.js +0 -120
- package/dist/generate/files.js +0 -147
- package/dist/start.js +0 -9
- package/dist/utils.js +0 -53
- package/src/clarinet-config.ts +0 -127
- package/src/commands/index.ts +0 -67
- package/src/config.ts +0 -78
- package/src/generate/declaration.ts +0 -116
- package/src/generate/files.ts +0 -181
- package/src/index.ts +0 -5
- package/src/start.ts +0 -5
- package/src/utils.ts +0 -78
package/dist/run-cli.js
ADDED
|
@@ -0,0 +1,1455 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
var __objRest = (source, exclude) => {
|
|
21
|
+
var target = {};
|
|
22
|
+
for (var prop in source)
|
|
23
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
24
|
+
target[prop] = source[prop];
|
|
25
|
+
if (source != null && __getOwnPropSymbols)
|
|
26
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
27
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
28
|
+
target[prop] = source[prop];
|
|
29
|
+
}
|
|
30
|
+
return target;
|
|
31
|
+
};
|
|
32
|
+
var __publicField = (obj, key, value) => {
|
|
33
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
34
|
+
return value;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// src/run-cli.ts
|
|
38
|
+
import { Cli, Builtins } from "clipanion";
|
|
39
|
+
|
|
40
|
+
// src/commands/session-info.ts
|
|
41
|
+
import { Command as Command2, Option as Option2 } from "clipanion";
|
|
42
|
+
|
|
43
|
+
// src/config.ts
|
|
44
|
+
import { z as z2 } from "zod";
|
|
45
|
+
|
|
46
|
+
// src/logger.ts
|
|
47
|
+
import { pino } from "pino";
|
|
48
|
+
import pinoPretty from "pino-pretty";
|
|
49
|
+
var colorizedClarigen = `\x1B[33m[Clarigen]\x1B[0m`;
|
|
50
|
+
var logger = pino(pinoPretty({
|
|
51
|
+
colorize: true,
|
|
52
|
+
ignore: "pid,hostname,time",
|
|
53
|
+
messageFormat: `${colorizedClarigen} {msg}`,
|
|
54
|
+
minimumLevel: "debug"
|
|
55
|
+
}));
|
|
56
|
+
logger.level = "info";
|
|
57
|
+
var log = logger;
|
|
58
|
+
|
|
59
|
+
// src/utils.ts
|
|
60
|
+
import { getContractName, toCamelCase } from "@clarigen/core";
|
|
61
|
+
import { stat, mkdir, writeFile as fsWriteFile } from "fs/promises";
|
|
62
|
+
import { dirname, relative } from "path";
|
|
63
|
+
function encodeVariableName(name) {
|
|
64
|
+
if (/^[A-Z\-_]*$/.test(name))
|
|
65
|
+
return name.replaceAll("-", "_");
|
|
66
|
+
return toCamelCase(name);
|
|
67
|
+
}
|
|
68
|
+
async function fileExists(filename) {
|
|
69
|
+
try {
|
|
70
|
+
await stat(filename);
|
|
71
|
+
return true;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function writeFile(path, contents) {
|
|
77
|
+
const dir = dirname(path);
|
|
78
|
+
await mkdir(dir, { recursive: true });
|
|
79
|
+
await fsWriteFile(path, contents, "utf-8");
|
|
80
|
+
return path;
|
|
81
|
+
}
|
|
82
|
+
function sortContracts(contracts) {
|
|
83
|
+
const nameSorted = [...contracts].sort((a, b) => {
|
|
84
|
+
if (getContractName(a.contract_id, false) < getContractName(b.contract_id, false)) {
|
|
85
|
+
return -1;
|
|
86
|
+
}
|
|
87
|
+
return 1;
|
|
88
|
+
});
|
|
89
|
+
return nameSorted;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/clarinet-config.ts
|
|
93
|
+
import { z } from "zod";
|
|
94
|
+
import { readFile } from "fs/promises";
|
|
95
|
+
import { parse } from "@iarna/toml";
|
|
96
|
+
var ClarinetConfigSchema = z.object({
|
|
97
|
+
project: z.object({
|
|
98
|
+
requirements: z.array(z.object({ contract_id: z.string() })).optional(),
|
|
99
|
+
cache_location: z.object({ path: z.string() }).optional()
|
|
100
|
+
}),
|
|
101
|
+
contracts: z.record(z.string(), z.object({ path: z.string() })).optional()
|
|
102
|
+
});
|
|
103
|
+
async function getClarinetConfig(path) {
|
|
104
|
+
const file = await readFile(path, "utf-8");
|
|
105
|
+
const config = ClarinetConfigSchema.parse(parse(file));
|
|
106
|
+
return config;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/config.ts
|
|
110
|
+
import { dirname as dirname2, join, relative as relative2, resolve as resolve2 } from "path";
|
|
111
|
+
import { stringify, parse as parse2 } from "@iarna/toml";
|
|
112
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
113
|
+
var CONFIG_FILE = "Clarigen.toml";
|
|
114
|
+
var typesSchema = z2.object({
|
|
115
|
+
output: z2.string().optional(),
|
|
116
|
+
outputs: z2.array(z2.string()).optional(),
|
|
117
|
+
include_accounts: z2.boolean().optional(),
|
|
118
|
+
after: z2.string().optional()
|
|
119
|
+
}).optional();
|
|
120
|
+
var ConfigFileSchema = z2.object({
|
|
121
|
+
clarinet: z2.string(),
|
|
122
|
+
["types" /* ESM */]: typesSchema,
|
|
123
|
+
["esm" /* ESM_OLD */]: typesSchema,
|
|
124
|
+
["docs" /* Docs */]: z2.object({
|
|
125
|
+
output: z2.string().optional(),
|
|
126
|
+
outputs: z2.array(z2.string()).optional(),
|
|
127
|
+
exclude: z2.array(z2.string()).optional(),
|
|
128
|
+
after: z2.string().optional()
|
|
129
|
+
}).optional()
|
|
130
|
+
});
|
|
131
|
+
var defaultConfigFile = {
|
|
132
|
+
clarinet: "./Clarinet.toml"
|
|
133
|
+
};
|
|
134
|
+
var Config = class {
|
|
135
|
+
configFile;
|
|
136
|
+
clarinet;
|
|
137
|
+
cwd;
|
|
138
|
+
constructor(config, clarinet, cwd) {
|
|
139
|
+
this.configFile = config;
|
|
140
|
+
this.clarinet = clarinet;
|
|
141
|
+
this.cwd = cwd ?? process.cwd();
|
|
142
|
+
}
|
|
143
|
+
static async load(cwd) {
|
|
144
|
+
const config = await getConfig(cwd);
|
|
145
|
+
if (config["esm" /* ESM_OLD */]) {
|
|
146
|
+
config["types" /* ESM */] = config["esm" /* ESM_OLD */];
|
|
147
|
+
delete config["esm" /* ESM_OLD */];
|
|
148
|
+
}
|
|
149
|
+
const clarinet = await getClarinetConfig(resolve2(cwd ?? "", config.clarinet));
|
|
150
|
+
return new this(config, clarinet, cwd);
|
|
151
|
+
}
|
|
152
|
+
getOutputs(type) {
|
|
153
|
+
var _a, _b;
|
|
154
|
+
const singlePath = (_a = this.configFile[type]) == null ? void 0 : _a.output;
|
|
155
|
+
const multiPath = ((_b = this.configFile[type]) == null ? void 0 : _b.outputs) || [];
|
|
156
|
+
if (singlePath !== void 0)
|
|
157
|
+
return [singlePath];
|
|
158
|
+
return multiPath;
|
|
159
|
+
}
|
|
160
|
+
outputResolve(type, filePath) {
|
|
161
|
+
const outputs = this.getOutputs(type);
|
|
162
|
+
if (!this.supports(type))
|
|
163
|
+
return null;
|
|
164
|
+
return outputs.map((path) => {
|
|
165
|
+
return resolve2(this.cwd, path, filePath || "");
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async writeOutput(type, contents, filePath) {
|
|
169
|
+
const paths = this.outputResolve(type, filePath);
|
|
170
|
+
if (paths === null)
|
|
171
|
+
return null;
|
|
172
|
+
await Promise.all(paths.map(async (path) => {
|
|
173
|
+
await writeFile(path, contents);
|
|
174
|
+
log.debug(`Generated ${type} file at ${relative2(this.cwd, path)}`);
|
|
175
|
+
}));
|
|
176
|
+
return paths;
|
|
177
|
+
}
|
|
178
|
+
supports(type) {
|
|
179
|
+
return this.getOutputs(type).length > 0;
|
|
180
|
+
}
|
|
181
|
+
type(type) {
|
|
182
|
+
return this.configFile[type];
|
|
183
|
+
}
|
|
184
|
+
get esm() {
|
|
185
|
+
return this.configFile["types" /* ESM */];
|
|
186
|
+
}
|
|
187
|
+
get docs() {
|
|
188
|
+
return this.configFile["docs" /* Docs */];
|
|
189
|
+
}
|
|
190
|
+
clarinetFile() {
|
|
191
|
+
return resolve2(this.cwd, this.configFile.clarinet);
|
|
192
|
+
}
|
|
193
|
+
joinFromClarinet(filePath) {
|
|
194
|
+
const baseDir = dirname2(this.clarinetFile());
|
|
195
|
+
return join(baseDir, filePath);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
function configFilePath(cwd) {
|
|
199
|
+
return resolve2(cwd ?? process.cwd(), CONFIG_FILE);
|
|
200
|
+
}
|
|
201
|
+
var sessionConfig;
|
|
202
|
+
async function getConfig(cwd) {
|
|
203
|
+
if (typeof sessionConfig !== "undefined")
|
|
204
|
+
return sessionConfig;
|
|
205
|
+
const path = configFilePath(cwd);
|
|
206
|
+
if (await fileExists(path)) {
|
|
207
|
+
const toml = await readFile2(path, "utf-8");
|
|
208
|
+
const parsedToml = parse2(toml);
|
|
209
|
+
const parseResult = ConfigFileSchema.safeParse(parsedToml);
|
|
210
|
+
if (parseResult.success) {
|
|
211
|
+
sessionConfig = parseResult.data;
|
|
212
|
+
} else {
|
|
213
|
+
logger.error("Error parsing Clarigen.toml:");
|
|
214
|
+
parseResult.error.errors.forEach((e) => {
|
|
215
|
+
logger.error(`${e.path.join(".")}: ${e.message}`);
|
|
216
|
+
});
|
|
217
|
+
throw new Error("Error parsing Clarigen.toml");
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
sessionConfig = defaultConfigFile;
|
|
221
|
+
}
|
|
222
|
+
return sessionConfig;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// src/commands/base-command.ts
|
|
226
|
+
import { Command, Option } from "clipanion";
|
|
227
|
+
import { ZodError } from "zod";
|
|
228
|
+
var BaseCommand = class extends Command {
|
|
229
|
+
verbose = Option.Boolean("-v,--verbose", false, {
|
|
230
|
+
description: "Enable verbose logging"
|
|
231
|
+
});
|
|
232
|
+
preexecute() {
|
|
233
|
+
if (this.verbose) {
|
|
234
|
+
logger.level = "debug";
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async catch(error) {
|
|
238
|
+
if (error instanceof ZodError) {
|
|
239
|
+
logger.error(error.issues, "Your configuration file is invalid.");
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
logger.error(error);
|
|
243
|
+
if (error instanceof Error) {
|
|
244
|
+
logger.error(error.stack);
|
|
245
|
+
}
|
|
246
|
+
throw error;
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// src/commands/session-info.ts
|
|
251
|
+
var SessionInfoCommand = class extends BaseCommand {
|
|
252
|
+
cwd = Option2.String({ required: false });
|
|
253
|
+
async execute() {
|
|
254
|
+
this.preexecute();
|
|
255
|
+
const config = await Config.load(this.cwd);
|
|
256
|
+
logger.info(config);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
__publicField(SessionInfoCommand, "paths", [["session-info"]]);
|
|
260
|
+
__publicField(SessionInfoCommand, "usage", Command2.Usage({
|
|
261
|
+
description: "Log info about this project's Clarinet session"
|
|
262
|
+
}));
|
|
263
|
+
|
|
264
|
+
// src/commands/default-command.ts
|
|
265
|
+
import { Command as Command3, Option as Option3 } from "clipanion";
|
|
266
|
+
|
|
267
|
+
// src/clarinet-sdk.ts
|
|
268
|
+
import { initSimnet } from "@hirosystems/clarinet-sdk";
|
|
269
|
+
import {
|
|
270
|
+
MAINNET_BURN_ADDRESS,
|
|
271
|
+
TESTNET_BURN_ADDRESS,
|
|
272
|
+
getContractName as getContractName4
|
|
273
|
+
} from "@clarigen/core";
|
|
274
|
+
import { ClarityType } from "@stacks/transactions";
|
|
275
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
276
|
+
|
|
277
|
+
// src/files/variables.ts
|
|
278
|
+
import {
|
|
279
|
+
cvToValue,
|
|
280
|
+
getContractName as getContractName3
|
|
281
|
+
} from "@clarigen/core";
|
|
282
|
+
|
|
283
|
+
// src/declaration.ts
|
|
284
|
+
import {
|
|
285
|
+
isClarityAbiBuffer,
|
|
286
|
+
isClarityAbiList,
|
|
287
|
+
isClarityAbiOptional,
|
|
288
|
+
isClarityAbiPrimitive,
|
|
289
|
+
isClarityAbiResponse,
|
|
290
|
+
isClarityAbiStringAscii,
|
|
291
|
+
isClarityAbiStringUtf8,
|
|
292
|
+
isClarityAbiTuple,
|
|
293
|
+
isClarityAbiTraitReference
|
|
294
|
+
} from "@clarigen/core";
|
|
295
|
+
import { toCamelCase as toCamelCase2 } from "@clarigen/core";
|
|
296
|
+
var jsTypeFromAbiType = (val, isArgument = false) => {
|
|
297
|
+
if (isClarityAbiPrimitive(val)) {
|
|
298
|
+
if (val === "uint128") {
|
|
299
|
+
if (isArgument)
|
|
300
|
+
return "number | bigint";
|
|
301
|
+
return "bigint";
|
|
302
|
+
} else if (val === "int128") {
|
|
303
|
+
if (isArgument)
|
|
304
|
+
return "number | bigint";
|
|
305
|
+
return "bigint";
|
|
306
|
+
} else if (val === "bool") {
|
|
307
|
+
return "boolean";
|
|
308
|
+
} else if (val === "principal") {
|
|
309
|
+
return "string";
|
|
310
|
+
} else if (val === "none") {
|
|
311
|
+
return "null";
|
|
312
|
+
} else if (val === "trait_reference") {
|
|
313
|
+
return "string";
|
|
314
|
+
} else {
|
|
315
|
+
throw new Error(`Unexpected Clarity ABI type primitive: ${JSON.stringify(val)}`);
|
|
316
|
+
}
|
|
317
|
+
} else if (isClarityAbiBuffer(val)) {
|
|
318
|
+
return "Uint8Array";
|
|
319
|
+
} else if (isClarityAbiResponse(val)) {
|
|
320
|
+
const ok = jsTypeFromAbiType(val.response.ok, isArgument);
|
|
321
|
+
const err = jsTypeFromAbiType(val.response.error, isArgument);
|
|
322
|
+
return `Response<${ok}, ${err}>`;
|
|
323
|
+
} else if (isClarityAbiOptional(val)) {
|
|
324
|
+
const innerType = jsTypeFromAbiType(val.optional, isArgument);
|
|
325
|
+
return `${innerType} | null`;
|
|
326
|
+
} else if (isClarityAbiTuple(val)) {
|
|
327
|
+
const tupleDefs = [];
|
|
328
|
+
val.tuple.forEach(({ name, type }) => {
|
|
329
|
+
const camelName = toCamelCase2(name);
|
|
330
|
+
const innerType = jsTypeFromAbiType(type, isArgument);
|
|
331
|
+
tupleDefs.push(`"${camelName}": ${innerType};`);
|
|
332
|
+
});
|
|
333
|
+
return `{
|
|
334
|
+
${tupleDefs.join("\n ")}
|
|
335
|
+
}`;
|
|
336
|
+
} else if (isClarityAbiList(val)) {
|
|
337
|
+
const innerType = jsTypeFromAbiType(val.list.type, isArgument);
|
|
338
|
+
return `${innerType}[]`;
|
|
339
|
+
} else if (isClarityAbiStringAscii(val)) {
|
|
340
|
+
return "string";
|
|
341
|
+
} else if (isClarityAbiStringUtf8(val)) {
|
|
342
|
+
return "string";
|
|
343
|
+
} else if (isClarityAbiTraitReference(val)) {
|
|
344
|
+
return "string";
|
|
345
|
+
} else {
|
|
346
|
+
throw new Error(`Unexpected Clarity ABI type: ${JSON.stringify(val)}`);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
function abiArgType(arg) {
|
|
350
|
+
const nativeType = jsTypeFromAbiType(arg.type, true);
|
|
351
|
+
const argName = getArgName(arg.name);
|
|
352
|
+
return `${argName}: TypedAbiArg<${nativeType}, "${argName}">`;
|
|
353
|
+
}
|
|
354
|
+
function abiFunctionType(abiFunction) {
|
|
355
|
+
const args2 = abiFunction.args.map(abiArgType);
|
|
356
|
+
const retType = jsTypeFromAbiType(abiFunction.outputs.type);
|
|
357
|
+
const argsTuple = `[${args2.join(", ")}]`;
|
|
358
|
+
return `TypedAbiFunction<${argsTuple}, ${retType}>`;
|
|
359
|
+
}
|
|
360
|
+
function getArgName(name) {
|
|
361
|
+
const camel = toCamelCase2(name);
|
|
362
|
+
const prefix = RESERVED[camel] ? "_" : "";
|
|
363
|
+
return `${prefix}${camel}`;
|
|
364
|
+
}
|
|
365
|
+
function _hash(...words) {
|
|
366
|
+
const h = {};
|
|
367
|
+
for (const word of words) {
|
|
368
|
+
h[word] = true;
|
|
369
|
+
}
|
|
370
|
+
return h;
|
|
371
|
+
}
|
|
372
|
+
var RESERVED = _hash("break", "do", "in", "typeof", "case", "else", "instanceof", "var", "catch", "export", "new", "void", "class", "extends", "return", "while", "const", "finally", "super", "with", "continue", "for", "switch", "yield", "debugger", "function", "this", "default", "if", "throw", "delete", "import", "try", "enum", "await", "null", "true", "false");
|
|
373
|
+
|
|
374
|
+
// src/files/base.ts
|
|
375
|
+
import { toCamelCase as toCamelCase3 } from "@clarigen/core";
|
|
376
|
+
|
|
377
|
+
// src/files/accounts.ts
|
|
378
|
+
function generateAccountsCode(session) {
|
|
379
|
+
const accounts = Object.fromEntries(session.accounts.map((account) => {
|
|
380
|
+
const _a = account, { name } = _a, rest = __objRest(_a, ["name"]);
|
|
381
|
+
return [name, rest];
|
|
382
|
+
}));
|
|
383
|
+
return `export const accounts = ${JSON.stringify(accounts)} as const;`;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/files/identifiers.ts
|
|
387
|
+
import { getContractName as getContractName2 } from "@clarigen/core";
|
|
388
|
+
function generateIdentifiers(session) {
|
|
389
|
+
const identifiers = Object.fromEntries(sortContracts(session.contracts).map((c) => {
|
|
390
|
+
const contractName = getContractName2(c.contract_id);
|
|
391
|
+
return [contractName, c.contract_id];
|
|
392
|
+
}));
|
|
393
|
+
return identifiers;
|
|
394
|
+
}
|
|
395
|
+
function generateIdentifiersCode(session) {
|
|
396
|
+
const identifiers = generateIdentifiers(session);
|
|
397
|
+
return `export const identifiers = ${JSON.stringify(identifiers)} as const`;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/files/base.ts
|
|
401
|
+
import { inspect } from "util";
|
|
402
|
+
function generateContractMeta(contract, constants) {
|
|
403
|
+
const abi = contract.contract_interface;
|
|
404
|
+
const functionLines = [];
|
|
405
|
+
const _a = abi, { functions, maps, variables, non_fungible_tokens } = _a, rest = __objRest(_a, ["functions", "maps", "variables", "non_fungible_tokens"]);
|
|
406
|
+
functions.forEach((func) => {
|
|
407
|
+
let functionLine = `${toCamelCase3(func.name)}: `;
|
|
408
|
+
const funcDef = JSON.stringify(func);
|
|
409
|
+
functionLine += funcDef;
|
|
410
|
+
const functionType = abiFunctionType(func);
|
|
411
|
+
functionLine += ` as ${functionType}`;
|
|
412
|
+
functionLines.push(functionLine);
|
|
413
|
+
});
|
|
414
|
+
const mapLines = maps.map((map) => {
|
|
415
|
+
let mapLine = `${toCamelCase3(map.name)}: `;
|
|
416
|
+
const keyType = jsTypeFromAbiType(map.key, true);
|
|
417
|
+
const valType = jsTypeFromAbiType(map.value);
|
|
418
|
+
mapLine += JSON.stringify(map);
|
|
419
|
+
mapLine += ` as TypedAbiMap<${keyType}, ${valType}>`;
|
|
420
|
+
return mapLine;
|
|
421
|
+
});
|
|
422
|
+
const otherAbi = JSON.stringify(rest);
|
|
423
|
+
const contractName = contract.contract_id.split(".")[1];
|
|
424
|
+
const variableLines = encodeVariables(variables);
|
|
425
|
+
const nftLines = non_fungible_tokens.map((nft) => {
|
|
426
|
+
return JSON.stringify(nft);
|
|
427
|
+
});
|
|
428
|
+
return `{
|
|
429
|
+
${serializeLines("functions", functionLines)}
|
|
430
|
+
${serializeLines("maps", mapLines)}
|
|
431
|
+
${serializeLines("variables", variableLines)}
|
|
432
|
+
constants: ${constants},
|
|
433
|
+
${serializeArray("non_fungible_tokens", nftLines)}
|
|
434
|
+
${otherAbi.slice(1, -1)},
|
|
435
|
+
contractName: '${contractName}',
|
|
436
|
+
}`;
|
|
437
|
+
}
|
|
438
|
+
var TYPE_IMPORTS = `import type { TypedAbiArg, TypedAbiFunction, TypedAbiMap, TypedAbiVariable, Response } from '@clarigen/core';`;
|
|
439
|
+
function generateBaseFile(session) {
|
|
440
|
+
const combined = session.contracts.map((c, i) => __spreadProps(__spreadValues({}, c), {
|
|
441
|
+
constants: session.variables[i]
|
|
442
|
+
}));
|
|
443
|
+
const contractDefs = sortContracts(combined).map((contract) => {
|
|
444
|
+
const meta = generateContractMeta(contract, contract.constants);
|
|
445
|
+
const id = contract.contract_id.split(".")[1];
|
|
446
|
+
const keyName = toCamelCase3(id);
|
|
447
|
+
return `${keyName}: ${meta}`;
|
|
448
|
+
});
|
|
449
|
+
const file = `
|
|
450
|
+
${TYPE_IMPORTS}
|
|
451
|
+
|
|
452
|
+
export const contracts = {
|
|
453
|
+
${contractDefs.join(",\n")}
|
|
454
|
+
} as const;
|
|
455
|
+
|
|
456
|
+
${generateAccountsCode(session)}
|
|
457
|
+
|
|
458
|
+
${generateIdentifiersCode(session)}
|
|
459
|
+
|
|
460
|
+
export const simnet = {
|
|
461
|
+
accounts,
|
|
462
|
+
contracts,
|
|
463
|
+
identifiers,
|
|
464
|
+
} as const;
|
|
465
|
+
|
|
466
|
+
`;
|
|
467
|
+
return file;
|
|
468
|
+
}
|
|
469
|
+
function encodeVariables(variables) {
|
|
470
|
+
return variables.map((v) => {
|
|
471
|
+
let varLine = `${encodeVariableName(v.name)}: `;
|
|
472
|
+
const type = jsTypeFromAbiType(v.type);
|
|
473
|
+
const varJSON = serialize(v);
|
|
474
|
+
varLine += `${varJSON} as TypedAbiVariable<${type}>`;
|
|
475
|
+
return varLine;
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
Uint8Array.prototype[inspect.custom] = function(depth, options) {
|
|
479
|
+
return `Uint8Array.from([${this.join(",")}])`;
|
|
480
|
+
};
|
|
481
|
+
function serialize(obj) {
|
|
482
|
+
return inspect(obj, {
|
|
483
|
+
showHidden: false,
|
|
484
|
+
compact: false,
|
|
485
|
+
depth: 100,
|
|
486
|
+
colors: false,
|
|
487
|
+
maxArrayLength: Infinity,
|
|
488
|
+
maxStringLength: Infinity,
|
|
489
|
+
breakLength: Infinity,
|
|
490
|
+
numericSeparator: true
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
function serializeLines(key, lines) {
|
|
494
|
+
return `"${key}": {
|
|
495
|
+
${lines.join(",\n ")}
|
|
496
|
+
},`;
|
|
497
|
+
}
|
|
498
|
+
function serializeArray(key, lines) {
|
|
499
|
+
return `"${key}": [
|
|
500
|
+
${lines.join(",\n ")}
|
|
501
|
+
],`;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/files/variables.ts
|
|
505
|
+
function getVariablesV2(contract, simnet, verbose) {
|
|
506
|
+
const [deployer] = contract.contract_id.split(".");
|
|
507
|
+
const fakeId = `${getContractName3(contract.contract_id)}-vars`;
|
|
508
|
+
logger.debug(`Deploying ${contract.contract_id} for variables.`);
|
|
509
|
+
if (!contract.source) {
|
|
510
|
+
logger.debug(`Contract ${getContractName3(contract.contract_id)} has no source. Skipping variables.`);
|
|
511
|
+
return {};
|
|
512
|
+
}
|
|
513
|
+
if (contract.contract_interface.variables.length === 0) {
|
|
514
|
+
logger.info(`Contract ${getContractName3(contract.contract_id, false)} has no variables`);
|
|
515
|
+
return {};
|
|
516
|
+
}
|
|
517
|
+
let varFn = `{
|
|
518
|
+
`;
|
|
519
|
+
const varLines = contract.contract_interface.variables.map((variable) => {
|
|
520
|
+
let varLine = `${variable.name}: `;
|
|
521
|
+
if (variable.access === "constant") {
|
|
522
|
+
varLine += `${variable.name}`;
|
|
523
|
+
} else {
|
|
524
|
+
varLine += `(var-get ${variable.name})`;
|
|
525
|
+
}
|
|
526
|
+
return varLine;
|
|
527
|
+
});
|
|
528
|
+
varFn += varLines.map((l) => ` ${l},`).join("\n");
|
|
529
|
+
varFn += "\n}";
|
|
530
|
+
const fullSrc = contract.source + `
|
|
531
|
+
|
|
532
|
+
${varFn}`;
|
|
533
|
+
try {
|
|
534
|
+
const receipt = simnet.deployContract(fakeId, fullSrc, {
|
|
535
|
+
clarityVersion: 2
|
|
536
|
+
}, deployer);
|
|
537
|
+
const result = receipt.result;
|
|
538
|
+
const varsAbi = {
|
|
539
|
+
tuple: []
|
|
540
|
+
};
|
|
541
|
+
contract.contract_interface.variables.forEach((v) => {
|
|
542
|
+
const _v = v;
|
|
543
|
+
varsAbi.tuple.push({
|
|
544
|
+
type: _v.type,
|
|
545
|
+
name: _v.name
|
|
546
|
+
});
|
|
547
|
+
});
|
|
548
|
+
if (verbose) {
|
|
549
|
+
logger.info(cvToValue(result, true));
|
|
550
|
+
}
|
|
551
|
+
return cvToValue(result, true);
|
|
552
|
+
} catch (error) {
|
|
553
|
+
logger.error(`Error getting variables for ${getContractName3(contract.contract_id, false)}`);
|
|
554
|
+
logger.error(`Source code: ${contract.source} with type ${String(typeof contract.source)}`);
|
|
555
|
+
logger.error(error);
|
|
556
|
+
logger.error(fullSrc);
|
|
557
|
+
return {};
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
function mapVariables(session, simnet) {
|
|
561
|
+
return session.contracts.map((contract) => {
|
|
562
|
+
const vars = getVariablesV2(contract, simnet);
|
|
563
|
+
return serialize(vars);
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// src/clarinet-sdk.ts
|
|
568
|
+
async function getSession(config) {
|
|
569
|
+
const simnet = await initSimnet(config.clarinetFile());
|
|
570
|
+
const interfaces = simnet.getContractsInterfaces();
|
|
571
|
+
const accounts = simnet.getAccounts();
|
|
572
|
+
const allAccounts = [...accounts.entries()].map(([name, address]) => {
|
|
573
|
+
const result = simnet.runSnippet(`(stx-get-balance '${address})`);
|
|
574
|
+
if (result.type !== ClarityType.UInt) {
|
|
575
|
+
throw new Error(`Unexpected result type for \`(stx-get-balance \``);
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
name,
|
|
579
|
+
address,
|
|
580
|
+
balance: result.value.toString()
|
|
581
|
+
};
|
|
582
|
+
});
|
|
583
|
+
const contracts = (await Promise.all([...interfaces.entries()].map(async ([contract_id, contract_interface]) => {
|
|
584
|
+
var _a, _b;
|
|
585
|
+
if (contract_id.startsWith(MAINNET_BURN_ADDRESS) || contract_id.startsWith(TESTNET_BURN_ADDRESS)) {
|
|
586
|
+
return void 0;
|
|
587
|
+
}
|
|
588
|
+
const name = getContractName4(contract_id, false);
|
|
589
|
+
const contractPathDef = (_b = (_a = config.clarinet.contracts) == null ? void 0 : _a[name]) == null ? void 0 : _b.path;
|
|
590
|
+
let source;
|
|
591
|
+
if (contractPathDef) {
|
|
592
|
+
const contractPathFull = config.joinFromClarinet(contractPathDef);
|
|
593
|
+
source = await readFile3(contractPathFull, "utf-8");
|
|
594
|
+
}
|
|
595
|
+
return {
|
|
596
|
+
contract_id,
|
|
597
|
+
contract_interface,
|
|
598
|
+
source: source ?? ""
|
|
599
|
+
};
|
|
600
|
+
}))).filter((x) => x !== void 0);
|
|
601
|
+
const session = {
|
|
602
|
+
session_id: 0,
|
|
603
|
+
accounts: allAccounts,
|
|
604
|
+
contracts
|
|
605
|
+
};
|
|
606
|
+
const variables = mapVariables(session, simnet);
|
|
607
|
+
return {
|
|
608
|
+
session_id: 0,
|
|
609
|
+
accounts: allAccounts,
|
|
610
|
+
contracts,
|
|
611
|
+
variables
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// src/files/esm.ts
|
|
616
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
617
|
+
import { join as join2, dirname as dirname3, relative as relative3 } from "path";
|
|
618
|
+
import { parse as parse3 } from "yaml";
|
|
619
|
+
|
|
620
|
+
// src/deployments.ts
|
|
621
|
+
function flatBatch(batches) {
|
|
622
|
+
const txs = [];
|
|
623
|
+
batches.forEach((batch) => txs.push(...batch.transactions));
|
|
624
|
+
return txs;
|
|
625
|
+
}
|
|
626
|
+
function getContractTxs(batches) {
|
|
627
|
+
const txs = flatBatch(batches);
|
|
628
|
+
return txs.filter(isContractTx);
|
|
629
|
+
}
|
|
630
|
+
function getDeploymentContract(contractName, deployment) {
|
|
631
|
+
const txs = flatBatch(deployment.plan.batches);
|
|
632
|
+
for (const tx of txs) {
|
|
633
|
+
if (!isContractTx(tx))
|
|
634
|
+
continue;
|
|
635
|
+
if ("requirement-publish" in tx) {
|
|
636
|
+
const [_, name] = tx["requirement-publish"]["contract-id"].split(".");
|
|
637
|
+
if (name === contractName) {
|
|
638
|
+
return tx;
|
|
639
|
+
}
|
|
640
|
+
} else if ("emulated-contract-publish" in tx) {
|
|
641
|
+
if (tx["emulated-contract-publish"]["contract-name"] === contractName) {
|
|
642
|
+
return tx;
|
|
643
|
+
}
|
|
644
|
+
} else if ("contract-publish" in tx) {
|
|
645
|
+
const contract = tx["contract-publish"];
|
|
646
|
+
if (contract["contract-name"] === contractName) {
|
|
647
|
+
return tx;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
throw new Error(`Unable to find deployment tx for contract '${contractName}'`);
|
|
652
|
+
}
|
|
653
|
+
function getDeploymentTxPath(tx) {
|
|
654
|
+
if (!isContractTx(tx)) {
|
|
655
|
+
throw new Error("Unable to get path for tx type.");
|
|
656
|
+
}
|
|
657
|
+
if ("requirement-publish" in tx) {
|
|
658
|
+
return tx["requirement-publish"].path;
|
|
659
|
+
} else if ("emulated-contract-publish" in tx) {
|
|
660
|
+
const contract = tx["emulated-contract-publish"];
|
|
661
|
+
return contract.path;
|
|
662
|
+
} else if ("contract-publish" in tx) {
|
|
663
|
+
const contract = tx["contract-publish"];
|
|
664
|
+
return contract.path;
|
|
665
|
+
}
|
|
666
|
+
throw new Error("Couldnt get path for deployment tx.");
|
|
667
|
+
}
|
|
668
|
+
function getIdentifier(tx) {
|
|
669
|
+
if (!isContractTx(tx)) {
|
|
670
|
+
throw new Error("Unable to get ID for tx type.");
|
|
671
|
+
}
|
|
672
|
+
if ("requirement-publish" in tx) {
|
|
673
|
+
const spec = tx["requirement-publish"];
|
|
674
|
+
const [_, name] = spec["contract-id"].split(".");
|
|
675
|
+
return `${spec["remap-sender"]}.${name}`;
|
|
676
|
+
} else if ("emulated-contract-publish" in tx) {
|
|
677
|
+
const contract = tx["emulated-contract-publish"];
|
|
678
|
+
return `${contract["emulated-sender"]}.${contract["contract-name"]}`;
|
|
679
|
+
} else if ("contract-publish" in tx) {
|
|
680
|
+
const contract = tx["contract-publish"];
|
|
681
|
+
return `${contract["expected-sender"]}.${contract["contract-name"]}`;
|
|
682
|
+
}
|
|
683
|
+
throw new Error(`Unable to find ID for contract.`);
|
|
684
|
+
}
|
|
685
|
+
function isContractTx(tx) {
|
|
686
|
+
if ("contract-call" in tx)
|
|
687
|
+
return false;
|
|
688
|
+
if ("btc-transfer" in tx)
|
|
689
|
+
return false;
|
|
690
|
+
if ("emulated-contract-call" in tx)
|
|
691
|
+
return false;
|
|
692
|
+
return true;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// src/files/esm.ts
|
|
696
|
+
import { getContractName as getContractName5 } from "@clarigen/core";
|
|
697
|
+
import { spawn } from "child_process";
|
|
698
|
+
async function parseDeployment(path) {
|
|
699
|
+
const contents = await readFile4(path, "utf-8");
|
|
700
|
+
const parsed = parse3(contents);
|
|
701
|
+
return parsed;
|
|
702
|
+
}
|
|
703
|
+
var DEPLOYMENT_NETWORKS = ["devnet", "simnet", "testnet", "mainnet"];
|
|
704
|
+
async function getDeployments(config) {
|
|
705
|
+
const entries = await Promise.all(DEPLOYMENT_NETWORKS.map(async (network) => {
|
|
706
|
+
const file = `default.${network}-plan.yaml`;
|
|
707
|
+
const path = join2(dirname3(config.clarinetFile()), "deployments", file);
|
|
708
|
+
let plan;
|
|
709
|
+
try {
|
|
710
|
+
plan = await parseDeployment(path);
|
|
711
|
+
} catch (_) {
|
|
712
|
+
}
|
|
713
|
+
return [network, plan];
|
|
714
|
+
}));
|
|
715
|
+
return Object.fromEntries(entries);
|
|
716
|
+
}
|
|
717
|
+
async function generateESMFile({
|
|
718
|
+
baseFile,
|
|
719
|
+
session,
|
|
720
|
+
config
|
|
721
|
+
}) {
|
|
722
|
+
const deployments = await getDeployments(config);
|
|
723
|
+
const contractDeployments = collectContractDeployments(session, deployments, config);
|
|
724
|
+
const simnet = generateSimnetCode(config, deployments, session);
|
|
725
|
+
return `${baseFile}
|
|
726
|
+
export const deployments = ${JSON.stringify(contractDeployments)} as const;
|
|
727
|
+
${simnet}
|
|
728
|
+
export const project = {
|
|
729
|
+
contracts,
|
|
730
|
+
deployments,
|
|
731
|
+
} as const;
|
|
732
|
+
`;
|
|
733
|
+
}
|
|
734
|
+
function insertNetworkId(deployments, identifier, network) {
|
|
735
|
+
const name = getContractName5(identifier);
|
|
736
|
+
if (!deployments[name]) {
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
if (deployments[name][network] === null) {
|
|
740
|
+
deployments[name][network] = identifier;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
function collectContractDeployments(session, deployments, config) {
|
|
744
|
+
var _a;
|
|
745
|
+
const full = Object.fromEntries(sortContracts(session.contracts).map((contract) => {
|
|
746
|
+
const contractName = getContractName5(contract.contract_id);
|
|
747
|
+
const contractDeployments = Object.fromEntries(DEPLOYMENT_NETWORKS.map((network) => {
|
|
748
|
+
const deployment = deployments[network];
|
|
749
|
+
if (typeof deployment === "undefined") {
|
|
750
|
+
return [network, null];
|
|
751
|
+
}
|
|
752
|
+
try {
|
|
753
|
+
const contractName2 = contract.contract_id.split(".")[1];
|
|
754
|
+
const tx = getDeploymentContract(contractName2, deployment);
|
|
755
|
+
const id = getIdentifier(tx);
|
|
756
|
+
return [network, id];
|
|
757
|
+
} catch (_) {
|
|
758
|
+
return [network, null];
|
|
759
|
+
}
|
|
760
|
+
}));
|
|
761
|
+
return [contractName, contractDeployments];
|
|
762
|
+
}));
|
|
763
|
+
const deployer = session.accounts.find((a) => a.name === "deployer");
|
|
764
|
+
(_a = config.clarinet.project.requirements) == null ? void 0 : _a.forEach(({ contract_id }) => {
|
|
765
|
+
insertNetworkId(full, contract_id, "mainnet");
|
|
766
|
+
const contractName = contract_id.split(".")[1];
|
|
767
|
+
if (deployer) {
|
|
768
|
+
const devnetId = `${deployer.address}.${contractName}`;
|
|
769
|
+
insertNetworkId(full, devnetId, "devnet");
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
session.contracts.forEach((contract) => {
|
|
773
|
+
insertNetworkId(full, contract.contract_id, "devnet");
|
|
774
|
+
insertNetworkId(full, contract.contract_id, "simnet");
|
|
775
|
+
});
|
|
776
|
+
return full;
|
|
777
|
+
}
|
|
778
|
+
function collectDeploymentFiles(deployments, clarinetFolder, cwd) {
|
|
779
|
+
if (!deployments.simnet)
|
|
780
|
+
return [];
|
|
781
|
+
const simnet = deployments.simnet;
|
|
782
|
+
const txs = getContractTxs(simnet.plan.batches);
|
|
783
|
+
const entries = txs.map((tx) => {
|
|
784
|
+
const id = getIdentifier(tx);
|
|
785
|
+
const contractFile = getDeploymentTxPath(tx);
|
|
786
|
+
return {
|
|
787
|
+
identifier: id,
|
|
788
|
+
file: relative3(cwd, join2(clarinetFolder, contractFile))
|
|
789
|
+
};
|
|
790
|
+
});
|
|
791
|
+
return entries;
|
|
792
|
+
}
|
|
793
|
+
function generateSimnetCode(config, deployments, _session) {
|
|
794
|
+
var _a;
|
|
795
|
+
if (!((_a = config.esm) == null ? void 0 : _a.include_accounts))
|
|
796
|
+
return "";
|
|
797
|
+
const clarinetFolder = dirname3(config.clarinetFile());
|
|
798
|
+
const files = collectDeploymentFiles(deployments, clarinetFolder, config.cwd);
|
|
799
|
+
return `
|
|
800
|
+
export const simnetDeployment = ${JSON.stringify(files)};
|
|
801
|
+
`;
|
|
802
|
+
}
|
|
803
|
+
async function afterESM(config) {
|
|
804
|
+
var _a;
|
|
805
|
+
const command = (_a = config.esm) == null ? void 0 : _a.after;
|
|
806
|
+
if (!command)
|
|
807
|
+
return;
|
|
808
|
+
logger.debug(`Running after ESM command: ${command}`);
|
|
809
|
+
const parts = command.split(" ");
|
|
810
|
+
const [cmd, ...args2] = parts;
|
|
811
|
+
return new Promise((resolve3, reject) => {
|
|
812
|
+
const child = spawn(cmd, args2, {
|
|
813
|
+
cwd: config.cwd,
|
|
814
|
+
stdio: "inherit"
|
|
815
|
+
});
|
|
816
|
+
child.on("error", reject);
|
|
817
|
+
child.on("exit", (code) => {
|
|
818
|
+
if (code === 0) {
|
|
819
|
+
resolve3();
|
|
820
|
+
} else {
|
|
821
|
+
reject(new Error(`Command failed with code ${code ?? "unknown"}`));
|
|
822
|
+
}
|
|
823
|
+
});
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// src/commands/default-command.ts
|
|
828
|
+
import chokidar from "chokidar";
|
|
829
|
+
import { dirname as dirname4, join as join3, relative as relative4 } from "path";
|
|
830
|
+
async function generate(config) {
|
|
831
|
+
const session = await getSession(config);
|
|
832
|
+
const baseFile = generateBaseFile(session);
|
|
833
|
+
if (config.supports("types" /* ESM */)) {
|
|
834
|
+
const esmFile = await generateESMFile({
|
|
835
|
+
baseFile,
|
|
836
|
+
session,
|
|
837
|
+
config
|
|
838
|
+
});
|
|
839
|
+
await config.writeOutput("types" /* ESM */, esmFile);
|
|
840
|
+
await afterESM(config);
|
|
841
|
+
}
|
|
842
|
+
if (!config.supports("types" /* ESM */)) {
|
|
843
|
+
logger.warn("no config for ESM outputs. Not outputting any generated types.");
|
|
844
|
+
}
|
|
845
|
+
logger.info("Types generated!");
|
|
846
|
+
}
|
|
847
|
+
async function watch(config, cwd) {
|
|
848
|
+
return new Promise((resolve3, reject) => {
|
|
849
|
+
const clarinetFolder = dirname4(config.clarinetFile());
|
|
850
|
+
const contractsFolder = join3(clarinetFolder, "/contracts/**/*.clar");
|
|
851
|
+
const relativeFolder = relative4(cwd || process.cwd(), contractsFolder);
|
|
852
|
+
logger.info(`Watching for changes in ${relativeFolder}`);
|
|
853
|
+
const watcher = chokidar.watch(contractsFolder, { persistent: true, cwd: clarinetFolder });
|
|
854
|
+
let running = false;
|
|
855
|
+
let start = 0;
|
|
856
|
+
const isVerbose = logger.level !== "info";
|
|
857
|
+
watcher.on("change", (path) => {
|
|
858
|
+
if (!running) {
|
|
859
|
+
start = Date.now();
|
|
860
|
+
logger.info(`File ${path} has been changed. Generating types.`);
|
|
861
|
+
running = true;
|
|
862
|
+
void generate(config).then(() => {
|
|
863
|
+
setTimeout(() => {
|
|
864
|
+
process.stdout.moveCursor(0, -1);
|
|
865
|
+
process.stdout.clearLine(1);
|
|
866
|
+
const elapsed = Date.now() - start;
|
|
867
|
+
logger.info(`Types generated (${(elapsed / 1e3).toFixed(2)}s). Watching for changes...`);
|
|
868
|
+
running = false;
|
|
869
|
+
});
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
var DefaultCommand = class extends BaseCommand {
|
|
876
|
+
cwd = Option3.String({
|
|
877
|
+
required: false
|
|
878
|
+
});
|
|
879
|
+
watch = Option3.Boolean("-w,--watch", {
|
|
880
|
+
description: "Watch for changes and regenerate types",
|
|
881
|
+
required: false
|
|
882
|
+
});
|
|
883
|
+
async execute() {
|
|
884
|
+
this.preexecute();
|
|
885
|
+
const config = await Config.load(this.cwd);
|
|
886
|
+
if (this.watch) {
|
|
887
|
+
await watch(config, this.cwd);
|
|
888
|
+
} else {
|
|
889
|
+
await generate(config);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
__publicField(DefaultCommand, "paths", [Command3.Default, ["generate"]]);
|
|
894
|
+
__publicField(DefaultCommand, "usage", Command3.Usage({
|
|
895
|
+
description: "Generate types for your Clarity contracts",
|
|
896
|
+
examples: [
|
|
897
|
+
["Basic usage:", "clarigen"],
|
|
898
|
+
["When your `Clarigen.toml` is in a different directory:", "clarigen /path/to/your/project"],
|
|
899
|
+
["Watch for changes and regenerate types:", "clarigen --watch"]
|
|
900
|
+
]
|
|
901
|
+
}));
|
|
902
|
+
|
|
903
|
+
// src/commands/docs-command.ts
|
|
904
|
+
import { Option as Option4 } from "clipanion";
|
|
905
|
+
|
|
906
|
+
// src/files/docs.ts
|
|
907
|
+
import { getContractName as getContractName7 } from "@clarigen/core";
|
|
908
|
+
import { relative as relative5, extname } from "path";
|
|
909
|
+
|
|
910
|
+
// src/docs/markdown.ts
|
|
911
|
+
import { getContractName as getContractName6 } from "@clarigen/core";
|
|
912
|
+
|
|
913
|
+
// src/docs/index.ts
|
|
914
|
+
import { spawn as spawn2 } from "child_process";
|
|
915
|
+
var FN_TYPES = ["read-only", "public", "private"];
|
|
916
|
+
var VAR_TYPES = ["map", "data-var", "constant"];
|
|
917
|
+
function createContractDocInfo({
|
|
918
|
+
contractSrc,
|
|
919
|
+
abi
|
|
920
|
+
}) {
|
|
921
|
+
const lines = contractSrc.split("\n");
|
|
922
|
+
let comments = [];
|
|
923
|
+
let parensCount = 0;
|
|
924
|
+
let currentFn;
|
|
925
|
+
const contract = {
|
|
926
|
+
comments: [],
|
|
927
|
+
functions: [],
|
|
928
|
+
variables: [],
|
|
929
|
+
maps: []
|
|
930
|
+
};
|
|
931
|
+
lines.forEach((line, lineNumber) => {
|
|
932
|
+
if (currentFn) {
|
|
933
|
+
currentFn.source.push(line);
|
|
934
|
+
parensCount = traceParens(line, parensCount);
|
|
935
|
+
if (parensCount === 0) {
|
|
936
|
+
pushItem(contract, currentFn);
|
|
937
|
+
currentFn = void 0;
|
|
938
|
+
}
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (isComment(line)) {
|
|
942
|
+
const comment = line.replace(/^\s*;;\s*/g, "");
|
|
943
|
+
if (contract.comments.length === lineNumber) {
|
|
944
|
+
contract.comments.push(comment);
|
|
945
|
+
} else {
|
|
946
|
+
comments.push(comment);
|
|
947
|
+
}
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
const name = findItemNameFromLine(line);
|
|
951
|
+
if (typeof name === "undefined") {
|
|
952
|
+
comments = [];
|
|
953
|
+
} else {
|
|
954
|
+
const abiFn = findAbiItemByName(abi, name);
|
|
955
|
+
if (!abiFn) {
|
|
956
|
+
console.debug(`[claridoc]: Unable to find ABI for function \`${name}\`. Probably a bug.`);
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
parensCount = traceParens(line, 0);
|
|
960
|
+
const metaComments = parseComments(comments, abiFn);
|
|
961
|
+
currentFn = {
|
|
962
|
+
abi: abiFn,
|
|
963
|
+
comments: metaComments,
|
|
964
|
+
startLine: lineNumber,
|
|
965
|
+
source: [line]
|
|
966
|
+
};
|
|
967
|
+
if (parensCount === 0) {
|
|
968
|
+
pushItem(contract, currentFn);
|
|
969
|
+
currentFn = void 0;
|
|
970
|
+
}
|
|
971
|
+
comments = [];
|
|
972
|
+
}
|
|
973
|
+
});
|
|
974
|
+
return contract;
|
|
975
|
+
}
|
|
976
|
+
function pushItem(contract, item) {
|
|
977
|
+
if ("args" in item.abi) {
|
|
978
|
+
contract.functions.push(item);
|
|
979
|
+
} else if ("key" in item.abi) {
|
|
980
|
+
contract.maps.push(item);
|
|
981
|
+
} else if ("access" in item.abi) {
|
|
982
|
+
contract.variables.push(item);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
function clarityNameMatcher(line) {
|
|
986
|
+
return /[\w|\-|\?|\!]+/.exec(line);
|
|
987
|
+
}
|
|
988
|
+
function findItemNameFromLine(line) {
|
|
989
|
+
const fnType = FN_TYPES.find((type) => {
|
|
990
|
+
return line.startsWith(`(define-${type}`);
|
|
991
|
+
});
|
|
992
|
+
if (fnType) {
|
|
993
|
+
const prefix = `(define-${fnType} (`;
|
|
994
|
+
const startString = line.slice(prefix.length);
|
|
995
|
+
const match = clarityNameMatcher(startString);
|
|
996
|
+
if (!match) {
|
|
997
|
+
console.debug(`[claridocs]: Unable to determine function name from line:
|
|
998
|
+
\`${line}\``);
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
return match[0];
|
|
1002
|
+
}
|
|
1003
|
+
for (const type of VAR_TYPES) {
|
|
1004
|
+
const prefix = `(define-${type} `;
|
|
1005
|
+
if (!line.startsWith(prefix))
|
|
1006
|
+
continue;
|
|
1007
|
+
const startString = line.slice(prefix.length);
|
|
1008
|
+
const match = clarityNameMatcher(startString);
|
|
1009
|
+
if (!match) {
|
|
1010
|
+
console.debug(`[claridocs]: Unable to determine ${type} name from line:
|
|
1011
|
+
\`${line}\``);
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
return match[0];
|
|
1015
|
+
}
|
|
1016
|
+
return void 0;
|
|
1017
|
+
}
|
|
1018
|
+
function findAbiItemByName(abi, name) {
|
|
1019
|
+
const fn = abi.functions.find((fn2) => {
|
|
1020
|
+
return fn2.name === name;
|
|
1021
|
+
});
|
|
1022
|
+
if (fn)
|
|
1023
|
+
return fn;
|
|
1024
|
+
const map = abi.maps.find((m) => m.name === name);
|
|
1025
|
+
if (map)
|
|
1026
|
+
return map;
|
|
1027
|
+
const v = abi.variables.find((v2) => v2.name === name);
|
|
1028
|
+
return v;
|
|
1029
|
+
}
|
|
1030
|
+
function isComment(line) {
|
|
1031
|
+
return line.startsWith(";;");
|
|
1032
|
+
}
|
|
1033
|
+
function traceParens(line, count) {
|
|
1034
|
+
let newCount = count;
|
|
1035
|
+
line.split("").forEach((char) => {
|
|
1036
|
+
if (char === "(")
|
|
1037
|
+
newCount++;
|
|
1038
|
+
if (char === ")")
|
|
1039
|
+
newCount--;
|
|
1040
|
+
});
|
|
1041
|
+
return newCount;
|
|
1042
|
+
}
|
|
1043
|
+
function parseComments(comments, abi) {
|
|
1044
|
+
let curParam;
|
|
1045
|
+
const parsed = {
|
|
1046
|
+
text: [],
|
|
1047
|
+
params: {}
|
|
1048
|
+
};
|
|
1049
|
+
comments.forEach((line) => {
|
|
1050
|
+
const paramMatches = /\s*@param\s([\w|\-]+)([;|-|\s]*)(.*)/.exec(line);
|
|
1051
|
+
if (paramMatches === null) {
|
|
1052
|
+
if (!curParam || line.trim() === "") {
|
|
1053
|
+
curParam = void 0;
|
|
1054
|
+
parsed.text.push(line);
|
|
1055
|
+
} else {
|
|
1056
|
+
parsed.params[curParam].comments.push(line);
|
|
1057
|
+
}
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
if (!("args" in abi))
|
|
1061
|
+
return;
|
|
1062
|
+
const [_full, name, _separator, rest] = paramMatches;
|
|
1063
|
+
const arg = abi.args.find((arg2) => arg2.name === name);
|
|
1064
|
+
if (!arg) {
|
|
1065
|
+
console.debug(`[claridocs]: Unable to find ABI for @param ${name}`);
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
curParam = name;
|
|
1069
|
+
parsed.params[curParam] = {
|
|
1070
|
+
abi: arg,
|
|
1071
|
+
comments: [rest]
|
|
1072
|
+
};
|
|
1073
|
+
});
|
|
1074
|
+
if ("args" in abi) {
|
|
1075
|
+
abi.args.forEach((arg) => {
|
|
1076
|
+
if (!parsed.params[arg.name]) {
|
|
1077
|
+
parsed.params[arg.name] = {
|
|
1078
|
+
abi: arg,
|
|
1079
|
+
comments: []
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
return parsed;
|
|
1085
|
+
}
|
|
1086
|
+
async function afterDocs(config) {
|
|
1087
|
+
var _a;
|
|
1088
|
+
const command = (_a = config.docs) == null ? void 0 : _a.after;
|
|
1089
|
+
if (!command)
|
|
1090
|
+
return;
|
|
1091
|
+
logger.debug(`Running after docs command: ${command}`);
|
|
1092
|
+
const parts = command.split(" ");
|
|
1093
|
+
const [cmd, ...args2] = parts;
|
|
1094
|
+
return new Promise((resolve3, reject) => {
|
|
1095
|
+
const child = spawn2(cmd, args2, {
|
|
1096
|
+
cwd: config.cwd,
|
|
1097
|
+
stdio: "inherit"
|
|
1098
|
+
});
|
|
1099
|
+
child.on("error", reject);
|
|
1100
|
+
child.on("exit", (code) => {
|
|
1101
|
+
if (code === 0) {
|
|
1102
|
+
resolve3();
|
|
1103
|
+
} else {
|
|
1104
|
+
reject(new Error(`Command failed with code ${code ?? "unknown"}`));
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// src/docs/markdown.ts
|
|
1111
|
+
import { basename } from "path";
|
|
1112
|
+
import { getTypeString } from "@stacks/transactions";
|
|
1113
|
+
function generateMarkdown({
|
|
1114
|
+
contract,
|
|
1115
|
+
contractFile,
|
|
1116
|
+
withToc = true
|
|
1117
|
+
}) {
|
|
1118
|
+
const contractName = getContractName6(contract.contract_id, false);
|
|
1119
|
+
const doc = createContractDocInfo({
|
|
1120
|
+
contractSrc: contract.source,
|
|
1121
|
+
abi: contract.contract_interface
|
|
1122
|
+
});
|
|
1123
|
+
const functions = doc.functions.map((fn) => markdownFunction(fn, contractFile));
|
|
1124
|
+
const maps = doc.maps.map((map) => markdownMap(map, contractFile));
|
|
1125
|
+
const vars = doc.variables.filter((v) => v.abi.access === "variable").map((v) => markdownVar(v, contractFile));
|
|
1126
|
+
const constants = doc.variables.filter((v) => v.abi.access === "constant").map((v) => markdownVar(v, contractFile));
|
|
1127
|
+
let fileLine = "";
|
|
1128
|
+
if (contractFile) {
|
|
1129
|
+
const fileName = basename(contractFile);
|
|
1130
|
+
fileLine = `
|
|
1131
|
+
[\`${fileName}\`](${contractFile})`;
|
|
1132
|
+
}
|
|
1133
|
+
return `
|
|
1134
|
+
# ${contractName}
|
|
1135
|
+
${fileLine}
|
|
1136
|
+
|
|
1137
|
+
${doc.comments.join("\n\n")}
|
|
1138
|
+
|
|
1139
|
+
${withToc ? markdownTOC(doc) : ""}
|
|
1140
|
+
|
|
1141
|
+
## Functions
|
|
1142
|
+
|
|
1143
|
+
${functions.join("\n\n")}
|
|
1144
|
+
|
|
1145
|
+
## Maps
|
|
1146
|
+
|
|
1147
|
+
${maps.join("\n\n")}
|
|
1148
|
+
|
|
1149
|
+
## Variables
|
|
1150
|
+
|
|
1151
|
+
${vars.join("\n\n")}
|
|
1152
|
+
|
|
1153
|
+
## Constants
|
|
1154
|
+
|
|
1155
|
+
${constants.join("\n\n")}
|
|
1156
|
+
`;
|
|
1157
|
+
}
|
|
1158
|
+
function markdownFunction(fn, contractFile) {
|
|
1159
|
+
const params = mdParams(fn);
|
|
1160
|
+
const returnType = getTypeString(fn.abi.outputs.type);
|
|
1161
|
+
const paramSigs = fn.abi.args.map((arg) => {
|
|
1162
|
+
return `(${arg.name} ${getTypeString(arg.type)})`;
|
|
1163
|
+
});
|
|
1164
|
+
const startLine = fn.startLine + 1;
|
|
1165
|
+
let link = "";
|
|
1166
|
+
if (contractFile) {
|
|
1167
|
+
link = `[View in file](${contractFile}#L${startLine})`;
|
|
1168
|
+
}
|
|
1169
|
+
const source = `<details>
|
|
1170
|
+
<summary>Source code:</summary>
|
|
1171
|
+
|
|
1172
|
+
\`\`\`clarity
|
|
1173
|
+
${fn.source.join("\n")}
|
|
1174
|
+
\`\`\`
|
|
1175
|
+
</details>
|
|
1176
|
+
`;
|
|
1177
|
+
const sig = `(define-${fn.abi.access.replace("_", "-")} (${fn.abi.name} (${paramSigs.join(" ")}) ${returnType})`;
|
|
1178
|
+
return `### ${fn.abi.name}
|
|
1179
|
+
|
|
1180
|
+
${link}
|
|
1181
|
+
|
|
1182
|
+
\`${sig}\`
|
|
1183
|
+
|
|
1184
|
+
${fn.comments.text.join("\n")}
|
|
1185
|
+
|
|
1186
|
+
${source}
|
|
1187
|
+
|
|
1188
|
+
${params}`;
|
|
1189
|
+
}
|
|
1190
|
+
function mdParams(fn) {
|
|
1191
|
+
if (fn.abi.args.length === 0)
|
|
1192
|
+
return "";
|
|
1193
|
+
const hasDescription = Object.values(fn.comments.params).some((p) => p.comments.length > 0);
|
|
1194
|
+
const params = Object.values(fn.comments.params).map((p) => markdownParam(p, hasDescription));
|
|
1195
|
+
return `**Parameters:**
|
|
1196
|
+
|
|
1197
|
+
| Name | Type | ${hasDescription ? "Description |" : ""}
|
|
1198
|
+
| --- | --- | ${hasDescription ? "--- |" : ""}
|
|
1199
|
+
${params.join("\n")}`;
|
|
1200
|
+
}
|
|
1201
|
+
function markdownParam(param, withDescription) {
|
|
1202
|
+
const typeString = getTypeString(param.abi.type);
|
|
1203
|
+
const base = `| ${param.abi.name} | ${typeString} |`;
|
|
1204
|
+
if (!withDescription)
|
|
1205
|
+
return base;
|
|
1206
|
+
return `${base} ${param.comments.join(" ")} |`;
|
|
1207
|
+
}
|
|
1208
|
+
function markdownMap(map, contractFile) {
|
|
1209
|
+
const startLine = map.startLine + 1;
|
|
1210
|
+
let link = "";
|
|
1211
|
+
if (contractFile) {
|
|
1212
|
+
link = `[View in file](${contractFile}#L${startLine})`;
|
|
1213
|
+
}
|
|
1214
|
+
return `### ${map.abi.name}
|
|
1215
|
+
|
|
1216
|
+
${map.comments.text.join("\n")}
|
|
1217
|
+
|
|
1218
|
+
\`\`\`clarity
|
|
1219
|
+
${map.source.join("\n")}
|
|
1220
|
+
\`\`\`
|
|
1221
|
+
|
|
1222
|
+
${link}`;
|
|
1223
|
+
}
|
|
1224
|
+
function markdownVar(variable, contractFile) {
|
|
1225
|
+
const startLine = variable.startLine + 1;
|
|
1226
|
+
let link = "";
|
|
1227
|
+
if (contractFile) {
|
|
1228
|
+
link = `[View in file](${contractFile}#L${startLine})`;
|
|
1229
|
+
}
|
|
1230
|
+
const sig = variable.abi.access === "variable" ? getTypeString(variable.abi.type) : "";
|
|
1231
|
+
return `### ${variable.abi.name}
|
|
1232
|
+
|
|
1233
|
+
${sig}
|
|
1234
|
+
|
|
1235
|
+
${variable.comments.text.join("\n")}
|
|
1236
|
+
|
|
1237
|
+
\`\`\`clarity
|
|
1238
|
+
${variable.source.join("\n")}
|
|
1239
|
+
\`\`\`
|
|
1240
|
+
|
|
1241
|
+
${link}`;
|
|
1242
|
+
}
|
|
1243
|
+
function markdownTOC(contract) {
|
|
1244
|
+
const publics = contract.functions.filter((fn) => fn.abi.access === "public");
|
|
1245
|
+
const readOnly = contract.functions.filter((fn) => fn.abi.access === "read_only");
|
|
1246
|
+
const privates = contract.functions.filter((fn) => fn.abi.access === "private");
|
|
1247
|
+
const maps = contract.maps;
|
|
1248
|
+
const constants = contract.variables.filter((v) => v.abi.access === "constant");
|
|
1249
|
+
const vars = contract.variables.filter((v) => v.abi.access === "variable");
|
|
1250
|
+
function tocLine(fn) {
|
|
1251
|
+
const name = fn.abi.name;
|
|
1252
|
+
return `- [\`${name}\`](#${name.toLowerCase().replaceAll("?", "")})`;
|
|
1253
|
+
}
|
|
1254
|
+
return `**Public functions:**
|
|
1255
|
+
|
|
1256
|
+
${publics.map(tocLine).join("\n")}
|
|
1257
|
+
|
|
1258
|
+
**Read-only functions:**
|
|
1259
|
+
|
|
1260
|
+
${readOnly.map(tocLine).join("\n")}
|
|
1261
|
+
|
|
1262
|
+
**Private functions:**
|
|
1263
|
+
|
|
1264
|
+
${privates.map(tocLine).join("\n")}
|
|
1265
|
+
|
|
1266
|
+
**Maps**
|
|
1267
|
+
|
|
1268
|
+
${maps.map(tocLine).join("\n")}
|
|
1269
|
+
|
|
1270
|
+
**Variables**
|
|
1271
|
+
|
|
1272
|
+
${vars.map(tocLine).join("\n")}
|
|
1273
|
+
|
|
1274
|
+
**Constants**
|
|
1275
|
+
|
|
1276
|
+
${constants.map(tocLine).join("\n")}
|
|
1277
|
+
`;
|
|
1278
|
+
}
|
|
1279
|
+
function generateReadme(session, excluded) {
|
|
1280
|
+
const contractLines = [];
|
|
1281
|
+
sortContracts(session.contracts).forEach((contract) => {
|
|
1282
|
+
const name = getContractName6(contract.contract_id, false);
|
|
1283
|
+
if (excluded[name])
|
|
1284
|
+
return;
|
|
1285
|
+
const fileName = `${name}.md`;
|
|
1286
|
+
const line = `- [\`${name}\`](${fileName})`;
|
|
1287
|
+
contractLines.push(line);
|
|
1288
|
+
});
|
|
1289
|
+
const fileContents = `# Contracts
|
|
1290
|
+
|
|
1291
|
+
${contractLines.join("\n")}
|
|
1292
|
+
`;
|
|
1293
|
+
return fileContents;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// src/files/docs.ts
|
|
1297
|
+
async function generateDocs({
|
|
1298
|
+
session,
|
|
1299
|
+
config
|
|
1300
|
+
}) {
|
|
1301
|
+
const docs = config.configFile["docs" /* Docs */];
|
|
1302
|
+
const docsBase = docs == null ? void 0 : docs.output;
|
|
1303
|
+
if (!docsBase) {
|
|
1304
|
+
warnNoDocs();
|
|
1305
|
+
return;
|
|
1306
|
+
}
|
|
1307
|
+
const docsPathExt = extname(docsBase);
|
|
1308
|
+
if (docsPathExt) {
|
|
1309
|
+
log.warn(`Docs output path ('${docsBase}') looks like a file - it needs to be a directory.`);
|
|
1310
|
+
}
|
|
1311
|
+
const excluded = Object.fromEntries((docs.exclude || []).map((e) => {
|
|
1312
|
+
return [e, true];
|
|
1313
|
+
}));
|
|
1314
|
+
log.debug(`Generating docs at path \`${docsBase}\``);
|
|
1315
|
+
const docsBaseFolder = config.outputResolve("docs" /* Docs */, "./")[0];
|
|
1316
|
+
const paths = await Promise.all(session.contracts.map(async (contract) => {
|
|
1317
|
+
var _a, _b;
|
|
1318
|
+
const name = getContractName7(contract.contract_id, false);
|
|
1319
|
+
if (excluded[name])
|
|
1320
|
+
return null;
|
|
1321
|
+
const docFile = `${name}.md`;
|
|
1322
|
+
const contractPathDef = (_b = (_a = config.clarinet.contracts) == null ? void 0 : _a[name]) == null ? void 0 : _b.path;
|
|
1323
|
+
let contractFile;
|
|
1324
|
+
if (contractPathDef) {
|
|
1325
|
+
const contractPathFull = config.joinFromClarinet(contractPathDef);
|
|
1326
|
+
contractFile = relative5(docsBaseFolder, contractPathFull);
|
|
1327
|
+
} else {
|
|
1328
|
+
log.debug(`Couldn't find contract file from Clarinet.toml for contract ${name}`);
|
|
1329
|
+
}
|
|
1330
|
+
const md = generateMarkdown({ contract, contractFile });
|
|
1331
|
+
const path = await config.writeOutput("docs" /* Docs */, md, docFile);
|
|
1332
|
+
return path[0];
|
|
1333
|
+
}));
|
|
1334
|
+
const readme = generateReadme(session, excluded);
|
|
1335
|
+
paths.push((await config.writeOutput("docs" /* Docs */, readme, "README.md"))[0]);
|
|
1336
|
+
await afterDocs(config);
|
|
1337
|
+
}
|
|
1338
|
+
function warnNoDocs() {
|
|
1339
|
+
log.warn(`
|
|
1340
|
+
Clarigen config file doesn't include an output directory for docs.
|
|
1341
|
+
|
|
1342
|
+
To generate docs, specify 'docs.output' in your config file:
|
|
1343
|
+
|
|
1344
|
+
[docs]
|
|
1345
|
+
output = "docs/"
|
|
1346
|
+
`.trimEnd());
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// src/commands/docs-command.ts
|
|
1350
|
+
var DocsCommand = class extends BaseCommand {
|
|
1351
|
+
cwd = Option4.String({ required: false });
|
|
1352
|
+
async execute() {
|
|
1353
|
+
this.preexecute();
|
|
1354
|
+
const config = await Config.load(this.cwd);
|
|
1355
|
+
const session = await getSession(config);
|
|
1356
|
+
await generateDocs({
|
|
1357
|
+
session: __spreadProps(__spreadValues({}, session), {
|
|
1358
|
+
variables: []
|
|
1359
|
+
}),
|
|
1360
|
+
config
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
};
|
|
1364
|
+
__publicField(DocsCommand, "paths", [["docs"]]);
|
|
1365
|
+
__publicField(DocsCommand, "usage", BaseCommand.Usage({
|
|
1366
|
+
description: "Generate markdown documentation for your Clarity contracts"
|
|
1367
|
+
}));
|
|
1368
|
+
|
|
1369
|
+
// src/commands/init-config-command.ts
|
|
1370
|
+
import { Option as Option5 } from "clipanion";
|
|
1371
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
1372
|
+
|
|
1373
|
+
// src/generated/init-config.ts
|
|
1374
|
+
var tomlInit = `
|
|
1375
|
+
# Set to your project's Clarinet config file
|
|
1376
|
+
clarinet = "./Clarinet.toml"
|
|
1377
|
+
|
|
1378
|
+
# Set where you'd like TypeScript types output.
|
|
1379
|
+
# Comment or remove section to skip TypeScript types
|
|
1380
|
+
[types]
|
|
1381
|
+
# \`output\` should be a path to a single file
|
|
1382
|
+
output = "src/clarigen-types.ts"
|
|
1383
|
+
|
|
1384
|
+
# You can also specify multiple output paths:
|
|
1385
|
+
# outputs = [
|
|
1386
|
+
# "src/clarigen-types.ts",
|
|
1387
|
+
# "test/clarigen-types.ts"
|
|
1388
|
+
# ]
|
|
1389
|
+
|
|
1390
|
+
# \`types.after\` - script to run after TypeScript types are generated.
|
|
1391
|
+
# examples:
|
|
1392
|
+
# after = "npm run prettier -w ./src/clarigen-types.ts"
|
|
1393
|
+
# after = "echo 'yay'"
|
|
1394
|
+
|
|
1395
|
+
# Set where you'd like generated contract docs
|
|
1396
|
+
# Generate docs by running \`clarigen docs\`
|
|
1397
|
+
[docs]
|
|
1398
|
+
# \`output\` should be a folder
|
|
1399
|
+
output = "docs"
|
|
1400
|
+
|
|
1401
|
+
# \`docs.after\` - script to run after docs are generated.
|
|
1402
|
+
# examples:
|
|
1403
|
+
# after = "npm run prettier -w ./docs"
|
|
1404
|
+
`;
|
|
1405
|
+
|
|
1406
|
+
// src/commands/init-config-command.ts
|
|
1407
|
+
var InitConfigCommand = class extends BaseCommand {
|
|
1408
|
+
cwd = Option5.String({ required: false });
|
|
1409
|
+
overwrite = Option5.Boolean("--overwrite", false, {
|
|
1410
|
+
description: "Overwrite the configuration file if it already exists"
|
|
1411
|
+
});
|
|
1412
|
+
async execute() {
|
|
1413
|
+
this.preexecute();
|
|
1414
|
+
const path = configFilePath(this.cwd);
|
|
1415
|
+
const configExists = await fileExists(path);
|
|
1416
|
+
if (configExists && !this.overwrite) {
|
|
1417
|
+
logger.warn("Configuration file already exists. Use --overwrite to overwrite it.");
|
|
1418
|
+
return 1;
|
|
1419
|
+
}
|
|
1420
|
+
logger.debug(`Writing configuration file to ${path}`);
|
|
1421
|
+
await writeFile2(path, tomlInit, "utf-8");
|
|
1422
|
+
}
|
|
1423
|
+
};
|
|
1424
|
+
__publicField(InitConfigCommand, "paths", [["init-config"], ["init"]]);
|
|
1425
|
+
__publicField(InitConfigCommand, "usage", {
|
|
1426
|
+
description: "Initialize a Clarigen configuration file"
|
|
1427
|
+
});
|
|
1428
|
+
|
|
1429
|
+
// src/generated/version.ts
|
|
1430
|
+
var version = "2.0.1";
|
|
1431
|
+
|
|
1432
|
+
// src/run-cli.ts
|
|
1433
|
+
var [node, script, ...args] = process.argv;
|
|
1434
|
+
var cli = new Cli({
|
|
1435
|
+
binaryLabel: "Clarigen",
|
|
1436
|
+
binaryName: "clarigen",
|
|
1437
|
+
binaryVersion: version
|
|
1438
|
+
});
|
|
1439
|
+
cli.register(Builtins.HelpCommand);
|
|
1440
|
+
cli.register(Builtins.VersionCommand);
|
|
1441
|
+
cli.register(DefaultCommand);
|
|
1442
|
+
cli.register(DocsCommand);
|
|
1443
|
+
cli.register(InitConfigCommand);
|
|
1444
|
+
cli.register(SessionInfoCommand);
|
|
1445
|
+
async function run() {
|
|
1446
|
+
await cli.runExit(args, Cli.defaultContext);
|
|
1447
|
+
}
|
|
1448
|
+
process.on("SIGINT", () => {
|
|
1449
|
+
logger.info("Bye! \u{1F44B}");
|
|
1450
|
+
process.exit();
|
|
1451
|
+
});
|
|
1452
|
+
run().catch(console.error).finally(() => {
|
|
1453
|
+
process.exit();
|
|
1454
|
+
});
|
|
1455
|
+
//# sourceMappingURL=run-cli.js.map
|