1 |
|
2 | var DumpException, Escaper, Inline, ParseException, Pattern, Unescaper, Utils,
|
3 | __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
4 |
|
5 | Pattern = require('./Pattern');
|
6 |
|
7 | Unescaper = require('./Unescaper');
|
8 |
|
9 | Escaper = require('./Escaper');
|
10 |
|
11 | Utils = require('./Utils');
|
12 |
|
13 | ParseException = require('./Exception/ParseException');
|
14 |
|
15 | DumpException = require('./Exception/DumpException');
|
16 |
|
17 | Inline = (function() {
|
18 | function Inline() {}
|
19 |
|
20 | Inline.REGEX_QUOTED_STRING = '(?:"(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\']*(?:\'\'[^\']*)*)\')';
|
21 |
|
22 | Inline.PATTERN_TRAILING_COMMENTS = new Pattern('^\\s*#.*$');
|
23 |
|
24 | Inline.PATTERN_QUOTED_SCALAR = new Pattern('^' + Inline.REGEX_QUOTED_STRING);
|
25 |
|
26 | Inline.PATTERN_THOUSAND_NUMERIC_SCALAR = new Pattern('^(-|\\+)?[0-9,]+(\\.[0-9]+)?$');
|
27 |
|
28 | Inline.PATTERN_SCALAR_BY_DELIMITERS = {};
|
29 |
|
30 | Inline.settings = {};
|
31 |
|
32 | Inline.configure = function(exceptionOnInvalidType, objectDecoder) {
|
33 | if (exceptionOnInvalidType == null) {
|
34 | exceptionOnInvalidType = null;
|
35 | }
|
36 | if (objectDecoder == null) {
|
37 | objectDecoder = null;
|
38 | }
|
39 | this.settings.exceptionOnInvalidType = exceptionOnInvalidType;
|
40 | this.settings.objectDecoder = objectDecoder;
|
41 | };
|
42 |
|
43 | Inline.parse = function(value, exceptionOnInvalidType, objectDecoder) {
|
44 | var context, result;
|
45 | if (exceptionOnInvalidType == null) {
|
46 | exceptionOnInvalidType = false;
|
47 | }
|
48 | if (objectDecoder == null) {
|
49 | objectDecoder = null;
|
50 | }
|
51 | this.settings.exceptionOnInvalidType = exceptionOnInvalidType;
|
52 | this.settings.objectDecoder = objectDecoder;
|
53 | if (value == null) {
|
54 | return '';
|
55 | }
|
56 | value = Utils.trim(value);
|
57 | if (0 === value.length) {
|
58 | return '';
|
59 | }
|
60 | context = {
|
61 | exceptionOnInvalidType: exceptionOnInvalidType,
|
62 | objectDecoder: objectDecoder,
|
63 | i: 0
|
64 | };
|
65 | switch (value.charAt(0)) {
|
66 | case '[':
|
67 | result = this.parseSequence(value, context);
|
68 | ++context.i;
|
69 | break;
|
70 | case '{':
|
71 | result = this.parseMapping(value, context);
|
72 | ++context.i;
|
73 | break;
|
74 | default:
|
75 | result = this.parseScalar(value, null, ['"', "'"], context);
|
76 | }
|
77 | if (this.PATTERN_TRAILING_COMMENTS.replace(value.slice(context.i), '') !== '') {
|
78 | throw new ParseException('Unexpected characters near "' + value.slice(context.i) + '".');
|
79 | }
|
80 | return result;
|
81 | };
|
82 |
|
83 | Inline.dump = function(value, exceptionOnInvalidType, objectEncoder) {
|
84 | var result, type, _ref;
|
85 | if (exceptionOnInvalidType == null) {
|
86 | exceptionOnInvalidType = false;
|
87 | }
|
88 | if (objectEncoder == null) {
|
89 | objectEncoder = null;
|
90 | }
|
91 | if (value == null) {
|
92 | return 'null';
|
93 | }
|
94 | type = typeof value;
|
95 | if (type === 'object') {
|
96 | if (value instanceof Date) {
|
97 | return value.toISOString();
|
98 | } else if (objectEncoder != null) {
|
99 | result = objectEncoder(value);
|
100 | if (typeof result === 'string' || (result != null)) {
|
101 | return result;
|
102 | }
|
103 | }
|
104 | return this.dumpObject(value);
|
105 | }
|
106 | if (type === 'boolean') {
|
107 | return (value ? 'true' : 'false');
|
108 | }
|
109 | if (Utils.isDigits(value)) {
|
110 | return (type === 'string' ? "'" + value + "'" : String(parseInt(value)));
|
111 | }
|
112 | if (Utils.isNumeric(value)) {
|
113 | return (type === 'string' ? "'" + value + "'" : String(parseFloat(value)));
|
114 | }
|
115 | if (type === 'number') {
|
116 | return (value === Infinity ? '.Inf' : (value === -Infinity ? '-.Inf' : (isNaN(value) ? '.NaN' : value)));
|
117 | }
|
118 | if (Escaper.requiresDoubleQuoting(value)) {
|
119 | return Escaper.escapeWithDoubleQuotes(value);
|
120 | }
|
121 | if (Escaper.requiresSingleQuoting(value)) {
|
122 | return Escaper.escapeWithSingleQuotes(value);
|
123 | }
|
124 | if ('' === value) {
|
125 | return '""';
|
126 | }
|
127 | if (Utils.PATTERN_DATE.test(value)) {
|
128 | return "'" + value + "'";
|
129 | }
|
130 | if ((_ref = value.toLowerCase()) === 'null' || _ref === '~' || _ref === 'true' || _ref === 'false') {
|
131 | return "'" + value + "'";
|
132 | }
|
133 | return value;
|
134 | };
|
135 |
|
136 | Inline.dumpObject = function(value, exceptionOnInvalidType, objectSupport) {
|
137 | var key, output, val, _i, _len;
|
138 | if (objectSupport == null) {
|
139 | objectSupport = null;
|
140 | }
|
141 | if (value instanceof Array) {
|
142 | output = [];
|
143 | for (_i = 0, _len = value.length; _i < _len; _i++) {
|
144 | val = value[_i];
|
145 | output.push(this.dump(val));
|
146 | }
|
147 | return '[' + output.join(', ') + ']';
|
148 | } else {
|
149 | output = [];
|
150 | for (key in value) {
|
151 | val = value[key];
|
152 | output.push(this.dump(key) + ': ' + this.dump(val));
|
153 | }
|
154 | return '{' + output.join(', ') + '}';
|
155 | }
|
156 | };
|
157 |
|
158 | Inline.parseScalar = function(scalar, delimiters, stringDelimiters, context, evaluate) {
|
159 | var i, joinedDelimiters, match, output, pattern, strpos, tmp, _ref, _ref1;
|
160 | if (delimiters == null) {
|
161 | delimiters = null;
|
162 | }
|
163 | if (stringDelimiters == null) {
|
164 | stringDelimiters = ['"', "'"];
|
165 | }
|
166 | if (context == null) {
|
167 | context = null;
|
168 | }
|
169 | if (evaluate == null) {
|
170 | evaluate = true;
|
171 | }
|
172 | if (context == null) {
|
173 | context = {
|
174 | exceptionOnInvalidType: this.settings.exceptionOnInvalidType,
|
175 | objectDecoder: this.settings.objectDecoder,
|
176 | i: 0
|
177 | };
|
178 | }
|
179 | i = context.i;
|
180 | if (_ref = scalar.charAt(i), __indexOf.call(stringDelimiters, _ref) >= 0) {
|
181 | output = this.parseQuotedScalar(scalar, context);
|
182 | i = context.i;
|
183 | if (delimiters != null) {
|
184 | tmp = Utils.ltrim(scalar.slice(i), ' ');
|
185 | if (!(_ref1 = tmp.charAt(0), __indexOf.call(delimiters, _ref1) >= 0)) {
|
186 | throw new ParseException('Unexpected characters (' + scalar.slice(i) + ').');
|
187 | }
|
188 | }
|
189 | } else {
|
190 | if (!delimiters) {
|
191 | output = scalar.slice(i);
|
192 | i += output.length;
|
193 | strpos = output.indexOf(' #');
|
194 | if (strpos !== -1) {
|
195 | output = Utils.rtrim(output.slice(0, strpos));
|
196 | }
|
197 | } else {
|
198 | joinedDelimiters = delimiters.join('|');
|
199 | pattern = this.PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters];
|
200 | if (pattern == null) {
|
201 | pattern = new Pattern('^(.+?)(' + joinedDelimiters + ')');
|
202 | this.PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters] = pattern;
|
203 | }
|
204 | if (match = pattern.exec(scalar.slice(i))) {
|
205 | output = match[1];
|
206 | i += output.length;
|
207 | } else {
|
208 | throw new ParseException('Malformed inline YAML string (' + scalar + ').');
|
209 | }
|
210 | }
|
211 | if (evaluate) {
|
212 | output = this.evaluateScalar(output, context);
|
213 | }
|
214 | }
|
215 | context.i = i;
|
216 | return output;
|
217 | };
|
218 |
|
219 | Inline.parseQuotedScalar = function(scalar, context) {
|
220 | var i, match, output;
|
221 | i = context.i;
|
222 | if (!(match = this.PATTERN_QUOTED_SCALAR.exec(scalar.slice(i)))) {
|
223 | throw new ParseException('Malformed inline YAML string (' + scalar.slice(i) + ').');
|
224 | }
|
225 | output = match[0].substr(1, match[0].length - 2);
|
226 | if ('"' === scalar.charAt(i)) {
|
227 | output = Unescaper.unescapeDoubleQuotedString(output);
|
228 | } else {
|
229 | output = Unescaper.unescapeSingleQuotedString(output);
|
230 | }
|
231 | i += match[0].length;
|
232 | context.i = i;
|
233 | return output;
|
234 | };
|
235 |
|
236 | Inline.parseSequence = function(sequence, context) {
|
237 | var e, i, isQuoted, len, output, value, _ref;
|
238 | output = [];
|
239 | len = sequence.length;
|
240 | i = context.i;
|
241 | i += 1;
|
242 | while (i < len) {
|
243 | context.i = i;
|
244 | switch (sequence.charAt(i)) {
|
245 | case '[':
|
246 | output.push(this.parseSequence(sequence, context));
|
247 | i = context.i;
|
248 | break;
|
249 | case '{':
|
250 | output.push(this.parseMapping(sequence, context));
|
251 | i = context.i;
|
252 | break;
|
253 | case ']':
|
254 | return output;
|
255 | case ',':
|
256 | case ' ':
|
257 | case "\n":
|
258 | break;
|
259 | default:
|
260 | isQuoted = ((_ref = sequence.charAt(i)) === '"' || _ref === "'");
|
261 | value = this.parseScalar(sequence, [',', ']'], ['"', "'"], context);
|
262 | i = context.i;
|
263 | if (!isQuoted && typeof value === 'string' && (value.indexOf(': ') !== -1 || value.indexOf(":\n") !== -1)) {
|
264 | try {
|
265 | value = this.parseMapping('{' + value + '}');
|
266 | } catch (_error) {
|
267 | e = _error;
|
268 | }
|
269 | }
|
270 | output.push(value);
|
271 | --i;
|
272 | }
|
273 | ++i;
|
274 | }
|
275 | throw new ParseException('Malformed inline YAML string ' + sequence);
|
276 | };
|
277 |
|
278 | Inline.parseMapping = function(mapping, context) {
|
279 | var done, i, key, len, output, shouldContinueWhileLoop, value;
|
280 | output = {};
|
281 | len = mapping.length;
|
282 | i = context.i;
|
283 | i += 1;
|
284 | shouldContinueWhileLoop = false;
|
285 | while (i < len) {
|
286 | context.i = i;
|
287 | switch (mapping.charAt(i)) {
|
288 | case ' ':
|
289 | case ',':
|
290 | case "\n":
|
291 | ++i;
|
292 | context.i = i;
|
293 | shouldContinueWhileLoop = true;
|
294 | break;
|
295 | case '}':
|
296 | return output;
|
297 | }
|
298 | if (shouldContinueWhileLoop) {
|
299 | shouldContinueWhileLoop = false;
|
300 | continue;
|
301 | }
|
302 | key = this.parseScalar(mapping, [':', ' ', "\n"], ['"', "'"], context, false);
|
303 | i = context.i;
|
304 | done = false;
|
305 | while (i < len) {
|
306 | context.i = i;
|
307 | switch (mapping.charAt(i)) {
|
308 | case '[':
|
309 | value = this.parseSequence(mapping, context);
|
310 | i = context.i;
|
311 | if (output[key] === void 0) {
|
312 | output[key] = value;
|
313 | }
|
314 | done = true;
|
315 | break;
|
316 | case '{':
|
317 | value = this.parseMapping(mapping, context);
|
318 | i = context.i;
|
319 | if (output[key] === void 0) {
|
320 | output[key] = value;
|
321 | }
|
322 | done = true;
|
323 | break;
|
324 | case ':':
|
325 | case ' ':
|
326 | case "\n":
|
327 | break;
|
328 | default:
|
329 | value = this.parseScalar(mapping, [',', '}'], ['"', "'"], context);
|
330 | i = context.i;
|
331 | if (output[key] === void 0) {
|
332 | output[key] = value;
|
333 | }
|
334 | done = true;
|
335 | --i;
|
336 | }
|
337 | ++i;
|
338 | if (done) {
|
339 | break;
|
340 | }
|
341 | }
|
342 | }
|
343 | throw new ParseException('Malformed inline YAML string ' + mapping);
|
344 | };
|
345 |
|
346 | Inline.evaluateScalar = function(scalar, context) {
|
347 | var cast, date, exceptionOnInvalidType, firstChar, firstSpace, firstWord, objectDecoder, raw, scalarLower, subValue, trimmedScalar;
|
348 | scalar = Utils.trim(scalar);
|
349 | scalarLower = scalar.toLowerCase();
|
350 | switch (scalarLower) {
|
351 | case 'null':
|
352 | case '':
|
353 | case '~':
|
354 | return null;
|
355 | case 'true':
|
356 | return true;
|
357 | case 'false':
|
358 | return false;
|
359 | case '.inf':
|
360 | return Infinity;
|
361 | case '.nan':
|
362 | return NaN;
|
363 | case '-.inf':
|
364 | return Infinity;
|
365 | default:
|
366 | firstChar = scalarLower.charAt(0);
|
367 | switch (firstChar) {
|
368 | case '!':
|
369 | firstSpace = scalar.indexOf(' ');
|
370 | if (firstSpace === -1) {
|
371 | firstWord = scalarLower;
|
372 | } else {
|
373 | firstWord = scalarLower.slice(0, firstSpace);
|
374 | }
|
375 | switch (firstWord) {
|
376 | case '!':
|
377 | if (firstSpace !== -1) {
|
378 | return parseInt(this.parseScalar(scalar.slice(2)));
|
379 | }
|
380 | return null;
|
381 | case '!str':
|
382 | return Utils.ltrim(scalar.slice(4));
|
383 | case '!!str':
|
384 | return Utils.ltrim(scalar.slice(5));
|
385 | case '!!int':
|
386 | return parseInt(this.parseScalar(scalar.slice(5)));
|
387 | case '!!bool':
|
388 | return Utils.parseBoolean(this.parseScalar(scalar.slice(6)), false);
|
389 | case '!!float':
|
390 | return parseFloat(this.parseScalar(scalar.slice(7)));
|
391 | case '!!timestamp':
|
392 | return Utils.stringToDate(Utils.ltrim(scalar.slice(11)));
|
393 | default:
|
394 | if (context == null) {
|
395 | context = {
|
396 | exceptionOnInvalidType: this.settings.exceptionOnInvalidType,
|
397 | objectDecoder: this.settings.objectDecoder,
|
398 | i: 0
|
399 | };
|
400 | }
|
401 | objectDecoder = context.objectDecoder, exceptionOnInvalidType = context.exceptionOnInvalidType;
|
402 | if (objectDecoder) {
|
403 | trimmedScalar = Utils.rtrim(scalar);
|
404 | firstSpace = trimmedScalar.indexOf(' ');
|
405 | if (firstSpace === -1) {
|
406 | return objectDecoder(trimmedScalar, null);
|
407 | } else {
|
408 | subValue = Utils.ltrim(trimmedScalar.slice(firstSpace + 1));
|
409 | if (!(subValue.length > 0)) {
|
410 | subValue = null;
|
411 | }
|
412 | return objectDecoder(trimmedScalar.slice(0, firstSpace), subValue);
|
413 | }
|
414 | }
|
415 | if (exceptionOnInvalidType) {
|
416 | throw new ParseException('Custom object support when parsing a YAML file has been disabled.');
|
417 | }
|
418 | return null;
|
419 | }
|
420 | break;
|
421 | case '0':
|
422 | if ('0x' === scalar.slice(0, 2)) {
|
423 | return Utils.hexDec(scalar);
|
424 | } else if (Utils.isDigits(scalar)) {
|
425 | return Utils.octDec(scalar);
|
426 | } else if (Utils.isNumeric(scalar)) {
|
427 | return parseFloat(scalar);
|
428 | } else {
|
429 | return scalar;
|
430 | }
|
431 | break;
|
432 | case '+':
|
433 | if (Utils.isDigits(scalar)) {
|
434 | raw = scalar;
|
435 | cast = parseInt(raw);
|
436 | if (raw === String(cast)) {
|
437 | return cast;
|
438 | } else {
|
439 | return raw;
|
440 | }
|
441 | } else if (Utils.isNumeric(scalar)) {
|
442 | return parseFloat(scalar);
|
443 | } else if (this.PATTERN_THOUSAND_NUMERIC_SCALAR.test(scalar)) {
|
444 | return parseFloat(scalar.replace(',', ''));
|
445 | }
|
446 | return scalar;
|
447 | case '-':
|
448 | if (Utils.isDigits(scalar.slice(1))) {
|
449 | if ('0' === scalar.charAt(1)) {
|
450 | return -Utils.octDec(scalar.slice(1));
|
451 | } else {
|
452 | raw = scalar.slice(1);
|
453 | cast = parseInt(raw);
|
454 | if (raw === String(cast)) {
|
455 | return -cast;
|
456 | } else {
|
457 | return -raw;
|
458 | }
|
459 | }
|
460 | } else if (Utils.isNumeric(scalar)) {
|
461 | return parseFloat(scalar);
|
462 | } else if (this.PATTERN_THOUSAND_NUMERIC_SCALAR.test(scalar)) {
|
463 | return parseFloat(scalar.replace(',', ''));
|
464 | }
|
465 | return scalar;
|
466 | default:
|
467 | if (date = Utils.stringToDate(scalar)) {
|
468 | return date;
|
469 | } else if (Utils.isNumeric(scalar)) {
|
470 | return parseFloat(scalar);
|
471 | } else if (this.PATTERN_THOUSAND_NUMERIC_SCALAR.test(scalar)) {
|
472 | return parseFloat(scalar.replace(',', ''));
|
473 | }
|
474 | return scalar;
|
475 | }
|
476 | }
|
477 | };
|
478 |
|
479 | return Inline;
|
480 |
|
481 | })();
|
482 |
|
483 | module.exports = Inline;
|