@ethernauta/cli
Advanced tools
| export {}; |
| import { readFileSync, readdirSync, writeFileSync } from "node:fs"; | ||
| import { join, resolve } from "node:path"; | ||
| import { DescriptionSchema, to_selector } from "@ethernauta/abi"; | ||
| import { emit_file_basename_for, emit_name_for, generate } from "@ethernauta/abi/generator"; | ||
| import { bytes4Schema } from "@ethernauta/core"; | ||
| import { bytes_to_hex } from "@ethernauta/utils"; | ||
| import { array, object, parse, string } from "valibot"; | ||
| //#region src/execute.ts | ||
| function selector_hex(signature) { | ||
| return parse(bytes4Schema, bytes_to_hex(to_selector(signature))); | ||
| } | ||
| function parse_flags(args) { | ||
| let in_path; | ||
| let out_dir; | ||
| for (let i = 0; i < args.length; i++) { | ||
| const arg = args[i]; | ||
| if (arg === "--in") in_path = args[++i]; | ||
| else if (arg === "--out") out_dir = args[++i]; | ||
| } | ||
| if (!in_path || !out_dir) throw new Error("usage: ethernauta abi --in <path> --out <dir>"); | ||
| return { | ||
| in_path: resolve(process.cwd(), in_path), | ||
| out_dir: resolve(process.cwd(), out_dir) | ||
| }; | ||
| } | ||
| function load_abi(path) { | ||
| const raw = JSON.parse(readFileSync(path, "utf8")); | ||
| if (Array.isArray(raw)) return raw; | ||
| if (Array.isArray(raw.abi)) return raw.abi; | ||
| throw new Error(`expected an ABI JSON array or a foundry artifact with an \`abi\` array at ${path}`); | ||
| } | ||
| function signature_key(d) { | ||
| if (d.type !== "function") return d.type; | ||
| const param_types = d.inputs.map((i) => i.type).join(","); | ||
| return `${d.name}(${param_types})`; | ||
| } | ||
| function dedupe_by_signature(descriptions) { | ||
| const seen = /* @__PURE__ */ new Set(); | ||
| const out = []; | ||
| for (const d of descriptions) { | ||
| const key = signature_key(d); | ||
| if (seen.has(key)) continue; | ||
| seen.add(key); | ||
| out.push(d); | ||
| } | ||
| return out; | ||
| } | ||
| function write_barrel(out_dir, functions, generated_emit_names) { | ||
| const seen = /* @__PURE__ */ new Set(); | ||
| const lines = []; | ||
| for (const f of functions) { | ||
| if (f.type !== "function") continue; | ||
| const js_name = emit_name_for(f, functions); | ||
| if (seen.has(js_name)) continue; | ||
| if (!generated_emit_names.has(js_name)) continue; | ||
| seen.add(js_name); | ||
| const basename = emit_file_basename_for(f, functions); | ||
| lines.push(`export { ${js_name} } from "./${basename}"`); | ||
| } | ||
| writeFileSync(join(out_dir, "methods", "index.ts"), `${lines.join("\n")}\n`); | ||
| } | ||
| function is_generatable(d) { | ||
| if (d.type !== "function") return false; | ||
| return true; | ||
| } | ||
| function execute_abi(args) { | ||
| const { in_path, out_dir } = parse_flags(args); | ||
| const raw = load_abi(in_path); | ||
| const generatable = dedupe_by_signature(parse(array(DescriptionSchema), raw).filter((d) => d.type === "function")).filter(is_generatable); | ||
| const result = generate(generatable, out_dir); | ||
| write_barrel(out_dir, generatable, new Set(result.generated)); | ||
| console.log(`regenerated ${result.generated.length} methods into ${out_dir}/methods/`); | ||
| if (result.skipped.length > 0) { | ||
| console.warn(`skipped ${result.skipped.length} method(s):`); | ||
| for (const s of result.skipped) console.warn(` - ${s.name}: ${s.reason}`); | ||
| } | ||
| } | ||
| function parse_registry_flags(args) { | ||
| let in_dir; | ||
| let out_file; | ||
| for (let i = 0; i < args.length; i++) { | ||
| const arg = args[i]; | ||
| if (arg === "--in") in_dir = args[++i]; | ||
| else if (arg === "--out") out_file = args[++i]; | ||
| } | ||
| if (!in_dir || !out_file) throw new Error("usage: ethernauta registry --in <dir> --out <file>"); | ||
| return { | ||
| in_dir: resolve(process.cwd(), in_dir), | ||
| out_file: resolve(process.cwd(), out_file) | ||
| }; | ||
| } | ||
| function walk_abi_jsons(root) { | ||
| const found = []; | ||
| const stack = [root]; | ||
| while (stack.length > 0) { | ||
| const dir = stack.pop(); | ||
| for (const entry of readdirSync(dir, { withFileTypes: true })) { | ||
| const full = join(dir, entry.name); | ||
| if (entry.isDirectory()) stack.push(full); | ||
| else if (entry.name.endsWith(".abi.json")) found.push(full); | ||
| } | ||
| } | ||
| return found.sort(); | ||
| } | ||
| object({ | ||
| signature: string(), | ||
| name: string(), | ||
| types: array(string()), | ||
| param_names: array(string()), | ||
| source: string() | ||
| }); | ||
| function collect_entries(files, root) { | ||
| const out = /* @__PURE__ */ new Map(); | ||
| for (const file of files) { | ||
| const raw = load_abi(file); | ||
| const descriptions = parse(array(DescriptionSchema), raw); | ||
| for (const d of descriptions) { | ||
| if (d.type !== "function") continue; | ||
| const types = d.inputs.map((i) => i.type); | ||
| const param_names = d.inputs.map((i) => i.name); | ||
| const signature = `${d.name}(${types.join(",")})`; | ||
| const selector = selector_hex(signature); | ||
| const relative = file.startsWith(`${root}/`) ? file.slice(root.length + 1) : file; | ||
| const existing = out.get(selector); | ||
| if (existing) { | ||
| if (existing.signature !== signature) throw new Error(`selector collision ${selector}: '${existing.signature}' (${existing.source}) vs '${signature}' (${relative})`); | ||
| continue; | ||
| } | ||
| out.set(selector, { | ||
| signature, | ||
| name: d.name, | ||
| types, | ||
| param_names, | ||
| source: relative | ||
| }); | ||
| } | ||
| } | ||
| return out; | ||
| } | ||
| function format_registry(entries) { | ||
| return `// AUTO-GENERATED — do not edit. Run \`pnpm --filter @ethernauta/erc generate\`. | ||
| export const REGISTRY = { | ||
| ${Array.from(entries.entries()).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([selector, entry]) => { | ||
| const types = entry.types.map((t) => JSON.stringify(t)).join(", "); | ||
| const names = entry.param_names.map((n) => JSON.stringify(n)).join(", "); | ||
| return ` ${JSON.stringify(selector)}: { name: ${JSON.stringify(entry.name)}, signature: ${JSON.stringify(entry.signature)}, types: [${types}], param_names: [${names}] },`; | ||
| }).join("\n")} | ||
| } as const | ||
| export type RegistrySelector = keyof typeof REGISTRY | ||
| export type RegistryEntry = (typeof REGISTRY)[RegistrySelector] | ||
| `; | ||
| } | ||
| function execute_registry(args) { | ||
| const { in_dir, out_file } = parse_registry_flags(args); | ||
| const files = walk_abi_jsons(in_dir); | ||
| const entries = collect_entries(files, in_dir); | ||
| writeFileSync(out_file, format_registry(entries)); | ||
| console.log(`wrote ${entries.size} registry entries from ${files.length} ABI JSONs to ${out_file}`); | ||
| } | ||
| //#endregion | ||
| export { execute_registry as n, execute_abi as t }; | ||
| //# sourceMappingURL=execute-by8xsAv7.js.map |
| {"version":3,"file":"execute-by8xsAv7.js","names":[],"sources":["../src/execute.ts"],"sourcesContent":["import {\n readdirSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\"\nimport { join, resolve } from \"node:path\"\nimport {\n type Description,\n DescriptionSchema,\n to_selector,\n} from \"@ethernauta/abi\"\nimport {\n emit_file_basename_for,\n emit_name_for,\n generate,\n} from \"@ethernauta/abi/generator\"\nimport { type Bytes4, bytes4Schema } from \"@ethernauta/core\"\nimport { bytes_to_hex } from \"@ethernauta/utils\"\nimport {\n array,\n type InferOutput,\n object,\n parse,\n string,\n} from \"valibot\"\n\nfunction selector_hex(signature: string): Bytes4 {\n return parse(\n bytes4Schema,\n bytes_to_hex(to_selector(signature)),\n )\n}\n\nfunction parse_flags(args: string[]) {\n let in_path: string | undefined\n let out_dir: string | undefined\n for (let i = 0; i < args.length; i++) {\n const arg = args[i] as string\n if (arg === \"--in\") {\n in_path = args[++i]\n } else if (arg === \"--out\") {\n out_dir = args[++i]\n }\n }\n if (!in_path || !out_dir) {\n throw new Error(\n \"usage: ethernauta abi --in <path> --out <dir>\",\n )\n }\n return {\n in_path: resolve(process.cwd(), in_path),\n out_dir: resolve(process.cwd(), out_dir),\n }\n}\n\nfunction load_abi(path: string): unknown[] {\n const raw = JSON.parse(readFileSync(path, \"utf8\"))\n if (Array.isArray(raw)) return raw\n if (Array.isArray(raw.abi)) return raw.abi\n throw new Error(\n `expected an ABI JSON array or a foundry artifact with an \\`abi\\` array at ${path}`,\n )\n}\n\nfunction signature_key(d: Description): string {\n if (d.type !== \"function\") return d.type\n const param_types = d.inputs.map((i) => i.type).join(\",\")\n return `${d.name}(${param_types})`\n}\n\nfunction _snake_or_kebab(name: string): string {\n if (name.includes(\"_\")) return name\n return name\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .toLowerCase()\n}\n\nfunction dedupe_by_signature(\n descriptions: Description[],\n): Description[] {\n const seen = new Set<string>()\n const out: Description[] = []\n for (const d of descriptions) {\n const key = signature_key(d)\n if (seen.has(key)) continue\n seen.add(key)\n out.push(d)\n }\n return out\n}\n\nfunction write_barrel(\n out_dir: string,\n functions: Description[],\n generated_emit_names: Set<string>,\n): void {\n const seen = new Set<string>()\n const lines: string[] = []\n for (const f of functions) {\n if (f.type !== \"function\") continue\n const js_name = emit_name_for(f, functions)\n if (seen.has(js_name)) continue\n if (!generated_emit_names.has(js_name)) continue\n seen.add(js_name)\n const basename = emit_file_basename_for(f, functions)\n lines.push(`export { ${js_name} } from \"./${basename}\"`)\n }\n writeFileSync(\n join(out_dir, \"methods\", \"index.ts\"),\n `${lines.join(\"\\n\")}\\n`,\n )\n}\n\nfunction is_generatable(d: Description): boolean {\n if (d.type !== \"function\") return false\n return true\n}\n\nexport function execute_abi(args: string[]): void {\n const { in_path, out_dir } = parse_flags(args)\n const raw = load_abi(in_path)\n const descriptions = parse(array(DescriptionSchema), raw)\n const functions = dedupe_by_signature(\n descriptions.filter((d) => d.type === \"function\"),\n )\n const generatable = functions.filter(is_generatable)\n const result = generate(generatable, out_dir)\n write_barrel(\n out_dir,\n generatable,\n new Set(result.generated),\n )\n console.log(\n `regenerated ${result.generated.length} methods into ${out_dir}/methods/`,\n )\n if (result.skipped.length > 0) {\n console.warn(\n `skipped ${result.skipped.length} method(s):`,\n )\n for (const s of result.skipped) {\n console.warn(` - ${s.name}: ${s.reason}`)\n }\n }\n}\n\nfunction parse_registry_flags(args: string[]) {\n let in_dir: string | undefined\n let out_file: string | undefined\n for (let i = 0; i < args.length; i++) {\n const arg = args[i] as string\n if (arg === \"--in\") {\n in_dir = args[++i]\n } else if (arg === \"--out\") {\n out_file = args[++i]\n }\n }\n if (!in_dir || !out_file) {\n throw new Error(\n \"usage: ethernauta registry --in <dir> --out <file>\",\n )\n }\n return {\n in_dir: resolve(process.cwd(), in_dir),\n out_file: resolve(process.cwd(), out_file),\n }\n}\n\nfunction walk_abi_jsons(root: string): string[] {\n const found: string[] = []\n const stack = [root]\n while (stack.length > 0) {\n const dir = stack.pop() as string\n for (const entry of readdirSync(dir, {\n withFileTypes: true,\n })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory()) {\n stack.push(full)\n } else if (entry.name.endsWith(\".abi.json\")) {\n found.push(full)\n }\n }\n }\n return found.sort()\n}\n\nconst registryEntrySchema = object({\n signature: string(),\n name: string(),\n types: array(string()),\n param_names: array(string()),\n source: string(),\n})\ntype RegistryEntry = InferOutput<typeof registryEntrySchema>\n\nfunction collect_entries(\n files: string[],\n root: string,\n): Map<Bytes4, RegistryEntry> {\n const out = new Map<Bytes4, RegistryEntry>()\n for (const file of files) {\n const raw = load_abi(file)\n const descriptions = parse(\n array(DescriptionSchema),\n raw,\n )\n for (const d of descriptions) {\n if (d.type !== \"function\") continue\n const types = d.inputs.map((i) => i.type)\n const param_names = d.inputs.map((i) => i.name)\n const signature = `${d.name}(${types.join(\",\")})`\n const selector = selector_hex(signature)\n const relative = file.startsWith(`${root}/`)\n ? file.slice(root.length + 1)\n : file\n const existing = out.get(selector)\n if (existing) {\n if (existing.signature !== signature) {\n throw new Error(\n `selector collision ${selector}: '${existing.signature}' (${existing.source}) vs '${signature}' (${relative})`,\n )\n }\n continue\n }\n out.set(selector, {\n signature,\n name: d.name,\n types,\n param_names,\n source: relative,\n })\n }\n }\n return out\n}\n\nfunction format_registry(\n entries: Map<Bytes4, RegistryEntry>,\n): string {\n const sorted = Array.from(entries.entries()).sort(\n ([a], [b]) => (a < b ? -1 : a > b ? 1 : 0),\n )\n const rows = sorted.map(([selector, entry]) => {\n const types = entry.types\n .map((t) => JSON.stringify(t))\n .join(\", \")\n const names = entry.param_names\n .map((n) => JSON.stringify(n))\n .join(\", \")\n return ` ${JSON.stringify(selector)}: { name: ${JSON.stringify(entry.name)}, signature: ${JSON.stringify(entry.signature)}, types: [${types}], param_names: [${names}] },`\n })\n return `// AUTO-GENERATED — do not edit. Run \\`pnpm --filter @ethernauta/erc generate\\`.\n\nexport const REGISTRY = {\n${rows.join(\"\\n\")}\n} as const\n\nexport type RegistrySelector = keyof typeof REGISTRY\nexport type RegistryEntry = (typeof REGISTRY)[RegistrySelector]\n`\n}\n\nexport function execute_registry(args: string[]): void {\n const { in_dir, out_file } = parse_registry_flags(args)\n const files = walk_abi_jsons(in_dir)\n const entries = collect_entries(files, in_dir)\n writeFileSync(out_file, format_registry(entries))\n console.log(\n `wrote ${entries.size} registry entries from ${files.length} ABI JSONs to ${out_file}`,\n )\n}\n"],"mappings":"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"} |
| //#region src/execute.d.ts | ||
| declare function execute_abi(args: string[]): void; | ||
| declare function execute_registry(args: string[]): void; | ||
| //#endregion | ||
| export { execute_abi, execute_registry }; | ||
| //# sourceMappingURL=index-DC1QWTR2.d.ts.map |
| {"version":3,"file":"index-DC1QWTR2.d.ts","names":[],"sources":["../src/execute.ts"],"mappings":";iBAsHgB,WAAA;AAAA,iBAgJA,gBAAA,CAhJW,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA"} |
+21
-24
| #!/usr/bin/env node | ||
| import { | ||
| n as execute_registry, | ||
| t as execute_abi, | ||
| } from "./execute-DKX5w-or.js" | ||
| import { n as execute_registry, t as execute_abi } from "./execute-by8xsAv7.js"; | ||
@@ -22,25 +19,25 @@ //#region src/bin.ts | ||
| metadata (signature, name, types, param names). | ||
| `.trim() | ||
| const [, , subcommand, ...rest] = process.argv | ||
| `.trim(); | ||
| const [, , subcommand, ...rest] = process.argv; | ||
| switch (subcommand) { | ||
| case "abi": | ||
| execute_abi(rest) | ||
| break | ||
| case "registry": | ||
| execute_registry(rest) | ||
| break | ||
| case "help": | ||
| case "--help": | ||
| case "-h": | ||
| case void 0: | ||
| console.log(HELP) | ||
| break | ||
| default: | ||
| console.error(`unknown subcommand: ${subcommand}\n`) | ||
| console.error(HELP) | ||
| process.exit(1) | ||
| case "abi": | ||
| execute_abi(rest); | ||
| break; | ||
| case "registry": | ||
| execute_registry(rest); | ||
| break; | ||
| case "help": | ||
| case "--help": | ||
| case "-h": | ||
| case void 0: | ||
| console.log(HELP); | ||
| break; | ||
| default: | ||
| console.error(`unknown subcommand: ${subcommand}\n`); | ||
| console.error(HELP); | ||
| process.exit(1); | ||
| } | ||
| //#endregion | ||
| export {} | ||
| //# sourceMappingURL=bin.js.map | ||
| export { }; | ||
| //# sourceMappingURL=bin.js.map |
+2
-5
@@ -1,6 +0,3 @@ | ||
| import { | ||
| n as execute_registry, | ||
| t as execute_abi, | ||
| } from "./execute-DKX5w-or.js" | ||
| import { n as execute_registry, t as execute_abi } from "./execute-by8xsAv7.js"; | ||
| export { execute_abi, execute_registry } | ||
| export { execute_abi, execute_registry }; |
+6
-3
@@ -5,3 +5,3 @@ { | ||
| "type": "module", | ||
| "version": "0.0.43", | ||
| "version": "0.0.44", | ||
| "publishConfig": { | ||
@@ -23,3 +23,5 @@ "access": "public" | ||
| "dependencies": { | ||
| "@ethernauta/abi": "0.0.43" | ||
| "@ethernauta/abi": "0.0.44", | ||
| "@ethernauta/core": "0.0.44", | ||
| "@ethernauta/utils": "0.0.44" | ||
| }, | ||
@@ -35,8 +37,9 @@ "peerDependencies": { | ||
| "dev": "tsdown --watch", | ||
| "build": "tsdown && biome format --write dist", | ||
| "build": "tsdown", | ||
| "lint": "biome check .", | ||
| "lint:fix": "biome check --write --unsafe .", | ||
| "format": "biome format --write .", | ||
| "typecheck": "tsc --noEmit", | ||
| "test:unit": "vitest" | ||
| } | ||
| } |
+18
-0
@@ -15,5 +15,9 @@ [](https://deno.bundlejs.com/?q=@ethernauta/cli&treeshake=[*]) | ||
| - [cli](https://github.com/niconiahi/ethernauta/tree/main/packages/cli) [[NPM](https://www.npmjs.com/package/@ethernauta/cli)] | ||
| - [core](https://github.com/niconiahi/ethernauta/tree/main/packages/core) [[NPM](https://www.npmjs.com/package/@ethernauta/core)] | ||
| - [crypto](https://github.com/niconiahi/ethernauta/tree/main/packages/crypto) [[NPM](https://www.npmjs.com/package/@ethernauta/crypto)] | ||
| - [eip](https://github.com/niconiahi/ethernauta/tree/main/packages/eip) [[NPM](https://www.npmjs.com/package/@ethernauta/eip)] | ||
| - [ens](https://github.com/niconiahi/ethernauta/tree/main/packages/ens) [[NPM](https://www.npmjs.com/package/@ethernauta/ens)] | ||
| - [erc](https://github.com/niconiahi/ethernauta/tree/main/packages/erc) [[NPM](https://www.npmjs.com/package/@ethernauta/erc)] | ||
| - [eth](https://github.com/niconiahi/ethernauta/tree/main/packages/eth) [[NPM](https://www.npmjs.com/package/@ethernauta/eth)] | ||
| - [react](https://github.com/niconiahi/ethernauta/tree/main/packages/react) [[NPM](https://www.npmjs.com/package/@ethernauta/react)] | ||
| - [transaction](https://github.com/niconiahi/ethernauta/tree/main/packages/transaction) [[NPM](https://www.npmjs.com/package/@ethernauta/transaction)] | ||
@@ -46,2 +50,9 @@ - [transport](https://github.com/niconiahi/ethernauta/tree/main/packages/transport) [[NPM](https://www.npmjs.com/package/@ethernauta/transport)] | ||
| Flags: | ||
| | Flag | Description | | ||
| | ------- | ---------------------------------------------------------------------------- | | ||
| | `--in` | Path to a raw ABI JSON array **or** a Foundry artifact with an `abi` field | | ||
| | `--out` | Output directory; the generator writes `<out>/methods/*.ts` + a barrel file | | ||
| ### `ethernauta registry` | ||
@@ -56,1 +67,8 @@ | ||
| The registry is used by the wallet to verify and display function names for transactions whose call data carries an unknown selector. | ||
| Flags: | ||
| | Flag | Description | | ||
| | ------- | ----------------------------------------------------------------- | | ||
| | `--in` | Directory walked recursively for `*.abi.json` files | | ||
| | `--out` | Output file path for the generated `REGISTRY` TypeScript module | |
+43
-26
@@ -17,11 +17,17 @@ import { | ||
| } from "@ethernauta/abi/generator" | ||
| import { array, parse } from "valibot" | ||
| import { type Bytes4, bytes4Schema } from "@ethernauta/core" | ||
| import { bytes_to_hex } from "@ethernauta/utils" | ||
| import { | ||
| array, | ||
| type InferOutput, | ||
| object, | ||
| parse, | ||
| string, | ||
| } from "valibot" | ||
| function selector_hex(signature: string): `0x${string}` { | ||
| const bytes = to_selector(signature) | ||
| let hex = "0x" | ||
| for (const b of bytes) { | ||
| hex += b.toString(16).padStart(2, "0") | ||
| } | ||
| return hex as `0x${string}` | ||
| function selector_hex(signature: string): Bytes4 { | ||
| return parse( | ||
| bytes4Schema, | ||
| bytes_to_hex(to_selector(signature)), | ||
| ) | ||
| } | ||
@@ -66,3 +72,3 @@ | ||
| function snake_or_kebab(name: string): string { | ||
| function _snake_or_kebab(name: string): string { | ||
| if (name.includes("_")) return name | ||
@@ -91,2 +97,3 @@ return name | ||
| functions: Description[], | ||
| generated_emit_names: Set<string>, | ||
| ): void { | ||
@@ -99,2 +106,3 @@ const seen = new Set<string>() | ||
| if (seen.has(js_name)) continue | ||
| if (!generated_emit_names.has(js_name)) continue | ||
| seen.add(js_name) | ||
@@ -112,6 +120,2 @@ const basename = emit_file_basename_for(f, functions) | ||
| if (d.type !== "function") return false | ||
| const is_readable = | ||
| d.stateMutability === "view" || | ||
| d.stateMutability === "pure" | ||
| if (is_readable && d.outputs.length > 1) return false | ||
| return true | ||
@@ -128,7 +132,19 @@ } | ||
| const generatable = functions.filter(is_generatable) | ||
| generate(generatable, out_dir) | ||
| write_barrel(out_dir, generatable) | ||
| const result = generate(generatable, out_dir) | ||
| write_barrel( | ||
| out_dir, | ||
| generatable, | ||
| new Set(result.generated), | ||
| ) | ||
| console.log( | ||
| `regenerated ${generatable.length} methods into ${out_dir}/methods/`, | ||
| `regenerated ${result.generated.length} methods into ${out_dir}/methods/`, | ||
| ) | ||
| if (result.skipped.length > 0) { | ||
| console.warn( | ||
| `skipped ${result.skipped.length} method(s):`, | ||
| ) | ||
| for (const s of result.skipped) { | ||
| console.warn(` - ${s.name}: ${s.reason}`) | ||
| } | ||
| } | ||
| } | ||
@@ -177,9 +193,10 @@ | ||
| type RegistryEntry = { | ||
| signature: string | ||
| name: string | ||
| types: string[] | ||
| param_names: string[] | ||
| source: string | ||
| } | ||
| const registryEntrySchema = object({ | ||
| signature: string(), | ||
| name: string(), | ||
| types: array(string()), | ||
| param_names: array(string()), | ||
| source: string(), | ||
| }) | ||
| type RegistryEntry = InferOutput<typeof registryEntrySchema> | ||
@@ -189,4 +206,4 @@ function collect_entries( | ||
| root: string, | ||
| ): Map<`0x${string}`, RegistryEntry> { | ||
| const out = new Map<`0x${string}`, RegistryEntry>() | ||
| ): Map<Bytes4, RegistryEntry> { | ||
| const out = new Map<Bytes4, RegistryEntry>() | ||
| for (const file of files) { | ||
@@ -229,3 +246,3 @@ const raw = load_abi(file) | ||
| function format_registry( | ||
| entries: Map<`0x${string}`, RegistryEntry>, | ||
| entries: Map<Bytes4, RegistryEntry>, | ||
| ): string { | ||
@@ -232,0 +249,0 @@ const sorted = Array.from(entries.entries()).sort( |
| export {} |
| import { | ||
| readFileSync, | ||
| readdirSync, | ||
| writeFileSync, | ||
| } from "node:fs" | ||
| import { join, resolve } from "node:path" | ||
| import { | ||
| DescriptionSchema, | ||
| to_selector, | ||
| } from "@ethernauta/abi" | ||
| import { | ||
| emit_file_basename_for, | ||
| emit_name_for, | ||
| generate, | ||
| } from "@ethernauta/abi/generator" | ||
| import { array, parse } from "valibot" | ||
| //#region src/execute.ts | ||
| function selector_hex(signature) { | ||
| const bytes = to_selector(signature) | ||
| let hex = "0x" | ||
| for (const b of bytes) | ||
| hex += b.toString(16).padStart(2, "0") | ||
| return hex | ||
| } | ||
| function parse_flags(args) { | ||
| let in_path | ||
| let out_dir | ||
| for (let i = 0; i < args.length; i++) { | ||
| const arg = args[i] | ||
| if (arg === "--in") in_path = args[++i] | ||
| else if (arg === "--out") out_dir = args[++i] | ||
| } | ||
| if (!in_path || !out_dir) | ||
| throw new Error( | ||
| "usage: ethernauta abi --in <path> --out <dir>", | ||
| ) | ||
| return { | ||
| in_path: resolve(process.cwd(), in_path), | ||
| out_dir: resolve(process.cwd(), out_dir), | ||
| } | ||
| } | ||
| function load_abi(path) { | ||
| const raw = JSON.parse(readFileSync(path, "utf8")) | ||
| if (Array.isArray(raw)) return raw | ||
| if (Array.isArray(raw.abi)) return raw.abi | ||
| throw new Error( | ||
| `expected an ABI JSON array or a foundry artifact with an \`abi\` array at ${path}`, | ||
| ) | ||
| } | ||
| function signature_key(d) { | ||
| if (d.type !== "function") return d.type | ||
| const param_types = d.inputs.map((i) => i.type).join(",") | ||
| return `${d.name}(${param_types})` | ||
| } | ||
| function dedupe_by_signature(descriptions) { | ||
| const seen = /* @__PURE__ */ new Set() | ||
| const out = [] | ||
| for (const d of descriptions) { | ||
| const key = signature_key(d) | ||
| if (seen.has(key)) continue | ||
| seen.add(key) | ||
| out.push(d) | ||
| } | ||
| return out | ||
| } | ||
| function write_barrel(out_dir, functions) { | ||
| const seen = /* @__PURE__ */ new Set() | ||
| const lines = [] | ||
| for (const f of functions) { | ||
| if (f.type !== "function") continue | ||
| const js_name = emit_name_for(f, functions) | ||
| if (seen.has(js_name)) continue | ||
| seen.add(js_name) | ||
| const basename = emit_file_basename_for(f, functions) | ||
| lines.push(`export { ${js_name} } from "./${basename}"`) | ||
| } | ||
| writeFileSync( | ||
| join(out_dir, "methods", "index.ts"), | ||
| `${lines.join("\n")}\n`, | ||
| ) | ||
| } | ||
| function is_generatable(d) { | ||
| if (d.type !== "function") return false | ||
| if ( | ||
| (d.stateMutability === "view" || | ||
| d.stateMutability === "pure") && | ||
| d.outputs.length > 1 | ||
| ) | ||
| return false | ||
| return true | ||
| } | ||
| function execute_abi(args) { | ||
| const { in_path, out_dir } = parse_flags(args) | ||
| const raw = load_abi(in_path) | ||
| const generatable = dedupe_by_signature( | ||
| parse(array(DescriptionSchema), raw).filter( | ||
| (d) => d.type === "function", | ||
| ), | ||
| ).filter(is_generatable) | ||
| generate(generatable, out_dir) | ||
| write_barrel(out_dir, generatable) | ||
| console.log( | ||
| `regenerated ${generatable.length} methods into ${out_dir}/methods/`, | ||
| ) | ||
| } | ||
| function parse_registry_flags(args) { | ||
| let in_dir | ||
| let out_file | ||
| for (let i = 0; i < args.length; i++) { | ||
| const arg = args[i] | ||
| if (arg === "--in") in_dir = args[++i] | ||
| else if (arg === "--out") out_file = args[++i] | ||
| } | ||
| if (!in_dir || !out_file) | ||
| throw new Error( | ||
| "usage: ethernauta registry --in <dir> --out <file>", | ||
| ) | ||
| return { | ||
| in_dir: resolve(process.cwd(), in_dir), | ||
| out_file: resolve(process.cwd(), out_file), | ||
| } | ||
| } | ||
| function walk_abi_jsons(root) { | ||
| const found = [] | ||
| const stack = [root] | ||
| while (stack.length > 0) { | ||
| const dir = stack.pop() | ||
| for (const entry of readdirSync(dir, { | ||
| withFileTypes: true, | ||
| })) { | ||
| const full = join(dir, entry.name) | ||
| if (entry.isDirectory()) stack.push(full) | ||
| else if (entry.name.endsWith(".abi.json")) | ||
| found.push(full) | ||
| } | ||
| } | ||
| return found.sort() | ||
| } | ||
| function collect_entries(files, root) { | ||
| const out = /* @__PURE__ */ new Map() | ||
| for (const file of files) { | ||
| const raw = load_abi(file) | ||
| const descriptions = parse( | ||
| array(DescriptionSchema), | ||
| raw, | ||
| ) | ||
| for (const d of descriptions) { | ||
| if (d.type !== "function") continue | ||
| const types = d.inputs.map((i) => i.type) | ||
| const param_names = d.inputs.map((i) => i.name) | ||
| const signature = `${d.name}(${types.join(",")})` | ||
| const selector = selector_hex(signature) | ||
| const relative = file.startsWith(`${root}/`) | ||
| ? file.slice(root.length + 1) | ||
| : file | ||
| const existing = out.get(selector) | ||
| if (existing) { | ||
| if (existing.signature !== signature) | ||
| throw new Error( | ||
| `selector collision ${selector}: '${existing.signature}' (${existing.source}) vs '${signature}' (${relative})`, | ||
| ) | ||
| continue | ||
| } | ||
| out.set(selector, { | ||
| signature, | ||
| name: d.name, | ||
| types, | ||
| param_names, | ||
| source: relative, | ||
| }) | ||
| } | ||
| } | ||
| return out | ||
| } | ||
| function format_registry(entries) { | ||
| return `// AUTO-GENERATED — do not edit. Run \`pnpm --filter @ethernauta/erc generate\`. | ||
| export const REGISTRY = { | ||
| ${Array.from(entries.entries()) | ||
| .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) | ||
| .map(([selector, entry]) => { | ||
| const types = entry.types | ||
| .map((t) => JSON.stringify(t)) | ||
| .join(", ") | ||
| const names = entry.param_names | ||
| .map((n) => JSON.stringify(n)) | ||
| .join(", ") | ||
| return ` ${JSON.stringify(selector)}: { name: ${JSON.stringify(entry.name)}, signature: ${JSON.stringify(entry.signature)}, types: [${types}], param_names: [${names}] },` | ||
| }) | ||
| .join("\n")} | ||
| } as const | ||
| export type RegistrySelector = keyof typeof REGISTRY | ||
| export type RegistryEntry = (typeof REGISTRY)[RegistrySelector] | ||
| ` | ||
| } | ||
| function execute_registry(args) { | ||
| const { in_dir, out_file } = parse_registry_flags(args) | ||
| const files = walk_abi_jsons(in_dir) | ||
| const entries = collect_entries(files, in_dir) | ||
| writeFileSync(out_file, format_registry(entries)) | ||
| console.log( | ||
| `wrote ${entries.size} registry entries from ${files.length} ABI JSONs to ${out_file}`, | ||
| ) | ||
| } | ||
| //#endregion | ||
| export { execute_registry as n, execute_abi as t } | ||
| //# sourceMappingURL=execute-DKX5w-or.js.map |
| {"version":3,"file":"execute-DKX5w-or.js","names":[],"sources":["../src/execute.ts"],"sourcesContent":["import {\n readdirSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\"\nimport { join, resolve } from \"node:path\"\nimport {\n type Description,\n DescriptionSchema,\n to_selector,\n} from \"@ethernauta/abi\"\nimport {\n emit_file_basename_for,\n emit_name_for,\n generate,\n} from \"@ethernauta/abi/generator\"\nimport { array, parse } from \"valibot\"\n\nfunction selector_hex(signature: string): `0x${string}` {\n const bytes = to_selector(signature)\n let hex = \"0x\"\n for (const b of bytes) {\n hex += b.toString(16).padStart(2, \"0\")\n }\n return hex as `0x${string}`\n}\n\nfunction parse_flags(args: string[]) {\n let in_path: string | undefined\n let out_dir: string | undefined\n for (let i = 0; i < args.length; i++) {\n const arg = args[i] as string\n if (arg === \"--in\") {\n in_path = args[++i]\n } else if (arg === \"--out\") {\n out_dir = args[++i]\n }\n }\n if (!in_path || !out_dir) {\n throw new Error(\n \"usage: ethernauta abi --in <path> --out <dir>\",\n )\n }\n return {\n in_path: resolve(process.cwd(), in_path),\n out_dir: resolve(process.cwd(), out_dir),\n }\n}\n\nfunction load_abi(path: string): unknown[] {\n const raw = JSON.parse(readFileSync(path, \"utf8\"))\n if (Array.isArray(raw)) return raw\n if (Array.isArray(raw.abi)) return raw.abi\n throw new Error(\n `expected an ABI JSON array or a foundry artifact with an \\`abi\\` array at ${path}`,\n )\n}\n\nfunction signature_key(d: Description): string {\n if (d.type !== \"function\") return d.type\n const param_types = d.inputs.map((i) => i.type).join(\",\")\n return `${d.name}(${param_types})`\n}\n\nfunction snake_or_kebab(name: string): string {\n if (name.includes(\"_\")) return name\n return name\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .toLowerCase()\n}\n\nfunction dedupe_by_signature(\n descriptions: Description[],\n): Description[] {\n const seen = new Set<string>()\n const out: Description[] = []\n for (const d of descriptions) {\n const key = signature_key(d)\n if (seen.has(key)) continue\n seen.add(key)\n out.push(d)\n }\n return out\n}\n\nfunction write_barrel(\n out_dir: string,\n functions: Description[],\n): void {\n const seen = new Set<string>()\n const lines: string[] = []\n for (const f of functions) {\n if (f.type !== \"function\") continue\n const js_name = emit_name_for(f, functions)\n if (seen.has(js_name)) continue\n seen.add(js_name)\n const basename = emit_file_basename_for(f, functions)\n lines.push(`export { ${js_name} } from \"./${basename}\"`)\n }\n writeFileSync(\n join(out_dir, \"methods\", \"index.ts\"),\n `${lines.join(\"\\n\")}\\n`,\n )\n}\n\nfunction is_generatable(d: Description): boolean {\n if (d.type !== \"function\") return false\n const is_readable =\n d.stateMutability === \"view\" ||\n d.stateMutability === \"pure\"\n if (is_readable && d.outputs.length > 1) return false\n return true\n}\n\nexport function execute_abi(args: string[]): void {\n const { in_path, out_dir } = parse_flags(args)\n const raw = load_abi(in_path)\n const descriptions = parse(array(DescriptionSchema), raw)\n const functions = dedupe_by_signature(\n descriptions.filter((d) => d.type === \"function\"),\n )\n const generatable = functions.filter(is_generatable)\n generate(generatable, out_dir)\n write_barrel(out_dir, generatable)\n console.log(\n `regenerated ${generatable.length} methods into ${out_dir}/methods/`,\n )\n}\n\nfunction parse_registry_flags(args: string[]) {\n let in_dir: string | undefined\n let out_file: string | undefined\n for (let i = 0; i < args.length; i++) {\n const arg = args[i] as string\n if (arg === \"--in\") {\n in_dir = args[++i]\n } else if (arg === \"--out\") {\n out_file = args[++i]\n }\n }\n if (!in_dir || !out_file) {\n throw new Error(\n \"usage: ethernauta registry --in <dir> --out <file>\",\n )\n }\n return {\n in_dir: resolve(process.cwd(), in_dir),\n out_file: resolve(process.cwd(), out_file),\n }\n}\n\nfunction walk_abi_jsons(root: string): string[] {\n const found: string[] = []\n const stack = [root]\n while (stack.length > 0) {\n const dir = stack.pop() as string\n for (const entry of readdirSync(dir, {\n withFileTypes: true,\n })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory()) {\n stack.push(full)\n } else if (entry.name.endsWith(\".abi.json\")) {\n found.push(full)\n }\n }\n }\n return found.sort()\n}\n\ntype RegistryEntry = {\n signature: string\n name: string\n types: string[]\n param_names: string[]\n source: string\n}\n\nfunction collect_entries(\n files: string[],\n root: string,\n): Map<`0x${string}`, RegistryEntry> {\n const out = new Map<`0x${string}`, RegistryEntry>()\n for (const file of files) {\n const raw = load_abi(file)\n const descriptions = parse(\n array(DescriptionSchema),\n raw,\n )\n for (const d of descriptions) {\n if (d.type !== \"function\") continue\n const types = d.inputs.map((i) => i.type)\n const param_names = d.inputs.map((i) => i.name)\n const signature = `${d.name}(${types.join(\",\")})`\n const selector = selector_hex(signature)\n const relative = file.startsWith(`${root}/`)\n ? file.slice(root.length + 1)\n : file\n const existing = out.get(selector)\n if (existing) {\n if (existing.signature !== signature) {\n throw new Error(\n `selector collision ${selector}: '${existing.signature}' (${existing.source}) vs '${signature}' (${relative})`,\n )\n }\n continue\n }\n out.set(selector, {\n signature,\n name: d.name,\n types,\n param_names,\n source: relative,\n })\n }\n }\n return out\n}\n\nfunction format_registry(\n entries: Map<`0x${string}`, RegistryEntry>,\n): string {\n const sorted = Array.from(entries.entries()).sort(\n ([a], [b]) => (a < b ? -1 : a > b ? 1 : 0),\n )\n const rows = sorted.map(([selector, entry]) => {\n const types = entry.types\n .map((t) => JSON.stringify(t))\n .join(\", \")\n const names = entry.param_names\n .map((n) => JSON.stringify(n))\n .join(\", \")\n return ` ${JSON.stringify(selector)}: { name: ${JSON.stringify(entry.name)}, signature: ${JSON.stringify(entry.signature)}, types: [${types}], param_names: [${names}] },`\n })\n return `// AUTO-GENERATED — do not edit. Run \\`pnpm --filter @ethernauta/erc generate\\`.\n\nexport const REGISTRY = {\n${rows.join(\"\\n\")}\n} as const\n\nexport type RegistrySelector = keyof typeof REGISTRY\nexport type RegistryEntry = (typeof REGISTRY)[RegistrySelector]\n`\n}\n\nexport function execute_registry(args: string[]): void {\n const { in_dir, out_file } = parse_registry_flags(args)\n const files = walk_abi_jsons(in_dir)\n const entries = collect_entries(files, in_dir)\n writeFileSync(out_file, format_registry(entries))\n console.log(\n `wrote ${entries.size} registry entries from ${files.length} ABI JSONs to ${out_file}`,\n )\n}\n"],"mappings":"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"} |
| //#region src/execute.d.ts | ||
| declare function execute_abi(args: string[]): void | ||
| declare function execute_registry(args: string[]): void | ||
| //#endregion | ||
| export { execute_abi, execute_registry } | ||
| //# sourceMappingURL=index-BUis45IC.d.ts.map |
| {"version":3,"file":"index-BUis45IC.d.ts","names":[],"sources":["../src/execute.ts"],"mappings":";iBAkHgB,WAAA;AAAA,iBAmIA,gBAAA,CAnIW,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA"} |
33944
7.03%72
33.33%4
100%489
-7.21%+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
Updated