From 384d71f9fe24a56eeade11889d44a54124e84ca3 Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Wed, 1 Nov 2023 19:49:57 +0000 Subject: [PATCH 1/7] feat: add `noir_codegen` package --- package.json | 1 + tooling/noir_codegen/.eslintignore | 2 + tooling/noir_codegen/.eslintrc.cjs | 3 + tooling/noir_codegen/.gitignore | 4 + tooling/noir_codegen/.mocharc.json | 11 ++ tooling/noir_codegen/README.md | 4 + tooling/noir_codegen/package.json | 49 +++++++ tooling/noir_codegen/src/index.ts | 25 ++++ tooling/noir_codegen/src/main.ts | 45 ++++++ tooling/noir_codegen/src/parseArgs.ts | 63 ++++++++ tooling/noir_codegen/src/utils/glob.ts | 11 ++ .../noir_codegen/test/assert_lt/Nargo.toml | 5 + .../noir_codegen/test/assert_lt/src/main.nr | 4 + .../test/assert_lt/target/assert_lt.json | 1 + tooling/noir_codegen/test/index.test.ts | 12 ++ tooling/noir_codegen/tsconfig.json | 20 +++ yarn.lock | 136 +++++++++++++++++- 17 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 tooling/noir_codegen/.eslintignore create mode 100644 tooling/noir_codegen/.eslintrc.cjs create mode 100644 tooling/noir_codegen/.gitignore create mode 100644 tooling/noir_codegen/.mocharc.json create mode 100644 tooling/noir_codegen/README.md create mode 100644 tooling/noir_codegen/package.json create mode 100644 tooling/noir_codegen/src/index.ts create mode 100644 tooling/noir_codegen/src/main.ts create mode 100644 tooling/noir_codegen/src/parseArgs.ts create mode 100644 tooling/noir_codegen/src/utils/glob.ts create mode 100644 tooling/noir_codegen/test/assert_lt/Nargo.toml create mode 100644 tooling/noir_codegen/test/assert_lt/src/main.nr create mode 100644 tooling/noir_codegen/test/assert_lt/target/assert_lt.json create mode 100644 tooling/noir_codegen/test/index.test.ts create mode 100644 tooling/noir_codegen/tsconfig.json diff --git a/package.json b/package.json index 47c77ffa945..0e86b100b7c 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "tooling/noir_js_types", "tooling/noirc_abi_wasm", "tooling/noir_js", + "tooling/noir_codegen", "tooling/noir_js_backend_barretenberg", "acvm-repo/acvm_js", "release-tests", diff --git a/tooling/noir_codegen/.eslintignore b/tooling/noir_codegen/.eslintignore new file mode 100644 index 00000000000..491fc35975b --- /dev/null +++ b/tooling/noir_codegen/.eslintignore @@ -0,0 +1,2 @@ +node_modules +lib diff --git a/tooling/noir_codegen/.eslintrc.cjs b/tooling/noir_codegen/.eslintrc.cjs new file mode 100644 index 00000000000..33335c2a877 --- /dev/null +++ b/tooling/noir_codegen/.eslintrc.cjs @@ -0,0 +1,3 @@ +module.exports = { + extends: ["../../.eslintrc.js"], +}; diff --git a/tooling/noir_codegen/.gitignore b/tooling/noir_codegen/.gitignore new file mode 100644 index 00000000000..721d05448d6 --- /dev/null +++ b/tooling/noir_codegen/.gitignore @@ -0,0 +1,4 @@ +crs +lib + +!test/*/target diff --git a/tooling/noir_codegen/.mocharc.json b/tooling/noir_codegen/.mocharc.json new file mode 100644 index 00000000000..82855d2ddf4 --- /dev/null +++ b/tooling/noir_codegen/.mocharc.json @@ -0,0 +1,11 @@ +{ + "require": "ts-node/register", + "loader": "ts-node/esm", + "extensions": [ + "ts", + "cjs" + ], + "spec": [ + "test/**/*.test.ts*" + ] +} \ No newline at end of file diff --git a/tooling/noir_codegen/README.md b/tooling/noir_codegen/README.md new file mode 100644 index 00000000000..c24c12ff987 --- /dev/null +++ b/tooling/noir_codegen/README.md @@ -0,0 +1,4 @@ + +## Acknowledgements + +`noir-codegen` repurposes the CLI code from https://github.com/dethcrypto/TypeChain, used under the MIT license. \ No newline at end of file diff --git a/tooling/noir_codegen/package.json b/tooling/noir_codegen/package.json new file mode 100644 index 00000000000..8023fe162c7 --- /dev/null +++ b/tooling/noir_codegen/package.json @@ -0,0 +1,49 @@ +{ + "name": "@noir-lang/noir_codegen", + "collaborators": [ + "The Noir Team " + ], + "version": "0.18.0", + "packageManager": "yarn@3.5.1", + "license": "(MIT OR Apache-2.0)", + "type": "module", + "dependencies": { + "@noir-lang/types": "workspace:*", + "glob": "^10.3.10", + "lodash": "^4.17.21", + "ts-command-line-args": "^2.5.1" + }, + "files": [ + "lib", + "package.json" + ], + "source": "src/index.ts", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "dev": "tsc-multi --watch", + "build": "tsc", + "test": "ts-node --esm src/main.ts ./test/assert_lt/target/** --out-dir ./test/codegen && yarn test:node && rm -rf ./test/codegen", + "test:node": "mocha --timeout 25000 --exit --config ./.mocharc.json", + "prettier": "prettier 'src/**/*.ts'", + "prettier:fix": "prettier --write 'src/**/*.ts' 'test/**/*.ts'", + "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0", + "nightly:version": "jq --arg new_version \"-$(git rev-parse --short HEAD)$1\" '.version = .version + $new_version' package.json > package-tmp.json && mv package-tmp.json package.json", + "publish": "echo 📡 publishing `$npm_package_name` && yarn npm publish", + "clean": "rm -rf ./lib" + }, + "devDependencies": { + "@types/chai": "^4", + "@types/lodash": "^4", + "@types/mocha": "^10.0.1", + "@types/node": "^20.6.2", + "@types/prettier": "^3", + "chai": "^4.3.8", + "eslint": "^8.50.0", + "eslint-plugin-prettier": "^5.0.0", + "mocha": "^10.2.0", + "prettier": "3.0.3", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/tooling/noir_codegen/src/index.ts b/tooling/noir_codegen/src/index.ts new file mode 100644 index 00000000000..ba81f52eb26 --- /dev/null +++ b/tooling/noir_codegen/src/index.ts @@ -0,0 +1,25 @@ +import { CompiledCircuit } from "@noir-lang/types"; + +const codegenImports = `import { InputMap, InputValue } from "@noir-lang/noirc_abi" +import { Noir } from "@noir-lang/noir_js"`; + + +const codegenFunction = (name: string, compiled_program: CompiledCircuit) => `export async function ${name}(args: InputMap): Promise { + const program = new Noir(${JSON.stringify(compiled_program)}); + const { returnValue } = await program.execute(args); + return returnValue +}` + +export const codegen = (programs: [string, CompiledCircuit][]): string => { + let results = [codegenImports]; + for (const [name, program] of programs) { + results.push(codegenFunction(name, stripUnwantedFields(program))); + } + + return results.join("\n\n"); +} + +function stripUnwantedFields(value: any): CompiledCircuit { + const { abi, bytecode } = value; + return { abi, bytecode }; +} diff --git a/tooling/noir_codegen/src/main.ts b/tooling/noir_codegen/src/main.ts new file mode 100644 index 00000000000..681fa84dd52 --- /dev/null +++ b/tooling/noir_codegen/src/main.ts @@ -0,0 +1,45 @@ +import { CompiledCircuit } from "@noir-lang/types"; +import fs from "fs"; +import path from "path" +import { parseArgs } from "./parseArgs.js"; +import { glob } from "./utils/glob.js"; +import { codegen } from "./index.js"; + +function main() { + const cliConfig = parseArgs() + const cwd = process.cwd() + + const files = getFilesToProcess(cwd, cliConfig.files) + if (files.length === 0) { + throw new Error('No files passed.' + '\n' + `\`${cliConfig.files}\` didn't match any input files in ${cwd}`) + } + + const programs = files.map((file_path): [string, CompiledCircuit] => { + const program_name = path.parse(file_path).name; + const file_contents = fs.readFileSync(file_path).toString() + const { abi, bytecode } = JSON.parse(file_contents); + + return [program_name, { abi, bytecode }] + }) + + const result = codegen(programs); + + const outputDir = path.resolve(cliConfig.outDir ?? "./codegen") + const outputFile = path.join(outputDir, "index.ts"); + if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir); + fs.writeFileSync(outputFile, result) +} + +function getFilesToProcess(cwd: string, filesOrPattern: string[]) { + let res = glob(cwd, filesOrPattern) + + if (res.length === 0) { + // If there are no files found, but first parameter is surrounded with single quotes, we try again without quotes + const match = filesOrPattern[0].match(/'([\s\S]*)'/)?.[1] + if (match) res = glob(cwd, [match]) + } + + return res +} + +main() diff --git a/tooling/noir_codegen/src/parseArgs.ts b/tooling/noir_codegen/src/parseArgs.ts new file mode 100644 index 00000000000..452dff309e5 --- /dev/null +++ b/tooling/noir_codegen/src/parseArgs.ts @@ -0,0 +1,63 @@ +import { parse as commandLineArgs } from 'ts-command-line-args' + +const DEFAULT_GLOB_PATTERN = './target/**/*.json' + +export interface ParsedArgs { + files: string[] + outDir?: string | undefined + inputDir?: string | undefined +} + +export function parseArgs(): ParsedArgs { + const rawOptions = commandLineArgs( + { + glob: { + type: String, + defaultOption: true, + multiple: true, + defaultValue: [DEFAULT_GLOB_PATTERN], + description: + 'Pattern that will be used to find program artifacts. Remember about adding quotes: noir-codegen "**/*.json".', + }, + 'out-dir': { type: String, optional: true, description: 'Output directory for generated files.' }, + 'input-dir': { + type: String, + optional: true, + description: 'Directory containing program artifact files. Inferred as lowest common path of all files if not specified.', + }, + help: { type: Boolean, defaultValue: false, alias: 'h', description: 'Prints this message.' }, + }, + { + helpArg: 'help', + headerContentSections: [ + { + content: `\ + noir-codegen generates TypeScript wrappers for Noir programs to simplify replicating your Noir logic in JS.`, + }, + ], + footerContentSections: [ + { + header: 'Example Usage', + content: `\ + noir-codegen --out-dir app/noir_programs './target/*.json' + + + You can read more about noir-codegen at {underline https://github.com/noir-lang/noir}.`, + }, + ], + }, + ) + + return { + files: rawOptions.glob, + outDir: rawOptions['out-dir'], + inputDir: rawOptions['input-dir'], + } +} + +interface CommandLineArgs { + glob: string[] + 'out-dir'?: string + 'input-dir'?: string + help: boolean +} \ No newline at end of file diff --git a/tooling/noir_codegen/src/utils/glob.ts b/tooling/noir_codegen/src/utils/glob.ts new file mode 100644 index 00000000000..70834bc89a2 --- /dev/null +++ b/tooling/noir_codegen/src/utils/glob.ts @@ -0,0 +1,11 @@ +import { sync as globSync } from 'glob' +import _ from "lodash"; +const { flatten, uniq } = _; + +export function glob(cwd: string, patternsOrFiles: string[]): string[] { + const matches = patternsOrFiles.map((p) => + globSync(p, { ignore: 'node_modules/**', absolute: true, cwd }), + ) + + return uniq(flatten(matches)) +} \ No newline at end of file diff --git a/tooling/noir_codegen/test/assert_lt/Nargo.toml b/tooling/noir_codegen/test/assert_lt/Nargo.toml new file mode 100644 index 00000000000..f32ec18cae7 --- /dev/null +++ b/tooling/noir_codegen/test/assert_lt/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "assert_lt" +type = "bin" +authors = [""] +[dependencies] diff --git a/tooling/noir_codegen/test/assert_lt/src/main.nr b/tooling/noir_codegen/test/assert_lt/src/main.nr new file mode 100644 index 00000000000..67b8c84bdcd --- /dev/null +++ b/tooling/noir_codegen/test/assert_lt/src/main.nr @@ -0,0 +1,4 @@ +fn main(x : u64, y : pub u64) -> pub u64 { + assert(x < y); + x + y +} diff --git a/tooling/noir_codegen/test/assert_lt/target/assert_lt.json b/tooling/noir_codegen/test/assert_lt/target/assert_lt.json new file mode 100644 index 00000000000..3b2b1b2c5a1 --- /dev/null +++ b/tooling/noir_codegen/test/assert_lt/target/assert_lt.json @@ -0,0 +1 @@ +{"hash":13834844072603749544,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"}],"param_witnesses":{"x":[1],"y":[2]},"return_type":{"kind":"integer","sign":"unsigned","width":64},"return_witnesses":[12]},"bytecode":"H4sIAAAAAAAA/+1WUW6DMAx1QksZoGr72jUcAiX8VbvJ0Oj9j7ChJpKbtXw0NpvUWkImUXixn53w3gDgHc6mfh7t/ZGMtR9TU96HeYuHtp36ZjLWfGIzjK7DthsPzjjTue6rcdZOrnX9MA49Dqa1kzl1gz3h2bL7sTDCMhmJbylmTDOT8WEhjXfjH/DcB8u8zwVygWifmL/9lTnWzSWKsxHA3QJf00vlveWvERJIUU4x0eb86aEJppljVox9oO+Py8QTV1Jnw6a85t7vSL8pwvN89j7gd88o8q79Gr2wRt3AeSFz4XvRSyokl5MAtSfgGO2ZCewdsDibLRVrDzIXTMxfqiLIGXPeMdY1gb/Fg8+tznJY50eSGmfB2DNrqciCD+tCRc4X5FNFJmIWnkhu3BL+t4qc8y75aySqIkvGOP9CRWKaGQ0ydUrsgUUVWXlfw4OpyAouVWQN66pITDPDqSJfQaZxuVVkxZhzzVgLTv5uHbDwXhN+vwGywklHPBQAAA=="} \ No newline at end of file diff --git a/tooling/noir_codegen/test/index.test.ts b/tooling/noir_codegen/test/index.test.ts new file mode 100644 index 00000000000..a4b3f586c0d --- /dev/null +++ b/tooling/noir_codegen/test/index.test.ts @@ -0,0 +1,12 @@ +import { expect } from 'chai'; +import { assert_lt } from "./codegen/index.js"; + +it('codegens a callable function', async () => { + const result = await assert_lt({ + x: '2', + y: '3', + }) + + expect(result).to.be.eq("0x05"); +}); + diff --git a/tooling/noir_codegen/tsconfig.json b/tooling/noir_codegen/tsconfig.json new file mode 100644 index 00000000000..532e9b192ce --- /dev/null +++ b/tooling/noir_codegen/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "esnext", + "declaration": true, + "emitDeclarationOnly": false, + "module": "ESNext", + "moduleResolution": "node", + "outDir": "./lib", + "esModuleInterop": true, + "resolveJsonModule": true, + "strict": true, + "noImplicitAny": false, + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 2efc4eabfec..59dfaaa7b12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3446,6 +3446,29 @@ __metadata: languageName: unknown linkType: soft +"@noir-lang/noir_codegen@workspace:tooling/noir_codegen": + version: 0.0.0-use.local + resolution: "@noir-lang/noir_codegen@workspace:tooling/noir_codegen" + dependencies: + "@noir-lang/types": "workspace:*" + "@types/chai": ^4 + "@types/lodash": ^4 + "@types/mocha": ^10.0.1 + "@types/node": ^20.6.2 + "@types/prettier": ^3 + chai: ^4.3.8 + eslint: ^8.50.0 + eslint-plugin-prettier: ^5.0.0 + glob: ^10.3.10 + lodash: ^4.17.21 + mocha: ^10.2.0 + prettier: 3.0.3 + ts-command-line-args: ^2.5.1 + ts-node: ^10.9.1 + typescript: ^5.2.2 + languageName: unknown + linkType: soft + "@noir-lang/noir_js@workspace:*, @noir-lang/noir_js@workspace:tooling/noir_js": version: 0.0.0-use.local resolution: "@noir-lang/noir_js@workspace:tooling/noir_js" @@ -4640,6 +4663,13 @@ __metadata: languageName: node linkType: hard +"@types/lodash@npm:^4": + version: 4.14.200 + resolution: "@types/lodash@npm:4.14.200" + checksum: 6471f8bb5da692a6ecf03a8da4935bfbc341e67ee9bcb4f5730bfacff0c367232548f0a01e8ac5ea18c6fe78fb085d502494e33ccb47a7ee87cbdee03b47d00d + languageName: node + linkType: hard + "@types/lru-cache@npm:^5.1.0": version: 5.1.1 resolution: "@types/lru-cache@npm:5.1.1" @@ -5971,6 +6001,13 @@ __metadata: languageName: node linkType: hard +"array-back@npm:^4.0.1, array-back@npm:^4.0.2": + version: 4.0.2 + resolution: "array-back@npm:4.0.2" + checksum: f30603270771eeb54e5aad5f54604c62b3577a18b6db212a7272b2b6c32049121b49431f656654790ed1469411e45f387e7627c0de8fd0515995cc40df9b9294 + languageName: node + linkType: hard + "array-back@npm:^6.2.2": version: 6.2.2 resolution: "array-back@npm:6.2.2" @@ -7271,6 +7308,18 @@ __metadata: languageName: node linkType: hard +"command-line-usage@npm:^6.1.0": + version: 6.1.3 + resolution: "command-line-usage@npm:6.1.3" + dependencies: + array-back: ^4.0.2 + chalk: ^2.4.2 + table-layout: ^1.0.2 + typical: ^5.2.0 + checksum: 8261d4e5536eb0bcddee0ec5e89c05bb2abd18e5760785c8078ede5020bc1c612cbe28eb6586f5ed4a3660689748e5aaad4a72f21566f4ef39393694e2fa1a0b + languageName: node + linkType: hard + "command-line-usage@npm:^7.0.0, command-line-usage@npm:^7.0.1": version: 7.0.1 resolution: "command-line-usage@npm:7.0.1" @@ -7966,7 +8015,7 @@ __metadata: languageName: node linkType: hard -"deep-extend@npm:^0.6.0": +"deep-extend@npm:^0.6.0, deep-extend@npm:~0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" checksum: 7be7e5a8d468d6b10e6a67c3de828f55001b6eb515d014f7aeb9066ce36bd5717161eb47d6a0f7bed8a9083935b465bc163ee2581c8b128d29bf61092fdf57a7 @@ -9818,6 +9867,21 @@ __metadata: languageName: node linkType: hard +"glob@npm:^10.3.10": + version: 10.3.10 + resolution: "glob@npm:10.3.10" + dependencies: + foreground-child: ^3.1.0 + jackspeak: ^2.3.5 + minimatch: ^9.0.1 + minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 + path-scurry: ^1.10.1 + bin: + glob: dist/esm/bin.mjs + checksum: 4f2fe2511e157b5a3f525a54092169a5f92405f24d2aed3142f4411df328baca13059f4182f1db1bf933e2c69c0bd89e57ae87edd8950cba8c7ccbe84f721cf3 + languageName: node + linkType: hard + "glob@npm:^7.0.0, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -11200,6 +11264,19 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^2.3.5": + version: 2.3.6 + resolution: "jackspeak@npm:2.3.6" + dependencies: + "@isaacs/cliui": ^8.0.2 + "@pkgjs/parseargs": ^0.11.0 + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 57d43ad11eadc98cdfe7496612f6bbb5255ea69fe51ea431162db302c2a11011642f50cfad57288bd0aea78384a0612b16e131944ad8ecd09d619041c8531b54 + languageName: node + linkType: hard + "jest-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-util@npm:29.7.0" @@ -14518,6 +14595,13 @@ __metadata: languageName: node linkType: hard +"reduce-flatten@npm:^2.0.0": + version: 2.0.0 + resolution: "reduce-flatten@npm:2.0.0" + checksum: 64393ef99a16b20692acfd60982d7fdbd7ff8d9f8f185c6023466444c6dd2abb929d67717a83cec7f7f8fb5f46a25d515b3b2bf2238fdbfcdbfd01d2a9e73cb8 + languageName: node + linkType: hard + "regenerate-unicode-properties@npm:^10.1.0": version: 10.1.1 resolution: "regenerate-unicode-properties@npm:10.1.1" @@ -15714,6 +15798,13 @@ __metadata: languageName: node linkType: hard +"string-format@npm:^2.0.0": + version: 2.0.0 + resolution: "string-format@npm:2.0.0" + checksum: dada2ef95f6d36c66562c673d95315f80457fa7dce2f3609a2e75d1190b98c88319028cf0a5b6c043d01c18d581b2641579f79480584ba030d6ac6fceb30bc55 + languageName: node + linkType: hard + "string-to-stream@npm:^3.0.1": version: 3.0.1 resolution: "string-to-stream@npm:3.0.1" @@ -15944,6 +16035,18 @@ __metadata: languageName: node linkType: hard +"table-layout@npm:^1.0.2": + version: 1.0.2 + resolution: "table-layout@npm:1.0.2" + dependencies: + array-back: ^4.0.1 + deep-extend: ~0.6.0 + typical: ^5.2.0 + wordwrapjs: ^4.0.0 + checksum: 8f41b5671f101a5195747ec1727b1d35ea2cd5bf85addda11cc2f4b36892db9696ce3c2c7334b5b8a122505b34d19135fede50e25678df71b0439e0704fd953f + languageName: node + linkType: hard + "table-layout@npm:^3.0.0": version: 3.0.2 resolution: "table-layout@npm:3.0.2" @@ -16205,6 +16308,20 @@ __metadata: languageName: node linkType: hard +"ts-command-line-args@npm:^2.5.1": + version: 2.5.1 + resolution: "ts-command-line-args@npm:2.5.1" + dependencies: + chalk: ^4.1.0 + command-line-args: ^5.1.1 + command-line-usage: ^6.1.0 + string-format: ^2.0.0 + bin: + write-markdown: dist/write-markdown.js + checksum: 7c0a7582e94f1d2160e3dd379851ec4f1758bc673ccd71bae07f839f83051b6b83e0ae14325c2d04ea728e5bde7b7eacfd2ab060b8fd4b8ab29e0bbf77f6c51e + languageName: node + linkType: hard + "ts-node@npm:^10.9.1": version: 10.9.1 resolution: "ts-node@npm:10.9.1" @@ -16458,6 +16575,13 @@ __metadata: languageName: node linkType: hard +"typical@npm:^5.2.0": + version: 5.2.0 + resolution: "typical@npm:5.2.0" + checksum: ccaeb151a9a556291b495571ca44c4660f736fb49c29314bbf773c90fad92e9485d3cc2b074c933866c1595abbbc962f2b8bfc6e0f52a8c6b0cdd205442036ac + languageName: node + linkType: hard + "typical@npm:^7.1.1": version: 7.1.1 resolution: "typical@npm:7.1.1" @@ -17247,6 +17371,16 @@ __metadata: languageName: node linkType: hard +"wordwrapjs@npm:^4.0.0": + version: 4.0.1 + resolution: "wordwrapjs@npm:4.0.1" + dependencies: + reduce-flatten: ^2.0.0 + typical: ^5.2.0 + checksum: 3d927f3c95d0ad990968da54c0ad8cde2801d8e91006cd7474c26e6b742cc8557250ce495c9732b2f9db1f903601cb74ec282e0f122ee0d02d7abe81e150eea8 + languageName: node + linkType: hard + "wordwrapjs@npm:^5.1.0": version: 5.1.0 resolution: "wordwrapjs@npm:5.1.0" From 66881960bd71dfdc3e5c4e558f863ed330b3af42 Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 2 Nov 2023 12:02:49 +0000 Subject: [PATCH 2/7] chore: linter --- tooling/noir_codegen/src/index.ts | 17 +++++----- tooling/noir_codegen/src/main.ts | 42 ++++++++++++------------- tooling/noir_codegen/src/parseArgs.ts | 27 ++++++++-------- tooling/noir_codegen/src/utils/glob.ts | 12 +++---- tooling/noir_codegen/test/index.test.ts | 7 ++--- 5 files changed, 53 insertions(+), 52 deletions(-) diff --git a/tooling/noir_codegen/src/index.ts b/tooling/noir_codegen/src/index.ts index ba81f52eb26..40a47575a1c 100644 --- a/tooling/noir_codegen/src/index.ts +++ b/tooling/noir_codegen/src/index.ts @@ -1,24 +1,27 @@ -import { CompiledCircuit } from "@noir-lang/types"; +import { CompiledCircuit } from '@noir-lang/types'; const codegenImports = `import { InputMap, InputValue } from "@noir-lang/noirc_abi" import { Noir } from "@noir-lang/noir_js"`; - -const codegenFunction = (name: string, compiled_program: CompiledCircuit) => `export async function ${name}(args: InputMap): Promise { +const codegenFunction = ( + name: string, + compiled_program: CompiledCircuit, +) => `export async function ${name}(args: InputMap): Promise { const program = new Noir(${JSON.stringify(compiled_program)}); const { returnValue } = await program.execute(args); return returnValue -}` +}`; export const codegen = (programs: [string, CompiledCircuit][]): string => { - let results = [codegenImports]; + const results = [codegenImports]; for (const [name, program] of programs) { results.push(codegenFunction(name, stripUnwantedFields(program))); } - return results.join("\n\n"); -} + return results.join('\n\n'); +}; +// eslint-disable-next-line @typescript-eslint/no-explicit-any function stripUnwantedFields(value: any): CompiledCircuit { const { abi, bytecode } = value; return { abi, bytecode }; diff --git a/tooling/noir_codegen/src/main.ts b/tooling/noir_codegen/src/main.ts index 681fa84dd52..023c4a80872 100644 --- a/tooling/noir_codegen/src/main.ts +++ b/tooling/noir_codegen/src/main.ts @@ -1,45 +1,45 @@ -import { CompiledCircuit } from "@noir-lang/types"; -import fs from "fs"; -import path from "path" -import { parseArgs } from "./parseArgs.js"; -import { glob } from "./utils/glob.js"; -import { codegen } from "./index.js"; +import { CompiledCircuit } from '@noir-lang/types'; +import fs from 'fs'; +import path from 'path'; +import { parseArgs } from './parseArgs.js'; +import { glob } from './utils/glob.js'; +import { codegen } from './index.js'; function main() { - const cliConfig = parseArgs() - const cwd = process.cwd() + const cliConfig = parseArgs(); + const cwd = process.cwd(); - const files = getFilesToProcess(cwd, cliConfig.files) + const files = getFilesToProcess(cwd, cliConfig.files); if (files.length === 0) { - throw new Error('No files passed.' + '\n' + `\`${cliConfig.files}\` didn't match any input files in ${cwd}`) + throw new Error('No files passed.' + '\n' + `\`${cliConfig.files}\` didn't match any input files in ${cwd}`); } const programs = files.map((file_path): [string, CompiledCircuit] => { const program_name = path.parse(file_path).name; - const file_contents = fs.readFileSync(file_path).toString() + const file_contents = fs.readFileSync(file_path).toString(); const { abi, bytecode } = JSON.parse(file_contents); - return [program_name, { abi, bytecode }] - }) + return [program_name, { abi, bytecode }]; + }); const result = codegen(programs); - const outputDir = path.resolve(cliConfig.outDir ?? "./codegen") - const outputFile = path.join(outputDir, "index.ts"); + const outputDir = path.resolve(cliConfig.outDir ?? './codegen'); + const outputFile = path.join(outputDir, 'index.ts'); if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir); - fs.writeFileSync(outputFile, result) + fs.writeFileSync(outputFile, result); } function getFilesToProcess(cwd: string, filesOrPattern: string[]) { - let res = glob(cwd, filesOrPattern) + let res = glob(cwd, filesOrPattern); if (res.length === 0) { // If there are no files found, but first parameter is surrounded with single quotes, we try again without quotes - const match = filesOrPattern[0].match(/'([\s\S]*)'/)?.[1] - if (match) res = glob(cwd, [match]) + const match = filesOrPattern[0].match(/'([\s\S]*)'/)?.[1]; + if (match) res = glob(cwd, [match]); } - return res + return res; } -main() +main(); diff --git a/tooling/noir_codegen/src/parseArgs.ts b/tooling/noir_codegen/src/parseArgs.ts index 452dff309e5..58468c1b8f8 100644 --- a/tooling/noir_codegen/src/parseArgs.ts +++ b/tooling/noir_codegen/src/parseArgs.ts @@ -1,11 +1,11 @@ -import { parse as commandLineArgs } from 'ts-command-line-args' +import { parse as commandLineArgs } from 'ts-command-line-args'; -const DEFAULT_GLOB_PATTERN = './target/**/*.json' +const DEFAULT_GLOB_PATTERN = './target/**/*.json'; export interface ParsedArgs { - files: string[] - outDir?: string | undefined - inputDir?: string | undefined + files: string[]; + outDir?: string | undefined; + inputDir?: string | undefined; } export function parseArgs(): ParsedArgs { @@ -23,7 +23,8 @@ export function parseArgs(): ParsedArgs { 'input-dir': { type: String, optional: true, - description: 'Directory containing program artifact files. Inferred as lowest common path of all files if not specified.', + description: + 'Directory containing program artifact files. Inferred as lowest common path of all files if not specified.', }, help: { type: Boolean, defaultValue: false, alias: 'h', description: 'Prints this message.' }, }, @@ -46,18 +47,18 @@ export function parseArgs(): ParsedArgs { }, ], }, - ) + ); return { files: rawOptions.glob, outDir: rawOptions['out-dir'], inputDir: rawOptions['input-dir'], - } + }; } interface CommandLineArgs { - glob: string[] - 'out-dir'?: string - 'input-dir'?: string - help: boolean -} \ No newline at end of file + glob: string[]; + 'out-dir'?: string; + 'input-dir'?: string; + help: boolean; +} diff --git a/tooling/noir_codegen/src/utils/glob.ts b/tooling/noir_codegen/src/utils/glob.ts index 70834bc89a2..15deaf72e44 100644 --- a/tooling/noir_codegen/src/utils/glob.ts +++ b/tooling/noir_codegen/src/utils/glob.ts @@ -1,11 +1,9 @@ -import { sync as globSync } from 'glob' -import _ from "lodash"; +import { sync as globSync } from 'glob'; +import _ from 'lodash'; const { flatten, uniq } = _; export function glob(cwd: string, patternsOrFiles: string[]): string[] { - const matches = patternsOrFiles.map((p) => - globSync(p, { ignore: 'node_modules/**', absolute: true, cwd }), - ) + const matches = patternsOrFiles.map((p) => globSync(p, { ignore: 'node_modules/**', absolute: true, cwd })); - return uniq(flatten(matches)) -} \ No newline at end of file + return uniq(flatten(matches)); +} diff --git a/tooling/noir_codegen/test/index.test.ts b/tooling/noir_codegen/test/index.test.ts index a4b3f586c0d..702ba1f9cbb 100644 --- a/tooling/noir_codegen/test/index.test.ts +++ b/tooling/noir_codegen/test/index.test.ts @@ -1,12 +1,11 @@ import { expect } from 'chai'; -import { assert_lt } from "./codegen/index.js"; +import { assert_lt } from './codegen/index.js'; it('codegens a callable function', async () => { const result = await assert_lt({ x: '2', y: '3', - }) + }); - expect(result).to.be.eq("0x05"); + expect(result).to.be.eq('0x05'); }); - From c489038de07cd3a802c05e999bfdbe9595b1c8e8 Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 2 Nov 2023 12:51:43 +0000 Subject: [PATCH 3/7] chore: create bin entry in package.json for noir-codegen --- tooling/noir_codegen/package.json | 3 +++ tooling/noir_codegen/tsconfig.json | 6 +++--- yarn.lock | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tooling/noir_codegen/package.json b/tooling/noir_codegen/package.json index 8023fe162c7..795a8d88138 100644 --- a/tooling/noir_codegen/package.json +++ b/tooling/noir_codegen/package.json @@ -20,6 +20,9 @@ "source": "src/index.ts", "main": "lib/index.js", "types": "lib/index.d.ts", + "bin": { + "noir-codegen": "lib/main.js" + }, "scripts": { "dev": "tsc-multi --watch", "build": "tsc", diff --git a/tooling/noir_codegen/tsconfig.json b/tooling/noir_codegen/tsconfig.json index 532e9b192ce..30dd2a7ee5f 100644 --- a/tooling/noir_codegen/tsconfig.json +++ b/tooling/noir_codegen/tsconfig.json @@ -3,8 +3,8 @@ "target": "esnext", "declaration": true, "emitDeclarationOnly": false, - "module": "ESNext", - "moduleResolution": "node", + "module": "NodeNext", + "moduleResolution": "NodeNext", "outDir": "./lib", "esModuleInterop": true, "resolveJsonModule": true, @@ -17,4 +17,4 @@ "exclude": [ "node_modules" ] -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index 59dfaaa7b12..4303e48edd0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3466,6 +3466,8 @@ __metadata: ts-command-line-args: ^2.5.1 ts-node: ^10.9.1 typescript: ^5.2.2 + bin: + noir-codegen: lib/main.js languageName: unknown linkType: soft From 130d6c12b6f309b19ceca58aabd00e9e637cb9ea Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 2 Nov 2023 15:27:00 +0000 Subject: [PATCH 4/7] chore: add shebang to noir-codegen cli --- tooling/noir_codegen/src/main.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tooling/noir_codegen/src/main.ts b/tooling/noir_codegen/src/main.ts index 023c4a80872..591e7420dba 100644 --- a/tooling/noir_codegen/src/main.ts +++ b/tooling/noir_codegen/src/main.ts @@ -1,3 +1,5 @@ +#! /usr/bin/env node + import { CompiledCircuit } from '@noir-lang/types'; import fs from 'fs'; import path from 'path'; From 2c9edfd7303895d4dc8299fafbe6dc4ac1690b32 Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 2 Nov 2023 15:29:04 +0000 Subject: [PATCH 5/7] chore: add missing semicolon --- tooling/noir_codegen/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/noir_codegen/src/index.ts b/tooling/noir_codegen/src/index.ts index 40a47575a1c..1f8d2d183d4 100644 --- a/tooling/noir_codegen/src/index.ts +++ b/tooling/noir_codegen/src/index.ts @@ -9,7 +9,7 @@ const codegenFunction = ( ) => `export async function ${name}(args: InputMap): Promise { const program = new Noir(${JSON.stringify(compiled_program)}); const { returnValue } = await program.execute(args); - return returnValue + return returnValue; }`; export const codegen = (programs: [string, CompiledCircuit][]): string => { From 07b7de064c4978c10c33480e0a56ecfeeeb7589c Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 2 Nov 2023 15:29:35 +0000 Subject: [PATCH 6/7] chore: add missing dev-dependency --- tooling/noir_codegen/package.json | 1 + yarn.lock | 1 + 2 files changed, 2 insertions(+) diff --git a/tooling/noir_codegen/package.json b/tooling/noir_codegen/package.json index 795a8d88138..9930ac2d603 100644 --- a/tooling/noir_codegen/package.json +++ b/tooling/noir_codegen/package.json @@ -36,6 +36,7 @@ "clean": "rm -rf ./lib" }, "devDependencies": { + "@noir-lang/noir_js": "workspace:*", "@types/chai": "^4", "@types/lodash": "^4", "@types/mocha": "^10.0.1", diff --git a/yarn.lock b/yarn.lock index 4303e48edd0..f423ba8b384 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3450,6 +3450,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/noir_codegen@workspace:tooling/noir_codegen" dependencies: + "@noir-lang/noir_js": "workspace:*" "@noir-lang/types": "workspace:*" "@types/chai": ^4 "@types/lodash": ^4 From 8fe37db1cb37e85d1ae449b67c71759b6c955770 Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 2 Nov 2023 15:29:46 +0000 Subject: [PATCH 7/7] chore: add noir_codegen to release-please --- release-please-config.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/release-please-config.json b/release-please-config.json index ddf6ff7b3a9..afc0bfd420d 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -24,6 +24,11 @@ "path": "compiler/wasm/package.json", "jsonpath": "$.version" }, + { + "type": "json", + "path": "tooling/noir_codegen/package.json", + "jsonpath": "$.version" + }, { "type": "json", "path": "tooling/noir_js/package.json", @@ -45,8 +50,8 @@ "jsonpath": "$.version" } ] - }, - "acvm-repo" : { + }, + "acvm-repo": { "release-type": "simple", "package-name": "acvm", "component": "acvm",