create-fhevm-example 1.2.3 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -146
- package/dist/scripts/add-mode.d.ts +11 -0
- package/dist/scripts/add-mode.d.ts.map +1 -0
- package/dist/{add-mode.js → scripts/add-mode.js} +84 -58
- package/dist/scripts/builders.d.ts +19 -0
- package/dist/scripts/builders.d.ts.map +1 -0
- package/dist/scripts/builders.js +211 -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 +11 -0
- package/dist/scripts/doctor.d.ts.map +1 -0
- package/dist/scripts/doctor.js +165 -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 +323 -0
- package/dist/scripts/generate-docs.d.ts +10 -0
- package/dist/scripts/generate-docs.d.ts.map +1 -0
- package/dist/scripts/generate-docs.js +190 -0
- package/dist/scripts/index.d.ts +12 -0
- package/dist/scripts/index.d.ts.map +1 -0
- package/dist/scripts/index.js +384 -0
- package/dist/scripts/maintenance.d.ts +13 -0
- package/dist/scripts/maintenance.d.ts.map +1 -0
- package/dist/scripts/maintenance.js +271 -0
- package/dist/{prompts.d.ts → scripts/ui.d.ts} +8 -7
- package/dist/scripts/ui.d.ts.map +1 -0
- package/dist/scripts/ui.js +170 -0
- package/dist/scripts/utils.d.ts +86 -0
- package/dist/scripts/utils.d.ts.map +1 -0
- package/dist/scripts/utils.js +525 -0
- package/package.json +25 -13
- 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 -398
- 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.map +0 -1
- package/dist/prompts.js +0 -79
- package/dist/prompts.js.map +0 -1
- package/dist/ui.d.ts +0 -35
- 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,384 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* create-fhevm-example - CLI for creating FHEVM example projects
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx create-fhevm-example # Interactive mode
|
|
8
|
+
* npx create-fhevm-example --example <name> # Create single example
|
|
9
|
+
* npx create-fhevm-example --category <name> # Create category project
|
|
10
|
+
* npx create-fhevm-example --add # Add to existing project
|
|
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
|
+
const p = __importStar(require("@clack/prompts"));
|
|
50
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
51
|
+
const fs = __importStar(require("fs"));
|
|
52
|
+
const path = __importStar(require("path"));
|
|
53
|
+
const os = __importStar(require("os"));
|
|
54
|
+
const config_1 = require("./config");
|
|
55
|
+
const utils_1 = require("./utils");
|
|
56
|
+
const builders_1 = require("./builders");
|
|
57
|
+
const ui_1 = require("./ui");
|
|
58
|
+
const add_mode_1 = require("./add-mode");
|
|
59
|
+
const generate_docs_1 = require("./generate-docs");
|
|
60
|
+
/** Prompts user to select mode and returns project configuration */
|
|
61
|
+
async function getProjectConfig() {
|
|
62
|
+
// Build options - docs only available in local dev mode
|
|
63
|
+
const options = [
|
|
64
|
+
{
|
|
65
|
+
value: "single",
|
|
66
|
+
label: "Create a single example project",
|
|
67
|
+
hint: "One example contract with tests",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
value: "category",
|
|
71
|
+
label: "Create a category-based project",
|
|
72
|
+
hint: "Bundle all examples from a category",
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
// Add docs option only in local dev mode (npm run create)
|
|
76
|
+
if (process.env.LOCAL_DEV === "1") {
|
|
77
|
+
options.push({
|
|
78
|
+
value: "docs",
|
|
79
|
+
label: "Generate documentation",
|
|
80
|
+
hint: "Generate GitBook docs for examples",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const mode = await p.select({
|
|
84
|
+
message: "What would you like to create?",
|
|
85
|
+
options,
|
|
86
|
+
});
|
|
87
|
+
if (p.isCancel(mode)) {
|
|
88
|
+
p.cancel("Operation cancelled.");
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
let name;
|
|
92
|
+
if (mode === "single") {
|
|
93
|
+
const category = await (0, ui_1.promptSelectCategory)();
|
|
94
|
+
if (p.isCancel(category)) {
|
|
95
|
+
p.cancel("Operation cancelled.");
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const example = await (0, ui_1.promptSelectExampleFromCategory)(category);
|
|
99
|
+
if (p.isCancel(example)) {
|
|
100
|
+
p.cancel("Operation cancelled.");
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
name = example;
|
|
104
|
+
}
|
|
105
|
+
else if (mode === "docs") {
|
|
106
|
+
// Handle docs mode - call generate-docs interactive
|
|
107
|
+
await (0, generate_docs_1.handleInteractiveDocs)();
|
|
108
|
+
return null; // Exit after docs generation
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const category = await (0, ui_1.promptSelectCategoryProject)();
|
|
112
|
+
if (p.isCancel(category)) {
|
|
113
|
+
p.cancel("Operation cancelled.");
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
name = category;
|
|
117
|
+
}
|
|
118
|
+
const projectName = await p.text({
|
|
119
|
+
message: "Project name:",
|
|
120
|
+
placeholder: `my-${name}-project`,
|
|
121
|
+
defaultValue: `my-${name}-project`,
|
|
122
|
+
});
|
|
123
|
+
if (p.isCancel(projectName)) {
|
|
124
|
+
p.cancel("Operation cancelled.");
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const outputDir = await p.text({
|
|
128
|
+
message: "Output directory:",
|
|
129
|
+
placeholder: `./${projectName}`,
|
|
130
|
+
defaultValue: `./${projectName}`,
|
|
131
|
+
});
|
|
132
|
+
if (p.isCancel(outputDir)) {
|
|
133
|
+
p.cancel("Operation cancelled.");
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const shouldInstall = await p.confirm({
|
|
137
|
+
message: "Install dependencies and run tests?",
|
|
138
|
+
initialValue: false,
|
|
139
|
+
});
|
|
140
|
+
if (p.isCancel(shouldInstall)) {
|
|
141
|
+
p.cancel("Operation cancelled.");
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
mode: mode,
|
|
146
|
+
name,
|
|
147
|
+
outputDir: outputDir,
|
|
148
|
+
shouldInstall: shouldInstall,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/** Scaffolds project and shows completion message */
|
|
152
|
+
async function scaffoldProject(config) {
|
|
153
|
+
const resolvedOutput = path.resolve(process.cwd(), config.outputDir);
|
|
154
|
+
if (fs.existsSync(resolvedOutput)) {
|
|
155
|
+
p.log.error(`Directory already exists: ${resolvedOutput}`);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "fhevm-"));
|
|
159
|
+
const s = p.spinner();
|
|
160
|
+
try {
|
|
161
|
+
s.start("Downloading template...");
|
|
162
|
+
const tempRepoPath = await (0, utils_1.cloneTemplate)(tempDir);
|
|
163
|
+
s.message("Initializing submodules...");
|
|
164
|
+
await (0, utils_1.initSubmodule)(tempRepoPath);
|
|
165
|
+
s.message("Scaffolding your confidential project...");
|
|
166
|
+
if (config.mode === "single") {
|
|
167
|
+
await (0, builders_1.createSingleExample)(config.name, resolvedOutput, tempRepoPath);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
await (0, builders_1.createCategoryProject)(config.name, resolvedOutput, tempRepoPath);
|
|
171
|
+
}
|
|
172
|
+
s.stop("🎉 Project scaffolded successfully!");
|
|
173
|
+
const relativePath = path.relative(process.cwd(), resolvedOutput);
|
|
174
|
+
p.log.success(`📁 Created: ${picocolors_1.default.cyan(relativePath)}`);
|
|
175
|
+
if (config.mode === "single") {
|
|
176
|
+
const exampleConfig = config_1.EXAMPLES[config.name];
|
|
177
|
+
if (exampleConfig) {
|
|
178
|
+
p.log.info(`📝 Example: ${picocolors_1.default.yellow(exampleConfig.title)}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
const categoryConfig = config_1.CATEGORIES[config.name];
|
|
183
|
+
if (categoryConfig) {
|
|
184
|
+
p.log.info(`📦 Category: ${picocolors_1.default.yellow(categoryConfig.name)}`);
|
|
185
|
+
p.log.info(`📄 Contracts: ${picocolors_1.default.green(String(categoryConfig.contracts.length))}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (config.shouldInstall) {
|
|
189
|
+
p.log.message("");
|
|
190
|
+
await (0, ui_1.runInstallAndTest)(resolvedOutput);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
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");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
s.stop(picocolors_1.default.red("Failed to create project"));
|
|
198
|
+
p.log.error(error instanceof Error ? error.message : String(error));
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
if (fs.existsSync(tempDir)) {
|
|
203
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
p.outro(picocolors_1.default.green("✅ Setup complete. Happy encrypting!"));
|
|
207
|
+
}
|
|
208
|
+
/** Main interactive mode entry point */
|
|
209
|
+
async function runInteractiveMode() {
|
|
210
|
+
console.clear();
|
|
211
|
+
p.intro(picocolors_1.default.bgCyan(picocolors_1.default.black(" ⚡ FHEVM Example Factory ")));
|
|
212
|
+
const config = await getProjectConfig();
|
|
213
|
+
if (!config)
|
|
214
|
+
return;
|
|
215
|
+
await scaffoldProject(config);
|
|
216
|
+
}
|
|
217
|
+
function parseArgs(args) {
|
|
218
|
+
const parsed = {};
|
|
219
|
+
for (let i = 0; i < args.length; i++) {
|
|
220
|
+
const arg = args[i];
|
|
221
|
+
if (arg.startsWith("--")) {
|
|
222
|
+
const key = arg.slice(2);
|
|
223
|
+
const nextArg = args[i + 1];
|
|
224
|
+
if (nextArg && !nextArg.startsWith("--")) {
|
|
225
|
+
parsed[key] = nextArg;
|
|
226
|
+
i++;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
parsed[key] = true;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
else if (arg === "-h") {
|
|
233
|
+
parsed["help"] = true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return parsed;
|
|
237
|
+
}
|
|
238
|
+
async function runDirectMode(args) {
|
|
239
|
+
const parsedArgs = parseArgs(args);
|
|
240
|
+
if (parsedArgs["help"]) {
|
|
241
|
+
showHelp();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (parsedArgs["add"]) {
|
|
245
|
+
const targetDir = parsedArgs["target"];
|
|
246
|
+
await (0, add_mode_1.runAddMode)(targetDir);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const exampleName = parsedArgs["example"];
|
|
250
|
+
const categoryName = parsedArgs["category"];
|
|
251
|
+
const outputDir = parsedArgs["output"];
|
|
252
|
+
const shouldInstall = parsedArgs["install"] === true;
|
|
253
|
+
if (!exampleName && !categoryName) {
|
|
254
|
+
utils_1.log.error(utils_1.ERROR_MESSAGES.EXAMPLE_REQUIRED);
|
|
255
|
+
showHelp();
|
|
256
|
+
(0, utils_1.handleError)("Missing required argument");
|
|
257
|
+
}
|
|
258
|
+
if (exampleName && categoryName) {
|
|
259
|
+
(0, utils_1.handleError)(utils_1.ERROR_MESSAGES.BOTH_SPECIFIED);
|
|
260
|
+
}
|
|
261
|
+
const mode = exampleName ? "example" : "category";
|
|
262
|
+
const name = (exampleName || categoryName);
|
|
263
|
+
try {
|
|
264
|
+
if (mode === "example") {
|
|
265
|
+
(0, utils_1.validateExample)(name);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
(0, utils_1.validateCategory)(name);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
utils_1.log.message("Available: " +
|
|
273
|
+
Object.keys(mode === "example" ? config_1.EXAMPLES : config_1.CATEGORIES).join(", "));
|
|
274
|
+
(0, utils_1.handleError)(error);
|
|
275
|
+
}
|
|
276
|
+
const defaultOutput = mode === "example" ? `./my-${name}-project` : `./my-${name}-examples`;
|
|
277
|
+
const output = outputDir || defaultOutput;
|
|
278
|
+
const resolved = path.resolve(process.cwd(), output);
|
|
279
|
+
try {
|
|
280
|
+
(0, utils_1.validateDirectoryNotExists)(resolved);
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
(0, utils_1.handleError)(error);
|
|
284
|
+
}
|
|
285
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "fhevm-"));
|
|
286
|
+
try {
|
|
287
|
+
utils_1.log.info(`\n🚀 Creating ${mode}: ${picocolors_1.default.yellow(name)}`);
|
|
288
|
+
utils_1.log.dim("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
289
|
+
utils_1.log.dim("Downloading template...");
|
|
290
|
+
const tempRepoPath = await (0, utils_1.cloneTemplate)(tempDir);
|
|
291
|
+
utils_1.log.dim("Initializing submodules...");
|
|
292
|
+
await (0, utils_1.initSubmodule)(tempRepoPath);
|
|
293
|
+
utils_1.log.dim("Building project...");
|
|
294
|
+
if (mode === "example") {
|
|
295
|
+
await (0, builders_1.createSingleExample)(name, resolved, tempRepoPath);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
await (0, builders_1.createCategoryProject)(name, resolved, tempRepoPath);
|
|
299
|
+
}
|
|
300
|
+
utils_1.log.success(`\n✨ Successfully created: ${picocolors_1.default.cyan(output)}`);
|
|
301
|
+
if (shouldInstall) {
|
|
302
|
+
utils_1.log.dim("Installing dependencies and running tests...");
|
|
303
|
+
await (0, ui_1.runInstallAndTest)(resolved);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
utils_1.log.message(picocolors_1.default.dim("\nNext steps:"));
|
|
307
|
+
utils_1.log.message(` ${picocolors_1.default.cyan("cd")} ${output}`);
|
|
308
|
+
utils_1.log.message(` ${picocolors_1.default.cyan("npm install")}`);
|
|
309
|
+
utils_1.log.message(` ${picocolors_1.default.cyan("npm run compile")}`);
|
|
310
|
+
utils_1.log.message(` ${picocolors_1.default.cyan("npm run test")}`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
(0, utils_1.handleError)(error);
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
if (fs.existsSync(tempDir)) {
|
|
318
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// =============================================================================
|
|
323
|
+
// QUICK MODE (CLI Arguments)
|
|
324
|
+
// =============================================================================
|
|
325
|
+
function showHelp() {
|
|
326
|
+
console.log(`
|
|
327
|
+
${picocolors_1.default.bgCyan(picocolors_1.default.black(picocolors_1.default.bold(" 🔐 create-fhevm-example ")))}
|
|
328
|
+
${picocolors_1.default.dim("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")}
|
|
329
|
+
|
|
330
|
+
${picocolors_1.default.cyan(picocolors_1.default.bold("📋 USAGE"))}
|
|
331
|
+
|
|
332
|
+
${picocolors_1.default.dim("$")} ${picocolors_1.default.white("npx create-fhevm-example")} ${picocolors_1.default.dim("→")} Interactive mode ${picocolors_1.default.yellow("(recommended)")}
|
|
333
|
+
${picocolors_1.default.dim("$")} ${picocolors_1.default.white("npx create-fhevm-example")} ${picocolors_1.default.green("--example")} ${picocolors_1.default.yellow("<name>")} ${picocolors_1.default.dim("→")} Create single example
|
|
334
|
+
${picocolors_1.default.dim("$")} ${picocolors_1.default.white("npx create-fhevm-example")} ${picocolors_1.default.green("--category")} ${picocolors_1.default.yellow("<name>")} ${picocolors_1.default.dim("→")} Create category project
|
|
335
|
+
${picocolors_1.default.dim("$")} ${picocolors_1.default.white("npx create-fhevm-example")} ${picocolors_1.default.green("--add")} ${picocolors_1.default.dim("→")} Add to existing project
|
|
336
|
+
|
|
337
|
+
${picocolors_1.default.cyan(picocolors_1.default.bold("⚙️ OPTIONS"))}
|
|
338
|
+
|
|
339
|
+
${picocolors_1.default.green("--example")} ${picocolors_1.default.dim("<name>")} Create a single example project
|
|
340
|
+
${picocolors_1.default.green("--category")} ${picocolors_1.default.dim("<name>")} Create a category project
|
|
341
|
+
${picocolors_1.default.green("--add")} Add FHEVM to existing Hardhat project
|
|
342
|
+
${picocolors_1.default.green("--target")} ${picocolors_1.default.dim("<dir>")} Target directory for --add mode
|
|
343
|
+
${picocolors_1.default.green("--output")} ${picocolors_1.default.dim("<dir>")} Output directory
|
|
344
|
+
${picocolors_1.default.green("--install")} Auto-install dependencies
|
|
345
|
+
${picocolors_1.default.green("--test")} Auto-run tests (requires --install)
|
|
346
|
+
${picocolors_1.default.green("--help")}${picocolors_1.default.dim(", -h")} Show this help message
|
|
347
|
+
|
|
348
|
+
${picocolors_1.default.cyan(picocolors_1.default.bold("⚡ EXAMPLES"))}
|
|
349
|
+
|
|
350
|
+
${picocolors_1.default.dim("$")} ${picocolors_1.default.white("npx create-fhevm-example")} ${picocolors_1.default.green("--example")} ${picocolors_1.default.yellow("fhe-counter")}
|
|
351
|
+
${picocolors_1.default.dim("$")} ${picocolors_1.default.white("npx create-fhevm-example")} ${picocolors_1.default.green("--category")} ${picocolors_1.default.yellow("basic")} ${picocolors_1.default.green("--output")} ${picocolors_1.default.blue("./my-project")}
|
|
352
|
+
${picocolors_1.default.dim("$")} ${picocolors_1.default.white("npx create-fhevm-example")} ${picocolors_1.default.green("--add")}
|
|
353
|
+
${picocolors_1.default.dim("$")} ${picocolors_1.default.white("npx create-fhevm-example")} ${picocolors_1.default.green("--example")} ${picocolors_1.default.yellow("fhe-counter")} ${picocolors_1.default.green("--install")} ${picocolors_1.default.green("--test")}
|
|
354
|
+
|
|
355
|
+
${picocolors_1.default.cyan(picocolors_1.default.bold("📦 AVAILABLE EXAMPLES"))}
|
|
356
|
+
|
|
357
|
+
${picocolors_1.default.dim(Object.keys(config_1.EXAMPLES).slice(0, 10).join(", "))}
|
|
358
|
+
${picocolors_1.default.dim("...")} and ${picocolors_1.default.yellow(String(Object.keys(config_1.EXAMPLES).length - 10))} more
|
|
359
|
+
|
|
360
|
+
${picocolors_1.default.cyan(picocolors_1.default.bold("📁 AVAILABLE CATEGORIES"))}
|
|
361
|
+
|
|
362
|
+
${Object.keys(config_1.CATEGORIES)
|
|
363
|
+
.map((c) => picocolors_1.default.yellow(c))
|
|
364
|
+
.join(", ")}
|
|
365
|
+
|
|
366
|
+
${picocolors_1.default.dim("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")}
|
|
367
|
+
${picocolors_1.default.dim("📚 Documentation:")} ${picocolors_1.default.blue("https://github.com/NecipAkgz/fhevm-example-factory")}
|
|
368
|
+
`);
|
|
369
|
+
}
|
|
370
|
+
// =============================================================================
|
|
371
|
+
// MAIN ENTRY POINT
|
|
372
|
+
// =============================================================================
|
|
373
|
+
async function main() {
|
|
374
|
+
const args = process.argv.slice(2);
|
|
375
|
+
if (args.length > 0) {
|
|
376
|
+
await runDirectMode(args);
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
await runInteractiveMode();
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
main().catch((error) => {
|
|
383
|
+
(0, utils_1.handleError)(error);
|
|
384
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Maintenance Tools - Utilities for project maintenance and testing.
|
|
4
|
+
*
|
|
5
|
+
* Includes the test-all runner which allows for efficient testing
|
|
6
|
+
* of multiple examples in a temporary workspace.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npm run test:all # Interactive selection
|
|
10
|
+
* npm run test:all fhe-counter,fhe-add # Direct CLI
|
|
11
|
+
*/
|
|
12
|
+
export declare function testAllExamples(cliExamples?: string[]): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=maintenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maintenance.d.ts","sourceRoot":"","sources":["../../scripts/maintenance.ts"],"names":[],"mappings":";AAEA;;;;;;;;;GASG;AAwNH,wBAAsB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC3E"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Maintenance Tools - Utilities for project maintenance and testing.
|
|
5
|
+
*
|
|
6
|
+
* Includes the test-all runner which allows for efficient testing
|
|
7
|
+
* of multiple examples in a temporary workspace.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* npm run test:all # Interactive selection
|
|
11
|
+
* npm run test:all fhe-counter,fhe-add # Direct CLI
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
47
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.testAllExamples = testAllExamples;
|
|
51
|
+
const p = __importStar(require("@clack/prompts"));
|
|
52
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
53
|
+
const fs = __importStar(require("fs"));
|
|
54
|
+
const path = __importStar(require("path"));
|
|
55
|
+
const config_1 = require("./config");
|
|
56
|
+
const utils_1 = require("./utils");
|
|
57
|
+
const builders_1 = require("./builders");
|
|
58
|
+
// =============================================================================
|
|
59
|
+
// Example Selection
|
|
60
|
+
// =============================================================================
|
|
61
|
+
async function getExamplesToTest(cliExamples) {
|
|
62
|
+
const allExamples = (0, config_1.getExampleNames)();
|
|
63
|
+
if (cliExamples && cliExamples.length > 0) {
|
|
64
|
+
const invalid = cliExamples.filter((e) => !allExamples.includes(e));
|
|
65
|
+
if (invalid.length > 0) {
|
|
66
|
+
p.log.error(`Unknown examples: ${invalid.join(", ")}`);
|
|
67
|
+
p.log.message(picocolors_1.default.dim(`Available: ${allExamples.join(", ")}`));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
p.log.message(`Testing ${picocolors_1.default.bold(String(cliExamples.length))} examples...`);
|
|
71
|
+
return cliExamples;
|
|
72
|
+
}
|
|
73
|
+
const selected = await p.multiselect({
|
|
74
|
+
message: "Select examples to test (space to toggle, enter to confirm):",
|
|
75
|
+
options: allExamples.map((ex) => ({
|
|
76
|
+
value: ex,
|
|
77
|
+
label: ex,
|
|
78
|
+
hint: config_1.EXAMPLES[ex]?.category || "",
|
|
79
|
+
})),
|
|
80
|
+
required: true,
|
|
81
|
+
});
|
|
82
|
+
if (p.isCancel(selected)) {
|
|
83
|
+
p.cancel("Operation cancelled");
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
return selected;
|
|
87
|
+
}
|
|
88
|
+
// =============================================================================
|
|
89
|
+
// Test Runner
|
|
90
|
+
// =============================================================================
|
|
91
|
+
async function runTestPipeline(tempDir, exampleCount) {
|
|
92
|
+
const summary = {
|
|
93
|
+
totalExamples: exampleCount,
|
|
94
|
+
passed: 0,
|
|
95
|
+
failed: 0,
|
|
96
|
+
compileSuccess: false,
|
|
97
|
+
failedTests: [],
|
|
98
|
+
};
|
|
99
|
+
const s1 = p.spinner();
|
|
100
|
+
s1.start("Installing dependencies...");
|
|
101
|
+
const installResult = await (0, utils_1.runCommandWithStatus)("npm", ["install"], tempDir);
|
|
102
|
+
if (!installResult.success) {
|
|
103
|
+
s1.stop(picocolors_1.default.red("✗ npm install failed"));
|
|
104
|
+
p.log.error((0, utils_1.extractErrorMessage)(installResult.output));
|
|
105
|
+
return summary;
|
|
106
|
+
}
|
|
107
|
+
s1.stop(picocolors_1.default.green("✓ Dependencies installed"));
|
|
108
|
+
const s2 = p.spinner();
|
|
109
|
+
s2.start("Compiling contracts...");
|
|
110
|
+
const compileResult = await (0, utils_1.runCommandWithStatus)("npm", ["run", "compile"], tempDir);
|
|
111
|
+
if (!compileResult.success) {
|
|
112
|
+
s2.stop(picocolors_1.default.red("✗ Compilation failed"));
|
|
113
|
+
p.log.error((0, utils_1.extractErrorMessage)(compileResult.output));
|
|
114
|
+
return summary;
|
|
115
|
+
}
|
|
116
|
+
s2.stop(picocolors_1.default.green("✓ Contracts compiled"));
|
|
117
|
+
summary.compileSuccess = true;
|
|
118
|
+
const testDir = path.join(tempDir, "test");
|
|
119
|
+
const testFiles = fs
|
|
120
|
+
.readdirSync(testDir)
|
|
121
|
+
.filter((f) => f.endsWith(".test.ts") || f.endsWith(".ts"))
|
|
122
|
+
.filter((f) => f !== "types.ts");
|
|
123
|
+
if (testFiles.length === 0) {
|
|
124
|
+
p.log.warning("No test files found");
|
|
125
|
+
return summary;
|
|
126
|
+
}
|
|
127
|
+
p.log.message("");
|
|
128
|
+
p.log.message(picocolors_1.default.bold(`🧪 Running ${testFiles.length} test files:`));
|
|
129
|
+
p.log.message("");
|
|
130
|
+
let passedTests = 0;
|
|
131
|
+
let failedTests = 0;
|
|
132
|
+
const startTime = Date.now();
|
|
133
|
+
for (let i = 0; i < testFiles.length; i++) {
|
|
134
|
+
const testFile = testFiles[i];
|
|
135
|
+
const progress = `[${i + 1}/${testFiles.length}]`;
|
|
136
|
+
process.stdout.write(` ${picocolors_1.default.dim(progress)} ${testFile} `);
|
|
137
|
+
const testStart = Date.now();
|
|
138
|
+
const result = await (0, utils_1.runCommandWithStatus)("npx", ["hardhat", "test", `test/${testFile}`], tempDir);
|
|
139
|
+
const duration = ((Date.now() - testStart) / 1000).toFixed(1);
|
|
140
|
+
if (result.success) {
|
|
141
|
+
const testResults = (0, utils_1.extractTestResults)(result.output);
|
|
142
|
+
const resultInfo = testResults
|
|
143
|
+
? picocolors_1.default.dim(`(${testResults.replace(" ✓", "")})`)
|
|
144
|
+
: "";
|
|
145
|
+
p.log.message(picocolors_1.default.green(`✓`) + ` ${picocolors_1.default.dim(duration + "s")} ${resultInfo}`);
|
|
146
|
+
passedTests++;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
p.log.message(picocolors_1.default.red(`✗`) + ` ${picocolors_1.default.dim(duration + "s")}`);
|
|
150
|
+
failedTests++;
|
|
151
|
+
summary.failedTests.push(testFile);
|
|
152
|
+
const errorMsg = (0, utils_1.extractErrorMessage)(result.output);
|
|
153
|
+
if (errorMsg) {
|
|
154
|
+
const shortError = errorMsg.split("\n")[0].slice(0, 80);
|
|
155
|
+
p.log.message(` ${picocolors_1.default.red(picocolors_1.default.dim(shortError))}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const totalDuration = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
160
|
+
p.log.message("");
|
|
161
|
+
p.log.message(picocolors_1.default.dim(`Completed in ${totalDuration}s`));
|
|
162
|
+
summary.passed = passedTests;
|
|
163
|
+
summary.failed = failedTests;
|
|
164
|
+
return summary;
|
|
165
|
+
}
|
|
166
|
+
function showSummary(summary) {
|
|
167
|
+
p.log.message("");
|
|
168
|
+
p.log.message(picocolors_1.default.bold("📊 Test Summary"));
|
|
169
|
+
p.log.message(picocolors_1.default.dim("─".repeat(50)));
|
|
170
|
+
p.log.message(`${picocolors_1.default.blue("📦 Examples:")} ${summary.totalExamples}`);
|
|
171
|
+
p.log.message(`${picocolors_1.default.blue("📁 Compile:")} ${summary.compileSuccess ? picocolors_1.default.green("✓ Success") : picocolors_1.default.red("✗ Failed")}`);
|
|
172
|
+
if (summary.compileSuccess) {
|
|
173
|
+
if (summary.failed === 0) {
|
|
174
|
+
p.log.message(`${picocolors_1.default.green("✓ Tests:")} All passed`);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
p.log.message(`${picocolors_1.default.green("✓ Passed:")} ${summary.passed}`);
|
|
178
|
+
p.log.message(`${picocolors_1.default.red("✗ Failed:")} ${summary.failed}`);
|
|
179
|
+
if (summary.failedTests.length > 0) {
|
|
180
|
+
p.log.message("");
|
|
181
|
+
p.log.message(picocolors_1.default.red(picocolors_1.default.bold("Failed tests:")));
|
|
182
|
+
for (const test of summary.failedTests.slice(0, 10)) {
|
|
183
|
+
p.log.message(picocolors_1.default.red(` ✗ ${test}`));
|
|
184
|
+
}
|
|
185
|
+
if (summary.failedTests.length > 10) {
|
|
186
|
+
p.log.message(picocolors_1.default.dim(` ... and ${summary.failedTests.length - 10} more`));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
p.log.message(picocolors_1.default.dim("─".repeat(50)));
|
|
192
|
+
if (summary.compileSuccess && summary.failed === 0) {
|
|
193
|
+
p.outro(picocolors_1.default.green("✨ All tests passed!"));
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
p.outro(picocolors_1.default.yellow("Some issues need attention"));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// =============================================================================
|
|
200
|
+
// Main Command
|
|
201
|
+
// =============================================================================
|
|
202
|
+
async function testAllExamples(cliExamples) {
|
|
203
|
+
p.intro(picocolors_1.default.cyan("🧪 FHEVM Example Tester"));
|
|
204
|
+
const examplesToTest = await getExamplesToTest(cliExamples);
|
|
205
|
+
if (examplesToTest.length === 0) {
|
|
206
|
+
p.log.warning("No examples selected");
|
|
207
|
+
p.outro(picocolors_1.default.dim("Nothing to test"));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
p.log.message("");
|
|
211
|
+
p.log.message(`📦 Testing ${picocolors_1.default.bold(String(examplesToTest.length))} examples...`);
|
|
212
|
+
const tempDir = path.join((0, utils_1.getRootDir)(), ".test-temp");
|
|
213
|
+
if (fs.existsSync(tempDir)) {
|
|
214
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
215
|
+
}
|
|
216
|
+
let summary;
|
|
217
|
+
try {
|
|
218
|
+
const s = p.spinner();
|
|
219
|
+
s.start("Setting up test project...");
|
|
220
|
+
await (0, builders_1.createLocalTestProject)(examplesToTest, tempDir);
|
|
221
|
+
s.stop(picocolors_1.default.green("✓ Project ready"));
|
|
222
|
+
summary = await runTestPipeline(tempDir, examplesToTest.length);
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
if (fs.existsSync(tempDir)) {
|
|
226
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
showSummary(summary);
|
|
230
|
+
}
|
|
231
|
+
// =============================================================================
|
|
232
|
+
// CLI Entry Point
|
|
233
|
+
// =============================================================================
|
|
234
|
+
function showHelp() {
|
|
235
|
+
utils_1.log.info("🔧 FHEVM Maintenance Tools");
|
|
236
|
+
utils_1.log.message("");
|
|
237
|
+
utils_1.log.message("Available commands:");
|
|
238
|
+
utils_1.log.message("");
|
|
239
|
+
utils_1.log.message(" test-all Test examples");
|
|
240
|
+
utils_1.log.message("");
|
|
241
|
+
utils_1.log.message("Usage:");
|
|
242
|
+
utils_1.log.dim(" npm run test:all");
|
|
243
|
+
utils_1.log.dim(" npm run test:all fhe-counter,fhe-add");
|
|
244
|
+
}
|
|
245
|
+
async function main() {
|
|
246
|
+
const args = process.argv.slice(2);
|
|
247
|
+
// Check for help flag first
|
|
248
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
249
|
+
showHelp();
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const command = args[0];
|
|
253
|
+
switch (command) {
|
|
254
|
+
case "test-all": {
|
|
255
|
+
const exampleArg = args[1];
|
|
256
|
+
// Filter out help flags from example list
|
|
257
|
+
const examples = exampleArg && !exampleArg.startsWith("-")
|
|
258
|
+
? exampleArg.split(",")
|
|
259
|
+
: undefined;
|
|
260
|
+
await testAllExamples(examples);
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
default:
|
|
264
|
+
showHelp();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Only run if this is the main module
|
|
268
|
+
const isMainModule = process.argv[1]?.includes("maintenance");
|
|
269
|
+
if (isMainModule) {
|
|
270
|
+
main().catch(console.error);
|
|
271
|
+
}
|