123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- var Collection = require('./collection');
- var util = require('../util');
- function property(obj, name, value) {
- if (value !== null && value !== undefined) {
- util.property.apply(this, arguments);
- }
- }
- function memoizedProperty(obj, name) {
- if (!obj.constructor.prototype[name]) {
- util.memoizedProperty.apply(this, arguments);
- }
- }
- function Shape(shape, options, memberName) {
- options = options || {};
- property(this, 'shape', shape.shape);
- property(this, 'api', options.api, false);
- property(this, 'type', shape.type);
- property(this, 'enum', shape.enum);
- property(this, 'min', shape.min);
- property(this, 'max', shape.max);
- property(this, 'pattern', shape.pattern);
- property(this, 'location', shape.location || this.location || 'body');
- property(this, 'name', this.name || shape.xmlName || shape.queryName ||
- shape.locationName || memberName);
- property(this, 'isStreaming', shape.streaming || this.isStreaming || false);
- property(this, 'requiresLength', shape.requiresLength, false);
- property(this, 'isComposite', shape.isComposite || false);
- property(this, 'isShape', true, false);
- property(this, 'isQueryName', Boolean(shape.queryName), false);
- property(this, 'isLocationName', Boolean(shape.locationName), false);
- property(this, 'isIdempotent', shape.idempotencyToken === true);
- property(this, 'isJsonValue', shape.jsonvalue === true);
- property(this, 'isSensitive', shape.sensitive === true || shape.prototype && shape.prototype.sensitive === true);
- property(this, 'isEventStream', Boolean(shape.eventstream), false);
- property(this, 'isEvent', Boolean(shape.event), false);
- property(this, 'isEventPayload', Boolean(shape.eventpayload), false);
- property(this, 'isEventHeader', Boolean(shape.eventheader), false);
- property(this, 'isTimestampFormatSet', Boolean(shape.timestampFormat) || shape.prototype && shape.prototype.isTimestampFormatSet === true, false);
- property(this, 'endpointDiscoveryId', Boolean(shape.endpointdiscoveryid), false);
- property(this, 'hostLabel', Boolean(shape.hostLabel), false);
- if (options.documentation) {
- property(this, 'documentation', shape.documentation);
- property(this, 'documentationUrl', shape.documentationUrl);
- }
- if (shape.xmlAttribute) {
- property(this, 'isXmlAttribute', shape.xmlAttribute || false);
- }
- // type conversion and parsing
- property(this, 'defaultValue', null);
- this.toWireFormat = function(value) {
- if (value === null || value === undefined) return '';
- return value;
- };
- this.toType = function(value) { return value; };
- }
- /**
- * @api private
- */
- Shape.normalizedTypes = {
- character: 'string',
- double: 'float',
- long: 'integer',
- short: 'integer',
- biginteger: 'integer',
- bigdecimal: 'float',
- blob: 'binary'
- };
- /**
- * @api private
- */
- Shape.types = {
- 'structure': StructureShape,
- 'list': ListShape,
- 'map': MapShape,
- 'boolean': BooleanShape,
- 'timestamp': TimestampShape,
- 'float': FloatShape,
- 'integer': IntegerShape,
- 'string': StringShape,
- 'base64': Base64Shape,
- 'binary': BinaryShape
- };
- Shape.resolve = function resolve(shape, options) {
- if (shape.shape) {
- var refShape = options.api.shapes[shape.shape];
- if (!refShape) {
- throw new Error('Cannot find shape reference: ' + shape.shape);
- }
- return refShape;
- } else {
- return null;
- }
- };
- Shape.create = function create(shape, options, memberName) {
- if (shape.isShape) return shape;
- var refShape = Shape.resolve(shape, options);
- if (refShape) {
- var filteredKeys = Object.keys(shape);
- if (!options.documentation) {
- filteredKeys = filteredKeys.filter(function(name) {
- return !name.match(/documentation/);
- });
- }
- // create an inline shape with extra members
- var InlineShape = function() {
- refShape.constructor.call(this, shape, options, memberName);
- };
- InlineShape.prototype = refShape;
- return new InlineShape();
- } else {
- // set type if not set
- if (!shape.type) {
- if (shape.members) shape.type = 'structure';
- else if (shape.member) shape.type = 'list';
- else if (shape.key) shape.type = 'map';
- else shape.type = 'string';
- }
- // normalize types
- var origType = shape.type;
- if (Shape.normalizedTypes[shape.type]) {
- shape.type = Shape.normalizedTypes[shape.type];
- }
- if (Shape.types[shape.type]) {
- return new Shape.types[shape.type](shape, options, memberName);
- } else {
- throw new Error('Unrecognized shape type: ' + origType);
- }
- }
- };
- function CompositeShape(shape) {
- Shape.apply(this, arguments);
- property(this, 'isComposite', true);
- if (shape.flattened) {
- property(this, 'flattened', shape.flattened || false);
- }
- }
- function StructureShape(shape, options) {
- var self = this;
- var requiredMap = null, firstInit = !this.isShape;
- CompositeShape.apply(this, arguments);
- if (firstInit) {
- property(this, 'defaultValue', function() { return {}; });
- property(this, 'members', {});
- property(this, 'memberNames', []);
- property(this, 'required', []);
- property(this, 'isRequired', function() { return false; });
- property(this, 'isDocument', Boolean(shape.document));
- }
- if (shape.members) {
- property(this, 'members', new Collection(shape.members, options, function(name, member) {
- return Shape.create(member, options, name);
- }));
- memoizedProperty(this, 'memberNames', function() {
- return shape.xmlOrder || Object.keys(shape.members);
- });
- if (shape.event) {
- memoizedProperty(this, 'eventPayloadMemberName', function() {
- var members = self.members;
- var memberNames = self.memberNames;
- // iterate over members to find ones that are event payloads
- for (var i = 0, iLen = memberNames.length; i < iLen; i++) {
- if (members[memberNames[i]].isEventPayload) {
- return memberNames[i];
- }
- }
- });
- memoizedProperty(this, 'eventHeaderMemberNames', function() {
- var members = self.members;
- var memberNames = self.memberNames;
- var eventHeaderMemberNames = [];
- // iterate over members to find ones that are event headers
- for (var i = 0, iLen = memberNames.length; i < iLen; i++) {
- if (members[memberNames[i]].isEventHeader) {
- eventHeaderMemberNames.push(memberNames[i]);
- }
- }
- return eventHeaderMemberNames;
- });
- }
- }
- if (shape.required) {
- property(this, 'required', shape.required);
- property(this, 'isRequired', function(name) {
- if (!requiredMap) {
- requiredMap = {};
- for (var i = 0; i < shape.required.length; i++) {
- requiredMap[shape.required[i]] = true;
- }
- }
- return requiredMap[name];
- }, false, true);
- }
- property(this, 'resultWrapper', shape.resultWrapper || null);
- if (shape.payload) {
- property(this, 'payload', shape.payload);
- }
- if (typeof shape.xmlNamespace === 'string') {
- property(this, 'xmlNamespaceUri', shape.xmlNamespace);
- } else if (typeof shape.xmlNamespace === 'object') {
- property(this, 'xmlNamespacePrefix', shape.xmlNamespace.prefix);
- property(this, 'xmlNamespaceUri', shape.xmlNamespace.uri);
- }
- }
- function ListShape(shape, options) {
- var self = this, firstInit = !this.isShape;
- CompositeShape.apply(this, arguments);
- if (firstInit) {
- property(this, 'defaultValue', function() { return []; });
- }
- if (shape.member) {
- memoizedProperty(this, 'member', function() {
- return Shape.create(shape.member, options);
- });
- }
- if (this.flattened) {
- var oldName = this.name;
- memoizedProperty(this, 'name', function() {
- return self.member.name || oldName;
- });
- }
- }
- function MapShape(shape, options) {
- var firstInit = !this.isShape;
- CompositeShape.apply(this, arguments);
- if (firstInit) {
- property(this, 'defaultValue', function() { return {}; });
- property(this, 'key', Shape.create({type: 'string'}, options));
- property(this, 'value', Shape.create({type: 'string'}, options));
- }
- if (shape.key) {
- memoizedProperty(this, 'key', function() {
- return Shape.create(shape.key, options);
- });
- }
- if (shape.value) {
- memoizedProperty(this, 'value', function() {
- return Shape.create(shape.value, options);
- });
- }
- }
- function TimestampShape(shape) {
- var self = this;
- Shape.apply(this, arguments);
- if (shape.timestampFormat) {
- property(this, 'timestampFormat', shape.timestampFormat);
- } else if (self.isTimestampFormatSet && this.timestampFormat) {
- property(this, 'timestampFormat', this.timestampFormat);
- } else if (this.location === 'header') {
- property(this, 'timestampFormat', 'rfc822');
- } else if (this.location === 'querystring') {
- property(this, 'timestampFormat', 'iso8601');
- } else if (this.api) {
- switch (this.api.protocol) {
- case 'json':
- case 'rest-json':
- property(this, 'timestampFormat', 'unixTimestamp');
- break;
- case 'rest-xml':
- case 'query':
- case 'ec2':
- property(this, 'timestampFormat', 'iso8601');
- break;
- }
- }
- this.toType = function(value) {
- if (value === null || value === undefined) return null;
- if (typeof value.toUTCString === 'function') return value;
- return typeof value === 'string' || typeof value === 'number' ?
- util.date.parseTimestamp(value) : null;
- };
- this.toWireFormat = function(value) {
- return util.date.format(value, self.timestampFormat);
- };
- }
- function StringShape() {
- Shape.apply(this, arguments);
- var nullLessProtocols = ['rest-xml', 'query', 'ec2'];
- this.toType = function(value) {
- value = this.api && nullLessProtocols.indexOf(this.api.protocol) > -1 ?
- value || '' : value;
- if (this.isJsonValue) {
- return JSON.parse(value);
- }
- return value && typeof value.toString === 'function' ?
- value.toString() : value;
- };
- this.toWireFormat = function(value) {
- return this.isJsonValue ? JSON.stringify(value) : value;
- };
- }
- function FloatShape() {
- Shape.apply(this, arguments);
- this.toType = function(value) {
- if (value === null || value === undefined) return null;
- return parseFloat(value);
- };
- this.toWireFormat = this.toType;
- }
- function IntegerShape() {
- Shape.apply(this, arguments);
- this.toType = function(value) {
- if (value === null || value === undefined) return null;
- return parseInt(value, 10);
- };
- this.toWireFormat = this.toType;
- }
- function BinaryShape() {
- Shape.apply(this, arguments);
- this.toType = function(value) {
- var buf = util.base64.decode(value);
- if (this.isSensitive && util.isNode() && typeof util.Buffer.alloc === 'function') {
- /* Node.js can create a Buffer that is not isolated.
- * i.e. buf.byteLength !== buf.buffer.byteLength
- * This means that the sensitive data is accessible to anyone with access to buf.buffer.
- * If this is the node shared Buffer, then other code within this process _could_ find this secret.
- * Copy sensitive data to an isolated Buffer and zero the sensitive data.
- * While this is safe to do here, copying this code somewhere else may produce unexpected results.
- */
- var secureBuf = util.Buffer.alloc(buf.length, buf);
- buf.fill(0);
- buf = secureBuf;
- }
- return buf;
- };
- this.toWireFormat = util.base64.encode;
- }
- function Base64Shape() {
- BinaryShape.apply(this, arguments);
- }
- function BooleanShape() {
- Shape.apply(this, arguments);
- this.toType = function(value) {
- if (typeof value === 'boolean') return value;
- if (value === null || value === undefined) return null;
- return value === 'true';
- };
- }
- /**
- * @api private
- */
- Shape.shapes = {
- StructureShape: StructureShape,
- ListShape: ListShape,
- MapShape: MapShape,
- StringShape: StringShape,
- BooleanShape: BooleanShape,
- Base64Shape: Base64Shape
- };
- /**
- * @api private
- */
- module.exports = Shape;
|