mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-14 05:21:03 +00:00
Move @parity/resolc from js-revive (#296)
- Move npm package from paritytech/js-revive - Rename package to `@parity/resolc`
This commit is contained in:
+2
-2
@@ -10,8 +10,8 @@ rustflags = [
|
|||||||
"-Clink-arg=-sWASM_ASYNC_COMPILATION=0",
|
"-Clink-arg=-sWASM_ASYNC_COMPILATION=0",
|
||||||
"-Clink-arg=-sDYNAMIC_EXECUTION=0",
|
"-Clink-arg=-sDYNAMIC_EXECUTION=0",
|
||||||
"-Clink-arg=-sALLOW_TABLE_GROWTH=1",
|
"-Clink-arg=-sALLOW_TABLE_GROWTH=1",
|
||||||
"-Clink-arg=--js-library=js/embed/soljson_interface.js",
|
"-Clink-arg=--js-library=js/emscripten/embed/soljson_interface.js",
|
||||||
"-Clink-arg=--pre-js=js/embed/pre.js",
|
"-Clink-arg=--pre-js=js/emscripten/embed/pre.js",
|
||||||
"-Clink-arg=-sSTACK_SIZE=128kb",
|
"-Clink-arg=-sSTACK_SIZE=128kb",
|
||||||
"-Clink-arg=-sNODEJS_CATCH_EXIT=0"
|
"-Clink-arg=-sNODEJS_CATCH_EXIT=0"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -286,3 +286,30 @@ jobs:
|
|||||||
resolc.wasm
|
resolc.wasm
|
||||||
resolc_web.js
|
resolc_web.js
|
||||||
checksums.txt
|
checksums.txt
|
||||||
|
|
||||||
|
npm-release:
|
||||||
|
needs: [create-release]
|
||||||
|
runs-on: macos-14
|
||||||
|
environment: tags
|
||||||
|
steps:
|
||||||
|
- name: Build
|
||||||
|
run: npm -w js/resolc run build
|
||||||
|
|
||||||
|
- name: Set version
|
||||||
|
run: npm -w js/resolc version --no-git-tag-version ${{github.event.release.tag_name}}
|
||||||
|
|
||||||
|
- name: npm pack
|
||||||
|
run: npm -w js/resolc pack
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: package
|
||||||
|
path: "parity-resolc-*.tgz"
|
||||||
|
|
||||||
|
- uses: octokit/request-action@bbedc70b1981e610d89f1f8de88311a1fc02fb83
|
||||||
|
with:
|
||||||
|
route: POST /repos/paritytech/npm_publish_automation/actions/workflows/publish.yml/dispatches
|
||||||
|
ref: main
|
||||||
|
inputs: '${{ format(''{{ "repo": "{0}", "run_id": "{1}" }}'', github.repository, github.run_id) }}'
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.NPM_PUBLISH_AUTOMATION_TOKEN }}
|
||||||
|
|||||||
@@ -86,13 +86,18 @@ jobs:
|
|||||||
- name: Install Node Packages
|
- name: Install Node Packages
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|
||||||
- name: Run Playwright tests
|
- name: Test emscripten
|
||||||
run: |
|
|
||||||
cd js
|
|
||||||
npx playwright install --with-deps
|
|
||||||
npx playwright test
|
|
||||||
|
|
||||||
- name: Test revive
|
|
||||||
run: |
|
run: |
|
||||||
echo "Running tests for ${{ matrix.os }}"
|
echo "Running tests for ${{ matrix.os }}"
|
||||||
npm run test:wasm
|
npm run test:wasm
|
||||||
|
|
||||||
|
- name: Test @parity/resolc
|
||||||
|
run: |
|
||||||
|
echo "Running tests for ${{ matrix.os }}"
|
||||||
|
npm run -w js/resolc test
|
||||||
|
|
||||||
|
- name: Run Playwright tests
|
||||||
|
run: |
|
||||||
|
cd js/emscripten
|
||||||
|
npx playwright install --with-deps
|
||||||
|
npx playwright test
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/target
|
/target
|
||||||
|
/js/resolc/dist
|
||||||
target-llvm
|
target-llvm
|
||||||
*.dot
|
*.dot
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": false
|
||||||
|
}
|
||||||
@@ -92,7 +92,4 @@ clean:
|
|||||||
rm -rf node_modules ; \
|
rm -rf node_modules ; \
|
||||||
rm -rf crates/solidity/src/tests/cli-tests/artifacts ; \
|
rm -rf crates/solidity/src/tests/cli-tests/artifacts ; \
|
||||||
cargo uninstall revive-solidity ; \
|
cargo uninstall revive-solidity ; \
|
||||||
cargo uninstall revive-llvm-builder ; \
|
cargo uninstall revive-llvm-builder ;
|
||||||
rm -f package-lock.json ; \
|
|
||||||
rm -rf js/dist ; \
|
|
||||||
rm -f js/src/resolc.{wasm,js}
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import globals from 'globals'
|
||||||
|
import pluginJs from '@eslint/js'
|
||||||
|
import tseslint from 'typescript-eslint'
|
||||||
|
|
||||||
|
/** @type {import('eslint').Linter.Config[]} */
|
||||||
|
export default [
|
||||||
|
{ files: ['**/*.{mjs,ts}'] },
|
||||||
|
{ languageOptions: { globals: globals.browser } },
|
||||||
|
pluginJs.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
]
|
||||||
@@ -8,7 +8,7 @@ const RESOLC_WASM_URI =
|
|||||||
process.env.RELEASE_RESOLC_WASM_URI || "http://127.0.0.1:8080/resolc.wasm";
|
process.env.RELEASE_RESOLC_WASM_URI || "http://127.0.0.1:8080/resolc.wasm";
|
||||||
const RESOLC_WASM_TARGET_DIR = path.join(
|
const RESOLC_WASM_TARGET_DIR = path.join(
|
||||||
__dirname,
|
__dirname,
|
||||||
"../target/wasm32-unknown-emscripten/release",
|
"../../target/wasm32-unknown-emscripten/release",
|
||||||
);
|
);
|
||||||
const RESOLC_JS = path.join(RESOLC_WASM_TARGET_DIR, "resolc.js");
|
const RESOLC_JS = path.join(RESOLC_WASM_TARGET_DIR, "resolc.js");
|
||||||
const RESOLC_WEB_JS = path.join(RESOLC_WASM_TARGET_DIR, "resolc_web.js");
|
const RESOLC_WEB_JS = path.join(RESOLC_WASM_TARGET_DIR, "resolc_web.js");
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../../target/wasm32-unknown-emscripten/release/resolc.js
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../../target/wasm32-unknown-emscripten/release/resolc.wasm
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../../target/wasm32-unknown-emscripten/release/resolc.wasm
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../target/wasm32-unknown-emscripten/release/resolc_web.js
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"fixtures/instantiate.sol": {
|
||||||
|
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.2 <0.9.0;\ncontract ChildContract {\n constructor() {\n }\n}\ncontract MainContract {\n constructor() {\n ChildContract newContract = new ChildContract();\n }\n}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"optimizer": {
|
||||||
|
"enabled": true,
|
||||||
|
"runs": 200
|
||||||
|
},
|
||||||
|
"outputSelection": {
|
||||||
|
"*": {
|
||||||
|
"*": ["abi"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-3
@@ -72,9 +72,7 @@
|
|||||||
},
|
},
|
||||||
"outputSelection": {
|
"outputSelection": {
|
||||||
"*": {
|
"*": {
|
||||||
"*": [
|
"*": ["abi"]
|
||||||
"abi"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,15 +65,15 @@ describe("Compile Function Tests", function () {
|
|||||||
expect(result).to.be.a("string");
|
expect(result).to.be.a("string");
|
||||||
const output = JSON.parse(result);
|
const output = JSON.parse(result);
|
||||||
expect(output).to.have.property("contracts");
|
expect(output).to.have.property("contracts");
|
||||||
expect(output.contracts["fixtures/instantiate_tokens.sol"]).to.have.property(
|
expect(
|
||||||
"TokensFactory",
|
output.contracts["fixtures/instantiate_tokens.sol"],
|
||||||
);
|
).to.have.property("TokensFactory");
|
||||||
expect(output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory).to.have.property(
|
expect(
|
||||||
"abi",
|
output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory,
|
||||||
);
|
).to.have.property("abi");
|
||||||
expect(output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory).to.have.property(
|
expect(
|
||||||
"evm",
|
output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory,
|
||||||
);
|
).to.have.property("evm");
|
||||||
expect(
|
expect(
|
||||||
output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory.evm,
|
output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory.evm,
|
||||||
).to.have.property("bytecode");
|
).to.have.property("bytecode");
|
||||||
@@ -117,27 +117,26 @@ describe("Compile Function Tests", function () {
|
|||||||
expect(output.contracts["fixtures/instantiate.sol"]).to.have.property(
|
expect(output.contracts["fixtures/instantiate.sol"]).to.have.property(
|
||||||
"ChildContract",
|
"ChildContract",
|
||||||
);
|
);
|
||||||
expect(output.contracts["fixtures/instantiate.sol"].ChildContract).to.have.property(
|
expect(
|
||||||
"abi",
|
output.contracts["fixtures/instantiate.sol"].ChildContract,
|
||||||
);
|
).to.have.property("abi");
|
||||||
expect(output.contracts["fixtures/instantiate.sol"].ChildContract).to.have.property(
|
expect(
|
||||||
"evm",
|
output.contracts["fixtures/instantiate.sol"].ChildContract,
|
||||||
);
|
).to.have.property("evm");
|
||||||
expect(
|
expect(
|
||||||
output.contracts["fixtures/instantiate.sol"].ChildContract.evm,
|
output.contracts["fixtures/instantiate.sol"].ChildContract.evm,
|
||||||
).to.have.property("bytecode");
|
).to.have.property("bytecode");
|
||||||
expect(output.contracts["fixtures/instantiate.sol"]).to.have.property(
|
expect(output.contracts["fixtures/instantiate.sol"]).to.have.property(
|
||||||
"MainContract",
|
"MainContract",
|
||||||
);
|
);
|
||||||
expect(output.contracts["fixtures/instantiate.sol"].MainContract).to.have.property(
|
expect(
|
||||||
"abi",
|
output.contracts["fixtures/instantiate.sol"].MainContract,
|
||||||
);
|
).to.have.property("abi");
|
||||||
expect(output.contracts["fixtures/instantiate.sol"].MainContract).to.have.property(
|
expect(
|
||||||
"evm",
|
output.contracts["fixtures/instantiate.sol"].MainContract,
|
||||||
);
|
).to.have.property("evm");
|
||||||
expect(
|
expect(
|
||||||
output.contracts["fixtures/instantiate.sol"].MainContract.evm,
|
output.contracts["fixtures/instantiate.sol"].MainContract.evm,
|
||||||
).to.have.property("bytecode");
|
).to.have.property("bytecode");
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../target/wasm32-unknown-emscripten/release/resolc.js
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../target/wasm32-unknown-emscripten/release/resolc.wasm
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../target/wasm32-unknown-emscripten/release/resolc.wasm
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../target/wasm32-unknown-emscripten/release/resolc_web.js
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"language": "Solidity",
|
|
||||||
"sources": {
|
|
||||||
"fixtures/instantiate.sol": {
|
|
||||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.2 <0.9.0;\ncontract ChildContract {\n constructor() {\n }\n}\ncontract MainContract {\n constructor() {\n ChildContract newContract = new ChildContract();\n }\n}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"optimizer": {
|
|
||||||
"enabled": true,
|
|
||||||
"runs": 200
|
|
||||||
},
|
|
||||||
"outputSelection": {
|
|
||||||
"*": {
|
|
||||||
"*": ["abi"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Usage from Node.js
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { compile } from "@parity/resolc";
|
||||||
|
const sources = {
|
||||||
|
["contracts/1_Storage.sol"]: {
|
||||||
|
content: readFileSync("fixtures/storage.sol", "utf8"),
|
||||||
|
}
|
||||||
|
|
||||||
|
const out = await compile(sources);
|
||||||
|
```
|
||||||
|
|
||||||
|
# Usage from shell
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx @parity/resolc@latest --bin contracts/1_Storage.sol
|
||||||
|
```
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity ^9999;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title Storage
|
||||||
|
* @dev Store & retrieve value in a variable
|
||||||
|
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts
|
||||||
|
*/
|
||||||
|
contract BadPragma {
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.8.2 <0.9.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title Storage
|
||||||
|
* @dev Store & retrieve value in a variable
|
||||||
|
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts
|
||||||
|
*/
|
||||||
|
contract Storage {
|
||||||
|
|
||||||
|
uint256 number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Store value in variable
|
||||||
|
* @param num value to store
|
||||||
|
*/
|
||||||
|
function store(uint256 num) public {
|
||||||
|
number = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Return value
|
||||||
|
* @return value of 'number'
|
||||||
|
*/
|
||||||
|
function retrieve() public view returns (uint256){
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// missing license and pragama
|
||||||
|
/**
|
||||||
|
* @title Storage
|
||||||
|
* @dev Store & retrieve value in a variable
|
||||||
|
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts
|
||||||
|
*/
|
||||||
|
contract Storage {
|
||||||
|
|
||||||
|
uint256 number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Store value in variable
|
||||||
|
* @param num value to store
|
||||||
|
*/
|
||||||
|
function store(uint256 num) public {
|
||||||
|
number = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Return value
|
||||||
|
* @return value of 'number'
|
||||||
|
*/
|
||||||
|
function retrieve() public view returns (uint256){
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Compatible with OpenZeppelin Contracts ^5.0.0
|
||||||
|
pragma solidity ^0.8.22;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||||
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||||
|
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
|
||||||
|
|
||||||
|
contract MyToken is ERC20, Ownable, ERC20Permit {
|
||||||
|
constructor(address initialOwner)
|
||||||
|
ERC20("MyToken", "MTK")
|
||||||
|
Ownable(initialOwner)
|
||||||
|
ERC20Permit("MyToken")
|
||||||
|
{
|
||||||
|
_mint(msg.sender, 100 * 10 ** decimals());
|
||||||
|
}
|
||||||
|
|
||||||
|
function mint(address to, uint256 amount) public onlyOwner {
|
||||||
|
_mint(to, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "@parity/resolc",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"version": "0.0.0-updated-via-gh-releases",
|
||||||
|
"author": "Parity <admin@parity.io> (https://parity.io)",
|
||||||
|
"module": "index.ts",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"bin": {
|
||||||
|
"resolc": "./dist/bin.js"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"require": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc && cp src/resolc/** dist/resolc",
|
||||||
|
"test": "npm run build && node ./dist/index.test.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@openzeppelin/contracts": "5.1.0",
|
||||||
|
"globals": "^15.12.0",
|
||||||
|
"typescript": "^5.6.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^22.9.0",
|
||||||
|
"commander": "^13.1.0",
|
||||||
|
"package-json": "^10.0.1",
|
||||||
|
"solc": "^0.8.29"
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+203
@@ -0,0 +1,203 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import * as commander from 'commander'
|
||||||
|
import * as fs from 'fs'
|
||||||
|
import * as os from 'os'
|
||||||
|
import * as path from 'path'
|
||||||
|
import * as resolc from '.'
|
||||||
|
import { SolcInput } from '.'
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// hold on to any exception handlers that existed prior to this script running, we'll be adding them back at the end
|
||||||
|
const originalUncaughtExceptionListeners =
|
||||||
|
process.listeners('uncaughtException')
|
||||||
|
// FIXME: remove annoying exception catcher of Emscripten
|
||||||
|
// see https://github.com/chriseth/browser-solidity/issues/167
|
||||||
|
process.removeAllListeners('uncaughtException')
|
||||||
|
|
||||||
|
const program = new commander.Command()
|
||||||
|
|
||||||
|
program.name('solcjs')
|
||||||
|
program.version(resolc.version())
|
||||||
|
program
|
||||||
|
.option('--bin', 'Binary of the contracts in hex.')
|
||||||
|
.option('--abi', 'ABI of the contracts.')
|
||||||
|
.option(
|
||||||
|
'--base-path <path>',
|
||||||
|
'Root of the project source tree. ' +
|
||||||
|
'The import callback will attempt to interpret all import paths as relative to this directory.'
|
||||||
|
)
|
||||||
|
.option(
|
||||||
|
'--include-path <path...>',
|
||||||
|
'Extra source directories available to the import callback. ' +
|
||||||
|
'When using a package manager to install libraries, use this option to specify directories where packages are installed. ' +
|
||||||
|
'Can be used multiple times to provide multiple locations.'
|
||||||
|
)
|
||||||
|
.option(
|
||||||
|
'-o, --output-dir <output-directory>',
|
||||||
|
'Output directory for the contracts.'
|
||||||
|
)
|
||||||
|
.option('-p, --pretty-json', 'Pretty-print all JSON output.', false)
|
||||||
|
.option('-v, --verbose', 'More detailed console output.', false)
|
||||||
|
.argument('<files...>')
|
||||||
|
|
||||||
|
program.parse(process.argv)
|
||||||
|
const options = program.opts<{
|
||||||
|
verbose: boolean
|
||||||
|
abi: boolean
|
||||||
|
bin: boolean
|
||||||
|
outputDir?: string
|
||||||
|
prettyJson: boolean
|
||||||
|
basePath?: string
|
||||||
|
includePath?: string[]
|
||||||
|
}>()
|
||||||
|
const files: string[] = program.args
|
||||||
|
const destination = options.outputDir ?? '.'
|
||||||
|
|
||||||
|
function abort(msg: string) {
|
||||||
|
console.error(msg || 'Error occurred')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function withUnixPathSeparators(filePath: string) {
|
||||||
|
// On UNIX-like systems forward slashes in paths are just a part of the file name.
|
||||||
|
if (os.platform() !== 'win32') {
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath.replace(/\\/g, '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeSourcePathRelativeIfPossible(sourcePath: string) {
|
||||||
|
const absoluteBasePath = options.basePath
|
||||||
|
? path.resolve(options.basePath)
|
||||||
|
: path.resolve('.')
|
||||||
|
const absoluteIncludePaths = options.includePath
|
||||||
|
? options.includePath.map((prefix: string) => {
|
||||||
|
return path.resolve(prefix)
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
|
||||||
|
// Compared to base path stripping logic in solc this is much simpler because path.resolve()
|
||||||
|
// handles symlinks correctly (does not resolve them except in work dir) and strips .. segments
|
||||||
|
// from paths going beyond root (e.g. `/../../a/b/c` -> `/a/b/c/`). It's simpler also because it
|
||||||
|
// ignores less important corner cases: drive letters are not stripped from absolute paths on
|
||||||
|
// Windows and UNC paths are not handled in a special way (at least on Linux). Finally, it has
|
||||||
|
// very little test coverage so there might be more differences that we are just not aware of.
|
||||||
|
const absoluteSourcePath = path.resolve(sourcePath)
|
||||||
|
|
||||||
|
for (const absolutePrefix of [absoluteBasePath].concat(
|
||||||
|
absoluteIncludePaths
|
||||||
|
)) {
|
||||||
|
const relativeSourcePath = path.relative(
|
||||||
|
absolutePrefix,
|
||||||
|
absoluteSourcePath
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!relativeSourcePath.startsWith('../')) {
|
||||||
|
return withUnixPathSeparators(relativeSourcePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// File is not located inside base path or include paths so use its absolute path.
|
||||||
|
return withUnixPathSeparators(absoluteSourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
function toFormattedJson<T>(input: T) {
|
||||||
|
return JSON.stringify(input, null, options.prettyJson ? 4 : 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (files.length === 0) {
|
||||||
|
console.error('Must provide a file')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(options.bin || options.abi)) {
|
||||||
|
abort('Invalid option selected, must specify either --bin or --abi')
|
||||||
|
}
|
||||||
|
|
||||||
|
const sources: SolcInput = {}
|
||||||
|
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
try {
|
||||||
|
sources[makeSourcePathRelativeIfPossible(files[i])] = {
|
||||||
|
content: fs.readFileSync(files[i]).toString(),
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
abort('Error reading ' + files[i] + ': ' + e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.verbose) {
|
||||||
|
console.log('>>> Compiling:\n' + toFormattedJson(sources) + '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
const output = await resolc.compile(sources)
|
||||||
|
let hasError = false
|
||||||
|
|
||||||
|
if (!output) {
|
||||||
|
abort('No output from compiler')
|
||||||
|
} else if (output.errors) {
|
||||||
|
for (const error in output.errors) {
|
||||||
|
const message = output.errors[error]
|
||||||
|
if (message.severity === 'warning') {
|
||||||
|
console.log(message.formattedMessage)
|
||||||
|
} else {
|
||||||
|
console.error(message.formattedMessage)
|
||||||
|
hasError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.mkdirSync(destination, { recursive: true })
|
||||||
|
|
||||||
|
function writeFile(file: string, content: Buffer | string) {
|
||||||
|
file = path.join(destination, file)
|
||||||
|
fs.writeFile(file, content, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error('Failed to write ' + file + ': ' + err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const fileName in output.contracts) {
|
||||||
|
for (const contractName in output.contracts[fileName]) {
|
||||||
|
let contractFileName = fileName + ':' + contractName
|
||||||
|
contractFileName = contractFileName.replace(/[:./\\]/g, '_')
|
||||||
|
|
||||||
|
if (options.bin) {
|
||||||
|
writeFile(
|
||||||
|
contractFileName + '.polkavm',
|
||||||
|
Buffer.from(
|
||||||
|
output.contracts[fileName][contractName].evm.bytecode
|
||||||
|
.object,
|
||||||
|
'hex'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.abi) {
|
||||||
|
writeFile(
|
||||||
|
contractFileName + '.abi',
|
||||||
|
toFormattedJson(
|
||||||
|
output.contracts[fileName][contractName].abi
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put back original exception handlers.
|
||||||
|
originalUncaughtExceptionListeners.forEach(function (listener) {
|
||||||
|
process.addListener('uncaughtException', listener)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (hasError) {
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error('Error:', err)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
import { test } from 'node:test'
|
||||||
|
import { readFileSync, existsSync } from 'node:fs'
|
||||||
|
import assert from 'node:assert'
|
||||||
|
import { compile, tryResolveImport } from '.'
|
||||||
|
import { resolve } from 'node:path'
|
||||||
|
|
||||||
|
|
||||||
|
const compileOptions = [{}]
|
||||||
|
if (existsSync('../../target/release/resolc')) {
|
||||||
|
compileOptions.push({ bin: '../../target/release/resolc' })
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const options of compileOptions) {
|
||||||
|
test(`check Ok output with option ${JSON.stringify(options)}`, async () => {
|
||||||
|
const contract = 'fixtures/token.sol'
|
||||||
|
const sources = {
|
||||||
|
[contract]: {
|
||||||
|
content: readFileSync('fixtures/storage.sol', 'utf8'),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const out = await compile(sources, options)
|
||||||
|
assert(out.contracts[contract].Storage.abi != null)
|
||||||
|
assert(out.contracts[contract].Storage.evm.bytecode != null)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
test('check Err output', async () => {
|
||||||
|
const sources = {
|
||||||
|
bad: {
|
||||||
|
content: readFileSync('fixtures/storage_bad.sol', 'utf8'),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const out = await compile(sources)
|
||||||
|
assert(
|
||||||
|
out?.errors?.[0].message.includes(
|
||||||
|
'SPDX license identifier not provided in source file'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
out?.errors?.[1].message.includes(
|
||||||
|
'Source file does not specify required compiler version'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('check Err from stderr', async () => {
|
||||||
|
const sources = {
|
||||||
|
bad: {
|
||||||
|
content: readFileSync('fixtures/bad_pragma.sol', 'utf8'),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await compile(sources)
|
||||||
|
assert(false, 'Expected error')
|
||||||
|
} catch (error) {
|
||||||
|
assert(
|
||||||
|
String(error).includes(
|
||||||
|
'Source file requires different compiler version'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('resolve import', () => {
|
||||||
|
const cases = [
|
||||||
|
// local
|
||||||
|
{
|
||||||
|
file: './fixtures/storage.sol',
|
||||||
|
expected: resolve('fixtures/storage.sol'),
|
||||||
|
},
|
||||||
|
// scopped module with version
|
||||||
|
{
|
||||||
|
file: '@openzeppelin/contracts@5.1.0/token/ERC20/ERC20.sol',
|
||||||
|
expected: require.resolve('@openzeppelin/contracts/token/ERC20/ERC20.sol'),
|
||||||
|
},
|
||||||
|
// scopped module without version
|
||||||
|
{
|
||||||
|
file: '@openzeppelin/contracts/token/ERC20/ERC20.sol',
|
||||||
|
expected: require.resolve('@openzeppelin/contracts/token/ERC20/ERC20.sol'),
|
||||||
|
},
|
||||||
|
// scopped module with wrong version
|
||||||
|
{
|
||||||
|
file: '@openzeppelin/contracts@4.8.3/token/ERC20/ERC20.sol',
|
||||||
|
expected: `Error: Version mismatch: Specified @openzeppelin/contracts@4.8.3, but installed version is 5.1.0`,
|
||||||
|
},
|
||||||
|
// module without version
|
||||||
|
{
|
||||||
|
file: '@openzeppelin/contracts/package.json',
|
||||||
|
expected: require.resolve('@openzeppelin/contracts/package.json'),
|
||||||
|
},
|
||||||
|
// scopped module with version
|
||||||
|
{
|
||||||
|
file: '@openzeppelin/contracts@5.1.0/package.json',
|
||||||
|
expected: require.resolve('@openzeppelin/contracts/package.json'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const { file, expected } of cases) {
|
||||||
|
try {
|
||||||
|
const resolved = tryResolveImport(file)
|
||||||
|
assert(
|
||||||
|
resolved === expected,
|
||||||
|
`\nGot:\n${resolved}\nExpected:\n${expected}`
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
assert(
|
||||||
|
String(error) == expected,
|
||||||
|
`\nGot:\n${String(error)}\nExpected:\n${expected}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
import solc from 'solc'
|
||||||
|
import { spawn } from 'child_process'
|
||||||
|
import { resolc, version as resolcVersion } from './resolc'
|
||||||
|
import path from 'path'
|
||||||
|
import { existsSync, readFileSync } from 'fs'
|
||||||
|
|
||||||
|
export type SolcInput = {
|
||||||
|
[contractName: string]: {
|
||||||
|
content: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SolcError = {
|
||||||
|
component: string
|
||||||
|
errorCode: string
|
||||||
|
formattedMessage: string
|
||||||
|
message: string
|
||||||
|
severity: string
|
||||||
|
sourceLocation?: {
|
||||||
|
file: string
|
||||||
|
start: number
|
||||||
|
end: number
|
||||||
|
}
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SolcOutput = {
|
||||||
|
contracts: {
|
||||||
|
[contractPath: string]: {
|
||||||
|
[contractName: string]: {
|
||||||
|
abi: Array<{
|
||||||
|
name: string
|
||||||
|
inputs: Array<{ name: string; type: string }>
|
||||||
|
outputs: Array<{ name: string; type: string }>
|
||||||
|
stateMutability: string
|
||||||
|
type: string
|
||||||
|
}>
|
||||||
|
evm: {
|
||||||
|
bytecode: { object: string }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errors?: Array<SolcError>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveInputs(sources: SolcInput): SolcInput {
|
||||||
|
const input = {
|
||||||
|
language: 'Solidity',
|
||||||
|
sources,
|
||||||
|
settings: {
|
||||||
|
outputSelection: {
|
||||||
|
'*': {
|
||||||
|
'*': ['evm.bytecode.object'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const out = solc.compile(JSON.stringify(input), {
|
||||||
|
import: (path: string) => {
|
||||||
|
return {
|
||||||
|
contents: readFileSync(tryResolveImport(path), 'utf8'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const output = JSON.parse(out) as {
|
||||||
|
sources: { [fileName: string]: { id: number } }
|
||||||
|
errors: Array<SolcError>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output.errors && Object.keys(output.sources).length === 0) {
|
||||||
|
throw new Error(output.errors[0].formattedMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.keys(output.sources).map((fileName) => {
|
||||||
|
return [
|
||||||
|
fileName,
|
||||||
|
sources[fileName] ?? {
|
||||||
|
content: readFileSync(tryResolveImport(fileName), 'utf8'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function version(): string {
|
||||||
|
const v = resolcVersion()
|
||||||
|
return v.split(' ').pop() ?? v
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function compile(
|
||||||
|
sources: SolcInput,
|
||||||
|
option: { bin?: string } = {}
|
||||||
|
): Promise<SolcOutput> {
|
||||||
|
const input = JSON.stringify({
|
||||||
|
language: 'Solidity',
|
||||||
|
sources: resolveInputs(sources),
|
||||||
|
settings: {
|
||||||
|
optimizer: { enabled: true, runs: 200 },
|
||||||
|
outputSelection: {
|
||||||
|
'*': {
|
||||||
|
'*': ['abi'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (option.bin) {
|
||||||
|
return compileWithBin(input, option.bin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolc(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve an import path to a file path.
|
||||||
|
* @param importPath - The import path to resolve.
|
||||||
|
*/
|
||||||
|
export function tryResolveImport(importPath: string) {
|
||||||
|
// resolve local path
|
||||||
|
if (existsSync(importPath)) {
|
||||||
|
return path.resolve(importPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
const importRegex = /^(@?[^@/]+(?:\/[^@/]+)?)(?:@([^/]+))?(\/.+)$/
|
||||||
|
const match = importPath.match(importRegex)
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
throw new Error('Invalid import path format.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const basePackage = match[1] // "foo", "@scope/foo"
|
||||||
|
const specifiedVersion = match[2] // "1.2.3" (optional)
|
||||||
|
const relativePath = match[3] // "/path/to/file.sol"
|
||||||
|
|
||||||
|
let packageJsonPath
|
||||||
|
try {
|
||||||
|
packageJsonPath = require.resolve(
|
||||||
|
path.join(basePackage, 'package.json')
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
throw new Error(`Could not resolve package ${basePackage}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a version was specified and compare with the installed version
|
||||||
|
if (specifiedVersion) {
|
||||||
|
const installedVersion = JSON.parse(
|
||||||
|
readFileSync(packageJsonPath, 'utf-8')
|
||||||
|
).version
|
||||||
|
|
||||||
|
if (installedVersion !== specifiedVersion) {
|
||||||
|
throw new Error(
|
||||||
|
`Version mismatch: Specified ${basePackage}@${specifiedVersion}, but installed version is ${installedVersion}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const packageRoot = path.dirname(packageJsonPath)
|
||||||
|
|
||||||
|
// Construct full path to the requested file
|
||||||
|
const resolvedPath = path.join(packageRoot, relativePath)
|
||||||
|
if (existsSync(resolvedPath)) {
|
||||||
|
return resolvedPath
|
||||||
|
} else {
|
||||||
|
throw new Error(`Resolved path ${resolvedPath} does not exist.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function compileWithBin(input: string, bin: string): PromiseLike<SolcOutput> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const process = spawn(bin, ['--standard-json'])
|
||||||
|
|
||||||
|
let output = ''
|
||||||
|
let error = ''
|
||||||
|
|
||||||
|
process.stdin.write(input)
|
||||||
|
process.stdin.end()
|
||||||
|
|
||||||
|
process.stdout.on('data', (data) => {
|
||||||
|
output += data.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
process.stderr.on('data', (data) => {
|
||||||
|
error += data.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
process.on('close', (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
try {
|
||||||
|
const result: SolcOutput = JSON.parse(output)
|
||||||
|
resolve(result)
|
||||||
|
} catch {
|
||||||
|
reject(new Error(`Failed to parse output`))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reject(new Error(`Process exited with code ${code}: ${error}`))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import soljson from 'solc/soljson'
|
||||||
|
import Resolc from './resolc/resolc'
|
||||||
|
import type { SolcOutput } from '.'
|
||||||
|
|
||||||
|
export function resolc(input: string): SolcOutput {
|
||||||
|
const m = Resolc() as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
m.soljson = soljson
|
||||||
|
m.writeToStdin(input)
|
||||||
|
m.callMain(['--standard-json'])
|
||||||
|
const err = m.readFromStderr()
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
throw new Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(m.readFromStdout()) as SolcOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
export function version(): string {
|
||||||
|
const m = Resolc() as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
m.soljson = soljson
|
||||||
|
m.callMain(['--version'])
|
||||||
|
const err = m.readFromStderr()
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
throw new Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.readFromStdout()
|
||||||
|
}
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../../target/wasm32-unknown-emscripten/release/resolc.js
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../../target/wasm32-unknown-emscripten/release/resolc.wasm
|
||||||
Vendored
+95
@@ -0,0 +1,95 @@
|
|||||||
|
declare module 'solc/soljson' {}
|
||||||
|
|
||||||
|
declare module 'solc' {
|
||||||
|
// Basic types for input/output handling
|
||||||
|
export interface CompileInput {
|
||||||
|
language: string
|
||||||
|
sources: {
|
||||||
|
[fileName: string]: {
|
||||||
|
content: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings?: {
|
||||||
|
optimizer?: {
|
||||||
|
enabled: boolean
|
||||||
|
runs: number
|
||||||
|
}
|
||||||
|
outputSelection: {
|
||||||
|
[fileName: string]: {
|
||||||
|
[contractName: string]: string[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CompileOutput {
|
||||||
|
errors?: Array<{
|
||||||
|
component: string
|
||||||
|
errorCode: string
|
||||||
|
formattedMessage: string
|
||||||
|
message: string
|
||||||
|
severity: string
|
||||||
|
sourceLocation?: {
|
||||||
|
file: string
|
||||||
|
start: number
|
||||||
|
end: number
|
||||||
|
}
|
||||||
|
type: string
|
||||||
|
}>
|
||||||
|
sources?: {
|
||||||
|
[fileName: string]: {
|
||||||
|
id: number
|
||||||
|
ast: object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contracts?: {
|
||||||
|
[fileName: string]: {
|
||||||
|
[contractName: string]: {
|
||||||
|
abi: object[]
|
||||||
|
evm: {
|
||||||
|
bytecode: {
|
||||||
|
object: string
|
||||||
|
sourceMap: string
|
||||||
|
linkReferences: {
|
||||||
|
[fileName: string]: {
|
||||||
|
[libraryName: string]: Array<{
|
||||||
|
start: number
|
||||||
|
length: number
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deployedBytecode: {
|
||||||
|
object: string
|
||||||
|
sourceMap: string
|
||||||
|
linkReferences: {
|
||||||
|
[fileName: string]: {
|
||||||
|
[libraryName: string]: Array<{
|
||||||
|
start: number
|
||||||
|
length: number
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main exported functions
|
||||||
|
export function compile(
|
||||||
|
input: string | CompileInput,
|
||||||
|
options?: {
|
||||||
|
import: (path: string) =>
|
||||||
|
| {
|
||||||
|
contents: string
|
||||||
|
error?: undefined
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
error: string
|
||||||
|
contents?: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
): string
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"outDir": "dist",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "ES2022",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"useUnknownInCatchVariables": true,
|
||||||
|
"types": ["node"],
|
||||||
|
"typeRoots": ["../../node_modules/@types", "./src"],
|
||||||
|
"paths": {
|
||||||
|
"#src/*": ["./src/*"]
|
||||||
|
},
|
||||||
|
"plugins": []
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
}
|
||||||
+19
-11
@@ -1,13 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "root",
|
"name": "root",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test:cli": "npm run test -w crates/solidity/src/tests/cli-tests",
|
"test:cli": "npm run test -w crates/solidity/src/tests/cli-tests",
|
||||||
"test:wasm": "npm run test:node -w js",
|
"test:wasm": "npm run test:node -w js/emscripten",
|
||||||
"build:package": "npm run build:package -w js"
|
"build:package": "npm run build:package -w js/emscripten",
|
||||||
},
|
"lint": "npx eslint 'js/**/*.{cjs,mjs,ts}' && npx prettier --check '**/*.{mjs,cjs,ts}'",
|
||||||
"workspaces": [
|
"lint:fix": "npx prettier --write '**/*.{mjs,cjs,ts}'"
|
||||||
"crates/solidity/src/tests/cli-tests",
|
},
|
||||||
"js"
|
"workspaces": [
|
||||||
]
|
"crates/solidity/src/tests/cli-tests",
|
||||||
|
"js/emscripten",
|
||||||
|
"js/resolc"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@eslint/js": "^9.14.0",
|
||||||
|
"eslint": "^9.14.0",
|
||||||
|
"typescript-eslint": "^8.13.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user