From cef0269ada662c3556d6d169fc64367d915fce23 Mon Sep 17 00:00:00 2001 From: blastonyz Date: Wed, 8 Jul 2026 22:49:33 -0300 Subject: [PATCH] fix: resolve Windows path separator issue in zkit generated types Normalize backslash import paths from @solarity/zktype on Windows and replace cmd & postinstall chaining with a cross-platform compile runner. Fixes: Error Cannot find module ..helpers during hardhat zkit verifiers. Co-authored-by: Cursor --- docs/PR-WINDOWS-ZKIT.md | 37 ++++++++++++++++++++++++ docs/WINDOWS-ZKIT.md | 35 +++++++++++++++++++++++ package.json | 7 ++++- scripts/fix-win-paths.js | 51 ++++++++++++++++++++++++++++++++++ scripts/run-compile.cjs | 30 ++++++++++++++++++++ scripts/run-zkit-verifiers.cjs | 29 +++++++++++++++++++ scripts/zkit-require-alias.cjs | 13 +++++++++ 7 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 docs/PR-WINDOWS-ZKIT.md create mode 100644 docs/WINDOWS-ZKIT.md create mode 100644 scripts/fix-win-paths.js create mode 100644 scripts/run-compile.cjs create mode 100644 scripts/run-zkit-verifiers.cjs create mode 100644 scripts/zkit-require-alias.cjs diff --git a/docs/PR-WINDOWS-ZKIT.md b/docs/PR-WINDOWS-ZKIT.md new file mode 100644 index 0000000..c921430 --- /dev/null +++ b/docs/PR-WINDOWS-ZKIT.md @@ -0,0 +1,37 @@ +## Problem + +Running `npm run compile` on Windows fails with: + +``` +Error: Cannot find module '..helpers' +``` + +`@solarity/zktype` uses `path.relative()` to build import paths in generated `.ts` files. +On Windows, that produces backslashes (`from "..\helpers"`), which Node cannot resolve as a module path. + +The existing `postinstall` script also used `cmd &` instead of sequential `&&`, which breaks the compile chain on Windows. + +## Affected files + +- `generated-types/zkit/core/*.ts` (and `index.ts`) — autogenerated on `zkit make` + +## Fix + +- Add `scripts/fix-win-paths.js` — normalizes `\` → `/` in import/require paths after `zkit make` +- Add `scripts/run-compile.cjs` — cross-platform sequential compile pipeline +- Add `scripts/zkit-require-alias.cjs` + `scripts/run-zkit-verifiers.cjs` — fallback during verifier generation +- Update `package.json`: `compile`, `postinstall`, `zkit:*` scripts + +## Testing + +- [x] `npm run compile` on Windows 11 — 5 circuits compiled, 5 verifiers generated +- [ ] `npm run compile` on macOS/Linux (expected no-op path fix, 0 files changed) +- [x] `generated-types/zkit/core/BurnCircuit.ts` imports `from "../helpers"` after fix + +## Related + +Upstream issue in `@solarity/zktype` path generation on Windows (`ZkitTSGenerator.ts` → `path.relative` without POSIX normalization). + +## Contribution + +Team1Latam / Avalanche hackathon — enabling Windows developers to build on EncryptedERC without WSL-only workflows. diff --git a/docs/WINDOWS-ZKIT.md b/docs/WINDOWS-ZKIT.md new file mode 100644 index 0000000..648958c --- /dev/null +++ b/docs/WINDOWS-ZKIT.md @@ -0,0 +1,35 @@ +# Windows — zkit generated import paths + +## Problem + +Running `npm run compile` on Windows fails with: + +``` +Error: Cannot find module '..helpers' +``` + +`@solarity/zktype` builds helper import paths with `path.relative()`. On Windows that yields +backslashes (`from "..\helpers"`), which Node treats as an invalid module name. + +## Fix + +1. `scripts/fix-win-paths.js` — after `zkit make`, rewrite `\` → `/` in generated `.ts` files. +2. `scripts/zkit-require-alias.cjs` — fallback resolver during `zkit verifiers`. +3. `scripts/run-compile.cjs` — cross-platform sequential `compile` (replaces `cmd &` chaining). + +## Usage + +```bash +npm run compile +``` + +Individual steps: + +```bash +npm run hardhat:compile +npm run zkit:make +npm run zkit:fix-paths +npm run zkit:verifiers +``` + +No-op on Linux/macOS when paths already use `/`. diff --git a/package.json b/package.json index f4bcde9..7385c91 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,12 @@ }, "scripts": { "test": "mocha 'src/**/*.test.js'", - "postinstall": "npx hardhat compile & npx hardhat zkit make --force && npx hardhat zkit verifiers", + "compile": "node scripts/run-compile.cjs", + "postinstall": "node scripts/run-compile.cjs", + "hardhat:compile": "hardhat compile", + "zkit:make": "hardhat zkit make --force && node scripts/fix-win-paths.js", + "zkit:fix-paths": "node scripts/fix-win-paths.js", + "zkit:verifiers": "node scripts/run-zkit-verifiers.cjs", "lint:sol": "solhint '**/*.sol' --config ./.solhint.json --ignore-path ./.solhintignore --max-warnings 0 && npx prettier --check '**/*.sol' --config ./.prettierrc", "lint:ts": "npx biome lint .", "lint": "npm run lint:sol && npm run lint:ts" diff --git a/scripts/fix-win-paths.js b/scripts/fix-win-paths.js new file mode 100644 index 0000000..009470a --- /dev/null +++ b/scripts/fix-win-paths.js @@ -0,0 +1,51 @@ +// Normalize backslashes in zkit generated TypeScript import/require paths (Windows). +// @solarity/zktype uses path.relative() which emits `\` on Windows; Node cannot resolve those. +const fs = require("fs"); +const path = require("path"); + +const root = path.join(__dirname, "..", "generated-types", "zkit"); + +function walk(dir) { + if (!fs.existsSync(dir)) { + return []; + } + + return fs.readdirSync(dir, {withFileTypes: true}).flatMap((entry) => { + const fullPath = path.join(dir, entry.name); + return entry.isDirectory() ? walk(fullPath) : [fullPath]; + }); +} + +if (!fs.existsSync(root)) { + console.log("No generated-types found, skipping path fix."); + process.exit(0); +} + +let fixed = 0; + +for (const filePath of walk(root)) { + if (!filePath.endsWith(".ts")) { + continue; + } + + const original = fs.readFileSync(filePath, "utf8"); + let content = original; + + content = content.replace(/from\s+(['"])([^'"]*)\1/g, (match, quote, importPath) => { + const normalized = importPath.replace(/\\/g, "/"); + return normalized === importPath ? match : `from ${quote}${normalized}${quote}`; + }); + + content = content.replace(/require\((['"])([^'"]*)\1\)/g, (match, quote, importPath) => { + const normalized = importPath.replace(/\\/g, "/"); + return normalized === importPath ? match : `require(${quote}${normalized}${quote})`; + }); + + if (content !== original) { + fs.writeFileSync(filePath, content); + console.log(`Fixed paths in: ${path.relative(process.cwd(), filePath)}`); + fixed++; + } +} + +console.log(`Fixed ${fixed} file(s).`); diff --git a/scripts/run-compile.cjs b/scripts/run-compile.cjs new file mode 100644 index 0000000..dd3fa8a --- /dev/null +++ b/scripts/run-compile.cjs @@ -0,0 +1,30 @@ +const {spawnSync} = require("child_process"); + +const steps = [ + ["hardhat", ["compile"]], + ["hardhat", ["zkit", "make", "--force"]], + ["node", ["scripts/fix-win-paths.js"]], +]; + +const hardhatBin = require("path").join( + __dirname, + "..", + "node_modules", + ".bin", + process.platform === "win32" ? "hardhat.cmd" : "hardhat", +); + +for (const [cmd, args] of steps) { + const bin = cmd === "hardhat" ? hardhatBin : cmd; + const result = spawnSync(bin, args, { + stdio: "inherit", + shell: process.platform === "win32", + cwd: require("path").join(__dirname, ".."), + }); + + if (result.status !== 0) { + process.exit(result.status ?? 1); + } +} + +require("./run-zkit-verifiers.cjs"); diff --git a/scripts/run-zkit-verifiers.cjs b/scripts/run-zkit-verifiers.cjs new file mode 100644 index 0000000..4ca1cc5 --- /dev/null +++ b/scripts/run-zkit-verifiers.cjs @@ -0,0 +1,29 @@ +const {spawnSync} = require("child_process"); +const path = require("path"); + +const preload = path.join(__dirname, "zkit-require-alias.cjs"); +const hardhatBin = path.join( + __dirname, + "..", + "node_modules", + ".bin", + process.platform === "win32" ? "hardhat.cmd" : "hardhat", +); + +const existingNodeOptions = process.env.NODE_OPTIONS || ""; +const requireOption = `--require ${JSON.stringify(preload)}`; + +const result = spawnSync(hardhatBin, ["zkit", "verifiers"], { + stdio: "inherit", + shell: process.platform === "win32", + env: { + ...process.env, + NODE_OPTIONS: `${requireOption} ${existingNodeOptions}`.trim(), + }, +}); + +if (result.status !== 0) { + process.exit(result.status ?? 1); +} + +require("./fix-win-paths.js"); diff --git a/scripts/zkit-require-alias.cjs b/scripts/zkit-require-alias.cjs new file mode 100644 index 0000000..2102fd8 --- /dev/null +++ b/scripts/zkit-require-alias.cjs @@ -0,0 +1,13 @@ +// Fallback when generated imports were not yet normalized (e.g. during zkit verifiers). +const Module = require("module"); +const path = require("path"); + +const originalResolveFilename = Module._resolveFilename; + +Module._resolveFilename = function resolveZkitGeneratedHelpers(request, parent, isMain, options) { + if (request === "..helpers" || request.replace(/\\/g, "/") === "../helpers") { + return path.join(process.cwd(), "generated-types", "zkit", "helpers.ts"); + } + + return originalResolveFilename.call(this, request, parent, isMain, options); +};