@latticexyz/cli 2.0.0-alpha.37 → 2.0.0-alpha.39

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/mud.js CHANGED
@@ -11264,9 +11264,9 @@ var commandModule11 = {
11264
11264
  compare: { type: "string", desc: "Compare to an existing gas report" }
11265
11265
  });
11266
11266
  },
11267
- async handler({ path: path8, save, compare: compare2 }) {
11267
+ async handler({ path: path9, save, compare: compare2 }) {
11268
11268
  let gasReport = [];
11269
- for (const file of path8) {
11269
+ for (const file of path9) {
11270
11270
  gasReport = gasReport.concat(await runGasReport(file));
11271
11271
  }
11272
11272
  const compareGasReport = [];
@@ -11298,14 +11298,14 @@ var commandModule11 = {
11298
11298
  }
11299
11299
  };
11300
11300
  var gas_report_default = commandModule11;
11301
- async function runGasReport(path8) {
11302
- if (!path8.endsWith(".t.sol")) {
11303
- console.log("Skipping gas report for", chalk3.bold(path8), "(not a test file)");
11301
+ async function runGasReport(path9) {
11302
+ if (!path9.endsWith(".t.sol")) {
11303
+ console.log("Skipping gas report for", chalk3.bold(path9), "(not a test file)");
11304
11304
  return [];
11305
11305
  }
11306
- console.log("Running gas report for", chalk3.bold(path8));
11306
+ console.log("Running gas report for", chalk3.bold(path9));
11307
11307
  const gasReport = [];
11308
- const fileContents = readFileSync2(path8, "utf8");
11308
+ const fileContents = readFileSync2(path9, "utf8");
11309
11309
  let newFile = fileContents;
11310
11310
  const functionRegex = new RegExp(/function (.*){/g);
11311
11311
  let functionMatch;
@@ -11329,7 +11329,7 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
11329
11329
  );
11330
11330
  }
11331
11331
  newFile = newFile.replace(/pure/g, "view");
11332
- const tempFileName = path8.replace(/\.t\.sol$/, "MudGasReport.t.sol");
11332
+ const tempFileName = path9.replace(/\.t\.sol$/, "MudGasReport.t.sol");
11333
11333
  writeFileSync(tempFileName, newFile);
11334
11334
  const child = execa2("forge", ["test", "--match-path", tempFileName, "-vvv"], {
11335
11335
  stdio: ["inherit", "pipe", "inherit"]
@@ -11350,7 +11350,7 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
11350
11350
  const name = gasReportMatch[1];
11351
11351
  const functionCall = gasReportMatch[2].replace(";", "");
11352
11352
  const gasUsed = gasReportMatch[3];
11353
- gasReport.push({ source: path8, name, functionCall, gasUsed: parseInt(gasUsed) });
11353
+ gasReport.push({ source: path9, name, functionCall, gasUsed: parseInt(gasUsed) });
11354
11354
  }
11355
11355
  return gasReport;
11356
11356
  }
@@ -11374,10 +11374,10 @@ function printGasReport(gasReport, compare2) {
11374
11374
  const rows = [headers, ...values];
11375
11375
  console.log(table(rows, { border: getBorderCharacters("norc") }));
11376
11376
  }
11377
- function saveGasReport(gasReport, path8) {
11378
- console.log(chalk3.bold(`Saving gas report to ${path8}`));
11377
+ function saveGasReport(gasReport, path9) {
11378
+ console.log(chalk3.bold(`Saving gas report to ${path9}`));
11379
11379
  const serializedGasReport = gasReport.map((entry) => `(${entry.source}) | ${entry.name} [${entry.functionCall}]: ${entry.gasUsed}`).join("\n");
11380
- writeFileSync(path8, serializedGasReport);
11380
+ writeFileSync(path9, serializedGasReport);
11381
11381
  }
11382
11382
 
11383
11383
  // src/commands/hello.ts
@@ -11483,7 +11483,7 @@ var commandModule15 = {
11483
11483
  await forge(["clean"], { profile });
11484
11484
  await forge(["build"], { profile });
11485
11485
  const srcDir = await getSrcDirectory();
11486
- const existingContracts = glob.sync(`${srcDir}/**/*.sol`).map((path8) => basename(path8, ".sol"));
11486
+ const existingContracts = glob.sync(`${srcDir}/**/*.sol`).map((path9) => basename(path9, ".sol"));
11487
11487
  const worldConfig = await loadWorldConfig(configPath, existingContracts);
11488
11488
  const storeConfig = await loadStoreConfig(configPath);
11489
11489
  const mudConfig = { ...worldConfig, ...storeConfig };
@@ -11724,9 +11724,9 @@ var commandModule16 = {
11724
11724
  async handler(args) {
11725
11725
  const { configPath, clean } = args;
11726
11726
  const srcDir = await getSrcDirectory();
11727
- const existingContracts = glob2.sync(`${srcDir}/**/*.sol`).map((path8) => ({
11728
- path: path8,
11729
- basename: basename2(path8, ".sol")
11727
+ const existingContracts = glob2.sync(`${srcDir}/**/*.sol`).map((path9) => ({
11728
+ path: path9,
11729
+ basename: basename2(path9, ".sol")
11730
11730
  }));
11731
11731
  const worldConfig = await loadWorldConfig(
11732
11732
  configPath,
@@ -11742,6 +11742,203 @@ var commandModule16 = {
11742
11742
  };
11743
11743
  var worldgen_default = commandModule16;
11744
11744
 
11745
+ // src/commands/set-version.ts
11746
+ import chalk5 from "chalk";
11747
+ import { existsSync, readFileSync as readFileSync4, rmSync as rmSync4, writeFileSync as writeFileSync3 } from "fs";
11748
+ import path8 from "path";
11749
+
11750
+ // package.json
11751
+ var package_default = {
11752
+ name: "@latticexyz/cli",
11753
+ version: "2.0.0-alpha.39+9af097de",
11754
+ description: "Command line interface for mud",
11755
+ main: "dist/index.js",
11756
+ types: "dist/index.d.ts",
11757
+ type: "module",
11758
+ license: "MIT",
11759
+ bin: {
11760
+ mud: "./dist/mud.js"
11761
+ },
11762
+ repository: {
11763
+ type: "git",
11764
+ url: "https://github.com/latticexyz/mud.git",
11765
+ directory: "packages/cli"
11766
+ },
11767
+ scripts: {
11768
+ prepare: "yarn build && chmod u+x git-install.sh",
11769
+ codegen: "ts-node --esm --files ./scripts/codegen.ts",
11770
+ lint: "eslint . --ext .ts",
11771
+ dev: "tsup --watch",
11772
+ build: "tsup",
11773
+ link: "yarn link",
11774
+ test: "vitest typecheck --run && yarn test:contracts",
11775
+ "test:contracts": "yarn codegen && forge test",
11776
+ "git:install": "bash git-install.sh",
11777
+ release: "npm publish --access=public"
11778
+ },
11779
+ devDependencies: {
11780
+ "@latticexyz/store": "^2.0.0-alpha.39+9af097de",
11781
+ "@types/ejs": "^3.1.1",
11782
+ "@types/glob": "^7.2.0",
11783
+ "@types/node": "^17.0.34",
11784
+ "@types/openurl": "^1.0.0",
11785
+ "@types/yargs": "^17.0.10",
11786
+ esbuild: "^0.15.16",
11787
+ tsup: "^6.6.3",
11788
+ vitest: "^0.29.8"
11789
+ },
11790
+ dependencies: {
11791
+ "@improbable-eng/grpc-web": "^0.15.0",
11792
+ "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
11793
+ "@latticexyz/schema-type": "^2.0.0-alpha.39+9af097de",
11794
+ "@latticexyz/services": "^2.0.0-alpha.39+9af097de",
11795
+ "@latticexyz/solecs": "^2.0.0-alpha.39+9af097de",
11796
+ "@latticexyz/std-contracts": "^2.0.0-alpha.39+9af097de",
11797
+ "@solidity-parser/parser": "^0.16.0",
11798
+ "@typechain/ethers-v5": "^10.1.1",
11799
+ chalk: "^5.0.1",
11800
+ chokidar: "^3.5.3",
11801
+ dotenv: "^16.0.3",
11802
+ "ds-test": "https://github.com/dapphub/ds-test.git#c9ce3f25bde29fc5eb9901842bf02850dfd2d084",
11803
+ ejs: "^3.1.8",
11804
+ ethers: "^5.7.2",
11805
+ execa: "^7.0.0",
11806
+ "find-up": "^6.3.0",
11807
+ "forge-std": "https://github.com/foundry-rs/forge-std.git#b4f121555729b3afb3c5ffccb62ff4b6e2818fd3",
11808
+ glob: "^8.0.3",
11809
+ "nice-grpc-web": "^2.0.1",
11810
+ openurl: "^1.1.1",
11811
+ path: "^0.12.7",
11812
+ prettier: "^2.8.4",
11813
+ "prettier-plugin-solidity": "^1.1.2",
11814
+ solmate: "https://github.com/Rari-Capital/solmate.git#9cf1428245074e39090dceacb0c28b1f684f584c",
11815
+ table: "^6.8.1",
11816
+ "ts-node": "^10.9.1",
11817
+ typechain: "^8.1.1",
11818
+ typescript: "^4.9.5",
11819
+ yargs: "^17.7.1",
11820
+ zod: "^3.21.4",
11821
+ "zod-validation-error": "^1.0.1"
11822
+ },
11823
+ gitHead: "9af097de7914d0c43b7d65ca6271260439bc6bc4"
11824
+ };
11825
+
11826
+ // src/commands/set-version.ts
11827
+ var BACKUP_FILE = ".mudbackup";
11828
+ var MUD_PREFIX = "@latticexyz";
11829
+ var commandModule17 = {
11830
+ command: "set-version",
11831
+ describe: "Install a custom MUD version and optionally backup the previously installed version",
11832
+ builder(yargs2) {
11833
+ return yargs2.options({
11834
+ backup: { type: "boolean", description: `Back up the current MUD versions to "${BACKUP_FILE}"` },
11835
+ force: {
11836
+ type: "boolean",
11837
+ description: `Backup fails if a "${BACKUP_FILE}" file is found, unless --force is provided`
11838
+ },
11839
+ restore: { type: "boolean", description: `Restore the previous MUD versions from "${BACKUP_FILE}"` },
11840
+ mudVersion: { alias: "v", type: "string", description: "The MUD version to install" }
11841
+ });
11842
+ },
11843
+ async handler(options) {
11844
+ try {
11845
+ if (!options.mudVersion && !options.restore) {
11846
+ throw new MUDError(`Version parameter is required unless --restore is provided.`);
11847
+ }
11848
+ options.mudVersion = options.mudVersion === "canary" ? await getCanaryVersion(package_default.name) : options.mudVersion;
11849
+ const rootPath = "./package.json";
11850
+ const { workspaces } = updatePackageJson(rootPath, options);
11851
+ if (workspaces) {
11852
+ for (const workspace of workspaces) {
11853
+ const filePath = path8.join(workspace, "/package.json");
11854
+ updatePackageJson(filePath, options);
11855
+ }
11856
+ }
11857
+ } catch (e) {
11858
+ logError(e);
11859
+ } finally {
11860
+ process.exit(0);
11861
+ }
11862
+ }
11863
+ };
11864
+ function updatePackageJson(filePath, options) {
11865
+ const { backup, restore, force, mudVersion } = options;
11866
+ const backupFilePath = path8.join(path8.dirname(filePath), BACKUP_FILE);
11867
+ if (backup && !force && existsSync(backupFilePath)) {
11868
+ throw new MUDError(
11869
+ `A backup file already exists at ${backupFilePath}.
11870
+ Use --force to overwrite it or --restore to restore it.`
11871
+ );
11872
+ }
11873
+ const packageJson = readPackageJson(filePath);
11874
+ const backupJson = restore ? readPackageJson(backupFilePath) : void 0;
11875
+ const mudDependencies = {};
11876
+ for (const key in packageJson.dependencies) {
11877
+ if (key.startsWith(MUD_PREFIX)) {
11878
+ mudDependencies[key] = packageJson.dependencies[key];
11879
+ }
11880
+ }
11881
+ const mudDevDependencies = {};
11882
+ for (const key in packageJson.devDependencies) {
11883
+ if (key.startsWith(MUD_PREFIX)) {
11884
+ mudDevDependencies[key] = packageJson.devDependencies[key];
11885
+ }
11886
+ }
11887
+ if (backup) {
11888
+ writeFileSync3(
11889
+ backupFilePath,
11890
+ JSON.stringify({ dependencies: mudDependencies, devDependencies: mudDevDependencies }, null, 2)
11891
+ );
11892
+ console.log(chalk5.green(`Backed up MUD dependencies from ${filePath} to ${backupFilePath}`));
11893
+ }
11894
+ for (const key in packageJson.dependencies) {
11895
+ if (key.startsWith(MUD_PREFIX)) {
11896
+ packageJson.dependencies[key] = restore && backupJson ? backupJson.dependencies[key] : mudVersion || packageJson.dependencies[key];
11897
+ }
11898
+ }
11899
+ for (const key in packageJson.devDependencies) {
11900
+ if (key.startsWith(MUD_PREFIX)) {
11901
+ packageJson.devDependencies[key] = restore && backupJson ? backupJson.devDependencies[key] : mudVersion || packageJson.devDependencies[key];
11902
+ }
11903
+ }
11904
+ writeFileSync3(filePath, JSON.stringify(packageJson, null, 2) + "\n");
11905
+ console.log(`Updating ${filePath}`);
11906
+ logComparison(mudDependencies, packageJson.dependencies);
11907
+ logComparison(mudDevDependencies, packageJson.devDependencies);
11908
+ if (restore && !backup) {
11909
+ rmSync4(backupFilePath);
11910
+ console.log(chalk5.green(`Cleaned up ${backupFilePath}`));
11911
+ }
11912
+ return packageJson;
11913
+ }
11914
+ function readPackageJson(path9) {
11915
+ try {
11916
+ const jsonString = readFileSync4(path9, "utf8");
11917
+ return JSON.parse(jsonString);
11918
+ } catch {
11919
+ throw new MUDError("Could not read JSON at " + path9);
11920
+ }
11921
+ }
11922
+ async function getCanaryVersion(pkg) {
11923
+ try {
11924
+ console.log(chalk5.blue("fetching MUD canary version..."));
11925
+ const result = await (await fetch(`https://registry.npmjs.org/${pkg}`)).json();
11926
+ const canary = result["dist-tags"].canary;
11927
+ console.log(chalk5.green("MUD canary version:", canary));
11928
+ return canary;
11929
+ } catch (e) {
11930
+ throw new MUDError(`Could not fetch canary version of ${pkg}`);
11931
+ }
11932
+ }
11933
+ function logComparison(prev, curr) {
11934
+ for (const key in prev) {
11935
+ if (prev[key] !== curr[key]) {
11936
+ console.log(`${key}: ${chalk5.red(prev[key])} -> ${chalk5.green(curr[key])}`);
11937
+ }
11938
+ }
11939
+ }
11940
+ var set_version_default = commandModule17;
11941
+
11745
11942
  // src/commands/index.ts
11746
11943
  var commands = [
11747
11944
  bulkupload_default,
@@ -11759,7 +11956,8 @@ var commands = [
11759
11956
  test_default,
11760
11957
  trace_default,
11761
11958
  types_default,
11762
- worldgen_default
11959
+ worldgen_default,
11960
+ set_version_default
11763
11961
  ];
11764
11962
 
11765
11963
  // src/mud.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latticexyz/cli",
3
- "version": "2.0.0-alpha.37+dd1efa6a",
3
+ "version": "2.0.0-alpha.39+9af097de",
4
4
  "description": "Command line interface for mud",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,7 +27,7 @@
27
27
  "release": "npm publish --access=public"
28
28
  },
29
29
  "devDependencies": {
30
- "@latticexyz/store": "^2.0.0-alpha.37+dd1efa6a",
30
+ "@latticexyz/store": "^2.0.0-alpha.39+9af097de",
31
31
  "@types/ejs": "^3.1.1",
32
32
  "@types/glob": "^7.2.0",
33
33
  "@types/node": "^17.0.34",
@@ -40,10 +40,10 @@
40
40
  "dependencies": {
41
41
  "@improbable-eng/grpc-web": "^0.15.0",
42
42
  "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
43
- "@latticexyz/schema-type": "^2.0.0-alpha.37+dd1efa6a",
44
- "@latticexyz/services": "^2.0.0-alpha.37+dd1efa6a",
45
- "@latticexyz/solecs": "^2.0.0-alpha.37+dd1efa6a",
46
- "@latticexyz/std-contracts": "^2.0.0-alpha.37+dd1efa6a",
43
+ "@latticexyz/schema-type": "^2.0.0-alpha.39+9af097de",
44
+ "@latticexyz/services": "^2.0.0-alpha.39+9af097de",
45
+ "@latticexyz/solecs": "^2.0.0-alpha.39+9af097de",
46
+ "@latticexyz/std-contracts": "^2.0.0-alpha.39+9af097de",
47
47
  "@solidity-parser/parser": "^0.16.0",
48
48
  "@typechain/ethers-v5": "^10.1.1",
49
49
  "chalk": "^5.0.1",
@@ -70,5 +70,5 @@
70
70
  "zod": "^3.21.4",
71
71
  "zod-validation-error": "^1.0.1"
72
72
  },
73
- "gitHead": "dd1efa6a1ebd2b3c62080d1b191633d7b0072916"
73
+ "gitHead": "9af097de7914d0c43b7d65ca6271260439bc6bc4"
74
74
  }
@@ -17,6 +17,7 @@ import tablegen from "./tablegen.js";
17
17
  import tsgen from "./tsgen.js";
18
18
  import deployV2 from "./deploy-v2.js";
19
19
  import worldgen from "./worldgen.js";
20
+ import setVersion from "./set-version.js";
20
21
 
21
22
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
22
23
  export const commands: CommandModule<any, any>[] = [
@@ -36,4 +37,5 @@ export const commands: CommandModule<any, any>[] = [
36
37
  trace,
37
38
  types,
38
39
  worldgen,
40
+ setVersion,
39
41
  ];
@@ -0,0 +1,171 @@
1
+ import chalk from "chalk";
2
+ import { existsSync, readFileSync, rmSync, writeFileSync } from "fs";
3
+ import path from "path";
4
+ import type { CommandModule } from "yargs";
5
+ import { logError, MUDError } from "../utils/errors.js";
6
+ import localPackageJson from "../../package.json";
7
+
8
+ type Options = {
9
+ backup?: boolean;
10
+ force?: boolean;
11
+ restore?: boolean;
12
+ mudVersion?: string;
13
+ };
14
+
15
+ const BACKUP_FILE = ".mudbackup";
16
+ const MUD_PREFIX = "@latticexyz";
17
+
18
+ const commandModule: CommandModule<Options, Options> = {
19
+ command: "set-version",
20
+
21
+ describe: "Install a custom MUD version and optionally backup the previously installed version",
22
+
23
+ builder(yargs) {
24
+ return yargs.options({
25
+ backup: { type: "boolean", description: `Back up the current MUD versions to "${BACKUP_FILE}"` },
26
+ force: {
27
+ type: "boolean",
28
+ description: `Backup fails if a "${BACKUP_FILE}" file is found, unless --force is provided`,
29
+ },
30
+ restore: { type: "boolean", description: `Restore the previous MUD versions from "${BACKUP_FILE}"` },
31
+ mudVersion: { alias: "v", type: "string", description: "The MUD version to install" },
32
+ });
33
+ },
34
+
35
+ async handler(options) {
36
+ try {
37
+ if (!options.mudVersion && !options.restore) {
38
+ throw new MUDError(`Version parameter is required unless --restore is provided.`);
39
+ }
40
+
41
+ // Resolve the `canary` version number if needed
42
+ options.mudVersion =
43
+ options.mudVersion === "canary" ? await getCanaryVersion(localPackageJson.name) : options.mudVersion;
44
+
45
+ // Read the current package.json
46
+ const rootPath = "./package.json";
47
+ const { workspaces } = updatePackageJson(rootPath, options);
48
+
49
+ // Load the package.json of each workspace
50
+ if (workspaces) {
51
+ for (const workspace of workspaces) {
52
+ const filePath = path.join(workspace, "/package.json");
53
+ updatePackageJson(filePath, options);
54
+ }
55
+ }
56
+ } catch (e) {
57
+ logError(e);
58
+ } finally {
59
+ process.exit(0);
60
+ }
61
+ },
62
+ };
63
+
64
+ function updatePackageJson(filePath: string, options: Options): { workspaces?: string[] } {
65
+ const { backup, restore, force, mudVersion } = options;
66
+ const backupFilePath = path.join(path.dirname(filePath), BACKUP_FILE);
67
+
68
+ // If `backup` is true and force not set, check if a backup file already exists and throw an error if it does
69
+ if (backup && !force && existsSync(backupFilePath)) {
70
+ throw new MUDError(
71
+ `A backup file already exists at ${backupFilePath}.\nUse --force to overwrite it or --restore to restore it.`
72
+ );
73
+ }
74
+
75
+ const packageJson = readPackageJson(filePath);
76
+
77
+ // Load .mudbackup if `restore` is true
78
+ const backupJson = restore ? readPackageJson(backupFilePath) : undefined;
79
+
80
+ // Find all MUD dependencies
81
+ const mudDependencies: Record<string, string> = {};
82
+ for (const key in packageJson.dependencies) {
83
+ if (key.startsWith(MUD_PREFIX)) {
84
+ mudDependencies[key] = packageJson.dependencies[key];
85
+ }
86
+ }
87
+
88
+ // Find all MUD devDependencies
89
+ const mudDevDependencies: Record<string, string> = {};
90
+ for (const key in packageJson.devDependencies) {
91
+ if (key.startsWith(MUD_PREFIX)) {
92
+ mudDevDependencies[key] = packageJson.devDependencies[key];
93
+ }
94
+ }
95
+
96
+ // Back up the current dependencies if `backup` is true
97
+ if (backup) {
98
+ writeFileSync(
99
+ backupFilePath,
100
+ JSON.stringify({ dependencies: mudDependencies, devDependencies: mudDevDependencies }, null, 2)
101
+ );
102
+ console.log(chalk.green(`Backed up MUD dependencies from ${filePath} to ${backupFilePath}`));
103
+ }
104
+
105
+ // Update the dependencies
106
+ for (const key in packageJson.dependencies) {
107
+ if (key.startsWith(MUD_PREFIX)) {
108
+ packageJson.dependencies[key] =
109
+ restore && backupJson ? backupJson.dependencies[key] : mudVersion || packageJson.dependencies[key];
110
+ }
111
+ }
112
+
113
+ // Update the devDependencies
114
+ for (const key in packageJson.devDependencies) {
115
+ if (key.startsWith(MUD_PREFIX)) {
116
+ packageJson.devDependencies[key] =
117
+ restore && backupJson ? backupJson.devDependencies[key] : mudVersion || packageJson.devDependencies[key];
118
+ }
119
+ }
120
+
121
+ // Write the updated package.json
122
+ writeFileSync(filePath, JSON.stringify(packageJson, null, 2) + "\n");
123
+
124
+ console.log(`Updating ${filePath}`);
125
+ logComparison(mudDependencies, packageJson.dependencies);
126
+ logComparison(mudDevDependencies, packageJson.devDependencies);
127
+
128
+ // Remove the backup file if `restore` is true and `backup` is false
129
+ // because the old backup file is no longer needed
130
+ if (restore && !backup) {
131
+ rmSync(backupFilePath);
132
+ console.log(chalk.green(`Cleaned up ${backupFilePath}`));
133
+ }
134
+
135
+ return packageJson;
136
+ }
137
+
138
+ function readPackageJson(path: string): {
139
+ workspaces?: string[];
140
+ dependencies: Record<string, string>;
141
+ devDependencies: Record<string, string>;
142
+ } {
143
+ try {
144
+ const jsonString = readFileSync(path, "utf8");
145
+ return JSON.parse(jsonString);
146
+ } catch {
147
+ throw new MUDError("Could not read JSON at " + path);
148
+ }
149
+ }
150
+
151
+ async function getCanaryVersion(pkg: string) {
152
+ try {
153
+ console.log(chalk.blue("fetching MUD canary version..."));
154
+ const result = await (await fetch(`https://registry.npmjs.org/${pkg}`)).json();
155
+ const canary = result["dist-tags"].canary;
156
+ console.log(chalk.green("MUD canary version:", canary));
157
+ return canary;
158
+ } catch (e) {
159
+ throw new MUDError(`Could not fetch canary version of ${pkg}`);
160
+ }
161
+ }
162
+
163
+ function logComparison(prev: Record<string, string>, curr: Record<string, string>) {
164
+ for (const key in prev) {
165
+ if (prev[key] !== curr[key]) {
166
+ console.log(`${key}: ${chalk.red(prev[key])} -> ${chalk.green(curr[key])}`);
167
+ }
168
+ }
169
+ }
170
+
171
+ export default commandModule;