@seljs/checker 1.0.0 → 1.0.1-beta.9
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.
- package/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/checker/checker.cjs +482 -0
- package/dist/checker/checker.d.cts +176 -0
- package/dist/checker/checker.d.mts +176 -0
- package/dist/checker/checker.mjs +481 -0
- package/dist/checker/diagnostics.cjs +66 -0
- package/dist/checker/diagnostics.mjs +66 -0
- package/dist/checker/index.cjs +2 -0
- package/dist/checker/index.d.mts +2 -0
- package/dist/checker/index.mjs +3 -0
- package/dist/checker/type-compatibility.cjs +70 -0
- package/dist/checker/type-compatibility.d.cts +8 -0
- package/dist/checker/type-compatibility.d.mts +8 -0
- package/dist/checker/type-compatibility.mjs +69 -0
- package/dist/constants.cjs +14 -0
- package/dist/constants.d.cts +7 -0
- package/dist/constants.d.mts +7 -0
- package/dist/constants.mjs +13 -0
- package/dist/debug.cjs +7 -0
- package/dist/debug.mjs +5 -0
- package/dist/environment/codec-registry.cjs +109 -0
- package/dist/environment/codec-registry.d.cts +45 -0
- package/dist/environment/codec-registry.d.mts +45 -0
- package/dist/environment/codec-registry.mjs +108 -0
- package/dist/environment/hydrate.cjs +163 -0
- package/dist/environment/hydrate.d.cts +52 -0
- package/dist/environment/hydrate.d.mts +52 -0
- package/dist/environment/hydrate.mjs +160 -0
- package/dist/environment/index.cjs +4 -0
- package/dist/environment/index.d.mts +4 -0
- package/dist/environment/index.mjs +5 -0
- package/dist/environment/register-types.cjs +107 -0
- package/dist/environment/register-types.d.cts +15 -0
- package/dist/environment/register-types.d.mts +15 -0
- package/dist/environment/register-types.mjs +106 -0
- package/dist/environment/value-wrappers.cjs +44 -0
- package/dist/environment/value-wrappers.d.cts +20 -0
- package/dist/environment/value-wrappers.d.mts +20 -0
- package/dist/environment/value-wrappers.mjs +41 -0
- package/dist/index.cjs +27 -0
- package/dist/index.d.cts +11 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.mjs +13 -0
- package/dist/rules/defaults/deferred-call.cjs +107 -0
- package/dist/rules/defaults/deferred-call.mjs +106 -0
- package/dist/rules/defaults/index.cjs +6 -0
- package/dist/rules/defaults/index.mjs +7 -0
- package/dist/rules/defaults/no-constant-condition.cjs +31 -0
- package/dist/rules/defaults/no-constant-condition.mjs +31 -0
- package/dist/rules/defaults/no-mixed-operators.cjs +39 -0
- package/dist/rules/defaults/no-mixed-operators.mjs +39 -0
- package/dist/rules/defaults/no-redundant-bool.cjs +26 -0
- package/dist/rules/defaults/no-redundant-bool.mjs +26 -0
- package/dist/rules/defaults/no-self-comparison.cjs +44 -0
- package/dist/rules/defaults/no-self-comparison.mjs +43 -0
- package/dist/rules/defaults/require-type.cjs +18 -0
- package/dist/rules/defaults/require-type.mjs +18 -0
- package/dist/rules/facade.cjs +31 -0
- package/dist/rules/facade.d.cts +20 -0
- package/dist/rules/facade.d.mts +20 -0
- package/dist/rules/facade.mjs +31 -0
- package/dist/rules/index.cjs +2 -0
- package/dist/rules/index.d.mts +3 -0
- package/dist/rules/index.mjs +3 -0
- package/dist/rules/runner.cjs +40 -0
- package/dist/rules/runner.d.cts +27 -0
- package/dist/rules/runner.d.mts +27 -0
- package/dist/rules/runner.mjs +40 -0
- package/dist/rules/types.d.cts +77 -0
- package/dist/rules/types.d.mts +77 -0
- package/dist/utils/ast-utils.cjs +164 -0
- package/dist/utils/ast-utils.mjs +162 -0
- package/package.json +23 -16
- package/dist/checker/checker.d.ts +0 -173
- package/dist/checker/checker.js +0 -567
- package/dist/checker/diagnostics.d.ts +0 -10
- package/dist/checker/diagnostics.js +0 -80
- package/dist/checker/index.d.ts +0 -2
- package/dist/checker/index.js +0 -2
- package/dist/checker/type-compatibility.d.ts +0 -16
- package/dist/checker/type-compatibility.js +0 -59
- package/dist/constants.d.ts +0 -4
- package/dist/constants.js +0 -10
- package/dist/debug.d.ts +0 -2
- package/dist/debug.js +0 -2
- package/dist/environment/codec-registry.d.ts +0 -42
- package/dist/environment/codec-registry.js +0 -146
- package/dist/environment/hydrate.d.ts +0 -48
- package/dist/environment/hydrate.js +0 -198
- package/dist/environment/index.d.ts +0 -4
- package/dist/environment/index.js +0 -4
- package/dist/environment/register-types.d.ts +0 -14
- package/dist/environment/register-types.js +0 -154
- package/dist/environment/value-wrappers.d.ts +0 -17
- package/dist/environment/value-wrappers.js +0 -65
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -4
- package/dist/rules/defaults/deferred-call.d.ts +0 -13
- package/dist/rules/defaults/deferred-call.js +0 -162
- package/dist/rules/defaults/index.d.ts +0 -6
- package/dist/rules/defaults/index.js +0 -6
- package/dist/rules/defaults/no-constant-condition.d.ts +0 -7
- package/dist/rules/defaults/no-constant-condition.js +0 -36
- package/dist/rules/defaults/no-mixed-operators.d.ts +0 -9
- package/dist/rules/defaults/no-mixed-operators.js +0 -44
- package/dist/rules/defaults/no-redundant-bool.d.ts +0 -5
- package/dist/rules/defaults/no-redundant-bool.js +0 -27
- package/dist/rules/defaults/no-self-comparison.d.ts +0 -9
- package/dist/rules/defaults/no-self-comparison.js +0 -31
- package/dist/rules/defaults/require-type.d.ts +0 -7
- package/dist/rules/defaults/require-type.js +0 -19
- package/dist/rules/facade.d.ts +0 -22
- package/dist/rules/facade.js +0 -29
- package/dist/rules/index.d.ts +0 -3
- package/dist/rules/index.js +0 -3
- package/dist/rules/runner.d.ts +0 -16
- package/dist/rules/runner.js +0 -30
- package/dist/rules/types.d.ts +0 -73
- package/dist/rules/types.js +0 -1
- package/dist/utils/ast-utils.d.ts +0 -55
- package/dist/utils/ast-utils.js +0 -255
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/checker/diagnostics.ts
|
|
2
|
+
/**
|
|
3
|
+
* Extract position information from a cel-js error message.
|
|
4
|
+
*
|
|
5
|
+
* cel-js error messages embed a caret (`^`) on a separate line indicating
|
|
6
|
+
* the error column. The format is:
|
|
7
|
+
* ```
|
|
8
|
+
* Error description
|
|
9
|
+
*
|
|
10
|
+
* > 1 | expression text
|
|
11
|
+
* ^
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* We parse the caret offset relative to the code line prefix (`> N | `)
|
|
15
|
+
* to derive the zero-based character offset within the expression.
|
|
16
|
+
*/
|
|
17
|
+
const extractPositionFromMessage = (message) => {
|
|
18
|
+
const lines = message.split("\n");
|
|
19
|
+
const caretLine = lines.find((line) => /^\s*\^+\s*$/.test(line));
|
|
20
|
+
if (!caretLine) return;
|
|
21
|
+
const codeLine = lines.find((line) => line.startsWith(">"));
|
|
22
|
+
if (!codeLine) return;
|
|
23
|
+
const pipeIndex = codeLine.indexOf("|");
|
|
24
|
+
if (pipeIndex === -1) return;
|
|
25
|
+
const prefixLength = pipeIndex + 2;
|
|
26
|
+
const caretStart = caretLine.indexOf("^");
|
|
27
|
+
const caretEnd = caretLine.lastIndexOf("^");
|
|
28
|
+
const from = caretStart - prefixLength;
|
|
29
|
+
const to = caretEnd - prefixLength + 1;
|
|
30
|
+
if (from < 0) return;
|
|
31
|
+
return {
|
|
32
|
+
from,
|
|
33
|
+
to
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Extract the plain error message without the caret/code-line decoration.
|
|
38
|
+
*/
|
|
39
|
+
const extractPlainMessage = (message) => {
|
|
40
|
+
return message.split("\n").filter((line) => !line.startsWith(">") && !/^\s*\^+\s*$/.test(line) && line.trim().length > 0).join(" ").trim() || message;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Convert a cel-js error into position-aware SEL diagnostics.
|
|
44
|
+
*
|
|
45
|
+
* The error's `name` property distinguishes parse errors (`"ParseError"`)
|
|
46
|
+
* from type errors (`"TypeError"`). Position information is extracted from
|
|
47
|
+
* the caret annotation embedded in the error message; when absent the
|
|
48
|
+
* diagnostic spans the entire expression.
|
|
49
|
+
*/
|
|
50
|
+
const extractDiagnostics = (expression, error) => {
|
|
51
|
+
if (!(error instanceof Error)) return [{
|
|
52
|
+
message: String(error),
|
|
53
|
+
severity: "error",
|
|
54
|
+
from: 0,
|
|
55
|
+
to: expression.length
|
|
56
|
+
}];
|
|
57
|
+
const position = extractPositionFromMessage(error.message);
|
|
58
|
+
return [{
|
|
59
|
+
message: extractPlainMessage(error.message),
|
|
60
|
+
severity: "error",
|
|
61
|
+
from: position?.from ?? 0,
|
|
62
|
+
to: position?.to ?? expression.length
|
|
63
|
+
}];
|
|
64
|
+
};
|
|
65
|
+
//#endregion
|
|
66
|
+
exports.extractDiagnostics = extractDiagnostics;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/checker/diagnostics.ts
|
|
2
|
+
/**
|
|
3
|
+
* Extract position information from a cel-js error message.
|
|
4
|
+
*
|
|
5
|
+
* cel-js error messages embed a caret (`^`) on a separate line indicating
|
|
6
|
+
* the error column. The format is:
|
|
7
|
+
* ```
|
|
8
|
+
* Error description
|
|
9
|
+
*
|
|
10
|
+
* > 1 | expression text
|
|
11
|
+
* ^
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* We parse the caret offset relative to the code line prefix (`> N | `)
|
|
15
|
+
* to derive the zero-based character offset within the expression.
|
|
16
|
+
*/
|
|
17
|
+
const extractPositionFromMessage = (message) => {
|
|
18
|
+
const lines = message.split("\n");
|
|
19
|
+
const caretLine = lines.find((line) => /^\s*\^+\s*$/.test(line));
|
|
20
|
+
if (!caretLine) return;
|
|
21
|
+
const codeLine = lines.find((line) => line.startsWith(">"));
|
|
22
|
+
if (!codeLine) return;
|
|
23
|
+
const pipeIndex = codeLine.indexOf("|");
|
|
24
|
+
if (pipeIndex === -1) return;
|
|
25
|
+
const prefixLength = pipeIndex + 2;
|
|
26
|
+
const caretStart = caretLine.indexOf("^");
|
|
27
|
+
const caretEnd = caretLine.lastIndexOf("^");
|
|
28
|
+
const from = caretStart - prefixLength;
|
|
29
|
+
const to = caretEnd - prefixLength + 1;
|
|
30
|
+
if (from < 0) return;
|
|
31
|
+
return {
|
|
32
|
+
from,
|
|
33
|
+
to
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Extract the plain error message without the caret/code-line decoration.
|
|
38
|
+
*/
|
|
39
|
+
const extractPlainMessage = (message) => {
|
|
40
|
+
return message.split("\n").filter((line) => !line.startsWith(">") && !/^\s*\^+\s*$/.test(line) && line.trim().length > 0).join(" ").trim() || message;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Convert a cel-js error into position-aware SEL diagnostics.
|
|
44
|
+
*
|
|
45
|
+
* The error's `name` property distinguishes parse errors (`"ParseError"`)
|
|
46
|
+
* from type errors (`"TypeError"`). Position information is extracted from
|
|
47
|
+
* the caret annotation embedded in the error message; when absent the
|
|
48
|
+
* diagnostic spans the entire expression.
|
|
49
|
+
*/
|
|
50
|
+
const extractDiagnostics = (expression, error) => {
|
|
51
|
+
if (!(error instanceof Error)) return [{
|
|
52
|
+
message: String(error),
|
|
53
|
+
severity: "error",
|
|
54
|
+
from: 0,
|
|
55
|
+
to: expression.length
|
|
56
|
+
}];
|
|
57
|
+
const position = extractPositionFromMessage(error.message);
|
|
58
|
+
return [{
|
|
59
|
+
message: extractPlainMessage(error.message),
|
|
60
|
+
severity: "error",
|
|
61
|
+
from: position?.from ?? 0,
|
|
62
|
+
to: position?.to ?? expression.length
|
|
63
|
+
}];
|
|
64
|
+
};
|
|
65
|
+
//#endregion
|
|
66
|
+
export { extractDiagnostics };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//#region src/checker/type-compatibility.ts
|
|
2
|
+
const LOGICAL_OPERATORS = new Set(["&&", "||"]);
|
|
3
|
+
const ARITHMETIC_OPERATORS = new Set([
|
|
4
|
+
"+",
|
|
5
|
+
"-",
|
|
6
|
+
"*",
|
|
7
|
+
"/",
|
|
8
|
+
"%"
|
|
9
|
+
]);
|
|
10
|
+
const COMPARISON_OPERATORS = new Set([
|
|
11
|
+
"<",
|
|
12
|
+
"<=",
|
|
13
|
+
">",
|
|
14
|
+
">="
|
|
15
|
+
]);
|
|
16
|
+
const EQUALITY_OPERATORS = new Set(["==", "!="]);
|
|
17
|
+
/** Types that support arithmetic operators (same-type only). */
|
|
18
|
+
const ARITHMETIC_TYPES = new Set([
|
|
19
|
+
"int",
|
|
20
|
+
"uint",
|
|
21
|
+
"double",
|
|
22
|
+
"sol_int"
|
|
23
|
+
]);
|
|
24
|
+
/** Types that support the + operator for concatenation. */
|
|
25
|
+
const CONCATENATION_TYPES = new Set([
|
|
26
|
+
"string",
|
|
27
|
+
"list",
|
|
28
|
+
"bytes"
|
|
29
|
+
]);
|
|
30
|
+
/** Types that support comparison operators (same-type only). */
|
|
31
|
+
const COMPARISON_TYPES = new Set([
|
|
32
|
+
"int",
|
|
33
|
+
"uint",
|
|
34
|
+
"double",
|
|
35
|
+
"string",
|
|
36
|
+
"bytes",
|
|
37
|
+
"sol_address",
|
|
38
|
+
"sol_int"
|
|
39
|
+
]);
|
|
40
|
+
/**
|
|
41
|
+
* Given the type of the left operand and the operator,
|
|
42
|
+
* returns the expected type for the right operand.
|
|
43
|
+
*
|
|
44
|
+
* Based on the registered operators in register-types.ts.
|
|
45
|
+
* Type compatibility is strictly same-type (no implicit coercion).
|
|
46
|
+
*
|
|
47
|
+
* Returns undefined when the type/operator combination is unknown,
|
|
48
|
+
* signaling that no narrowing should occur.
|
|
49
|
+
*/
|
|
50
|
+
const expectedTypeForOperator = (leftType, operator) => {
|
|
51
|
+
if (LOGICAL_OPERATORS.has(operator)) return "bool";
|
|
52
|
+
if (ARITHMETIC_OPERATORS.has(operator)) {
|
|
53
|
+
if (ARITHMETIC_TYPES.has(leftType)) return leftType;
|
|
54
|
+
if (operator === "+" && CONCATENATION_TYPES.has(leftType)) return leftType;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (COMPARISON_OPERATORS.has(operator)) return COMPARISON_TYPES.has(leftType) ? leftType : void 0;
|
|
58
|
+
if (EQUALITY_OPERATORS.has(operator)) return leftType;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Check if a candidate type is compatible with an expected type.
|
|
62
|
+
* "dyn" is a wildcard — compatible with anything in either direction.
|
|
63
|
+
*/
|
|
64
|
+
const isTypeCompatible = (candidateType, expectedType) => {
|
|
65
|
+
if (expectedType === "dyn" || candidateType === "dyn") return true;
|
|
66
|
+
return candidateType === expectedType;
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
exports.expectedTypeForOperator = expectedTypeForOperator;
|
|
70
|
+
exports.isTypeCompatible = isTypeCompatible;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/checker/type-compatibility.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Check if a candidate type is compatible with an expected type.
|
|
4
|
+
* "dyn" is a wildcard — compatible with anything in either direction.
|
|
5
|
+
*/
|
|
6
|
+
declare const isTypeCompatible: (candidateType: string, expectedType: string) => boolean;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { isTypeCompatible };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/checker/type-compatibility.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Check if a candidate type is compatible with an expected type.
|
|
4
|
+
* "dyn" is a wildcard — compatible with anything in either direction.
|
|
5
|
+
*/
|
|
6
|
+
declare const isTypeCompatible: (candidateType: string, expectedType: string) => boolean;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { isTypeCompatible };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//#region src/checker/type-compatibility.ts
|
|
2
|
+
const LOGICAL_OPERATORS = new Set(["&&", "||"]);
|
|
3
|
+
const ARITHMETIC_OPERATORS = new Set([
|
|
4
|
+
"+",
|
|
5
|
+
"-",
|
|
6
|
+
"*",
|
|
7
|
+
"/",
|
|
8
|
+
"%"
|
|
9
|
+
]);
|
|
10
|
+
const COMPARISON_OPERATORS = new Set([
|
|
11
|
+
"<",
|
|
12
|
+
"<=",
|
|
13
|
+
">",
|
|
14
|
+
">="
|
|
15
|
+
]);
|
|
16
|
+
const EQUALITY_OPERATORS = new Set(["==", "!="]);
|
|
17
|
+
/** Types that support arithmetic operators (same-type only). */
|
|
18
|
+
const ARITHMETIC_TYPES = new Set([
|
|
19
|
+
"int",
|
|
20
|
+
"uint",
|
|
21
|
+
"double",
|
|
22
|
+
"sol_int"
|
|
23
|
+
]);
|
|
24
|
+
/** Types that support the + operator for concatenation. */
|
|
25
|
+
const CONCATENATION_TYPES = new Set([
|
|
26
|
+
"string",
|
|
27
|
+
"list",
|
|
28
|
+
"bytes"
|
|
29
|
+
]);
|
|
30
|
+
/** Types that support comparison operators (same-type only). */
|
|
31
|
+
const COMPARISON_TYPES = new Set([
|
|
32
|
+
"int",
|
|
33
|
+
"uint",
|
|
34
|
+
"double",
|
|
35
|
+
"string",
|
|
36
|
+
"bytes",
|
|
37
|
+
"sol_address",
|
|
38
|
+
"sol_int"
|
|
39
|
+
]);
|
|
40
|
+
/**
|
|
41
|
+
* Given the type of the left operand and the operator,
|
|
42
|
+
* returns the expected type for the right operand.
|
|
43
|
+
*
|
|
44
|
+
* Based on the registered operators in register-types.ts.
|
|
45
|
+
* Type compatibility is strictly same-type (no implicit coercion).
|
|
46
|
+
*
|
|
47
|
+
* Returns undefined when the type/operator combination is unknown,
|
|
48
|
+
* signaling that no narrowing should occur.
|
|
49
|
+
*/
|
|
50
|
+
const expectedTypeForOperator = (leftType, operator) => {
|
|
51
|
+
if (LOGICAL_OPERATORS.has(operator)) return "bool";
|
|
52
|
+
if (ARITHMETIC_OPERATORS.has(operator)) {
|
|
53
|
+
if (ARITHMETIC_TYPES.has(leftType)) return leftType;
|
|
54
|
+
if (operator === "+" && CONCATENATION_TYPES.has(leftType)) return leftType;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (COMPARISON_OPERATORS.has(operator)) return COMPARISON_TYPES.has(leftType) ? leftType : void 0;
|
|
58
|
+
if (EQUALITY_OPERATORS.has(operator)) return leftType;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Check if a candidate type is compatible with an expected type.
|
|
62
|
+
* "dyn" is a wildcard — compatible with anything in either direction.
|
|
63
|
+
*/
|
|
64
|
+
const isTypeCompatible = (candidateType, expectedType) => {
|
|
65
|
+
if (expectedType === "dyn" || candidateType === "dyn") return true;
|
|
66
|
+
return candidateType === expectedType;
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { expectedTypeForOperator, isTypeCompatible };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/constants.ts
|
|
2
|
+
/** Comprehension macro names that introduce scoped iteration variables. */
|
|
3
|
+
const COMPREHENSION_MACROS = new Set([
|
|
4
|
+
"map",
|
|
5
|
+
"filter",
|
|
6
|
+
"exists",
|
|
7
|
+
"all",
|
|
8
|
+
"exists_one"
|
|
9
|
+
]);
|
|
10
|
+
/** Solidity scalar wrapper functions (pass-through for arg classification). */
|
|
11
|
+
const SCALAR_WRAPPER_FUNCTIONS = new Set(["solInt", "solAddress"]);
|
|
12
|
+
//#endregion
|
|
13
|
+
exports.COMPREHENSION_MACROS = COMPREHENSION_MACROS;
|
|
14
|
+
exports.SCALAR_WRAPPER_FUNCTIONS = SCALAR_WRAPPER_FUNCTIONS;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/constants.d.ts
|
|
2
|
+
/** Comprehension macro names that introduce scoped iteration variables. */
|
|
3
|
+
declare const COMPREHENSION_MACROS: Set<string>;
|
|
4
|
+
/** Solidity scalar wrapper functions (pass-through for arg classification). */
|
|
5
|
+
declare const SCALAR_WRAPPER_FUNCTIONS: Set<string>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { COMPREHENSION_MACROS, SCALAR_WRAPPER_FUNCTIONS };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/constants.d.ts
|
|
2
|
+
/** Comprehension macro names that introduce scoped iteration variables. */
|
|
3
|
+
declare const COMPREHENSION_MACROS: Set<string>;
|
|
4
|
+
/** Solidity scalar wrapper functions (pass-through for arg classification). */
|
|
5
|
+
declare const SCALAR_WRAPPER_FUNCTIONS: Set<string>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { COMPREHENSION_MACROS, SCALAR_WRAPPER_FUNCTIONS };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/constants.ts
|
|
2
|
+
/** Comprehension macro names that introduce scoped iteration variables. */
|
|
3
|
+
const COMPREHENSION_MACROS = new Set([
|
|
4
|
+
"map",
|
|
5
|
+
"filter",
|
|
6
|
+
"exists",
|
|
7
|
+
"all",
|
|
8
|
+
"exists_one"
|
|
9
|
+
]);
|
|
10
|
+
/** Solidity scalar wrapper functions (pass-through for arg classification). */
|
|
11
|
+
const SCALAR_WRAPPER_FUNCTIONS = new Set(["solInt", "solAddress"]);
|
|
12
|
+
//#endregion
|
|
13
|
+
export { COMPREHENSION_MACROS, SCALAR_WRAPPER_FUNCTIONS };
|
package/dist/debug.cjs
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
let debug = require("debug");
|
|
3
|
+
debug = require_runtime.__toESM(debug);
|
|
4
|
+
//#region src/debug.ts
|
|
5
|
+
const createLogger = (namespace) => (0, debug.default)(`sel:checker:${namespace}`);
|
|
6
|
+
//#endregion
|
|
7
|
+
exports.createLogger = createLogger;
|
package/dist/debug.mjs
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
let _seljs_types = require("@seljs/types");
|
|
3
|
+
let zod = require("zod");
|
|
4
|
+
//#region src/environment/codec-registry.ts
|
|
5
|
+
const solidityAddressCodec = zod.z.codec(zod.z.string(), zod.z.instanceof(_seljs_types.SolidityAddressTypeWrapper), {
|
|
6
|
+
decode: (s) => new _seljs_types.SolidityAddressTypeWrapper(s),
|
|
7
|
+
encode: (w) => w.value
|
|
8
|
+
});
|
|
9
|
+
const solidityIntCodec = zod.z.codec(zod.z.union([zod.z.bigint(), zod.z.number().transform((n) => BigInt(n))]), zod.z.instanceof(_seljs_types.SolidityIntTypeWrapper), {
|
|
10
|
+
decode: (n) => new _seljs_types.SolidityIntTypeWrapper(n),
|
|
11
|
+
encode: (w) => w.value
|
|
12
|
+
});
|
|
13
|
+
/**
|
|
14
|
+
* Registry that maps CEL type strings to bidirectional Zod 4 codecs.
|
|
15
|
+
* Immutable after construction — all codecs resolved eagerly.
|
|
16
|
+
*/
|
|
17
|
+
var CelCodecRegistry = class {
|
|
18
|
+
codecs;
|
|
19
|
+
structMetas;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this.codecs = /* @__PURE__ */ new Map();
|
|
22
|
+
this.structMetas = /* @__PURE__ */ new Map();
|
|
23
|
+
this.codecs.set("sol_address", solidityAddressCodec);
|
|
24
|
+
this.codecs.set("sol_int", solidityIntCodec);
|
|
25
|
+
this.codecs.set("bool", zod.z.boolean());
|
|
26
|
+
this.codecs.set("string", zod.z.string());
|
|
27
|
+
this.codecs.set("int", zod.z.bigint());
|
|
28
|
+
this.codecs.set("bytes", zod.z.union([zod.z.instanceof(Uint8Array), zod.z.string().transform((s) => {
|
|
29
|
+
const hex = s.startsWith("0x") ? s.slice(2) : s;
|
|
30
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
31
|
+
for (let i = 0; i < bytes.length; i++) bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
32
|
+
return bytes;
|
|
33
|
+
})]));
|
|
34
|
+
this.codecs.set("dyn", zod.z.unknown().transform((v) => typeof v === "bigint" ? new _seljs_types.SolidityIntTypeWrapper(v) : v));
|
|
35
|
+
for (const desc of options?.structs ?? []) {
|
|
36
|
+
this.codecs.set(desc.name, this.buildStructCodec(desc));
|
|
37
|
+
this.structMetas.set(desc.name, {
|
|
38
|
+
fieldNames: desc.fieldNames,
|
|
39
|
+
fieldTypes: desc.fieldTypes
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve a codec for the given CEL type string.
|
|
45
|
+
* Handles `list<T>` container types by composing element codecs.
|
|
46
|
+
* Unknown types fall back to z.unknown().
|
|
47
|
+
*/
|
|
48
|
+
resolve(celType) {
|
|
49
|
+
const listMatch = /^list<(.+)>$/.exec(celType);
|
|
50
|
+
if (listMatch) {
|
|
51
|
+
const elementCodec = this.resolve(listMatch[1]);
|
|
52
|
+
return zod.z.array(elementCodec);
|
|
53
|
+
}
|
|
54
|
+
return this.codecs.get(celType) ?? zod.z.unknown();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Encode a CEL value back to its raw form using the codec for the given type.
|
|
58
|
+
* For bidirectional codecs (SolidityAddress, SolidityInt) this calls .encode().
|
|
59
|
+
* For structs, it recursively encodes each field.
|
|
60
|
+
* For passthrough types (bool, string, int), returns the value as-is.
|
|
61
|
+
*/
|
|
62
|
+
encode(celType, value) {
|
|
63
|
+
if (celType === "bytes") {
|
|
64
|
+
if (value instanceof Uint8Array) return "0x" + Array.from(value).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
if (celType === "dyn") {
|
|
68
|
+
if (value instanceof _seljs_types.SolidityIntTypeWrapper) return value.value;
|
|
69
|
+
if (value instanceof _seljs_types.SolidityAddressTypeWrapper) return value.value;
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
const listMatch = /^list<(.+)>$/.exec(celType);
|
|
73
|
+
if (listMatch && Array.isArray(value)) {
|
|
74
|
+
const elementType = listMatch[1];
|
|
75
|
+
return value.map((item) => this.encode(elementType, item));
|
|
76
|
+
}
|
|
77
|
+
const structMeta = this.structMetas.get(celType);
|
|
78
|
+
if (structMeta) {
|
|
79
|
+
const raw = value;
|
|
80
|
+
const result = {};
|
|
81
|
+
for (const name of structMeta.fieldNames) result[name] = this.encode(structMeta.fieldTypes[name] ?? "dyn", raw[name]);
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
const codec = this.codecs.get(celType);
|
|
85
|
+
if (!codec) return value;
|
|
86
|
+
try {
|
|
87
|
+
return codec.encode(value);
|
|
88
|
+
} catch {
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
buildStructCodec(desc) {
|
|
93
|
+
const { ctor, fieldNames, fieldTypes } = desc;
|
|
94
|
+
return zod.z.unknown().transform((input) => {
|
|
95
|
+
let data;
|
|
96
|
+
if (Array.isArray(input)) data = Object.fromEntries(fieldNames.map((name, i) => [name, this.decodeField(fieldTypes[name] ?? "dyn", input[i])]));
|
|
97
|
+
else {
|
|
98
|
+
const raw = input;
|
|
99
|
+
data = Object.fromEntries(fieldNames.map((name) => [name, this.decodeField(fieldTypes[name] ?? "dyn", raw[name])]));
|
|
100
|
+
}
|
|
101
|
+
return Object.assign(new ctor(), data);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
decodeField(celType, value) {
|
|
105
|
+
return this.resolve(celType).parse(value);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
//#endregion
|
|
109
|
+
exports.CelCodecRegistry = CelCodecRegistry;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/environment/codec-registry.d.ts
|
|
4
|
+
type AnyCodec = z.ZodType;
|
|
5
|
+
/**
|
|
6
|
+
* Struct descriptor provided to CelCodecRegistry.
|
|
7
|
+
*/
|
|
8
|
+
interface StructCodecDescriptor {
|
|
9
|
+
name: string;
|
|
10
|
+
ctor: new () => object;
|
|
11
|
+
fieldNames: string[];
|
|
12
|
+
fieldTypes: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Options for constructing a CelCodecRegistry.
|
|
16
|
+
*/
|
|
17
|
+
interface CelCodecRegistryOptions {
|
|
18
|
+
structs?: StructCodecDescriptor[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Registry that maps CEL type strings to bidirectional Zod 4 codecs.
|
|
22
|
+
* Immutable after construction — all codecs resolved eagerly.
|
|
23
|
+
*/
|
|
24
|
+
declare class CelCodecRegistry {
|
|
25
|
+
private readonly codecs;
|
|
26
|
+
private readonly structMetas;
|
|
27
|
+
constructor(options?: CelCodecRegistryOptions);
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a codec for the given CEL type string.
|
|
30
|
+
* Handles `list<T>` container types by composing element codecs.
|
|
31
|
+
* Unknown types fall back to z.unknown().
|
|
32
|
+
*/
|
|
33
|
+
resolve(celType: string): AnyCodec;
|
|
34
|
+
/**
|
|
35
|
+
* Encode a CEL value back to its raw form using the codec for the given type.
|
|
36
|
+
* For bidirectional codecs (SolidityAddress, SolidityInt) this calls .encode().
|
|
37
|
+
* For structs, it recursively encodes each field.
|
|
38
|
+
* For passthrough types (bool, string, int), returns the value as-is.
|
|
39
|
+
*/
|
|
40
|
+
encode(celType: string, value: unknown): unknown;
|
|
41
|
+
private buildStructCodec;
|
|
42
|
+
private decodeField;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { CelCodecRegistry, CelCodecRegistryOptions, StructCodecDescriptor };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/environment/codec-registry.d.ts
|
|
4
|
+
type AnyCodec = z.ZodType;
|
|
5
|
+
/**
|
|
6
|
+
* Struct descriptor provided to CelCodecRegistry.
|
|
7
|
+
*/
|
|
8
|
+
interface StructCodecDescriptor {
|
|
9
|
+
name: string;
|
|
10
|
+
ctor: new () => object;
|
|
11
|
+
fieldNames: string[];
|
|
12
|
+
fieldTypes: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Options for constructing a CelCodecRegistry.
|
|
16
|
+
*/
|
|
17
|
+
interface CelCodecRegistryOptions {
|
|
18
|
+
structs?: StructCodecDescriptor[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Registry that maps CEL type strings to bidirectional Zod 4 codecs.
|
|
22
|
+
* Immutable after construction — all codecs resolved eagerly.
|
|
23
|
+
*/
|
|
24
|
+
declare class CelCodecRegistry {
|
|
25
|
+
private readonly codecs;
|
|
26
|
+
private readonly structMetas;
|
|
27
|
+
constructor(options?: CelCodecRegistryOptions);
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a codec for the given CEL type string.
|
|
30
|
+
* Handles `list<T>` container types by composing element codecs.
|
|
31
|
+
* Unknown types fall back to z.unknown().
|
|
32
|
+
*/
|
|
33
|
+
resolve(celType: string): AnyCodec;
|
|
34
|
+
/**
|
|
35
|
+
* Encode a CEL value back to its raw form using the codec for the given type.
|
|
36
|
+
* For bidirectional codecs (SolidityAddress, SolidityInt) this calls .encode().
|
|
37
|
+
* For structs, it recursively encodes each field.
|
|
38
|
+
* For passthrough types (bool, string, int), returns the value as-is.
|
|
39
|
+
*/
|
|
40
|
+
encode(celType: string, value: unknown): unknown;
|
|
41
|
+
private buildStructCodec;
|
|
42
|
+
private decodeField;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { CelCodecRegistry, CelCodecRegistryOptions, StructCodecDescriptor };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { SolidityAddressTypeWrapper, SolidityIntTypeWrapper } from "@seljs/types";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/environment/codec-registry.ts
|
|
4
|
+
const solidityAddressCodec = z.codec(z.string(), z.instanceof(SolidityAddressTypeWrapper), {
|
|
5
|
+
decode: (s) => new SolidityAddressTypeWrapper(s),
|
|
6
|
+
encode: (w) => w.value
|
|
7
|
+
});
|
|
8
|
+
const solidityIntCodec = z.codec(z.union([z.bigint(), z.number().transform((n) => BigInt(n))]), z.instanceof(SolidityIntTypeWrapper), {
|
|
9
|
+
decode: (n) => new SolidityIntTypeWrapper(n),
|
|
10
|
+
encode: (w) => w.value
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Registry that maps CEL type strings to bidirectional Zod 4 codecs.
|
|
14
|
+
* Immutable after construction — all codecs resolved eagerly.
|
|
15
|
+
*/
|
|
16
|
+
var CelCodecRegistry = class {
|
|
17
|
+
codecs;
|
|
18
|
+
structMetas;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.codecs = /* @__PURE__ */ new Map();
|
|
21
|
+
this.structMetas = /* @__PURE__ */ new Map();
|
|
22
|
+
this.codecs.set("sol_address", solidityAddressCodec);
|
|
23
|
+
this.codecs.set("sol_int", solidityIntCodec);
|
|
24
|
+
this.codecs.set("bool", z.boolean());
|
|
25
|
+
this.codecs.set("string", z.string());
|
|
26
|
+
this.codecs.set("int", z.bigint());
|
|
27
|
+
this.codecs.set("bytes", z.union([z.instanceof(Uint8Array), z.string().transform((s) => {
|
|
28
|
+
const hex = s.startsWith("0x") ? s.slice(2) : s;
|
|
29
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
30
|
+
for (let i = 0; i < bytes.length; i++) bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
31
|
+
return bytes;
|
|
32
|
+
})]));
|
|
33
|
+
this.codecs.set("dyn", z.unknown().transform((v) => typeof v === "bigint" ? new SolidityIntTypeWrapper(v) : v));
|
|
34
|
+
for (const desc of options?.structs ?? []) {
|
|
35
|
+
this.codecs.set(desc.name, this.buildStructCodec(desc));
|
|
36
|
+
this.structMetas.set(desc.name, {
|
|
37
|
+
fieldNames: desc.fieldNames,
|
|
38
|
+
fieldTypes: desc.fieldTypes
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve a codec for the given CEL type string.
|
|
44
|
+
* Handles `list<T>` container types by composing element codecs.
|
|
45
|
+
* Unknown types fall back to z.unknown().
|
|
46
|
+
*/
|
|
47
|
+
resolve(celType) {
|
|
48
|
+
const listMatch = /^list<(.+)>$/.exec(celType);
|
|
49
|
+
if (listMatch) {
|
|
50
|
+
const elementCodec = this.resolve(listMatch[1]);
|
|
51
|
+
return z.array(elementCodec);
|
|
52
|
+
}
|
|
53
|
+
return this.codecs.get(celType) ?? z.unknown();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Encode a CEL value back to its raw form using the codec for the given type.
|
|
57
|
+
* For bidirectional codecs (SolidityAddress, SolidityInt) this calls .encode().
|
|
58
|
+
* For structs, it recursively encodes each field.
|
|
59
|
+
* For passthrough types (bool, string, int), returns the value as-is.
|
|
60
|
+
*/
|
|
61
|
+
encode(celType, value) {
|
|
62
|
+
if (celType === "bytes") {
|
|
63
|
+
if (value instanceof Uint8Array) return "0x" + Array.from(value).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
if (celType === "dyn") {
|
|
67
|
+
if (value instanceof SolidityIntTypeWrapper) return value.value;
|
|
68
|
+
if (value instanceof SolidityAddressTypeWrapper) return value.value;
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
const listMatch = /^list<(.+)>$/.exec(celType);
|
|
72
|
+
if (listMatch && Array.isArray(value)) {
|
|
73
|
+
const elementType = listMatch[1];
|
|
74
|
+
return value.map((item) => this.encode(elementType, item));
|
|
75
|
+
}
|
|
76
|
+
const structMeta = this.structMetas.get(celType);
|
|
77
|
+
if (structMeta) {
|
|
78
|
+
const raw = value;
|
|
79
|
+
const result = {};
|
|
80
|
+
for (const name of structMeta.fieldNames) result[name] = this.encode(structMeta.fieldTypes[name] ?? "dyn", raw[name]);
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
const codec = this.codecs.get(celType);
|
|
84
|
+
if (!codec) return value;
|
|
85
|
+
try {
|
|
86
|
+
return codec.encode(value);
|
|
87
|
+
} catch {
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
buildStructCodec(desc) {
|
|
92
|
+
const { ctor, fieldNames, fieldTypes } = desc;
|
|
93
|
+
return z.unknown().transform((input) => {
|
|
94
|
+
let data;
|
|
95
|
+
if (Array.isArray(input)) data = Object.fromEntries(fieldNames.map((name, i) => [name, this.decodeField(fieldTypes[name] ?? "dyn", input[i])]));
|
|
96
|
+
else {
|
|
97
|
+
const raw = input;
|
|
98
|
+
data = Object.fromEntries(fieldNames.map((name) => [name, this.decodeField(fieldTypes[name] ?? "dyn", raw[name])]));
|
|
99
|
+
}
|
|
100
|
+
return Object.assign(new ctor(), data);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
decodeField(celType, value) {
|
|
104
|
+
return this.resolve(celType).parse(value);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
//#endregion
|
|
108
|
+
export { CelCodecRegistry };
|