github.com/enmand/kubernetes@v1.2.0-alpha.0/third_party/swagger-ui/lib/shred/content.js (about)

     1  
     2  // The purpose of the `Content` object is to abstract away the data conversions
     3  // to and from raw content entities as strings. For example, you want to be able
     4  // to pass in a Javascript object and have it be automatically converted into a
     5  // JSON string if the `content-type` is set to a JSON-based media type.
     6  // Conversely, you want to be able to transparently get back a Javascript object
     7  // in the response if the `content-type` is a JSON-based media-type.
     8  
     9  // One limitation of the current implementation is that it [assumes the `charset` is UTF-8](https://github.com/spire-io/shred/issues/5).
    10  
    11  // The `Content` constructor takes an options object, which *must* have either a
    12  // `body` or `data` property and *may* have a `type` property indicating the
    13  // media type. If there is no `type` attribute, a default will be inferred.
    14  var Content = function(options) {
    15    this.body = options.body;
    16    this.data = options.data;
    17    this.type = options.type;
    18  };
    19  
    20  Content.prototype = {
    21    // Treat `toString()` as asking for the `content.body`. That is, the raw content entity.
    22    //
    23    //     toString: function() { return this.body; }
    24    //
    25    // Commented out, but I've forgotten why. :/
    26  };
    27  
    28  
    29  // `Content` objects have the following attributes:
    30  Object.defineProperties(Content.prototype,{
    31    
    32  // - **type**. Typically accessed as `content.type`, reflects the `content-type`
    33  //   header associated with the request or response. If not passed as an options
    34  //   to the constructor or set explicitly, it will infer the type the `data`
    35  //   attribute, if possible, and, failing that, will default to `text/plain`.
    36    type: {
    37      get: function() {
    38        if (this._type) {
    39          return this._type;
    40        } else {
    41          if (this._data) {
    42            switch(typeof this._data) {
    43              case "string": return "text/plain";
    44              case "object": return "application/json";
    45            }
    46          }
    47        }
    48        return "text/plain";
    49      },
    50      set: function(value) {
    51        this._type = value;
    52        return this;
    53      },
    54      enumerable: true
    55    },
    56  
    57  // - **data**. Typically accessed as `content.data`, reflects the content entity
    58  //   converted into Javascript data. This can be a string, if the `type` is, say,
    59  //   `text/plain`, but can also be a Javascript object. The conversion applied is
    60  //   based on the `processor` attribute. The `data` attribute can also be set
    61  //   directly, in which case the conversion will be done the other way, to infer
    62  //   the `body` attribute.
    63    data: {
    64      get: function() {
    65        if (this._body) {
    66          return this.processor.parser(this._body);
    67        } else {
    68          return this._data;
    69        }
    70      },
    71      set: function(data) {
    72        if (this._body&&data) Errors.setDataWithBody(this);
    73        this._data = data;
    74        return this;
    75      },
    76      enumerable: true
    77    },
    78  
    79  // - **body**. Typically accessed as `content.body`, reflects the content entity
    80  //   as a UTF-8 string. It is the mirror of the `data` attribute. If you set the
    81  //   `data` attribute, the `body` attribute will be inferred and vice-versa. If
    82  //   you attempt to set both, an exception is raised.
    83    body: {
    84      get: function() {
    85        if (this._data) {
    86          return this.processor.stringify(this._data);
    87        } else {
    88          return this._body.toString();
    89        }
    90      },
    91      set: function(body) {
    92        if (this._data&&body) Errors.setBodyWithData(this);
    93        this._body = body;
    94        return this;
    95      },
    96      enumerable: true
    97    },
    98  
    99  // - **processor**. The functions that will be used to convert to/from `data` and
   100  //   `body` attributes. You can add processors. The two that are built-in are for
   101  //   `text/plain`, which is basically an identity transformation and
   102  //   `application/json` and other JSON-based media types (including custom media
   103  //   types with `+json`). You can add your own processors. See below.
   104    processor: {
   105      get: function() {
   106        var processor = Content.processors[this.type];
   107        if (processor) {
   108          return processor;
   109        } else {
   110          // Return the first processor that matches any part of the
   111          // content type. ex: application/vnd.foobar.baz+json will match json.
   112          var main = this.type.split(";")[0];
   113          var parts = main.split(/\+|\//);
   114          for (var i=0, l=parts.length; i < l; i++) {
   115            processor = Content.processors[parts[i]]
   116          }
   117          return processor || {parser:identity,stringify:toString};
   118        }
   119      },
   120      enumerable: true
   121    },
   122  
   123  // - **length**. Typically accessed as `content.length`, returns the length in
   124  //   bytes of the raw content entity.
   125    length: {
   126      get: function() {
   127        if (typeof Buffer !== 'undefined') {
   128          return Buffer.byteLength(this.body);
   129        }
   130        return this.body.length;
   131      }
   132    }
   133  });
   134  
   135  Content.processors = {};
   136  
   137  // The `registerProcessor` function allows you to add your own processors to
   138  // convert content entities. Each processor consists of a Javascript object with
   139  // two properties:
   140  // - **parser**. The function used to parse a raw content entity and convert it
   141  //   into a Javascript data type.
   142  // - **stringify**. The function used to convert a Javascript data type into a
   143  //   raw content entity.
   144  Content.registerProcessor = function(types,processor) {
   145    
   146  // You can pass an array of types that will trigger this processor, or just one.
   147  // We determine the array via duck-typing here.
   148    if (types.forEach) {
   149      types.forEach(function(type) {
   150        Content.processors[type] = processor;
   151      });
   152    } else {
   153      // If you didn't pass an array, we just use what you pass in.
   154      Content.processors[types] = processor;
   155    }
   156  };
   157  
   158  // Register the identity processor, which is used for text-based media types.
   159  var identity = function(x) { return x; }
   160    , toString = function(x) { return x.toString(); }
   161  Content.registerProcessor(
   162    ["text/html","text/plain","text"],
   163    { parser: identity, stringify: toString });
   164  
   165  // Register the JSON processor, which is used for JSON-based media types.
   166  Content.registerProcessor(
   167    ["application/json; charset=utf-8","application/json","json"],
   168    {
   169      parser: function(string) {
   170        return JSON.parse(string);
   171      },
   172      stringify: function(data) {
   173        return JSON.stringify(data); }});
   174  
   175  var qs = require('querystring');
   176  // Register the post processor, which is used for JSON-based media types.
   177  Content.registerProcessor(
   178    ["application/x-www-form-urlencoded"],
   179    { parser : qs.parse, stringify : qs.stringify });
   180  
   181  // Error functions are defined separately here in an attempt to make the code
   182  // easier to read.
   183  var Errors = {
   184    setDataWithBody: function(object) {
   185      throw new Error("Attempt to set data attribute of a content object " +
   186          "when the body attributes was already set.");
   187    },
   188    setBodyWithData: function(object) {
   189      throw new Error("Attempt to set body attribute of a content object " +
   190          "when the data attributes was already set.");
   191    }
   192  }
   193  module.exports = Content;