1 | var fillRefs, fs, getDescriptions, getSchemas, isAllowedTypeless, mergeAllOf, path, renderCapabilities, renderMessage, renderMessages, renderProperty, schemas,
|
2 | hasProp = {}.hasOwnProperty;
|
3 |
|
4 | fs = require('fs');
|
5 |
|
6 | path = require('path');
|
7 |
|
8 | schemas = null;
|
9 |
|
10 | getSchemas = function() {
|
11 | var dir, filename, i, jsonFile, len, name, ref, schema;
|
12 | if (!schemas) {
|
13 | schemas = {};
|
14 | dir = './schema/json/';
|
15 | ref = fs.readdirSync(dir);
|
16 | for (i = 0, len = ref.length; i < len; i++) {
|
17 | jsonFile = ref[i];
|
18 | if (jsonFile !== '.' && jsonFile !== '..') {
|
19 | name = jsonFile.split('.')[0];
|
20 | filename = path.join(dir, jsonFile);
|
21 | schema = JSON.parse(fs.readFileSync(filename));
|
22 | schemas[name] = schema;
|
23 | }
|
24 | }
|
25 | }
|
26 | return schemas;
|
27 | };
|
28 |
|
29 | fillRefs = function(obj, baseUrl) {
|
30 | var key, newObj, refKey, refObj, refValue, schemaPath, tv4, value;
|
31 | tv4 = require('../schema/index.js');
|
32 | if (typeof obj !== 'object') {
|
33 | return obj;
|
34 | } else if ((typeof obj) === 'object' && (obj.length != null)) {
|
35 | return obj.map(function(item) {
|
36 | return fillRefs(item, baseUrl);
|
37 | });
|
38 | }
|
39 | newObj = {};
|
40 | for (key in obj) {
|
41 | if (!hasProp.call(obj, key)) continue;
|
42 | value = obj[key];
|
43 | if (key === '$ref') {
|
44 | schemaPath = value;
|
45 | if (schemaPath.indexOf('../') !== -1) {
|
46 | schemaPath = path.resolve(path.dirname(`${baseUrl}${obj.id}`), value);
|
47 | }
|
48 | refObj = fillRefs(tv4.getSchema(schemaPath), baseUrl);
|
49 | for (refKey in refObj) {
|
50 | if (!hasProp.call(refObj, refKey)) continue;
|
51 | refValue = refObj[refKey];
|
52 | newObj[refKey] = refValue;
|
53 | }
|
54 | } else {
|
55 | newObj[key] = fillRefs(value, baseUrl);
|
56 | }
|
57 | }
|
58 | return newObj;
|
59 | };
|
60 |
|
61 | mergeAllOf = function(obj) {
|
62 | var i, key, len, mergeObj, newObj, prop, propName, ref, value;
|
63 | if (!(typeof obj === "object" && (obj.length == null))) {
|
64 | return obj;
|
65 | }
|
66 | newObj = {};
|
67 | for (key in obj) {
|
68 | value = obj[key];
|
69 | if (key === 'allOf') {
|
70 | ref = obj[key];
|
71 | for (i = 0, len = ref.length; i < len; i++) {
|
72 | mergeObj = ref[i];
|
73 | for (propName in mergeObj) {
|
74 | prop = mergeObj[propName];
|
75 | if (newObj[propName] == null) {
|
76 | newObj[propName] = prop;
|
77 | }
|
78 | }
|
79 | }
|
80 | } else if (typeof value === "object" && (value.length == null)) {
|
81 | newObj[key] = mergeAllOf(value);
|
82 | } else {
|
83 | newObj[key] = value;
|
84 | }
|
85 | }
|
86 | return newObj;
|
87 | };
|
88 |
|
89 |
|
90 | getDescriptions = function(schemas) {
|
91 | var categories, category, desc, event, i, key, len, message, messages, protocol, protocols, ref, ref1, schema, value;
|
92 | desc = {};
|
93 | protocols = {
|
94 | runtime: ['input', 'output'],
|
95 | graph: ['input'],
|
96 | component: ['input', 'output'],
|
97 | network: ['input', 'output'],
|
98 | trace: ['input', 'output']
|
99 | };
|
100 | for (protocol in protocols) {
|
101 | categories = protocols[protocol];
|
102 | messages = {};
|
103 | desc[protocol] = {
|
104 | title: schemas[protocol].title,
|
105 | description: schemas[protocol].description,
|
106 | messages: messages
|
107 | };
|
108 | for (i = 0, len = categories.length; i < len; i++) {
|
109 | category = categories[i];
|
110 | ref = schemas[protocol][category];
|
111 | for (event in ref) {
|
112 | schema = ref[event];
|
113 | schema = fillRefs(schema, `/${protocol}/`);
|
114 | message = {
|
115 | id: schema.id,
|
116 | description: schema.description
|
117 | };
|
118 | if (schema.allOf != null) {
|
119 | ref1 = schema.allOf[1].properties.payload;
|
120 |
|
121 | for (key in ref1) {
|
122 | value = ref1[key];
|
123 | message[key] = value;
|
124 | }
|
125 | }
|
126 |
|
127 |
|
128 | messages[event] = mergeAllOf(message);
|
129 | }
|
130 | }
|
131 | }
|
132 | return desc;
|
133 | };
|
134 |
|
135 | isAllowedTypeless = function(name, parent) {
|
136 | if (parent.id === '/shared/port_definition' && name === 'default') {
|
137 | return true;
|
138 | }
|
139 | if (parent.id === '/runtime/input/packet' && name === 'payload') {
|
140 | return true;
|
141 | }
|
142 | if (parent.id === 'input/packet' && name === 'payload') {
|
143 | return true;
|
144 | }
|
145 | if (parent.id === '/runtime/output/packet' && name === 'payload') {
|
146 | return true;
|
147 | }
|
148 | if (parent.id === 'output/packet' && name === 'payload') {
|
149 | return true;
|
150 | }
|
151 | if (parent.id === 'output/packetsent' && name === 'payload') {
|
152 | return true;
|
153 | }
|
154 | return false;
|
155 | };
|
156 |
|
157 | renderProperty = function(name, def, parent) {
|
158 | var classes, description, example, isOptional, ref, ref1, ref2, ref3, ref4, ref5, type;
|
159 | if (!def.description) {
|
160 | throw new Error(`Property ${name} is missing .description`);
|
161 | }
|
162 | if (!isAllowedTypeless(name, parent)) {
|
163 | if (!def.type) {
|
164 | throw new Error(`Property ${name} is missing .type`);
|
165 | }
|
166 | }
|
167 | if (!parent) {
|
168 | throw new Error(`Parent schema not specified for ${name}`);
|
169 | }
|
170 | if (parent.type === 'array') {
|
171 | if (!((ref = parent.items) != null ? (ref1 = ref.required) != null ? ref1.length : void 0 : void 0)) {
|
172 | throw new Error(`.required array not specified for ${name} of ${parent.id} (array)`);
|
173 | }
|
174 | } else {
|
175 | if (((ref2 = parent.required) != null ? ref2.length : void 0) == null) {
|
176 | console.log(JSON.stringify(parent, null, 2));
|
177 | throw new Error(`.required array not specified for ${name} of ${parent.id}`);
|
178 | }
|
179 | }
|
180 | isOptional = (parent.type === 'array' && ((ref3 = parent.required) != null ? ref3.indexOf(name) : void 0) === -1) || ((ref4 = parent.items) != null ? (ref5 = ref4.required) != null ? ref5.indexOf(name) : void 0 : void 0) === -1;
|
181 | classes = "property";
|
182 | if (isOptional) {
|
183 | classes += " optional";
|
184 | }
|
185 | name = `<label class='${classes} name'>${name}</label>`;
|
186 | type = `<label class='${classes} type'>${def.type || 'any'}</label>`;
|
187 | description = `<label class='${classes} description'>${def.description}</label>`;
|
188 | example = "";
|
189 | if (def.example != null) {
|
190 | example = `<code class='${classes} example'>${JSON.stringify(def.example)}</code>`;
|
191 | }
|
192 | return name + type + description + example;
|
193 | };
|
194 |
|
195 | renderMessage = function(messageType, message, protocolName) {
|
196 | var anchorUrl, itemProp, itemPropName, itemSubProp, itemSubPropName, items, line, lines, messageId, messageProp, messagePropName, p, ref, ref1, ref2, ref3, subProp, subPropName;
|
197 | lines = [];
|
198 | p = function(line) {
|
199 | return lines.push(line);
|
200 | };
|
201 | messageId = `${protocolName}-${messageType}`;
|
202 | anchorUrl = '#' + messageId;
|
203 | p(`<h3 id='${messageId}' class='message name'><a href='${anchorUrl}'>${messageType}</a></h3>`);
|
204 | p(`<p>${message.description}</p>`);
|
205 | p("<ul class='message properties'>");
|
206 | ref = message.properties;
|
207 | for (messagePropName in ref) {
|
208 | messageProp = ref[messagePropName];
|
209 | line = `<li>${renderProperty(messagePropName, messageProp, message)}</li>`;
|
210 | items = messageProp.items;
|
211 | if (messageProp.type === 'object' && (messageProp.properties != null)) {
|
212 | p(line);
|
213 | p("<ul class='properties'>");
|
214 | ref1 = messageProp.properties;
|
215 | for (subPropName in ref1) {
|
216 | subProp = ref1[subPropName];
|
217 | p(`<li>${renderProperty(subPropName, subProp, messageProp)}</li>`);
|
218 | }
|
219 | p("</ul>");
|
220 | } else if ((items != null ? items.type : void 0) === 'object') {
|
221 | line += "Each item contains:";
|
222 | p(line);
|
223 | p("<ul class='properties'>");
|
224 | ref2 = items.properties;
|
225 | for (itemPropName in ref2) {
|
226 | itemProp = ref2[itemPropName];
|
227 | if (itemProp.type === 'object') {
|
228 | p(`<li>${renderProperty(itemPropName, itemProp, messageProp)}</li>`);
|
229 | p("<ul class='properties'>");
|
230 | ref3 = itemProp.properties;
|
231 | for (itemSubPropName in ref3) {
|
232 | itemSubProp = ref3[itemSubPropName];
|
233 | p(`<li>${renderProperty(itemSubPropName, itemSubProp, itemProp)}</li>`);
|
234 | }
|
235 | p("</ul>");
|
236 | } else {
|
237 | p(`<li>${renderProperty(itemPropName, itemProp, messageProp)}</li>`);
|
238 | }
|
239 | }
|
240 | p("</ul>");
|
241 | } else {
|
242 | p(line);
|
243 | }
|
244 | }
|
245 | p("</ul>");
|
246 | return lines;
|
247 | };
|
248 |
|
249 | renderCapabilities = function() {
|
250 | var enumDescription, i, j, k, len, len1, len2, lines, messageUrl, name, p, ref, ref1, ref2, schema, tv4;
|
251 | tv4 = require('../schema/index.js');
|
252 | schema = tv4.getSchema('/shared/capabilities');
|
253 | lines = [];
|
254 | p = function(line) {
|
255 | return lines.push(line);
|
256 | };
|
257 | p("<section class='capabilities'>");
|
258 | ref = schema.items._enumDescriptions;
|
259 | for (i = 0, len = ref.length; i < len; i++) {
|
260 | enumDescription = ref[i];
|
261 | p(`<h4 class='capability name'>${enumDescription.name}</h4>`);
|
262 | p(`<p>${enumDescription.description}</p>`);
|
263 | p("<h5 class='capability messages header'>input messages</h5>");
|
264 | p("<ul class='capability messages'>");
|
265 | ref1 = enumDescription.inputs;
|
266 | for (j = 0, len1 = ref1.length; j < len1; j++) {
|
267 | name = ref1[j];
|
268 | messageUrl = "#" + name.replace(':', '-');
|
269 | p(`<li><a href='${messageUrl}'>${name}</a></li>`);
|
270 | }
|
271 | p("</ul>");
|
272 | p("<h5 class='capability messages header'>output messages</h5>");
|
273 | p("<ul class='capability messages'>");
|
274 | ref2 = enumDescription.outputs;
|
275 | for (k = 0, len2 = ref2.length; k < len2; k++) {
|
276 | name = ref2[k];
|
277 | messageUrl = "#" + name.replace(':', '-');
|
278 | p(`<li><a href='${messageUrl}'>${name}</a></li>`);
|
279 | }
|
280 | p("</ul>");
|
281 | }
|
282 | p("</section>");
|
283 | return lines.join('\n');
|
284 | };
|
285 |
|
286 | renderMessages = function() {
|
287 | var descriptions, lines, m, message, messageType, p, protocol, protocolProps, ref;
|
288 | schemas = getSchemas();
|
289 | descriptions = getDescriptions(schemas);
|
290 | lines = [];
|
291 | p = function(line) {
|
292 | return lines.push(line);
|
293 | };
|
294 | for (protocol in descriptions) {
|
295 | protocolProps = descriptions[protocol];
|
296 | p(`<h2 class='protocol name'>${protocolProps.title}</h2>`);
|
297 | p(`<p class='protocol description'>${protocolProps.description}</p>`);
|
298 | ref = protocolProps.messages;
|
299 | for (messageType in ref) {
|
300 | message = ref[messageType];
|
301 | m = renderMessage(messageType, message, protocol);
|
302 | lines = lines.concat(m);
|
303 | }
|
304 | }
|
305 | return lines.join('\n');
|
306 | };
|
307 |
|
308 | module.exports = {
|
309 | renderMessages: renderMessages,
|
310 | renderCapabilities: renderCapabilities,
|
311 | getSchemas: getSchemas
|
312 | };
|