git-off

git off handles large files in git repos
git clone https://noulin.net/git/git-off.git
Log | Files | Refs | README

shape.js (9074B)


      1 var Collection = require('./collection');
      2 
      3 var util = require('../util');
      4 
      5 function property(obj, name, value) {
      6   if (value !== null && value !== undefined) {
      7     util.property.apply(this, arguments);
      8   }
      9 }
     10 
     11 function memoizedProperty(obj, name) {
     12   if (!obj.constructor.prototype[name]) {
     13     util.memoizedProperty.apply(this, arguments);
     14   }
     15 }
     16 
     17 function Shape(shape, options, memberName) {
     18   options = options || {};
     19 
     20   property(this, 'shape', shape.shape);
     21   property(this, 'api', options.api, false);
     22   property(this, 'type', shape.type);
     23   property(this, 'enum', shape.enum);
     24   property(this, 'min', shape.min);
     25   property(this, 'max', shape.max);
     26   property(this, 'pattern', shape.pattern);
     27   property(this, 'location', shape.location || this.location || 'body');
     28   property(this, 'name', this.name || shape.xmlName || shape.queryName ||
     29     shape.locationName || memberName);
     30   property(this, 'isStreaming', shape.streaming || this.isStreaming || false);
     31   property(this, 'isComposite', shape.isComposite || false);
     32   property(this, 'isShape', true, false);
     33   property(this, 'isQueryName', shape.queryName ? true : false, false);
     34   property(this, 'isLocationName', shape.locationName ? true : false, false);
     35 
     36   if (options.documentation) {
     37     property(this, 'documentation', shape.documentation);
     38     property(this, 'documentationUrl', shape.documentationUrl);
     39   }
     40 
     41   if (shape.xmlAttribute) {
     42     property(this, 'isXmlAttribute', shape.xmlAttribute || false);
     43   }
     44 
     45   // type conversion and parsing
     46   property(this, 'defaultValue', null);
     47   this.toWireFormat = function(value) {
     48     if (value === null || value === undefined) return '';
     49     return value;
     50   };
     51   this.toType = function(value) { return value; };
     52 }
     53 
     54 /**
     55  * @api private
     56  */
     57 Shape.normalizedTypes = {
     58   character: 'string',
     59   double: 'float',
     60   long: 'integer',
     61   short: 'integer',
     62   biginteger: 'integer',
     63   bigdecimal: 'float',
     64   blob: 'binary'
     65 };
     66 
     67 /**
     68  * @api private
     69  */
     70 Shape.types = {
     71   'structure': StructureShape,
     72   'list': ListShape,
     73   'map': MapShape,
     74   'boolean': BooleanShape,
     75   'timestamp': TimestampShape,
     76   'float': FloatShape,
     77   'integer': IntegerShape,
     78   'string': StringShape,
     79   'base64': Base64Shape,
     80   'binary': BinaryShape
     81 };
     82 
     83 Shape.resolve = function resolve(shape, options) {
     84   if (shape.shape) {
     85     var refShape = options.api.shapes[shape.shape];
     86     if (!refShape) {
     87       throw new Error('Cannot find shape reference: ' + shape.shape);
     88     }
     89 
     90     return refShape;
     91   } else {
     92     return null;
     93   }
     94 };
     95 
     96 Shape.create = function create(shape, options, memberName) {
     97   if (shape.isShape) return shape;
     98 
     99   var refShape = Shape.resolve(shape, options);
    100   if (refShape) {
    101     var filteredKeys = Object.keys(shape);
    102     if (!options.documentation) {
    103       filteredKeys = filteredKeys.filter(function(name) {
    104         return !name.match(/documentation/);
    105       });
    106     }
    107     if (filteredKeys === ['shape']) { // no inline customizations
    108       return refShape;
    109     }
    110 
    111     // create an inline shape with extra members
    112     var InlineShape = function() {
    113       refShape.constructor.call(this, shape, options, memberName);
    114     };
    115     InlineShape.prototype = refShape;
    116     return new InlineShape();
    117   } else {
    118     // set type if not set
    119     if (!shape.type) {
    120       if (shape.members) shape.type = 'structure';
    121       else if (shape.member) shape.type = 'list';
    122       else if (shape.key) shape.type = 'map';
    123       else shape.type = 'string';
    124     }
    125 
    126     // normalize types
    127     var origType = shape.type;
    128     if (Shape.normalizedTypes[shape.type]) {
    129       shape.type = Shape.normalizedTypes[shape.type];
    130     }
    131 
    132     if (Shape.types[shape.type]) {
    133       return new Shape.types[shape.type](shape, options, memberName);
    134     } else {
    135       throw new Error('Unrecognized shape type: ' + origType);
    136     }
    137   }
    138 };
    139 
    140 function CompositeShape(shape) {
    141   Shape.apply(this, arguments);
    142   property(this, 'isComposite', true);
    143 
    144   if (shape.flattened) {
    145     property(this, 'flattened', shape.flattened || false);
    146   }
    147 }
    148 
    149 function StructureShape(shape, options) {
    150   var requiredMap = null, firstInit = !this.isShape;
    151 
    152   CompositeShape.apply(this, arguments);
    153 
    154   if (firstInit) {
    155     property(this, 'defaultValue', function() { return {}; });
    156     property(this, 'members', {});
    157     property(this, 'memberNames', []);
    158     property(this, 'required', []);
    159     property(this, 'isRequired', function() { return false; });
    160   }
    161 
    162   if (shape.members) {
    163     property(this, 'members', new Collection(shape.members, options, function(name, member) {
    164       return Shape.create(member, options, name);
    165     }));
    166     memoizedProperty(this, 'memberNames', function() {
    167       return shape.xmlOrder || Object.keys(shape.members);
    168     });
    169   }
    170 
    171   if (shape.required) {
    172     property(this, 'required', shape.required);
    173     property(this, 'isRequired', function(name) {
    174       if (!requiredMap) {
    175         requiredMap = {};
    176         for (var i = 0; i < shape.required.length; i++) {
    177           requiredMap[shape.required[i]] = true;
    178         }
    179       }
    180 
    181       return requiredMap[name];
    182     }, false, true);
    183   }
    184 
    185   property(this, 'resultWrapper', shape.resultWrapper || null);
    186 
    187   if (shape.payload) {
    188     property(this, 'payload', shape.payload);
    189   }
    190 
    191   if (typeof shape.xmlNamespace === 'string') {
    192     property(this, 'xmlNamespaceUri', shape.xmlNamespace);
    193   } else if (typeof shape.xmlNamespace === 'object') {
    194     property(this, 'xmlNamespacePrefix', shape.xmlNamespace.prefix);
    195     property(this, 'xmlNamespaceUri', shape.xmlNamespace.uri);
    196   }
    197 }
    198 
    199 function ListShape(shape, options) {
    200   var self = this, firstInit = !this.isShape;
    201   CompositeShape.apply(this, arguments);
    202 
    203   if (firstInit) {
    204     property(this, 'defaultValue', function() { return []; });
    205   }
    206 
    207   if (shape.member) {
    208     memoizedProperty(this, 'member', function() {
    209       return Shape.create(shape.member, options);
    210     });
    211   }
    212 
    213   if (this.flattened) {
    214     var oldName = this.name;
    215     memoizedProperty(this, 'name', function() {
    216       return self.member.name || oldName;
    217     });
    218   }
    219 }
    220 
    221 function MapShape(shape, options) {
    222   var firstInit = !this.isShape;
    223   CompositeShape.apply(this, arguments);
    224 
    225   if (firstInit) {
    226     property(this, 'defaultValue', function() { return {}; });
    227     property(this, 'key', Shape.create({type: 'string'}, options));
    228     property(this, 'value', Shape.create({type: 'string'}, options));
    229   }
    230 
    231   if (shape.key) {
    232     memoizedProperty(this, 'key', function() {
    233       return Shape.create(shape.key, options);
    234     });
    235   }
    236   if (shape.value) {
    237     memoizedProperty(this, 'value', function() {
    238       return Shape.create(shape.value, options);
    239     });
    240   }
    241 }
    242 
    243 function TimestampShape(shape) {
    244   var self = this;
    245   Shape.apply(this, arguments);
    246 
    247   if (this.location === 'header') {
    248     property(this, 'timestampFormat', 'rfc822');
    249   } else if (shape.timestampFormat) {
    250     property(this, 'timestampFormat', shape.timestampFormat);
    251   } else if (this.api) {
    252     if (this.api.timestampFormat) {
    253       property(this, 'timestampFormat', this.api.timestampFormat);
    254     } else {
    255       switch (this.api.protocol) {
    256         case 'json':
    257         case 'rest-json':
    258           property(this, 'timestampFormat', 'unixTimestamp');
    259           break;
    260         case 'rest-xml':
    261         case 'query':
    262         case 'ec2':
    263           property(this, 'timestampFormat', 'iso8601');
    264           break;
    265       }
    266     }
    267   }
    268 
    269   this.toType = function(value) {
    270     if (value === null || value === undefined) return null;
    271     if (typeof value.toUTCString === 'function') return value;
    272     return typeof value === 'string' || typeof value === 'number' ?
    273            util.date.parseTimestamp(value) : null;
    274   };
    275 
    276   this.toWireFormat = function(value) {
    277     return util.date.format(value, self.timestampFormat);
    278   };
    279 }
    280 
    281 function StringShape() {
    282   Shape.apply(this, arguments);
    283 
    284   if (this.api) {
    285     switch (this.api.protocol) {
    286       case 'rest-xml':
    287       case 'query':
    288       case 'ec2':
    289         this.toType = function(value) { return value || ''; };
    290     }
    291   }
    292 }
    293 
    294 function FloatShape() {
    295   Shape.apply(this, arguments);
    296 
    297   this.toType = function(value) {
    298     if (value === null || value === undefined) return null;
    299     return parseFloat(value);
    300   };
    301   this.toWireFormat = this.toType;
    302 }
    303 
    304 function IntegerShape() {
    305   Shape.apply(this, arguments);
    306 
    307   this.toType = function(value) {
    308     if (value === null || value === undefined) return null;
    309     return parseInt(value, 10);
    310   };
    311   this.toWireFormat = this.toType;
    312 }
    313 
    314 function BinaryShape() {
    315   Shape.apply(this, arguments);
    316   this.toType = util.base64.decode;
    317   this.toWireFormat = util.base64.encode;
    318 }
    319 
    320 function Base64Shape() {
    321   BinaryShape.apply(this, arguments);
    322 }
    323 
    324 function BooleanShape() {
    325   Shape.apply(this, arguments);
    326 
    327   this.toType = function(value) {
    328     if (typeof value === 'boolean') return value;
    329     if (value === null || value === undefined) return null;
    330     return value === 'true';
    331   };
    332 }
    333 
    334 /**
    335  * @api private
    336  */
    337 Shape.shapes = {
    338   StructureShape: StructureShape,
    339   ListShape: ListShape,
    340   MapShape: MapShape,
    341   StringShape: StringShape,
    342   BooleanShape: BooleanShape,
    343   Base64Shape: Base64Shape
    344 };
    345 
    346 module.exports = Shape;