create-fhevm-example 1.2.2 → 1.3.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/README.md +74 -148
- package/dist/scripts/add-mode.d.ts +8 -0
- package/dist/scripts/add-mode.d.ts.map +1 -0
- package/dist/{add-mode.js → scripts/add-mode.js} +81 -58
- package/dist/scripts/builders.d.ts +20 -0
- package/dist/scripts/builders.d.ts.map +1 -0
- package/dist/scripts/builders.js +160 -0
- package/dist/{config.d.ts → scripts/config.d.ts} +24 -3
- package/dist/scripts/config.d.ts.map +1 -0
- package/dist/scripts/config.js +465 -0
- package/dist/scripts/doctor.d.ts +3 -0
- package/dist/scripts/doctor.d.ts.map +1 -0
- package/dist/scripts/doctor.js +157 -0
- package/dist/scripts/generate-config.d.ts +9 -0
- package/dist/scripts/generate-config.d.ts.map +1 -0
- package/dist/scripts/generate-config.js +315 -0
- package/dist/scripts/generate-docs.d.ts +9 -0
- package/dist/scripts/generate-docs.d.ts.map +1 -0
- package/dist/scripts/generate-docs.js +189 -0
- package/dist/scripts/index.d.ts +12 -0
- package/dist/scripts/index.d.ts.map +1 -0
- package/dist/scripts/index.js +360 -0
- package/dist/scripts/maintenance.d.ts +12 -0
- package/dist/scripts/maintenance.d.ts.map +1 -0
- package/dist/scripts/maintenance.js +320 -0
- package/dist/{ui.d.ts → scripts/ui.d.ts} +0 -1
- package/dist/scripts/ui.d.ts.map +1 -0
- package/dist/scripts/ui.js +197 -0
- package/dist/scripts/utils.d.ts +79 -0
- package/dist/scripts/utils.d.ts.map +1 -0
- package/dist/scripts/utils.js +504 -0
- package/package.json +24 -12
- package/dist/add-mode.d.ts +0 -21
- package/dist/add-mode.d.ts.map +0 -1
- package/dist/add-mode.js.map +0 -1
- package/dist/builders.d.ts +0 -30
- package/dist/builders.d.ts.map +0 -1
- package/dist/builders.js +0 -195
- package/dist/builders.js.map +0 -1
- package/dist/commands.d.ts +0 -19
- package/dist/commands.d.ts.map +0 -1
- package/dist/commands.js +0 -91
- package/dist/commands.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -403
- package/dist/config.js.map +0 -1
- package/dist/constants.d.ts +0 -16
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -40
- package/dist/constants.js.map +0 -1
- package/dist/index.d.ts +0 -20
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -337
- package/dist/index.js.map +0 -1
- package/dist/prompts.d.ts +0 -26
- package/dist/prompts.d.ts.map +0 -1
- package/dist/prompts.js +0 -79
- package/dist/prompts.js.map +0 -1
- package/dist/ui.d.ts.map +0 -1
- package/dist/ui.js +0 -155
- package/dist/ui.js.map +0 -1
- package/dist/utils.d.ts +0 -99
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -285
- package/dist/utils.js.map +0 -1
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* FHEVM Example Factory - Maintenance Tools
|
|
5
|
+
*
|
|
6
|
+
* Test multiple examples efficiently in a single project.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npm run test:all # Interactive selection
|
|
10
|
+
* npm run test:all fhe-counter,fhe-add # Direct CLI
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
46
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
47
|
+
};
|
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
+
exports.testAllExamples = testAllExamples;
|
|
50
|
+
const p = __importStar(require("@clack/prompts"));
|
|
51
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
52
|
+
const fs = __importStar(require("fs"));
|
|
53
|
+
const path = __importStar(require("path"));
|
|
54
|
+
const config_1 = require("./config");
|
|
55
|
+
const utils_1 = require("./utils");
|
|
56
|
+
// =============================================================================
|
|
57
|
+
// Project Builder
|
|
58
|
+
// =============================================================================
|
|
59
|
+
async function createTestProject(exampleNames, outputDir) {
|
|
60
|
+
const rootDir = (0, utils_1.getRootDir)();
|
|
61
|
+
const templateDir = (0, utils_1.getTemplateDir)();
|
|
62
|
+
(0, utils_1.copyDirectoryRecursive)(templateDir, outputDir);
|
|
63
|
+
(0, utils_1.cleanupTemplate)(outputDir);
|
|
64
|
+
const allNpmDeps = {};
|
|
65
|
+
const allContractDeps = new Set();
|
|
66
|
+
for (const exampleName of exampleNames) {
|
|
67
|
+
const example = config_1.EXAMPLES[exampleName];
|
|
68
|
+
if (!example)
|
|
69
|
+
continue;
|
|
70
|
+
const contractPath = path.join(rootDir, example.contract);
|
|
71
|
+
const testPath = path.join(rootDir, example.test);
|
|
72
|
+
if (fs.existsSync(contractPath)) {
|
|
73
|
+
const contractName = (0, utils_1.getContractName)(example.contract);
|
|
74
|
+
if (contractName) {
|
|
75
|
+
fs.copyFileSync(contractPath, path.join(outputDir, "contracts", `${contractName}.sol`));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (fs.existsSync(testPath)) {
|
|
79
|
+
fs.copyFileSync(testPath, path.join(outputDir, "test", path.basename(example.test)));
|
|
80
|
+
}
|
|
81
|
+
if (example.dependencies) {
|
|
82
|
+
example.dependencies.forEach((dep) => allContractDeps.add(dep));
|
|
83
|
+
}
|
|
84
|
+
if (example.npmDependencies) {
|
|
85
|
+
Object.assign(allNpmDeps, example.npmDependencies);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const depPath of allContractDeps) {
|
|
89
|
+
const depFullPath = path.join(rootDir, depPath);
|
|
90
|
+
if (fs.existsSync(depFullPath)) {
|
|
91
|
+
const relativePath = depPath.replace(/^contracts\//, "");
|
|
92
|
+
const depDestPath = path.join(outputDir, "contracts", relativePath);
|
|
93
|
+
const depDestDir = path.dirname(depDestPath);
|
|
94
|
+
if (!fs.existsSync(depDestDir)) {
|
|
95
|
+
fs.mkdirSync(depDestDir, { recursive: true });
|
|
96
|
+
}
|
|
97
|
+
fs.copyFileSync(depFullPath, depDestPath);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Update package.json using shared utility
|
|
101
|
+
(0, utils_1.updateProjectPackageJson)(outputDir, "fhevm-test-project", `Testing ${exampleNames.length} examples`, Object.keys(allNpmDeps).length > 0 ? allNpmDeps : undefined);
|
|
102
|
+
const typesPath = path.join(outputDir, "test", "types.ts");
|
|
103
|
+
if (!fs.existsSync(typesPath)) {
|
|
104
|
+
fs.writeFileSync(typesPath, utils_1.TEST_TYPES_CONTENT);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// =============================================================================
|
|
108
|
+
// Example Selection
|
|
109
|
+
// =============================================================================
|
|
110
|
+
async function getExamplesToTest(cliExamples) {
|
|
111
|
+
const allExamples = (0, config_1.getExampleNames)();
|
|
112
|
+
if (cliExamples && cliExamples.length > 0) {
|
|
113
|
+
const invalid = cliExamples.filter((e) => !allExamples.includes(e));
|
|
114
|
+
if (invalid.length > 0) {
|
|
115
|
+
p.log.error(`Unknown examples: ${invalid.join(", ")}`);
|
|
116
|
+
p.log.message(picocolors_1.default.dim(`Available: ${allExamples.join(", ")}`));
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
p.log.message(`Testing ${picocolors_1.default.bold(String(cliExamples.length))} examples...`);
|
|
120
|
+
return cliExamples;
|
|
121
|
+
}
|
|
122
|
+
const selected = await p.multiselect({
|
|
123
|
+
message: "Select examples to test (space to toggle, enter to confirm):",
|
|
124
|
+
options: allExamples.map((ex) => ({
|
|
125
|
+
value: ex,
|
|
126
|
+
label: ex,
|
|
127
|
+
hint: config_1.EXAMPLES[ex]?.category || "",
|
|
128
|
+
})),
|
|
129
|
+
required: true,
|
|
130
|
+
});
|
|
131
|
+
if (p.isCancel(selected)) {
|
|
132
|
+
p.cancel("Operation cancelled");
|
|
133
|
+
process.exit(0);
|
|
134
|
+
}
|
|
135
|
+
return selected;
|
|
136
|
+
}
|
|
137
|
+
// =============================================================================
|
|
138
|
+
// Test Runner
|
|
139
|
+
// =============================================================================
|
|
140
|
+
async function runTestPipeline(tempDir, exampleCount) {
|
|
141
|
+
const summary = {
|
|
142
|
+
totalExamples: exampleCount,
|
|
143
|
+
passed: 0,
|
|
144
|
+
failed: 0,
|
|
145
|
+
compileSuccess: false,
|
|
146
|
+
failedTests: [],
|
|
147
|
+
};
|
|
148
|
+
const s1 = p.spinner();
|
|
149
|
+
s1.start("Installing dependencies...");
|
|
150
|
+
const installResult = await (0, utils_1.runCommandWithStatus)("npm", ["install"], tempDir);
|
|
151
|
+
if (!installResult.success) {
|
|
152
|
+
s1.stop(picocolors_1.default.red("✗ npm install failed"));
|
|
153
|
+
p.log.error((0, utils_1.extractErrorMessage)(installResult.output));
|
|
154
|
+
return summary;
|
|
155
|
+
}
|
|
156
|
+
s1.stop(picocolors_1.default.green("✓ Dependencies installed"));
|
|
157
|
+
const s2 = p.spinner();
|
|
158
|
+
s2.start("Compiling contracts...");
|
|
159
|
+
const compileResult = await (0, utils_1.runCommandWithStatus)("npm", ["run", "compile"], tempDir);
|
|
160
|
+
if (!compileResult.success) {
|
|
161
|
+
s2.stop(picocolors_1.default.red("✗ Compilation failed"));
|
|
162
|
+
p.log.error((0, utils_1.extractErrorMessage)(compileResult.output));
|
|
163
|
+
return summary;
|
|
164
|
+
}
|
|
165
|
+
s2.stop(picocolors_1.default.green("✓ Contracts compiled"));
|
|
166
|
+
summary.compileSuccess = true;
|
|
167
|
+
const testDir = path.join(tempDir, "test");
|
|
168
|
+
const testFiles = fs
|
|
169
|
+
.readdirSync(testDir)
|
|
170
|
+
.filter((f) => f.endsWith(".test.ts") || f.endsWith(".ts"))
|
|
171
|
+
.filter((f) => f !== "types.ts");
|
|
172
|
+
if (testFiles.length === 0) {
|
|
173
|
+
p.log.warning("No test files found");
|
|
174
|
+
return summary;
|
|
175
|
+
}
|
|
176
|
+
p.log.message("");
|
|
177
|
+
p.log.message(picocolors_1.default.bold(`🧪 Running ${testFiles.length} test files:`));
|
|
178
|
+
p.log.message("");
|
|
179
|
+
let passedTests = 0;
|
|
180
|
+
let failedTests = 0;
|
|
181
|
+
const startTime = Date.now();
|
|
182
|
+
for (let i = 0; i < testFiles.length; i++) {
|
|
183
|
+
const testFile = testFiles[i];
|
|
184
|
+
const progress = `[${i + 1}/${testFiles.length}]`;
|
|
185
|
+
process.stdout.write(` ${picocolors_1.default.dim(progress)} ${testFile} `);
|
|
186
|
+
const testStart = Date.now();
|
|
187
|
+
const result = await (0, utils_1.runCommandWithStatus)("npx", ["hardhat", "test", `test/${testFile}`], tempDir);
|
|
188
|
+
const duration = ((Date.now() - testStart) / 1000).toFixed(1);
|
|
189
|
+
if (result.success) {
|
|
190
|
+
const testResults = (0, utils_1.extractTestResults)(result.output);
|
|
191
|
+
const resultInfo = testResults
|
|
192
|
+
? picocolors_1.default.dim(`(${testResults.replace(" ✓", "")})`)
|
|
193
|
+
: "";
|
|
194
|
+
p.log.message(picocolors_1.default.green(`✓`) + ` ${picocolors_1.default.dim(duration + "s")} ${resultInfo}`);
|
|
195
|
+
passedTests++;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
p.log.message(picocolors_1.default.red(`✗`) + ` ${picocolors_1.default.dim(duration + "s")}`);
|
|
199
|
+
failedTests++;
|
|
200
|
+
summary.failedTests.push(testFile);
|
|
201
|
+
const errorMsg = (0, utils_1.extractErrorMessage)(result.output);
|
|
202
|
+
if (errorMsg) {
|
|
203
|
+
const shortError = errorMsg.split("\n")[0].slice(0, 80);
|
|
204
|
+
p.log.message(` ${picocolors_1.default.red(picocolors_1.default.dim(shortError))}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const totalDuration = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
209
|
+
p.log.message("");
|
|
210
|
+
p.log.message(picocolors_1.default.dim(`Completed in ${totalDuration}s`));
|
|
211
|
+
summary.passed = passedTests;
|
|
212
|
+
summary.failed = failedTests;
|
|
213
|
+
return summary;
|
|
214
|
+
}
|
|
215
|
+
function showSummary(summary) {
|
|
216
|
+
p.log.message("");
|
|
217
|
+
p.log.message(picocolors_1.default.bold("📊 Test Summary"));
|
|
218
|
+
p.log.message(picocolors_1.default.dim("─".repeat(50)));
|
|
219
|
+
p.log.message(`${picocolors_1.default.blue("📦 Examples:")} ${summary.totalExamples}`);
|
|
220
|
+
p.log.message(`${picocolors_1.default.blue("📁 Compile:")} ${summary.compileSuccess ? picocolors_1.default.green("✓ Success") : picocolors_1.default.red("✗ Failed")}`);
|
|
221
|
+
if (summary.compileSuccess) {
|
|
222
|
+
if (summary.failed === 0) {
|
|
223
|
+
p.log.message(`${picocolors_1.default.green("✓ Tests:")} All passed`);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
p.log.message(`${picocolors_1.default.green("✓ Passed:")} ${summary.passed}`);
|
|
227
|
+
p.log.message(`${picocolors_1.default.red("✗ Failed:")} ${summary.failed}`);
|
|
228
|
+
if (summary.failedTests.length > 0) {
|
|
229
|
+
p.log.message("");
|
|
230
|
+
p.log.message(picocolors_1.default.red(picocolors_1.default.bold("Failed tests:")));
|
|
231
|
+
for (const test of summary.failedTests.slice(0, 10)) {
|
|
232
|
+
p.log.message(picocolors_1.default.red(` ✗ ${test}`));
|
|
233
|
+
}
|
|
234
|
+
if (summary.failedTests.length > 10) {
|
|
235
|
+
p.log.message(picocolors_1.default.dim(` ... and ${summary.failedTests.length - 10} more`));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
p.log.message(picocolors_1.default.dim("─".repeat(50)));
|
|
241
|
+
if (summary.compileSuccess && summary.failed === 0) {
|
|
242
|
+
p.outro(picocolors_1.default.green("✨ All tests passed!"));
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
p.outro(picocolors_1.default.yellow("Some issues need attention"));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// =============================================================================
|
|
249
|
+
// Main Command
|
|
250
|
+
// =============================================================================
|
|
251
|
+
async function testAllExamples(cliExamples) {
|
|
252
|
+
p.intro(picocolors_1.default.cyan("🧪 FHEVM Example Tester"));
|
|
253
|
+
const examplesToTest = await getExamplesToTest(cliExamples);
|
|
254
|
+
if (examplesToTest.length === 0) {
|
|
255
|
+
p.log.warning("No examples selected");
|
|
256
|
+
p.outro(picocolors_1.default.dim("Nothing to test"));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
p.log.message("");
|
|
260
|
+
p.log.message(`📦 Testing ${picocolors_1.default.bold(String(examplesToTest.length))} examples...`);
|
|
261
|
+
const tempDir = path.join((0, utils_1.getRootDir)(), ".test-temp");
|
|
262
|
+
if (fs.existsSync(tempDir)) {
|
|
263
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
264
|
+
}
|
|
265
|
+
let summary;
|
|
266
|
+
try {
|
|
267
|
+
const s = p.spinner();
|
|
268
|
+
s.start("Setting up test project...");
|
|
269
|
+
await createTestProject(examplesToTest, tempDir);
|
|
270
|
+
s.stop(picocolors_1.default.green("✓ Project ready"));
|
|
271
|
+
summary = await runTestPipeline(tempDir, examplesToTest.length);
|
|
272
|
+
}
|
|
273
|
+
finally {
|
|
274
|
+
if (fs.existsSync(tempDir)) {
|
|
275
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
showSummary(summary);
|
|
279
|
+
}
|
|
280
|
+
// =============================================================================
|
|
281
|
+
// CLI Entry Point
|
|
282
|
+
// =============================================================================
|
|
283
|
+
function showHelp() {
|
|
284
|
+
utils_1.log.info("🔧 FHEVM Maintenance Tools");
|
|
285
|
+
utils_1.log.message("");
|
|
286
|
+
utils_1.log.message("Available commands:");
|
|
287
|
+
utils_1.log.message("");
|
|
288
|
+
utils_1.log.message(" test-all Test examples");
|
|
289
|
+
utils_1.log.message("");
|
|
290
|
+
utils_1.log.message("Usage:");
|
|
291
|
+
utils_1.log.dim(" npm run test:all");
|
|
292
|
+
utils_1.log.dim(" npm run test:all fhe-counter,fhe-add");
|
|
293
|
+
}
|
|
294
|
+
async function main() {
|
|
295
|
+
const args = process.argv.slice(2);
|
|
296
|
+
// Check for help flag first
|
|
297
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
298
|
+
showHelp();
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const command = args[0];
|
|
302
|
+
switch (command) {
|
|
303
|
+
case "test-all": {
|
|
304
|
+
const exampleArg = args[1];
|
|
305
|
+
// Filter out help flags from example list
|
|
306
|
+
const examples = exampleArg && !exampleArg.startsWith("-")
|
|
307
|
+
? exampleArg.split(",")
|
|
308
|
+
: undefined;
|
|
309
|
+
await testAllExamples(examples);
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
default:
|
|
313
|
+
showHelp();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// Only run if this is the main module
|
|
317
|
+
const isMainModule = process.argv[1]?.includes("maintenance");
|
|
318
|
+
if (isMainModule) {
|
|
319
|
+
main().catch(console.error);
|
|
320
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../scripts/ui.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiBH;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMjE;AAMD;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,CAmBrE;AAED;;GAEG;AACH,wBAAsB,+BAA+B,CACnD,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,CAe1B;AAED;;GAEG;AACH,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,CAS5E;AAMD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiD1E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAOzD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* User Interface - Prompts & Commands
|
|
4
|
+
*
|
|
5
|
+
* Interactive prompts and command execution for CLI.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.countExamplesPerCategory = countExamplesPerCategory;
|
|
45
|
+
exports.promptSelectCategory = promptSelectCategory;
|
|
46
|
+
exports.promptSelectExampleFromCategory = promptSelectExampleFromCategory;
|
|
47
|
+
exports.promptSelectCategoryProject = promptSelectCategoryProject;
|
|
48
|
+
exports.runInstallAndTest = runInstallAndTest;
|
|
49
|
+
exports.showQuickStart = showQuickStart;
|
|
50
|
+
exports.askInstallAndTest = askInstallAndTest;
|
|
51
|
+
const p = __importStar(require("@clack/prompts"));
|
|
52
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
53
|
+
const config_1 = require("./config");
|
|
54
|
+
const utils_1 = require("./utils");
|
|
55
|
+
// =============================================================================
|
|
56
|
+
// Category Helpers
|
|
57
|
+
// =============================================================================
|
|
58
|
+
/**
|
|
59
|
+
* Counts how many examples exist in each category
|
|
60
|
+
*/
|
|
61
|
+
function countExamplesPerCategory() {
|
|
62
|
+
const counts = {};
|
|
63
|
+
for (const config of Object.values(config_1.EXAMPLES)) {
|
|
64
|
+
counts[config.category] = (counts[config.category] || 0) + 1;
|
|
65
|
+
}
|
|
66
|
+
return counts;
|
|
67
|
+
}
|
|
68
|
+
// =============================================================================
|
|
69
|
+
// Selection Prompts
|
|
70
|
+
// =============================================================================
|
|
71
|
+
/**
|
|
72
|
+
* Prompts user to select a category
|
|
73
|
+
*/
|
|
74
|
+
async function promptSelectCategory() {
|
|
75
|
+
const categoryCounts = countExamplesPerCategory();
|
|
76
|
+
const allCategories = Object.keys(categoryCounts);
|
|
77
|
+
const orderedCategories = [
|
|
78
|
+
...utils_1.CATEGORY_ORDER.filter((cat) => allCategories.includes(cat)),
|
|
79
|
+
...allCategories.filter((cat) => !utils_1.CATEGORY_ORDER.includes(cat)).sort(),
|
|
80
|
+
];
|
|
81
|
+
return p.select({
|
|
82
|
+
message: "Select a category:",
|
|
83
|
+
options: orderedCategories.map((category) => ({
|
|
84
|
+
value: category,
|
|
85
|
+
label: `${utils_1.CATEGORY_ICON} ${category}`,
|
|
86
|
+
hint: `${categoryCounts[category] || 0} example${categoryCounts[category] !== 1 ? "s" : ""}`,
|
|
87
|
+
})),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Prompts user to select an example from a specific category
|
|
92
|
+
*/
|
|
93
|
+
async function promptSelectExampleFromCategory(category) {
|
|
94
|
+
const categoryExamples = Object.entries(config_1.EXAMPLES)
|
|
95
|
+
.filter(([, config]) => config.category === category)
|
|
96
|
+
.map(([key, config]) => ({
|
|
97
|
+
value: key,
|
|
98
|
+
label: key,
|
|
99
|
+
hint: config.description.slice(0, utils_1.MAX_DESCRIPTION_LENGTH) +
|
|
100
|
+
(config.description.length > utils_1.MAX_DESCRIPTION_LENGTH ? "..." : ""),
|
|
101
|
+
}));
|
|
102
|
+
return p.select({
|
|
103
|
+
message: `Select an example from ${category}:`,
|
|
104
|
+
options: categoryExamples,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Prompts user to select a category project
|
|
109
|
+
*/
|
|
110
|
+
async function promptSelectCategoryProject() {
|
|
111
|
+
return p.select({
|
|
112
|
+
message: "Select a category:",
|
|
113
|
+
options: Object.entries(config_1.CATEGORIES).map(([key, config]) => ({
|
|
114
|
+
value: key,
|
|
115
|
+
label: `${utils_1.CATEGORY_ICON} ${config.name}`,
|
|
116
|
+
hint: `${config.contracts.length} contracts`,
|
|
117
|
+
})),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// =============================================================================
|
|
121
|
+
// Install & Test Commands
|
|
122
|
+
// =============================================================================
|
|
123
|
+
/**
|
|
124
|
+
* Runs npm install, compile, and test in the project directory
|
|
125
|
+
*/
|
|
126
|
+
async function runInstallAndTest(projectPath) {
|
|
127
|
+
const steps = [
|
|
128
|
+
{
|
|
129
|
+
name: "Installing dependencies",
|
|
130
|
+
cmd: "npm",
|
|
131
|
+
args: ["install"],
|
|
132
|
+
showOutput: false,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: "Compiling contracts",
|
|
136
|
+
cmd: "npm",
|
|
137
|
+
args: ["run", "compile"],
|
|
138
|
+
showOutput: false,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: "Running tests",
|
|
142
|
+
cmd: "npm",
|
|
143
|
+
args: ["run", "test"],
|
|
144
|
+
showOutput: true,
|
|
145
|
+
},
|
|
146
|
+
];
|
|
147
|
+
for (const step of steps) {
|
|
148
|
+
const s = p.spinner();
|
|
149
|
+
s.start(step.name + "...");
|
|
150
|
+
try {
|
|
151
|
+
const output = await (0, utils_1.runCommand)(step.cmd, step.args, projectPath);
|
|
152
|
+
if (step.showOutput) {
|
|
153
|
+
const testResults = (0, utils_1.extractTestResults)(output);
|
|
154
|
+
s.stop(testResults
|
|
155
|
+
? picocolors_1.default.green(`✓ ${step.name} - ${testResults}`)
|
|
156
|
+
: picocolors_1.default.green(`✓ ${step.name} completed`));
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
s.stop(picocolors_1.default.green(`✓ ${step.name} completed`));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
s.stop(picocolors_1.default.red(`✗ ${step.name} failed`));
|
|
164
|
+
if (error instanceof Error) {
|
|
165
|
+
p.log.error(error.message);
|
|
166
|
+
}
|
|
167
|
+
throw new Error(`${step.name} failed`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
p.log.success(picocolors_1.default.green("🔐 All encryption tests passed!"));
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Shows quick start commands for the created project
|
|
174
|
+
*/
|
|
175
|
+
function showQuickStart(relativePath) {
|
|
176
|
+
p.note(`${picocolors_1.default.dim("$")} cd ${relativePath}\n${picocolors_1.default.dim("$")} npm install\n${picocolors_1.default.dim("$")} npm run compile\n${picocolors_1.default.dim("$")} npm run test`, "🚀 Quick Start");
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Asks user if they want to install and test
|
|
180
|
+
*/
|
|
181
|
+
async function askInstallAndTest(resolvedOutput, relativePath) {
|
|
182
|
+
const shouldInstall = await p.confirm({
|
|
183
|
+
message: "Install dependencies and run tests?",
|
|
184
|
+
initialValue: false,
|
|
185
|
+
});
|
|
186
|
+
if (p.isCancel(shouldInstall)) {
|
|
187
|
+
showQuickStart(relativePath);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (shouldInstall) {
|
|
191
|
+
p.log.message("");
|
|
192
|
+
await runInstallAndTest(resolvedOutput);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
showQuickStart(relativePath);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for FHEVM Example Factory CLI
|
|
3
|
+
*/
|
|
4
|
+
export type ProjectMode = "single" | "category";
|
|
5
|
+
export declare const CATEGORY_ICON = "\uD83D\uDCC1";
|
|
6
|
+
/** Template directory name within the cloned repo */
|
|
7
|
+
export declare const TEMPLATE_DIR_NAME = "fhevm-hardhat-template";
|
|
8
|
+
/** Maximum description length for UI display */
|
|
9
|
+
export declare const MAX_DESCRIPTION_LENGTH = 80;
|
|
10
|
+
/** Directories to exclude when copying template */
|
|
11
|
+
export declare const EXCLUDE_DIRS: string[];
|
|
12
|
+
/** FHEVM package versions for --add mode */
|
|
13
|
+
export declare const FHEVM_DEPENDENCIES: {
|
|
14
|
+
dependencies: {
|
|
15
|
+
"encrypted-types": string;
|
|
16
|
+
"@fhevm/solidity": string;
|
|
17
|
+
};
|
|
18
|
+
devDependencies: {
|
|
19
|
+
"@fhevm/hardhat-plugin": string;
|
|
20
|
+
"@zama-fhe/relayer-sdk": string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export declare const CATEGORY_ORDER: string[];
|
|
24
|
+
export declare const TEST_TYPES_CONTENT = "import type { HardhatEthersSigner } from \"@nomicfoundation/hardhat-ethers/signers\";\n\n/**\n * Common signers interface used across test files\n */\nexport interface Signers {\n owner: HardhatEthersSigner;\n alice: HardhatEthersSigner;\n}\n";
|
|
25
|
+
export declare const ERROR_MESSAGES: {
|
|
26
|
+
EXAMPLE_REQUIRED: string;
|
|
27
|
+
BOTH_SPECIFIED: string;
|
|
28
|
+
UNKNOWN_EXAMPLE: (name: string) => string;
|
|
29
|
+
UNKNOWN_CATEGORY: (name: string) => string;
|
|
30
|
+
DIR_EXISTS: (path: string) => string;
|
|
31
|
+
NOT_HARDHAT: string;
|
|
32
|
+
CONFIG_NOT_FOUND: string;
|
|
33
|
+
CONTRACT_NAME_FAILED: string;
|
|
34
|
+
};
|
|
35
|
+
export declare const log: {
|
|
36
|
+
success: (msg: string) => void;
|
|
37
|
+
error: (msg: string) => void;
|
|
38
|
+
info: (msg: string) => void;
|
|
39
|
+
dim: (msg: string) => void;
|
|
40
|
+
message: (msg: string) => void;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Standardized error handler for CLI - logs error and exits
|
|
44
|
+
*/
|
|
45
|
+
export declare function handleError(error: unknown, exitCode?: number): never;
|
|
46
|
+
/** Resolves root directory of the project */
|
|
47
|
+
export declare function getRootDir(): string;
|
|
48
|
+
export declare function getTemplateDir(): string;
|
|
49
|
+
/** Extracts contract name from file path or content */
|
|
50
|
+
export declare function getContractName(contractPathOrContent: string): string | null;
|
|
51
|
+
/** Copies directory recursively, excluding specified directories */
|
|
52
|
+
export declare function copyDirectoryRecursive(source: string, destination: string, excludeDirs?: string[]): void;
|
|
53
|
+
export declare function toKebabCase(str: string): string;
|
|
54
|
+
export declare function contractNameToExampleName(contractName: string): string;
|
|
55
|
+
export declare function contractNameToTitle(contractName: string): string;
|
|
56
|
+
export declare function formatCategoryName(folderName: string): string;
|
|
57
|
+
export declare function validateExample(name: string): void;
|
|
58
|
+
export declare function validateCategory(name: string): void;
|
|
59
|
+
export declare function validateDirectoryNotExists(dirPath: string): void;
|
|
60
|
+
export declare function cleanupTemplate(outputDir: string): void;
|
|
61
|
+
export declare function generateDeployScript(contractName: string): string;
|
|
62
|
+
export declare function generateGitBookMarkdown(description: string, contractContent: string, testContent: string, contractName: string, testFileName: string): string;
|
|
63
|
+
/** Downloads a file from GitHub repository */
|
|
64
|
+
export declare function downloadFileFromGitHub(filePath: string, outputPath: string): Promise<void>;
|
|
65
|
+
/** Clones the template repository to temp directory */
|
|
66
|
+
export declare function cloneTemplate(tempDir: string): Promise<string>;
|
|
67
|
+
/** Initializes git submodule for the template */
|
|
68
|
+
export declare function initSubmodule(repoPath: string): Promise<void>;
|
|
69
|
+
/** Updates package.json with project name, description, and npm dependencies */
|
|
70
|
+
export declare function updateProjectPackageJson(outputDir: string, projectName: string, description?: string, npmDependencies?: Record<string, string>): void;
|
|
71
|
+
/** Executes a command and returns output */
|
|
72
|
+
export declare function runCommand(cmd: string, args: string[], cwd: string): Promise<string>;
|
|
73
|
+
export declare function runCommandWithStatus(cmd: string, args: string[], cwd: string): Promise<{
|
|
74
|
+
success: boolean;
|
|
75
|
+
output: string;
|
|
76
|
+
}>;
|
|
77
|
+
export declare function extractTestResults(output: string): string | null;
|
|
78
|
+
export declare function extractErrorMessage(output: string): string;
|
|
79
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../scripts/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEhD,eAAO,MAAM,aAAa,iBAAO,CAAC;AAElC,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,2BAA2B,CAAC;AAE1D,gDAAgD;AAChD,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,mDAAmD;AACnD,eAAO,MAAM,YAAY,UAQxB,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,kBAAkB;;;;;;;;;CAS9B,CAAC;AAEF,eAAO,MAAM,cAAc,UAQ1B,CAAC;AAEF,eAAO,MAAM,kBAAkB,yPAS9B,CAAC;AAEF,eAAO,MAAM,cAAc;;;4BAGD,MAAM;6BACL,MAAM;uBACZ,MAAM;;;;CAI1B,CAAC;AAMF,eAAO,MAAM,GAAG;mBACC,MAAM;iBACR,MAAM;gBACP,MAAM;eACP,MAAM;mBACF,MAAM;CACtB,CAAC;AAEF;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,SAAI,GAAG,KAAK,CAI/D;AAMD,6CAA6C;AAC7C,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,uDAAuD;AACvD,wBAAgB,eAAe,CAAC,qBAAqB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqB5E;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,GAAE,MAAM,EAAiB,GACnC,IAAI,CAoBN;AAMD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAKhE;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAK7D;AAMD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIlD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAInD;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAIhE;AAMD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CA4CvD;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAqBjE;AAED,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,MAAM,CA2BR;AAMD,8CAA8C;AAC9C,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,uDAAuD;AACvD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmCpE;AAED,iDAAiD;AACjD,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BnE;AAMD,gFAAgF;AAChF,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACvC,IAAI,CAiBN;AAMD,4CAA4C;AAC5C,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CA+BjB;AAED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA2B/C;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAchE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA4B1D"}
|