diff --git a/.changeset/good-students-play.md b/.changeset/good-students-play.md new file mode 100644 index 00000000000..8b799152678 --- /dev/null +++ b/.changeset/good-students-play.md @@ -0,0 +1,7 @@ +--- +"@smithy/smithy-client": minor +"@smithy/types": minor +"@smithy/core": minor +--- + +remove usage of non-static schema classes diff --git a/packages/core/src/submodules/cbor/CborCodec.spec.ts b/packages/core/src/submodules/cbor/CborCodec.spec.ts index d16134af89d..2fbd138a289 100644 --- a/packages/core/src/submodules/cbor/CborCodec.spec.ts +++ b/packages/core/src/submodules/cbor/CborCodec.spec.ts @@ -1,4 +1,5 @@ -import { NormalizedSchema, sim, struct } from "@smithy/core/schema"; +import { NormalizedSchema } from "@smithy/core/schema"; +import type { StaticSimpleSchema, StaticStructureSchema, StringSchema } from "@smithy/types"; import { describe, expect, it } from "vitest"; import { cbor } from "./cbor"; @@ -10,14 +11,14 @@ describe(CborShapeSerializer.name, () => { const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; const idempotencyTokenSchemas = [ - NormalizedSchema.of(sim("", "StringWithTraits", 0, 0b0100)), - NormalizedSchema.of(sim("", "StringWithTraits", 0, { idempotencyToken: 1 })), + NormalizedSchema.of([0, "", "StringWithTraits", 0b0100, 0] satisfies StaticSimpleSchema), + NormalizedSchema.of([0, "", "StringWithTraits", { idempotencyToken: 1 }, 0] satisfies StaticSimpleSchema), ]; const plainSchemas = [ - NormalizedSchema.of(0), - NormalizedSchema.of(sim("", "StringWithTraits", 0, 0)), - NormalizedSchema.of(sim("", "StringWithTraits", 0, {})), + NormalizedSchema.of(0 satisfies StringSchema), + NormalizedSchema.of([0, "", "StringWithTraits", 0, 0] satisfies StaticSimpleSchema), + NormalizedSchema.of([0, "", "StringWithTraits", {}, 0] satisfies StaticSimpleSchema), ]; const serializer = codec.createSerializer(); @@ -26,13 +27,14 @@ describe(CborShapeSerializer.name, () => { it("should generate an idempotency token when the input for such a member is undefined", () => { for (const idempotencyTokenSchema of idempotencyTokenSchemas) { for (const plainSchema of plainSchemas) { - const objectSchema = struct( + const objectSchema = [ + 3, "ns", "StructWithIdempotencyToken", 0, ["idempotencyToken", "plainString", "memberTraitToken"], - [idempotencyTokenSchema, plainSchema, [() => plainSchema, 0b0100]] - ); + [idempotencyTokenSchema, plainSchema, [() => plainSchema, 0b0100]], + ] satisfies StaticStructureSchema; serializer.write(objectSchema, { idempotencyToken: undefined, diff --git a/packages/core/src/submodules/cbor/SmithyRpcV2CborProtocol.spec.ts b/packages/core/src/submodules/cbor/SmithyRpcV2CborProtocol.spec.ts index 3b7efc7f6fe..1f2e2bb59a9 100644 --- a/packages/core/src/submodules/cbor/SmithyRpcV2CborProtocol.spec.ts +++ b/packages/core/src/submodules/cbor/SmithyRpcV2CborProtocol.spec.ts @@ -1,14 +1,16 @@ -import { error, list, map, op, SCHEMA, struct, TypeRegistry } from "@smithy/core/schema"; +import { op, TypeRegistry } from "@smithy/core/schema"; import { HttpRequest, HttpResponse } from "@smithy/protocol-http"; import type { + $SchemaRef, BlobSchema, BooleanSchema, MapSchemaModifier, NumericSchema, ResponseMetadata, RetryableTrait, - SchemaRef, StaticErrorSchema, + StaticOperationSchema, + StaticStructureSchema, StringSchema, TimestampDefaultSchema, } from "@smithy/types"; @@ -24,7 +26,7 @@ describe(SmithyRpcV2CborProtocol.name, () => { describe("serialization", () => { const testCases: Array<{ name: string; - schema: SchemaRef; + schema: $SchemaRef; input: any; expected: { request: any; @@ -33,7 +35,8 @@ describe(SmithyRpcV2CborProtocol.name, () => { }> = [ { name: "document with timestamp and blob", - schema: struct( + schema: [ + 3, "", "MyExtendedDocument", {}, @@ -41,8 +44,8 @@ describe(SmithyRpcV2CborProtocol.name, () => { [ [4 satisfies TimestampDefaultSchema, 0], [21 satisfies BlobSchema, 0], - ] - ), + ], + ], input: { bool: true, int: 5, @@ -60,7 +63,8 @@ describe(SmithyRpcV2CborProtocol.name, () => { }, { name: "do not write to header or query", - schema: struct( + schema: [ + 3, "", "MyExtendedDocument", {}, @@ -71,8 +75,8 @@ describe(SmithyRpcV2CborProtocol.name, () => { [21 satisfies BlobSchema, { httpHeader: "blob" }], [(128 satisfies MapSchemaModifier) | (0 satisfies StringSchema), { httpPrefixHeaders: "anti-" }], [(128 satisfies MapSchemaModifier) | (0 satisfies StringSchema), { httpQueryParams: 1 }], - ] - ), + ], + ], input: { bool: true, timestamp: new Date(1_000_000), @@ -108,18 +112,19 @@ describe(SmithyRpcV2CborProtocol.name, () => { }, { name: "sparse list and map", - schema: struct( + schema: [ + 3, "", "MyShape", 0, ["mySparseList", "myRegularList", "mySparseMap", "myRegularMap"], [ - [() => list("", "MySparseList", { sparse: 1 }, 1 satisfies NumericSchema), {}], - [() => list("", "MyList", {}, 1 satisfies NumericSchema), {}], - [() => map("", "MySparseMap", { sparse: 1 }, 0 satisfies StringSchema, 1 satisfies NumericSchema), {}], - [() => map("", "MyMap", {}, 0 satisfies StringSchema, 1 satisfies NumericSchema), {}], - ] - ), + [() => [1, "", "MySparseList", { sparse: 1 }, 1 satisfies NumericSchema], {}], + [() => [1, "", "MyList", {}, 1 satisfies NumericSchema], {}], + [() => [2, "", "MySparseMap", { sparse: 1 }, 0 satisfies StringSchema, 1 satisfies NumericSchema], {}], + [() => [2, "", "MyMap", {}, 0 satisfies StringSchema, 1 satisfies NumericSchema], {}], + ], + ], input: { mySparseList: [null, 1, null, 2, null], myRegularList: [null, 1, null, 2, null], @@ -211,18 +216,19 @@ describe(SmithyRpcV2CborProtocol.name, () => { const testCases = [ { name: "sparse list and map", - schema: struct( + schema: [ + 3, "", "MyShape", 0, ["mySparseList", "myRegularList", "mySparseMap", "myRegularMap"], [ - [() => list("", "MyList", { sparse: 1 }, 1 satisfies NumericSchema), {}], - [() => list("", "MyList", {}, 1 satisfies NumericSchema), {}], - [() => map("", "MyMap", { sparse: 1 }, 0 satisfies StringSchema, 1 satisfies NumericSchema), {}], - [() => map("", "MyMap", {}, 0 satisfies StringSchema, 1 satisfies NumericSchema), {}], - ] - ), + [() => [1, "", "MyList", { sparse: 1 }, 1 satisfies NumericSchema], {}], + [() => [1, "", "MyList", {}, 1 satisfies NumericSchema], {}], + [() => [2, "", "MyMap", { sparse: 1 }, 0 satisfies StringSchema, 1 satisfies NumericSchema], {}], + [() => [2, "", "MyMap", {}, 0 satisfies StringSchema, 1 satisfies NumericSchema], {}], + ], + ] satisfies StaticStructureSchema, mockOutput: { mySparseList: [null, 1, null, 2, null], myRegularList: [null, 1, null, 2, null], @@ -290,12 +296,21 @@ describe(SmithyRpcV2CborProtocol.name, () => { describe("error handling", () => { const protocol = new SmithyRpcV2CborProtocol({ defaultNamespace: "ns" }); - const operation = op( + const staticOperation = [ + 9, "ns", "OperationWithModeledException", {}, - struct("ns", "Input", 0, [], []), - struct("ns", "Output", 0, [], []) + [3, "ns", "Input", 0, [], []], + [3, "ns", "Output", 0, [], []], + ] satisfies StaticOperationSchema; + + const operation = op( + staticOperation[1], + staticOperation[2], + staticOperation[3], + staticOperation[4], + staticOperation[5] ); const errorResponse = new HttpResponse({ diff --git a/packages/core/src/submodules/event-streams/EventStreamSerde.spec.ts b/packages/core/src/submodules/event-streams/EventStreamSerde.spec.ts index 044554caea7..c3b5952689d 100644 --- a/packages/core/src/submodules/event-streams/EventStreamSerde.spec.ts +++ b/packages/core/src/submodules/event-streams/EventStreamSerde.spec.ts @@ -1,10 +1,12 @@ import { cbor, CborCodec, dateToTag } from "@smithy/core/cbor"; -import { NormalizedSchema, sim, struct } from "@smithy/core/schema"; +import { NormalizedSchema } from "@smithy/core/schema"; import { EventStreamMarshaller } from "@smithy/eventstream-serde-node"; import { HttpResponse } from "@smithy/protocol-http"; import type { BlobSchema, Message as EventMessage, + StaticSimpleSchema, + StaticStructureSchema, StreamingBlobSchema, StringSchema, TimestampEpochSecondsSchema, @@ -44,49 +46,65 @@ describe(EventStreamSerde.name, () => { defaultContentType: impl.getDefaultContentType(), }); - const eventStreamUnionSchema = struct( + const eventStreamUnionSchema = [ + 3, "ns", "EventStreamStructure", { streaming: 1 }, ["A", "B", "C", "Payload", "TextPayload", "CustomHeaders"], // D is omitted to represent an unknown event. [ - struct("ns", "A", 0, ["name"], [0]), - struct("ns", "B", 0, ["name"], [0]), - struct("ns", "C", 0, ["name"], [0]), - struct( + [3, "ns", "A", 0, ["name"], [0]] satisfies StaticStructureSchema, + [3, "ns", "B", 0, ["name"], [0]] satisfies StaticStructureSchema, + [3, "ns", "C", 0, ["name"], [0]] satisfies StaticStructureSchema, + [ + 3, "ns", "Payload", 0, ["payload"], - [sim("ns", "StreamingBlobPayload", 42 satisfies StreamingBlobSchema, { eventPayload: 1 })] - ), - struct( + [ + [ + 0, + "ns", + "StreamingBlobPayload", + { eventPayload: 1 }, + 42 satisfies StreamingBlobSchema, + ] satisfies StaticSimpleSchema, + ], + ], + [ + 3, "ns", "TextPayload", 0, ["payload"], - [sim("ns", "TextPayload", 0 satisfies StringSchema, { eventPayload: 1 })] - ), - struct( + [[0, "ns", "TextPayload", { eventPayload: 1 }, 0 satisfies StringSchema] satisfies StaticSimpleSchema], + ], + [ + 3, "ns", "CustomHeaders", 0, ["header1", "header2"], - [sim("ns", "EventHeader", 0, { eventHeader: 1 }), sim("ns", "EventHeader", 0, { eventHeader: 1 })] - ), - ] - ); + [ + [0, "ns", "EventHeader", { eventHeader: 1 }, 0 satisfies StringSchema] satisfies StaticSimpleSchema, + [0, "ns", "EventHeader", { eventHeader: 1 }, 0 satisfies StringSchema] satisfies StaticSimpleSchema, + ], + ], + ], + ] satisfies StaticStructureSchema; - const eventStreamContainerSchema = struct( + const eventStreamContainerSchema = [ + 3, "ns", "EventStreamContainer", 0, // here the non-eventstream members form an initial-request // or initial-response when present. ["eventStreamMember", "dateMember", "blobMember"], - [eventStreamUnionSchema, 7 satisfies TimestampEpochSecondsSchema, 21 satisfies BlobSchema] - ); + [eventStreamUnionSchema, 7 satisfies TimestampEpochSecondsSchema, 21 satisfies BlobSchema], + ] satisfies StaticStructureSchema; describe("serialization", () => { async function messageDeserializer(event: Record): Promise { diff --git a/packages/core/src/submodules/event-streams/EventStreamSerde.ts b/packages/core/src/submodules/event-streams/EventStreamSerde.ts index 91531f9643d..6e03e7b39d3 100644 --- a/packages/core/src/submodules/event-streams/EventStreamSerde.ts +++ b/packages/core/src/submodules/event-streams/EventStreamSerde.ts @@ -1,4 +1,4 @@ -import type { NormalizedSchema, StructureSchema } from "@smithy/core/schema"; +import type { NormalizedSchema } from "@smithy/core/schema"; import type { DocumentSchema, EventStreamMarshaller, @@ -10,6 +10,7 @@ import type { SerdeFunctions, ShapeDeserializer, ShapeSerializer, + StaticStructureSchema, } from "@smithy/types"; import { fromUtf8 } from "@smithy/util-utf8"; @@ -68,7 +69,6 @@ export class EventStreamSerde { const marshaller = this.marshaller; const eventStreamMember = requestSchema.getEventStreamMember(); const unionSchema = requestSchema.getMemberSchema(eventStreamMember); - const memberSchemas = unionSchema.getMemberSchemas(); const serializer = this.serializer; const defaultContentType = this.defaultContentType; @@ -233,8 +233,8 @@ export class EventStreamSerde { let explicitPayloadContentType: undefined | string; const isKnownSchema = (() => { - const struct = unionSchema.getSchema() as StructureSchema; - return struct.memberNames.includes(unionMember); + const struct = unionSchema.getSchema() as StaticStructureSchema; + return struct[4].includes(unionMember); })(); const additionalHeaders: MessageHeaders = {}; diff --git a/packages/core/src/submodules/protocols/HttpBindingProtocol.spec.ts b/packages/core/src/submodules/protocols/HttpBindingProtocol.spec.ts index ce6eed9b625..4b3001a695b 100644 --- a/packages/core/src/submodules/protocols/HttpBindingProtocol.spec.ts +++ b/packages/core/src/submodules/protocols/HttpBindingProtocol.spec.ts @@ -1,6 +1,7 @@ -import { map, op, struct } from "@smithy/core/schema"; +import { op } from "@smithy/core/schema"; import { HttpResponse } from "@smithy/protocol-http"; import type { + $Schema, Codec, CodecSettings, HandlerExecutionContext, @@ -10,7 +11,6 @@ import type { MetadataBearer, OperationSchema, ResponseMetadata, - Schema, SerdeFunctions, ShapeDeserializer, ShapeSerializer, @@ -75,26 +75,21 @@ describe(HttpBindingProtocol.name, () => { const protocol = new StringRestProtocol(); const output = (await protocol.deserializeResponse( - op( + op("", "", 0, "unit", [ + 3, "", "", 0, - "unit", - struct( - "", - "", - 0, - ["timestampList"], + ["timestampList"], + [ [ - [ - (64 satisfies ListSchemaModifier) | (4 satisfies TimestampDefaultSchema), - { - httpHeader: "x-timestamplist", - }, - ], - ] - ) - ), + (64 satisfies ListSchemaModifier) | (4 satisfies TimestampDefaultSchema), + { + httpHeader: "x-timestamplist", + }, + ], + ], + ]), {} as any, response )) as Partial; @@ -115,26 +110,21 @@ describe(HttpBindingProtocol.name, () => { const protocol = new StringRestProtocol(); const output = (await protocol.deserializeResponse( - op( + op("", "", 0, "unit", [ + 3, "", "", 0, - "unit", - struct( - "", - "", - 0, - ["httpPrefixHeaders"], + ["httpPrefixHeaders"], + [ [ - [ - (128 satisfies MapSchemaModifier) | (0 satisfies StringSchema), - { - httpPrefixHeaders: "", - }, - ], - ] - ) - ), + (128 satisfies MapSchemaModifier) | (0 satisfies StringSchema), + { + httpPrefixHeaders: "", + }, + ], + ], + ]), {} as any, response )) as Partial; @@ -169,7 +159,7 @@ describe(HttpBindingProtocol.name, () => { it("can deserialize a prefix header binding and header binding from the same header", async () => { type TestSignature = ( - schema: Schema, + schema: $Schema, context: HandlerExecutionContext & SerdeFunctions, response: IHttpResponse, dataObject: any @@ -194,16 +184,17 @@ describe(HttpBindingProtocol.name, () => { const dataObject = {}; await deserializeHttpMessage( - struct( + [ + 3, "", "Struct", 0, ["prefixHeaders", "header"], [ - [map("", "Map", 0, 0, 0), { httpPrefixHeaders: "my-" }], + [[2, "", "Map", 0, 0, 0], { httpPrefixHeaders: "my-" }], [0, { httpHeader: "my-header" }], - ] - ), + ], + ], {} as any, httpResponse, dataObject diff --git a/packages/core/src/submodules/protocols/HttpProtocol.ts b/packages/core/src/submodules/protocols/HttpProtocol.ts index 7d94e616d37..f881dcef7be 100644 --- a/packages/core/src/submodules/protocols/HttpProtocol.ts +++ b/packages/core/src/submodules/protocols/HttpProtocol.ts @@ -1,5 +1,5 @@ import type { EventStreamSerde } from "@smithy/core/event-streams"; -import { NormalizedSchema } from "@smithy/core/schema"; +import { NormalizedSchema, translateTraits } from "@smithy/core/schema"; import { HttpRequest, HttpResponse } from "@smithy/protocol-http"; import type { ClientProtocol, @@ -109,10 +109,11 @@ export abstract class HttpProtocol extends SerdeContext implements ClientProtoco operationSchema: OperationSchema, input: Input ): void { - const operationNs = NormalizedSchema.of(operationSchema); const inputNs = NormalizedSchema.of(operationSchema.input); - if (operationNs.getMergedTraits().endpoint) { - let hostPrefix = operationNs.getMergedTraits().endpoint?.[0]; + const opTraits = translateTraits(operationSchema.traits ?? {}); + + if (opTraits.endpoint) { + let hostPrefix = opTraits.endpoint?.[0]; if (typeof hostPrefix === "string") { const hostLabelInputs = [...inputNs.structIterator()].filter( ([, member]) => member.getMergedTraits().hostLabel diff --git a/packages/core/src/submodules/schema/TypeRegistry.spec.ts b/packages/core/src/submodules/schema/TypeRegistry.spec.ts index 486ce427d1d..5f0384dfe8c 100644 --- a/packages/core/src/submodules/schema/TypeRegistry.spec.ts +++ b/packages/core/src/submodules/schema/TypeRegistry.spec.ts @@ -1,26 +1,33 @@ -import type { StaticErrorSchema } from "@smithy/types"; +import type { StaticErrorSchema, StaticListSchema, StaticMapSchema, StaticStructureSchema } from "@smithy/types"; import { describe, expect, test as it } from "vitest"; -import { list } from "./schemas/ListSchema"; -import { map } from "./schemas/MapSchema"; -import { struct } from "./schemas/StructureSchema"; import { TypeRegistry } from "./TypeRegistry"; describe(TypeRegistry.name, () => { - const [List, Map, Struct] = [ - list("NAMESPACE", "List", { sparse: 1 }, 0), - map("NAMESPACE", "Map", 0, 0, 1), + const [List, Map, Struct]: [StaticListSchema, StaticMapSchema, () => StaticStructureSchema] = [ + [1, "NAMESPACE", "List", { sparse: 1 }, 0], + [2, "NAMESPACE", "Map", 0, 0, 1], () => schema, ]; - const schema = struct("NAMESPACE", "Structure", {}, ["list", "map", "struct"], [List, Map, Struct]); + const schema: StaticStructureSchema = [ + 3, + "NAMESPACE", + "Structure", + {}, + ["list", "map", "struct"], + [List, Map, Struct], + ]; it("stores and retrieves schema objects", () => { const tr = TypeRegistry.for("NAMESPACE"); - tr.register(List.getName(), List); + + tr.register(`${List[1]}#${List[2]}`, List); expect(tr.getSchema("List")).toBe(List); - tr.register(Map.getName(), Map); + + tr.register(`${Map[1]}#${Map[2]}`, Map); expect(tr.getSchema("Map")).toBe(Map); - tr.register(Struct().getName(), Struct()); + + tr.register(`${Struct()[1]}#${Struct()[2]}`, Struct()); expect(tr.getSchema("Structure")).toBe(schema); }); diff --git a/packages/core/src/submodules/schema/TypeRegistry.ts b/packages/core/src/submodules/schema/TypeRegistry.ts index 2534a7ec28a..46e61af0167 100644 --- a/packages/core/src/submodules/schema/TypeRegistry.ts +++ b/packages/core/src/submodules/schema/TypeRegistry.ts @@ -13,7 +13,7 @@ export class TypeRegistry { private constructor( public readonly namespace: string, private schemas: Map = new Map(), - private exceptions: Map = new Map() + private exceptions: Map = new Map() ) {} /** @@ -68,7 +68,7 @@ export class TypeRegistry { public getErrorCtor(es: ErrorSchema | StaticErrorSchema): any { const $error = es as StaticErrorSchema; const registry = TypeRegistry.for($error[1]); - return registry.exceptions.get(es); + return registry.exceptions.get($error); } /** diff --git a/packages/core/src/submodules/schema/index.ts b/packages/core/src/submodules/schema/index.ts index 5229be011ea..fe9508c3d45 100644 --- a/packages/core/src/submodules/schema/index.ts +++ b/packages/core/src/submodules/schema/index.ts @@ -3,6 +3,7 @@ export * from "./middleware/getSchemaSerdePlugin"; export * from "./schemas/ListSchema"; export * from "./schemas/MapSchema"; export * from "./schemas/OperationSchema"; +export * from "./schemas/operation"; export * from "./schemas/ErrorSchema"; export * from "./schemas/NormalizedSchema"; export * from "./schemas/Schema"; diff --git a/packages/core/src/submodules/schema/middleware/schemaDeserializationMiddleware.spec.ts b/packages/core/src/submodules/schema/middleware/schemaDeserializationMiddleware.spec.ts index d9149301efa..269237a4cdf 100644 --- a/packages/core/src/submodules/schema/middleware/schemaDeserializationMiddleware.spec.ts +++ b/packages/core/src/submodules/schema/middleware/schemaDeserializationMiddleware.spec.ts @@ -85,7 +85,7 @@ describe(schemaDeserializationMiddleware.name, () => { expect(mockNext).toHaveBeenCalledWith(mockArgs); expect(mockDeserializer).toHaveBeenCalledTimes(1); expect(mockDeserializer).toHaveBeenCalledWith( - undefined as any as SchemaRef, + {}, { ...mockOptions, __smithy_context: {}, @@ -182,7 +182,11 @@ describe(schemaDeserializationMiddleware.name, () => { statusCode: 503, }), }), - {} + { + __smithy_context: { + operationSchema: [9, "", "", 0, "unit", "unit"], + }, + } ); try { await handler(mockArgs); @@ -209,7 +213,11 @@ describe(schemaDeserializationMiddleware.name, () => { }, }), }), - {} + { + __smithy_context: { + operationSchema: [9, "", "", 0, "unit", "unit"], + }, + } ); try { await handler(mockArgs); diff --git a/packages/core/src/submodules/schema/middleware/schemaDeserializationMiddleware.ts b/packages/core/src/submodules/schema/middleware/schemaDeserializationMiddleware.ts index 1ad63a66738..aecd3258381 100644 --- a/packages/core/src/submodules/schema/middleware/schemaDeserializationMiddleware.ts +++ b/packages/core/src/submodules/schema/middleware/schemaDeserializationMiddleware.ts @@ -4,12 +4,11 @@ import type { DeserializeHandlerArguments, HandlerExecutionContext, MetadataBearer, - OperationSchema, StaticOperationSchema, } from "@smithy/types"; import { getSmithyContext } from "@smithy/util-middleware"; -import { hydrate, isStaticSchema } from "../schemas/NormalizedSchema"; +import { operation } from "../schemas/operation"; import type { PreviouslyResolved } from "./schema-middleware-types"; /** @@ -20,16 +19,14 @@ export const schemaDeserializationMiddleware = (next: DeserializeHandler, context: HandlerExecutionContext) => async (args: DeserializeHandlerArguments) => { const { response } = await next(args); - let { operationSchema } = getSmithyContext(context) as { - operationSchema: OperationSchema | StaticOperationSchema; + const { operationSchema } = getSmithyContext(context) as { + operationSchema: StaticOperationSchema; }; - if (isStaticSchema(operationSchema)) { - operationSchema = hydrate(operationSchema); - } + const [, ns, n, t, i, o] = operationSchema ?? []; try { const parsed = await config.protocol.deserializeResponse( - operationSchema, + operation(ns, n, t, i, o), { ...config, ...context, diff --git a/packages/core/src/submodules/schema/middleware/schemaSerializationMiddleware.spec.ts b/packages/core/src/submodules/schema/middleware/schemaSerializationMiddleware.spec.ts index 7d7a2fdebaf..fe4366e6685 100644 --- a/packages/core/src/submodules/schema/middleware/schemaSerializationMiddleware.spec.ts +++ b/packages/core/src/submodules/schema/middleware/schemaSerializationMiddleware.spec.ts @@ -59,7 +59,7 @@ describe(schemaSerializationMiddleware.name, () => { await expect(schemaSerializationMiddleware(mockOptions)(mockNext, {})(mockArgs)).resolves.toStrictEqual(mockReturn); expect(mockSerializer).toHaveBeenCalledTimes(1); - expect(mockSerializer).toHaveBeenCalledWith(undefined as unknown as SchemaRef, mockArgs.input, { + expect(mockSerializer).toHaveBeenCalledWith({}, mockArgs.input, { ...mockOptions, __smithy_context: {}, }); diff --git a/packages/core/src/submodules/schema/middleware/schemaSerializationMiddleware.ts b/packages/core/src/submodules/schema/middleware/schemaSerializationMiddleware.ts index 46cc50e5e0d..d59ade1846f 100644 --- a/packages/core/src/submodules/schema/middleware/schemaSerializationMiddleware.ts +++ b/packages/core/src/submodules/schema/middleware/schemaSerializationMiddleware.ts @@ -2,7 +2,6 @@ import type { Endpoint, EndpointBearer, HandlerExecutionContext, - OperationSchema as IOperationSchema, Provider, SerializeHandler, SerializeHandlerArguments, @@ -10,7 +9,7 @@ import type { } from "@smithy/types"; import { getSmithyContext } from "@smithy/util-middleware"; -import { hydrate, isStaticSchema } from "../schemas/NormalizedSchema"; +import { operation } from "../schemas/operation"; import type { PreviouslyResolved } from "./schema-middleware-types"; /** @@ -20,19 +19,17 @@ export const schemaSerializationMiddleware = (config: PreviouslyResolved) => (next: SerializeHandler, context: HandlerExecutionContext) => async (args: SerializeHandlerArguments) => { - let { operationSchema } = getSmithyContext(context) as { - operationSchema: IOperationSchema | StaticOperationSchema; + const { operationSchema } = getSmithyContext(context) as { + operationSchema: StaticOperationSchema; }; - if (isStaticSchema(operationSchema)) { - operationSchema = hydrate(operationSchema); - } + const [, ns, n, t, i, o] = operationSchema ?? []; const endpoint: Provider = context.endpointV2?.url && config.urlParser ? async () => config.urlParser!(context.endpointV2!.url as URL) : (config as unknown as EndpointBearer).endpoint!; - const request = await config.protocol.serializeRequest(operationSchema, args.input, { + const request = await config.protocol.serializeRequest(operation(ns, n, t, i, o), args.input, { ...config, ...context, endpoint, diff --git a/packages/core/src/submodules/schema/schemas/ErrorSchema.ts b/packages/core/src/submodules/schema/schemas/ErrorSchema.ts index accb166cf64..c80421142e2 100644 --- a/packages/core/src/submodules/schema/schemas/ErrorSchema.ts +++ b/packages/core/src/submodules/schema/schemas/ErrorSchema.ts @@ -10,6 +10,7 @@ import { StructureSchema } from "./StructureSchema"; * by additionally holding the class reference for the corresponding ServiceException class. * * @alpha + * @deprecated use StaticSchema */ export class ErrorSchema extends StructureSchema { public static readonly symbol = Symbol.for("@smithy/err"); @@ -24,6 +25,7 @@ export class ErrorSchema extends StructureSchema { * Factory for ErrorSchema, to reduce codegen output and register the schema. * * @internal + * @deprecated use StaticSchema * * @param namespace - shapeId namespace. * @param name - shapeId name. diff --git a/packages/core/src/submodules/schema/schemas/ListSchema.ts b/packages/core/src/submodules/schema/schemas/ListSchema.ts index a474e7ac32e..50236cc7859 100644 --- a/packages/core/src/submodules/schema/schemas/ListSchema.ts +++ b/packages/core/src/submodules/schema/schemas/ListSchema.ts @@ -7,6 +7,7 @@ import { Schema } from "./Schema"; * The deprecated Set type may be represented as a list. * * @alpha + * @deprecated use StaticSchema */ export class ListSchema extends Schema implements IListSchema { public static readonly symbol = Symbol.for("@smithy/lis"); @@ -20,6 +21,7 @@ export class ListSchema extends Schema implements IListSchema { * Factory for ListSchema. * * @internal + * @deprecated use StaticSchema */ export const list = (namespace: string, name: string, traits: SchemaTraits, valueSchema: SchemaRef): ListSchema => Schema.assign(new ListSchema(), { diff --git a/packages/core/src/submodules/schema/schemas/MapSchema.ts b/packages/core/src/submodules/schema/schemas/MapSchema.ts index bfb450845a0..4150713b86b 100644 --- a/packages/core/src/submodules/schema/schemas/MapSchema.ts +++ b/packages/core/src/submodules/schema/schemas/MapSchema.ts @@ -5,6 +5,7 @@ import { Schema } from "./Schema"; /** * A schema with a key schema and value schema. * @alpha + * @deprecated use StaticSchema */ export class MapSchema extends Schema implements IMapSchema { public static readonly symbol = Symbol.for("@smithy/map"); @@ -21,6 +22,7 @@ export class MapSchema extends Schema implements IMapSchema { /** * Factory for MapSchema. * @internal + * @deprecated use StaticSchema */ export const map = ( namespace: string, diff --git a/packages/core/src/submodules/schema/schemas/NormalizedSchema.spec.ts b/packages/core/src/submodules/schema/schemas/NormalizedSchema.spec.ts index c5e130f75d5..9b55ab8345d 100644 --- a/packages/core/src/submodules/schema/schemas/NormalizedSchema.spec.ts +++ b/packages/core/src/submodules/schema/schemas/NormalizedSchema.spec.ts @@ -1,4 +1,5 @@ import type { + $MemberSchema, BigDecimalSchema, BigIntegerSchema, BlobSchema, @@ -6,28 +7,27 @@ import type { DocumentSchema, ListSchemaModifier, MapSchemaModifier, - MemberSchema, NumericSchema, StaticListSchema, StaticMapSchema, + StaticSimpleSchema, StaticStructureSchema, StreamingBlobSchema, StringSchema, - StructureSchema, TimestampDefaultSchema, } from "@smithy/types"; import { describe, expect, test as it } from "vitest"; -import { list } from "./ListSchema"; -import { map } from "./MapSchema"; import { NormalizedSchema } from "./NormalizedSchema"; -import { sim } from "./SimpleSchema"; -import { struct } from "./StructureSchema"; import { translateTraits } from "./translateTraits"; describe(NormalizedSchema.name, () => { - const [List, Map, Struct] = [list("ack", "List", { sparse: 1 }, 0), map("ack", "Map", 0, 0, 1), () => schema]; - const schema = struct("ack", "Structure", {}, ["list", "map", "struct"], [List, Map, Struct]); + const [List, Map, Struct]: [StaticListSchema, StaticMapSchema, () => StaticStructureSchema] = [ + [1, "ack", "List", { sparse: 1 }, 0] satisfies StaticListSchema, + [2, "ack", "Map", 0, 0, 1] satisfies StaticMapSchema, + () => schema, + ]; + const schema: StaticStructureSchema = [3, "ack", "Structure", {}, ["list", "map", "struct"], [List, Map, Struct]]; const ns = NormalizedSchema.of(schema); const nsFromIndirect = NormalizedSchema.of(() => ns); @@ -121,13 +121,14 @@ describe(NormalizedSchema.name, () => { expect(NormalizedSchema.of(19 satisfies BigDecimalSchema).isBigDecimalSchema()).toBe(true); expect(NormalizedSchema.of(42 satisfies StreamingBlobSchema).isStreaming()).toBe(true); - const structWithStreamingMember = struct( + const structWithStreamingMember = [ + 3, "ack", "StructWithStreamingMember", 0, ["m"], - [sim("ns", "blob", 21 as BlobSchema, { streaming: 1 })] - ); + [[0, "ns", "blob", { streaming: 1 }, 21 as BlobSchema] satisfies StaticSimpleSchema], + ] satisfies StaticStructureSchema; expect(NormalizedSchema.of(structWithStreamingMember).getMemberSchema("m").isStreaming()).toBe(true); }); @@ -221,8 +222,11 @@ describe(NormalizedSchema.name, () => { }); describe("traits", () => { - const member: MemberSchema = [sim("ack", "SimpleString", 0, { idempotencyToken: 1 }), 0b0000_0001]; - const container: StructureSchema = struct("ack", "Container", 0, ["member_name"], [member, 0]); + const member: $MemberSchema = [ + [0, "ack", "SimpleString", { idempotencyToken: 1 }, 0] satisfies StaticSimpleSchema, + 0b0000_0001, + ]; + const container: StaticStructureSchema = [3, "ack", "Container", 0, ["member_name"], [member, 0]]; const ns = NormalizedSchema.of(container).getMemberSchema("member_name"); @@ -247,14 +251,14 @@ describe(NormalizedSchema.name, () => { describe("idempotency token detection", () => { const idempotencyTokenSchemas = [ - NormalizedSchema.of(sim("", "StringWithTraits", 0, 0b0100)), - NormalizedSchema.of(sim("", "StringWithTraits", 0, { idempotencyToken: 1 })), + NormalizedSchema.of([0, "", "StringWithTraits", 0b0100, 0] satisfies StaticSimpleSchema), + NormalizedSchema.of([0, "", "StringWithTraits", { idempotencyToken: 1 }, 0] satisfies StaticSimpleSchema), ]; const plainSchemas = [ NormalizedSchema.of(0), - NormalizedSchema.of(sim("", "StringWithTraits", 0, 0)), - NormalizedSchema.of(sim("", "StringWithTraits", 0, {})), + NormalizedSchema.of([0, "", "StringWithTraits", 0, 0] satisfies StaticSimpleSchema), + NormalizedSchema.of([0, "", "StringWithTraits", {}, 0] satisfies StaticSimpleSchema), ]; it("has a consistent shortcut method for idempotencyToken detection", () => { @@ -274,7 +278,14 @@ describe(NormalizedSchema.name, () => { expect(schema.isIdempotencyToken()).toBe(false); expect(schema.getMergedTraits().idempotencyToken).toBe(undefined); - const structure = struct("", "StructureWithIdempotencyTokenMember", 0, ["token"], [[() => schema, 0b0100]]); + const structure = [ + 3, + "", + "StructureWithIdempotencyTokenMember", + 0, + ["token"], + [[() => schema, 0b0100]], + ] satisfies StaticStructureSchema; const ns = NormalizedSchema.of(structure).getMemberSchema("token"); expect(ns.isIdempotencyToken()).toBe(true); @@ -284,26 +295,28 @@ describe(NormalizedSchema.name, () => { describe("event stream detection", () => { it("should retrieve the event stream member", () => { - const schema = struct( + const schema: StaticStructureSchema = [ + 3, "ns", "StructureWithEventStream", 0, ["A", "B", "C", "D", "EventStream"], - [0, 0, 0, 0, struct("ns", "Union", { streaming: 1 }, [], [])] - ); + [0, 0, 0, 0, [3, "ns", "Union", { streaming: 1 }, [], []] satisfies StaticStructureSchema], + ]; const ns = NormalizedSchema.of(schema); expect(ns.getEventStreamMember()).toEqual("EventStream"); }); it("should return empty string if no event stream member is present", () => { - const schema = struct( + const schema: StaticStructureSchema = [ + 3, "ns", "StructureWithEventStream", 0, ["A", "B", "C", "D", "EventStream"], - [0, 0, 0, 0, struct("ns", "Union", 0, [], [])] - ); + [0, 0, 0, 0, [3, "ns", "Union", 0, [], []] satisfies StaticStructureSchema], + ]; const ns = NormalizedSchema.of(schema); expect(ns.getEventStreamMember()).toEqual(""); @@ -344,4 +357,13 @@ describe(NormalizedSchema.name, () => { expect(ns.getMemberSchema("struct").getMemberSchema("map").getValueSchema().isNumericSchema()).toBe(true); }); }); + + describe("simple schema wrapper", () => { + it("should still be able to detect the inner schema type", () => { + const schema: StaticSimpleSchema = [0, "ack", "String", { unknownTrait: 1 }, 0]; + + const ns = NormalizedSchema.of(schema); + expect(ns.isStringSchema()).toBe(true); + }); + }); }); diff --git a/packages/core/src/submodules/schema/schemas/NormalizedSchema.ts b/packages/core/src/submodules/schema/schemas/NormalizedSchema.ts index 3da56b898f1..921d10e62bb 100644 --- a/packages/core/src/submodules/schema/schemas/NormalizedSchema.ts +++ b/packages/core/src/submodules/schema/schemas/NormalizedSchema.ts @@ -1,4 +1,7 @@ import type { + $MemberSchema, + $Schema, + $SchemaRef, BigDecimalSchema, BigIntegerSchema, BlobSchema, @@ -6,23 +9,18 @@ import type { DocumentSchema, ListSchemaModifier, MapSchemaModifier, - MemberSchema, NormalizedSchema as INormalizedSchema, NumericSchema, - Schema as ISchema, SchemaRef, SchemaTraits, SchemaTraitsObject, - StaticErrorSchema, + SimpleSchema, StaticListSchema, StaticMapSchema, - StaticOperationSchema, StaticSchema, StaticSchemaIdError, StaticSchemaIdList, StaticSchemaIdMap, - StaticSchemaIdOperation, - StaticSchemaIdSimple, StaticSchemaIdStruct, StaticSimpleSchema, StaticStructureSchema, @@ -35,16 +33,6 @@ import type { import type { IdempotencyTokenBitMask, TraitBitVector } from "@smithy/types/src/schema/traits"; import { deref } from "../deref"; -import type { ErrorSchema } from "./ErrorSchema"; -import { error } from "./ErrorSchema"; -import { list, ListSchema } from "./ListSchema"; -import { map, MapSchema } from "./MapSchema"; -import type { OperationSchema } from "./OperationSchema"; -import { op } from "./OperationSchema"; -import { Schema } from "./Schema"; -import type { SimpleSchema } from "./SimpleSchema"; -import { simAdapter } from "./SimpleSchema"; -import { struct, StructureSchema } from "./StructureSchema"; import { translateTraits } from "./translateTraits"; /** @@ -65,7 +53,7 @@ export class NormalizedSchema implements INormalizedSchema { protected readonly symbol = NormalizedSchema.symbol; private readonly name!: string; - private readonly schema!: Exclude; + private readonly schema!: Exclude<$Schema, $MemberSchema | INormalizedSchema>; private readonly _isMemberSchema: boolean; private readonly traits!: SchemaTraits; @@ -77,7 +65,7 @@ export class NormalizedSchema implements INormalizedSchema { * @param memberName - optional memberName if this NormalizedSchema should be considered a member schema. */ private constructor( - readonly ref: SchemaRef, + readonly ref: $SchemaRef, private readonly memberName?: string ) { const traitStack = [] as SchemaTraits[]; @@ -87,13 +75,11 @@ export class NormalizedSchema implements INormalizedSchema { while (isMemberSchema(_ref)) { traitStack.push(_ref[1]); - _ref = _ref[0]; - schema = deref(_ref); + _ref = _ref[0] as $SchemaRef; + schema = deref(_ref) as $Schema; this._isMemberSchema = true; } - if (isStaticSchema(schema)) schema = hydrate(schema); - if (traitStack.length > 0) { this.memberTraits = {}; for (let i = traitStack.length - 1; i >= 0; --i) { @@ -113,30 +99,34 @@ export class NormalizedSchema implements INormalizedSchema { return; } - this.schema = deref(schema) as Exclude; + this.schema = deref(schema) as Exclude<$Schema, $MemberSchema | INormalizedSchema>; - if (this.schema && typeof this.schema === "object") { - // excluded by the checked hydrate call above. - this.traits = (this.schema as Exclude)?.traits ?? {}; + if (isStaticSchema(this.schema)) { + this.name = `${this.schema[1]}#${this.schema[2]}`; + this.traits = this.schema[3]; } else { + this.name = this.memberName ?? String(schema); this.traits = 0; } - this.name = (this.schema instanceof Schema ? this.schema.getName?.() : void 0) ?? this.memberName ?? String(schema); - if (this._isMemberSchema && !memberName) { throw new Error(`@smithy/core/schema - NormalizedSchema member init ${this.getName(true)} missing member name.`); } } public static [Symbol.hasInstance](lhs: unknown): lhs is NormalizedSchema { - return Schema[Symbol.hasInstance].bind(this)(lhs); + const isPrototype = this.prototype.isPrototypeOf(lhs as any); + if (!isPrototype && typeof lhs === "object" && lhs !== null) { + const ns = lhs as any; + return ns.symbol === (this as any).symbol; + } + return isPrototype; } /** * Static constructor that attempts to avoid wrapping a NormalizedSchema within another. */ - public static of(ref: SchemaRef): NormalizedSchema { + public static of(ref: SchemaRef | $SchemaRef): NormalizedSchema { const sc = deref(ref); if (sc instanceof NormalizedSchema) { return sc; @@ -151,17 +141,18 @@ export class NormalizedSchema implements INormalizedSchema { // container. throw new Error(`@smithy/core/schema - may not init unwrapped member schema=${JSON.stringify(ref, null, 2)}.`); } - return new NormalizedSchema(sc); + return new NormalizedSchema(sc as $SchemaRef); } /** * @returns the underlying non-normalized schema. */ - public getSchema(): Exclude { - return deref((this.schema as SimpleSchema)?.schemaRef ?? this.schema) as Exclude< - ISchema, - MemberSchema | INormalizedSchema - >; + public getSchema(): Exclude<$Schema, $MemberSchema | INormalizedSchema> { + const sc = this.schema; + if ((sc as StaticSimpleSchema)[0] === 0) { + return (sc as StaticSimpleSchema)[4] as SimpleSchema; + } + return sc as Exclude<$Schema, $MemberSchema | INormalizedSchema>; } /** @@ -193,19 +184,22 @@ export class NormalizedSchema implements INormalizedSchema { const sc = this.getSchema(); return typeof sc === "number" ? sc >= (64 satisfies ListSchemaModifier) && sc < (128 satisfies MapSchemaModifier) - : sc instanceof ListSchema; + : (sc as StaticSchema)[0] === (1 satisfies StaticSchemaIdList); } public isMapSchema(): boolean { const sc = this.getSchema(); return typeof sc === "number" ? sc >= (128 satisfies MapSchemaModifier) && sc <= 0b1111_1111 - : sc instanceof MapSchema; + : (sc as StaticSchema)[0] === (2 satisfies StaticSchemaIdMap); } public isStructSchema(): boolean { const sc = this.getSchema(); - return (sc !== null && typeof sc === "object" && "members" in sc) || sc instanceof StructureSchema; + return ( + (sc as StaticSchema)[0] === (3 satisfies StaticSchemaIdStruct) || + (sc as StaticSchema)[0] === (-3 satisfies StaticSchemaIdError) + ); } public isBlobSchema(): boolean { @@ -312,7 +306,7 @@ export class NormalizedSchema implements INormalizedSchema { const schema = this.getSchema(); const memberSchema = isDoc ? (15 satisfies DocumentSchema) - : (schema as MapSchema)?.keySchema ?? (0 satisfies StringSchema); + : (schema as StaticMapSchema)[4] ?? (0 satisfies StringSchema); return member([memberSchema, 0], "key"); } @@ -329,7 +323,7 @@ export class NormalizedSchema implements INormalizedSchema { typeof sc === "number" ? 0b0011_1111 & sc : sc && typeof sc === "object" && (isMap || isList) - ? ((sc as MapSchema | ListSchema).valueSchema as typeof sc) + ? ((sc as StaticMapSchema | StaticListSchema)[3 + (sc as StaticSchema)[0]] as typeof sc) : isDoc ? (15 satisfies DocumentSchema) : void 0; @@ -348,10 +342,10 @@ export class NormalizedSchema implements INormalizedSchema { * Note that errors are assumed to be structures and unions are considered structures for these purposes. */ public getMemberSchema(memberName: string): NormalizedSchema { - const struct = this.getSchema() as StructureSchema; - if (this.isStructSchema() && struct.memberNames.includes(memberName)) { - const i = struct.memberNames.indexOf(memberName); - const memberSchema = struct.memberList[i]; + const struct = this.getSchema() as StaticStructureSchema; + if (this.isStructSchema() && struct[4].includes(memberName)) { + const i = struct[4].indexOf(memberName); + const memberSchema = struct[5][i]; return member(isMemberSchema(memberSchema) ? memberSchema : [memberSchema, 0], memberName); } if (this.isDocumentSchema()) { @@ -408,9 +402,9 @@ export class NormalizedSchema implements INormalizedSchema { if (!this.isStructSchema()) { throw new Error("@smithy/core/schema - cannot iterate non-struct schema."); } - const struct = this.getSchema() as StructureSchema; - for (let i = 0; i < struct.memberNames.length; ++i) { - yield [struct.memberNames[i], member([struct.memberList[i], 0], struct.memberNames[i])]; + const struct = this.getSchema() as StaticStructureSchema; + for (let i = 0; i < struct[4].length; ++i) { + yield [struct[4][i], member([struct[5][i], 0], struct[4][i])]; } } } @@ -431,39 +425,10 @@ function member(memberSchema: NormalizedSchema | [SchemaRef, SchemaTraits], memb return new internalCtorAccess(memberSchema, memberName); } -/** - * @internal - * @returns a class instance version of a static schema. - */ -export function hydrate(ss: StaticSimpleSchema): SimpleSchema; -export function hydrate(ss: StaticListSchema): ListSchema; -export function hydrate(ss: StaticMapSchema): MapSchema; -export function hydrate(ss: StaticStructureSchema): StructureSchema; -export function hydrate(ss: StaticErrorSchema): ErrorSchema; -export function hydrate(ss: StaticOperationSchema): OperationSchema; -export function hydrate( - ss: StaticSchema -): SimpleSchema | ListSchema | MapSchema | StructureSchema | ErrorSchema | OperationSchema; -export function hydrate( - ss: StaticSchema -): SimpleSchema | ListSchema | MapSchema | StructureSchema | ErrorSchema | OperationSchema { - const [id, ...rest] = ss; - return ( - { - [0 satisfies StaticSchemaIdSimple]: simAdapter, - [1 satisfies StaticSchemaIdList]: list, - [2 satisfies StaticSchemaIdMap]: map, - [3 satisfies StaticSchemaIdStruct]: struct, - [-3 satisfies StaticSchemaIdError]: error, - [9 satisfies StaticSchemaIdOperation]: op, - }[id] as Function - ).call(null, ...rest); -} - /** * @internal */ -const isMemberSchema = (sc: SchemaRef): sc is MemberSchema => Array.isArray(sc) && sc.length === 2; +const isMemberSchema = (sc: SchemaRef): sc is $MemberSchema => Array.isArray(sc) && sc.length === 2; /** * @internal diff --git a/packages/core/src/submodules/schema/schemas/OperationSchema.ts b/packages/core/src/submodules/schema/schemas/OperationSchema.ts index 0b281851c8d..dedd233ce42 100644 --- a/packages/core/src/submodules/schema/schemas/OperationSchema.ts +++ b/packages/core/src/submodules/schema/schemas/OperationSchema.ts @@ -7,6 +7,7 @@ import { Schema } from "./Schema"; * detection on the operation that may affect client protocol logic. * * @alpha + * @deprecated use StaticSchema */ export class OperationSchema extends Schema implements IOperationSchema { public static readonly symbol = Symbol.for("@smithy/ope"); @@ -20,6 +21,7 @@ export class OperationSchema extends Schema implements IOperationSchema { /** * Factory for OperationSchema. * @internal + * @deprecated use StaticSchema */ export const op = ( namespace: string, diff --git a/packages/core/src/submodules/schema/schemas/Schema.ts b/packages/core/src/submodules/schema/schemas/Schema.ts index e84c2860d04..d71e0ae4062 100644 --- a/packages/core/src/submodules/schema/schemas/Schema.ts +++ b/packages/core/src/submodules/schema/schemas/Schema.ts @@ -6,6 +6,7 @@ import { TypeRegistry } from "../TypeRegistry"; * Abstract base for class-based Schema except NormalizedSchema. * * @alpha + * @deprecated use StaticSchema */ export abstract class Schema implements TraitsSchema { public name!: string; diff --git a/packages/core/src/submodules/schema/schemas/SimpleSchema.ts b/packages/core/src/submodules/schema/schemas/SimpleSchema.ts index f5fbb912eb9..3777b5ad3fa 100644 --- a/packages/core/src/submodules/schema/schemas/SimpleSchema.ts +++ b/packages/core/src/submodules/schema/schemas/SimpleSchema.ts @@ -8,6 +8,7 @@ import { Schema } from "./Schema"; * attached to those schema, since a single number cannot easily represent both a schema and its traits. * * @alpha + * @deprecated use StaticSchema */ export class SimpleSchema extends Schema implements TraitsSchema { public static readonly symbol = Symbol.for("@smithy/sim"); @@ -21,6 +22,7 @@ export class SimpleSchema extends Schema implements TraitsSchema { * Factory for simple schema class objects. * * @internal + * @deprecated use StaticSchema */ export const sim = (namespace: string, name: string, schemaRef: SchemaRef, traits: SchemaTraits) => Schema.assign(new SimpleSchema(), { diff --git a/packages/core/src/submodules/schema/schemas/StructureSchema.ts b/packages/core/src/submodules/schema/schemas/StructureSchema.ts index dc7d5093c28..2ab9cc1c7ff 100644 --- a/packages/core/src/submodules/schema/schemas/StructureSchema.ts +++ b/packages/core/src/submodules/schema/schemas/StructureSchema.ts @@ -7,6 +7,7 @@ import { Schema } from "./Schema"; * A structure schema has a known list of members. This is also used for unions. * * @alpha + * @deprecated use StaticSchema */ export class StructureSchema extends Schema implements IStructureSchema { public static symbol = Symbol.for("@smithy/str"); @@ -21,6 +22,7 @@ export class StructureSchema extends Schema implements IStructureSchema { * Factory for StructureSchema. * * @internal + * @deprecated use StaticSchema */ export const struct = ( namespace: string, diff --git a/packages/core/src/submodules/schema/schemas/operation.ts b/packages/core/src/submodules/schema/schemas/operation.ts new file mode 100644 index 00000000000..b99b8670f62 --- /dev/null +++ b/packages/core/src/submodules/schema/schemas/operation.ts @@ -0,0 +1,20 @@ +import type { OperationSchema, SchemaRef, SchemaTraits } from "@smithy/types"; + +/** + * Converts the static schema array into an object-form to adapt + * to the signature of ClientProtocol classes. + * @internal + */ +export const operation = ( + namespace: string, + name: string, + traits: SchemaTraits, + input: SchemaRef, + output: SchemaRef +): OperationSchema => ({ + name, + namespace, + traits, + input, + output, +}); diff --git a/packages/core/src/submodules/schema/schemas/schemas.spec.ts b/packages/core/src/submodules/schema/schemas/schemas.spec.ts index 7b31b0a3098..46d6e24893c 100644 --- a/packages/core/src/submodules/schema/schemas/schemas.spec.ts +++ b/packages/core/src/submodules/schema/schemas/schemas.spec.ts @@ -1,7 +1,6 @@ import type { SchemaRef, SchemaTraits } from "@smithy/types"; import { describe, expect, test as it } from "vitest"; -import { TypeRegistry } from "../TypeRegistry"; import { error, ErrorSchema } from "./ErrorSchema"; import { list, ListSchema } from "./ListSchema"; import { map, MapSchema } from "./MapSchema"; diff --git a/packages/smithy-client/src/schemaLogFilter.spec.ts b/packages/smithy-client/src/schemaLogFilter.spec.ts index 18d04cd8508..19cd1586ade 100644 --- a/packages/smithy-client/src/schemaLogFilter.spec.ts +++ b/packages/smithy-client/src/schemaLogFilter.spec.ts @@ -1,39 +1,47 @@ -import { list, map, SCHEMA, sim, struct } from "@smithy/core/schema"; +import type { + BooleanSchema, + NumericSchema, + StaticSimpleSchema, + StaticStructureSchema, + StringSchema, +} from "@smithy/types"; import { describe, expect, test as it } from "vitest"; import { schemaLogFilter } from "./schemaLogFilter"; describe(schemaLogFilter.name, () => { it("should filter sensitive trait-marked fields", () => { - const sensitiveString = sim("ns", "SensitiveString", 0, { sensitive: 1 }); + const sensitiveString: StaticSimpleSchema = [0, "ns", "SensitiveString", { sensitive: 1 }, 0]; - const schema = struct( + const schema: StaticStructureSchema = [ + 3, "ns", "Struct", 0, ["a", "b", "sensitive", "nestedSensitive", "various"], [ - SCHEMA.STRING, - SCHEMA.STRING, + 0 satisfies StringSchema, + 0 satisfies StringSchema, sensitiveString, - struct("ns", "NestedSensitiveStruct", 0, ["sensitive"], [sensitiveString]), - struct( + [3, "ns", "NestedSensitiveStruct", 0, ["sensitive"], [sensitiveString]], + [ + 3, "ns", "Various", 0, ["boolean", "number", "struct", "list-s", "list", "map-s", "map"], [ - sim("ns", "Boolean", SCHEMA.BOOLEAN, { sensitive: 1 }), - sim("ns", "Numeric", SCHEMA.NUMERIC, { sensitive: 1 }), - struct("ns", "SensitiveStruct", { sensitive: 1 }, [], []), - list("ns", "List", 0, sensitiveString), - list("ns", "List", 0, SCHEMA.STRING), - map("ns", "Map", 0, sensitiveString, SCHEMA.STRING), - map("ns", "Map", 0, SCHEMA.STRING, SCHEMA.STRING), - ] - ), - ] - ); + [0, "ns", "Boolean", { sensitive: 1 }, 2 satisfies BooleanSchema], + [0, "ns", "Numeric", { sensitive: 1 }, 1 satisfies NumericSchema], + [3, "ns", "SensitiveStruct", { sensitive: 1 }, [], []], + [1, "ns", "List", 0, sensitiveString], + [1, "ns", "List", 0, 0 satisfies StringSchema], + [2, "ns", "Map", 0, sensitiveString, 0 satisfies StringSchema], + [2, "ns", "Map", 0, 0 satisfies StringSchema, 0 satisfies StringSchema], + ], + ], + ], + ]; expect( schemaLogFilter(schema, { diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 12338d6cdce..dab8f7cca80 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -22,6 +22,7 @@ export * from "./profile"; export * from "./response"; export * from "./retry"; export * from "./schema/schema"; +export * from "./schema/schema-deprecated"; export * from "./schema/sentinels"; export * from "./schema/static-schemas"; export * from "./serde"; diff --git a/packages/types/src/schema/schema-deprecated.ts b/packages/types/src/schema/schema-deprecated.ts new file mode 100644 index 00000000000..af4e5a7ea7c --- /dev/null +++ b/packages/types/src/schema/schema-deprecated.ts @@ -0,0 +1,169 @@ +import type { EndpointV2 } from "../endpoint"; +import type { HandlerExecutionContext } from "../middleware"; +import type { MetadataBearer } from "../response"; +import type { EndpointBearer, SerdeFunctions } from "../serde"; +import type { ConfigurableSerdeContext, NormalizedSchema, SchemaTraits, SimpleSchema, UnitSchema } from "./schema"; +import type { StaticSchema } from "./static-schemas"; + +/** + * A schema is an object or value that describes how to serialize/deserialize data. + * @public + * @deprecated use $Schema + */ +export type Schema = + | UnitSchema + | TraitsSchema + | SimpleSchema + | ListSchema + | MapSchema + | StructureSchema + | MemberSchema + | OperationSchema + | StaticSchema + | NormalizedSchema; + +/** + * A schema "reference" is either a schema or a function that + * provides a schema. This is useful for lazy loading, and to allow + * code generation to define schema out of dependency order. + * @public + * @deprecated use $SchemaRef + */ +export type SchemaRef = Schema | (() => Schema); + +/** + * A schema that has traits. + * + * @public + * @deprecated use static schema. + */ +export interface TraitsSchema { + namespace: string; + name: string; + traits: SchemaTraits; +} + +/** + * Indicates the schema is a member of a parent Structure schema. + * It may also have a set of member traits distinct from its target shape's traits. + * @public + * @deprecated use $MemberSchema + */ +export type MemberSchema = [SchemaRef, SchemaTraits]; + +/** + * Schema for the structure aggregate type. + * @public + * @deprecated use static schema. + */ +export interface StructureSchema extends TraitsSchema { + memberNames: string[]; + memberList: SchemaRef[]; + + /** + * @deprecated structure member iteration will be linear on the memberNames and memberList arrays. + * It can be collected into a hashmap form on an ad-hoc basis, but will not initialize as such. + */ + members?: Record | undefined; +} + +/** + * Schema for the list aggregate type. + * @public + * @deprecated use static schema. + */ +export interface ListSchema extends TraitsSchema { + valueSchema: SchemaRef; +} + +/** + * Schema for the map aggregate type. + * @public + * @deprecated use static schema. + */ +export interface MapSchema extends TraitsSchema { + keySchema: SchemaRef; + valueSchema: SchemaRef; +} + +/** + * Schema for an operation. + * @public + * @deprecated use StaticOperationSchema or $OperationSchema + */ +export interface OperationSchema { + namespace: string; + name: string; + traits: SchemaTraits; + input: SchemaRef; + output: SchemaRef; +} + +/** + * Turns a serialization into a data object. + * @public + * @deprecated use $ShapeDeserializer + */ +export interface ShapeDeserializer extends ConfigurableSerdeContext { + /** + * Optionally async. + */ + read(schema: Schema, data: SerializationType): any | Promise; +} + +/** + * Turns a data object into a serialization. + * @public + * @deprecated use $ShapeSerializer + */ +export interface ShapeSerializer extends ConfigurableSerdeContext { + write(schema: Schema, value: unknown): void; + + flush(): SerializationType; +} + +/** + * A codec creates serializers and deserializers for some format such as JSON, XML, or CBOR. + * + * @public + * @deprecated use $Codec + */ +export interface Codec extends ConfigurableSerdeContext { + createSerializer(): ShapeSerializer; + createDeserializer(): ShapeDeserializer; +} + +/** + * A client protocol defines how to convert a message (e.g. HTTP request/response) to and from a data object. + * @public + * @deprecated use $ClientProtocol + */ +export interface ClientProtocol extends ConfigurableSerdeContext { + /** + * @returns the Smithy qualified shape id. + */ + getShapeId(): string; + + getRequestType(): { new (...args: any[]): Request }; + getResponseType(): { new (...args: any[]): Response }; + + /** + * @returns the payload codec if the requests/responses have a symmetric format. + * It otherwise may return null. + */ + getPayloadCodec(): Codec; + + serializeRequest( + operationSchema: OperationSchema, + input: Input, + context: HandlerExecutionContext & SerdeFunctions & EndpointBearer + ): Promise; + + updateServiceEndpoint(request: Request, endpoint: EndpointV2): Request; + + deserializeResponse( + operationSchema: OperationSchema, + context: HandlerExecutionContext & SerdeFunctions, + response: Response + ): Promise; +} diff --git a/packages/types/src/schema/schema.ts b/packages/types/src/schema/schema.ts index 4a53e4b3b58..c9dc21ee448 100644 --- a/packages/types/src/schema/schema.ts +++ b/packages/types/src/schema/schema.ts @@ -21,19 +21,9 @@ import type { TraitBitVector } from "./traits"; /** * A schema is an object or value that describes how to serialize/deserialize data. - * @public + * @alpha */ -export type Schema = - | UnitSchema - | TraitsSchema - | SimpleSchema - | ListSchema - | MapSchema - | StructureSchema - | MemberSchema - | OperationSchema - | StaticSchema - | NormalizedSchema; +export type $Schema = UnitSchema | SimpleSchema | $MemberSchema | StaticSchema | NormalizedSchema; /** * Traits attached to schema objects. @@ -46,17 +36,6 @@ export type Schema = */ export type SchemaTraits = TraitBitVector | SchemaTraitsObject; -/** - * A schema that has traits. - * - * @public - */ -export interface TraitsSchema { - namespace: string; - name: string; - traits: SchemaTraits; -} - /** * Simple schemas are those corresponding to simple Smithy types. * @see https://smithy.io/2.0/spec/simple-types.html @@ -95,7 +74,7 @@ export type BlobSchemas = BlobSchema | StreamingBlobSchema; * Signal value for the Smithy void value. Typically used for * operation input and outputs. * - * @internal + * @alpha */ export type UnitSchema = "unit"; @@ -152,58 +131,22 @@ export type SchemaTraitsObject = { }; /** - * Schema for the structure aggregate type. - * @public + * Indicates the schema is a member of a parent Structure schema. + * It may also have a set of member traits distinct from its target shape's traits. + * @alpha */ -export interface StructureSchema extends TraitsSchema { - name: string; - traits: SchemaTraits; - memberNames: string[]; - memberList: SchemaRef[]; - - /** - * @deprecated structure member iteration will be linear on the memberNames and memberList arrays. - * It can be collected into a hashmap form on an ad-hoc basis, but will not initialize as such. - */ - members?: Record | undefined; -} - -/** - * Schema for the list aggregate type. - * @public - */ -export interface ListSchema extends TraitsSchema { - name: string; - traits: SchemaTraits; - valueSchema: SchemaRef; -} - -/** - * Schema for the map aggregate type. - * @public - */ -export interface MapSchema extends TraitsSchema { - name: string; - traits: SchemaTraits; - keySchema: SchemaRef; - valueSchema: SchemaRef; -} - -/** - * @public - */ -export type MemberSchema = [SchemaRef, SchemaTraits]; +export type $MemberSchema = [$SchemaRef, SchemaTraits]; /** * Schema for an operation. - * - * @public + * @alpha */ -export interface OperationSchema extends TraitsSchema { +export interface $OperationSchema { + namespace: string; name: string; traits: SchemaTraits; - input: SchemaRef; - output: SchemaRef; + input: $SchemaRef; + output: $SchemaRef; } /** @@ -211,7 +154,7 @@ export interface OperationSchema extends TraitsSchema { * @public */ export interface NormalizedSchema { - getSchema(): Schema; + getSchema(): $Schema; getName(): string | undefined; isMemberSchema(): boolean; isListSchema(): boolean; @@ -243,18 +186,18 @@ export interface NormalizedSchema { * A schema "reference" is either a schema or a function that * provides a schema. This is useful for lazy loading, and to allow * code generation to define schema out of dependency order. - * @public + * @alpha */ -export type SchemaRef = Schema | (() => Schema); +export type $SchemaRef = $Schema | (() => $Schema); /** * A codec creates serializers and deserializers for some format such as JSON, XML, or CBOR. * * @public */ -export interface Codec extends ConfigurableSerdeContext { - createSerializer(): ShapeSerializer; - createDeserializer(): ShapeDeserializer; +export interface $Codec extends ConfigurableSerdeContext { + createSerializer(): $ShapeSerializer; + createDeserializer(): $ShapeDeserializer; } /** @@ -283,19 +226,19 @@ export type CodecSettings = { * Turns a serialization into a data object. * @public */ -export interface ShapeDeserializer extends ConfigurableSerdeContext { +export interface $ShapeDeserializer extends ConfigurableSerdeContext { /** * Optionally async. */ - read(schema: Schema, data: SerializationType): any | Promise; + read(schema: $Schema, data: SerializationType): any | Promise; } /** * Turns a data object into a serialization. * @public */ -export interface ShapeSerializer extends ConfigurableSerdeContext { - write(schema: Schema, value: unknown): void; +export interface $ShapeSerializer extends ConfigurableSerdeContext { + write(schema: $Schema, value: unknown): void; flush(): SerializationType; } @@ -304,7 +247,7 @@ export interface ShapeSerializer extends Configu * A client protocol defines how to convert a message (e.g. HTTP request/response) to and from a data object. * @public */ -export interface ClientProtocol extends ConfigurableSerdeContext { +export interface $ClientProtocol extends ConfigurableSerdeContext { /** * @returns the Smithy qualified shape id. */ @@ -317,10 +260,10 @@ export interface ClientProtocol extends ConfigurableSerdeCont * @returns the payload codec if the requests/responses have a symmetric format. * It otherwise may return null. */ - getPayloadCodec(): Codec; + getPayloadCodec(): $Codec; serializeRequest( - operationSchema: OperationSchema, + operationSchema: $OperationSchema, input: Input, context: HandlerExecutionContext & SerdeFunctions & EndpointBearer ): Promise; @@ -328,7 +271,7 @@ export interface ClientProtocol extends ConfigurableSerdeCont updateServiceEndpoint(request: Request, endpoint: EndpointV2): Request; deserializeResponse( - operationSchema: OperationSchema, + operationSchema: $OperationSchema, context: HandlerExecutionContext & SerdeFunctions, response: Response ): Promise; diff --git a/packages/types/src/schema/static-schemas.ts b/packages/types/src/schema/static-schemas.ts index 43b07d4c8a4..df12e3fb60a 100644 --- a/packages/types/src/schema/static-schemas.ts +++ b/packages/types/src/schema/static-schemas.ts @@ -3,7 +3,7 @@ A static schema is a non-function-call object that has no side effects. Schemas are generated as static objects to improve tree-shaking behavior in downstream applications. */ -import type { SchemaRef, SchemaTraits } from "../schema/schema"; +import type { $SchemaRef, SchemaTraits } from "../schema/schema"; /** * @alpha @@ -59,17 +59,17 @@ export type ShapeNamespace = string; /** * @alpha */ -export type StaticSimpleSchema = [StaticSchemaIdSimple, ShapeNamespace, ShapeName, SchemaTraits, SchemaRef]; +export type StaticSimpleSchema = [StaticSchemaIdSimple, ShapeNamespace, ShapeName, SchemaTraits, $SchemaRef]; /** * @alpha */ -export type StaticListSchema = [StaticSchemaIdList, ShapeNamespace, ShapeName, SchemaTraits, SchemaRef]; +export type StaticListSchema = [StaticSchemaIdList, ShapeNamespace, ShapeName, SchemaTraits, $SchemaRef]; /** * @alpha */ -export type StaticMapSchema = [StaticSchemaIdMap, ShapeNamespace, ShapeName, SchemaTraits, SchemaRef, SchemaRef]; +export type StaticMapSchema = [StaticSchemaIdMap, ShapeNamespace, ShapeName, SchemaTraits, $SchemaRef, $SchemaRef]; /** * @alpha @@ -80,7 +80,7 @@ export type StaticStructureSchema = [ ShapeName, SchemaTraits, string[], // member name list - SchemaRef[], // member schema list + $SchemaRef[], // member schema list ]; /** @@ -92,7 +92,7 @@ export type StaticErrorSchema = [ ShapeName, SchemaTraits, string[], // member name list - SchemaRef[], // member schema list + $SchemaRef[], // member schema list ]; /** @@ -103,6 +103,6 @@ export type StaticOperationSchema = [ ShapeNamespace, ShapeName, SchemaTraits, - SchemaRef, // input schema - SchemaRef, // output schema + $SchemaRef, // input schema + $SchemaRef, // output schema ]; diff --git a/packages/types/src/serde.ts b/packages/types/src/serde.ts index 8cb265f6dc8..baf84e64d0f 100644 --- a/packages/types/src/serde.ts +++ b/packages/types/src/serde.ts @@ -1,5 +1,5 @@ import type { Endpoint } from "./http"; -import type { ClientProtocol } from "./schema/schema"; +import type { $ClientProtocol } from "./schema/schema"; import type { RequestHandler } from "./transfer"; import type { Decoder, Encoder, Provider } from "./util"; @@ -35,7 +35,7 @@ export interface StreamCollector { export interface SerdeContext extends SerdeFunctions, EndpointBearer { requestHandler: RequestHandler; disableHostPrefix: boolean; - protocol?: ClientProtocol; + protocol?: $ClientProtocol; } /**