UNPKG

21.2 kBJavaScriptView Raw
1// Generated by CoffeeScript 1.8.0
2var Inline, ParseException, Parser, Pattern, Utils;
3
4Inline = require('./Inline');
5
6Pattern = require('./Pattern');
7
8Utils = require('./Utils');
9
10ParseException = require('./Exception/ParseException');
11
12Parser = (function() {
13 Parser.prototype.PATTERN_FOLDED_SCALAR_ALL = new Pattern('^(?:(?<type>![^\\|>]*)\\s+)?(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$');
14
15 Parser.prototype.PATTERN_FOLDED_SCALAR_END = new Pattern('(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$');
16
17 Parser.prototype.PATTERN_SEQUENCE_ITEM = new Pattern('^\\-((?<leadspaces>\\s+)(?<value>.+?))?\\s*$');
18
19 Parser.prototype.PATTERN_ANCHOR_VALUE = new Pattern('^&(?<ref>[^ ]+) *(?<value>.*)');
20
21 Parser.prototype.PATTERN_COMPACT_NOTATION = new Pattern('^(?<key>' + Inline.REGEX_QUOTED_STRING + '|[^ \'"\\{\\[].*?) *\\:(\\s+(?<value>.+?))?\\s*$');
22
23 Parser.prototype.PATTERN_MAPPING_ITEM = new Pattern('^(?<key>' + Inline.REGEX_QUOTED_STRING + '|[^ \'"\\[\\{].*?) *\\:(\\s+(?<value>.+?))?\\s*$');
24
25 Parser.prototype.PATTERN_DECIMAL = new Pattern('\\d+');
26
27 Parser.prototype.PATTERN_INDENT_SPACES = new Pattern('^ +');
28
29 Parser.prototype.PATTERN_TRAILING_LINES = new Pattern('(\n*)$');
30
31 Parser.prototype.PATTERN_YAML_HEADER = new Pattern('^\\%YAML[: ][\\d\\.]+.*\n');
32
33 Parser.prototype.PATTERN_LEADING_COMMENTS = new Pattern('^(\\#.*?\n)+');
34
35 Parser.prototype.PATTERN_DOCUMENT_MARKER_START = new Pattern('^\\-\\-\\-.*?\n');
36
37 Parser.prototype.PATTERN_DOCUMENT_MARKER_END = new Pattern('^\\.\\.\\.\\s*$');
38
39 Parser.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION = {};
40
41 Parser.prototype.CONTEXT_NONE = 0;
42
43 Parser.prototype.CONTEXT_SEQUENCE = 1;
44
45 Parser.prototype.CONTEXT_MAPPING = 2;
46
47 function Parser(offset) {
48 this.offset = offset != null ? offset : 0;
49 this.lines = [];
50 this.currentLineNb = -1;
51 this.currentLine = '';
52 this.refs = {};
53 }
54
55 Parser.prototype.parse = function(value, exceptionOnInvalidType, objectDecoder) {
56 var alias, allowOverwrite, block, c, context, data, e, first, i, indent, isRef, k, key, lastKey, lineCount, matches, mergeNode, parsed, parsedItem, parser, refName, refValue, val, values, _i, _j, _k, _l, _len, _len1, _len2, _len3, _name, _ref, _ref1, _ref2;
57 if (exceptionOnInvalidType == null) {
58 exceptionOnInvalidType = false;
59 }
60 if (objectDecoder == null) {
61 objectDecoder = null;
62 }
63 this.currentLineNb = -1;
64 this.currentLine = '';
65 this.lines = this.cleanup(value).split("\n");
66 data = null;
67 context = this.CONTEXT_NONE;
68 allowOverwrite = false;
69 while (this.moveToNextLine()) {
70 if (this.isCurrentLineEmpty()) {
71 continue;
72 }
73 if ("\t" === this.currentLine[0]) {
74 throw new ParseException('A YAML file cannot contain tabs as indentation.', this.getRealCurrentLineNb() + 1, this.currentLine);
75 }
76 isRef = mergeNode = false;
77 if (values = this.PATTERN_SEQUENCE_ITEM.exec(this.currentLine)) {
78 if (this.CONTEXT_MAPPING === context) {
79 throw new ParseException('You cannot define a sequence item when in a mapping');
80 }
81 context = this.CONTEXT_SEQUENCE;
82 if (data == null) {
83 data = [];
84 }
85 if ((values.value != null) && (matches = this.PATTERN_ANCHOR_VALUE.exec(values.value))) {
86 isRef = matches.ref;
87 values.value = matches.value;
88 }
89 if (!(values.value != null) || '' === Utils.trim(values.value, ' ') || Utils.ltrim(values.value, ' ').indexOf('#') === 0) {
90 if (this.currentLineNb < this.lines.length - 1 && !this.isNextLineUnIndentedCollection()) {
91 c = this.getRealCurrentLineNb() + 1;
92 parser = new Parser(c);
93 parser.refs = this.refs;
94 data.push(parser.parse(this.getNextEmbedBlock(null, true), exceptionOnInvalidType, objectDecoder));
95 } else {
96 data.push(null);
97 }
98 } else {
99 if (((_ref = values.leadspaces) != null ? _ref.length : void 0) && (matches = this.PATTERN_COMPACT_NOTATION.exec(values.value))) {
100 c = this.getRealCurrentLineNb();
101 parser = new Parser(c);
102 parser.refs = this.refs;
103 block = values.value;
104 indent = this.getCurrentLineIndentation();
105 if (this.isNextLineIndented(false)) {
106 block += "\n" + this.getNextEmbedBlock(indent + values.leadspaces.length + 1, true);
107 }
108 data.push(parser.parse(block, exceptionOnInvalidType, objectDecoder));
109 } else {
110 data.push(this.parseValue(values.value, exceptionOnInvalidType, objectDecoder));
111 }
112 }
113 } else if ((values = this.PATTERN_MAPPING_ITEM.exec(this.currentLine)) && values.key.indexOf(' #') === -1) {
114 if (this.CONTEXT_SEQUENCE === context) {
115 throw new ParseException('You cannot define a mapping item when in a sequence');
116 }
117 context = this.CONTEXT_MAPPING;
118 if (data == null) {
119 data = {};
120 }
121 Inline.configure(exceptionOnInvalidType, objectDecoder);
122 try {
123 key = Inline.parseScalar(values.key);
124 } catch (_error) {
125 e = _error;
126 e.parsedLine = this.getRealCurrentLineNb() + 1;
127 e.snippet = this.currentLine;
128 throw e;
129 }
130 if ('<<' === key) {
131 mergeNode = true;
132 allowOverwrite = true;
133 if (((_ref1 = values.value) != null ? _ref1.indexOf('*') : void 0) === 0) {
134 refName = values.value.slice(1);
135 if (this.refs[refName] == null) {
136 throw new ParseException('Reference "' + refName + '" does not exist.', this.getRealCurrentLineNb() + 1, this.currentLine);
137 }
138 refValue = this.refs[refName];
139 if (typeof refValue !== 'object') {
140 throw new ParseException('YAML merge keys used with a scalar value instead of an object.', this.getRealCurrentLineNb() + 1, this.currentLine);
141 }
142 if (refValue instanceof Array) {
143 for (i = _i = 0, _len = refValue.length; _i < _len; i = ++_i) {
144 value = refValue[i];
145 if (data[_name = String(i)] == null) {
146 data[_name] = value;
147 }
148 }
149 } else {
150 for (key in refValue) {
151 value = refValue[key];
152 if (data[key] == null) {
153 data[key] = value;
154 }
155 }
156 }
157 } else {
158 if ((values.value != null) && values.value !== '') {
159 value = values.value;
160 } else {
161 value = this.getNextEmbedBlock();
162 }
163 c = this.getRealCurrentLineNb() + 1;
164 parser = new Parser(c);
165 parser.refs = this.refs;
166 parsed = parser.parse(value, exceptionOnInvalidType);
167 if (typeof parsed !== 'object') {
168 throw new ParseException('YAML merge keys used with a scalar value instead of an object.', this.getRealCurrentLineNb() + 1, this.currentLine);
169 }
170 if (parsed instanceof Array) {
171 for (_j = 0, _len1 = parsed.length; _j < _len1; _j++) {
172 parsedItem = parsed[_j];
173 if (typeof parsedItem !== 'object') {
174 throw new ParseException('Merge items must be objects.', this.getRealCurrentLineNb() + 1, parsedItem);
175 }
176 if (parsedItem instanceof Array) {
177 for (i = _k = 0, _len2 = parsedItem.length; _k < _len2; i = ++_k) {
178 value = parsedItem[i];
179 k = String(i);
180 if (!data.hasOwnProperty(k)) {
181 data[k] = value;
182 }
183 }
184 } else {
185 for (key in parsedItem) {
186 value = parsedItem[key];
187 if (!data.hasOwnProperty(key)) {
188 data[key] = value;
189 }
190 }
191 }
192 }
193 } else {
194 for (key in parsed) {
195 value = parsed[key];
196 if (!data.hasOwnProperty(key)) {
197 data[key] = value;
198 }
199 }
200 }
201 }
202 } else if ((values.value != null) && (matches = this.PATTERN_ANCHOR_VALUE.exec(values.value))) {
203 isRef = matches.ref;
204 values.value = matches.value;
205 }
206 if (mergeNode) {
207
208 } else if (!(values.value != null) || '' === Utils.trim(values.value, ' ') || Utils.ltrim(values.value, ' ').indexOf('#') === 0) {
209 if (!(this.isNextLineIndented()) && !(this.isNextLineUnIndentedCollection())) {
210 if (allowOverwrite || data[key] === void 0) {
211 data[key] = null;
212 }
213 } else {
214 c = this.getRealCurrentLineNb() + 1;
215 parser = new Parser(c);
216 parser.refs = this.refs;
217 val = parser.parse(this.getNextEmbedBlock(), exceptionOnInvalidType, objectDecoder);
218 if (allowOverwrite || data[key] === void 0) {
219 data[key] = val;
220 }
221 }
222 } else {
223 val = this.parseValue(values.value, exceptionOnInvalidType, objectDecoder);
224 if (allowOverwrite || data[key] === void 0) {
225 data[key] = val;
226 }
227 }
228 } else {
229 lineCount = this.lines.length;
230 if (1 === lineCount || (2 === lineCount && Utils.isEmpty(this.lines[1]))) {
231 try {
232 value = Inline.parse(this.lines[0], exceptionOnInvalidType, objectDecoder);
233 } catch (_error) {
234 e = _error;
235 e.parsedLine = this.getRealCurrentLineNb() + 1;
236 e.snippet = this.currentLine;
237 throw e;
238 }
239 if (typeof value === 'object') {
240 if (value instanceof Array) {
241 first = value[0];
242 } else {
243 for (key in value) {
244 first = value[key];
245 break;
246 }
247 }
248 if (typeof first === 'string' && first.indexOf('*') === 0) {
249 data = [];
250 for (_l = 0, _len3 = value.length; _l < _len3; _l++) {
251 alias = value[_l];
252 data.push(this.refs[alias.slice(1)]);
253 }
254 value = data;
255 }
256 }
257 return value;
258 } else if ((_ref2 = Utils.ltrim(value).charAt(0)) === '[' || _ref2 === '{') {
259 try {
260 return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
261 } catch (_error) {
262 e = _error;
263 e.parsedLine = this.getRealCurrentLineNb() + 1;
264 e.snippet = this.currentLine;
265 throw e;
266 }
267 }
268 throw new ParseException('Unable to parse.', this.getRealCurrentLineNb() + 1, this.currentLine);
269 }
270 if (isRef) {
271 if (data instanceof Array) {
272 this.refs[isRef] = data[data.length - 1];
273 } else {
274 lastKey = null;
275 for (key in data) {
276 lastKey = key;
277 }
278 this.refs[isRef] = data[lastKey];
279 }
280 }
281 }
282 if (Utils.isEmpty(data)) {
283 return null;
284 } else {
285 return data;
286 }
287 };
288
289 Parser.prototype.getRealCurrentLineNb = function() {
290 return this.currentLineNb + this.offset;
291 };
292
293 Parser.prototype.getCurrentLineIndentation = function() {
294 return this.currentLine.length - Utils.ltrim(this.currentLine, ' ').length;
295 };
296
297 Parser.prototype.getNextEmbedBlock = function(indentation, includeUnindentedCollection) {
298 var data, indent, isItUnindentedCollection, newIndent, removeComments, removeCommentsPattern, unindentedEmbedBlock;
299 if (indentation == null) {
300 indentation = null;
301 }
302 if (includeUnindentedCollection == null) {
303 includeUnindentedCollection = false;
304 }
305 this.moveToNextLine();
306 if (indentation == null) {
307 newIndent = this.getCurrentLineIndentation();
308 unindentedEmbedBlock = this.isStringUnIndentedCollectionItem(this.currentLine);
309 if (!(this.isCurrentLineEmpty()) && 0 === newIndent && !unindentedEmbedBlock) {
310 throw new ParseException('Indentation problem.', this.getRealCurrentLineNb() + 1, this.currentLine);
311 }
312 } else {
313 newIndent = indentation;
314 }
315 data = [this.currentLine.slice(newIndent)];
316 if (!includeUnindentedCollection) {
317 isItUnindentedCollection = this.isStringUnIndentedCollectionItem(this.currentLine);
318 }
319 removeCommentsPattern = this.PATTERN_FOLDED_SCALAR_END;
320 removeComments = !removeCommentsPattern.test(this.currentLine);
321 while (this.moveToNextLine()) {
322 indent = this.getCurrentLineIndentation();
323 if (indent === newIndent) {
324 removeComments = !removeCommentsPattern.test(this.currentLine);
325 }
326 if (isItUnindentedCollection && !this.isStringUnIndentedCollectionItem(this.currentLine) && indent === newIndent) {
327 this.moveToPreviousLine();
328 break;
329 }
330 if (this.isCurrentLineBlank()) {
331 data.push(this.currentLine.slice(newIndent));
332 continue;
333 }
334 if (removeComments && this.isCurrentLineComment()) {
335 if (indent === newIndent) {
336 continue;
337 }
338 }
339 if (indent >= newIndent) {
340 data.push(this.currentLine.slice(newIndent));
341 } else if (0 === indent) {
342 this.moveToPreviousLine();
343 break;
344 } else {
345 throw new ParseException('Indentation problem.', this.getRealCurrentLineNb() + 1, this.currentLine);
346 }
347 }
348 return data.join("\n");
349 };
350
351 Parser.prototype.moveToNextLine = function() {
352 if (this.currentLineNb >= this.lines.length - 1) {
353 return false;
354 }
355 this.currentLine = this.lines[++this.currentLineNb];
356 return true;
357 };
358
359 Parser.prototype.moveToPreviousLine = function() {
360 this.currentLine = this.lines[--this.currentLineNb];
361 };
362
363 Parser.prototype.parseValue = function(value, exceptionOnInvalidType, objectDecoder) {
364 var e, foldedIndent, matches, modifiers, pos, val, _ref, _ref1;
365 if (0 === value.indexOf('*')) {
366 pos = value.indexOf('#');
367 if (pos !== -1) {
368 value = value.substr(1, pos - 2);
369 } else {
370 value = value.slice(1);
371 }
372 if (this.refs[value] === void 0) {
373 throw new ParseException('Reference "' + value + '" does not exist.', this.currentLine);
374 }
375 return this.refs[value];
376 }
377 if (matches = this.PATTERN_FOLDED_SCALAR_ALL.exec(value)) {
378 modifiers = (_ref = matches.modifiers) != null ? _ref : '';
379 foldedIndent = Math.abs(parseInt(modifiers));
380 if (isNaN(foldedIndent)) {
381 foldedIndent = 0;
382 }
383 val = this.parseFoldedScalar(matches.separator, this.PATTERN_DECIMAL.replace(modifiers, ''), foldedIndent);
384 if (matches.type != null) {
385 Inline.configure(exceptionOnInvalidType, objectDecoder);
386 return Inline.parseScalar(matches.type + ' ' + val);
387 } else {
388 return val;
389 }
390 }
391 try {
392 return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
393 } catch (_error) {
394 e = _error;
395 if (((_ref1 = value.charAt(0)) === '[' || _ref1 === '{') && e instanceof ParseException && this.isNextLineIndented()) {
396 value += "\n" + this.getNextEmbedBlock();
397 try {
398 return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
399 } catch (_error) {
400 e = _error;
401 e.parsedLine = this.getRealCurrentLineNb() + 1;
402 e.snippet = this.currentLine;
403 throw e;
404 }
405 } else {
406 e.parsedLine = this.getRealCurrentLineNb() + 1;
407 e.snippet = this.currentLine;
408 throw e;
409 }
410 }
411 };
412
413 Parser.prototype.parseFoldedScalar = function(separator, indicator, indentation) {
414 var isCurrentLineBlank, line, matches, newText, notEOF, pattern, text, _i, _len, _ref;
415 if (indicator == null) {
416 indicator = '';
417 }
418 if (indentation == null) {
419 indentation = 0;
420 }
421 notEOF = this.moveToNextLine();
422 if (!notEOF) {
423 return '';
424 }
425 isCurrentLineBlank = this.isCurrentLineBlank();
426 text = '';
427 while (notEOF && isCurrentLineBlank) {
428 if (notEOF = this.moveToNextLine()) {
429 text += "\n";
430 isCurrentLineBlank = this.isCurrentLineBlank();
431 }
432 }
433 if (0 === indentation) {
434 if (matches = this.PATTERN_INDENT_SPACES.exec(this.currentLine)) {
435 indentation = matches[0].length;
436 }
437 }
438 if (indentation > 0) {
439 pattern = this.PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation];
440 if (pattern == null) {
441 pattern = new Pattern('^ {' + indentation + '}(.*)$');
442 Parser.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation] = pattern;
443 }
444 while (notEOF && (isCurrentLineBlank || (matches = pattern.exec(this.currentLine)))) {
445 if (isCurrentLineBlank) {
446 text += this.currentLine.slice(indentation);
447 } else {
448 text += matches[1];
449 }
450 if (notEOF = this.moveToNextLine()) {
451 text += "\n";
452 isCurrentLineBlank = this.isCurrentLineBlank();
453 }
454 }
455 } else if (notEOF) {
456 text += "\n";
457 }
458 if (notEOF) {
459 this.moveToPreviousLine();
460 }
461 if ('>' === separator) {
462 newText = '';
463 _ref = text.split("\n");
464 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
465 line = _ref[_i];
466 if (line.length === 0 || line.charAt(0) === ' ') {
467 newText = Utils.rtrim(newText, ' ') + line + "\n";
468 } else {
469 newText += line + ' ';
470 }
471 }
472 text = newText;
473 }
474 if ('+' !== indicator) {
475 text = Utils.rtrim(text);
476 }
477 if ('' === indicator) {
478 text = this.PATTERN_TRAILING_LINES.replace(text, "\n");
479 } else if ('-' === indicator) {
480 text = this.PATTERN_TRAILING_LINES.replace(text, '');
481 }
482 return text;
483 };
484
485 Parser.prototype.isNextLineIndented = function(ignoreComments) {
486 var EOF, currentIndentation, ret;
487 if (ignoreComments == null) {
488 ignoreComments = true;
489 }
490 currentIndentation = this.getCurrentLineIndentation();
491 EOF = !this.moveToNextLine();
492 if (ignoreComments) {
493 while (!EOF && this.isCurrentLineEmpty()) {
494 EOF = !this.moveToNextLine();
495 }
496 } else {
497 while (!EOF && this.isCurrentLineBlank()) {
498 EOF = !this.moveToNextLine();
499 }
500 }
501 if (EOF) {
502 return false;
503 }
504 ret = false;
505 if (this.getCurrentLineIndentation() > currentIndentation) {
506 ret = true;
507 }
508 this.moveToPreviousLine();
509 return ret;
510 };
511
512 Parser.prototype.isCurrentLineEmpty = function() {
513 var trimmedLine;
514 trimmedLine = Utils.trim(this.currentLine, ' ');
515 return trimmedLine.length === 0 || trimmedLine.charAt(0) === '#';
516 };
517
518 Parser.prototype.isCurrentLineBlank = function() {
519 return '' === Utils.trim(this.currentLine, ' ');
520 };
521
522 Parser.prototype.isCurrentLineComment = function() {
523 var ltrimmedLine;
524 ltrimmedLine = Utils.ltrim(this.currentLine, ' ');
525 return ltrimmedLine.charAt(0) === '#';
526 };
527
528 Parser.prototype.cleanup = function(value) {
529 var count, trimmedValue, _ref, _ref1, _ref2;
530 if (value.indexOf("\r") !== -1) {
531 value = value.split("\r\n").join("\n").split("\r").join("\n");
532 }
533 count = 0;
534 _ref = this.PATTERN_YAML_HEADER.replaceAll(value, ''), value = _ref[0], count = _ref[1];
535 this.offset += count;
536 _ref1 = this.PATTERN_LEADING_COMMENTS.replaceAll(value, '', 1), trimmedValue = _ref1[0], count = _ref1[1];
537 if (count === 1) {
538 this.offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n");
539 value = trimmedValue;
540 }
541 _ref2 = this.PATTERN_DOCUMENT_MARKER_START.replaceAll(value, '', 1), trimmedValue = _ref2[0], count = _ref2[1];
542 if (count === 1) {
543 this.offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n");
544 value = trimmedValue;
545 value = this.PATTERN_DOCUMENT_MARKER_END.replace(value, '');
546 }
547 return value;
548 };
549
550 Parser.prototype.isNextLineUnIndentedCollection = function(currentIndentation) {
551 var notEOF, ret;
552 if (currentIndentation == null) {
553 currentIndentation = null;
554 }
555 if (currentIndentation == null) {
556 currentIndentation = this.getCurrentLineIndentation();
557 }
558 notEOF = this.moveToNextLine();
559 while (notEOF && this.isCurrentLineEmpty()) {
560 notEOF = this.moveToNextLine();
561 }
562 if (false === notEOF) {
563 return false;
564 }
565 ret = false;
566 if (this.getCurrentLineIndentation() === currentIndentation && this.isStringUnIndentedCollectionItem(this.currentLine)) {
567 ret = true;
568 }
569 this.moveToPreviousLine();
570 return ret;
571 };
572
573 Parser.prototype.isStringUnIndentedCollectionItem = function() {
574 return this.currentLine === '-' || this.currentLine.slice(0, 2) === '- ';
575 };
576
577 return Parser;
578
579})();
580
581module.exports = Parser;