Skip to content

Commit 1814fd6

Browse files
committed
test: 💍
feat: 🎸 rename "field" node to "key"
1 parent 8d48b83 commit 1814fd6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+349
-317
lines changed

README.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -206,15 +206,15 @@ interface NumberSchema {
206206
format?: 'i' | 'u' | 'f' | 'i8' | 'i16' | 'i32' | 'i64' | 'u8' | 'u16' | 'u32' | 'u64' | 'f32' | 'f64';
207207
gt?: number; // Greater than (exclusive)
208208
gte?: number; // Greater than or equal to
209-
lt?: number; // Less than (exclusive)
209+
lt?: number; // Less than (exclusive)
210210
lte?: number; // Less than or equal to
211211
validator?: string | string[];
212212
}
213213
```
214214

215215
**Format options:**
216216
- `i*` - Signed integers (i8, i16, i32, i64)
217-
- `u*` - Unsigned integers (u8, u16, u32, u64)
217+
- `u*` - Unsigned integers (u8, u16, u32, u64)
218218
- `f*` - Floating point (f32, f64)
219219

220220
**Examples:**
@@ -234,7 +234,7 @@ interface StringSchema {
234234
ascii?: boolean; // @deprecated Use format: 'ascii'
235235
noJsonEscape?: boolean; // Skip JSON escaping for performance
236236
min?: number; // Minimum length
237-
max?: number; // Maximum length
237+
max?: number; // Maximum length
238238
validator?: string | string[];
239239
}
240240
```
@@ -269,7 +269,7 @@ s.Binary(s.Object(), {format: 'cbor'}) // CBOR-encoded object
269269

270270
### Composite Types
271271

272-
#### ArraySchema (`arr`)
272+
#### ArraySchema (`arr`)
273273
Represents a JSON array with elements of a specific type.
274274

275275
```ts
@@ -310,9 +310,9 @@ Represents a JSON object with defined fields.
310310
```ts
311311
interface ObjectSchema {
312312
kind: 'obj';
313-
fields: ObjectFieldSchema[]; // Defined object fields
314-
unknownFields?: boolean; // @deprecated Allow undefined fields
315-
encodeUnknownFields?: boolean; // Include unknown fields in output
313+
keys: ObjectKeydSchema[]; // Defined object keys
314+
decodeUnknownKeys?: boolean;
315+
encodeUnknownKeys?: boolean;
316316
validator?: string | string[];
317317
}
318318
```
@@ -325,12 +325,12 @@ s.Object([
325325
])
326326
```
327327

328-
#### ObjectFieldSchema (`field`)
328+
#### ObjectKeySchema (`key`)
329329
Represents a single field in an object.
330330

331331
```ts
332-
interface ObjectFieldSchema {
333-
kind: 'field';
332+
interface ObjectKeydSchema {
333+
kind: 'key';
334334
key: string; // Field name
335335
type: TType; // Field value type
336336
optional?: boolean; // Whether field is optional
@@ -340,7 +340,7 @@ interface ObjectFieldSchema {
340340
**Examples:**
341341
```ts
342342
s.prop('id', s.String()) // Required field
343-
s.propOpt('description', s.String()) // Optional field
343+
s.propOpt('description', s.String()) // Optional field
344344
```
345345

346346
#### MapSchema (`map`)
@@ -350,7 +350,7 @@ Represents an object treated as a map with string keys and uniform value types.
350350
interface MapSchema {
351351
kind: 'map';
352352
type: TType; // Type of all values
353-
validator?: string | string[];
353+
validator?: string | string[];
354354
}
355355
```
356356

@@ -379,7 +379,7 @@ s.Const(42 as const) // Constant number
379379
s.Const(null) // Null constant
380380
```
381381

382-
#### RefSchema (`ref`)
382+
#### RefSchema (`ref`)
383383
References another type by ID.
384384

385385
```ts
@@ -413,7 +413,7 @@ s.Or(s.String(), s.Number()) // String or number
413413
#### FunctionSchema (`fn`)
414414
Represents a function type with request and response.
415415

416-
```ts
416+
```ts
417417
interface FunctionSchema {
418418
kind: 'fn';
419419
req: TType; // Request type
@@ -432,7 +432,7 @@ Represents a streaming function type.
432432
```ts
433433
interface FunctionStreamingSchema {
434434
kind: 'fn$';
435-
req: TType; // Request stream type
435+
req: TType; // Request stream type
436436
res: TType; // Response stream type
437437
}
438438
```
@@ -449,17 +449,17 @@ All node types extend the base `TType` interface with these common properties:
449449
```ts
450450
interface TType {
451451
kind: string; // Node type identifier
452-
452+
453453
// Display properties
454454
title?: string; // Human-readable title
455455
intro?: string; // Short description
456456
description?: string; // Long description (may include Markdown)
457-
457+
458458
// Metadata
459459
id?: string; // Unique identifier
460460
meta?: Record<string, unknown>; // Custom metadata
461461
examples?: TExample[]; // Usage examples
462-
462+
463463
// Deprecation
464464
deprecated?: {
465465
description?: string; // Deprecation reason and alternative
@@ -475,7 +475,7 @@ Many types support custom validation through the `validator` property:
475475
// Single validator
476476
{ validator: 'email' }
477477

478-
// Multiple validators
478+
// Multiple validators
479479
{ validator: ['required', 'email'] }
480480
```
481481

SPECIFICATION.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ A simple user type:
3232
{
3333
"kind": "obj",
3434
"title": "User",
35-
"fields": [
35+
"keys": [
3636
{ "kind": "field", "key": "id", "type": { "kind": "str" }, "title": "User ID" },
3737
{ "kind": "field", "key": "name", "type": { "kind": "str" } },
3838
{ "kind": "field", "key": "age", "type": { "kind": "num", "gte": 0 }, "optional": true }
@@ -246,9 +246,9 @@ Represents a fixed-length array, each position with its own type.
246246
Represents a JSON object with a defined set of fields. `obj` fields are ordered and can be required or optional. Optional fields are usually defined at the end of the `fields` array. Even if in many languages objects are unordered, the order of fields in the schema is a useful feature as the field order can be used in documentation, code generation, and serialization to binary formats.
247247

248248
**Properties:**
249-
- `fields` (array): Array of field nodes (see below).
250-
- `unknownFields` (boolean, deprecated): Allow fields not listed.
251-
- `encodeUnknownFields` (boolean): Emit unknown fields during encoding.
249+
- `keys` (array): Array of field nodes (see below).
250+
- `decodeUnknownKeys` (boolean, deprecated): Allow fields not listed.
251+
- `encodeUnknownKeys` (boolean): Emit unknown fields during encoding.
252252
- `validator` (string or array): Custom validation.
253253

254254
**Example:**
@@ -467,7 +467,7 @@ All nodes may contain the following metadata:
467467
- **Type inference:** Types can be mapped to language types using the structure.
468468
- **Optional and required fields:** Fields are required by default; set `optional: true` for optional fields.
469469
- **Type composition:** Types can be nested and composed arbitrarily.
470-
- **Unknown fields:** By default, unknown fields are rejected. Use `unknownFields: true` or `encodeUnknownFields: true` to allow or preserve them.
470+
- **Unknown fields:** By default, unknown fields are rejected. Use `decodeUnknownKeys: true` or `encodeUnknownKeys: true` to allow or preserve them.
471471

472472
---
473473

src/__demos__/json-type.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ console.log('Can compile a fast validator, which returns booleans as errors:');
119119
console.log();
120120
const validator = user.type.compileValidator({
121121
errors: 'boolean',
122-
skipObjectExtraFieldsCheck: true,
122+
skipObjectExtraKeysCheck: true,
123123
});
124124
console.log(validator.toString());
125125

@@ -128,7 +128,7 @@ console.log('Can compile a fast validator, which returns JSON strings as errors:
128128
console.log();
129129
const validator2 = user.type.compileValidator({
130130
errors: 'string',
131-
skipObjectExtraFieldsCheck: true,
131+
skipObjectExtraKeysCheck: true,
132132
});
133133
console.log(validator2.toString());
134134

@@ -137,6 +137,6 @@ console.log('Can compile a fast validator, which returns objects as errors:');
137137
console.log();
138138
const validator3 = user.type.compileValidator({
139139
errors: 'object',
140-
skipObjectExtraFieldsCheck: true,
140+
skipObjectExtraKeysCheck: true,
141141
});
142142
console.log(validator3.toString());

src/__demos__/samples.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const types = {
4343
s.prop(
4444
'meta',
4545
s.Object([], {
46-
unknownFields: true,
46+
decodeUnknownKeys: true,
4747
}),
4848
),
4949
],

src/codegen/binary/__tests__/testBinaryCodegen.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ export const testBinaryCodegen = (transcode: (system: TypeSystem, type: Type, va
289289
const t = system.t;
290290
const type = t
291291
.Object(t.prop('id', t.str), t.propOpt('name', t.str), t.prop('age', t.num), t.propOpt('address', t.str))
292-
.options({encodeUnknownFields: true});
292+
.options({encodeUnknownKeys: true});
293293
const value: any = {
294294
id: 'xxxxx',
295295
name: 'Go Lang',
@@ -313,7 +313,7 @@ export const testBinaryCodegen = (transcode: (system: TypeSystem, type: Type, va
313313
t.Object(t.propOpt('hobbies', t.Array(t.str)), t.propOpt('sports', t.Array(t.Tuple([t.num, t.str])))),
314314
),
315315
)
316-
.options({encodeUnknownFields: true});
316+
.options({encodeUnknownKeys: true});
317317
const decoded = transcode(system, type, {
318318
id: 'xxxxx',
319319
name: 'Go Lang',
@@ -353,7 +353,7 @@ export const testBinaryCodegen = (transcode: (system: TypeSystem, type: Type, va
353353
const t = system.t;
354354
const type = t
355355
.Object(t.propOpt('id', t.str), t.propOpt('name', t.str), t.propOpt('address', t.str))
356-
.options({encodeUnknownFields: true});
356+
.options({encodeUnknownKeys: true});
357357
let value: any = {
358358
id: 'xxxxx',
359359
name: 'Go Lang',
@@ -380,7 +380,7 @@ export const testBinaryCodegen = (transcode: (system: TypeSystem, type: Type, va
380380
const t = system.t;
381381
const type = t
382382
.Object(t.propOpt('id', t.str), t.propOpt('name', t.str), t.propOpt('address', t.str))
383-
.options({encodeUnknownFields: false});
383+
.options({encodeUnknownKeys: false});
384384
let value: any = {
385385
id: 'xxxxx',
386386
name: 'Go Lang',
@@ -550,7 +550,7 @@ export const testBinaryCodegen = (transcode: (system: TypeSystem, type: Type, va
550550
test('supports "encodeUnknownFields" property', () => {
551551
const system = new TypeSystem();
552552
const t = system.t;
553-
const type = t.Object(t.prop('a', t.Object().options({encodeUnknownFields: true})));
553+
const type = t.Object(t.prop('a', t.Object().options({encodeUnknownKeys: true})));
554554
const value = {
555555
a: {
556556
foo: 123,
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import {AbstractBinaryCodegen} from '../AbstractBinaryCodegen';
2+
import {writer} from '../writer';
3+
import {JsExpression} from '@jsonjoy.com/codegen/lib/util/JsExpression';
4+
import {CborEncoder} from '@jsonjoy.com/json-pack/lib/cbor/CborEncoder';
5+
import {lazyKeyedFactory} from '../../util';
6+
import {ObjKeyOptType, type MapType, type ObjType, type Type} from '../../../type';
7+
import type {CompiledBinaryEncoder, SchemaPath} from '../../types';
8+
import {normalizeAccessor} from '@jsonjoy.com/codegen/lib/util/normalizeAccessor';
9+
10+
export class CborCodegen extends AbstractBinaryCodegen<CborEncoder> {
11+
public static readonly get = lazyKeyedFactory((type: Type, name?: string) => {
12+
const codegen = new CborCodegen(type, name);
13+
const r = codegen.codegen.options.args[0];
14+
const expression = new JsExpression(() => r);
15+
codegen.onNode([], expression, type);
16+
return codegen.compile();
17+
});
18+
19+
protected encoder = new CborEncoder(writer);
20+
21+
protected onObj(path: SchemaPath, value: JsExpression, type: ObjType): void {
22+
const codegen = this.codegen;
23+
const r = codegen.r();
24+
const fields = type.keys;
25+
const length = fields.length;
26+
const requiredFields = fields.filter((field) => !(field instanceof ObjKeyOptType));
27+
const optionalFields = fields.filter((field) => field instanceof ObjKeyOptType);
28+
const requiredLength = requiredFields.length;
29+
const optionalLength = optionalFields.length;
30+
const encodeUnknownFields = !!type.schema.encodeUnknownKeys;
31+
const emitRequiredFields = () => {
32+
for (let i = 0; i < requiredLength; i++) {
33+
const field = requiredFields[i];
34+
this.blob(this.gen((encoder) => encoder.writeStr(field.key)));
35+
const accessor = normalizeAccessor(field.key);
36+
this.onNode([...path, field.key], new JsExpression(() => `${r}${accessor}`), field.val);
37+
}
38+
};
39+
const emitOptionalFields = () => {
40+
for (let i = 0; i < optionalLength; i++) {
41+
const field = optionalFields[i];
42+
const accessor = normalizeAccessor(field.key);
43+
codegen.js(`if (${JSON.stringify(field.key)} in ${r}) {`);
44+
this.blob(this.gen((encoder) => encoder.writeStr(field.key)));
45+
this.onNode([...path, field.key], new JsExpression(() => `${r}${accessor}`), field.val);
46+
codegen.js(`}`);
47+
}
48+
};
49+
const emitUnknownFields = () => {
50+
const rKeys = codegen.r();
51+
const rKey = codegen.r();
52+
const ri = codegen.r();
53+
const rLength = codegen.r();
54+
const keys = fields.map((field) => JSON.stringify(field.key));
55+
const rKnownFields = codegen.addConstant(`new Set([${keys.join(',')}])`);
56+
codegen.js(`var ${rKeys} = Object.keys(${r}), ${rLength} = ${rKeys}.length, ${rKey};`);
57+
codegen.js(`for (var ${ri} = 0; ${ri} < ${rLength}; ${ri}++) {`);
58+
codegen.js(`${rKey} = ${rKeys}[${ri}];`);
59+
codegen.js(`if (${rKnownFields}.has(${rKey})) continue;`);
60+
codegen.js(`encoder.writeStr(${rKey});`);
61+
codegen.js(`encoder.writeAny(${r}[${rKey}]);`);
62+
codegen.js(`}`);
63+
};
64+
codegen.js(/* js */ `var ${r} = ${value.use()};`);
65+
if (!encodeUnknownFields && !optionalLength) {
66+
this.blob(this.gen((encoder) => encoder.writeObjHdr(length)));
67+
emitRequiredFields();
68+
} else if (!encodeUnknownFields) {
69+
this.blob(this.gen((encoder) => encoder.writeStartObj()));
70+
emitRequiredFields();
71+
emitOptionalFields();
72+
this.blob(this.gen((encoder) => encoder.writeEndObj()));
73+
} else {
74+
this.blob(this.gen((encoder) => encoder.writeStartObj()));
75+
emitRequiredFields();
76+
emitOptionalFields();
77+
emitUnknownFields();
78+
this.blob(this.gen((encoder) => encoder.writeEndObj()));
79+
}
80+
}
81+
82+
protected genEncoder(type: Type): CompiledBinaryEncoder {
83+
return CborCodegen.get(type);
84+
}
85+
}

src/codegen/binary/cbor/CborCodegen.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ export class CborCodegen extends AbstractBinaryCodegen<CborEncoder> {
2121
protected onObj(path: SchemaPath, value: JsExpression, type: ObjType): void {
2222
const codegen = this.codegen;
2323
const r = codegen.r();
24-
const fields = type.fields;
24+
const fields = type.keys;
2525
const length = fields.length;
2626
const requiredFields = fields.filter((field) => !(field instanceof ObjKeyOptType));
2727
const optionalFields = fields.filter((field) => field instanceof ObjKeyOptType);
2828
const requiredLength = requiredFields.length;
2929
const optionalLength = optionalFields.length;
30-
const encodeUnknownFields = !!type.schema.encodeUnknownFields;
30+
const encodeUnknownFields = !!type.schema.encodeUnknownKeys;
3131
const emitRequiredFields = () => {
3232
for (let i = 0; i < requiredLength; i++) {
3333
const field = requiredFields[i];

src/codegen/binary/cbor/__tests__/fuzzing.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const encoder = new CborEncoder(new Writer(16));
99
const decoder = new CborDecoder();
1010

1111
test('can encode random values', () => {
12-
for (let i = 0; i < 100; i++) {
12+
for (let i = 0; i < 10; i++) {
1313
const json = randomJson();
1414
const t = new TypeBuilder();
1515
const type = t.from(json);

src/codegen/binary/json/JsonCodegen.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,12 @@ export class JsonCodegen extends AbstractBinaryCodegen<JsonEncoder> {
9797
protected onObj(path: SchemaPath, value: JsExpression, type: ObjType): void {
9898
const codegen = this.codegen;
9999
const r = codegen.var(value.use());
100-
const fields = type.fields;
100+
const fields = type.keys;
101101
const requiredFields = fields.filter((field) => !(field instanceof ObjKeyOptType));
102102
const optionalFields = fields.filter((field) => field instanceof ObjKeyOptType);
103103
const requiredLength = requiredFields.length;
104104
const optionalLength = optionalFields.length;
105-
const encodeUnknownFields = !!type.schema.encodeUnknownFields;
105+
const encodeUnknownFields = !!type.schema.encodeUnknownKeys;
106106
const separatorBlob = this.gen((encoder) => encoder.writeObjSeparator());
107107
const keySeparatorBlob = this.gen((encoder) => encoder.writeObjKeySeparator());
108108
const endBlob = this.gen((encoder) => encoder.writeEndObj());

src/codegen/binary/msgpack/MsgPackCodegen.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ export class MsgPackCodegen extends AbstractBinaryCodegen<MsgPackEncoder> {
2121
protected onObj(path: SchemaPath, value: JsExpression, type: ObjType): void {
2222
const codegen = this.codegen;
2323
const r = codegen.r();
24-
const fields = type.fields;
24+
const fields = type.keys;
2525
const length = fields.length;
2626
const requiredFields = fields.filter((field) => !(field instanceof ObjKeyOptType));
2727
const optionalFields = fields.filter((field) => field instanceof ObjKeyOptType);
2828
const requiredLength = requiredFields.length;
2929
const optionalLength = optionalFields.length;
3030
const totalMaxKnownFields = requiredLength + optionalLength;
3131
if (totalMaxKnownFields > 0xffff) throw new Error('Too many fields');
32-
const encodeUnknownFields = !!type.schema.encodeUnknownFields;
32+
const encodeUnknownFields = !!type.schema.encodeUnknownKeys;
3333
const rFieldCount = codegen.r();
3434
const emitRequiredFields = () => {
3535
for (let i = 0; i < requiredLength; i++) {

0 commit comments

Comments
 (0)