Skip to content

Commit b1a901e

Browse files
committed
feat: schema
schema generator wip checkpoint: schema codegen compiles in typescript feat: scaffold schema types wip: codec/protocol/transport operation schema
1 parent bb4f6ff commit b1a901e

File tree

81 files changed

+5796
-129
lines changed

Some content is hidden

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

81 files changed

+5796
-129
lines changed

.changeset/nice-deers-shake.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@smithy/smithy-client": minor
3+
"@smithy/types": minor
4+
"@smithy/core": minor
5+
---
6+
7+
implement schema framework

packages/core/package.json

+10
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@
4646
"require": "./dist-cjs/submodules/protocols/index.js",
4747
"types": "./dist-types/submodules/protocols/index.d.ts"
4848
},
49+
"./schema": {
50+
"module": "./dist-es/submodules/schema/index.js",
51+
"node": "./dist-cjs/submodules/schema/index.js",
52+
"import": "./dist-es/submodules/schema/index.js",
53+
"require": "./dist-cjs/submodules/schema/index.js",
54+
"types": "./dist-types/submodules/schema/index.d.ts"
55+
},
4956
"./serde": {
5057
"module": "./dist-es/submodules/serde/index.js",
5158
"node": "./dist-cjs/submodules/serde/index.js",
@@ -64,6 +71,7 @@
6471
"@smithy/middleware-serde": "workspace:^",
6572
"@smithy/protocol-http": "workspace:^",
6673
"@smithy/types": "workspace:^",
74+
"@smithy/util-base64": "workspace:^",
6775
"@smithy/util-body-length-browser": "workspace:^",
6876
"@smithy/util-middleware": "workspace:^",
6977
"@smithy/util-stream": "workspace:^",
@@ -85,6 +93,8 @@
8593
"./cbor.js",
8694
"./protocols.d.ts",
8795
"./protocols.js",
96+
"./schema.d.ts",
97+
"./schema.js",
8898
"./serde.d.ts",
8999
"./serde.js",
90100
"dist-*/**"

packages/core/schema.d.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Do not edit:
3+
* This is a compatibility redirect for contexts that do not understand package.json exports field.
4+
*/
5+
declare module "@smithy/core/schema" {
6+
export * from "@smithy/core/dist-types/submodules/schema/index.d";
7+
}

packages/core/schema.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
/**
3+
* Do not edit:
4+
* This is a compatibility redirect for contexts that do not understand package.json exports field.
5+
*/
6+
module.exports = require("./dist-cjs/submodules/schema/index.js");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import { deref, ListSchema, MapSchema, StructureSchema } from "@smithy/core/schema";
2+
import { copyDocumentWithTransform, parseEpochTimestamp } from "@smithy/core/serde";
3+
import {
4+
Codec,
5+
MemberSchema,
6+
Schema,
7+
SchemaRef,
8+
SerdeContext,
9+
ShapeDeserializer,
10+
ShapeSerializer,
11+
TraitsSchema,
12+
} from "@smithy/types";
13+
14+
import { cbor } from "./cbor";
15+
import { dateToTag } from "./parseCborBody";
16+
17+
export class CborCodec implements Codec<Uint8Array, Uint8Array> {
18+
private serdeContext?: SerdeContext;
19+
20+
public createSerializer(): CborShapeSerializer {
21+
const serializer = new CborShapeSerializer();
22+
serializer.setSerdeContext(this.serdeContext!);
23+
return serializer;
24+
}
25+
public createDeserializer(): CborShapeDeserializer {
26+
const deserializer = new CborShapeDeserializer();
27+
deserializer.setSerdeContext(this.serdeContext!);
28+
return deserializer;
29+
}
30+
31+
public setSerdeContext(serdeContext: SerdeContext): void {
32+
this.serdeContext = serdeContext;
33+
}
34+
}
35+
36+
export class CborShapeSerializer implements ShapeSerializer<Uint8Array> {
37+
private serdeContext?: SerdeContext;
38+
private value: unknown;
39+
40+
public setSerdeContext(serdeContext: SerdeContext) {
41+
this.serdeContext = serdeContext;
42+
}
43+
44+
public write(schema: Schema, value: unknown): void {
45+
this.value = copyDocumentWithTransform(value, schema, (_: any, schemaRef: SchemaRef) => {
46+
if (_ instanceof Date) {
47+
return dateToTag(_);
48+
}
49+
const schema = deref((schemaRef as MemberSchema)?.[0] ?? schemaRef);
50+
if (_ instanceof Uint8Array) {
51+
return _;
52+
}
53+
const sparse = (schema as TraitsSchema)?.traits?.sparse;
54+
if (Array.isArray(_)) {
55+
if (!sparse) {
56+
return _.filter((item) => item != null);
57+
}
58+
} else if (_ && typeof _ === "object") {
59+
if (!sparse) {
60+
for (const [k, v] of Object.entries(_)) {
61+
if (v == null) {
62+
delete _[k];
63+
}
64+
}
65+
return _;
66+
}
67+
}
68+
return _;
69+
});
70+
}
71+
72+
public flush(): Uint8Array {
73+
const buffer = cbor.serialize(this.value);
74+
this.value = undefined;
75+
return buffer as Uint8Array;
76+
}
77+
}
78+
79+
export class CborShapeDeserializer implements ShapeDeserializer {
80+
private serdeContext?: SerdeContext;
81+
82+
public setSerdeContext(serdeContext: SerdeContext) {
83+
this.serdeContext = serdeContext;
84+
}
85+
86+
public read(schema: Schema, bytes: Uint8Array): any {
87+
const data: any = cbor.deserialize(bytes);
88+
return this.readValue(schema, data);
89+
}
90+
91+
private readValue(schema: Schema, value: any): any {
92+
if (typeof schema === "string") {
93+
if (schema === "time" || schema === "epoch-seconds" || schema === "date-time") {
94+
return parseEpochTimestamp(value);
95+
}
96+
if (schema === "blob" || schema === "streaming-blob") {
97+
return value;
98+
}
99+
}
100+
switch (typeof value) {
101+
case "undefined":
102+
case "boolean":
103+
case "number":
104+
case "string":
105+
case "bigint":
106+
case "symbol":
107+
return value;
108+
case "function":
109+
case "object":
110+
if (value === null) {
111+
return null;
112+
}
113+
if ("byteLength" in (value as Uint8Array)) {
114+
return value;
115+
}
116+
if (value instanceof Date) {
117+
return value;
118+
}
119+
const traits =
120+
Array.isArray(schema) && schema.length >= 2
121+
? {
122+
...(deref((schema as MemberSchema)[0]) as TraitsSchema)?.traits,
123+
...(schema as MemberSchema)[1],
124+
}
125+
: (deref(schema) as TraitsSchema)?.traits;
126+
127+
if (Array.isArray(value)) {
128+
const newArray = [];
129+
for (const item of value) {
130+
newArray.push(this.readValue(schema instanceof ListSchema ? deref(schema.valueSchema) : void 0, item));
131+
if (!traits?.sparse) {
132+
if (newArray[newArray.length - 1] == null) {
133+
newArray.pop();
134+
}
135+
}
136+
}
137+
return newArray;
138+
}
139+
140+
const newObject = {} as any;
141+
for (const key of Object.keys(value)) {
142+
const targetSchema =
143+
schema instanceof StructureSchema
144+
? deref(schema.members[key]?.[0])
145+
: schema instanceof MapSchema
146+
? deref(schema.valueSchema)
147+
: void 0;
148+
newObject[key] = this.readValue(targetSchema, value[key]);
149+
if (!traits?.sparse && newObject[key] == null) {
150+
delete newObject[key];
151+
}
152+
}
153+
return newObject;
154+
default:
155+
return value;
156+
}
157+
}
158+
}

0 commit comments

Comments
 (0)