You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+74-26Lines changed: 74 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,50 +21,98 @@ When responding:
21
21
22
22
# Sury Architecture
23
23
24
-
A schema is a representation of TWO types. Input and output
24
+
## Schema Input and Output Types
25
25
26
-
1. S.string - Sometimes input and output are the same
26
+
A schema represents two types: Input and Output.
27
27
28
-
- Input: string
29
-
- Output: string
28
+
### Example 1: Same Input and Output
30
29
31
-
2. S.schema({
32
-
foo: S.string.with(S.to, S.number)
33
-
}) - In this case, the input and output are different, even though the S.schema won't have .to property itself
34
-
- Input: { foo: string }
35
-
- Output: { foo: number }
30
+
```typescript
31
+
S.string
32
+
// Input: string
33
+
// Output: string
34
+
```
36
35
37
-
When we modify a schema, we modify the output type.
36
+
### Example 2: Different Input and Output
38
37
39
-
```ts
38
+
```typescript
39
+
S.schema({
40
+
foo: S.string.with(S.to, S.number)
41
+
})
42
+
// Input: { foo: string }
43
+
// Output: { foo: number }
44
+
```
45
+
46
+
The input and output differ because nested items have transformations, even though the schema itself does not have a `.to` property.
47
+
48
+
## Modifying a Schema
49
+
50
+
When modifying a schema, the modification applies to the output type.
51
+
52
+
```typescript
40
53
S.schema({
41
54
foo: S.string.with(S.to, S.number)
42
55
}).with(S.refine, () => {...})
43
56
```
44
57
45
-
Since the case doesn't have .to, we MUST deffirentiate between input and output refines to support `S.reverse` - Every schema should be able to be reversed from Input->Output to Output->Input, unless it's explicitly prevented.
58
+
Since this schema does not have `.to`, input and output refiners must be stored separately to support `S.reverse`. Every schema should be reversible from Input→Output to Output→Input, unless explicitly prevented.
59
+
60
+
For modifications like `name` or built-in refinements that do not affect nested items, they apply to both input and output without differentiation.
61
+
62
+
## Decode Function
63
+
64
+
The decode function is created from a single schema and transforms the schema's Input to Output. When multiple schemas are joined by the `.to` property, they are automatically combined into a single transformation pipeline.
65
+
66
+
## Schema Properties and Execution Order
67
+
68
+
Schema properties are executed in the following order:
69
+
70
+
1.**decoder** - If input val differs from the schema, decode it to the schema's input type. May skip directly to schema output if there is no inputRefiner.
71
+
72
+
2.**inputRefiner** - Custom validations on the input part of the schema value.
73
+
74
+
3.**decoder** - Decodes input to output for the current schema. Typically required to decode nested items such as object fields.
75
+
76
+
4.**outputRefiner** - Custom validations on the output part of the schema value.
77
+
78
+
### If Schema Has `.to` Property
79
+
80
+
5.**parser** - Custom transformation logic to the `.to` schema. The serializer is the reverse of parser.
81
+
82
+
### If There Is No Parser
83
+
84
+
5.**encoder** - Transformation logic from the current schema's output to the `.to` schema's input.
85
+
86
+
6.**.to.decoder** - Starts the cycle from the beginning with the `.to` schema.
46
87
47
-
We should also try to store every data-point on schema to be able to use them to compile a decode function.
88
+
## Reversal with S.reverse
48
89
49
-
The decode function should be created from a single schema and must transform schema input to output. For multiple schemas it automatically joins them by .to property and turns into a single one.
90
+
`S.reverse` swaps:
50
91
51
-
This makes schema to have the following properties and run them in order:
92
+
-`inputRefiner` ↔ `outputRefiner`
93
+
-`parser` ↔ `serializer`
94
+
- Reverses the `.to` chain direction
52
95
53
-
- inputRefiner - Custom validations to the input part of the schema value
54
-
- innerDecoder - Decoding of inner items like object fields
55
-
- outputRefiner - Custom validations to the output part of the schema value
96
+
## Async Support
56
97
57
-
If schema has .to property:
98
+
Every transformation may return an async value. To continue the transformation chain:
58
99
59
-
- parser - Custom transformation logic to the .to schema (serializer is a reverse of parser)
100
+
1. Append `.then()` and continue the logic in the callback function.
101
+
2. For nested items (e.g., object fields, array items), create a promise that collects all inner items with `Promise.all()`.
60
102
61
-
And if there's no .parser:
103
+
## Val
62
104
63
-
- encoder - Transformation logic from the current schema to the .to schema
64
-
- decoder - Transformation logic of the .to schema from any other schema
105
+
The `val` represents a value at a specific point in the transformation pipeline during code generation.
65
106
66
-
After the step either finish the decode function or continue with the inputRefiner.
107
+
Key properties:
67
108
68
-
Additionally for async support we should be aware of that every transformation might return an async value, so to continue the transformation chain we need to append .then and continue the logic in the callback function. For innerDecoder it should create a promise which collects all inner items.
109
+
-`schema` - The actual type of the value
110
+
-`expected` - The schema of decoder
111
+
-`var` - Returns the variable name in generated code
112
+
-`inline` - The value as an inline code expression
113
+
-`code` - Accumulated generated code (used by all transformation steps)
114
+
-`validation` - Built-in type check condition for the decoder (e.g., `typeof x === "string"`). Different from custom refiners.
115
+
-`from` - The previous val in the chain (tracks transformation history)
116
+
-`path` - Current location in the data structure (for error messages)
69
117
70
-
Every transformation point is connected by a val
118
+
The decoder uses `schema` vs `expected` to skip unnecessary validations when the actual type is already compatible.
0 commit comments