From 44a48ea5a0c44f56826c41d44b7db07a498b5f81 Mon Sep 17 00:00:00 2001 From: Klaus Hott Vidal Date: Tue, 1 Oct 2024 16:45:08 +1300 Subject: [PATCH] Infer version (#1047) * update dependencies * Adding the compiler inference logic * upgrading tests for version inferrence * Since importing maxSatisfying and minSatisfying, there is no benefit in importing semver functionality by independent functions. * fixing bug in VersionLiteral * using string replace to remove all comments from the VersionExpressionSets * Move inferLanguage to its own module * Add tests for inferLanguage * added extra test case * check if there is at least 1 valid version in the ranges before comparing it against the supported versions. * adding more specific tests * validating a range like `0.5.0 - 0.6.0` gets rewritten to comparators `>=0.5.0 <=0.6.0` which can be concatenated. * refactor test * Add test case for infer-language --------- Co-authored-by: Franco Victorio --- jest.config.js | 1 + package-lock.json | 159 ++++++++++-------- package.json | 9 +- src/slang-nodes/ContractDefinition.ts | 3 +- src/slang-nodes/FunctionDefinition.ts | 3 +- .../ImportDeconstructionSymbols.ts | 3 +- src/slang-nodes/VersionLiteral.ts | 4 +- src/slang-utils/infer-language.ts | 94 +++++++++++ src/slang-utils/print-warning.ts | 12 ++ src/slangSolidityParser.ts | 25 ++- .../AllSolidityFeatures.sol | 2 - .../__snapshots__/format.test.js.snap | 3 - .../__snapshots__/format.test.js.snap | 3 +- .../AllSolidityFeaturesV0.4.26/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 3 +- tests/format/AssemblyV0.4.26/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 3 +- tests/format/BasicIterator/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 6 +- tests/format/BinaryOperators/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 61 ------- .../BreakingChangesV0.7.4/format.test.js | 2 - .../__snapshots__/format.test.js.snap | 3 +- tests/format/Comments/format.test.js | 2 +- tests/format/Constructors/Constructors.sol | 3 - .../__snapshots__/format.test.js.snap | 7 - .../ConstructorsV0.4.26/Constructors.sol | 6 + .../__snapshots__/format.test.js.snap | 26 +++ .../format/ConstructorsV0.4.26/format.test.js | 1 + .../__snapshots__/format.test.js.snap | 3 +- .../format/FunctionDefinitions/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 3 +- .../FunctionDefinitionsv0.5.0/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 14 +- .../IndexOf/__snapshots__/format.test.js.snap | 3 +- tests/format/IndexOf/format.test.js | 2 +- tests/format/MemberAccess/MemberAccess.sol | 2 +- .../__snapshots__/format.test.js.snap | 4 +- .../__snapshots__/format.test.js.snap | 3 +- .../format/ModifierInvocations/format.test.js | 2 +- .../__snapshots__/format.test.js.snap | 36 ++-- tests/format/Parentheses/format.test.js | 2 +- tests/format/Pragma/Pragma.sol | 4 +- .../Pragma/__snapshots__/format.test.js.snap | 6 +- .../format/PrettierIgnore/PrettierIgnore.sol | 2 +- .../__snapshots__/format.test.js.snap | 4 +- .../Proxy/__snapshots__/format.test.js.snap | 3 +- tests/format/Proxy/format.test.js | 2 +- tests/format/StyleGuide/ControlStructures.sol | 2 +- tests/format/StyleGuide/MaximumLineLength.sol | 2 +- .../StyleGuide/OtherRecommendations.sol | 2 +- .../StyleGuide/WhitespaceInExpressions.sol | 2 +- .../__snapshots__/format.test.js.snap | 40 ++--- tests/format/StyleGuide/format.test.js | 2 +- tests/unit/slang-utils/infer-language.test.js | 103 ++++++++++++ 55 files changed, 441 insertions(+), 263 deletions(-) create mode 100644 src/slang-utils/infer-language.ts create mode 100644 src/slang-utils/print-warning.ts create mode 100644 tests/format/ConstructorsV0.4.26/Constructors.sol create mode 100644 tests/format/ConstructorsV0.4.26/__snapshots__/format.test.js.snap create mode 100644 tests/format/ConstructorsV0.4.26/format.test.js create mode 100644 tests/unit/slang-utils/infer-language.test.js diff --git a/jest.config.js b/jest.config.js index 27727ef91..8fac73df0 100644 --- a/jest.config.js +++ b/jest.config.js @@ -8,6 +8,7 @@ if (TEST_STANDALONE) { ); } else { testMatch.push('/tests/unit/**/*.test.js'); + testMatch.push('/tests/unit/**/*.test.ts'); } export default { diff --git a/package-lock.json b/package-lock.json index f5d62a71a..36adeffbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,12 +15,13 @@ }, "devDependencies": { "@babel/code-frame": "^7.24.7", + "@types/jest": "^29.5.13", "@types/semver": "^7.5.8", - "@typescript-eslint/eslint-plugin": "^8.6.0", - "@typescript-eslint/parser": "^8.6.0", + "@typescript-eslint/eslint-plugin": "^8.7.0", + "@typescript-eslint/parser": "^8.7.0", "c8": "^9.1.0", "cross-env": "^7.0.3", - "eslint": "^9.10.0", + "eslint": "^9.11.1", "eslint-config-prettier": "^9.1.0", "esm-utils": "^4.3.0", "esmock": "^2.6.7", @@ -36,7 +37,7 @@ "ts-loader": "^9.5.1", "ts-node": "^10.9.2", "typescript": "^5.5.4", - "webpack": "^5.94.0", + "webpack": "^5.95.0", "webpack-cli": "^5.1.4" }, "engines": { @@ -715,6 +716,16 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/core": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", + "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", @@ -740,9 +751,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.10.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz", - "integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==", + "version": "9.11.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.1.tgz", + "integrity": "sha512-/qu+TWz8WwPWc7/HcIJKi+c+MOm46GdVaSlTTQcaqaL53+GsoA6MxWp5PtTx48qbSP7ylM1Kn7nhvkugfJvRSA==", "dev": true, "license": "MIT", "engines": { @@ -760,9 +771,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.1.0.tgz", - "integrity": "sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", + "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1529,9 +1540,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, "license": "MIT" }, @@ -1568,11 +1579,22 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jest": { + "version": "29.5.13", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.13.tgz", + "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { "version": "18.11.17", @@ -1609,17 +1631,17 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz", - "integrity": "sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz", + "integrity": "sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.6.0", - "@typescript-eslint/type-utils": "8.6.0", - "@typescript-eslint/utils": "8.6.0", - "@typescript-eslint/visitor-keys": "8.6.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/type-utils": "8.7.0", + "@typescript-eslint/utils": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1643,16 +1665,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.6.0.tgz", - "integrity": "sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.7.0.tgz", + "integrity": "sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.6.0", - "@typescript-eslint/types": "8.6.0", - "@typescript-eslint/typescript-estree": "8.6.0", - "@typescript-eslint/visitor-keys": "8.6.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/typescript-estree": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", "debug": "^4.3.4" }, "engines": { @@ -1672,14 +1694,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.6.0.tgz", - "integrity": "sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", + "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.6.0", - "@typescript-eslint/visitor-keys": "8.6.0" + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1690,14 +1712,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz", - "integrity": "sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz", + "integrity": "sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.6.0", - "@typescript-eslint/utils": "8.6.0", + "@typescript-eslint/typescript-estree": "8.7.0", + "@typescript-eslint/utils": "8.7.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1715,9 +1737,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.6.0.tgz", - "integrity": "sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", + "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", "dev": true, "license": "MIT", "engines": { @@ -1729,14 +1751,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.6.0.tgz", - "integrity": "sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", + "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.6.0", - "@typescript-eslint/visitor-keys": "8.6.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1784,16 +1806,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.6.0.tgz", - "integrity": "sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", + "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.6.0", - "@typescript-eslint/types": "8.6.0", - "@typescript-eslint/typescript-estree": "8.6.0" + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/typescript-estree": "8.7.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1807,13 +1829,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.6.0.tgz", - "integrity": "sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", + "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/types": "8.7.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2972,21 +2994,24 @@ } }, "node_modules/eslint": { - "version": "9.10.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.10.0.tgz", - "integrity": "sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw==", + "version": "9.11.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.1.tgz", + "integrity": "sha512-MobhYKIoAO1s1e4VUrgx1l1Sk2JBR/Gqjjgw8+mfgoLE2xwsHur4gdfTxyTgShrhvdVFTaJSgMiQBl1jv/AWxg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.10.0", - "@eslint/plugin-kit": "^0.1.0", + "@eslint/js": "9.11.1", + "@eslint/plugin-kit": "^0.2.0", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -6934,9 +6959,9 @@ } }, "node_modules/webpack": { - "version": "5.94.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", - "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "version": "5.95.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", + "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index fd56a7577..0d2144b31 100644 --- a/package.json +++ b/package.json @@ -75,12 +75,13 @@ }, "devDependencies": { "@babel/code-frame": "^7.24.7", + "@types/jest": "^29.5.13", "@types/semver": "^7.5.8", - "@typescript-eslint/eslint-plugin": "^8.6.0", - "@typescript-eslint/parser": "^8.6.0", + "@typescript-eslint/eslint-plugin": "^8.7.0", + "@typescript-eslint/parser": "^8.7.0", "c8": "^9.1.0", "cross-env": "^7.0.3", - "eslint": "^9.10.0", + "eslint": "^9.11.1", "eslint-config-prettier": "^9.1.0", "esm-utils": "^4.3.0", "esmock": "^2.6.7", @@ -96,7 +97,7 @@ "ts-loader": "^9.5.1", "ts-node": "^10.9.2", "typescript": "^5.5.4", - "webpack": "^5.94.0", + "webpack": "^5.95.0", "webpack-cli": "^5.1.4" }, "dependencies": { diff --git a/src/slang-nodes/ContractDefinition.ts b/src/slang-nodes/ContractDefinition.ts index 2dbdb3302..eae0e7443 100644 --- a/src/slang-nodes/ContractDefinition.ts +++ b/src/slang-nodes/ContractDefinition.ts @@ -1,6 +1,5 @@ import { doc } from 'prettier'; -import coerce from 'semver/functions/coerce.js'; -import satisfies from 'semver/functions/satisfies.js'; +import { coerce, satisfies } from 'semver'; import { NonterminalKind } from '@nomicfoundation/slang/kinds/index.js'; import { getNodeMetadata, updateMetadata } from '../slang-utils/metadata.js'; import { Identifier } from './Identifier.js'; diff --git a/src/slang-nodes/FunctionDefinition.ts b/src/slang-nodes/FunctionDefinition.ts index d792dcd64..f177f4fcf 100644 --- a/src/slang-nodes/FunctionDefinition.ts +++ b/src/slang-nodes/FunctionDefinition.ts @@ -1,5 +1,4 @@ -import coerce from 'semver/functions/coerce.js'; -import satisfies from 'semver/functions/satisfies.js'; +import { coerce, satisfies } from 'semver'; import { NonterminalKind } from '@nomicfoundation/slang/kinds/index.js'; import { printFunction } from '../slang-printers/print-function.js'; import { getNodeMetadata, updateMetadata } from '../slang-utils/metadata.js'; diff --git a/src/slang-nodes/ImportDeconstructionSymbols.ts b/src/slang-nodes/ImportDeconstructionSymbols.ts index e31818de5..fc76cdc77 100644 --- a/src/slang-nodes/ImportDeconstructionSymbols.ts +++ b/src/slang-nodes/ImportDeconstructionSymbols.ts @@ -1,6 +1,5 @@ import { doc } from 'prettier'; -import coerce from 'semver/functions/coerce.js'; -import satisfies from 'semver/functions/satisfies.js'; +import { coerce, satisfies } from 'semver'; import { NonterminalKind } from '@nomicfoundation/slang/kinds/index.js'; import { printSeparatedList } from '../slang-printers/print-separated-list.js'; import { getNodeMetadata, updateMetadata } from '../slang-utils/metadata.js'; diff --git a/src/slang-nodes/VersionLiteral.ts b/src/slang-nodes/VersionLiteral.ts index ef0919e33..1990abe26 100644 --- a/src/slang-nodes/VersionLiteral.ts +++ b/src/slang-nodes/VersionLiteral.ts @@ -35,6 +35,8 @@ export class VersionLiteral implements SlangNode { } print(path: AstPath, print: PrintFunction): Doc { - return path.call(print, 'variant'); + return typeof this.variant === 'string' + ? this.variant + : path.call(print, 'variant'); } } diff --git a/src/slang-utils/infer-language.ts b/src/slang-utils/infer-language.ts new file mode 100644 index 000000000..e3697f997 --- /dev/null +++ b/src/slang-utils/infer-language.ts @@ -0,0 +1,94 @@ +import { VersionExpressionSets as SlangVersionExpressionSets } from '@nomicfoundation/slang/ast/index.js'; +import { NonterminalKind } from '@nomicfoundation/slang/kinds/index.js'; +import { Language } from '@nomicfoundation/slang/language/index.js'; +import { Query } from '@nomicfoundation/slang/query/index.js'; +import { + maxSatisfying, + minSatisfying, + minor, + major, + minVersion, + validRange +} from 'semver'; +import { VersionExpressionSets } from '../slang-nodes/VersionExpressionSets.js'; + +import type { NonterminalNode } from '@nomicfoundation/slang/cst'; + +const supportedVersions = Language.supportedVersions(); + +const milestoneVersions = Array.from( + supportedVersions.reduce((minorRanges, version) => { + minorRanges.add(`^${major(version)}.${minor(version)}.0`); + return minorRanges; + }, new Set()) +) + .reverse() + .reduce((versions: string[], range) => { + versions.push(maxSatisfying(supportedVersions, range)!); + versions.push(minSatisfying(supportedVersions, range)!); + return versions; + }, []); + +export function inferLanguage(text: string): Language { + let inferredRange = ''; + + for (const version of milestoneVersions) { + try { + inferredRange = tryToCollectPragmas(text, version); + break; + } catch {} + } + + if (!minVersion(inferredRange)) { + throw new Error( + "Couldn't infer any version from the ranges in the pragmas." + ); + } + + const maxSatisfyingVersion = maxSatisfying(supportedVersions, inferredRange); + + return maxSatisfyingVersion + ? new Language(maxSatisfyingVersion) + : new Language(supportedVersions[supportedVersions.length - 1]); +} + +function tryToCollectPragmas(text: string, version: string): string { + const language = new Language(version); + const parseOutput = language.parse(NonterminalKind.SourceUnit, text); + const query = Query.parse( + '[VersionPragma @versionRanges [VersionExpressionSets]]' + ); + const matches = parseOutput.createTreeCursor().query([query]); + const ranges: string[] = []; + + let match; + while ((match = matches.next())) { + const versionRange = new SlangVersionExpressionSets( + match.captures.versionRanges[0].node() as NonterminalNode + ); + ranges.push( + // Replace all comments that could be in the expression with whitespace + new VersionExpressionSets(versionRange, 0).comments.reduce( + (range, comment) => range.replace(comment.value, ' '), + versionRange.cst.unparse() + ) + ); + } + + // Check if we found pragmas. + if (ranges.length === 0) { + // If we didn't find pragmas but succeeded parsing the source we keep it. + if (parseOutput.isValid) { + return version; + } + // Otherwise we throw. + throw new Error( + `Using version ${version} did not find any pragma statement and does not parse without errors.` + ); + } + + // validRange rewrites `0.5.0 - 0.6.0` as `>=0.5.0 <=0.6.0` but it returns + // null if the range is not valid. We have to coerce null to 'null' so it + // fails the `minVersion(inferredRange)` call. + return ranges.map((range) => `${validRange(range)}`).join(' '); +} diff --git a/src/slang-utils/print-warning.ts b/src/slang-utils/print-warning.ts new file mode 100644 index 000000000..367ee9b56 --- /dev/null +++ b/src/slang-utils/print-warning.ts @@ -0,0 +1,12 @@ +export function printWarning(message: string): void { + // Prettier prints some temporary messages while formatting, and this warning + // can mess with that output. We clear the line and move the cursor to the + // beginning of the line to avoid this. + // + // \x1b: Escape character + // [2K: Escape code to clear the entire line + // \r: Carriage return + const clearLine = '\x1b[2K\r'; + + console.warn(`${clearLine}[prettier-solidity] ${message}`); +} diff --git a/src/slangSolidityParser.ts b/src/slangSolidityParser.ts index 9df0c90b4..a32051e67 100644 --- a/src/slangSolidityParser.ts +++ b/src/slangSolidityParser.ts @@ -3,30 +3,39 @@ import { Language } from '@nomicfoundation/slang/language/index.js'; import { NonterminalKind } from '@nomicfoundation/slang/kinds/index.js'; import { SourceUnit as SlangSourceUnit } from '@nomicfoundation/slang/ast/index.js'; -import coerce from 'semver/functions/coerce.js'; +import { maxSatisfying } from 'semver'; +import { inferLanguage } from './slang-utils/infer-language.js'; +import { printWarning } from './slang-utils/print-warning.js'; import { SourceUnit } from './slang-nodes/SourceUnit.js'; import type { NonterminalNode } from '@nomicfoundation/slang/cst'; import type { Parser, ParserOptions } from 'prettier'; import type { AstNode } from './slang-nodes/index.js'; +const supportedVersions = Language.supportedVersions(); + export default function parse( text: string, _parsers: Parser[] | ParserOptions, options = _parsers as ParserOptions ): AstNode { - const compiler = coerce(options.compiler); - const supportedVersions = Language.supportedVersions(); + const compiler = maxSatisfying(supportedVersions, options.compiler); - const language = new Language( - compiler && supportedVersions.includes(compiler.version) - ? compiler.version - : supportedVersions[supportedVersions.length - 1] - ); + const language = + compiler && supportedVersions.includes(compiler) + ? new Language(compiler) + : inferLanguage(text); const parseOutput = language.parse(NonterminalKind.SourceUnit, text); + printWarning( + compiler + ? `Using version ${language.version} based on the compiler option provided.` + : `Inferred version ${language.version} based on the pragma statements in the code.` + ); if (parseOutput.isValid) { + // We update the compiler version by the inferred one. + options.compiler = language.version; return new SourceUnit( new SlangSourceUnit(parseOutput.tree() as NonterminalNode), 0, diff --git a/tests/format/AllSolidityFeatures/AllSolidityFeatures.sol b/tests/format/AllSolidityFeatures/AllSolidityFeatures.sol index dddad0499..487df3a6e 100644 --- a/tests/format/AllSolidityFeatures/AllSolidityFeatures.sol +++ b/tests/format/AllSolidityFeatures/AllSolidityFeatures.sol @@ -263,8 +263,6 @@ enum TopLevelEnum { Level, Enum } -pragma solidity ^0.6.0; - contract A { function doStuff() public virtual {} diff --git a/tests/format/AllSolidityFeatures/__snapshots__/format.test.js.snap b/tests/format/AllSolidityFeatures/__snapshots__/format.test.js.snap index da272f176..ac2f0ffef 100644 --- a/tests/format/AllSolidityFeatures/__snapshots__/format.test.js.snap +++ b/tests/format/AllSolidityFeatures/__snapshots__/format.test.js.snap @@ -271,8 +271,6 @@ enum TopLevelEnum { Level, Enum } -pragma solidity ^0.6.0; - contract A { function doStuff() public virtual {} @@ -632,7 +630,6 @@ enum TopLevelEnum { Level, Enum } -pragma solidity ^0.6.0; contract A { function doStuff() public virtual {} diff --git a/tests/format/AllSolidityFeaturesV0.4.26/__snapshots__/format.test.js.snap b/tests/format/AllSolidityFeaturesV0.4.26/__snapshots__/format.test.js.snap index beb9ef282..07a64f845 100644 --- a/tests/format/AllSolidityFeaturesV0.4.26/__snapshots__/format.test.js.snap +++ b/tests/format/AllSolidityFeaturesV0.4.26/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`AllSolidityFeatures.sol - {"compiler":"0.4.26"} format 1`] = ` +exports[`AllSolidityFeatures.sol format 1`] = ` ====================================options===================================== -compiler: "0.4.26" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/AllSolidityFeaturesV0.4.26/format.test.js b/tests/format/AllSolidityFeaturesV0.4.26/format.test.js index 33e420012..903b20e05 100644 --- a/tests/format/AllSolidityFeaturesV0.4.26/format.test.js +++ b/tests/format/AllSolidityFeaturesV0.4.26/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.4.26' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/AssemblyV0.4.26/__snapshots__/format.test.js.snap b/tests/format/AssemblyV0.4.26/__snapshots__/format.test.js.snap index df3c40580..fc9c0fc17 100644 --- a/tests/format/AssemblyV0.4.26/__snapshots__/format.test.js.snap +++ b/tests/format/AssemblyV0.4.26/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Assembly.sol - {"compiler":"0.4.26"} format 1`] = ` +exports[`Assembly.sol format 1`] = ` ====================================options===================================== -compiler: "0.4.26" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/AssemblyV0.4.26/format.test.js b/tests/format/AssemblyV0.4.26/format.test.js index 33e420012..903b20e05 100644 --- a/tests/format/AssemblyV0.4.26/format.test.js +++ b/tests/format/AssemblyV0.4.26/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.4.26' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/BasicIterator/__snapshots__/format.test.js.snap b/tests/format/BasicIterator/__snapshots__/format.test.js.snap index b109cc404..73486bc57 100644 --- a/tests/format/BasicIterator/__snapshots__/format.test.js.snap +++ b/tests/format/BasicIterator/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`BasicIterator.sol - {"compiler":"0.4.26"} format 1`] = ` +exports[`BasicIterator.sol format 1`] = ` ====================================options===================================== -compiler: "0.4.26" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/BasicIterator/format.test.js b/tests/format/BasicIterator/format.test.js index 33e420012..903b20e05 100644 --- a/tests/format/BasicIterator/format.test.js +++ b/tests/format/BasicIterator/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.4.26' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/BinaryOperators/__snapshots__/format.test.js.snap b/tests/format/BinaryOperators/__snapshots__/format.test.js.snap index e890511b0..39de7969a 100644 --- a/tests/format/BinaryOperators/__snapshots__/format.test.js.snap +++ b/tests/format/BinaryOperators/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`BinaryOperators.sol - {"compiler":"0.5.8"} format 1`] = ` +exports[`BinaryOperators.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.8" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -686,9 +685,8 @@ contract LogicalOperators { ================================================================================ `; -exports[`Parentheses.sol - {"compiler":"0.5.8"} format 1`] = ` +exports[`Parentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.8" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/BinaryOperators/format.test.js b/tests/format/BinaryOperators/format.test.js index 93df2bace..903b20e05 100644 --- a/tests/format/BinaryOperators/format.test.js +++ b/tests/format/BinaryOperators/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.5.8' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/BreakingChangesV0.7.4/__snapshots__/format.test.js.snap b/tests/format/BreakingChangesV0.7.4/__snapshots__/format.test.js.snap index 739214851..f7d81fb1c 100644 --- a/tests/format/BreakingChangesV0.7.4/__snapshots__/format.test.js.snap +++ b/tests/format/BreakingChangesV0.7.4/__snapshots__/format.test.js.snap @@ -1,36 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`BreakingChangesV0.7.4.sol - {"bracketSpacing":true} format 1`] = ` -====================================options===================================== -bracketSpacing: true -parsers: ["slang-solidity"] -printWidth: 80 - | printWidth -=====================================input====================================== -pragma solidity ^0.7.0; - -/** - * - if options.compiler is undefined we won't break the ImportDirective. - * - if options.compiler is lower than 0.7.4 we won't break the ImportDirective. - * - if options.compiler is greater than or equal to 0.7.4 we will break the - * ImportDirective if the line length exceeds the printWidth. - */ -import {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from "File2.sol"; - -=====================================output===================================== -pragma solidity ^0.7.0; - -/** - * - if options.compiler is undefined we won't break the ImportDirective. - * - if options.compiler is lower than 0.7.4 we won't break the ImportDirective. - * - if options.compiler is greater than or equal to 0.7.4 we will break the - * ImportDirective if the line length exceeds the printWidth. - */ -import { symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4 } from "File2.sol"; - -================================================================================ -`; - exports[`BreakingChangesV0.7.4.sol - {"compiler":"0.7.3","bracketSpacing":true} format 1`] = ` ====================================options===================================== bracketSpacing: true @@ -166,33 +135,3 @@ import { ================================================================================ `; - -exports[`BreakingChangesV0.7.4.sol format 1`] = ` -====================================options===================================== -parsers: ["slang-solidity"] -printWidth: 80 - | printWidth -=====================================input====================================== -pragma solidity ^0.7.0; - -/** - * - if options.compiler is undefined we won't break the ImportDirective. - * - if options.compiler is lower than 0.7.4 we won't break the ImportDirective. - * - if options.compiler is greater than or equal to 0.7.4 we will break the - * ImportDirective if the line length exceeds the printWidth. - */ -import {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from "File2.sol"; - -=====================================output===================================== -pragma solidity ^0.7.0; - -/** - * - if options.compiler is undefined we won't break the ImportDirective. - * - if options.compiler is lower than 0.7.4 we won't break the ImportDirective. - * - if options.compiler is greater than or equal to 0.7.4 we will break the - * ImportDirective if the line length exceeds the printWidth. - */ -import {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from "File2.sol"; - -================================================================================ -`; diff --git a/tests/format/BreakingChangesV0.7.4/format.test.js b/tests/format/BreakingChangesV0.7.4/format.test.js index d32104828..3bf2fe10b 100644 --- a/tests/format/BreakingChangesV0.7.4/format.test.js +++ b/tests/format/BreakingChangesV0.7.4/format.test.js @@ -8,5 +8,3 @@ runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.7.3', bracketSpacing: true }); -runFormatTest(import.meta, ['slang-solidity']); -runFormatTest(import.meta, ['slang-solidity'], { bracketSpacing: true }); diff --git a/tests/format/Comments/__snapshots__/format.test.js.snap b/tests/format/Comments/__snapshots__/format.test.js.snap index a79c13424..fe1184aa6 100644 --- a/tests/format/Comments/__snapshots__/format.test.js.snap +++ b/tests/format/Comments/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Comments.sol - {"compiler":"0.4.24"} format 1`] = ` +exports[`Comments.sol format 1`] = ` ====================================options===================================== -compiler: "0.4.24" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/Comments/format.test.js b/tests/format/Comments/format.test.js index 736908342..903b20e05 100644 --- a/tests/format/Comments/format.test.js +++ b/tests/format/Comments/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.4.24' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/Constructors/Constructors.sol b/tests/format/Constructors/Constructors.sol index 0388ac967..494f1cf98 100644 --- a/tests/format/Constructors/Constructors.sol +++ b/tests/format/Constructors/Constructors.sol @@ -1,8 +1,5 @@ pragma solidity ^0.5.2; contract Constructors is Ownable, Changeable { - function Constructors(variable1) public Changeable(variable1) Ownable() onlyOwner { - } - constructor(variable1, variable2, variable3, variable4, variable5, variable6, variable7) public Changeable(variable1, variable2, variable3, variable4, variable5, variable6, variable7) Ownable() onlyOwner {} } diff --git a/tests/format/Constructors/__snapshots__/format.test.js.snap b/tests/format/Constructors/__snapshots__/format.test.js.snap index b3e967279..2cfa25418 100644 --- a/tests/format/Constructors/__snapshots__/format.test.js.snap +++ b/tests/format/Constructors/__snapshots__/format.test.js.snap @@ -9,9 +9,6 @@ printWidth: 80 pragma solidity ^0.5.2; contract Constructors is Ownable, Changeable { - function Constructors(variable1) public Changeable(variable1) Ownable() onlyOwner { - } - constructor(variable1, variable2, variable3, variable4, variable5, variable6, variable7) public Changeable(variable1, variable2, variable3, variable4, variable5, variable6, variable7) Ownable() onlyOwner {} } @@ -19,10 +16,6 @@ contract Constructors is Ownable, Changeable { pragma solidity ^0.5.2; contract Constructors is Ownable, Changeable { - function Constructors( - variable1 - ) public Changeable(variable1) Ownable() onlyOwner {} - constructor( variable1, variable2, diff --git a/tests/format/ConstructorsV0.4.26/Constructors.sol b/tests/format/ConstructorsV0.4.26/Constructors.sol new file mode 100644 index 000000000..273157c4e --- /dev/null +++ b/tests/format/ConstructorsV0.4.26/Constructors.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.4.26; + +contract Constructors is Ownable, Changeable { + function Constructors(variable1) public Changeable(variable1) Ownable() onlyOwner { + } +} diff --git a/tests/format/ConstructorsV0.4.26/__snapshots__/format.test.js.snap b/tests/format/ConstructorsV0.4.26/__snapshots__/format.test.js.snap new file mode 100644 index 000000000..6e3b882d7 --- /dev/null +++ b/tests/format/ConstructorsV0.4.26/__snapshots__/format.test.js.snap @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Constructors.sol format 1`] = ` +====================================options===================================== +parsers: ["slang-solidity"] +printWidth: 80 + | printWidth +=====================================input====================================== +pragma solidity ^0.4.26; + +contract Constructors is Ownable, Changeable { + function Constructors(variable1) public Changeable(variable1) Ownable() onlyOwner { + } +} + +=====================================output===================================== +pragma solidity ^0.4.26; + +contract Constructors is Ownable, Changeable { + function Constructors( + variable1 + ) public Changeable(variable1) Ownable() onlyOwner {} +} + +================================================================================ +`; diff --git a/tests/format/ConstructorsV0.4.26/format.test.js b/tests/format/ConstructorsV0.4.26/format.test.js new file mode 100644 index 000000000..903b20e05 --- /dev/null +++ b/tests/format/ConstructorsV0.4.26/format.test.js @@ -0,0 +1 @@ +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/FunctionDefinitions/__snapshots__/format.test.js.snap b/tests/format/FunctionDefinitions/__snapshots__/format.test.js.snap index 0e6afdba6..f651f0d4f 100644 --- a/tests/format/FunctionDefinitions/__snapshots__/format.test.js.snap +++ b/tests/format/FunctionDefinitions/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FunctionDefinitions.sol - {"compiler":"0.8.0"} format 1`] = ` +exports[`FunctionDefinitions.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/FunctionDefinitions/format.test.js b/tests/format/FunctionDefinitions/format.test.js index 7b2a6b775..903b20e05 100644 --- a/tests/format/FunctionDefinitions/format.test.js +++ b/tests/format/FunctionDefinitions/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.8.0' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/FunctionDefinitionsv0.5.0/__snapshots__/format.test.js.snap b/tests/format/FunctionDefinitionsv0.5.0/__snapshots__/format.test.js.snap index 220e65901..d369db5db 100644 --- a/tests/format/FunctionDefinitionsv0.5.0/__snapshots__/format.test.js.snap +++ b/tests/format/FunctionDefinitionsv0.5.0/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FunctionDefinitions.sol - {"compiler":"0.5.0"} format 1`] = ` +exports[`FunctionDefinitions.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/FunctionDefinitionsv0.5.0/format.test.js b/tests/format/FunctionDefinitionsv0.5.0/format.test.js index 356182fec..903b20e05 100644 --- a/tests/format/FunctionDefinitionsv0.5.0/format.test.js +++ b/tests/format/FunctionDefinitionsv0.5.0/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.5.0' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/ImportDirective/__snapshots__/format.test.js.snap b/tests/format/ImportDirective/__snapshots__/format.test.js.snap index bfd5c1f45..8cca1f2e7 100644 --- a/tests/format/ImportDirective/__snapshots__/format.test.js.snap +++ b/tests/format/ImportDirective/__snapshots__/format.test.js.snap @@ -18,7 +18,12 @@ import "SomeFile.sol"; import "SomeFile.sol" as SomeOtherFile; import * as SomeSymbol from "AnotherFile.sol"; import { symbol1 as alias1, symbol2 } from "File.sol"; -import { symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4 } from "File2.sol"; +import { + symbol1 as alias1, + symbol2 as alias2, + symbol3 as alias3, + symbol4 +} from "File2.sol"; ================================================================================ `; @@ -63,7 +68,12 @@ import "SomeFile.sol"; import "SomeFile.sol" as SomeOtherFile; import * as SomeSymbol from "AnotherFile.sol"; import {symbol1 as alias1, symbol2} from "File.sol"; -import {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from "File2.sol"; +import { + symbol1 as alias1, + symbol2 as alias2, + symbol3 as alias3, + symbol4 +} from "File2.sol"; ================================================================================ `; diff --git a/tests/format/IndexOf/__snapshots__/format.test.js.snap b/tests/format/IndexOf/__snapshots__/format.test.js.snap index 9e427dc6f..ea2596b63 100644 --- a/tests/format/IndexOf/__snapshots__/format.test.js.snap +++ b/tests/format/IndexOf/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`IndexOf.sol - {"compiler":"0.4.26"} format 1`] = ` +exports[`IndexOf.sol format 1`] = ` ====================================options===================================== -compiler: "0.4.26" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/IndexOf/format.test.js b/tests/format/IndexOf/format.test.js index 33e420012..903b20e05 100644 --- a/tests/format/IndexOf/format.test.js +++ b/tests/format/IndexOf/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.4.26' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/MemberAccess/MemberAccess.sol b/tests/format/MemberAccess/MemberAccess.sol index 10b9943d0..7b66b782b 100644 --- a/tests/format/MemberAccess/MemberAccess.sol +++ b/tests/format/MemberAccess/MemberAccess.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; contract MemberAccess { function foo() { diff --git a/tests/format/MemberAccess/__snapshots__/format.test.js.snap b/tests/format/MemberAccess/__snapshots__/format.test.js.snap index 46fa45270..ba78f0e59 100644 --- a/tests/format/MemberAccess/__snapshots__/format.test.js.snap +++ b/tests/format/MemberAccess/__snapshots__/format.test.js.snap @@ -6,7 +6,7 @@ parsers: ["slang-solidity"] printWidth: 80 | printWidth =====================================input====================================== -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; contract MemberAccess { function foo() { @@ -115,7 +115,7 @@ contract MemberAccessIsEndOfChainCases { } =====================================output===================================== -pragma solidity ^0.5.0; +pragma solidity ^0.6.0; contract MemberAccess { function foo() { diff --git a/tests/format/ModifierInvocations/__snapshots__/format.test.js.snap b/tests/format/ModifierInvocations/__snapshots__/format.test.js.snap index b237b7e46..5167c3308 100644 --- a/tests/format/ModifierInvocations/__snapshots__/format.test.js.snap +++ b/tests/format/ModifierInvocations/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ModifierInvocations.sol - {"compiler":"0.8.0"} format 1`] = ` +exports[`ModifierInvocations.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/ModifierInvocations/format.test.js b/tests/format/ModifierInvocations/format.test.js index 7b2a6b775..903b20e05 100644 --- a/tests/format/ModifierInvocations/format.test.js +++ b/tests/format/ModifierInvocations/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.8.0' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/Parentheses/__snapshots__/format.test.js.snap b/tests/format/Parentheses/__snapshots__/format.test.js.snap index 102d89b24..12e774509 100644 --- a/tests/format/Parentheses/__snapshots__/format.test.js.snap +++ b/tests/format/Parentheses/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`AddNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`AddNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -197,9 +196,8 @@ contract AddNoParentheses { ================================================================================ `; -exports[`BitAndNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`BitAndNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -394,9 +392,8 @@ contract BitAndNoParentheses { ================================================================================ `; -exports[`BitOrNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`BitOrNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -591,9 +588,8 @@ contract BitOrNoParentheses { ================================================================================ `; -exports[`BitXorNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`BitXorNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -788,9 +784,8 @@ contract BitXorNoParentheses { ================================================================================ `; -exports[`DivNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`DivNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -985,9 +980,8 @@ contract DivNoParentheses { ================================================================================ `; -exports[`ExpNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`ExpNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -1182,9 +1176,8 @@ contract ExpNoParentheses { ================================================================================ `; -exports[`LogicNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`LogicNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -1235,9 +1228,8 @@ contract LogicNoParentheses { ================================================================================ `; -exports[`ModNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`ModNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -1432,9 +1424,8 @@ contract ModNoParentheses { ================================================================================ `; -exports[`MulNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`MulNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -1629,9 +1620,8 @@ contract MulNoParentheses { ================================================================================ `; -exports[`ShiftLNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`ShiftLNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -1826,9 +1816,8 @@ contract ShiftLNoParentheses { ================================================================================ `; -exports[`ShiftRNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`ShiftRNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -2023,9 +2012,8 @@ contract ShiftRNoParentheses { ================================================================================ `; -exports[`SubNoParentheses.sol - {"compiler":"0.8.6"} format 1`] = ` +exports[`SubNoParentheses.sol format 1`] = ` ====================================options===================================== -compiler: "0.8.6" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/Parentheses/format.test.js b/tests/format/Parentheses/format.test.js index 37e318348..903b20e05 100644 --- a/tests/format/Parentheses/format.test.js +++ b/tests/format/Parentheses/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.8.6' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/Pragma/Pragma.sol b/tests/format/Pragma/Pragma.sol index 83f9315d5..b25fcc72b 100644 --- a/tests/format/Pragma/Pragma.sol +++ b/tests/format/Pragma/Pragma.sol @@ -2,10 +2,10 @@ pragma solidity >=0.4.21 <0.6.0; pragma solidity >=0.4.21 <=0.6.0 ; pragma solidity >0.4.21 <0.6.0; pragma solidity >0.4.21 <=0.6.0; -pragma solidity >=0.4.21<0.6.0; +pragma solidity >=0.4.21 <0.6.0; pragma solidity ^ 0.4.21 ; pragma solidity ~ 0.4.21 ; -pragma solidity ^0.5.0 || ^0.6.0 || ^0.7.0 ; +pragma solidity ^0.4.0 || ^0.5.0 || ^0.6.0 ; pragma solidity 0.5.0 - 0.6.0 ; pragma experimental ABIEncoderV2; pragma abicoder v2; diff --git a/tests/format/Pragma/__snapshots__/format.test.js.snap b/tests/format/Pragma/__snapshots__/format.test.js.snap index f32ecb50e..f63413440 100644 --- a/tests/format/Pragma/__snapshots__/format.test.js.snap +++ b/tests/format/Pragma/__snapshots__/format.test.js.snap @@ -10,10 +10,10 @@ pragma solidity >=0.4.21 <0.6.0; pragma solidity >=0.4.21 <=0.6.0 ; pragma solidity >0.4.21 <0.6.0; pragma solidity >0.4.21 <=0.6.0; -pragma solidity >=0.4.21<0.6.0; +pragma solidity >=0.4.21 <0.6.0; pragma solidity ^ 0.4.21 ; pragma solidity ~ 0.4.21 ; -pragma solidity ^0.5.0 || ^0.6.0 || ^0.7.0 ; +pragma solidity ^0.4.0 || ^0.5.0 || ^0.6.0 ; pragma solidity 0.5.0 - 0.6.0 ; pragma experimental ABIEncoderV2; pragma abicoder v2; @@ -26,7 +26,7 @@ pragma solidity >0.4.21 <=0.6.0; pragma solidity >=0.4.21 <0.6.0; pragma solidity ^0.4.21; pragma solidity ~0.4.21; -pragma solidity ^0.5.0 || ^0.6.0 || ^0.7.0; +pragma solidity ^0.4.0 || ^0.5.0 || ^0.6.0; pragma solidity 0.5.0 - 0.6.0; pragma experimental ABIEncoderV2; pragma abicoder v2; diff --git a/tests/format/PrettierIgnore/PrettierIgnore.sol b/tests/format/PrettierIgnore/PrettierIgnore.sol index b2e54f789..57bf9f231 100644 --- a/tests/format/PrettierIgnore/PrettierIgnore.sol +++ b/tests/format/PrettierIgnore/PrettierIgnore.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.2; +pragma solidity ^0.6.0; contract PrettierIgnore { fallback() external payable { diff --git a/tests/format/PrettierIgnore/__snapshots__/format.test.js.snap b/tests/format/PrettierIgnore/__snapshots__/format.test.js.snap index 70ba3c777..0e678d915 100644 --- a/tests/format/PrettierIgnore/__snapshots__/format.test.js.snap +++ b/tests/format/PrettierIgnore/__snapshots__/format.test.js.snap @@ -6,7 +6,7 @@ parsers: ["slang-solidity"] printWidth: 80 | printWidth =====================================input====================================== -pragma solidity ^0.5.2; +pragma solidity ^0.6.0; contract PrettierIgnore { fallback() external payable { @@ -47,7 +47,7 @@ contract Example { } =====================================output===================================== -pragma solidity ^0.5.2; +pragma solidity ^0.6.0; contract PrettierIgnore { fallback() external payable { diff --git a/tests/format/Proxy/__snapshots__/format.test.js.snap b/tests/format/Proxy/__snapshots__/format.test.js.snap index 48108bb4b..1ce4085c5 100644 --- a/tests/format/Proxy/__snapshots__/format.test.js.snap +++ b/tests/format/Proxy/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Proxy.sol - {"compiler":"0.4.24"} format 1`] = ` +exports[`Proxy.sol format 1`] = ` ====================================options===================================== -compiler: "0.4.24" parsers: ["slang-solidity"] printWidth: 80 | printWidth diff --git a/tests/format/Proxy/format.test.js b/tests/format/Proxy/format.test.js index 736908342..903b20e05 100644 --- a/tests/format/Proxy/format.test.js +++ b/tests/format/Proxy/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.4.24' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/format/StyleGuide/ControlStructures.sol b/tests/format/StyleGuide/ControlStructures.sol index 0546fcd28..275b5e25d 100644 --- a/tests/format/StyleGuide/ControlStructures.sol +++ b/tests/format/StyleGuide/ControlStructures.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract ControlStructures diff --git a/tests/format/StyleGuide/MaximumLineLength.sol b/tests/format/StyleGuide/MaximumLineLength.sol index ee624ff6f..3073e0c81 100644 --- a/tests/format/StyleGuide/MaximumLineLength.sol +++ b/tests/format/StyleGuide/MaximumLineLength.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract FunctionCalls { diff --git a/tests/format/StyleGuide/OtherRecommendations.sol b/tests/format/StyleGuide/OtherRecommendations.sol index 91a12d547..e30d21ff0 100644 --- a/tests/format/StyleGuide/OtherRecommendations.sol +++ b/tests/format/StyleGuide/OtherRecommendations.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract OtherRecommendations { diff --git a/tests/format/StyleGuide/WhitespaceInExpressions.sol b/tests/format/StyleGuide/WhitespaceInExpressions.sol index 0ff2badd5..16c9004c0 100644 --- a/tests/format/StyleGuide/WhitespaceInExpressions.sol +++ b/tests/format/StyleGuide/WhitespaceInExpressions.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract WhitespaceInExpressions { diff --git a/tests/format/StyleGuide/__snapshots__/format.test.js.snap b/tests/format/StyleGuide/__snapshots__/format.test.js.snap index b38b35771..cafdd4383 100644 --- a/tests/format/StyleGuide/__snapshots__/format.test.js.snap +++ b/tests/format/StyleGuide/__snapshots__/format.test.js.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`BlankLines.sol - {"compiler":"0.5.0"} format 1`] = ` +exports[`BlankLines.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -47,14 +46,13 @@ contract A { ================================================================================ `; -exports[`ControlStructures.sol - {"compiler":"0.5.0"} format 1`] = ` +exports[`ControlStructures.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth =====================================input====================================== -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract ControlStructures @@ -113,7 +111,7 @@ contract ControlStructures } =====================================output===================================== -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract ControlStructures { struct Bank { @@ -169,9 +167,8 @@ contract ControlStructures { ================================================================================ `; -exports[`FunctionDeclaration.sol - {"compiler":"0.5.0"} format 1`] = ` +exports[`FunctionDeclaration.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -461,9 +458,8 @@ contract X is B, C, D { ================================================================================ `; -exports[`Mappings.sol - {"compiler":"0.5.0"} format 1`] = ` +exports[`Mappings.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -491,14 +487,13 @@ contract Mappings { ================================================================================ `; -exports[`MaximumLineLength.sol - {"compiler":"0.5.0"} format 1`] = ` +exports[`MaximumLineLength.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth =====================================input====================================== -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract FunctionCalls { @@ -567,7 +562,7 @@ contract EventDefinitionsAndEventEmitters { } =====================================output===================================== -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract FunctionCalls { function() { @@ -647,14 +642,13 @@ contract EventDefinitionsAndEventEmitters { ================================================================================ `; -exports[`OtherRecommendations.sol - {"compiler":"0.5.0"} format 1`] = ` +exports[`OtherRecommendations.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth =====================================input====================================== -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract OtherRecommendations { @@ -685,7 +679,7 @@ contract OtherRecommendations { } =====================================output===================================== -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract OtherRecommendations { function() { @@ -715,9 +709,8 @@ contract OtherRecommendations { ================================================================================ `; -exports[`VariableDeclarations.sol - {"compiler":"0.5.0"} format 1`] = ` +exports[`VariableDeclarations.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth @@ -739,14 +732,13 @@ contract VariableDeclarations { ================================================================================ `; -exports[`WhitespaceInExpressions.sol - {"compiler":"0.5.0"} format 1`] = ` +exports[`WhitespaceInExpressions.sol format 1`] = ` ====================================options===================================== -compiler: "0.5.0" parsers: ["slang-solidity"] printWidth: 80 | printWidth =====================================input====================================== -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract WhitespaceInExpressions { @@ -761,7 +753,7 @@ contract WhitespaceInExpressions { } =====================================output===================================== -pragma solidity >=0.4.0 <0.7.0; +pragma solidity >=0.4.0 <0.6.0; contract WhitespaceInExpressions { function() { diff --git a/tests/format/StyleGuide/format.test.js b/tests/format/StyleGuide/format.test.js index 356182fec..903b20e05 100644 --- a/tests/format/StyleGuide/format.test.js +++ b/tests/format/StyleGuide/format.test.js @@ -1 +1 @@ -runFormatTest(import.meta, ['slang-solidity'], { compiler: '0.5.0' }); +runFormatTest(import.meta, ['slang-solidity']); diff --git a/tests/unit/slang-utils/infer-language.test.js b/tests/unit/slang-utils/infer-language.test.js new file mode 100644 index 000000000..c1f882ea5 --- /dev/null +++ b/tests/unit/slang-utils/infer-language.test.js @@ -0,0 +1,103 @@ +import { Language } from '@nomicfoundation/slang/language/index.js'; +import { inferLanguage } from '../../../src/slang-utils/infer-language.js'; + +describe('inferLanguage', function () { + const supportedVersions = Language.supportedVersions(); + const latestSupportedVersion = + supportedVersions[supportedVersions.length - 1]; + + const fixtures = [ + { + description: 'Caret range', + source: `pragma solidity ^0.7.0;`, + version: '0.7.6' + }, + { + description: 'Pinned version', + source: `pragma solidity 0.8.1;`, + version: '0.8.1' + }, + { + description: 'With nightly commit', + source: `pragma solidity 0.8.18-ci.2023.1.17+commit.e7b959af;`, + version: '0.8.18' + }, + { + description: 'Caret range and pinned version', + source: `pragma solidity ^0.8.0; pragma solidity 0.8.2;`, + version: '0.8.2' + }, + { + description: 'With multiline comment before the range', + source: `pragma solidity /* comment */ 0.8.2;`, + version: '0.8.2' + }, + { + description: 'With natspec comment before the range', + source: `pragma solidity /** comment */ 0.8.2;`, + version: '0.8.2' + }, + { + description: 'With multiline comment between the ranges', + source: `pragma solidity ^0.8.0 /* comment */ 0.8.2;`, + version: '0.8.2' + }, + { + description: 'With natspec comment between the ranges', + source: `pragma solidity ^0.8.0 /** comment */ 0.8.2;`, + version: '0.8.2' + }, + { + description: 'With multiline comment after the range', + source: `pragma solidity 0.8.2 /* comment */;`, + version: '0.8.2' + }, + { + description: 'With natspec comment after the range', + source: `pragma solidity 0.8.2 /** comment */;`, + version: '0.8.2' + }, + { + description: 'With tracing line comment', + source: `pragma solidity 0.8.2; // line comment`, + version: '0.8.2' + }, + { + description: 'With line comment between "solidity" and the version', + source: `pragma solidity +// line comment +0.8.2;`, + version: '0.8.2' + }, + { + description: 'should use the latest version if the source has no pragmas', + source: `contract Foo {}`, + version: latestSupportedVersion + }, + { + description: + 'should use the latest valid version if the source has no pragmas and the syntax is old', + source: `contract Foo {byte bar;}`, + version: '0.7.6' + }, + { + description: + 'should use the latest version if the range is outside the supported versions', + source: `pragma solidity ^0.8.27;`, + version: latestSupportedVersion + } + ]; + + for (const { description, source, version } of fixtures) { + test(description, function () { + const inferredLanguage = inferLanguage(source); + expect(inferredLanguage.version).toEqual(version); + }); + } + + test('should throw an error if there are incompatible ranges', function () { + expect(() => + inferLanguage(`pragma solidity ^0.8.0; pragma solidity 0.7.6;`) + ).toThrow(); + }); +});