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 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../scripts/doctor.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const p = __importStar(require("@clack/prompts"));
|
|
44
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
45
|
+
const utils_1 = require("./utils");
|
|
46
|
+
const config_1 = require("./config");
|
|
47
|
+
const ROOT_DIR = (0, utils_1.getRootDir)();
|
|
48
|
+
// =============================================================================
|
|
49
|
+
// Checks
|
|
50
|
+
// =============================================================================
|
|
51
|
+
async function checkNodeVersion() {
|
|
52
|
+
const version = process.version;
|
|
53
|
+
const major = parseInt(version.slice(1).split(".")[0]);
|
|
54
|
+
if (major >= 20) {
|
|
55
|
+
return {
|
|
56
|
+
name: "Node.js Version",
|
|
57
|
+
status: "success",
|
|
58
|
+
message: `${version} (>= 20.0.0)`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
return {
|
|
63
|
+
name: "Node.js Version",
|
|
64
|
+
status: "fail",
|
|
65
|
+
message: `${version} (Required: >= 20.0.0)`,
|
|
66
|
+
details: ["Please upgrade Node.js to version 20 or later."],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function checkGit() {
|
|
71
|
+
try {
|
|
72
|
+
(0, child_process_1.execSync)("git --version", { stdio: "ignore" });
|
|
73
|
+
return {
|
|
74
|
+
name: "Git Installation",
|
|
75
|
+
status: "success",
|
|
76
|
+
message: "Installed",
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
return {
|
|
81
|
+
name: "Git Installation",
|
|
82
|
+
status: "fail",
|
|
83
|
+
message: "Not found",
|
|
84
|
+
details: [
|
|
85
|
+
"Git is required to clone templates and manage the repository.",
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function checkConfigIntegrity() {
|
|
91
|
+
const issues = [];
|
|
92
|
+
// 1. Check if configured files exist
|
|
93
|
+
for (const [name, config] of Object.entries(config_1.EXAMPLES)) {
|
|
94
|
+
const c = config;
|
|
95
|
+
// Config paths already include "contracts/" and "test/" prefixes
|
|
96
|
+
// So we join them directly with ROOT_DIR
|
|
97
|
+
const contractPath = path.join(ROOT_DIR, c.contract);
|
|
98
|
+
const testPath = path.join(ROOT_DIR, c.test);
|
|
99
|
+
if (!fs.existsSync(contractPath)) {
|
|
100
|
+
issues.push(`Checking ${picocolors_1.default.bold(name)}: Contract not found at ${c.contract}`);
|
|
101
|
+
}
|
|
102
|
+
if (!fs.existsSync(testPath)) {
|
|
103
|
+
issues.push(`Checking ${picocolors_1.default.bold(name)}: Test file not found at ${c.test}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (issues.length === 0) {
|
|
107
|
+
return {
|
|
108
|
+
name: "Config Integrity",
|
|
109
|
+
status: "success",
|
|
110
|
+
message: "All paths valid",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
return {
|
|
115
|
+
name: "Config Integrity",
|
|
116
|
+
status: "fail",
|
|
117
|
+
message: `${issues.length} issues found`,
|
|
118
|
+
details: issues,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// =============================================================================
|
|
123
|
+
// Main
|
|
124
|
+
// =============================================================================
|
|
125
|
+
async function main() {
|
|
126
|
+
p.intro(picocolors_1.default.cyan("🩺 FHEVM Doctor"));
|
|
127
|
+
const checks = [checkNodeVersion(), checkGit(), checkConfigIntegrity()];
|
|
128
|
+
const results = await Promise.all(checks);
|
|
129
|
+
let hasFailure = false;
|
|
130
|
+
for (const result of results) {
|
|
131
|
+
if (result.status === "success") {
|
|
132
|
+
p.log.message(`${picocolors_1.default.green("✓")} ${picocolors_1.default.bold(result.name)}: ${picocolors_1.default.dim(result.message || "OK")}`);
|
|
133
|
+
}
|
|
134
|
+
else if (result.status === "warn") {
|
|
135
|
+
p.log.message(`${picocolors_1.default.yellow("!")} ${picocolors_1.default.bold(result.name)}: ${result.message}`);
|
|
136
|
+
if (result.details) {
|
|
137
|
+
result.details.forEach((line) => p.log.message(picocolors_1.default.yellow(` ${line}`)));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
hasFailure = true;
|
|
142
|
+
p.log.message(`${picocolors_1.default.red("✗")} ${picocolors_1.default.bold(result.name)}: ${result.message}`);
|
|
143
|
+
if (result.details) {
|
|
144
|
+
result.details.forEach((line) => p.log.message(picocolors_1.default.red(` ${line}`)));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
p.log.message("");
|
|
149
|
+
if (hasFailure) {
|
|
150
|
+
p.outro(picocolors_1.default.red("❌ Some checks failed. Please review the issues above."));
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
p.outro(picocolors_1.default.green("✅ All checks passed! You are ready to develop. 🚀"));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
main().catch(console.error);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-config.d.ts","sourceRoot":"","sources":["../../scripts/generate-config.ts"],"names":[],"mappings":";AAEA;;;;;GAKG"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Auto-Discovery Config Generator
|
|
5
|
+
*
|
|
6
|
+
* Scans contracts/ directory and generates config.ts automatically
|
|
7
|
+
* Extracts metadata from @notice tags and folder structure.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const utils_1 = require("./utils");
|
|
46
|
+
const ROOT_DIR = path.resolve(__dirname, "..");
|
|
47
|
+
const CONTRACTS_DIR = path.join(ROOT_DIR, "contracts");
|
|
48
|
+
const TEST_DIR = path.join(ROOT_DIR, "test");
|
|
49
|
+
const OUTPUT_FILE = path.join(ROOT_DIR, "scripts/config.ts");
|
|
50
|
+
// =============================================================================
|
|
51
|
+
// Contract Analysis
|
|
52
|
+
// =============================================================================
|
|
53
|
+
function extractNotice(contractPath) {
|
|
54
|
+
const content = fs.readFileSync(contractPath, "utf-8");
|
|
55
|
+
const noticeRegex = /\/\*\*[\s\S]*?@notice\s+([^\n*]+)[\s\S]*?\*\/[\s\S]*?contract\s+\w+/;
|
|
56
|
+
const match = content.match(noticeRegex);
|
|
57
|
+
return match && match[1] ? match[1].trim() : null;
|
|
58
|
+
}
|
|
59
|
+
function readExistingConfig() {
|
|
60
|
+
try {
|
|
61
|
+
if (!fs.existsSync(OUTPUT_FILE)) {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
delete require.cache[require.resolve(OUTPUT_FILE)];
|
|
65
|
+
const config = require(OUTPUT_FILE);
|
|
66
|
+
return config.EXAMPLES || {};
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.warn("⚠️ Could not read existing config, starting fresh");
|
|
70
|
+
return {};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function getCategoryFromPath(relativePath) {
|
|
74
|
+
const parts = relativePath.split("/");
|
|
75
|
+
parts.pop();
|
|
76
|
+
if (parts.length === 0)
|
|
77
|
+
return "Uncategorized";
|
|
78
|
+
if (parts.length === 1)
|
|
79
|
+
return (0, utils_1.formatCategoryName)(parts[0]);
|
|
80
|
+
return parts.map(utils_1.formatCategoryName).join(" - ");
|
|
81
|
+
}
|
|
82
|
+
function findTestFile(contractPath) {
|
|
83
|
+
const relativePath = path.relative(CONTRACTS_DIR, contractPath);
|
|
84
|
+
const testPath = path.join(TEST_DIR, relativePath.replace(".sol", ".ts"));
|
|
85
|
+
return fs.existsSync(testPath)
|
|
86
|
+
? `test/${path.relative(TEST_DIR, testPath)}`
|
|
87
|
+
: null;
|
|
88
|
+
}
|
|
89
|
+
function getDocsOutput(contractPath) {
|
|
90
|
+
const relativePath = contractPath
|
|
91
|
+
.replace(/^contracts\//, "")
|
|
92
|
+
.replace(/\.sol$/, "");
|
|
93
|
+
return `docs/${(0, utils_1.toKebabCase)(relativePath)}.md`;
|
|
94
|
+
}
|
|
95
|
+
function scanContracts() {
|
|
96
|
+
const contracts = [];
|
|
97
|
+
const existingConfig = readExistingConfig();
|
|
98
|
+
function scan(dir) {
|
|
99
|
+
const items = fs.readdirSync(dir);
|
|
100
|
+
for (const item of items) {
|
|
101
|
+
const fullPath = path.join(dir, item);
|
|
102
|
+
const stat = fs.statSync(fullPath);
|
|
103
|
+
if (stat.isDirectory() && item !== "mocks") {
|
|
104
|
+
scan(fullPath);
|
|
105
|
+
}
|
|
106
|
+
else if (stat.isFile() && item.endsWith(".sol")) {
|
|
107
|
+
const relativePath = path.relative(CONTRACTS_DIR, fullPath);
|
|
108
|
+
const contractName = item.replace(".sol", "");
|
|
109
|
+
const exampleName = (0, utils_1.contractNameToExampleName)(contractName);
|
|
110
|
+
const category = getCategoryFromPath(relativePath);
|
|
111
|
+
const testPath = findTestFile(fullPath);
|
|
112
|
+
const description = extractNotice(fullPath);
|
|
113
|
+
if (!description) {
|
|
114
|
+
console.warn(`⚠️ No @notice found in ${relativePath}`);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (!testPath) {
|
|
118
|
+
console.warn(`⚠️ No test file found for ${relativePath}`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const contractInfo = {
|
|
122
|
+
name: exampleName,
|
|
123
|
+
contractPath: `contracts/${relativePath}`,
|
|
124
|
+
testPath,
|
|
125
|
+
description,
|
|
126
|
+
category,
|
|
127
|
+
title: (0, utils_1.contractNameToTitle)(contractName),
|
|
128
|
+
docsOutput: getDocsOutput(`contracts/${relativePath}`),
|
|
129
|
+
};
|
|
130
|
+
const existingExample = existingConfig[exampleName];
|
|
131
|
+
if (existingExample?.npmDependencies) {
|
|
132
|
+
contractInfo.npmDependencies = existingExample.npmDependencies;
|
|
133
|
+
}
|
|
134
|
+
if (existingExample?.dependencies) {
|
|
135
|
+
contractInfo.dependencies = existingExample.dependencies;
|
|
136
|
+
}
|
|
137
|
+
contracts.push(contractInfo);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
scan(CONTRACTS_DIR);
|
|
142
|
+
return contracts;
|
|
143
|
+
}
|
|
144
|
+
// =============================================================================
|
|
145
|
+
// Config Generation
|
|
146
|
+
// =============================================================================
|
|
147
|
+
function generateExamplesConfig(contracts) {
|
|
148
|
+
const entries = contracts.map((c) => {
|
|
149
|
+
const npmDepsField = c.npmDependencies
|
|
150
|
+
? `\n npmDependencies: ${JSON.stringify(c.npmDependencies, null, 2).replace(/\n/g, "\n ")},`
|
|
151
|
+
: "";
|
|
152
|
+
const depsField = c.dependencies
|
|
153
|
+
? `\n dependencies: ${JSON.stringify(c.dependencies, null, 2).replace(/\n/g, "\n ")},`
|
|
154
|
+
: "";
|
|
155
|
+
return ` "${c.name}": {
|
|
156
|
+
contract: "${c.contractPath}",
|
|
157
|
+
test: "${c.testPath}",${npmDepsField}${depsField}
|
|
158
|
+
description:
|
|
159
|
+
"${c.description}",
|
|
160
|
+
category: "${c.category}",
|
|
161
|
+
docsOutput: "${c.docsOutput}",
|
|
162
|
+
title: "${c.title}"
|
|
163
|
+
}`;
|
|
164
|
+
});
|
|
165
|
+
return `export const EXAMPLES: Record<string, ExampleConfig> = {\n${entries.join(",\n")}\n};`;
|
|
166
|
+
}
|
|
167
|
+
function generateCategoriesConfig(contracts) {
|
|
168
|
+
const categoryMap = {};
|
|
169
|
+
for (const contract of contracts) {
|
|
170
|
+
if (!categoryMap[contract.category]) {
|
|
171
|
+
categoryMap[contract.category] = [];
|
|
172
|
+
}
|
|
173
|
+
categoryMap[contract.category].push(contract);
|
|
174
|
+
}
|
|
175
|
+
const categoryEntries = Object.entries(categoryMap).map(([category, items]) => {
|
|
176
|
+
const categoryKey = category
|
|
177
|
+
.toLowerCase()
|
|
178
|
+
.replace(/\s+/g, "")
|
|
179
|
+
.replace(/-/g, "");
|
|
180
|
+
const contracts = items
|
|
181
|
+
.map((c) => ` {
|
|
182
|
+
sol: "${c.contractPath}",
|
|
183
|
+
test: "${c.testPath}",
|
|
184
|
+
}`)
|
|
185
|
+
.join(",\n");
|
|
186
|
+
return ` ${categoryKey}: {
|
|
187
|
+
name: "${category} Examples",
|
|
188
|
+
contracts: [
|
|
189
|
+
${contracts}
|
|
190
|
+
],
|
|
191
|
+
}`;
|
|
192
|
+
});
|
|
193
|
+
return `export const CATEGORIES: Record<string, CategoryConfig> = {\n${categoryEntries.join(",\n")}\n};`;
|
|
194
|
+
}
|
|
195
|
+
function generateConfigFile(contracts) {
|
|
196
|
+
return `/**
|
|
197
|
+
* ⚠️ AUTO-GENERATED FILE - DO NOT EDIT MANUALLY ⚠️
|
|
198
|
+
*
|
|
199
|
+
* This file is auto-generated by cli/generate-config.ts
|
|
200
|
+
* Run 'npm run generate:config' to regenerate
|
|
201
|
+
*/
|
|
202
|
+
|
|
203
|
+
// =============================================================================
|
|
204
|
+
// Types
|
|
205
|
+
// =============================================================================
|
|
206
|
+
|
|
207
|
+
export interface ExampleConfig {
|
|
208
|
+
/** Path to the Solidity contract file */
|
|
209
|
+
contract: string;
|
|
210
|
+
/** Path to the TypeScript test file */
|
|
211
|
+
test: string;
|
|
212
|
+
/** Optional additional contract dependencies */
|
|
213
|
+
dependencies?: string[];
|
|
214
|
+
/** Optional npm packages to install */
|
|
215
|
+
npmDependencies?: Record<string, string>;
|
|
216
|
+
/** Full description for documentation */
|
|
217
|
+
description: string;
|
|
218
|
+
/** Category for grouping */
|
|
219
|
+
category: string;
|
|
220
|
+
/** Output path for generated documentation */
|
|
221
|
+
docsOutput: string;
|
|
222
|
+
/** Title for documentation */
|
|
223
|
+
title: string;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface CategoryConfig {
|
|
227
|
+
/** Display name */
|
|
228
|
+
name: string;
|
|
229
|
+
/** List of contracts in this category */
|
|
230
|
+
contracts: Array<{ sol: string; test?: string }>;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// =============================================================================
|
|
234
|
+
// GitHub Repository Configuration
|
|
235
|
+
// =============================================================================
|
|
236
|
+
|
|
237
|
+
export const REPO_URL = "https://github.com/NecipAkgz/fhevm-example-factory";
|
|
238
|
+
export const REPO_BRANCH = "main";
|
|
239
|
+
|
|
240
|
+
// =============================================================================
|
|
241
|
+
// Example Configurations
|
|
242
|
+
// =============================================================================
|
|
243
|
+
|
|
244
|
+
${generateExamplesConfig(contracts)}
|
|
245
|
+
|
|
246
|
+
// =============================================================================
|
|
247
|
+
// Category Configurations
|
|
248
|
+
// =============================================================================
|
|
249
|
+
|
|
250
|
+
${generateCategoriesConfig(contracts)}
|
|
251
|
+
|
|
252
|
+
// =============================================================================
|
|
253
|
+
// Helper Functions
|
|
254
|
+
// =============================================================================
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Get list of example names
|
|
258
|
+
*/
|
|
259
|
+
export function getExampleNames(): string[] {
|
|
260
|
+
return Object.keys(EXAMPLES);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get list of category names
|
|
265
|
+
*/
|
|
266
|
+
export function getCategoryNames(): string[] {
|
|
267
|
+
return Object.keys(CATEGORIES);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Get example by name
|
|
272
|
+
*/
|
|
273
|
+
export function getExample(name: string): ExampleConfig | undefined {
|
|
274
|
+
return EXAMPLES[name];
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get category by name
|
|
279
|
+
*/
|
|
280
|
+
export function getCategory(name: string): CategoryConfig | undefined {
|
|
281
|
+
return CATEGORIES[name];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Generate consistent docs filename with fhe- prefix
|
|
286
|
+
*/
|
|
287
|
+
export function getDocsFileName(exampleName: string): string {
|
|
288
|
+
return exampleName.startsWith("fhe-") ? exampleName : \`fhe-\${exampleName}\`;
|
|
289
|
+
}
|
|
290
|
+
`;
|
|
291
|
+
}
|
|
292
|
+
// =============================================================================
|
|
293
|
+
// Main
|
|
294
|
+
// =============================================================================
|
|
295
|
+
function main() {
|
|
296
|
+
utils_1.log.info("🔍 Scanning contracts...\n");
|
|
297
|
+
const contracts = scanContracts();
|
|
298
|
+
utils_1.log.success(`✅ Found ${contracts.length} contracts\n`);
|
|
299
|
+
const categoryCount = {};
|
|
300
|
+
for (const c of contracts) {
|
|
301
|
+
categoryCount[c.category] = (categoryCount[c.category] || 0) + 1;
|
|
302
|
+
}
|
|
303
|
+
utils_1.log.message("📊 By category:");
|
|
304
|
+
for (const [category, count] of Object.entries(categoryCount)) {
|
|
305
|
+
utils_1.log.message(` ${category}: ${count}`);
|
|
306
|
+
}
|
|
307
|
+
utils_1.log.message("\n📝 Generating config...");
|
|
308
|
+
const configContent = generateConfigFile(contracts);
|
|
309
|
+
fs.writeFileSync(OUTPUT_FILE, configContent);
|
|
310
|
+
utils_1.log.success(`✅ Config generated: ${path.relative(ROOT_DIR, OUTPUT_FILE)}`);
|
|
311
|
+
}
|
|
312
|
+
const isMainModule = process.argv[1]?.includes("generate-config");
|
|
313
|
+
if (isMainModule) {
|
|
314
|
+
main();
|
|
315
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Generate Documentation - GitBook Documentation Generator
|
|
4
|
+
*
|
|
5
|
+
* Generates GitBook-compatible markdown documentation for FHEVM examples.
|
|
6
|
+
*/
|
|
7
|
+
export declare function handleInteractiveDocs(): Promise<void>;
|
|
8
|
+
export declare function handleDirect(args: string[]): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=generate-docs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-docs.d.ts","sourceRoot":"","sources":["../../scripts/generate-docs.ts"],"names":[],"mappings":";AAEA;;;;GAIG;AAuEH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiE3D;AAMD,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhE"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Generate Documentation - GitBook Documentation Generator
|
|
5
|
+
*
|
|
6
|
+
* Generates GitBook-compatible markdown documentation for FHEVM examples.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
42
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.handleInteractiveDocs = handleInteractiveDocs;
|
|
46
|
+
exports.handleDirect = handleDirect;
|
|
47
|
+
const p = __importStar(require("@clack/prompts"));
|
|
48
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
49
|
+
const fs = __importStar(require("fs"));
|
|
50
|
+
const path = __importStar(require("path"));
|
|
51
|
+
const config_1 = require("./config");
|
|
52
|
+
const utils_1 = require("./utils");
|
|
53
|
+
// =============================================================================
|
|
54
|
+
// Documentation Generator
|
|
55
|
+
// =============================================================================
|
|
56
|
+
async function generateDocumentation(exampleName) {
|
|
57
|
+
const rootDir = (0, utils_1.getRootDir)();
|
|
58
|
+
let count = 0;
|
|
59
|
+
const examples = exampleName === "all" ? Object.keys(config_1.EXAMPLES) : [exampleName];
|
|
60
|
+
for (const name of examples) {
|
|
61
|
+
const example = config_1.EXAMPLES[name];
|
|
62
|
+
if (!example)
|
|
63
|
+
continue;
|
|
64
|
+
const contractPath = path.join(rootDir, example.contract);
|
|
65
|
+
const testPath = path.join(rootDir, example.test);
|
|
66
|
+
if (!fs.existsSync(contractPath) || !fs.existsSync(testPath))
|
|
67
|
+
continue;
|
|
68
|
+
const contractContent = fs.readFileSync(contractPath, "utf-8");
|
|
69
|
+
const testContent = fs.readFileSync(testPath, "utf-8");
|
|
70
|
+
const contractName = (0, utils_1.getContractName)(example.contract) || "Contract";
|
|
71
|
+
const testFileName = path.basename(example.test);
|
|
72
|
+
const markdown = (0, utils_1.generateGitBookMarkdown)(example.description, contractContent, testContent, contractName, testFileName);
|
|
73
|
+
const outputPath = example.docsOutput
|
|
74
|
+
? path.join(rootDir, example.docsOutput)
|
|
75
|
+
: path.join(rootDir, "docs", `${(0, config_1.getDocsFileName)(name)}.md`);
|
|
76
|
+
const outputDir = path.dirname(outputPath);
|
|
77
|
+
if (!fs.existsSync(outputDir)) {
|
|
78
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
fs.writeFileSync(outputPath, markdown);
|
|
81
|
+
count++;
|
|
82
|
+
}
|
|
83
|
+
return count;
|
|
84
|
+
}
|
|
85
|
+
// =============================================================================
|
|
86
|
+
// Interactive Mode
|
|
87
|
+
// =============================================================================
|
|
88
|
+
async function handleInteractiveDocs() {
|
|
89
|
+
console.clear();
|
|
90
|
+
p.intro(picocolors_1.default.bgCyan(picocolors_1.default.black(" 📚 Generate Documentation ")));
|
|
91
|
+
const scope = await p.select({
|
|
92
|
+
message: "Generate documentation for:",
|
|
93
|
+
options: [
|
|
94
|
+
{
|
|
95
|
+
value: "all",
|
|
96
|
+
label: "All examples",
|
|
97
|
+
hint: `${Object.keys(config_1.EXAMPLES).length} files`,
|
|
98
|
+
},
|
|
99
|
+
{ value: "single", label: "Single example" },
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
if (p.isCancel(scope)) {
|
|
103
|
+
p.cancel("Operation cancelled.");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
let target = "all";
|
|
107
|
+
if (scope === "single") {
|
|
108
|
+
const example = await p.select({
|
|
109
|
+
message: "Select an example:",
|
|
110
|
+
options: Object.entries(config_1.EXAMPLES).map(([key, config]) => ({
|
|
111
|
+
value: key,
|
|
112
|
+
label: key,
|
|
113
|
+
hint: config.category,
|
|
114
|
+
})),
|
|
115
|
+
});
|
|
116
|
+
if (p.isCancel(example)) {
|
|
117
|
+
p.cancel("Operation cancelled.");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
target = example;
|
|
121
|
+
}
|
|
122
|
+
const s = p.spinner();
|
|
123
|
+
s.start("Generating documentation...");
|
|
124
|
+
try {
|
|
125
|
+
const count = await generateDocumentation(target);
|
|
126
|
+
s.stop(`Generated ${count} documentation file(s)`);
|
|
127
|
+
p.log.success(`📄 Files: ${picocolors_1.default.green(String(count))} documentation file(s)`);
|
|
128
|
+
p.log.info(`📁 Location: ${picocolors_1.default.cyan("docs/")}`);
|
|
129
|
+
if (target !== "all") {
|
|
130
|
+
const docFileName = (0, config_1.getDocsFileName)(target);
|
|
131
|
+
p.log.message(` └─ ${picocolors_1.default.dim(docFileName + ".md")}`);
|
|
132
|
+
}
|
|
133
|
+
p.log.message("");
|
|
134
|
+
p.log.message(picocolors_1.default.dim("💡 Tip: Run 'npm run create:docs' to regenerate all docs"));
|
|
135
|
+
p.outro(picocolors_1.default.green("🎉 Documentation generated!"));
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
s.stop("Failed to generate documentation");
|
|
139
|
+
p.log.error(error instanceof Error ? error.message : String(error));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// =============================================================================
|
|
143
|
+
// QUICK MODE (CLI)
|
|
144
|
+
// =============================================================================
|
|
145
|
+
async function handleDirect(args) {
|
|
146
|
+
const [target] = args;
|
|
147
|
+
if (!target) {
|
|
148
|
+
utils_1.log.info("Generating all documentation...");
|
|
149
|
+
const count = await generateDocumentation("all");
|
|
150
|
+
utils_1.log.success(`✓ Generated ${count} documentation files`);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (!config_1.EXAMPLES[target]) {
|
|
154
|
+
utils_1.log.message("Available: " + Object.keys(config_1.EXAMPLES).join(", "));
|
|
155
|
+
(0, utils_1.handleError)(`Unknown example "${target}"`);
|
|
156
|
+
}
|
|
157
|
+
utils_1.log.info(`Generating docs for: ${target}`);
|
|
158
|
+
await generateDocumentation(target);
|
|
159
|
+
utils_1.log.success(`✓ Generated: docs/${(0, config_1.getDocsFileName)(target)}.md`);
|
|
160
|
+
}
|
|
161
|
+
// =============================================================================
|
|
162
|
+
// Help
|
|
163
|
+
// =============================================================================
|
|
164
|
+
function showHelp() {
|
|
165
|
+
utils_1.log.info("📚 FHEVM Documentation Generator");
|
|
166
|
+
utils_1.log.message("");
|
|
167
|
+
utils_1.log.message("Usage:");
|
|
168
|
+
utils_1.log.message(" npm run create:docs Generate all docs");
|
|
169
|
+
utils_1.log.message(" npm run create:docs <example> Generate specific example doc");
|
|
170
|
+
utils_1.log.message("");
|
|
171
|
+
utils_1.log.message("Examples:");
|
|
172
|
+
utils_1.log.dim(" npm run create:docs");
|
|
173
|
+
utils_1.log.dim(" npm run create:docs fhe-counter");
|
|
174
|
+
}
|
|
175
|
+
// =============================================================================
|
|
176
|
+
// Main Entry Point
|
|
177
|
+
// =============================================================================
|
|
178
|
+
async function main() {
|
|
179
|
+
const args = process.argv.slice(2);
|
|
180
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
181
|
+
showHelp();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
await handleDirect(args);
|
|
185
|
+
}
|
|
186
|
+
const isMainModule = process.argv[1]?.includes("generate-docs");
|
|
187
|
+
if (isMainModule) {
|
|
188
|
+
main().catch(console.error);
|
|
189
|
+
}
|