@seljs/checker 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/_virtual/_rolldown/runtime.cjs +23 -0
  3. package/dist/checker/checker.cjs +482 -0
  4. package/dist/checker/checker.d.cts +176 -0
  5. package/dist/checker/checker.d.mts +176 -0
  6. package/dist/checker/checker.mjs +481 -0
  7. package/dist/checker/diagnostics.cjs +66 -0
  8. package/dist/checker/diagnostics.mjs +66 -0
  9. package/dist/checker/index.cjs +2 -0
  10. package/dist/checker/index.d.mts +2 -0
  11. package/dist/checker/index.mjs +3 -0
  12. package/dist/checker/type-compatibility.cjs +70 -0
  13. package/dist/checker/type-compatibility.d.cts +8 -0
  14. package/dist/checker/type-compatibility.d.mts +8 -0
  15. package/dist/checker/type-compatibility.mjs +69 -0
  16. package/dist/constants.cjs +14 -0
  17. package/dist/constants.d.cts +7 -0
  18. package/dist/constants.d.mts +7 -0
  19. package/dist/constants.mjs +13 -0
  20. package/dist/debug.cjs +7 -0
  21. package/dist/debug.mjs +5 -0
  22. package/dist/environment/codec-registry.cjs +109 -0
  23. package/dist/environment/codec-registry.d.cts +45 -0
  24. package/dist/environment/codec-registry.d.mts +45 -0
  25. package/dist/environment/codec-registry.mjs +108 -0
  26. package/dist/environment/hydrate.cjs +163 -0
  27. package/dist/environment/hydrate.d.cts +52 -0
  28. package/dist/environment/hydrate.d.mts +52 -0
  29. package/dist/environment/hydrate.mjs +160 -0
  30. package/dist/environment/index.cjs +4 -0
  31. package/dist/environment/index.d.mts +4 -0
  32. package/dist/environment/index.mjs +5 -0
  33. package/dist/environment/register-types.cjs +107 -0
  34. package/dist/environment/register-types.d.cts +15 -0
  35. package/dist/environment/register-types.d.mts +15 -0
  36. package/dist/environment/register-types.mjs +106 -0
  37. package/dist/environment/value-wrappers.cjs +44 -0
  38. package/dist/environment/value-wrappers.d.cts +20 -0
  39. package/dist/environment/value-wrappers.d.mts +20 -0
  40. package/dist/environment/value-wrappers.mjs +41 -0
  41. package/dist/index.cjs +27 -0
  42. package/dist/index.d.cts +11 -0
  43. package/dist/index.d.mts +11 -0
  44. package/dist/index.mjs +13 -0
  45. package/dist/rules/defaults/deferred-call.cjs +107 -0
  46. package/dist/rules/defaults/deferred-call.mjs +106 -0
  47. package/dist/rules/defaults/index.cjs +6 -0
  48. package/dist/rules/defaults/index.mjs +7 -0
  49. package/dist/rules/defaults/no-constant-condition.cjs +31 -0
  50. package/dist/rules/defaults/no-constant-condition.mjs +31 -0
  51. package/dist/rules/defaults/no-mixed-operators.cjs +39 -0
  52. package/dist/rules/defaults/no-mixed-operators.mjs +39 -0
  53. package/dist/rules/defaults/no-redundant-bool.cjs +26 -0
  54. package/dist/rules/defaults/no-redundant-bool.mjs +26 -0
  55. package/dist/rules/defaults/no-self-comparison.cjs +44 -0
  56. package/dist/rules/defaults/no-self-comparison.mjs +43 -0
  57. package/dist/rules/defaults/require-type.cjs +18 -0
  58. package/dist/rules/defaults/require-type.mjs +18 -0
  59. package/dist/rules/facade.cjs +31 -0
  60. package/dist/rules/facade.d.cts +20 -0
  61. package/dist/rules/facade.d.mts +20 -0
  62. package/dist/rules/facade.mjs +31 -0
  63. package/dist/rules/index.cjs +2 -0
  64. package/dist/rules/index.d.mts +3 -0
  65. package/dist/rules/index.mjs +3 -0
  66. package/dist/rules/runner.cjs +40 -0
  67. package/dist/rules/runner.d.cts +27 -0
  68. package/dist/rules/runner.d.mts +27 -0
  69. package/dist/rules/runner.mjs +40 -0
  70. package/dist/rules/types.d.cts +77 -0
  71. package/dist/rules/types.d.mts +77 -0
  72. package/dist/utils/ast-utils.cjs +164 -0
  73. package/dist/utils/ast-utils.mjs +162 -0
  74. package/package.json +24 -17
  75. package/dist/checker/checker.d.ts +0 -173
  76. package/dist/checker/checker.js +0 -567
  77. package/dist/checker/diagnostics.d.ts +0 -10
  78. package/dist/checker/diagnostics.js +0 -80
  79. package/dist/checker/index.d.ts +0 -2
  80. package/dist/checker/index.js +0 -2
  81. package/dist/checker/type-compatibility.d.ts +0 -16
  82. package/dist/checker/type-compatibility.js +0 -59
  83. package/dist/constants.d.ts +0 -4
  84. package/dist/constants.js +0 -10
  85. package/dist/debug.d.ts +0 -2
  86. package/dist/debug.js +0 -2
  87. package/dist/environment/codec-registry.d.ts +0 -42
  88. package/dist/environment/codec-registry.js +0 -146
  89. package/dist/environment/hydrate.d.ts +0 -48
  90. package/dist/environment/hydrate.js +0 -198
  91. package/dist/environment/index.d.ts +0 -4
  92. package/dist/environment/index.js +0 -4
  93. package/dist/environment/register-types.d.ts +0 -14
  94. package/dist/environment/register-types.js +0 -154
  95. package/dist/environment/value-wrappers.d.ts +0 -17
  96. package/dist/environment/value-wrappers.js +0 -65
  97. package/dist/index.d.ts +0 -4
  98. package/dist/index.js +0 -4
  99. package/dist/rules/defaults/deferred-call.d.ts +0 -13
  100. package/dist/rules/defaults/deferred-call.js +0 -162
  101. package/dist/rules/defaults/index.d.ts +0 -6
  102. package/dist/rules/defaults/index.js +0 -6
  103. package/dist/rules/defaults/no-constant-condition.d.ts +0 -7
  104. package/dist/rules/defaults/no-constant-condition.js +0 -36
  105. package/dist/rules/defaults/no-mixed-operators.d.ts +0 -9
  106. package/dist/rules/defaults/no-mixed-operators.js +0 -44
  107. package/dist/rules/defaults/no-redundant-bool.d.ts +0 -5
  108. package/dist/rules/defaults/no-redundant-bool.js +0 -27
  109. package/dist/rules/defaults/no-self-comparison.d.ts +0 -9
  110. package/dist/rules/defaults/no-self-comparison.js +0 -31
  111. package/dist/rules/defaults/require-type.d.ts +0 -7
  112. package/dist/rules/defaults/require-type.js +0 -19
  113. package/dist/rules/facade.d.ts +0 -22
  114. package/dist/rules/facade.js +0 -29
  115. package/dist/rules/index.d.ts +0 -3
  116. package/dist/rules/index.js +0 -3
  117. package/dist/rules/runner.d.ts +0 -16
  118. package/dist/rules/runner.js +0 -30
  119. package/dist/rules/types.d.ts +0 -73
  120. package/dist/rules/types.js +0 -1
  121. package/dist/utils/ast-utils.d.ts +0 -55
  122. package/dist/utils/ast-utils.js +0 -255
  123. package/dist/utils/index.d.ts +0 -1
  124. package/dist/utils/index.js +0 -1
@@ -0,0 +1,106 @@
1
+ import { SOLIDITY_TYPES, SolidityIntTypeWrapper, formatUnitsValue, parseUnitsValue, toAddress, toBigInt } from "@seljs/types";
2
+ //#region src/environment/register-types.ts
3
+ /**
4
+ * Try to register an operator, silently ignoring "already registered" errors.
5
+ * cel-js auto-derives some cross-type operators (e.g., registering
6
+ * `sol_int == int` also creates `int == sol_int`).
7
+ */
8
+ const tryRegisterOperator = (env, signature, handler) => {
9
+ try {
10
+ env.registerOperator(signature, handler);
11
+ } catch (error) {
12
+ if (!(error instanceof Error) || !error.message.includes("already registered")) throw error;
13
+ }
14
+ };
15
+ const registerAddressOperators = (env) => {
16
+ env.registerOperator("sol_address == sol_address", (left, right) => toAddress(left) === toAddress(right));
17
+ env.registerOperator("sol_address < sol_address", (left, right) => toAddress(left) < toAddress(right));
18
+ env.registerOperator("sol_address <= sol_address", (left, right) => toAddress(left) <= toAddress(right));
19
+ env.registerOperator("sol_address > sol_address", (left, right) => toAddress(left) > toAddress(right));
20
+ env.registerOperator("sol_address >= sol_address", (left, right) => toAddress(left) >= toAddress(right));
21
+ };
22
+ const toSolInt = (value) => new SolidityIntTypeWrapper(value);
23
+ const registerIntegerOperators = (env) => {
24
+ env.registerOperator("sol_int + sol_int", (a, b) => toSolInt(toBigInt(a) + toBigInt(b)));
25
+ env.registerOperator("sol_int - sol_int", (a, b) => toSolInt(toBigInt(a) - toBigInt(b)));
26
+ env.registerOperator("sol_int * sol_int", (a, b) => toSolInt(toBigInt(a) * toBigInt(b)));
27
+ env.registerOperator("sol_int / sol_int", (a, b) => {
28
+ const divisor = toBigInt(b);
29
+ if (divisor === 0n) throw new Error("division by zero");
30
+ return toSolInt(toBigInt(a) / divisor);
31
+ });
32
+ env.registerOperator("sol_int % sol_int", (a, b) => {
33
+ const divisor = toBigInt(b);
34
+ if (divisor === 0n) throw new Error("modulo by zero");
35
+ return toSolInt(toBigInt(a) % divisor);
36
+ });
37
+ env.registerOperator("-sol_int", (a) => toSolInt(-toBigInt(a)));
38
+ env.registerOperator("sol_int == sol_int", (a, b) => toBigInt(a) === toBigInt(b));
39
+ env.registerOperator("sol_int < sol_int", (a, b) => toBigInt(a) < toBigInt(b));
40
+ env.registerOperator("sol_int <= sol_int", (a, b) => toBigInt(a) <= toBigInt(b));
41
+ env.registerOperator("sol_int > sol_int", (a, b) => toBigInt(a) > toBigInt(b));
42
+ env.registerOperator("sol_int >= sol_int", (a, b) => toBigInt(a) >= toBigInt(b));
43
+ tryRegisterOperator(env, "sol_int + int", (a, b) => toSolInt(toBigInt(a) + toBigInt(b)));
44
+ tryRegisterOperator(env, "sol_int - int", (a, b) => toSolInt(toBigInt(a) - toBigInt(b)));
45
+ tryRegisterOperator(env, "sol_int * int", (a, b) => toSolInt(toBigInt(a) * toBigInt(b)));
46
+ tryRegisterOperator(env, "sol_int / int", (a, b) => {
47
+ const divisor = toBigInt(b);
48
+ if (divisor === 0n) throw new Error("division by zero");
49
+ return toSolInt(toBigInt(a) / divisor);
50
+ });
51
+ tryRegisterOperator(env, "sol_int % int", (a, b) => {
52
+ const divisor = toBigInt(b);
53
+ if (divisor === 0n) throw new Error("modulo by zero");
54
+ return toSolInt(toBigInt(a) % divisor);
55
+ });
56
+ tryRegisterOperator(env, "sol_int == int", (a, b) => toBigInt(a) === toBigInt(b));
57
+ tryRegisterOperator(env, "int == sol_int", (a, b) => toBigInt(a) === toBigInt(b));
58
+ tryRegisterOperator(env, "sol_int < int", (a, b) => toBigInt(a) < toBigInt(b));
59
+ tryRegisterOperator(env, "int < sol_int", (a, b) => toBigInt(a) < toBigInt(b));
60
+ tryRegisterOperator(env, "sol_int <= int", (a, b) => toBigInt(a) <= toBigInt(b));
61
+ tryRegisterOperator(env, "int <= sol_int", (a, b) => toBigInt(a) <= toBigInt(b));
62
+ tryRegisterOperator(env, "sol_int > int", (a, b) => toBigInt(a) > toBigInt(b));
63
+ tryRegisterOperator(env, "int > sol_int", (a, b) => toBigInt(a) > toBigInt(b));
64
+ tryRegisterOperator(env, "sol_int >= int", (a, b) => toBigInt(a) >= toBigInt(b));
65
+ tryRegisterOperator(env, "int >= sol_int", (a, b) => toBigInt(a) >= toBigInt(b));
66
+ };
67
+ /**
68
+ * Register all Solidity primitive types on a CEL Environment.
69
+ */
70
+ const registerSolidityTypes = (env) => {
71
+ for (const entry of SOLIDITY_TYPES) {
72
+ if (entry.type === "builtin") continue;
73
+ env.registerType(entry.name, entry.wrapperClass);
74
+ if (entry.name === "sol_address") registerAddressOperators(env);
75
+ if (entry.name === "sol_int") registerIntegerOperators(env);
76
+ const Ctor = entry.wrapperClass;
77
+ for (const sig of entry.castSignatures) env.registerFunction(sig, (value) => new Ctor(value));
78
+ }
79
+ env.registerFunction("parseUnits(string, int): sol_int", (value, decimals) => parseUnitsValue(value, Number(toBigInt(decimals))));
80
+ env.registerFunction("parseUnits(int, int): sol_int", (value, decimals) => parseUnitsValue(value, Number(toBigInt(decimals))));
81
+ env.registerFunction("parseUnits(double, int): sol_int", (value, decimals) => parseUnitsValue(value, Number(toBigInt(decimals))));
82
+ env.registerFunction("parseUnits(sol_int, int): sol_int", (value, decimals) => parseUnitsValue(value, Number(toBigInt(decimals))));
83
+ env.registerFunction("formatUnits(sol_int, int): double", (value, decimals) => formatUnitsValue(value, Number(toBigInt(decimals))));
84
+ env.registerFunction("formatUnits(int, int): double", (value, decimals) => formatUnitsValue(value, Number(toBigInt(decimals))));
85
+ env.registerFunction("min(sol_int, sol_int): sol_int", (a, b) => toBigInt(a) <= toBigInt(b) ? toSolInt(a) : toSolInt(b));
86
+ env.registerFunction("min(sol_int, int): sol_int", (a, b) => toBigInt(a) <= toBigInt(b) ? toSolInt(a) : toSolInt(b));
87
+ env.registerFunction("min(int, sol_int): sol_int", (a, b) => toBigInt(a) <= toBigInt(b) ? toSolInt(a) : toSolInt(b));
88
+ env.registerFunction("min(int, int): sol_int", (a, b) => toBigInt(a) <= toBigInt(b) ? toSolInt(a) : toSolInt(b));
89
+ env.registerFunction("max(sol_int, sol_int): sol_int", (a, b) => toBigInt(a) >= toBigInt(b) ? toSolInt(a) : toSolInt(b));
90
+ env.registerFunction("max(sol_int, int): sol_int", (a, b) => toBigInt(a) >= toBigInt(b) ? toSolInt(a) : toSolInt(b));
91
+ env.registerFunction("max(int, sol_int): sol_int", (a, b) => toBigInt(a) >= toBigInt(b) ? toSolInt(a) : toSolInt(b));
92
+ env.registerFunction("max(int, int): sol_int", (a, b) => toBigInt(a) >= toBigInt(b) ? toSolInt(a) : toSolInt(b));
93
+ env.registerFunction("abs(sol_int): sol_int", (a) => {
94
+ const v = toBigInt(a);
95
+ return toSolInt(v < 0n ? -v : v);
96
+ });
97
+ env.registerFunction("abs(int): sol_int", (a) => {
98
+ const v = toBigInt(a);
99
+ return toSolInt(v < 0n ? -v : v);
100
+ });
101
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
102
+ env.registerFunction("isZeroAddress(sol_address): bool", (addr) => toAddress(addr) === ZERO_ADDRESS);
103
+ env.registerFunction("isZeroAddress(string): bool", (addr) => toAddress(addr) === ZERO_ADDRESS);
104
+ };
105
+ //#endregion
106
+ export { registerSolidityTypes };
@@ -0,0 +1,44 @@
1
+ require("../_virtual/_rolldown/runtime.cjs");
2
+ let _seljs_types = require("@seljs/types");
3
+ //#region src/environment/value-wrappers.ts
4
+ const wrapFieldValue = (registry, celType, value) => {
5
+ const nested = registry.get(celType);
6
+ if (nested) return wrapStructValue(registry, nested, value);
7
+ return wrapValueForSel(celType, value);
8
+ };
9
+ /**
10
+ * Maps a CEL type to the native CEL literal type for dual function registration.
11
+ */
12
+ const toCelLiteralType = (celType) => {
13
+ if (celType === "sol_int") return "int";
14
+ if (celType === "sol_address") return "string";
15
+ return null;
16
+ };
17
+ /**
18
+ * Wraps a raw value into the corresponding SEL wrapper type.
19
+ */
20
+ const wrapValueForSel = (celType, value) => {
21
+ if (value instanceof _seljs_types.SolidityAddressTypeWrapper) return value;
22
+ if (value instanceof _seljs_types.SolidityIntTypeWrapper) return value;
23
+ if (celType === "sol_address") return new _seljs_types.SolidityAddressTypeWrapper(value);
24
+ if (typeof value === "bigint") return new _seljs_types.SolidityIntTypeWrapper(value);
25
+ if (typeof value === "number" && Number.isInteger(value)) return new _seljs_types.SolidityIntTypeWrapper(BigInt(value));
26
+ return value;
27
+ };
28
+ /**
29
+ * Recursively wraps a raw struct value with the correct ctor and wrapped field values.
30
+ */
31
+ const wrapStructValue = (registry, info, value) => {
32
+ const { ctor, fieldNames, fieldTypes } = info;
33
+ let data;
34
+ if (Array.isArray(value)) data = Object.fromEntries(fieldNames.map((name, i) => [name, wrapFieldValue(registry, fieldTypes[name] ?? "dyn", value[i])]));
35
+ else {
36
+ const raw = value;
37
+ data = Object.fromEntries(Object.entries(raw).map(([name, val]) => [name, fieldTypes[name] ? wrapFieldValue(registry, fieldTypes[name], val) : val]));
38
+ }
39
+ return Object.assign(new ctor(), data);
40
+ };
41
+ //#endregion
42
+ exports.toCelLiteralType = toCelLiteralType;
43
+ exports.wrapStructValue = wrapStructValue;
44
+ exports.wrapValueForSel = wrapValueForSel;
@@ -0,0 +1,20 @@
1
+ //#region src/environment/value-wrappers.d.ts
2
+ interface StructInfo {
3
+ ctor: new () => object;
4
+ fieldNames: string[];
5
+ fieldTypes: Record<string, string>;
6
+ }
7
+ /**
8
+ * Maps a CEL type to the native CEL literal type for dual function registration.
9
+ */
10
+ declare const toCelLiteralType: (celType: string) => string | null;
11
+ /**
12
+ * Wraps a raw value into the corresponding SEL wrapper type.
13
+ */
14
+ declare const wrapValueForSel: (celType: string, value: unknown) => unknown;
15
+ /**
16
+ * Recursively wraps a raw struct value with the correct ctor and wrapped field values.
17
+ */
18
+ declare const wrapStructValue: (registry: Map<string, StructInfo>, info: StructInfo, value: unknown) => unknown;
19
+ //#endregion
20
+ export { StructInfo, toCelLiteralType, wrapStructValue, wrapValueForSel };
@@ -0,0 +1,20 @@
1
+ //#region src/environment/value-wrappers.d.ts
2
+ interface StructInfo {
3
+ ctor: new () => object;
4
+ fieldNames: string[];
5
+ fieldTypes: Record<string, string>;
6
+ }
7
+ /**
8
+ * Maps a CEL type to the native CEL literal type for dual function registration.
9
+ */
10
+ declare const toCelLiteralType: (celType: string) => string | null;
11
+ /**
12
+ * Wraps a raw value into the corresponding SEL wrapper type.
13
+ */
14
+ declare const wrapValueForSel: (celType: string, value: unknown) => unknown;
15
+ /**
16
+ * Recursively wraps a raw struct value with the correct ctor and wrapped field values.
17
+ */
18
+ declare const wrapStructValue: (registry: Map<string, StructInfo>, info: StructInfo, value: unknown) => unknown;
19
+ //#endregion
20
+ export { StructInfo, toCelLiteralType, wrapStructValue, wrapValueForSel };
@@ -0,0 +1,41 @@
1
+ import { SolidityAddressTypeWrapper, SolidityIntTypeWrapper } from "@seljs/types";
2
+ //#region src/environment/value-wrappers.ts
3
+ const wrapFieldValue = (registry, celType, value) => {
4
+ const nested = registry.get(celType);
5
+ if (nested) return wrapStructValue(registry, nested, value);
6
+ return wrapValueForSel(celType, value);
7
+ };
8
+ /**
9
+ * Maps a CEL type to the native CEL literal type for dual function registration.
10
+ */
11
+ const toCelLiteralType = (celType) => {
12
+ if (celType === "sol_int") return "int";
13
+ if (celType === "sol_address") return "string";
14
+ return null;
15
+ };
16
+ /**
17
+ * Wraps a raw value into the corresponding SEL wrapper type.
18
+ */
19
+ const wrapValueForSel = (celType, value) => {
20
+ if (value instanceof SolidityAddressTypeWrapper) return value;
21
+ if (value instanceof SolidityIntTypeWrapper) return value;
22
+ if (celType === "sol_address") return new SolidityAddressTypeWrapper(value);
23
+ if (typeof value === "bigint") return new SolidityIntTypeWrapper(value);
24
+ if (typeof value === "number" && Number.isInteger(value)) return new SolidityIntTypeWrapper(BigInt(value));
25
+ return value;
26
+ };
27
+ /**
28
+ * Recursively wraps a raw struct value with the correct ctor and wrapped field values.
29
+ */
30
+ const wrapStructValue = (registry, info, value) => {
31
+ const { ctor, fieldNames, fieldTypes } = info;
32
+ let data;
33
+ if (Array.isArray(value)) data = Object.fromEntries(fieldNames.map((name, i) => [name, wrapFieldValue(registry, fieldTypes[name] ?? "dyn", value[i])]));
34
+ else {
35
+ const raw = value;
36
+ data = Object.fromEntries(Object.entries(raw).map(([name, val]) => [name, fieldTypes[name] ? wrapFieldValue(registry, fieldTypes[name], val) : val]));
37
+ }
38
+ return Object.assign(new ctor(), data);
39
+ };
40
+ //#endregion
41
+ export { toCelLiteralType, wrapStructValue, wrapValueForSel };
package/dist/index.cjs ADDED
@@ -0,0 +1,27 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_type_compatibility = require("./checker/type-compatibility.cjs");
3
+ const require_codec_registry = require("./environment/codec-registry.cjs");
4
+ const require_register_types = require("./environment/register-types.cjs");
5
+ const require_value_wrappers = require("./environment/value-wrappers.cjs");
6
+ const require_hydrate = require("./environment/hydrate.cjs");
7
+ const require_constants = require("./constants.cjs");
8
+ const require_facade = require("./rules/facade.cjs");
9
+ const require_runner = require("./rules/runner.cjs");
10
+ require("./rules/index.cjs");
11
+ const require_checker = require("./checker/checker.cjs");
12
+ require("./checker/index.cjs");
13
+ require("./environment/index.cjs");
14
+ exports.COMPREHENSION_MACROS = require_constants.COMPREHENSION_MACROS;
15
+ exports.CelCodecRegistry = require_codec_registry.CelCodecRegistry;
16
+ exports.SCALAR_WRAPPER_FUNCTIONS = require_constants.SCALAR_WRAPPER_FUNCTIONS;
17
+ exports.SELChecker = require_checker.SELChecker;
18
+ exports.createBaseEnvironment = require_hydrate.createBaseEnvironment;
19
+ exports.createCheckerEnvironment = require_hydrate.createCheckerEnvironment;
20
+ exports.createRuntimeEnvironment = require_hydrate.createRuntimeEnvironment;
21
+ exports.isTypeCompatible = require_type_compatibility.isTypeCompatible;
22
+ exports.registerSolidityTypes = require_register_types.registerSolidityTypes;
23
+ exports.rules = require_facade.rules;
24
+ exports.runRules = require_runner.runRules;
25
+ exports.toCelLiteralType = require_value_wrappers.toCelLiteralType;
26
+ exports.wrapStructValue = require_value_wrappers.wrapStructValue;
27
+ exports.wrapValueForSel = require_value_wrappers.wrapValueForSel;
@@ -0,0 +1,11 @@
1
+ import { RuleContext, RuleSeverity, RuleTier, SELRule } from "./rules/types.cjs";
2
+ import { rules } from "./rules/facade.cjs";
3
+ import { RunRulesOptions, runRules } from "./rules/runner.cjs";
4
+ import { CompletionItem, SELChecker, SELCheckerOptions, SELDiagnostic } from "./checker/checker.cjs";
5
+ import { isTypeCompatible } from "./checker/type-compatibility.cjs";
6
+ import { COMPREHENSION_MACROS, SCALAR_WRAPPER_FUNCTIONS } from "./constants.cjs";
7
+ import { CelCodecRegistry, CelCodecRegistryOptions, StructCodecDescriptor } from "./environment/codec-registry.cjs";
8
+ import { CelLimits, ContractCallHandler, RuntimeEnvironmentResult, createBaseEnvironment, createCheckerEnvironment, createRuntimeEnvironment } from "./environment/hydrate.cjs";
9
+ import { registerSolidityTypes } from "./environment/register-types.cjs";
10
+ import { StructInfo, toCelLiteralType, wrapStructValue, wrapValueForSel } from "./environment/value-wrappers.cjs";
11
+ export { COMPREHENSION_MACROS, CelCodecRegistry, CelCodecRegistryOptions, CelLimits, CompletionItem, ContractCallHandler, RuleContext, RuleSeverity, RuleTier, RunRulesOptions, RuntimeEnvironmentResult, SCALAR_WRAPPER_FUNCTIONS, SELChecker, SELCheckerOptions, SELDiagnostic, SELRule, StructCodecDescriptor, StructInfo, createBaseEnvironment, createCheckerEnvironment, createRuntimeEnvironment, isTypeCompatible, registerSolidityTypes, rules, runRules, toCelLiteralType, wrapStructValue, wrapValueForSel };
@@ -0,0 +1,11 @@
1
+ import { RuleContext, RuleSeverity, RuleTier, SELRule } from "./rules/types.mjs";
2
+ import { rules } from "./rules/facade.mjs";
3
+ import { RunRulesOptions, runRules } from "./rules/runner.mjs";
4
+ import { CompletionItem, SELChecker, SELCheckerOptions, SELDiagnostic } from "./checker/checker.mjs";
5
+ import { isTypeCompatible } from "./checker/type-compatibility.mjs";
6
+ import { COMPREHENSION_MACROS, SCALAR_WRAPPER_FUNCTIONS } from "./constants.mjs";
7
+ import { CelCodecRegistry, CelCodecRegistryOptions, StructCodecDescriptor } from "./environment/codec-registry.mjs";
8
+ import { CelLimits, ContractCallHandler, RuntimeEnvironmentResult, createBaseEnvironment, createCheckerEnvironment, createRuntimeEnvironment } from "./environment/hydrate.mjs";
9
+ import { registerSolidityTypes } from "./environment/register-types.mjs";
10
+ import { StructInfo, toCelLiteralType, wrapStructValue, wrapValueForSel } from "./environment/value-wrappers.mjs";
11
+ export { COMPREHENSION_MACROS, CelCodecRegistry, CelCodecRegistryOptions, CelLimits, CompletionItem, ContractCallHandler, RuleContext, RuleSeverity, RuleTier, RunRulesOptions, RuntimeEnvironmentResult, SCALAR_WRAPPER_FUNCTIONS, SELChecker, SELCheckerOptions, SELDiagnostic, SELRule, StructCodecDescriptor, StructInfo, createBaseEnvironment, createCheckerEnvironment, createRuntimeEnvironment, isTypeCompatible, registerSolidityTypes, rules, runRules, toCelLiteralType, wrapStructValue, wrapValueForSel };
package/dist/index.mjs ADDED
@@ -0,0 +1,13 @@
1
+ import { isTypeCompatible } from "./checker/type-compatibility.mjs";
2
+ import { CelCodecRegistry } from "./environment/codec-registry.mjs";
3
+ import { registerSolidityTypes } from "./environment/register-types.mjs";
4
+ import { toCelLiteralType, wrapStructValue, wrapValueForSel } from "./environment/value-wrappers.mjs";
5
+ import { createBaseEnvironment, createCheckerEnvironment, createRuntimeEnvironment } from "./environment/hydrate.mjs";
6
+ import { COMPREHENSION_MACROS, SCALAR_WRAPPER_FUNCTIONS } from "./constants.mjs";
7
+ import { rules } from "./rules/facade.mjs";
8
+ import { runRules } from "./rules/runner.mjs";
9
+ import "./rules/index.mjs";
10
+ import { SELChecker } from "./checker/checker.mjs";
11
+ import "./checker/index.mjs";
12
+ import "./environment/index.mjs";
13
+ export { COMPREHENSION_MACROS, CelCodecRegistry, SCALAR_WRAPPER_FUNCTIONS, SELChecker, createBaseEnvironment, createCheckerEnvironment, createRuntimeEnvironment, isTypeCompatible, registerSolidityTypes, rules, runRules, toCelLiteralType, wrapStructValue, wrapValueForSel };
@@ -0,0 +1,107 @@
1
+ require("../../_virtual/_rolldown/runtime.cjs");
2
+ const require_constants = require("../../constants.cjs");
3
+ const require_ast_utils = require("../../utils/ast-utils.cjs");
4
+ let _seljs_common = require("@seljs/common");
5
+ //#region src/rules/defaults/deferred-call.ts
6
+ /**
7
+ * Checks whether a scalar wrapper inner value (inside solInt/solAddress) is resolvable.
8
+ */
9
+ const isScalarInnerResolvable = (inner, scopedVars) => {
10
+ if (!(0, _seljs_common.isAstNode)(inner)) return false;
11
+ if (inner.op === "value") return true;
12
+ return inner.op === "id" && typeof inner.args === "string" && !scopedVars.has(inner.args);
13
+ };
14
+ /**
15
+ * Checks whether a call node is a resolvable scalar wrapper (solInt/solAddress).
16
+ */
17
+ const isResolvableScalarWrapper = (node, scopedVars) => {
18
+ const nodeArgs = node.args;
19
+ const fnName = nodeArgs[0];
20
+ const fnArgs = nodeArgs[1];
21
+ if (typeof fnName !== "string" || !require_constants.SCALAR_WRAPPER_FUNCTIONS.has(fnName) || !Array.isArray(fnArgs) || fnArgs.length !== 1) return false;
22
+ return isScalarInnerResolvable(fnArgs[0], scopedVars);
23
+ };
24
+ /**
25
+ * Checks whether a single argument node is statically resolvable
26
+ * (literal, context variable, or nested contract call result).
27
+ */
28
+ const isResolvableArg = (argNode, contractNames, scopedVars) => {
29
+ if (!(0, _seljs_common.isAstNode)(argNode)) return false;
30
+ if (argNode.op === "call") return isResolvableScalarWrapper(argNode, scopedVars);
31
+ if (argNode.op === "value") return true;
32
+ if (argNode.op === "id" && typeof argNode.args === "string") return !scopedVars.has(argNode.args);
33
+ if (argNode.op === "rcall") return isContractRCall(argNode, contractNames);
34
+ return false;
35
+ };
36
+ /**
37
+ * Checks whether an rcall node targets a registered contract.
38
+ */
39
+ const isContractRCall = (node, contractNames) => {
40
+ const receiverNode = node.args[1];
41
+ return (0, _seljs_common.isAstNode)(receiverNode) && receiverNode.op === "id" && typeof receiverNode.args === "string" && contractNames.has(receiverNode.args);
42
+ };
43
+ /**
44
+ * Extracts the rcall components: method name, receiver node, and argument list.
45
+ */
46
+ const parseRCallNode = (node) => {
47
+ const nodeArgs = node.args;
48
+ const method = nodeArgs[0];
49
+ const receiver = nodeArgs[1];
50
+ const callArgs = nodeArgs[2];
51
+ if (typeof method !== "string" || !Array.isArray(callArgs)) return;
52
+ return {
53
+ method,
54
+ receiver,
55
+ callArgs
56
+ };
57
+ };
58
+ /**
59
+ * Tracks scoped variables introduced by comprehension macros or cel.bind().
60
+ */
61
+ const trackScopedVars = (parsed, scopedVars) => {
62
+ const { method, receiver, callArgs } = parsed;
63
+ if ((0, _seljs_common.isAstNode)(receiver) && receiver.op !== "id" && require_constants.COMPREHENSION_MACROS.has(method) && callArgs.length >= 1) {
64
+ const iterVarNode = callArgs[0];
65
+ if ((0, _seljs_common.isAstNode)(iterVarNode) && iterVarNode.op === "id" && typeof iterVarNode.args === "string") scopedVars.add(iterVarNode.args);
66
+ }
67
+ if (method === "bind" && (0, _seljs_common.isAstNode)(receiver) && receiver.op === "id" && receiver.args === "cel" && callArgs.length >= 1) {
68
+ const nameNode = callArgs[0];
69
+ if ((0, _seljs_common.isAstNode)(nameNode) && nameNode.op === "id" && typeof nameNode.args === "string") scopedVars.add(nameNode.args);
70
+ }
71
+ };
72
+ /**
73
+ * Flags contract calls whose arguments cannot be resolved statically,
74
+ * meaning they will execute as live RPC calls at evaluation time instead
75
+ * of being batched via multicall.
76
+ *
77
+ * This includes calls with arguments that depend on:
78
+ * - Comprehension iteration variables (map/filter/exists)
79
+ * - cel.bind() scoped variables
80
+ * - Arithmetic or other expressions on call results
81
+ * - Struct field access on call results
82
+ */
83
+ const deferredCall = {
84
+ name: "deferred-call",
85
+ description: "Flags contract calls with dynamic arguments that cannot be batched via multicall.",
86
+ defaultSeverity: "info",
87
+ tier: "structural",
88
+ run(context) {
89
+ const contractNames = new Set(context.schema.contracts.map((c) => c.name));
90
+ if (contractNames.size === 0) return [];
91
+ const diagnostics = [];
92
+ const scopedVars = /* @__PURE__ */ new Set();
93
+ require_ast_utils.walkAST(context.ast, (node) => {
94
+ if (node.op !== "rcall") return;
95
+ const parsed = parseRCallNode(node);
96
+ if (!parsed) return;
97
+ const { method, callArgs } = parsed;
98
+ trackScopedVars(parsed, scopedVars);
99
+ if (!isContractRCall(node, contractNames)) return;
100
+ const contractName = node.args[1].args;
101
+ if (callArgs.some((argNode) => !isResolvableArg(argNode, contractNames, scopedVars))) diagnostics.push(context.report(node, `\`${contractName}.${method}()\` has dynamic arguments and will execute as a live RPC call instead of being batched.`));
102
+ });
103
+ return diagnostics;
104
+ }
105
+ };
106
+ //#endregion
107
+ exports.deferredCall = deferredCall;
@@ -0,0 +1,106 @@
1
+ import { COMPREHENSION_MACROS, SCALAR_WRAPPER_FUNCTIONS } from "../../constants.mjs";
2
+ import { walkAST } from "../../utils/ast-utils.mjs";
3
+ import { isAstNode } from "@seljs/common";
4
+ //#region src/rules/defaults/deferred-call.ts
5
+ /**
6
+ * Checks whether a scalar wrapper inner value (inside solInt/solAddress) is resolvable.
7
+ */
8
+ const isScalarInnerResolvable = (inner, scopedVars) => {
9
+ if (!isAstNode(inner)) return false;
10
+ if (inner.op === "value") return true;
11
+ return inner.op === "id" && typeof inner.args === "string" && !scopedVars.has(inner.args);
12
+ };
13
+ /**
14
+ * Checks whether a call node is a resolvable scalar wrapper (solInt/solAddress).
15
+ */
16
+ const isResolvableScalarWrapper = (node, scopedVars) => {
17
+ const nodeArgs = node.args;
18
+ const fnName = nodeArgs[0];
19
+ const fnArgs = nodeArgs[1];
20
+ if (typeof fnName !== "string" || !SCALAR_WRAPPER_FUNCTIONS.has(fnName) || !Array.isArray(fnArgs) || fnArgs.length !== 1) return false;
21
+ return isScalarInnerResolvable(fnArgs[0], scopedVars);
22
+ };
23
+ /**
24
+ * Checks whether a single argument node is statically resolvable
25
+ * (literal, context variable, or nested contract call result).
26
+ */
27
+ const isResolvableArg = (argNode, contractNames, scopedVars) => {
28
+ if (!isAstNode(argNode)) return false;
29
+ if (argNode.op === "call") return isResolvableScalarWrapper(argNode, scopedVars);
30
+ if (argNode.op === "value") return true;
31
+ if (argNode.op === "id" && typeof argNode.args === "string") return !scopedVars.has(argNode.args);
32
+ if (argNode.op === "rcall") return isContractRCall(argNode, contractNames);
33
+ return false;
34
+ };
35
+ /**
36
+ * Checks whether an rcall node targets a registered contract.
37
+ */
38
+ const isContractRCall = (node, contractNames) => {
39
+ const receiverNode = node.args[1];
40
+ return isAstNode(receiverNode) && receiverNode.op === "id" && typeof receiverNode.args === "string" && contractNames.has(receiverNode.args);
41
+ };
42
+ /**
43
+ * Extracts the rcall components: method name, receiver node, and argument list.
44
+ */
45
+ const parseRCallNode = (node) => {
46
+ const nodeArgs = node.args;
47
+ const method = nodeArgs[0];
48
+ const receiver = nodeArgs[1];
49
+ const callArgs = nodeArgs[2];
50
+ if (typeof method !== "string" || !Array.isArray(callArgs)) return;
51
+ return {
52
+ method,
53
+ receiver,
54
+ callArgs
55
+ };
56
+ };
57
+ /**
58
+ * Tracks scoped variables introduced by comprehension macros or cel.bind().
59
+ */
60
+ const trackScopedVars = (parsed, scopedVars) => {
61
+ const { method, receiver, callArgs } = parsed;
62
+ if (isAstNode(receiver) && receiver.op !== "id" && COMPREHENSION_MACROS.has(method) && callArgs.length >= 1) {
63
+ const iterVarNode = callArgs[0];
64
+ if (isAstNode(iterVarNode) && iterVarNode.op === "id" && typeof iterVarNode.args === "string") scopedVars.add(iterVarNode.args);
65
+ }
66
+ if (method === "bind" && isAstNode(receiver) && receiver.op === "id" && receiver.args === "cel" && callArgs.length >= 1) {
67
+ const nameNode = callArgs[0];
68
+ if (isAstNode(nameNode) && nameNode.op === "id" && typeof nameNode.args === "string") scopedVars.add(nameNode.args);
69
+ }
70
+ };
71
+ /**
72
+ * Flags contract calls whose arguments cannot be resolved statically,
73
+ * meaning they will execute as live RPC calls at evaluation time instead
74
+ * of being batched via multicall.
75
+ *
76
+ * This includes calls with arguments that depend on:
77
+ * - Comprehension iteration variables (map/filter/exists)
78
+ * - cel.bind() scoped variables
79
+ * - Arithmetic or other expressions on call results
80
+ * - Struct field access on call results
81
+ */
82
+ const deferredCall = {
83
+ name: "deferred-call",
84
+ description: "Flags contract calls with dynamic arguments that cannot be batched via multicall.",
85
+ defaultSeverity: "info",
86
+ tier: "structural",
87
+ run(context) {
88
+ const contractNames = new Set(context.schema.contracts.map((c) => c.name));
89
+ if (contractNames.size === 0) return [];
90
+ const diagnostics = [];
91
+ const scopedVars = /* @__PURE__ */ new Set();
92
+ walkAST(context.ast, (node) => {
93
+ if (node.op !== "rcall") return;
94
+ const parsed = parseRCallNode(node);
95
+ if (!parsed) return;
96
+ const { method, callArgs } = parsed;
97
+ trackScopedVars(parsed, scopedVars);
98
+ if (!isContractRCall(node, contractNames)) return;
99
+ const contractName = node.args[1].args;
100
+ if (callArgs.some((argNode) => !isResolvableArg(argNode, contractNames, scopedVars))) diagnostics.push(context.report(node, `\`${contractName}.${method}()\` has dynamic arguments and will execute as a live RPC call instead of being batched.`));
101
+ });
102
+ return diagnostics;
103
+ }
104
+ };
105
+ //#endregion
106
+ export { deferredCall };
@@ -0,0 +1,6 @@
1
+ require("./deferred-call.cjs");
2
+ require("./no-constant-condition.cjs");
3
+ require("./no-mixed-operators.cjs");
4
+ require("./no-redundant-bool.cjs");
5
+ require("./no-self-comparison.cjs");
6
+ require("./require-type.cjs");
@@ -0,0 +1,7 @@
1
+ import "./deferred-call.mjs";
2
+ import "./no-constant-condition.mjs";
3
+ import "./no-mixed-operators.mjs";
4
+ import "./no-redundant-bool.mjs";
5
+ import "./no-self-comparison.mjs";
6
+ import "./require-type.mjs";
7
+ export {};
@@ -0,0 +1,31 @@
1
+ const require_ast_utils = require("../../utils/ast-utils.cjs");
2
+ //#region src/rules/defaults/no-constant-condition.ts
3
+ /**
4
+ * Flags conditions that are always true or always false:
5
+ * - `true && x`, `false || x` (boolean literal in logical operator)
6
+ * - Both sides are literal values in a comparison
7
+ */
8
+ const noConstantCondition = {
9
+ name: "no-constant-condition",
10
+ description: "Disallow constant conditions in logical and comparison operators.",
11
+ defaultSeverity: "warning",
12
+ tier: "structural",
13
+ run(context) {
14
+ const diagnostics = [];
15
+ require_ast_utils.walkAST(context.ast, (node) => {
16
+ if (node.op === "&&" || node.op === "||") {
17
+ const [left, right] = node.args;
18
+ if (left.op === "value" && typeof left.args === "boolean") diagnostics.push(context.report(node, `Constant condition: left side of \`${node.op}\` is always \`${String(left.args)}\`.`));
19
+ if (right.op === "value" && typeof right.args === "boolean") diagnostics.push(context.report(node, `Constant condition: right side of \`${node.op}\` is always \`${String(right.args)}\`.`));
20
+ return;
21
+ }
22
+ if (node.op === "==" || node.op === "!=") {
23
+ const [left, right] = node.args;
24
+ if (left.op === "value" && right.op === "value") diagnostics.push(context.report(node, `Constant condition: both sides of \`${node.op}\` are literal values.`));
25
+ }
26
+ });
27
+ return diagnostics;
28
+ }
29
+ };
30
+ //#endregion
31
+ exports.noConstantCondition = noConstantCondition;
@@ -0,0 +1,31 @@
1
+ import { walkAST } from "../../utils/ast-utils.mjs";
2
+ //#region src/rules/defaults/no-constant-condition.ts
3
+ /**
4
+ * Flags conditions that are always true or always false:
5
+ * - `true && x`, `false || x` (boolean literal in logical operator)
6
+ * - Both sides are literal values in a comparison
7
+ */
8
+ const noConstantCondition = {
9
+ name: "no-constant-condition",
10
+ description: "Disallow constant conditions in logical and comparison operators.",
11
+ defaultSeverity: "warning",
12
+ tier: "structural",
13
+ run(context) {
14
+ const diagnostics = [];
15
+ walkAST(context.ast, (node) => {
16
+ if (node.op === "&&" || node.op === "||") {
17
+ const [left, right] = node.args;
18
+ if (left.op === "value" && typeof left.args === "boolean") diagnostics.push(context.report(node, `Constant condition: left side of \`${node.op}\` is always \`${String(left.args)}\`.`));
19
+ if (right.op === "value" && typeof right.args === "boolean") diagnostics.push(context.report(node, `Constant condition: right side of \`${node.op}\` is always \`${String(right.args)}\`.`));
20
+ return;
21
+ }
22
+ if (node.op === "==" || node.op === "!=") {
23
+ const [left, right] = node.args;
24
+ if (left.op === "value" && right.op === "value") diagnostics.push(context.report(node, `Constant condition: both sides of \`${node.op}\` are literal values.`));
25
+ }
26
+ });
27
+ return diagnostics;
28
+ }
29
+ };
30
+ //#endregion
31
+ export { noConstantCondition };
@@ -0,0 +1,39 @@
1
+ const require_ast_utils = require("../../utils/ast-utils.cjs");
2
+ //#region src/rules/defaults/no-mixed-operators.ts
3
+ /**
4
+ * Check whether a child expression has explicit parentheses in the source.
5
+ * Scans backwards from the child's start position for a `(`.
6
+ */
7
+ const hasExplicitParens = (src, child) => {
8
+ let i = require_ast_utils.nodeSpan(child).from - 1;
9
+ while (i >= 0 && (src[i] === " " || src[i] === " ")) i--;
10
+ return i >= 0 && src[i] === "(";
11
+ };
12
+ /**
13
+ * Flags mixed `&&` and `||` without explicit parentheses.
14
+ *
15
+ * The cel-js parser discards parentheses from the AST, so this rule
16
+ * inspects the original source text via `node.input` to determine
17
+ * whether parentheses were explicitly written.
18
+ */
19
+ const noMixedOperators = {
20
+ name: "no-mixed-operators",
21
+ description: "Require parentheses when mixing logical operators (&& and ||).",
22
+ defaultSeverity: "info",
23
+ tier: "structural",
24
+ run(context) {
25
+ const diagnostics = [];
26
+ require_ast_utils.walkAST(context.ast, (node) => {
27
+ if (node.op !== "&&" && node.op !== "||") return;
28
+ const opposite = node.op === "&&" ? "||" : "&&";
29
+ const [left, right] = node.args;
30
+ for (const child of [left, right]) if (child.op === opposite && !hasExplicitParens(node.input, child)) {
31
+ diagnostics.push(context.report(node, "Mixed logical operators without parentheses. Add explicit grouping to clarify precedence."));
32
+ break;
33
+ }
34
+ });
35
+ return diagnostics;
36
+ }
37
+ };
38
+ //#endregion
39
+ exports.noMixedOperators = noMixedOperators;