|
| 1 | +var clone = require('clone'); |
| 2 | +var Velocity = require('velocityjs'); |
| 3 | +var _jsonpath = require('JSONPath'); |
| 4 | +var jsonpath = function(obj, path) { |
| 5 | + if (path === '$') { |
| 6 | + return obj; |
| 7 | + } |
| 8 | + |
| 9 | + var result = _jsonpath({ |
| 10 | + json: obj, |
| 11 | + path: path |
| 12 | + }); |
| 13 | + |
| 14 | + if (result.length === 1) { |
| 15 | + return result[0]; |
| 16 | + } else { |
| 17 | + return result; |
| 18 | + } |
| 19 | +}; |
| 20 | + |
| 21 | +module.exports = function(template, payload, params, context) { |
| 22 | + params = clone(params || {}); |
| 23 | + params.path = params.path || {}; |
| 24 | + params.querystring = params.querystring || {}; |
| 25 | + params.header = params.header || {}; |
| 26 | + |
| 27 | + context = clone(context || {}); |
| 28 | + context.identity = context.identity || {}; |
| 29 | + |
| 30 | + // API Gateway Mapping Template Reference |
| 31 | + // http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html |
| 32 | + var data = { |
| 33 | + context: context, |
| 34 | + input: { |
| 35 | + _payload: payload.toString(), |
| 36 | + path: function(path) { |
| 37 | + var obj; |
| 38 | + // if payload starts with `{` or `[` or `"`, treat as JSON |
| 39 | + if (/^\s*(?:{|\[|")/.test(this._payload)) { |
| 40 | + obj = JSON.parse(this._payload); |
| 41 | + } else { |
| 42 | + // treat as string |
| 43 | + obj = this._payload; |
| 44 | + } |
| 45 | + |
| 46 | + return jsonpath(obj, path); |
| 47 | + }, |
| 48 | + json: function(path) { |
| 49 | + var obj = JSON.parse(payload); |
| 50 | + if (typeof obj === 'string') { |
| 51 | + // re-parse when parsed payload is string. |
| 52 | + // because of |
| 53 | + // - https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-0ce08526 |
| 54 | + // - https://github.com/ToQoz/api-gateway-mapping-template/blob/master/test/_.md#example-1b8d22cd |
| 55 | + obj = JSON.parse(obj); |
| 56 | + } |
| 57 | + |
| 58 | + return JSON.stringify(jsonpath(obj, path)); |
| 59 | + }, |
| 60 | + params: function(x) { |
| 61 | + switch (true) { |
| 62 | + case x === undefined: |
| 63 | + return params; |
| 64 | + case x in params.path: |
| 65 | + return params.path[x]; |
| 66 | + case x in params.querystring: |
| 67 | + return params.querystring[x]; |
| 68 | + case x in params.header: |
| 69 | + return params.header[x]; |
| 70 | + } |
| 71 | + }, |
| 72 | + }, |
| 73 | + util: { |
| 74 | + escapeJavaScript: escapeJavaScript, |
| 75 | + urlEncode: encodeURIComponent, |
| 76 | + urlDecode: decodeURIComponent, |
| 77 | + base64Encode: base64Encode, |
| 78 | + base64Decode: base64Decode, |
| 79 | + } |
| 80 | + }; |
| 81 | + |
| 82 | + // API Gateway convert function to "{}" on toString. |
| 83 | + var returnEmptyObject = function() { return "{}"; }; |
| 84 | + [ |
| 85 | + data.input, |
| 86 | + data.input.params, |
| 87 | + data.input.path, |
| 88 | + data.input.json, |
| 89 | + data.util, |
| 90 | + data.util.escapeJavaScript, |
| 91 | + data.util.urlEncode, |
| 92 | + data.util.urlDecode, |
| 93 | + data.util.base64Encode, |
| 94 | + data.util.base64Decode, |
| 95 | + ].forEach(function(f) { |
| 96 | + f.toString = returnEmptyObject; |
| 97 | + }); |
| 98 | + |
| 99 | + var ast = Velocity.parse(template.toString()); |
| 100 | + return (new Velocity.Compile(ast)).render(data); |
| 101 | +}; |
| 102 | + |
| 103 | +function base64Encode(x) { |
| 104 | + return (new Buffer(x)).toString('base64'); |
| 105 | +} |
| 106 | + |
| 107 | +function base64Decode(x) { |
| 108 | + return (new Buffer(x, 'base64')).toString(); |
| 109 | +} |
| 110 | + |
| 111 | +// I recognize $util.escapeJavaScript as almost `escapeJSONString` and implemented so. |
| 112 | +// c.f. 24.3.2.2 Runtime Semantics: QuoteJSONString ( value ) |
| 113 | +// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-quotejsonstring |
| 114 | +// DO: 2.a -> 2.b -> 2.c -> 2.d |
| 115 | +var escapeJavaScriptTable = { |
| 116 | + '"': '\"', // 2.a |
| 117 | + '\\': '\\\\', |
| 118 | + '\b': '\\b', // 2.b (skip abbrev) |
| 119 | + '\f': '\\f', |
| 120 | + '\n': '\\n', |
| 121 | + '\r': '\\r', |
| 122 | + '\t': '\\t', |
| 123 | +}; |
| 124 | +// 2.c |
| 125 | +for (var code = 0; code < 20; code++) { |
| 126 | + escapeJavaScriptTable[String.fromCharCode(code)] = ((code < 16) ? '\\u000' : '\\u00') + code.toString(16); |
| 127 | +} |
| 128 | +function escapeJavaScript(x) { |
| 129 | + return x.split("").map(function(c) { |
| 130 | + // 2.a - 2.c |
| 131 | + if (c in escapeJavaScriptTable) { |
| 132 | + return escapeJavaScriptTable[c]; |
| 133 | + } |
| 134 | + |
| 135 | + // 2.d |
| 136 | + return c; |
| 137 | + }).join(""); |
| 138 | +} |
0 commit comments