@clarigen/cli 3.1.0 → 3.2.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/run-cli.cjs CHANGED
@@ -30,7 +30,7 @@ var import_clipanion6 = require("clipanion");
30
30
  var import_clipanion2 = require("clipanion");
31
31
 
32
32
  // src/config.ts
33
- var import_zod2 = require("zod");
33
+ var import_arktype2 = require("arktype");
34
34
 
35
35
  // src/logger.ts
36
36
  var import_pino = require("pino");
@@ -80,19 +80,27 @@ function sortContracts(contracts) {
80
80
  }
81
81
 
82
82
  // src/clarinet-config.ts
83
- var import_zod = require("zod");
83
+ var import_arktype = require("arktype");
84
84
  var import_promises2 = require("fs/promises");
85
85
  var import_toml = require("@iarna/toml");
86
- var ClarinetConfigSchema = import_zod.z.object({
87
- project: import_zod.z.object({
88
- requirements: import_zod.z.array(import_zod.z.object({ contract_id: import_zod.z.string() })).optional(),
89
- cache_location: import_zod.z.object({ path: import_zod.z.string() }).optional()
86
+ var ClarinetConfig = (0, import_arktype.type)({
87
+ project: (0, import_arktype.type)({
88
+ requirements: (0, import_arktype.type)({
89
+ contract_id: (0, import_arktype.type)("string").describe("Contract ID")
90
+ }).array().describe("Project requirements").optional(),
91
+ cache_location: (0, import_arktype.type)({
92
+ path: (0, import_arktype.type)("string").describe("Cache location path")
93
+ }).optional()
90
94
  }),
91
- contracts: import_zod.z.record(import_zod.z.string(), import_zod.z.object({ path: import_zod.z.string() })).optional()
95
+ contracts: (0, import_arktype.type)({
96
+ "[string]": (0, import_arktype.type)({
97
+ path: (0, import_arktype.type)("string").describe("Contract path")
98
+ })
99
+ }).optional()
92
100
  });
93
101
  async function getClarinetConfig(path) {
94
102
  const file = await (0, import_promises2.readFile)(path, "utf-8");
95
- const config = ClarinetConfigSchema.parse((0, import_toml.parse)(file));
103
+ const config = ClarinetConfig.assert((0, import_toml.parse)(file));
96
104
  return config;
97
105
  }
98
106
 
@@ -101,23 +109,23 @@ var import_path2 = require("path");
101
109
  var import_toml2 = require("@iarna/toml");
102
110
  var import_promises3 = require("fs/promises");
103
111
  var CONFIG_FILE = "Clarigen.toml";
104
- var typesSchema = import_zod2.z.object({
105
- output: import_zod2.z.string().optional(),
106
- outputs: import_zod2.z.array(import_zod2.z.string()).optional(),
107
- include_accounts: import_zod2.z.boolean().optional(),
108
- after: import_zod2.z.string().optional(),
109
- include_boot_contracts: import_zod2.z.boolean().optional(),
110
- watch_folders: import_zod2.z.array(import_zod2.z.string()).optional()
112
+ var typesSchema = (0, import_arktype2.type)({
113
+ "output?": (0, import_arktype2.type)("string").describe("Path to the output file"),
114
+ "outputs?": (0, import_arktype2.type)("string[]").describe("Paths to the output files"),
115
+ "include_accounts?": (0, import_arktype2.type)("boolean").describe("Include accounts in the output"),
116
+ "after?": (0, import_arktype2.type)("string").describe("Script to run after the output is generated"),
117
+ "include_boot_contracts?": (0, import_arktype2.type)("boolean").describe("Include boot contracts in the output"),
118
+ "watch_folders?": (0, import_arktype2.type)("string[]").describe("Folders to watch for changes")
111
119
  }).optional();
112
- var ConfigFileSchema = import_zod2.z.object({
113
- clarinet: import_zod2.z.string(),
120
+ var ConfigFile = (0, import_arktype2.type)({
121
+ clarinet: (0, import_arktype2.type)("string").describe("Path to the Clarinet config file"),
114
122
  ["types" /* ESM */]: typesSchema,
115
123
  ["esm" /* ESM_OLD */]: typesSchema,
116
- ["docs" /* Docs */]: import_zod2.z.object({
117
- output: import_zod2.z.string().optional(),
118
- outputs: import_zod2.z.array(import_zod2.z.string()).optional(),
119
- exclude: import_zod2.z.array(import_zod2.z.string()).optional(),
120
- after: import_zod2.z.string().optional()
124
+ ["docs" /* Docs */]: (0, import_arktype2.type)({
125
+ "output?": (0, import_arktype2.type)("string").describe("Path to docs output folder. Defaults to ./docs"),
126
+ "outputs?": (0, import_arktype2.type)("string[]").describe("Paths to docs output folders"),
127
+ "exclude?": (0, import_arktype2.type)("string[]").describe("Contracts to exclude from docs generation"),
128
+ "after?": (0, import_arktype2.type)("string").describe("Script to run after docs are generated")
121
129
  }).optional()
122
130
  });
123
131
  var defaultConfigFile = {
@@ -141,36 +149,36 @@ var Config = class {
141
149
  const clarinet = await getClarinetConfig((0, import_path2.resolve)(cwd ?? "", config.clarinet));
142
150
  return new this(config, clarinet, cwd);
143
151
  }
144
- getOutputs(type) {
152
+ getOutputs(type4) {
145
153
  var _a, _b;
146
- const singlePath = (_a = this.configFile[type]) == null ? void 0 : _a.output;
147
- const multiPath = ((_b = this.configFile[type]) == null ? void 0 : _b.outputs) || [];
154
+ const singlePath = (_a = this.configFile[type4]) == null ? void 0 : _a.output;
155
+ const multiPath = ((_b = this.configFile[type4]) == null ? void 0 : _b.outputs) || [];
148
156
  if (singlePath !== void 0) return [singlePath];
149
157
  return multiPath;
150
158
  }
151
- outputResolve(type, filePath) {
152
- const outputs = this.getOutputs(type);
153
- if (!this.supports(type)) return null;
159
+ outputResolve(type4, filePath) {
160
+ const outputs = this.getOutputs(type4);
161
+ if (!this.supports(type4)) return null;
154
162
  return outputs.map((path) => {
155
163
  return (0, import_path2.resolve)(this.cwd, path, filePath || "");
156
164
  });
157
165
  }
158
- async writeOutput(type, contents, filePath) {
159
- const paths = this.outputResolve(type, filePath);
166
+ async writeOutput(type4, contents, filePath) {
167
+ const paths = this.outputResolve(type4, filePath);
160
168
  if (paths === null) return null;
161
169
  await Promise.all(
162
170
  paths.map(async (path) => {
163
171
  await writeFile(path, contents);
164
- log.debug(`Generated ${type} file at ${(0, import_path2.relative)(this.cwd, path)}`);
172
+ log.debug(`Generated ${type4} file at ${(0, import_path2.relative)(this.cwd, path)}`);
165
173
  })
166
174
  );
167
175
  return paths;
168
176
  }
169
- supports(type) {
170
- return this.getOutputs(type).length > 0;
177
+ supports(type4) {
178
+ return this.getOutputs(type4).length > 0;
171
179
  }
172
- type(type) {
173
- return this.configFile[type];
180
+ type(type4) {
181
+ return this.configFile[type4];
174
182
  }
175
183
  get esm() {
176
184
  return this.configFile["types" /* ESM */];
@@ -196,16 +204,12 @@ async function getConfig(cwd) {
196
204
  if (await fileExists(path)) {
197
205
  const toml = await (0, import_promises3.readFile)(path, "utf-8");
198
206
  const parsedToml = (0, import_toml2.parse)(toml);
199
- const parseResult = ConfigFileSchema.safeParse(parsedToml);
200
- if (parseResult.success) {
201
- sessionConfig = parseResult.data;
202
- } else {
203
- logger.error("Error parsing Clarigen.toml:");
204
- parseResult.error.errors.forEach((e) => {
205
- logger.error(`${e.path.join(".")}: ${e.message}`);
206
- });
207
- throw new Error("Error parsing Clarigen.toml");
207
+ const parsed = ConfigFile(parsedToml);
208
+ if (parsed instanceof import_arktype2.type.errors) {
209
+ logger.error(`Error parsing Clarigen config: ${parsed.summary}`);
210
+ throw new Error(`Error parsing Clarigen config: ${parsed.summary}`);
208
211
  }
212
+ sessionConfig = parsed;
209
213
  } else {
210
214
  sessionConfig = defaultConfigFile;
211
215
  }
@@ -214,7 +218,7 @@ async function getConfig(cwd) {
214
218
 
215
219
  // src/commands/base-command.ts
216
220
  var import_clipanion = require("clipanion");
217
- var import_zod3 = require("zod");
221
+ var import_arktype3 = require("arktype");
218
222
  var BaseCommand = class extends import_clipanion.Command {
219
223
  verbose = import_clipanion.Option.Boolean("-v,--verbose", false, {
220
224
  description: "Enable verbose logging"
@@ -226,8 +230,8 @@ var BaseCommand = class extends import_clipanion.Command {
226
230
  }
227
231
  // eslint-disable-next-line @typescript-eslint/require-await
228
232
  async catch(error) {
229
- if (error instanceof import_zod3.ZodError) {
230
- logger.error(error.issues, "Your configuration file is invalid.");
233
+ if (error instanceof import_arktype3.type.errors) {
234
+ logger.error("Your configuration file is invalid.", error.summary);
231
235
  return;
232
236
  }
233
237
  logger.error(error);
@@ -296,9 +300,9 @@ var jsTypeFromAbiType = (val, isArgument = false) => {
296
300
  return `${innerType} | null`;
297
301
  } else if ((0, import_core2.isClarityAbiTuple)(val)) {
298
302
  const tupleDefs = [];
299
- val.tuple.forEach(({ name, type }) => {
303
+ val.tuple.forEach(({ name, type: type4 }) => {
300
304
  const camelName = (0, import_core3.toCamelCase)(name);
301
- const innerType = jsTypeFromAbiType(type, isArgument);
305
+ const innerType = jsTypeFromAbiType(type4, isArgument);
302
306
  tupleDefs.push(`"${camelName}": ${innerType};`);
303
307
  });
304
308
  return `{
@@ -498,9 +502,9 @@ export const simnet = {
498
502
  function encodeVariables(variables) {
499
503
  return variables.map((v) => {
500
504
  let varLine = `${encodeVariableName(v.name)}: `;
501
- const type = jsTypeFromAbiType(v.type);
505
+ const type4 = jsTypeFromAbiType(v.type);
502
506
  const varJSON = serialize(v);
503
- varLine += `${varJSON} as TypedAbiVariable<${type}>`;
507
+ varLine += `${varJSON} as TypedAbiVariable<${type4}>`;
504
508
  return varLine;
505
509
  });
506
510
  }
@@ -537,6 +541,20 @@ function serializeArray(key, lines) {
537
541
  }
538
542
 
539
543
  // src/files/variables.ts
544
+ function clarityVersionForContract(contract) {
545
+ switch (contract.contract_interface.clarity_version) {
546
+ case "Clarity1":
547
+ return 1;
548
+ case "Clarity2":
549
+ return 2;
550
+ case "Clarity3":
551
+ return 3;
552
+ case "Clarity4":
553
+ return 4;
554
+ default:
555
+ return 3;
556
+ }
557
+ }
540
558
  function getVariablesV2(contract, simnet, verbose) {
541
559
  const [deployer] = contract.contract_id.split(".");
542
560
  const fakeId = `${(0, import_core6.getContractName)(contract.contract_id)}-vars`;
@@ -572,7 +590,7 @@ ${varFn}`;
572
590
  fakeId,
573
591
  fullSrc,
574
592
  {
575
- clarityVersion: 3
593
+ clarityVersion: clarityVersionForContract(contract)
576
594
  },
577
595
  deployer
578
596
  );
@@ -638,7 +656,11 @@ async function getSession(config) {
638
656
  }
639
657
  return {
640
658
  contract_id,
641
- contract_interface,
659
+ contract_interface: {
660
+ ...contract_interface,
661
+ epoch: contract_interface.epoch,
662
+ clarity_version: contract_interface.clarity_version
663
+ },
642
664
  source: source ?? ""
643
665
  };
644
666
  })
@@ -871,7 +893,7 @@ async function afterESM(config) {
871
893
 
872
894
  // src/commands/default-command.ts
873
895
  var import_chokidar = __toESM(require("chokidar"), 1);
874
- var import_path4 = require("path");
896
+ var import_node_path = require("path");
875
897
  async function generate(config) {
876
898
  const session = await getSession(config);
877
899
  const baseFile = generateBaseFile(session);
@@ -897,9 +919,9 @@ async function watch(config, cwd) {
897
919
  } catch (error) {
898
920
  logger.error({ error }, "Error generating types");
899
921
  }
900
- const clarinetFolder = (0, import_path4.dirname)(config.clarinetFile());
901
- const contractsFolder = (0, import_path4.join)(clarinetFolder, "/contracts/**/*.clar");
902
- const relativeFolder = (0, import_path4.relative)(cwd || process.cwd(), contractsFolder);
922
+ const clarinetFolder = (0, import_node_path.dirname)(config.clarinetFile());
923
+ const contractsFolder = (0, import_node_path.join)(clarinetFolder, "/contracts/**/*.clar");
924
+ const relativeFolder = (0, import_node_path.relative)(cwd || process.cwd(), contractsFolder);
903
925
  const watchFolders = ((_a = config.esm) == null ? void 0 : _a.watch_folders) ?? [];
904
926
  watchFolders.push(relativeFolder);
905
927
  logger.info(`Watching for changes in ${watchFolders}`);
@@ -963,7 +985,7 @@ var import_clipanion4 = require("clipanion");
963
985
 
964
986
  // src/files/docs.ts
965
987
  var import_core10 = require("@clarigen/core");
966
- var import_path6 = require("path");
988
+ var import_path5 = require("path");
967
989
 
968
990
  // src/docs/markdown.ts
969
991
  var import_core9 = require("@clarigen/core");
@@ -1044,8 +1066,8 @@ function clarityNameMatcher(line) {
1044
1066
  return /[\w|\-|\?|\!]+/.exec(line);
1045
1067
  }
1046
1068
  function findItemNameFromLine(line) {
1047
- const fnType = FN_TYPES.find((type) => {
1048
- return line.startsWith(`(define-${type}`);
1069
+ const fnType = FN_TYPES.find((type4) => {
1070
+ return line.startsWith(`(define-${type4}`);
1049
1071
  });
1050
1072
  if (fnType) {
1051
1073
  const prefix = `(define-${fnType} (`;
@@ -1058,13 +1080,13 @@ function findItemNameFromLine(line) {
1058
1080
  }
1059
1081
  return match[0];
1060
1082
  }
1061
- for (const type of VAR_TYPES) {
1062
- const prefix = `(define-${type} `;
1083
+ for (const type4 of VAR_TYPES) {
1084
+ const prefix = `(define-${type4} `;
1063
1085
  if (!line.startsWith(prefix)) continue;
1064
1086
  const startString = line.slice(prefix.length);
1065
1087
  const match = clarityNameMatcher(startString);
1066
1088
  if (!match) {
1067
- console.debug(`[claridocs]: Unable to determine ${type} name from line:
1089
+ console.debug(`[claridocs]: Unable to determine ${type4} name from line:
1068
1090
  \`${line}\``);
1069
1091
  return;
1070
1092
  }
@@ -1159,7 +1181,7 @@ async function afterDocs(config) {
1159
1181
  }
1160
1182
 
1161
1183
  // src/docs/markdown.ts
1162
- var import_path5 = require("path");
1184
+ var import_path4 = require("path");
1163
1185
  function generateMarkdown({
1164
1186
  contract,
1165
1187
  contractFile,
@@ -1176,7 +1198,7 @@ function generateMarkdown({
1176
1198
  const constants = doc.variables.filter((v) => v.abi.access === "constant").map((v) => markdownVar(v, contractFile));
1177
1199
  let fileLine = "";
1178
1200
  if (contractFile) {
1179
- const fileName = (0, import_path5.basename)(contractFile);
1201
+ const fileName = (0, import_path4.basename)(contractFile);
1180
1202
  fileLine = `
1181
1203
  [\`${fileName}\`](${contractFile})`;
1182
1204
  }
@@ -1336,8 +1358,8 @@ function generateReadme(session, excluded) {
1336
1358
  contractLines.push(line);
1337
1359
  });
1338
1360
  const fileContents = `# Contracts
1339
-
1340
- ${contractLines.join("\n")}
1361
+
1362
+ ${contractLines.join("\n")}
1341
1363
  `;
1342
1364
  return fileContents;
1343
1365
  }
@@ -1353,7 +1375,7 @@ async function generateDocs({
1353
1375
  warnNoDocs();
1354
1376
  return;
1355
1377
  }
1356
- const docsPathExt = (0, import_path6.extname)(docsBase);
1378
+ const docsPathExt = (0, import_path5.extname)(docsBase);
1357
1379
  if (docsPathExt) {
1358
1380
  log.warn(`Docs output path ('${docsBase}') looks like a file - it needs to be a directory.`);
1359
1381
  }
@@ -1374,7 +1396,7 @@ async function generateDocs({
1374
1396
  let contractFile;
1375
1397
  if (contractPathDef) {
1376
1398
  const contractPathFull = config.joinFromClarinet(contractPathDef);
1377
- contractFile = (0, import_path6.relative)(docsBaseFolder, contractPathFull);
1399
+ contractFile = (0, import_path5.relative)(docsBaseFolder, contractPathFull);
1378
1400
  } else {
1379
1401
  log.debug(`Couldn't find contract file from Clarinet.toml for contract ${name}`);
1380
1402
  }
@@ -1401,23 +1423,81 @@ output = "docs/"
1401
1423
  }
1402
1424
 
1403
1425
  // src/commands/docs-command.ts
1426
+ var import_node_path2 = require("path");
1427
+ var import_chokidar2 = __toESM(require("chokidar"), 1);
1428
+ async function watch2(config, cwd) {
1429
+ return new Promise(async (resolve3, reject) => {
1430
+ var _a;
1431
+ const session = await getSession(config);
1432
+ try {
1433
+ await generateDocs({
1434
+ session,
1435
+ config
1436
+ });
1437
+ } catch (error) {
1438
+ logger.error({ error }, "Error generating types");
1439
+ }
1440
+ const clarinetFolder = (0, import_node_path2.dirname)(config.clarinetFile());
1441
+ const contractsFolder = (0, import_node_path2.join)(clarinetFolder, "/contracts/**/*.clar");
1442
+ const relativeFolder = (0, import_node_path2.relative)(cwd || process.cwd(), contractsFolder);
1443
+ const watchFolders = ((_a = config.esm) == null ? void 0 : _a.watch_folders) ?? [];
1444
+ watchFolders.push(relativeFolder);
1445
+ logger.info(`Watching for changes in ${watchFolders}`);
1446
+ const watcher = import_chokidar2.default.watch(watchFolders, { persistent: true, cwd: clarinetFolder });
1447
+ let running = false;
1448
+ let start = 0;
1449
+ const isVerbose = logger.level !== "info";
1450
+ watcher.on("change", async (path) => {
1451
+ if (!running) {
1452
+ start = Date.now();
1453
+ logger.info(`File ${path} has been changed. Generating types.`);
1454
+ running = true;
1455
+ const session2 = await getSession(config);
1456
+ void generateDocs({
1457
+ session: session2,
1458
+ config
1459
+ }).catch((e) => {
1460
+ logger.error({ error: e }, "Error generating types");
1461
+ }).then(() => {
1462
+ setTimeout(() => {
1463
+ process.stdout.moveCursor(0, -1);
1464
+ process.stdout.clearLine(1);
1465
+ const elapsed = Date.now() - start;
1466
+ logger.info(
1467
+ `Docs generated (${(elapsed / 1e3).toFixed(2)}s). Watching for changes...`
1468
+ );
1469
+ running = false;
1470
+ });
1471
+ });
1472
+ }
1473
+ });
1474
+ });
1475
+ }
1404
1476
  var DocsCommand = class extends BaseCommand {
1405
1477
  static paths = [["docs"]];
1406
1478
  static usage = BaseCommand.Usage({
1407
1479
  description: "Generate markdown documentation for your Clarity contracts"
1408
1480
  });
1409
1481
  cwd = import_clipanion4.Option.String({ required: false });
1482
+ watch = import_clipanion4.Option.Boolean("-w,--watch", {
1483
+ description: "Watch for changes and regenerate docs",
1484
+ required: false
1485
+ });
1410
1486
  async execute() {
1411
1487
  this.preexecute();
1412
1488
  const config = await Config.load(this.cwd);
1413
- const session = await getSession(config);
1414
- await generateDocs({
1415
- session: {
1416
- ...session,
1417
- variables: []
1418
- },
1419
- config
1420
- });
1489
+ if (this.watch) {
1490
+ await watch2(config, this.cwd);
1491
+ } else {
1492
+ const session = await getSession(config);
1493
+ await generateDocs({
1494
+ session: {
1495
+ ...session,
1496
+ variables: []
1497
+ },
1498
+ config
1499
+ });
1500
+ }
1421
1501
  }
1422
1502
  };
1423
1503
 
@@ -1482,7 +1562,7 @@ var InitConfigCommand = class extends BaseCommand {
1482
1562
  };
1483
1563
 
1484
1564
  // src/generated/version.ts
1485
- var version = "3.1.0";
1565
+ var version = "3.2.0";
1486
1566
 
1487
1567
  // src/run-cli.ts
1488
1568
  var [node, script, ...args] = process.argv;