1 |
|
2 |
|
3 | function each(obj, iter) {
|
4 | for (var key in obj) {
|
5 | if (obj.hasOwnProperty(key)) iter(key, obj[key]);
|
6 | }
|
7 | }
|
8 |
|
9 | function nextString(str) {
|
10 | return 'S' + (parseInt(str.substr(1), 36) + 1).toString(36);
|
11 | }
|
12 |
|
13 |
|
14 |
|
15 | function Translator(api, options) {
|
16 | var origLength = JSON.stringify(api, null, 2).length;
|
17 | var debugInfo = {flattened: {}, pruned: {}};
|
18 | var shapeName = 'S0';
|
19 | var shapeNameMap = {};
|
20 | var visitedShapes = {};
|
21 |
|
22 | function logResults() {
|
23 | console.log('** Generated', api.metadata.endpointPrefix + '-' +
|
24 | api.metadata.apiVersion +'.min.json' +
|
25 | (process.env.DEBUG ? ':' : ''));
|
26 |
|
27 | if (process.env.DEBUG) {
|
28 | var pruned = Object.keys(debugInfo.pruned);
|
29 | var flattened = Object.keys(debugInfo.flattened);
|
30 | var newLength = JSON.stringify(api, null, 2).length;
|
31 | console.log('- Pruned Shapes:', pruned.length);
|
32 | console.log('- Flattened Shapes:', flattened.length);
|
33 | console.log('- Remaining Shapes:', Object.keys(api.shapes).length);
|
34 | console.log('- Original Size:', origLength / 1024.0, 'kb');
|
35 | console.log('- Minified Size:', newLength / 1024.0, 'kb');
|
36 | console.log('- Size Saving:', (origLength - newLength) / 1024.0, 'kb');
|
37 | console.log('');
|
38 | }
|
39 | }
|
40 |
|
41 | function deleteTraits(obj) {
|
42 | if (!options.documentation) {
|
43 | delete obj.documentation;
|
44 | delete obj.documentationUrl;
|
45 | delete obj.errors;
|
46 | delete obj.min;
|
47 | delete obj.max;
|
48 | delete obj.pattern;
|
49 | delete obj['enum'];
|
50 | delete obj.box;
|
51 | }
|
52 | }
|
53 |
|
54 | function trackShapeDeclaration(ref) {
|
55 | if (ref.shape && !shapeNameMap[ref.shape]) {
|
56 |
|
57 |
|
58 | var oldShapeName = ref.shape;
|
59 | ref.shape = shapeName = nextString(shapeName);
|
60 |
|
61 | visitedShapes[shapeName] = api.shapes[oldShapeName];
|
62 | shapeNameMap[oldShapeName] = {name: shapeName, refs: [ref]};
|
63 |
|
64 | traverseShapeRef(api.shapes[oldShapeName]);
|
65 | } else if (ref.shape && shapeNameMap[ref.shape]) {
|
66 |
|
67 |
|
68 | var map = shapeNameMap[ref.shape];
|
69 | map.refs.push(ref);
|
70 | ref.shape = map.name;
|
71 | }
|
72 | }
|
73 |
|
74 | function pruneShapes() {
|
75 |
|
76 | each(shapeNameMap, function(name, map) {
|
77 | if (Object.keys(visitedShapes[map.name]).join() === 'type' &&
|
78 | ['structure','map','list'].indexOf(visitedShapes[map.name].type) < 0) {
|
79 |
|
80 | for (var i = 0; i < map.refs.length; i++) {
|
81 | var ref = map.refs[i];
|
82 | debugInfo.flattened[name] = true;
|
83 | delete ref.shape;
|
84 | ref.type = visitedShapes[map.name].type;
|
85 |
|
86 |
|
87 | if (ref.type === 'string') delete ref.type;
|
88 | }
|
89 |
|
90 |
|
91 | delete visitedShapes[map.name];
|
92 | debugInfo.pruned[name] = true;
|
93 | } else if (map.refs.length === 1) {
|
94 |
|
95 | var shape = visitedShapes[map.name];
|
96 |
|
97 | for (var i = 0; i < map.refs.length; i++) {
|
98 | delete map.refs[i].shape;
|
99 | for (var prop in shape) {
|
100 | if (shape.hasOwnProperty(prop)) {
|
101 |
|
102 | if (map.refs[i].hasOwnProperty(prop) && ['timestampFormat'].indexOf(prop) >= 0) {
|
103 | continue;
|
104 | }
|
105 | map.refs[i][prop] = shape[prop];
|
106 | }
|
107 |
|
108 | }
|
109 | }
|
110 |
|
111 |
|
112 | delete visitedShapes[map.name];
|
113 | debugInfo.pruned[name] = true;
|
114 | }
|
115 | });
|
116 | }
|
117 |
|
118 | function traverseShapeRef(ref) {
|
119 | if (!ref) return;
|
120 |
|
121 | deleteTraits(ref);
|
122 |
|
123 | traverseShapeRef(ref.key);
|
124 | traverseShapeRef(ref.value);
|
125 | traverseShapeRef(ref.member);
|
126 |
|
127 |
|
128 | each(ref.members || {}, function(key, value) { traverseShapeRef(value); });
|
129 |
|
130 |
|
131 | trackShapeDeclaration(ref);
|
132 | }
|
133 |
|
134 | function traverseOperation(op) {
|
135 | deleteTraits(op);
|
136 |
|
137 | delete op.name;
|
138 | if (op.http) {
|
139 | if (op.http.method === 'POST') delete op.http.method;
|
140 | if (op.http.requestUri === '/') delete op.http.requestUri;
|
141 | if (Object.keys(op.http).length === 0) delete op.http;
|
142 | }
|
143 |
|
144 | traverseShapeRef(op.input);
|
145 | traverseShapeRef(op.output);
|
146 | }
|
147 |
|
148 | function traverseApi() {
|
149 | deleteTraits(api);
|
150 | each(api.operations, function(name, op) { traverseOperation(op); });
|
151 | api.shapes = visitedShapes;
|
152 | }
|
153 |
|
154 | traverseApi();
|
155 | pruneShapes();
|
156 | logResults();
|
157 | return api;
|
158 | }
|
159 |
|
160 | module.exports = Translator;
|