Skip to content

Commit 82198a7

Browse files
committed
chore: schema code size optimization
1 parent b2c8dfa commit 82198a7

File tree

17 files changed

+266
-324
lines changed

17 files changed

+266
-324
lines changed

.changeset/pink-items-shake.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@smithy/types": minor
3+
"@smithy/core": minor
4+
---
5+
6+
schema code size optimizations

packages/core/src/submodules/protocols/HttpBindingProtocol.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ describe(HttpBindingProtocol.name, () => {
6464
const response = new HttpResponse({
6565
statusCode: 200,
6666
headers: {
67-
"x-timestamplist": "Mon, 16 Dec 2019 23:48:18 GMT, Mon, 16 Dec 2019 23:48:18 GMT",
67+
"x-timestamplist": "Mon, 16 Nov 2019 23:48:18 GMT, Mon, 16 Dec 2019 23:48:18 GMT",
6868
},
6969
});
7070

@@ -95,7 +95,7 @@ describe(HttpBindingProtocol.name, () => {
9595
)) as Partial<MetadataBearer>;
9696
delete output.$metadata;
9797
expect(output).toEqual({
98-
timestampList: [new Date("2019-12-16T23:48:18.000Z"), new Date("2019-12-16T23:48:18.000Z")],
98+
timestampList: [new Date("2019-11-16T23:48:18.000Z"), new Date("2019-12-16T23:48:18.000Z")],
9999
});
100100
});
101101

packages/core/src/submodules/protocols/HttpBindingProtocol.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -157,20 +157,15 @@ export abstract class HttpBindingProtocol extends HttpProtocol {
157157
if (traits.httpQueryParams) {
158158
for (const [key, val] of Object.entries(data)) {
159159
if (!(key in query)) {
160-
this.serializeQuery(
161-
NormalizedSchema.of([
162-
ns.getValueSchema(),
163-
{
164-
// We pass on the traits to the sub-schema
165-
// because we are still in the process of serializing the map itself.
166-
...traits,
167-
httpQuery: key,
168-
httpQueryParams: undefined,
169-
},
170-
]),
171-
val,
172-
query
173-
);
160+
const valueSchema = ns.getValueSchema();
161+
Object.assign(valueSchema.getMergedTraits(), {
162+
// We pass on the traits to the sub-schema
163+
// because we are still in the process of serializing the map itself.
164+
...traits,
165+
httpQuery: key,
166+
httpQueryParams: undefined,
167+
});
168+
this.serializeQuery(valueSchema, val, query);
174169
}
175170
}
176171
return;
@@ -305,6 +300,7 @@ export abstract class HttpBindingProtocol extends HttpProtocol {
305300
if (null != value) {
306301
if (memberSchema.isListSchema()) {
307302
const headerListValueSchema = memberSchema.getValueSchema();
303+
headerListValueSchema.getMergedTraits().httpHeader = key;
308304
let sections: string[];
309305
if (
310306
headerListValueSchema.isTimestampSchema() &&
@@ -316,7 +312,7 @@ export abstract class HttpBindingProtocol extends HttpProtocol {
316312
}
317313
const list = [];
318314
for (const section of sections) {
319-
list.push(await deserializer.read([headerListValueSchema, { httpHeader: key }], section.trim()));
315+
list.push(await deserializer.read(headerListValueSchema, section.trim()));
320316
}
321317
dataObject[memberName] = list;
322318
} else {
@@ -327,8 +323,10 @@ export abstract class HttpBindingProtocol extends HttpProtocol {
327323
dataObject[memberName] = {};
328324
for (const [header, value] of Object.entries(response.headers)) {
329325
if (header.startsWith(memberTraits.httpPrefixHeaders)) {
326+
const valueSchema = memberSchema.getValueSchema();
327+
valueSchema.getMergedTraits().httpHeader = header;
330328
dataObject[memberName][header.slice(memberTraits.httpPrefixHeaders.length)] = await deserializer.read(
331-
[memberSchema.getValueSchema(), { httpHeader: header }],
329+
valueSchema,
332330
value
333331
);
334332
}

packages/core/src/submodules/protocols/serde/FromStringShapeDeserializer.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,18 @@ export class FromStringShapeDeserializer implements ShapeDeserializer<string> {
2929

3030
public read(_schema: Schema, data: string): any {
3131
const ns = NormalizedSchema.of(_schema);
32+
3233
if (ns.isListSchema()) {
3334
return splitHeader(data).map((item) => this.read(ns.getValueSchema(), item));
3435
}
36+
3537
if (ns.isBlobSchema()) {
3638
return (this.serdeContext?.base64Decoder ?? fromBase64)(data);
3739
}
40+
3841
if (ns.isTimestampSchema()) {
3942
const format = determineTimestampFormat(ns, this.settings);
43+
4044
switch (format) {
4145
case SCHEMA.TIMESTAMP_DATE_TIME:
4246
return parseRfc3339DateTimeWithOffset(data);

packages/core/src/submodules/protocols/serde/determineTimestampFormat.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@ export function determineTimestampFormat(
2929
}
3030

3131
const { httpLabel, httpPrefixHeaders, httpHeader, httpQuery } = ns.getMergedTraits();
32+
3233
const bindingFormat = settings.httpBindings
3334
? typeof httpPrefixHeaders === "string" || Boolean(httpHeader)
3435
? SCHEMA.TIMESTAMP_HTTP_DATE
3536
: Boolean(httpQuery) || Boolean(httpLabel)
36-
? SCHEMA.TIMESTAMP_DATE_TIME
37-
: undefined
37+
? SCHEMA.TIMESTAMP_DATE_TIME
38+
: undefined
3839
: undefined;
3940

4041
return bindingFormat ?? settings.timestampFormat.default;
Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { SchemaRef, SchemaTraits } from "@smithy/types";
22

33
import { TypeRegistry } from "../TypeRegistry";
4+
import { Schema } from "./Schema";
45
import { StructureSchema } from "./StructureSchema";
56

67
/**
@@ -12,30 +13,9 @@ import { StructureSchema } from "./StructureSchema";
1213
* @alpha
1314
*/
1415
export class ErrorSchema extends StructureSchema {
15-
public static symbol = Symbol.for("@smithy/core/schema::ErrorSchema");
16-
protected symbol = ErrorSchema.symbol;
17-
18-
public constructor(
19-
public name: string,
20-
public traits: SchemaTraits,
21-
public memberNames: string[],
22-
public memberList: SchemaRef[],
23-
/**
24-
* Constructor for a modeled service exception class that extends Error.
25-
*/
26-
public ctor: any
27-
) {
28-
super(name, traits, memberNames, memberList);
29-
}
30-
31-
public static [Symbol.hasInstance](lhs: unknown): lhs is ErrorSchema {
32-
const isPrototype = ErrorSchema.prototype.isPrototypeOf(lhs as any);
33-
if (!isPrototype && typeof lhs === "object" && lhs !== null) {
34-
const err = lhs as ErrorSchema;
35-
return err.symbol === ErrorSchema.symbol;
36-
}
37-
return isPrototype;
38-
}
16+
public static readonly symbol = Symbol.for("@smithy/err");
17+
public ctor!: any;
18+
protected readonly symbol = ErrorSchema.symbol;
3919
}
4020

4121
/**
@@ -50,15 +30,19 @@ export class ErrorSchema extends StructureSchema {
5030
* @param memberList - list of schemaRef corresponding to each
5131
* @param ctor - class reference for the existing Error extending class.
5232
*/
53-
export function error(
33+
export const error = (
5434
namespace: string,
5535
name: string,
56-
traits: SchemaTraits = {},
36+
traits: SchemaTraits,
5737
memberNames: string[],
5838
memberList: SchemaRef[],
5939
ctor: any
60-
): ErrorSchema {
61-
const schema = new ErrorSchema(namespace + "#" + name, traits, memberNames, memberList, ctor);
62-
TypeRegistry.for(namespace).register(name, schema);
63-
return schema;
64-
}
40+
): ErrorSchema =>
41+
Schema.assign(new ErrorSchema(), {
42+
name,
43+
namespace,
44+
traits,
45+
memberNames,
46+
memberList,
47+
ctor,
48+
});
Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { ListSchema as IListSchema, SchemaRef, SchemaTraits } from "@smithy/types";
22

3-
import { TypeRegistry } from "../TypeRegistry";
43
import { Schema } from "./Schema";
54

65
/**
@@ -10,38 +9,22 @@ import { Schema } from "./Schema";
109
* @alpha
1110
*/
1211
export class ListSchema extends Schema implements IListSchema {
13-
public static symbol = Symbol.for("@smithy/core/schema::ListSchema");
14-
protected symbol = ListSchema.symbol;
15-
16-
public constructor(
17-
public name: string,
18-
public traits: SchemaTraits,
19-
public valueSchema: SchemaRef
20-
) {
21-
super(name, traits);
22-
}
23-
24-
public static [Symbol.hasInstance](lhs: unknown): lhs is ListSchema {
25-
const isPrototype = ListSchema.prototype.isPrototypeOf(lhs as any);
26-
if (!isPrototype && typeof lhs === "object" && lhs !== null) {
27-
const list = lhs as ListSchema;
28-
return list.symbol === ListSchema.symbol;
29-
}
30-
return isPrototype;
31-
}
12+
public static readonly symbol = Symbol.for("@smithy/lis");
13+
public name!: string;
14+
public traits!: SchemaTraits;
15+
public valueSchema!: SchemaRef;
16+
protected readonly symbol = ListSchema.symbol;
3217
}
3318

3419
/**
3520
* Factory for ListSchema.
3621
*
3722
* @internal
3823
*/
39-
export function list(namespace: string, name: string, traits: SchemaTraits = {}, valueSchema: SchemaRef): ListSchema {
40-
const schema = new ListSchema(
41-
namespace + "#" + name,
24+
export const list = (namespace: string, name: string, traits: SchemaTraits, valueSchema: SchemaRef): ListSchema =>
25+
Schema.assign(new ListSchema(), {
26+
name,
27+
namespace,
4228
traits,
43-
typeof valueSchema === "function" ? valueSchema() : valueSchema
44-
);
45-
TypeRegistry.for(namespace).register(name, schema);
46-
return schema;
47-
}
29+
valueSchema,
30+
});
Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,38 @@
11
import type { MapSchema as IMapSchema, SchemaRef, SchemaTraits } from "@smithy/types";
22

3-
import { TypeRegistry } from "../TypeRegistry";
43
import { Schema } from "./Schema";
54

65
/**
76
* A schema with a key schema and value schema.
87
* @alpha
98
*/
109
export class MapSchema extends Schema implements IMapSchema {
11-
public static symbol = Symbol.for("@smithy/core/schema::MapSchema");
12-
protected symbol = MapSchema.symbol;
13-
14-
public constructor(
15-
public name: string,
16-
public traits: SchemaTraits,
17-
/**
18-
* This is expected to be StringSchema, but may have traits.
19-
*/
20-
public keySchema: SchemaRef,
21-
public valueSchema: SchemaRef
22-
) {
23-
super(name, traits);
24-
}
25-
26-
public static [Symbol.hasInstance](lhs: unknown): lhs is MapSchema {
27-
const isPrototype = MapSchema.prototype.isPrototypeOf(lhs as any);
28-
if (!isPrototype && typeof lhs === "object" && lhs !== null) {
29-
const map = lhs as MapSchema;
30-
return map.symbol === MapSchema.symbol;
31-
}
32-
return isPrototype;
33-
}
10+
public static readonly symbol = Symbol.for("@smithy/map");
11+
public name!: string;
12+
public traits!: SchemaTraits;
13+
/**
14+
* This is expected to be StringSchema, but may have traits.
15+
*/
16+
public keySchema!: SchemaRef;
17+
public valueSchema!: SchemaRef;
18+
protected readonly symbol = MapSchema.symbol;
3419
}
3520

3621
/**
3722
* Factory for MapSchema.
3823
* @internal
3924
*/
40-
export function map(
25+
export const map = (
4126
namespace: string,
4227
name: string,
43-
traits: SchemaTraits = {},
28+
traits: SchemaTraits,
4429
keySchema: SchemaRef,
4530
valueSchema: SchemaRef
46-
): MapSchema {
47-
const schema = new MapSchema(
48-
namespace + "#" + name,
31+
): MapSchema =>
32+
Schema.assign(new MapSchema(), {
33+
name,
34+
namespace,
4935
traits,
5036
keySchema,
51-
typeof valueSchema === "function" ? valueSchema() : valueSchema
52-
);
53-
TypeRegistry.for(namespace).register(name, schema);
54-
return schema;
55-
}
37+
valueSchema,
38+
});

packages/core/src/submodules/schema/schemas/NormalizedSchema.spec.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { MemberSchema } from "@smithy/types";
1+
import type { MemberSchema, StructureSchema } from "@smithy/types";
22
import { describe, expect, test as it } from "vitest";
33

44
import { list } from "./ListSchema";
@@ -12,8 +12,8 @@ describe(NormalizedSchema.name, () => {
1212
const [List, Map, Struct] = [list("ack", "List", { sparse: 1 }, 0), map("ack", "Map", 0, 0, 1), () => schema];
1313
const schema = struct("ack", "Structure", {}, ["list", "map", "struct"], [List, Map, Struct]);
1414

15-
const ns = new NormalizedSchema(() => schema);
16-
const nsFromIndirect = NormalizedSchema.of([() => ns, 0]);
15+
const ns = NormalizedSchema.of(schema);
16+
const nsFromIndirect = NormalizedSchema.of(() => ns);
1717

1818
it("has a static constructor", () => {
1919
expect(NormalizedSchema.of(ns)).toBeInstanceOf(NormalizedSchema);
@@ -105,7 +105,15 @@ describe(NormalizedSchema.name, () => {
105105
expect(NormalizedSchema.of(SCHEMA.BIG_INTEGER).isBigIntegerSchema()).toBe(true);
106106
expect(NormalizedSchema.of(SCHEMA.BIG_DECIMAL).isBigDecimalSchema()).toBe(true);
107107
expect(NormalizedSchema.of(SCHEMA.STREAMING_BLOB).isStreaming()).toBe(true);
108-
expect(NormalizedSchema.of([ns, { streaming: 1 }]).isStreaming()).toBe(true);
108+
109+
const structWithStreamingMember = struct(
110+
"ack",
111+
"StructWithStreamingMember",
112+
0,
113+
["m"],
114+
[sim("ns", "blob", SCHEMA.BLOB, { streaming: 1 })]
115+
);
116+
expect(NormalizedSchema.of(structWithStreamingMember).getMemberSchema("m").isStreaming()).toBe(true);
109117
});
110118

111119
describe("list member", () => {
@@ -184,8 +192,8 @@ describe(NormalizedSchema.name, () => {
184192

185193
describe("iteration", () => {
186194
it("iterates over member schemas", () => {
187-
const iteration = Array.from(ns.structIterator());
188-
const entries = Object.entries(ns.getMemberSchemas());
195+
const iteration = Array.from(ns.structIterator()) as [string, NormalizedSchema][];
196+
const entries = Object.entries(ns.getMemberSchemas()) as [string, NormalizedSchema][];
189197
for (let i = 0; i < iteration.length; i++) {
190198
const [name, schema] = iteration[i];
191199
const [entryName, entrySchema] = entries[i];
@@ -203,7 +211,9 @@ describe(NormalizedSchema.name, () => {
203211

204212
describe("traits", () => {
205213
const member: MemberSchema = [sim("ack", "SimpleString", 0, { idempotencyToken: 1 }), 0b0000_0001];
206-
const ns = NormalizedSchema.of(member, "member_name");
214+
const container: StructureSchema = struct("ack", "Container", 0, ["member_name"], [member, 0]);
215+
216+
const ns = NormalizedSchema.of(container).getMemberSchema("member_name");
207217

208218
it("has merged traits", () => {
209219
expect(ns.getMergedTraits()).toEqual({

0 commit comments

Comments
 (0)