@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.
- package/CHANGELOG.md +7 -0
- 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 +24 -17
- 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
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
const LOGICAL_OPERATORS = new Set(["&&", "||"]);
|
|
2
|
-
const ARITHMETIC_OPERATORS = new Set(["+", "-", "*", "/", "%"]);
|
|
3
|
-
const COMPARISON_OPERATORS = new Set(["<", "<=", ">", ">="]);
|
|
4
|
-
const EQUALITY_OPERATORS = new Set(["==", "!="]);
|
|
5
|
-
/** Types that support arithmetic operators (same-type only). */
|
|
6
|
-
const ARITHMETIC_TYPES = new Set(["int", "uint", "double", "sol_int"]);
|
|
7
|
-
/** Types that support the + operator for concatenation. */
|
|
8
|
-
const CONCATENATION_TYPES = new Set(["string", "list", "bytes"]);
|
|
9
|
-
/** Types that support comparison operators (same-type only). */
|
|
10
|
-
const COMPARISON_TYPES = new Set([
|
|
11
|
-
"int",
|
|
12
|
-
"uint",
|
|
13
|
-
"double",
|
|
14
|
-
"string",
|
|
15
|
-
"bytes",
|
|
16
|
-
"sol_address",
|
|
17
|
-
"sol_int",
|
|
18
|
-
]);
|
|
19
|
-
/**
|
|
20
|
-
* Given the type of the left operand and the operator,
|
|
21
|
-
* returns the expected type for the right operand.
|
|
22
|
-
*
|
|
23
|
-
* Based on the registered operators in register-types.ts.
|
|
24
|
-
* Type compatibility is strictly same-type (no implicit coercion).
|
|
25
|
-
*
|
|
26
|
-
* Returns undefined when the type/operator combination is unknown,
|
|
27
|
-
* signaling that no narrowing should occur.
|
|
28
|
-
*/
|
|
29
|
-
export const expectedTypeForOperator = (leftType, operator) => {
|
|
30
|
-
if (LOGICAL_OPERATORS.has(operator)) {
|
|
31
|
-
return "bool";
|
|
32
|
-
}
|
|
33
|
-
if (ARITHMETIC_OPERATORS.has(operator)) {
|
|
34
|
-
if (ARITHMETIC_TYPES.has(leftType)) {
|
|
35
|
-
return leftType;
|
|
36
|
-
}
|
|
37
|
-
if (operator === "+" && CONCATENATION_TYPES.has(leftType)) {
|
|
38
|
-
return leftType;
|
|
39
|
-
}
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
42
|
-
if (COMPARISON_OPERATORS.has(operator)) {
|
|
43
|
-
return COMPARISON_TYPES.has(leftType) ? leftType : undefined;
|
|
44
|
-
}
|
|
45
|
-
if (EQUALITY_OPERATORS.has(operator)) {
|
|
46
|
-
return leftType;
|
|
47
|
-
}
|
|
48
|
-
return undefined;
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* Check if a candidate type is compatible with an expected type.
|
|
52
|
-
* "dyn" is a wildcard — compatible with anything in either direction.
|
|
53
|
-
*/
|
|
54
|
-
export const isTypeCompatible = (candidateType, expectedType) => {
|
|
55
|
-
if (expectedType === "dyn" || candidateType === "dyn") {
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
return candidateType === expectedType;
|
|
59
|
-
};
|
package/dist/constants.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
/** Comprehension macro names that introduce scoped iteration variables. */
|
|
2
|
-
export declare const COMPREHENSION_MACROS: Set<string>;
|
|
3
|
-
/** Solidity scalar wrapper functions (pass-through for arg classification). */
|
|
4
|
-
export declare const SCALAR_WRAPPER_FUNCTIONS: Set<string>;
|
package/dist/constants.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/** Comprehension macro names that introduce scoped iteration variables. */
|
|
2
|
-
export const COMPREHENSION_MACROS = new Set([
|
|
3
|
-
"map",
|
|
4
|
-
"filter",
|
|
5
|
-
"exists",
|
|
6
|
-
"all",
|
|
7
|
-
"exists_one",
|
|
8
|
-
]);
|
|
9
|
-
/** Solidity scalar wrapper functions (pass-through for arg classification). */
|
|
10
|
-
export const SCALAR_WRAPPER_FUNCTIONS = new Set(["solInt", "solAddress"]);
|
package/dist/debug.d.ts
DELETED
package/dist/debug.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
type AnyCodec = z.ZodType;
|
|
3
|
-
/**
|
|
4
|
-
* Struct descriptor provided to CelCodecRegistry.
|
|
5
|
-
*/
|
|
6
|
-
export interface StructCodecDescriptor {
|
|
7
|
-
name: string;
|
|
8
|
-
ctor: new () => object;
|
|
9
|
-
fieldNames: string[];
|
|
10
|
-
fieldTypes: Record<string, string>;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Options for constructing a CelCodecRegistry.
|
|
14
|
-
*/
|
|
15
|
-
export interface CelCodecRegistryOptions {
|
|
16
|
-
structs?: StructCodecDescriptor[];
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Registry that maps CEL type strings to bidirectional Zod 4 codecs.
|
|
20
|
-
* Immutable after construction — all codecs resolved eagerly.
|
|
21
|
-
*/
|
|
22
|
-
export declare class CelCodecRegistry {
|
|
23
|
-
private readonly codecs;
|
|
24
|
-
private readonly structMetas;
|
|
25
|
-
constructor(options?: CelCodecRegistryOptions);
|
|
26
|
-
/**
|
|
27
|
-
* Resolve a codec for the given CEL type string.
|
|
28
|
-
* Handles `list<T>` container types by composing element codecs.
|
|
29
|
-
* Unknown types fall back to z.unknown().
|
|
30
|
-
*/
|
|
31
|
-
resolve(celType: string): AnyCodec;
|
|
32
|
-
/**
|
|
33
|
-
* Encode a CEL value back to its raw form using the codec for the given type.
|
|
34
|
-
* For bidirectional codecs (SolidityAddress, SolidityInt) this calls .encode().
|
|
35
|
-
* For structs, it recursively encodes each field.
|
|
36
|
-
* For passthrough types (bool, string, int), returns the value as-is.
|
|
37
|
-
*/
|
|
38
|
-
encode(celType: string, value: unknown): unknown;
|
|
39
|
-
private buildStructCodec;
|
|
40
|
-
private decodeField;
|
|
41
|
-
}
|
|
42
|
-
export {};
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { SolidityAddressTypeWrapper, SolidityIntTypeWrapper, } from "@seljs/types";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
const solidityAddressCodec = z.codec(z.string(), z.instanceof(SolidityAddressTypeWrapper), {
|
|
4
|
-
decode: (s) => new SolidityAddressTypeWrapper(s),
|
|
5
|
-
encode: (w) => w.value,
|
|
6
|
-
});
|
|
7
|
-
const solidityIntCodec = z.codec(z.union([z.bigint(), z.number().transform((n) => BigInt(n))]), z.instanceof(SolidityIntTypeWrapper), {
|
|
8
|
-
decode: (n) => new SolidityIntTypeWrapper(n),
|
|
9
|
-
encode: (w) => w.value,
|
|
10
|
-
});
|
|
11
|
-
/**
|
|
12
|
-
* Registry that maps CEL type strings to bidirectional Zod 4 codecs.
|
|
13
|
-
* Immutable after construction — all codecs resolved eagerly.
|
|
14
|
-
*/
|
|
15
|
-
export class CelCodecRegistry {
|
|
16
|
-
codecs;
|
|
17
|
-
structMetas;
|
|
18
|
-
constructor(options) {
|
|
19
|
-
this.codecs = new Map();
|
|
20
|
-
this.structMetas = new Map();
|
|
21
|
-
// Register base codecs
|
|
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([
|
|
28
|
-
z.instanceof(Uint8Array),
|
|
29
|
-
z.string().transform((s) => {
|
|
30
|
-
const hex = s.startsWith("0x") ? s.slice(2) : s;
|
|
31
|
-
const bytes = new Uint8Array(hex.length / 2);
|
|
32
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
33
|
-
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
34
|
-
}
|
|
35
|
-
return bytes;
|
|
36
|
-
}),
|
|
37
|
-
]));
|
|
38
|
-
this.codecs.set("dyn", z
|
|
39
|
-
.unknown()
|
|
40
|
-
.transform((v) => typeof v === "bigint" ? new SolidityIntTypeWrapper(v) : v));
|
|
41
|
-
// Register struct codecs eagerly
|
|
42
|
-
for (const desc of options?.structs ?? []) {
|
|
43
|
-
this.codecs.set(desc.name, this.buildStructCodec(desc));
|
|
44
|
-
this.structMetas.set(desc.name, {
|
|
45
|
-
fieldNames: desc.fieldNames,
|
|
46
|
-
fieldTypes: desc.fieldTypes,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Resolve a codec for the given CEL type string.
|
|
52
|
-
* Handles `list<T>` container types by composing element codecs.
|
|
53
|
-
* Unknown types fall back to z.unknown().
|
|
54
|
-
*/
|
|
55
|
-
resolve(celType) {
|
|
56
|
-
// Handle list<T> container type
|
|
57
|
-
const listMatch = /^list<(.+)>$/.exec(celType);
|
|
58
|
-
if (listMatch) {
|
|
59
|
-
const elementCodec = this.resolve(listMatch[1]);
|
|
60
|
-
return z.array(elementCodec);
|
|
61
|
-
}
|
|
62
|
-
return this.codecs.get(celType) ?? z.unknown();
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Encode a CEL value back to its raw form using the codec for the given type.
|
|
66
|
-
* For bidirectional codecs (SolidityAddress, SolidityInt) this calls .encode().
|
|
67
|
-
* For structs, it recursively encodes each field.
|
|
68
|
-
* For passthrough types (bool, string, int), returns the value as-is.
|
|
69
|
-
*/
|
|
70
|
-
encode(celType, value) {
|
|
71
|
-
// Handle bytes — convert Uint8Array back to hex string for viem
|
|
72
|
-
if (celType === "bytes") {
|
|
73
|
-
if (value instanceof Uint8Array) {
|
|
74
|
-
return ("0x" +
|
|
75
|
-
Array.from(value)
|
|
76
|
-
.map((b) => b.toString(16).padStart(2, "0"))
|
|
77
|
-
.join(""));
|
|
78
|
-
}
|
|
79
|
-
return value;
|
|
80
|
-
}
|
|
81
|
-
// Handle dyn — unwrap known wrapper types
|
|
82
|
-
if (celType === "dyn") {
|
|
83
|
-
if (value instanceof SolidityIntTypeWrapper) {
|
|
84
|
-
return value.value;
|
|
85
|
-
}
|
|
86
|
-
if (value instanceof SolidityAddressTypeWrapper) {
|
|
87
|
-
return value.value;
|
|
88
|
-
}
|
|
89
|
-
return value;
|
|
90
|
-
}
|
|
91
|
-
// Handle list<T>
|
|
92
|
-
const listMatch = /^list<(.+)>$/.exec(celType);
|
|
93
|
-
if (listMatch && Array.isArray(value)) {
|
|
94
|
-
const elementType = listMatch[1];
|
|
95
|
-
return value.map((item) => this.encode(elementType, item));
|
|
96
|
-
}
|
|
97
|
-
// Handle structs — recurse into fields
|
|
98
|
-
const structMeta = this.structMetas.get(celType);
|
|
99
|
-
if (structMeta) {
|
|
100
|
-
const raw = value;
|
|
101
|
-
const result = {};
|
|
102
|
-
for (const name of structMeta.fieldNames) {
|
|
103
|
-
result[name] = this.encode(structMeta.fieldTypes[name] ?? "dyn", raw[name]);
|
|
104
|
-
}
|
|
105
|
-
return result;
|
|
106
|
-
}
|
|
107
|
-
// For bidirectional codecs, use .encode(); for passthrough, return as-is
|
|
108
|
-
const codec = this.codecs.get(celType);
|
|
109
|
-
if (!codec) {
|
|
110
|
-
return value;
|
|
111
|
-
}
|
|
112
|
-
try {
|
|
113
|
-
return codec.encode(value);
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
return value;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
buildStructCodec(desc) {
|
|
120
|
-
const { ctor, fieldNames, fieldTypes } = desc;
|
|
121
|
-
// Build a transform that accepts array (positional) or object input
|
|
122
|
-
return z.unknown().transform((input) => {
|
|
123
|
-
let data;
|
|
124
|
-
if (Array.isArray(input)) {
|
|
125
|
-
// Positional multi-return from viem
|
|
126
|
-
data = Object.fromEntries(fieldNames.map((name, i) => [
|
|
127
|
-
name,
|
|
128
|
-
this.decodeField(fieldTypes[name] ?? "dyn", input[i]),
|
|
129
|
-
]));
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
// Named-field object
|
|
133
|
-
const raw = input;
|
|
134
|
-
data = Object.fromEntries(fieldNames.map((name) => [
|
|
135
|
-
name,
|
|
136
|
-
this.decodeField(fieldTypes[name] ?? "dyn", raw[name]),
|
|
137
|
-
]));
|
|
138
|
-
}
|
|
139
|
-
// eslint-disable-next-line new-cap
|
|
140
|
-
return Object.assign(new ctor(), data);
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
decodeField(celType, value) {
|
|
144
|
-
return this.resolve(celType).parse(value);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { Environment } from "@marcbachmann/cel-js";
|
|
2
|
-
import { CelCodecRegistry } from "./codec-registry.js";
|
|
3
|
-
import type { SELSchema } from "@seljs/schema";
|
|
4
|
-
/**
|
|
5
|
-
* CEL environment limits configuration.
|
|
6
|
-
*/
|
|
7
|
-
export interface CelLimits {
|
|
8
|
-
maxAstNodes?: number;
|
|
9
|
-
maxDepth?: number;
|
|
10
|
-
maxListElements?: number;
|
|
11
|
-
maxMapEntries?: number;
|
|
12
|
-
maxCallArguments?: number;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Handler called when a contract method is invoked at runtime.
|
|
16
|
-
*/
|
|
17
|
-
export type ContractCallHandler = (contractName: string, methodName: string, args: unknown[]) => unknown;
|
|
18
|
-
/**
|
|
19
|
-
* Create a base CEL environment with Solidity types registered.
|
|
20
|
-
* No contracts, no variables — just the type system.
|
|
21
|
-
*
|
|
22
|
-
* Use this when you need to register contracts and variables yourself
|
|
23
|
-
* (e.g., runtime evaluation with real async handlers).
|
|
24
|
-
*/
|
|
25
|
-
export declare const createBaseEnvironment: (options?: {
|
|
26
|
-
limits?: CelLimits;
|
|
27
|
-
}) => Environment;
|
|
28
|
-
/**
|
|
29
|
-
* Create a fully hydrated checker environment from a SELSchema.
|
|
30
|
-
*
|
|
31
|
-
* Registers Solidity primitive types, contract types with their methods
|
|
32
|
-
* (using no-op handlers since the checker only needs type information),
|
|
33
|
-
* schema variables, and built-in functions.
|
|
34
|
-
*/
|
|
35
|
-
export declare const createCheckerEnvironment: (schema: SELSchema) => Environment;
|
|
36
|
-
export interface RuntimeEnvironmentResult {
|
|
37
|
-
env: Environment;
|
|
38
|
-
contractBindings: Record<string, unknown>;
|
|
39
|
-
codecRegistry: CelCodecRegistry;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Create a fully hydrated runtime environment from a SELSchema with a
|
|
43
|
-
* real async handler for contract method calls.
|
|
44
|
-
*/
|
|
45
|
-
export declare const createRuntimeEnvironment: (schema: SELSchema, handler: ContractCallHandler, options?: {
|
|
46
|
-
limits?: CelLimits;
|
|
47
|
-
unlistedVariablesAreDyn?: boolean;
|
|
48
|
-
}) => RuntimeEnvironmentResult;
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { Environment } from "@marcbachmann/cel-js";
|
|
2
|
-
import { contractTypeName } from "@seljs/common";
|
|
3
|
-
import { createLogger } from "../debug.js";
|
|
4
|
-
import { CelCodecRegistry } from "./codec-registry.js";
|
|
5
|
-
import { registerSolidityTypes } from "./register-types.js";
|
|
6
|
-
import { toCelLiteralType } from "./value-wrappers.js";
|
|
7
|
-
const debug = createLogger("hydrate");
|
|
8
|
-
const hydrateEnvironment = (env, schema, handler) => {
|
|
9
|
-
const contractBindings = {};
|
|
10
|
-
const structRegistry = new Map();
|
|
11
|
-
// Register struct types from schema (nested types appear before parents)
|
|
12
|
-
for (const type of schema.types) {
|
|
13
|
-
if (type.kind === "struct" && type.fields) {
|
|
14
|
-
const fields = {};
|
|
15
|
-
for (const field of type.fields) {
|
|
16
|
-
fields[field.name] = field.type;
|
|
17
|
-
}
|
|
18
|
-
try {
|
|
19
|
-
if (handler !== undefined) {
|
|
20
|
-
// Runtime mode: register WITH ctor so structs can be instantiated
|
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
|
22
|
-
const StructCtor = class {
|
|
23
|
-
};
|
|
24
|
-
env.registerType(type.name, { ctor: StructCtor, fields });
|
|
25
|
-
structRegistry.set(type.name, {
|
|
26
|
-
ctor: StructCtor,
|
|
27
|
-
fieldNames: Object.keys(fields),
|
|
28
|
-
fieldTypes: fields,
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
// Checker mode: no ctor needed
|
|
33
|
-
env.registerType(type.name, { fields });
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
debug("skipped type %s: %O", type.name, err);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
const codecRegistry = handler !== undefined
|
|
42
|
-
? new CelCodecRegistry({
|
|
43
|
-
structs: Array.from(structRegistry.entries()).map(([name, info]) => ({
|
|
44
|
-
name,
|
|
45
|
-
...info,
|
|
46
|
-
})),
|
|
47
|
-
})
|
|
48
|
-
: undefined;
|
|
49
|
-
// Register contract types and methods
|
|
50
|
-
for (const contract of schema.contracts) {
|
|
51
|
-
const typeName = contractTypeName(contract.name);
|
|
52
|
-
class ContractType {
|
|
53
|
-
name;
|
|
54
|
-
constructor(name) {
|
|
55
|
-
this.name = name;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
env
|
|
59
|
-
.registerType(typeName, { ctor: ContractType, fields: {} })
|
|
60
|
-
.registerVariable(contract.name, typeName);
|
|
61
|
-
contractBindings[contract.name] = new ContractType(contract.name);
|
|
62
|
-
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
63
|
-
for (const method of contract.methods) {
|
|
64
|
-
const returnType = method.returns || "dyn";
|
|
65
|
-
const methodHandler = handler !== undefined
|
|
66
|
-
? async (...args) => {
|
|
67
|
-
const raw = await handler(contract.name, method.name, args.slice(1));
|
|
68
|
-
if (!codecRegistry) {
|
|
69
|
-
throw new Error("codecRegistry is required when handler is provided");
|
|
70
|
-
}
|
|
71
|
-
return codecRegistry.resolve(returnType).parse(raw);
|
|
72
|
-
}
|
|
73
|
-
: () => undefined;
|
|
74
|
-
// Primary overload with schema param types
|
|
75
|
-
try {
|
|
76
|
-
env.registerFunction({
|
|
77
|
-
name: method.name,
|
|
78
|
-
receiverType: typeName,
|
|
79
|
-
returnType,
|
|
80
|
-
handler: methodHandler,
|
|
81
|
-
params: method.params.map((param) => ({
|
|
82
|
-
name: param.name,
|
|
83
|
-
type: param.type,
|
|
84
|
-
})),
|
|
85
|
-
}, undefined);
|
|
86
|
-
}
|
|
87
|
-
catch (err) {
|
|
88
|
-
debug("skipped method %s.%s: %O", contract.name, method.name, err);
|
|
89
|
-
}
|
|
90
|
-
// CEL literal type overloads for SolidityInt/SolidityAddress params
|
|
91
|
-
const hasCustomParams = method.params.some((p) => toCelLiteralType(p.type) !== null);
|
|
92
|
-
if (hasCustomParams) {
|
|
93
|
-
try {
|
|
94
|
-
env.registerFunction({
|
|
95
|
-
name: method.name,
|
|
96
|
-
receiverType: typeName,
|
|
97
|
-
returnType,
|
|
98
|
-
handler: methodHandler,
|
|
99
|
-
params: method.params.map((param) => ({
|
|
100
|
-
name: param.name,
|
|
101
|
-
type: toCelLiteralType(param.type) ?? param.type,
|
|
102
|
-
})),
|
|
103
|
-
}, undefined);
|
|
104
|
-
}
|
|
105
|
-
catch (err) {
|
|
106
|
-
debug("skipped literal overload %s.%s: %O", contract.name, method.name, err);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/* eslint-enable @typescript-eslint/no-unsafe-argument */
|
|
111
|
-
}
|
|
112
|
-
// Register variables
|
|
113
|
-
for (const variable of schema.variables) {
|
|
114
|
-
try {
|
|
115
|
-
env.registerVariable(variable.name, variable.type);
|
|
116
|
-
}
|
|
117
|
-
catch (err) {
|
|
118
|
-
debug("variable %s: fallback to dyn: %O", variable.name, err);
|
|
119
|
-
env.registerVariable(variable.name, "dyn");
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
// Register schema functions with receiverType for type-checking
|
|
123
|
-
for (const fn of schema.functions) {
|
|
124
|
-
if (!fn.receiverType) {
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
try {
|
|
128
|
-
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
129
|
-
env.registerFunction({
|
|
130
|
-
name: fn.name,
|
|
131
|
-
receiverType: fn.receiverType,
|
|
132
|
-
returnType: fn.returns,
|
|
133
|
-
handler: () => undefined,
|
|
134
|
-
params: fn.params.map((param) => ({
|
|
135
|
-
name: param.name,
|
|
136
|
-
type: param.type,
|
|
137
|
-
})),
|
|
138
|
-
}, undefined);
|
|
139
|
-
/* eslint-enable @typescript-eslint/no-unsafe-argument */
|
|
140
|
-
}
|
|
141
|
-
catch (err) {
|
|
142
|
-
// Skip functions that are already registered as CEL builtins
|
|
143
|
-
if (!(err instanceof Error) ||
|
|
144
|
-
!err.message.includes("overlaps with existing overload")) {
|
|
145
|
-
throw err;
|
|
146
|
-
}
|
|
147
|
-
debug("skipped overlapping overload: %O", err);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return { contractBindings, codecRegistry };
|
|
151
|
-
};
|
|
152
|
-
/**
|
|
153
|
-
* Create a base CEL environment with Solidity types registered.
|
|
154
|
-
* No contracts, no variables — just the type system.
|
|
155
|
-
*
|
|
156
|
-
* Use this when you need to register contracts and variables yourself
|
|
157
|
-
* (e.g., runtime evaluation with real async handlers).
|
|
158
|
-
*/
|
|
159
|
-
export const createBaseEnvironment = (options) => {
|
|
160
|
-
const env = new Environment({
|
|
161
|
-
unlistedVariablesAreDyn: false,
|
|
162
|
-
...(options?.limits ? { limits: options.limits } : {}),
|
|
163
|
-
});
|
|
164
|
-
registerSolidityTypes(env);
|
|
165
|
-
return env;
|
|
166
|
-
};
|
|
167
|
-
/**
|
|
168
|
-
* Create a fully hydrated checker environment from a SELSchema.
|
|
169
|
-
*
|
|
170
|
-
* Registers Solidity primitive types, contract types with their methods
|
|
171
|
-
* (using no-op handlers since the checker only needs type information),
|
|
172
|
-
* schema variables, and built-in functions.
|
|
173
|
-
*/
|
|
174
|
-
export const createCheckerEnvironment = (schema) => {
|
|
175
|
-
const env = createBaseEnvironment();
|
|
176
|
-
hydrateEnvironment(env, schema);
|
|
177
|
-
return env;
|
|
178
|
-
};
|
|
179
|
-
/**
|
|
180
|
-
* Create a fully hydrated runtime environment from a SELSchema with a
|
|
181
|
-
* real async handler for contract method calls.
|
|
182
|
-
*/
|
|
183
|
-
export const createRuntimeEnvironment = (schema, handler, options) => {
|
|
184
|
-
const env = new Environment({
|
|
185
|
-
unlistedVariablesAreDyn: options?.unlistedVariablesAreDyn ?? false,
|
|
186
|
-
...(options?.limits ? { limits: options.limits } : {}),
|
|
187
|
-
});
|
|
188
|
-
registerSolidityTypes(env);
|
|
189
|
-
const result = hydrateEnvironment(env, schema, handler);
|
|
190
|
-
if (!result.codecRegistry) {
|
|
191
|
-
throw new Error("codecRegistry is required when handler is provided");
|
|
192
|
-
}
|
|
193
|
-
return {
|
|
194
|
-
env,
|
|
195
|
-
contractBindings: result.contractBindings,
|
|
196
|
-
codecRegistry: result.codecRegistry,
|
|
197
|
-
};
|
|
198
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { Environment } from "@marcbachmann/cel-js";
|
|
2
|
-
/**
|
|
3
|
-
* Subset of the CEL Environment API needed for Solidity type registration.
|
|
4
|
-
* Mirrors the parameter signatures from Environment but drops the return type
|
|
5
|
-
* to void — registerSolidityTypes never chains the return value.
|
|
6
|
-
*/
|
|
7
|
-
type SolidityTypeHost = {
|
|
8
|
-
[K in "registerType" | "registerOperator" | "registerFunction"]: (...args: Parameters<Environment[K]>) => void;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Register all Solidity primitive types on a CEL Environment.
|
|
12
|
-
*/
|
|
13
|
-
export declare const registerSolidityTypes: (env: SolidityTypeHost) => void;
|
|
14
|
-
export {};
|