@latticexyz/cli 2.0.0-alpha.0 → 2.0.0-alpha.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/dist/chunk-6V563IAZ.js +283 -0
- package/dist/{chunk-ATAWDHWC.js → chunk-FPG73MVN.js} +5 -1
- package/dist/{chunk-O6HOO6WA.js → chunk-L4YLJHLJ.js} +1 -9
- package/dist/{chunk-J4DJQNIC.js → chunk-SKNB74MT.js} +129 -568
- package/dist/chunk-VQTZJIFF.js +353 -0
- package/dist/chunk-WZFXLDPK.js +761 -0
- package/dist/chunk-YL4GJLLL.js +26139 -0
- package/dist/chunk-ZSZDPSLH.js +3841 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.js +0 -21
- package/dist/mud.d.ts +1 -1
- package/dist/mud.js +326 -4452
- package/dist/mud2.d.ts +1 -0
- package/dist/mud2.js +25 -0
- package/dist/render-solidity/index.d.ts +171 -0
- package/dist/render-solidity/index.js +49 -0
- package/dist/render-ts/index.d.ts +26 -0
- package/dist/render-ts/index.js +14 -0
- package/dist/utils/deprecated/index.js +3 -3
- package/dist/utils/index.d.ts +13 -18
- package/dist/utils/index.js +14 -16
- package/package.json +20 -21
- package/src/commands/deploy-v2.ts +80 -64
- package/src/commands/deprecated/index.ts +22 -0
- package/src/commands/deprecated/test.ts +1 -1
- package/src/commands/gas-report.ts +54 -55
- package/src/commands/index.ts +6 -17
- package/src/commands/set-version.ts +172 -0
- package/src/commands/tablegen.ts +5 -5
- package/src/commands/test-v2.ts +71 -0
- package/src/commands/tsgen.ts +33 -0
- package/src/commands/worldgen.ts +5 -4
- package/src/contracts/BulkUpload.sol +13 -20
- package/src/contracts/Deploy.sol +3 -3
- package/src/contracts/LibDeploy.sol +1 -1
- package/src/contracts/LibDeployStub.sol +1 -1
- package/src/index.ts +1 -15
- package/src/mud.ts +4 -3
- package/src/mud2.ts +29 -0
- package/src/render-solidity/common.ts +4 -4
- package/src/render-solidity/field.ts +25 -2
- package/src/render-solidity/record.ts +14 -10
- package/src/render-solidity/renderSystemInterface.ts +4 -4
- package/src/render-solidity/renderTableIndex.ts +15 -0
- package/src/render-solidity/renderTypesFromConfig.ts +1 -1
- package/src/render-solidity/tableOptions.ts +2 -2
- package/src/render-solidity/tablegen.ts +15 -13
- package/src/render-solidity/types.ts +2 -1
- package/src/render-solidity/userType.ts +1 -2
- package/src/render-solidity/worldgen.ts +8 -9
- package/src/render-ts/index.ts +5 -0
- package/src/render-ts/recsV1TableOptions.ts +39 -0
- package/src/render-ts/renderRecsV1Tables.ts +31 -0
- package/src/render-ts/schemaTypesToRecsTypeStrings.ts +202 -0
- package/src/render-ts/tsgen.ts +12 -0
- package/src/render-ts/types.ts +13 -0
- package/src/utils/contractToInterface.ts +5 -3
- package/src/utils/deploy-v2.ts +90 -84
- package/src/utils/errors.ts +3 -34
- package/src/utils/format.ts +6 -0
- package/src/utils/formatAndWrite.ts +11 -2
- package/src/utils/foundry.ts +9 -0
- package/src/utils/index.ts +1 -0
- package/dist/chunk-O57QENJ6.js +0 -23039
- package/dist/chunk-SLIMIO4Z.js +0 -14358
- package/dist/config/index.d.ts +0 -763
- package/dist/config/index.js +0 -83
- package/src/config/commonSchemas.ts +0 -34
- package/src/config/dynamicResolution.ts +0 -49
- package/src/config/index.ts +0 -24
- package/src/config/loadConfig.ts +0 -39
- package/src/config/loadStoreConfig.ts +0 -18
- package/src/config/parseStoreConfig.test-d.ts +0 -40
- package/src/config/parseStoreConfig.ts +0 -314
- package/src/config/validation.ts +0 -163
- package/src/config/world/index.ts +0 -4
- package/src/config/world/loadWorldConfig.test-d.ts +0 -11
- package/src/config/world/loadWorldConfig.ts +0 -26
- package/src/config/world/parseWorldConfig.ts +0 -55
- package/src/config/world/resolveWorldConfig.ts +0 -80
- package/src/config/world/userTypes.ts +0 -72
- package/src/utils/typeUtils.ts +0 -17
|
@@ -1,80 +1,81 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import glob from "glob";
|
|
3
3
|
import path, { basename } from "path";
|
|
4
|
-
import type { CommandModule } from "yargs";
|
|
5
|
-
import { loadWorldConfig } from "
|
|
4
|
+
import type { CommandModule, Options } from "yargs";
|
|
5
|
+
import { loadStoreConfig, loadWorldConfig } from "@latticexyz/config";
|
|
6
|
+
import { MUDError } from "@latticexyz/config";
|
|
6
7
|
import { deploy } from "../utils/deploy-v2.js";
|
|
7
|
-
import { logError
|
|
8
|
+
import { logError } from "../utils/errors.js";
|
|
8
9
|
import { forge, getRpcUrl, getSrcDirectory } from "../utils/foundry.js";
|
|
9
10
|
import { mkdirSync, writeFileSync } from "fs";
|
|
10
|
-
import { loadStoreConfig } from "../config/loadStoreConfig.js";
|
|
11
11
|
import { getChainId } from "../utils/getChainId.js";
|
|
12
12
|
|
|
13
|
-
type
|
|
13
|
+
export type DeployOptions = {
|
|
14
14
|
configPath?: string;
|
|
15
15
|
printConfig?: boolean;
|
|
16
16
|
profile?: string;
|
|
17
|
-
privateKey: string;
|
|
18
17
|
priorityFeeMultiplier: number;
|
|
19
18
|
clean?: boolean;
|
|
20
19
|
debug?: boolean;
|
|
20
|
+
saveDeployment?: boolean;
|
|
21
|
+
rpc?: string;
|
|
22
|
+
worldAddress?: string;
|
|
23
|
+
srcDir?: string;
|
|
21
24
|
};
|
|
22
25
|
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
profile: { type: "string", desc: "The foundry profile to use" },
|
|
34
|
-
debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
|
|
35
|
-
priorityFeeMultiplier: {
|
|
36
|
-
type: "number",
|
|
37
|
-
desc: "Multiply the estimated priority fee by the provided factor",
|
|
38
|
-
default: 1,
|
|
39
|
-
},
|
|
40
|
-
});
|
|
26
|
+
export const yDeployOptions = {
|
|
27
|
+
configPath: { type: "string", desc: "Path to the config file" },
|
|
28
|
+
clean: { type: "boolean", desc: "Remove the build forge artifacts and cache directories before building" },
|
|
29
|
+
printConfig: { type: "boolean", desc: "Print the resolved config" },
|
|
30
|
+
profile: { type: "string", desc: "The foundry profile to use" },
|
|
31
|
+
debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
|
|
32
|
+
priorityFeeMultiplier: {
|
|
33
|
+
type: "number",
|
|
34
|
+
desc: "Multiply the estimated priority fee by the provided factor",
|
|
35
|
+
default: 1,
|
|
41
36
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
37
|
+
saveDeployment: { type: "boolean", desc: "Save the deployment info to a file", default: true },
|
|
38
|
+
rpc: { type: "string", desc: "The RPC URL to use. Defaults to the RPC url from the local foundry.toml" },
|
|
39
|
+
worldAddress: { type: "string", desc: "Deploy to an existing World at the given address" },
|
|
40
|
+
srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." },
|
|
41
|
+
} satisfies Record<keyof DeployOptions, Options>;
|
|
42
|
+
|
|
43
|
+
export async function deployHandler(args: Parameters<(typeof commandModule)["handler"]>[0]) {
|
|
44
|
+
args.profile = args.profile ?? process.env.FOUNDRY_PROFILE;
|
|
45
|
+
const { configPath, printConfig, profile, clean } = args;
|
|
46
|
+
|
|
47
|
+
const rpc = args.rpc ?? (await getRpcUrl(profile));
|
|
48
|
+
console.log(
|
|
49
|
+
chalk.bgBlue(
|
|
50
|
+
chalk.whiteBright(`\n Deploying MUD v2 contracts${profile ? " with profile " + profile : ""} to RPC ${rpc} \n`)
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
if (clean) await forge(["clean"], { profile });
|
|
55
|
+
|
|
56
|
+
// Run forge build
|
|
57
|
+
await forge(["build"], { profile });
|
|
58
|
+
|
|
59
|
+
// Get a list of all contract names
|
|
60
|
+
const srcDir = args?.srcDir ?? (await getSrcDirectory());
|
|
61
|
+
const existingContracts = glob
|
|
62
|
+
.sync(`${srcDir}/**/*.sol`)
|
|
63
|
+
// Get the basename of the file
|
|
64
|
+
.map((path) => basename(path, ".sol"));
|
|
65
|
+
|
|
66
|
+
// Load and resolve the config
|
|
67
|
+
const worldConfig = await loadWorldConfig(configPath, existingContracts);
|
|
68
|
+
const storeConfig = await loadStoreConfig(configPath);
|
|
69
|
+
const mudConfig = { ...worldConfig, ...storeConfig };
|
|
70
|
+
|
|
71
|
+
if (printConfig) console.log(chalk.green("\nResolved config:\n"), JSON.stringify(mudConfig, null, 2));
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const privateKey = process.env.PRIVATE_KEY;
|
|
75
|
+
if (!privateKey) throw new MUDError("Missing PRIVATE_KEY environment variable");
|
|
76
|
+
const deploymentInfo = await deploy(mudConfig, { ...args, rpc, privateKey });
|
|
77
|
+
|
|
78
|
+
if (args.saveDeployment) {
|
|
78
79
|
// Write deployment result to file (latest and timestamp)
|
|
79
80
|
const chainId = await getChainId(rpc);
|
|
80
81
|
const outputDir = path.join(mudConfig.deploysDirectory, chainId.toString());
|
|
@@ -83,12 +84,27 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
83
84
|
writeFileSync(path.join(outputDir, Date.now() + ".json"), JSON.stringify(deploymentInfo, null, 2));
|
|
84
85
|
|
|
85
86
|
console.log(chalk.bgGreen(chalk.whiteBright(`\n Deployment result (written to ${outputDir}): \n`)));
|
|
86
|
-
console.log(deploymentInfo);
|
|
87
|
-
} catch (error: any) {
|
|
88
|
-
logError(error);
|
|
89
|
-
process.exit(1);
|
|
90
87
|
}
|
|
91
88
|
|
|
89
|
+
console.log(deploymentInfo);
|
|
90
|
+
return deploymentInfo;
|
|
91
|
+
} catch (error: any) {
|
|
92
|
+
logError(error);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const commandModule: CommandModule<DeployOptions, DeployOptions> = {
|
|
98
|
+
command: "deploy-v2",
|
|
99
|
+
|
|
100
|
+
describe: "Deploy MUD v2 contracts",
|
|
101
|
+
|
|
102
|
+
builder(yargs) {
|
|
103
|
+
return yargs.options(yDeployOptions);
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
async handler(args) {
|
|
107
|
+
await deployHandler(args);
|
|
92
108
|
process.exit(0);
|
|
93
109
|
},
|
|
94
110
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CommandModule } from "yargs";
|
|
2
|
+
|
|
3
|
+
import bulkupload from "./bulkupload.js";
|
|
4
|
+
import callSystem from "./call-system.js";
|
|
5
|
+
import codegenLibdeploy from "./codegen-libdeploy.js";
|
|
6
|
+
import deployContracts from "./deploy-contracts.js";
|
|
7
|
+
import systemTypes from "./system-types.js";
|
|
8
|
+
import test from "./test.js";
|
|
9
|
+
import trace from "./trace.js";
|
|
10
|
+
import types from "./types.js";
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
|
|
13
|
+
export const commands: CommandModule<any, any>[] = [
|
|
14
|
+
bulkupload,
|
|
15
|
+
callSystem,
|
|
16
|
+
deployContracts,
|
|
17
|
+
codegenLibdeploy,
|
|
18
|
+
systemTypes,
|
|
19
|
+
test,
|
|
20
|
+
trace,
|
|
21
|
+
types,
|
|
22
|
+
];
|
|
@@ -39,6 +39,8 @@ type GasReportEntry = {
|
|
|
39
39
|
|
|
40
40
|
type GasReport = GasReportEntry[];
|
|
41
41
|
|
|
42
|
+
const tempFileSuffix = "MudGasReport";
|
|
43
|
+
|
|
42
44
|
const commandModule: CommandModule<Options, Options> = {
|
|
43
45
|
command: "gas-report",
|
|
44
46
|
|
|
@@ -52,43 +54,43 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
52
54
|
});
|
|
53
55
|
},
|
|
54
56
|
|
|
55
|
-
async handler({ path, save, compare }) {
|
|
56
|
-
|
|
57
|
+
async handler({ path: files, save, compare }) {
|
|
58
|
+
const validFiles = files.filter((file) => file.endsWith(".t.sol"));
|
|
59
|
+
const tempFiles = await Promise.all(validFiles.map((file) => createGasReport(file)));
|
|
60
|
+
|
|
61
|
+
process.once("SIGINT", () => {
|
|
62
|
+
console.log("caught sigint, deleting temp files");
|
|
63
|
+
tempFiles.forEach((file) => rmSync(file));
|
|
64
|
+
});
|
|
57
65
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
gasReport =
|
|
66
|
+
let gasReport: GasReport;
|
|
67
|
+
try {
|
|
68
|
+
gasReport = await runGasReport();
|
|
69
|
+
} catch {
|
|
70
|
+
setTimeout(() => process.exit());
|
|
71
|
+
return;
|
|
72
|
+
} finally {
|
|
73
|
+
// Delete the temporary files
|
|
74
|
+
tempFiles.forEach((file) => rmSync(file));
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
// If this gas report should be compared to an existing one, load the existing one
|
|
64
|
-
const compareGasReport: GasReport = [];
|
|
65
78
|
if (compare) {
|
|
66
79
|
try {
|
|
67
|
-
const
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const functionCall = compareGasReportMatch[3];
|
|
76
|
-
const gasUsed = compareGasReportMatch[4];
|
|
77
|
-
|
|
78
|
-
compareGasReport.push({ source, name, functionCall, gasUsed: parseInt(gasUsed) });
|
|
79
|
-
}
|
|
80
|
+
const compareGasReport: GasReport = JSON.parse(readFileSync(compare, "utf8"));
|
|
81
|
+
// Merge the previous gas report with the new one
|
|
82
|
+
gasReport = gasReport.map((entry) => {
|
|
83
|
+
const prevEntry = compareGasReport.find(
|
|
84
|
+
(e) => e.name === entry.name && e.functionCall === entry.functionCall
|
|
85
|
+
);
|
|
86
|
+
return { ...entry, prevGasUsed: prevEntry?.gasUsed };
|
|
87
|
+
});
|
|
80
88
|
} catch {
|
|
81
89
|
console.log(chalk.red(`Gas report to compare not found: ${compare}`));
|
|
82
90
|
compare = undefined;
|
|
83
91
|
}
|
|
84
92
|
}
|
|
85
93
|
|
|
86
|
-
// Merge the previous gas report with the new one
|
|
87
|
-
gasReport = gasReport.map((entry) => {
|
|
88
|
-
const prevEntry = compareGasReport.find((e) => e.name === entry.name && e.functionCall === entry.functionCall);
|
|
89
|
-
return { ...entry, prevGasUsed: prevEntry?.gasUsed };
|
|
90
|
-
});
|
|
91
|
-
|
|
92
94
|
// Print gas report
|
|
93
95
|
printGasReport(gasReport, compare);
|
|
94
96
|
|
|
@@ -101,16 +103,11 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
101
103
|
|
|
102
104
|
export default commandModule;
|
|
103
105
|
|
|
104
|
-
async function
|
|
105
|
-
|
|
106
|
-
console.log("Skipping gas report for", chalk.bold(path), "(not a test file)");
|
|
107
|
-
return [];
|
|
108
|
-
}
|
|
109
|
-
console.log("Running gas report for", chalk.bold(path));
|
|
110
|
-
const gasReport: GasReport = [];
|
|
106
|
+
async function createGasReport(filename: string): Promise<string> {
|
|
107
|
+
console.log("Creating gas report for", chalk.bold(filename));
|
|
111
108
|
|
|
112
109
|
// Parse the given test file, and add gas reporting wherever requested by a `// !gasreport` comment
|
|
113
|
-
const fileContents = readFileSync(
|
|
110
|
+
const fileContents = readFileSync(filename, "utf8");
|
|
114
111
|
let newFile = fileContents;
|
|
115
112
|
|
|
116
113
|
// Use a regex to find first line of each function
|
|
@@ -139,7 +136,7 @@ async function runGasReport(path: string): Promise<GasReport> {
|
|
|
139
136
|
_gasreport = gasleft();
|
|
140
137
|
${functionCall}
|
|
141
138
|
_gasreport = _gasreport - gasleft();
|
|
142
|
-
console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _gasreport);`
|
|
139
|
+
console.log("GAS REPORT(${filename}): ${name} [${functionCall.replaceAll('"', '\\"')}]:", _gasreport);`
|
|
143
140
|
);
|
|
144
141
|
}
|
|
145
142
|
|
|
@@ -148,41 +145,47 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
|
|
|
148
145
|
|
|
149
146
|
// Write the new file to disk (temporarily)
|
|
150
147
|
// Create the temp file by replacing the previous file name with MudGasReport
|
|
151
|
-
const tempFileName =
|
|
148
|
+
const tempFileName = filename.replace(/\.t\.sol$/, `${tempFileSuffix}.t.sol`);
|
|
152
149
|
writeFileSync(tempFileName, newFile);
|
|
153
150
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
151
|
+
return tempFileName;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function runGasReport(): Promise<GasReport> {
|
|
155
|
+
console.log("Running gas report");
|
|
156
|
+
const gasReport: GasReport = [];
|
|
158
157
|
|
|
159
158
|
// Extract the logs from the child process
|
|
160
159
|
let logs = "";
|
|
161
160
|
try {
|
|
161
|
+
// Run the generated file using forge
|
|
162
|
+
const child = execa("forge", ["test", "--match-path", `*${tempFileSuffix}*`, "-vvv"], {
|
|
163
|
+
stdio: ["inherit", "pipe", "inherit"],
|
|
164
|
+
});
|
|
162
165
|
logs = (await child).stdout;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
console.log(e.stdout ?? e);
|
|
166
|
+
} catch (error: any) {
|
|
167
|
+
console.log(error.stdout ?? error);
|
|
166
168
|
console.log(chalk.red("\n-----------\nError while running the gas report (see above)"));
|
|
167
|
-
|
|
168
|
-
process.exit();
|
|
169
|
+
throw error;
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
// Extract the gas reports from the logs
|
|
172
173
|
|
|
173
174
|
// Create a regex to find all lines starting with `GAS REPORT:` and extract the name, function call and gas used
|
|
174
|
-
const gasReportRegex = new RegExp(/GAS REPORT: (.*) \[(.*)\]: (.*)/g);
|
|
175
|
+
const gasReportRegex = new RegExp(/GAS REPORT\((.*)\): (.*) \[(.*)\]: (.*)/g);
|
|
175
176
|
|
|
176
177
|
// Loop through the matches and print the gas report
|
|
177
178
|
let gasReportMatch;
|
|
178
179
|
while ((gasReportMatch = gasReportRegex.exec(logs)) !== null) {
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
gasReport.push({ source
|
|
180
|
+
const source = gasReportMatch[1];
|
|
181
|
+
const name = gasReportMatch[2];
|
|
182
|
+
const functionCall = gasReportMatch[3].replace(";", "");
|
|
183
|
+
const gasUsed = parseInt(gasReportMatch[4]);
|
|
184
|
+
gasReport.push({ source, name, functionCall, gasUsed });
|
|
184
185
|
}
|
|
185
186
|
|
|
187
|
+
gasReport.sort((a, b) => a.source.localeCompare(b.source));
|
|
188
|
+
|
|
186
189
|
return gasReport;
|
|
187
190
|
}
|
|
188
191
|
|
|
@@ -212,9 +215,5 @@ function printGasReport(gasReport: GasReport, compare?: string) {
|
|
|
212
215
|
|
|
213
216
|
function saveGasReport(gasReport: GasReport, path: string) {
|
|
214
217
|
console.log(chalk.bold(`Saving gas report to ${path}`));
|
|
215
|
-
|
|
216
|
-
.map((entry) => `(${entry.source}) | ${entry.name} [${entry.functionCall}]: ${entry.gasUsed}`)
|
|
217
|
-
.join("\n");
|
|
218
|
-
|
|
219
|
-
writeFileSync(path, serializedGasReport);
|
|
218
|
+
writeFileSync(path, `${JSON.stringify(gasReport, null, 2)}\n`);
|
|
220
219
|
}
|
package/src/commands/index.ts
CHANGED
|
@@ -1,37 +1,26 @@
|
|
|
1
1
|
import { CommandModule } from "yargs";
|
|
2
2
|
|
|
3
|
-
import bulkupload from "./deprecated/bulkupload.js";
|
|
4
|
-
import callSystem from "./deprecated/call-system.js";
|
|
5
|
-
import codegenLibdeploy from "./deprecated/codegen-libdeploy.js";
|
|
6
|
-
import deployContracts from "./deprecated/deploy-contracts.js";
|
|
7
|
-
import systemTypes from "./deprecated/system-types.js";
|
|
8
|
-
import test from "./deprecated/test.js";
|
|
9
|
-
import trace from "./deprecated/trace.js";
|
|
10
|
-
import types from "./deprecated/types.js";
|
|
11
|
-
|
|
12
3
|
import devnode from "./devnode.js";
|
|
13
4
|
import faucet from "./faucet.js";
|
|
14
5
|
import gasReport from "./gas-report.js";
|
|
15
6
|
import hello from "./hello.js";
|
|
16
7
|
import tablegen from "./tablegen.js";
|
|
8
|
+
import tsgen from "./tsgen.js";
|
|
17
9
|
import deployV2 from "./deploy-v2.js";
|
|
18
10
|
import worldgen from "./worldgen.js";
|
|
11
|
+
import setVersion from "./set-version.js";
|
|
12
|
+
import testV2 from "./test-v2.js";
|
|
19
13
|
|
|
20
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
|
|
21
15
|
export const commands: CommandModule<any, any>[] = [
|
|
22
|
-
bulkupload,
|
|
23
|
-
callSystem,
|
|
24
|
-
codegenLibdeploy,
|
|
25
|
-
deployContracts,
|
|
26
16
|
deployV2,
|
|
27
17
|
devnode,
|
|
28
18
|
faucet,
|
|
29
19
|
gasReport,
|
|
30
20
|
hello,
|
|
31
|
-
systemTypes,
|
|
32
21
|
tablegen,
|
|
33
|
-
|
|
34
|
-
trace,
|
|
35
|
-
types,
|
|
22
|
+
tsgen,
|
|
36
23
|
worldgen,
|
|
24
|
+
setVersion,
|
|
25
|
+
testV2,
|
|
37
26
|
];
|
|
@@ -0,0 +1,172 @@
|
|
|
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 { MUDError } from "@latticexyz/config";
|
|
6
|
+
import { logError } from "../utils/errors.js";
|
|
7
|
+
import localPackageJson from "../../package.json" assert { type: "json" };
|
|
8
|
+
|
|
9
|
+
type Options = {
|
|
10
|
+
backup?: boolean;
|
|
11
|
+
force?: boolean;
|
|
12
|
+
restore?: boolean;
|
|
13
|
+
mudVersion?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const BACKUP_FILE = ".mudbackup";
|
|
17
|
+
const MUD_PREFIX = "@latticexyz";
|
|
18
|
+
|
|
19
|
+
const commandModule: CommandModule<Options, Options> = {
|
|
20
|
+
command: "set-version",
|
|
21
|
+
|
|
22
|
+
describe: "Install a custom MUD version and optionally backup the previously installed version",
|
|
23
|
+
|
|
24
|
+
builder(yargs) {
|
|
25
|
+
return yargs.options({
|
|
26
|
+
backup: { type: "boolean", description: `Back up the current MUD versions to "${BACKUP_FILE}"` },
|
|
27
|
+
force: {
|
|
28
|
+
type: "boolean",
|
|
29
|
+
description: `Backup fails if a "${BACKUP_FILE}" file is found, unless --force is provided`,
|
|
30
|
+
},
|
|
31
|
+
restore: { type: "boolean", description: `Restore the previous MUD versions from "${BACKUP_FILE}"` },
|
|
32
|
+
mudVersion: { alias: "v", type: "string", description: "The MUD version to install" },
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
async handler(options) {
|
|
37
|
+
try {
|
|
38
|
+
if (!options.mudVersion && !options.restore) {
|
|
39
|
+
throw new MUDError(`Version parameter is required unless --restore is provided.`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Resolve the `canary` version number if needed
|
|
43
|
+
options.mudVersion =
|
|
44
|
+
options.mudVersion === "canary" ? await getCanaryVersion(localPackageJson.name) : options.mudVersion;
|
|
45
|
+
|
|
46
|
+
// Read the current package.json
|
|
47
|
+
const rootPath = "./package.json";
|
|
48
|
+
const { workspaces } = updatePackageJson(rootPath, options);
|
|
49
|
+
|
|
50
|
+
// Load the package.json of each workspace
|
|
51
|
+
if (workspaces) {
|
|
52
|
+
for (const workspace of workspaces) {
|
|
53
|
+
const filePath = path.join(workspace, "/package.json");
|
|
54
|
+
updatePackageJson(filePath, options);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} catch (e) {
|
|
58
|
+
logError(e);
|
|
59
|
+
} finally {
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function updatePackageJson(filePath: string, options: Options): { workspaces?: string[] } {
|
|
66
|
+
const { backup, restore, force, mudVersion } = options;
|
|
67
|
+
const backupFilePath = path.join(path.dirname(filePath), BACKUP_FILE);
|
|
68
|
+
|
|
69
|
+
// If `backup` is true and force not set, check if a backup file already exists and throw an error if it does
|
|
70
|
+
if (backup && !force && existsSync(backupFilePath)) {
|
|
71
|
+
throw new MUDError(
|
|
72
|
+
`A backup file already exists at ${backupFilePath}.\nUse --force to overwrite it or --restore to restore it.`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const packageJson = readPackageJson(filePath);
|
|
77
|
+
|
|
78
|
+
// Load .mudbackup if `restore` is true
|
|
79
|
+
const backupJson = restore ? readPackageJson(backupFilePath) : undefined;
|
|
80
|
+
|
|
81
|
+
// Find all MUD dependencies
|
|
82
|
+
const mudDependencies: Record<string, string> = {};
|
|
83
|
+
for (const key in packageJson.dependencies) {
|
|
84
|
+
if (key.startsWith(MUD_PREFIX)) {
|
|
85
|
+
mudDependencies[key] = packageJson.dependencies[key];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Find all MUD devDependencies
|
|
90
|
+
const mudDevDependencies: Record<string, string> = {};
|
|
91
|
+
for (const key in packageJson.devDependencies) {
|
|
92
|
+
if (key.startsWith(MUD_PREFIX)) {
|
|
93
|
+
mudDevDependencies[key] = packageJson.devDependencies[key];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Back up the current dependencies if `backup` is true
|
|
98
|
+
if (backup) {
|
|
99
|
+
writeFileSync(
|
|
100
|
+
backupFilePath,
|
|
101
|
+
JSON.stringify({ dependencies: mudDependencies, devDependencies: mudDevDependencies }, null, 2)
|
|
102
|
+
);
|
|
103
|
+
console.log(chalk.green(`Backed up MUD dependencies from ${filePath} to ${backupFilePath}`));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Update the dependencies
|
|
107
|
+
for (const key in packageJson.dependencies) {
|
|
108
|
+
if (key.startsWith(MUD_PREFIX)) {
|
|
109
|
+
packageJson.dependencies[key] =
|
|
110
|
+
restore && backupJson ? backupJson.dependencies[key] : mudVersion || packageJson.dependencies[key];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Update the devDependencies
|
|
115
|
+
for (const key in packageJson.devDependencies) {
|
|
116
|
+
if (key.startsWith(MUD_PREFIX)) {
|
|
117
|
+
packageJson.devDependencies[key] =
|
|
118
|
+
restore && backupJson ? backupJson.devDependencies[key] : mudVersion || packageJson.devDependencies[key];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Write the updated package.json
|
|
123
|
+
writeFileSync(filePath, JSON.stringify(packageJson, null, 2) + "\n");
|
|
124
|
+
|
|
125
|
+
console.log(`Updating ${filePath}`);
|
|
126
|
+
logComparison(mudDependencies, packageJson.dependencies);
|
|
127
|
+
logComparison(mudDevDependencies, packageJson.devDependencies);
|
|
128
|
+
|
|
129
|
+
// Remove the backup file if `restore` is true and `backup` is false
|
|
130
|
+
// because the old backup file is no longer needed
|
|
131
|
+
if (restore && !backup) {
|
|
132
|
+
rmSync(backupFilePath);
|
|
133
|
+
console.log(chalk.green(`Cleaned up ${backupFilePath}`));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return packageJson;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function readPackageJson(path: string): {
|
|
140
|
+
workspaces?: string[];
|
|
141
|
+
dependencies: Record<string, string>;
|
|
142
|
+
devDependencies: Record<string, string>;
|
|
143
|
+
} {
|
|
144
|
+
try {
|
|
145
|
+
const jsonString = readFileSync(path, "utf8");
|
|
146
|
+
return JSON.parse(jsonString);
|
|
147
|
+
} catch {
|
|
148
|
+
throw new MUDError("Could not read JSON at " + path);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function getCanaryVersion(pkg: string) {
|
|
153
|
+
try {
|
|
154
|
+
console.log(chalk.blue("fetching MUD canary version..."));
|
|
155
|
+
const result = await (await fetch(`https://registry.npmjs.org/${pkg}`)).json();
|
|
156
|
+
const canary = result["dist-tags"].canary;
|
|
157
|
+
console.log(chalk.green("MUD canary version:", canary));
|
|
158
|
+
return canary;
|
|
159
|
+
} catch (e) {
|
|
160
|
+
throw new MUDError(`Could not fetch canary version of ${pkg}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function logComparison(prev: Record<string, string>, curr: Record<string, string>) {
|
|
165
|
+
for (const key in prev) {
|
|
166
|
+
if (prev[key] !== curr[key]) {
|
|
167
|
+
console.log(`${key}: ${chalk.red(prev[key])} -> ${chalk.green(curr[key])}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export default commandModule;
|
package/src/commands/tablegen.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import path from "path";
|
|
1
2
|
import type { CommandModule } from "yargs";
|
|
2
|
-
import { loadStoreConfig } from "
|
|
3
|
-
import { getSrcDirectory } from "../utils/foundry.js";
|
|
3
|
+
import { loadStoreConfig } from "@latticexyz/config";
|
|
4
4
|
import { tablegen } from "../render-solidity/tablegen.js";
|
|
5
|
+
import { getSrcDirectory } from "../utils/index.js";
|
|
5
6
|
|
|
6
7
|
type Options = {
|
|
7
8
|
configPath?: string;
|
|
@@ -19,11 +20,10 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
19
20
|
},
|
|
20
21
|
|
|
21
22
|
async handler({ configPath }) {
|
|
22
|
-
const srcDirectory = await getSrcDirectory();
|
|
23
|
-
|
|
24
23
|
const config = await loadStoreConfig(configPath);
|
|
24
|
+
const srcDir = await getSrcDirectory();
|
|
25
25
|
|
|
26
|
-
await tablegen(config,
|
|
26
|
+
await tablegen(config, path.join(srcDir, config.codegenDirectory));
|
|
27
27
|
|
|
28
28
|
process.exit(0);
|
|
29
29
|
},
|