UNPKG

lambda-live-debugger

Version:

Debug Lambda functions locally like it is running in the cloud

177 lines (176 loc) 7.07 kB
import { determineTimestampFormat } from "@smithy/core/protocols"; import { NormalizedSchema } from "@smithy/core/schema"; import { dateToUtcString, generateIdempotencyToken, LazyJsonString, NumericValue } from "@smithy/core/serde"; import { toBase64 } from "@smithy/util-base64"; import { SerdeContextConfig } from "../ConfigurableSerdeContext"; import { JsonReplacer } from "./jsonReplacer"; export class JsonShapeSerializer extends SerdeContextConfig { settings; buffer; useReplacer = false; rootSchema; constructor(settings) { super(); this.settings = settings; } write(schema, value) { this.rootSchema = NormalizedSchema.of(schema); this.buffer = this._write(this.rootSchema, value); } writeDiscriminatedDocument(schema, value) { this.write(schema, value); if (typeof this.buffer === "object") { this.buffer.__type = NormalizedSchema.of(schema).getName(true); } } flush() { const { rootSchema, useReplacer } = this; this.rootSchema = undefined; this.useReplacer = false; if (rootSchema?.isStructSchema() || rootSchema?.isDocumentSchema()) { if (!useReplacer) { return JSON.stringify(this.buffer); } const replacer = new JsonReplacer(); return replacer.replaceInJson(JSON.stringify(this.buffer, replacer.createReplacer(), 0)); } return this.buffer; } _write(schema, value, container) { const isObject = value !== null && typeof value === "object"; const ns = NormalizedSchema.of(schema); if (isObject) { if (ns.isStructSchema()) { const record = value; const out = {}; const { jsonName } = this.settings; let nameMap = void 0; if (jsonName) { nameMap = {}; } for (const [memberName, memberSchema] of ns.structIterator()) { const serializableValue = this._write(memberSchema, record[memberName], ns); if (serializableValue !== undefined) { let targetKey = memberName; if (jsonName) { targetKey = memberSchema.getMergedTraits().jsonName ?? memberName; nameMap[memberName] = targetKey; } out[targetKey] = serializableValue; } } if (ns.isUnionSchema() && Object.keys(out).length === 0) { const { $unknown } = record; if (Array.isArray($unknown)) { const [k, v] = $unknown; out[k] = this._write(15, v); } } else if (typeof record.__type === "string") { for (const [k, v] of Object.entries(record)) { const targetKey = jsonName ? nameMap[k] ?? k : k; if (!(targetKey in out)) { out[targetKey] = this._write(15, v); } } } return out; } if (Array.isArray(value) && ns.isListSchema()) { const listMember = ns.getValueSchema(); const out = []; const sparse = !!ns.getMergedTraits().sparse; for (const item of value) { if (sparse || item != null) { out.push(this._write(listMember, item)); } } return out; } if (ns.isMapSchema()) { const mapMember = ns.getValueSchema(); const out = {}; const sparse = !!ns.getMergedTraits().sparse; for (const [_k, _v] of Object.entries(value)) { if (sparse || _v != null) { out[_k] = this._write(mapMember, _v); } } return out; } if (value instanceof Uint8Array && (ns.isBlobSchema() || ns.isDocumentSchema())) { if (ns === this.rootSchema) { return value; } return (this.serdeContext?.base64Encoder ?? toBase64)(value); } if (value instanceof Date && (ns.isTimestampSchema() || ns.isDocumentSchema())) { const format = determineTimestampFormat(ns, this.settings); switch (format) { case 5: return value.toISOString().replace(".000Z", "Z"); case 6: return dateToUtcString(value); case 7: return value.getTime() / 1000; default: console.warn("Missing timestamp format, using epoch seconds", value); return value.getTime() / 1000; } } if (value instanceof NumericValue) { this.useReplacer = true; } } if (value === null && container?.isStructSchema()) { return void 0; } if (ns.isStringSchema()) { if (typeof value === "undefined" && ns.isIdempotencyToken()) { return generateIdempotencyToken(); } const mediaType = ns.getMergedTraits().mediaType; if (value != null && mediaType) { const isJson = mediaType === "application/json" || mediaType.endsWith("+json"); if (isJson) { return LazyJsonString.from(value); } } return value; } if (typeof value === "number" && ns.isNumericSchema()) { if (Math.abs(value) === Infinity || isNaN(value)) { return String(value); } return value; } if (typeof value === "string" && ns.isBlobSchema()) { if (ns === this.rootSchema) { return value; } return (this.serdeContext?.base64Encoder ?? toBase64)(value); } if (typeof value === "bigint") { this.useReplacer = true; } if (ns.isDocumentSchema()) { if (isObject) { const out = Array.isArray(value) ? [] : {}; for (const [k, v] of Object.entries(value)) { if (v instanceof NumericValue) { this.useReplacer = true; out[k] = v; } else { out[k] = this._write(ns, v); } } return out; } else { return structuredClone(value); } } return value; } }