Website/node_modules/yaml-js/lib/scanner.js

1514 lines
46 KiB
JavaScript

(function() {
var MarkedYAMLError, SimpleKey, tokens, util, _ref,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
__slice = [].slice,
__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; };
MarkedYAMLError = require('./errors').MarkedYAMLError;
tokens = require('./tokens');
util = require('./util');
/*
The Scanner throws these.
*/
this.ScannerError = (function(_super) {
__extends(ScannerError, _super);
function ScannerError() {
_ref = ScannerError.__super__.constructor.apply(this, arguments);
return _ref;
}
return ScannerError;
})(MarkedYAMLError);
/*
Represents a possible simple key.
*/
SimpleKey = (function() {
function SimpleKey(token_number, required, index, line, column, mark) {
this.token_number = token_number;
this.required = required;
this.index = index;
this.line = line;
this.column = column;
this.mark = mark;
}
return SimpleKey;
})();
/*
The Scanner class deals with converting a YAML stream into a token stream.
*/
this.Scanner = (function() {
var C_LB, C_NUMBERS, C_WS, ESCAPE_CODES, ESCAPE_REPLACEMENTS;
C_LB = '\r\n\x85\u2028\u2029';
C_WS = '\t ';
C_NUMBERS = '0123456789';
ESCAPE_REPLACEMENTS = {
'0': '\x00',
'a': '\x07',
'b': '\x08',
't': '\x09',
'\t': '\x09',
'n': '\x0A',
'v': '\x0B',
'f': '\x0C',
'r': '\x0D',
'e': '\x1B',
' ': '\x20',
'"': '"',
'\\': '\\',
'N': '\x85',
'_': '\xA0',
'L': '\u2028',
'P': '\u2029'
};
ESCAPE_CODES = {
'x': 2,
'u': 4,
'U': 8
};
/*
Initialise the Scanner
*/
function Scanner() {
this.done = false;
this.flow_level = 0;
this.tokens = [];
this.fetch_stream_start();
this.tokens_taken = 0;
this.indent = -1;
this.indents = [];
this.allow_simple_key = true;
this.possible_simple_keys = {};
}
/*
Check if the next token is one of the given types.
*/
Scanner.prototype.check_token = function() {
var choice, choices, _i, _len;
choices = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
while (this.need_more_tokens()) {
this.fetch_more_tokens();
}
if (this.tokens.length !== 0) {
if (choices.length === 0) {
return true;
}
for (_i = 0, _len = choices.length; _i < _len; _i++) {
choice = choices[_i];
if (this.tokens[0] instanceof choice) {
return true;
}
}
}
return false;
};
/*
Return the next token, but do not delete it from the queue.
*/
Scanner.prototype.peek_token = function() {
while (this.need_more_tokens()) {
this.fetch_more_tokens();
}
if (this.tokens.length !== 0) {
return this.tokens[0];
}
};
/*
Return the next token, and remove it from the queue.
*/
Scanner.prototype.get_token = function() {
while (this.need_more_tokens()) {
this.fetch_more_tokens();
}
if (this.tokens.length !== 0) {
this.tokens_taken++;
return this.tokens.shift();
}
};
Scanner.prototype.need_more_tokens = function() {
if (this.done) {
return false;
}
if (this.tokens.length === 0) {
return true;
}
this.stale_possible_simple_keys();
if (this.next_possible_simple_key() === this.tokens_taken) {
return true;
}
return false;
};
Scanner.prototype.fetch_more_tokens = function() {
var char;
this.scan_to_next_token();
this.stale_possible_simple_keys();
this.unwind_indent(this.column);
char = this.peek();
if (char === '\x00') {
return this.fetch_stream_end();
}
if (char === '%' && this.check_directive()) {
return this.fetch_directive();
}
if (char === '-' && this.check_document_start()) {
return this.fetch_document_start();
}
if (char === '.' && this.check_document_end()) {
return this.fetch_document_end();
}
if (char === '[') {
return this.fetch_flow_sequence_start();
}
if (char === '{') {
return this.fetch_flow_mapping_start();
}
if (char === ']') {
return this.fetch_flow_sequence_end();
}
if (char === '}') {
return this.fetch_flow_mapping_end();
}
if (char === ',') {
return this.fetch_flow_entry();
}
if (char === '-' && this.check_block_entry()) {
return this.fetch_block_entry();
}
if (char === '?' && this.check_key()) {
return this.fetch_key();
}
if (char === ':' && this.check_value()) {
return this.fetch_value();
}
if (char === '*') {
return this.fetch_alias();
}
if (char === '&') {
return this.fetch_anchor();
}
if (char === '!') {
return this.fetch_tag();
}
if (char === '|' && this.flow_level === 0) {
return this.fetch_literal();
}
if (char === '>' && this.flow_level === 0) {
return this.fetch_folded();
}
if (char === '\'') {
return this.fetch_single();
}
if (char === '"') {
return this.fetch_double();
}
if (this.check_plain()) {
return this.fetch_plain();
}
throw new exports.ScannerError('while scanning for the next token', null, "found character " + char + " that cannot start any token", this.get_mark());
};
/*
Return the number of the nearest possible simple key.
*/
Scanner.prototype.next_possible_simple_key = function() {
var key, level, min_token_number, _ref1;
min_token_number = null;
_ref1 = this.possible_simple_keys;
for (level in _ref1) {
if (!__hasProp.call(_ref1, level)) continue;
key = _ref1[level];
if (min_token_number === null || key.token_number < min_token_number) {
min_token_number = key.token_number;
}
}
return min_token_number;
};
/*
Remove entries that are no longer possible simple keys. According to the
YAML spec, simple keys:
should be limited to a single line
should be no longer than 1024 characters
Disabling this procedure will allow simple keys of any length and height
(may cause problems if indentation is broken though).
*/
Scanner.prototype.stale_possible_simple_keys = function() {
var key, level, _ref1, _results;
_ref1 = this.possible_simple_keys;
_results = [];
for (level in _ref1) {
if (!__hasProp.call(_ref1, level)) continue;
key = _ref1[level];
if (key.line === this.line && this.index - key.index <= 1024) {
continue;
}
if (!key.required) {
_results.push(delete this.possible_simple_keys[level]);
} else {
throw new exports.ScannerError('while scanning a simple key', key.mark, 'could not find expected \':\'', this.get_mark());
}
}
return _results;
};
/*
The next token may start a simple key. We check if it's possible and save
its position. This function is called for ALIAS, ANCHOR, TAG,
SCALAR (flow),'[' and '{'.
*/
Scanner.prototype.save_possible_simple_key = function() {
var required, token_number;
required = this.flow_level === 0 && this.indent === this.column;
if (required && !this.allow_simple_key) {
throw new Error('logic failure');
}
if (!this.allow_simple_key) {
return;
}
this.remove_possible_simple_key();
token_number = this.tokens_taken + this.tokens.length;
return this.possible_simple_keys[this.flow_level] = new SimpleKey(token_number, required, this.index, this.line, this.column, this.get_mark());
};
/*
Remove the saved possible simple key at the current flow level.
*/
Scanner.prototype.remove_possible_simple_key = function() {
var key;
if (!(key = this.possible_simple_keys[this.flow_level])) {
return;
}
if (!key.required) {
return delete this.possible_simple_keys[this.flow_level];
} else {
throw new exports.ScannerError('while scanning a simple key', key.mark, 'could not find expected \':\'', this.get_mark());
}
};
/*
In flow context, tokens should respect indentation.
Actually the condition should be `self.indent >= column` according to
the spec. But this condition will prohibit intuitively correct
constructions such as
key : {
}
*/
Scanner.prototype.unwind_indent = function(column) {
var mark, _results;
if (this.flow_level !== 0) {
return;
}
_results = [];
while (this.indent > column) {
mark = this.get_mark();
this.indent = this.indents.pop();
_results.push(this.tokens.push(new tokens.BlockEndToken(mark, mark)));
}
return _results;
};
/*
Check if we need to increase indentation.
*/
Scanner.prototype.add_indent = function(column) {
if (!(column > this.indent)) {
return false;
}
this.indents.push(this.indent);
this.indent = column;
return true;
};
Scanner.prototype.fetch_stream_start = function() {
var mark;
mark = this.get_mark();
return this.tokens.push(new tokens.StreamStartToken(mark, mark, this.encoding));
};
Scanner.prototype.fetch_stream_end = function() {
var mark;
this.unwind_indent(-1);
this.remove_possible_simple_key();
this.allow_possible_simple_key = false;
this.possible_simple_keys = {};
mark = this.get_mark();
this.tokens.push(new tokens.StreamEndToken(mark, mark));
return this.done = true;
};
Scanner.prototype.fetch_directive = function() {
this.unwind_indent(-1);
this.remove_possible_simple_key();
this.allow_simple_key = false;
return this.tokens.push(this.scan_directive());
};
Scanner.prototype.fetch_document_start = function() {
return this.fetch_document_indicator(tokens.DocumentStartToken);
};
Scanner.prototype.fetch_document_end = function() {
return this.fetch_document_indicator(tokens.DocumentEndToken);
};
Scanner.prototype.fetch_document_indicator = function(TokenClass) {
var start_mark;
this.unwind_indent(-1);
this.remove_possible_simple_key();
this.allow_simple_key = false;
start_mark = this.get_mark();
this.forward(3);
return this.tokens.push(new TokenClass(start_mark, this.get_mark()));
};
Scanner.prototype.fetch_flow_sequence_start = function() {
return this.fetch_flow_collection_start(tokens.FlowSequenceStartToken);
};
Scanner.prototype.fetch_flow_mapping_start = function() {
return this.fetch_flow_collection_start(tokens.FlowMappingStartToken);
};
Scanner.prototype.fetch_flow_collection_start = function(TokenClass) {
var start_mark;
this.save_possible_simple_key();
this.flow_level++;
this.allow_simple_key = true;
start_mark = this.get_mark();
this.forward();
return this.tokens.push(new TokenClass(start_mark, this.get_mark()));
};
Scanner.prototype.fetch_flow_sequence_end = function() {
return this.fetch_flow_collection_end(tokens.FlowSequenceEndToken);
};
Scanner.prototype.fetch_flow_mapping_end = function() {
return this.fetch_flow_collection_end(tokens.FlowMappingEndToken);
};
Scanner.prototype.fetch_flow_collection_end = function(TokenClass) {
var start_mark;
this.remove_possible_simple_key();
this.flow_level--;
this.allow_simple_key = false;
start_mark = this.get_mark();
this.forward();
return this.tokens.push(new TokenClass(start_mark, this.get_mark()));
};
Scanner.prototype.fetch_flow_entry = function() {
var start_mark;
this.allow_simple_key = true;
this.remove_possible_simple_key();
start_mark = this.get_mark();
this.forward();
return this.tokens.push(new tokens.FlowEntryToken(start_mark, this.get_mark()));
};
Scanner.prototype.fetch_block_entry = function() {
var mark, start_mark;
if (this.flow_level === 0) {
if (!this.allow_simple_key) {
throw new exports.ScannerError(null, null, 'sequence entries are not allowed here', this.get_mark());
}
if (this.add_indent(this.column)) {
mark = this.get_mark();
this.tokens.push(new tokens.BlockSequenceStartToken(mark, mark));
}
}
this.allow_simple_key = true;
this.remove_possible_simple_key();
start_mark = this.get_mark();
this.forward();
return this.tokens.push(new tokens.BlockEntryToken(start_mark, this.get_mark()));
};
Scanner.prototype.fetch_key = function() {
var mark, start_mark;
if (this.flow_level === 0) {
if (!this.allow_simple_key) {
throw new exports.ScannerError(null, null, 'mapping keys are not allowed here', this.get_mark());
}
if (this.add_indent(this.column)) {
mark = this.get_mark();
this.tokens.push(new tokens.BlockMappingStartToken(mark, mark));
}
}
this.allow_simple_key = !this.flow_level;
this.remove_possible_simple_key();
start_mark = this.get_mark();
this.forward();
return this.tokens.push(new tokens.KeyToken(start_mark, this.get_mark()));
};
Scanner.prototype.fetch_value = function() {
var key, mark, start_mark;
if (key = this.possible_simple_keys[this.flow_level]) {
delete this.possible_simple_keys[this.flow_level];
this.tokens.splice(key.token_number - this.tokens_taken, 0, new tokens.KeyToken(key.mark, key.mark));
if (this.flow_level === 0) {
if (this.add_indent(key.column)) {
this.tokens.splice(key.token_number - this.tokens_taken, 0, new tokens.BlockMappingStartToken(key.mark, key.mark));
}
}
this.allow_simple_key = false;
} else {
if (this.flow_level === 0) {
if (!this.allow_simple_key) {
throw new exports.ScannerError(null, null, 'mapping values are not allowed here', this.get_mark());
}
if (this.add_indent(this.column)) {
mark = this.get_mark();
this.tokens.push(new tokens.BlockMappingStartToken(mark, mark));
}
}
this.allow_simple_key = !this.flow_level;
this.remove_possible_simple_key();
}
start_mark = this.get_mark();
this.forward();
return this.tokens.push(new tokens.ValueToken(start_mark, this.get_mark()));
};
Scanner.prototype.fetch_alias = function() {
this.save_possible_simple_key();
this.allow_simple_key = false;
return this.tokens.push(this.scan_anchor(tokens.AliasToken));
};
Scanner.prototype.fetch_anchor = function() {
this.save_possible_simple_key();
this.allow_simple_key = false;
return this.tokens.push(this.scan_anchor(tokens.AnchorToken));
};
Scanner.prototype.fetch_tag = function() {
this.save_possible_simple_key();
this.allow_simple_key = false;
return this.tokens.push(this.scan_tag());
};
Scanner.prototype.fetch_literal = function() {
return this.fetch_block_scalar('|');
};
Scanner.prototype.fetch_folded = function() {
return this.fetch_block_scalar('>');
};
Scanner.prototype.fetch_block_scalar = function(style) {
this.allow_simple_key = true;
this.remove_possible_simple_key();
return this.tokens.push(this.scan_block_scalar(style));
};
Scanner.prototype.fetch_single = function() {
return this.fetch_flow_scalar('\'');
};
Scanner.prototype.fetch_double = function() {
return this.fetch_flow_scalar('"');
};
Scanner.prototype.fetch_flow_scalar = function(style) {
this.save_possible_simple_key();
this.allow_simple_key = false;
return this.tokens.push(this.scan_flow_scalar(style));
};
Scanner.prototype.fetch_plain = function() {
this.save_possible_simple_key();
this.allow_simple_key = false;
return this.tokens.push(this.scan_plain());
};
/*
DIRECTIVE: ^ '%'
*/
Scanner.prototype.check_directive = function() {
if (this.column === 0) {
return true;
}
return false;
};
/*
DOCUMENT-START: ^ '---' (' '|'\n')
*/
Scanner.prototype.check_document_start = function() {
var _ref1;
if (this.column === 0 && this.prefix(3) === '---' && (_ref1 = this.peek(3), __indexOf.call(C_LB + C_WS + '\x00', _ref1) >= 0)) {
return true;
}
return false;
};
/*
DOCUMENT-END: ^ '...' (' '|'\n')
*/
Scanner.prototype.check_document_end = function() {
var _ref1;
if (this.column === 0 && this.prefix(3) === '...' && (_ref1 = this.peek(3), __indexOf.call(C_LB + C_WS + '\x00', _ref1) >= 0)) {
return true;
}
return false;
};
/*
BLOCK-ENTRY: '-' (' '|'\n')
*/
Scanner.prototype.check_block_entry = function() {
var _ref1;
return _ref1 = this.peek(1), __indexOf.call(C_LB + C_WS + '\x00', _ref1) >= 0;
};
/*
KEY (flow context): '?'
KEY (block context): '?' (' '|'\n')
*/
Scanner.prototype.check_key = function() {
var _ref1;
if (this.flow_level !== 0) {
return true;
}
return _ref1 = this.peek(1), __indexOf.call(C_LB + C_WS + '\x00', _ref1) >= 0;
};
/*
VALUE (flow context): ':'
VALUE (block context): ':' (' '|'\n')
*/
Scanner.prototype.check_value = function() {
var _ref1;
if (this.flow_level !== 0) {
return true;
}
return _ref1 = this.peek(1), __indexOf.call(C_LB + C_WS + '\x00', _ref1) >= 0;
};
/*
A plain scalar may start with any non-space character except:
'-', '?', ':', ',', '[', ']', '{', '}',
'#', '&', '*', '!', '|', '>', '\'', '"',
'%', '@', '`'.
It may also start with
'-', '?', ':'
if it is followed by a non-space character.
Note that we limit the last rule to the block context (except the '-'
character) because we want the flow context to be space independent.
*/
Scanner.prototype.check_plain = function() {
var char, _ref1;
char = this.peek();
return __indexOf.call(C_LB + C_WS + '\x00-?:,[]{}#&*!|>\'"%@`', char) < 0 || ((_ref1 = this.peek(1), __indexOf.call(C_LB + C_WS + '\x00', _ref1) < 0) && (char === '-' || (this.flow_level === 0 && __indexOf.call('?:', char) >= 0)));
};
/*
We ignore spaces, line breaks and comments.
If we find a line break in the block context, we set the flag
`allow_simple_key` on.
The byte order mark is stripped if it's the first character in the stream.
We do not yet support BOM inside the stream as the specification requires.
Any such mark will be considered as a part of the document.
TODO: We need to make tab handling rules more sane. A good rule is
Tabs cannot precede tokens BLOCK-SEQUENCE-START, BLOCK-MAPPING-START,
BLOCK-END, KEY (block context), VALUE (block context), BLOCK-ENTRY
So the tab checking code is
@allow_simple_key = off if <TAB>
We also need to add the check for `allow_simple_key is on` to
`unwind_indent` before issuing BLOCK-END. Scanners for block, flow and
plain scalars need to be modified.
*/
Scanner.prototype.scan_to_next_token = function() {
var found, _ref1, _results;
if (this.index === 0 && this.peek() === '\uFEFF') {
this.forward();
}
found = false;
_results = [];
while (!found) {
while (this.peek() === ' ') {
this.forward();
}
if (this.peek() === '#') {
while (_ref1 = this.peek(), __indexOf.call(C_LB + '\x00', _ref1) < 0) {
this.forward();
}
}
if (this.scan_line_break()) {
if (this.flow_level === 0) {
_results.push(this.allow_simple_key = true);
} else {
_results.push(void 0);
}
} else {
_results.push(found = true);
}
}
return _results;
};
/*
See the specification for details.
*/
Scanner.prototype.scan_directive = function() {
var end_mark, name, start_mark, value, _ref1;
start_mark = this.get_mark();
this.forward();
name = this.scan_directive_name(start_mark);
value = null;
if (name === 'YAML') {
value = this.scan_yaml_directive_value(start_mark);
end_mark = this.get_mark();
} else if (name === 'TAG') {
value = this.scan_tag_directive_value(start_mark);
end_mark = this.get_mark();
} else {
end_mark = this.get_mark();
while (_ref1 = this.peek(), __indexOf.call(C_LB + '\x00', _ref1) < 0) {
this.forward();
}
}
this.scan_directive_ignored_line(start_mark);
return new tokens.DirectiveToken(name, value, start_mark, end_mark);
};
/*
See the specification for details.
*/
Scanner.prototype.scan_directive_name = function(start_mark) {
var char, length, value;
length = 0;
char = this.peek(length);
while (('0' <= char && char <= '9') || ('A' <= char && char <= 'Z') || ('a' <= char && char <= 'z') || __indexOf.call('-_', char) >= 0) {
length++;
char = peek(length);
}
throw new exports.ScannerError('while scanning a directive', start_mark, "expected alphanumeric or numeric character but found " + char, length === 0 ? this.get_mark() : void 0);
value = this.prefix(length);
this.forward(length);
char = this.peek();
throw new exports.ScannerError('while scanning a directive', start_mark, "expected alphanumeric or numeric character but found " + char, __indexOf.call(C_LB + '\x00 ', char) < 0 ? this.get_mark() : void 0);
return value;
};
/*
See the specification for details.
*/
Scanner.prototype.scan_yaml_directive_value = function(start_mark) {
var major, minor, _ref1;
while (this.peek() === ' ') {
this.forward();
}
major = this.scan_yaml_directive_number(start_mark);
throw new exports.ScannerError('while scanning a directive', start_mark, "expected a digit or '.' but found " + (this.peek()), this.peek() !== '.' ? this.get_mark() : void 0);
this.forward();
minor = this.scan_yaml_directive_number(start_mark);
throw new exports.ScannerError('while scanning a directive', start_mark, "expected a digit or ' ' but found " + (this.peek()), (_ref1 = this.peek(), __indexOf.call(C_LB + '\x00 ', _ref1) < 0) ? this.get_mark() : void 0);
return [major, minor];
};
/*
See the specification for details.
*/
Scanner.prototype.scan_yaml_directive_number = function(start_mark) {
var char, length, value, _ref1;
char = this.peek();
throw new exports.ScannerError('while scanning a directive', start_mark, "expected a digit but found " + char, !(('0' <= char && char <= '9')) ? this.get_mark() : void 0);
length = 0;
while (('0' <= (_ref1 = this.peek(length)) && _ref1 <= '9')) {
length++;
}
value = parseInt(this.prefix(length));
this.forward(length);
return value;
};
/*
See the specification for details.
*/
Scanner.prototype.scan_tag_directive_value = function(start_mark) {
var handle, prefix;
while (this.peek() === ' ') {
this.forward();
}
handle = this.scan_tag_directive_handle(start_mark);
while (this.peek() === ' ') {
this.forward();
}
prefix = this.scan_tag_directive_prefix(start_mark);
return [handle, prefix];
};
/*
See the specification for details.
*/
Scanner.prototype.scan_tag_directive_handle = function(start_mark) {
var char, value;
value = this.scan_tag_handle('directive', start_mark);
char = this.peek();
throw new exports.ScannerError('while scanning a directive', start_mark, "expected ' ' but found " + char, char !== ' ' ? this.get_mark() : void 0);
return value;
};
/*
See the specification for details.
*/
Scanner.prototype.scan_tag_directive_prefix = function(start_mark) {
var char, value;
value = this.scan_tag_uri('directive', start_mark);
char = this.peek();
throw new exports.ScannerError('while scanning a directive', start_mark, "expected ' ' but found " + char, __indexOf.call(C_LB + '\x00 ', char) < 0 ? this.get_mark() : void 0);
return value;
};
/*
See the specification for details.
*/
Scanner.prototype.scan_directive_ignored_line = function(start_mark) {
var char, _ref1;
while (this.peek() === ' ') {
this.forward();
}
if (this.peek() === '#') {
while (_ref1 = this.peek(), __indexOf.call(C_LB + '\x00', _ref1) < 0) {
this.forward();
}
}
char = this.peek();
throw new exports.ScannerError('while scanning a directive', start_mark, "expected a comment or a line break but found " + char, __indexOf.call(C_LB + '\x00', char) < 0 ? this.get_mark() : void 0);
return this.scan_line_break();
};
/*
The specification does not restrict characters for anchors and aliases.
This may lead to problems, for instance, the document:
[ *alias, value ]
can be interpteted in two ways, as
[ "value" ]
and
[ *alias , "value" ]
Therefore we restrict aliases to numbers and ASCII letters.
*/
Scanner.prototype.scan_anchor = function(TokenClass) {
var char, indicator, length, name, start_mark, value;
start_mark = this.get_mark();
indicator = this.peek();
if (indicator === '*') {
name = 'alias';
} else {
name = 'anchor';
}
this.forward();
length = 0;
char = this.peek(length);
while (('0' <= char && char <= '9') || ('A' <= char && char <= 'Z') || ('a' <= char && char <= 'z') || __indexOf.call('-_', char) >= 0) {
length++;
char = this.peek(length);
}
if (length === 0) {
throw new exports.ScannerError("while scanning an " + name, start_mark, "expected alphabetic or numeric character but found '" + char + "'", this.get_mark());
}
value = this.prefix(length);
this.forward(length);
char = this.peek();
if (__indexOf.call(C_LB + C_WS + '\x00' + '?:,]}%@`', char) < 0) {
throw new exports.ScannerError("while scanning an " + name, start_mark, "expected alphabetic or numeric character but found '" + char + "'", this.get_mark());
}
return new TokenClass(value, start_mark, this.get_mark());
};
/*
See the specification for details.
*/
Scanner.prototype.scan_tag = function() {
var char, handle, length, start_mark, suffix, use_handle;
start_mark = this.get_mark();
char = this.peek(1);
if (char === '<') {
handle = null;
this.forward(2);
suffix = this.scan_tag_uri('tag', start_mark);
if (this.peek() !== '>') {
throw new exports.ScannerError('while parsing a tag', start_mark, "expected '>' but found " + (this.peek()), this.get_mark());
}
this.forward();
} else if (__indexOf.call(C_LB + C_WS + '\x00', char) >= 0) {
handle = null;
suffix = '!';
this.forward();
} else {
length = 1;
use_handle = false;
while (__indexOf.call(C_LB + '\x00 ', char) < 0) {
if (char === '!') {
use_handle = true;
break;
}
length++;
char = this.peek(length);
}
if (use_handle) {
handle = this.scan_tag_handle('tag', start_mark);
} else {
handle = '!';
this.forward();
}
suffix = this.scan_tag_uri('tag', start_mark);
}
char = this.peek();
if (__indexOf.call(C_LB + '\x00 ', char) < 0) {
throw new exports.ScannerError('while scanning a tag', start_mark, "expected ' ' but found " + char, this.get_mark());
}
return new tokens.TagToken([handle, suffix], start_mark, this.get_mark());
};
/*
See the specification for details.
*/
Scanner.prototype.scan_block_scalar = function(style) {
var breaks, chomping, chunks, end_mark, folded, increment, indent, leading_non_space, length, line_break, max_indent, min_indent, start_mark, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7;
folded = style === '>';
chunks = [];
start_mark = this.get_mark();
this.forward();
_ref1 = this.scan_block_scalar_indicators(start_mark), chomping = _ref1[0], increment = _ref1[1];
this.scan_block_scalar_ignored_line(start_mark);
min_indent = this.indent + 1;
if (min_indent < 1) {
min_indent = 1;
}
if (increment == null) {
_ref2 = this.scan_block_scalar_indentation(), breaks = _ref2[0], max_indent = _ref2[1], end_mark = _ref2[2];
indent = Math.max(min_indent, max_indent);
} else {
indent = min_indent + increment - 1;
_ref3 = this.scan_block_scalar_breaks(indent), breaks = _ref3[0], end_mark = _ref3[1];
}
line_break = '';
while (this.column === indent && this.peek() !== '\x00') {
chunks = chunks.concat(breaks);
leading_non_space = (_ref4 = this.peek(), __indexOf.call(' \t', _ref4) < 0);
length = 0;
while (_ref5 = this.peek(length), __indexOf.call(C_LB + '\x00', _ref5) < 0) {
length++;
}
chunks.push(this.prefix(length));
this.forward(length);
line_break = this.scan_line_break();
_ref6 = this.scan_block_scalar_breaks(indent), breaks = _ref6[0], end_mark = _ref6[1];
if (this.column === indent && this.peek() !== '\x00') {
if (folded && line_break === '\n' && leading_non_space && (_ref7 = this.peek(), __indexOf.call(' \t', _ref7) < 0)) {
if (util.is_empty(breaks)) {
chunks.push(' ');
}
} else {
chunks.push(line_break);
}
} else {
break;
}
}
if (chomping !== false) {
chunks.push(line_break);
}
if (chomping === true) {
chunks = chunks.concat(breaks);
}
return new tokens.ScalarToken(chunks.join(''), false, start_mark, end_mark, style);
};
/*
See the specification for details.
*/
Scanner.prototype.scan_block_scalar_indicators = function(start_mark) {
var char, chomping, increment;
chomping = null;
increment = null;
char = this.peek();
if (__indexOf.call('+-', char) >= 0) {
chomping = char === '+';
this.forward();
char = this.peek();
if (__indexOf.call(C_NUMBERS, char) >= 0) {
increment = parseInt(char);
if (increment === 0) {
throw new exports.ScannerError('while scanning a block scalar', start_mark, 'expected indentation indicator in the range 1-9 but found 0', this.get_mark());
}
this.forward();
}
} else if (__indexOf.call(C_NUMBERS, char) >= 0) {
increment = parseInt(char);
if (increment === 0) {
throw new exports.ScannerError('while scanning a block scalar', start_mark, 'expected indentation indicator in the range 1-9 but found 0', this.get_mark());
}
this.forward();
char = this.peek();
if (__indexOf.call('+-', char) >= 0) {
chomping = char === '+';
this.forward();
}
}
char = this.peek();
if (__indexOf.call(C_LB + '\x00 ', char) < 0) {
throw new exports.ScannerError('while scanning a block scalar', start_mark, "expected chomping or indentation indicators, but found " + char, this.get_mark());
}
return [chomping, increment];
};
/*
See the specification for details.
*/
Scanner.prototype.scan_block_scalar_ignored_line = function(start_mark) {
var char, _ref1;
while (this.peek() === ' ') {
this.forward();
}
if (this.peek() === '#') {
while (_ref1 = this.peek(), __indexOf.call(C_LB + '\x00', _ref1) < 0) {
this.forward();
}
}
char = this.peek();
if (__indexOf.call(C_LB + '\x00', char) < 0) {
throw new exports.ScannerError('while scanning a block scalar', start_mark, "expected a comment or a line break but found " + char, this.get_mark());
}
return this.scan_line_break();
};
/*
See the specification for details.
*/
Scanner.prototype.scan_block_scalar_indentation = function() {
var chunks, end_mark, max_indent, _ref1;
chunks = [];
max_indent = 0;
end_mark = this.get_mark();
while (_ref1 = this.peek(), __indexOf.call(C_LB + ' ', _ref1) >= 0) {
if (this.peek() !== ' ') {
chunks.push(this.scan_line_break());
end_mark = this.get_mark();
} else {
this.forward();
if (this.column > max_indent) {
max_indent = this.column;
}
}
}
return [chunks, max_indent, end_mark];
};
/*
See the specification for details.
*/
Scanner.prototype.scan_block_scalar_breaks = function(indent) {
var chunks, end_mark, _ref1;
chunks = [];
end_mark = this.get_mark();
while (this.column < indent && this.peek() === ' ') {
this.forward();
}
while (_ref1 = this.peek(), __indexOf.call(C_LB, _ref1) >= 0) {
chunks.push(this.scan_line_break());
end_mark = this.get_mark();
while (this.column < indent && this.peek() === ' ') {
this.forward();
}
}
return [chunks, end_mark];
};
/*
See the specification for details.
Note that we loose indentation rules for quoted scalars. Quoted scalars
don't need to adhere indentation because " and ' clearly mark the beginning
and the end of them. Therefore we are less restrictive than the
specification requires. We only need to check that document separators are
not included in scalars.
*/
Scanner.prototype.scan_flow_scalar = function(style) {
var chunks, double, quote, start_mark;
double = style === '"';
chunks = [];
start_mark = this.get_mark();
quote = this.peek();
this.forward();
chunks = chunks.concat(this.scan_flow_scalar_non_spaces(double, start_mark));
while (this.peek() !== quote) {
chunks = chunks.concat(this.scan_flow_scalar_spaces(double, start_mark));
chunks = chunks.concat(this.scan_flow_scalar_non_spaces(double, start_mark));
}
this.forward();
return new tokens.ScalarToken(chunks.join(''), false, start_mark, this.get_mark(), style);
};
/*
See the specification for details.
*/
Scanner.prototype.scan_flow_scalar_non_spaces = function(double, start_mark) {
var char, chunks, code, k, length, _i, _ref1, _ref2;
chunks = [];
while (true) {
length = 0;
while (_ref1 = this.peek(length), __indexOf.call(C_LB + C_WS + '\'"\\\x00', _ref1) < 0) {
length++;
}
if (length !== 0) {
chunks.push(this.prefix(length));
this.forward(length);
}
char = this.peek();
if (!double && char === '\'' && this.peek(1) === '\'') {
chunks.push('\'');
this.forward(2);
} else if ((double && char === '\'') || (!double && __indexOf.call('"\\', char) >= 0)) {
chunks.push(char);
this.forward();
} else if (double && char === '\\') {
this.forward();
char = this.peek();
if (char in ESCAPE_REPLACEMENTS) {
chunks.push(ESCAPE_REPLACEMENTS[char]);
this.forward();
} else if (char in ESCAPE_CODES) {
length = ESCAPE_CODES[char];
this.forward();
for (k = _i = 0; 0 <= length ? _i < length : _i > length; k = 0 <= length ? ++_i : --_i) {
if (_ref2 = this.peek(k), __indexOf.call(C_NUMBERS + 'ABCDEFabcdef', _ref2) < 0) {
throw new exports.ScannerError('while scanning a double-quoted scalar', start_mark, "expected escape sequence of " + length + " hexadecimal numbers, but " + "found " + (this.peek(k)), this.get_mark());
}
}
code = parseInt(this.prefix(length), 16);
chunks.push(String.fromCharCode(code));
this.forward(length);
} else if (__indexOf.call(C_LB, char) >= 0) {
this.scan_line_break();
chunks = chunks.concat(this.scan_flow_scalar_breaks(double, start_mark));
} else {
throw new exports.ScannerError('while scanning a double-quoted scalar', start_mark, "found unknown escape character " + char, this.get_mark());
}
} else {
return chunks;
}
}
};
/*
See the specification for details.
*/
Scanner.prototype.scan_flow_scalar_spaces = function(double, start_mark) {
var breaks, char, chunks, length, line_break, whitespaces, _ref1;
chunks = [];
length = 0;
while (_ref1 = this.peek(length), __indexOf.call(C_WS, _ref1) >= 0) {
length++;
}
whitespaces = this.prefix(length);
this.forward(length);
char = this.peek();
if (char === '\x00') {
throw new exports.ScannerError('while scanning a quoted scalar', start_mark, 'found unexpected end of stream', this.get_mark());
}
if (__indexOf.call(C_LB, char) >= 0) {
line_break = this.scan_line_break();
breaks = this.scan_flow_scalar_breaks(double, start_mark);
if (line_break !== '\n') {
chunks.push(line_break);
} else if (!breaks) {
chunks.push(' ');
}
chunks = chunks.concat(breaks);
} else {
chunks.push(whitespaces);
}
return chunks;
};
/*
See the specification for details.
*/
Scanner.prototype.scan_flow_scalar_breaks = function(double, start_mark) {
var chunks, prefix, _ref1, _ref2, _ref3;
chunks = [];
while (true) {
prefix = this.prefix(3);
if (prefix === '---' || prefix === '...' && (_ref1 = this.peek(3), __indexOf.call(C_LB + C_WS + '\x00', _ref1) >= 0)) {
throw new exports.ScannerError('while scanning a quoted scalar', start_mark, 'found unexpected document separator', this.get_mark());
}
while (_ref2 = this.peek(), __indexOf.call(C_WS, _ref2) >= 0) {
this.forward();
}
if (_ref3 = this.peek(), __indexOf.call(C_LB, _ref3) >= 0) {
chunks.push(this.scan_line_break());
} else {
return chunks;
}
}
};
/*
See the specification for details.
We add an additional restriction for the flow context:
plain scalars in the flow context cannot contain ',', ':' and '?'.
We also keep track of the `allow_simple_key` flag here.
Indentation rules are loosed for the flow context.
*/
Scanner.prototype.scan_plain = function() {
var char, chunks, end_mark, indent, length, spaces, start_mark, _ref1, _ref2;
chunks = [];
start_mark = end_mark = this.get_mark();
indent = this.indent + 1;
spaces = [];
while (true) {
length = 0;
if (this.peek() === '#') {
break;
}
while (true) {
char = this.peek(length);
if (__indexOf.call(C_LB + C_WS + '\x00', char) >= 0 || (this.flow_level === 0 && char === ':' && (_ref1 = this.peek(length + 1), __indexOf.call(C_LB + C_WS + '\x00', _ref1) >= 0)) || (this.flow_level !== 0 && __indexOf.call(',:?[]{}', char) >= 0)) {
break;
}
length++;
}
if (this.flow_level !== 0 && char === ':' && (_ref2 = this.peek(length + 1), __indexOf.call(C_LB + C_WS + '\x00,[]{}', _ref2) < 0)) {
this.forward(length);
throw new exports.ScannerError('while scanning a plain scalar', start_mark, 'found unexpected \':\'', this.get_mark(), 'Please check http://pyyaml.org/wiki/YAMLColonInFlowContext');
}
if (length === 0) {
break;
}
this.allow_simple_key = false;
chunks = chunks.concat(spaces);
chunks.push(this.prefix(length));
this.forward(length);
end_mark = this.get_mark();
spaces = this.scan_plain_spaces(indent, start_mark);
if ((spaces == null) || spaces.length === 0 || this.peek() === '#' || (this.flow_level === 0 && this.column < indent)) {
break;
}
}
return new tokens.ScalarToken(chunks.join(''), true, start_mark, end_mark);
};
/*
See the specification for details.
The specification is really confusing about tabs in plain scalars.
We just forbid them completely. Do not use tabs in YAML!
*/
Scanner.prototype.scan_plain_spaces = function(indent, start_mark) {
var breaks, char, chunks, length, line_break, prefix, whitespaces, _ref1, _ref2, _ref3, _ref4;
chunks = [];
length = 0;
while (_ref1 = this.peek(length), __indexOf.call(' ', _ref1) >= 0) {
length++;
}
whitespaces = this.prefix(length);
this.forward(length);
char = this.peek();
if (__indexOf.call(C_LB, char) >= 0) {
line_break = this.scan_line_break();
this.allow_simple_key = true;
prefix = this.prefix(3);
if (prefix === '---' || prefix === '...' && (_ref2 = this.peek(3), __indexOf.call(C_LB + C_WS + '\x00', _ref2) >= 0)) {
return;
}
breaks = [];
while (_ref4 = this.peek(), __indexOf.call(C_LB + ' ', _ref4) >= 0) {
if (this.peek() === ' ') {
this.forward();
} else {
breaks.push(this.scan_line_break());
prefix = this.prefix(3);
if (prefix === '---' || prefix === '...' && (_ref3 = this.peek(3), __indexOf.call(C_LB + C_WS + '\x00', _ref3) >= 0)) {
return;
}
}
}
if (line_break !== '\n') {
chunks.push(line_break);
} else if (breaks.length === 0) {
chunks.push(' ');
}
chunks = chunks.concat(breaks);
} else if (whitespaces) {
chunks.push(whitespaces);
}
return chunks;
};
/*
See the specification for details.
For some strange reasons, the specification does not allow '_' in tag
handles. I have allowed it anyway.
*/
Scanner.prototype.scan_tag_handle = function(name, start_mark) {
var char, length, value;
char = this.peek();
if (char !== '!') {
throw new exports.ScannerError("while scanning a " + name, start_mark, "expected '!' but found " + char, this.get_mark());
}
length = 1;
char = this.peek(length);
if (char !== ' ') {
while (('0' <= char && char <= '9') || ('A' <= char && char <= 'Z') || ('a' <= char && char <= 'z') || __indexOf.call('-_', char) >= 0) {
length++;
char = this.peek(length);
}
if (char !== '!') {
this.forward(length);
throw new exports.ScannerError("while scanning a " + name, start_mark, "expected '!' but found " + char, this.get_mark());
}
length++;
}
value = this.prefix(length);
this.forward(length);
return value;
};
/*
See the specification for details.
Note: we do not check if URI is well-formed.
*/
Scanner.prototype.scan_tag_uri = function(name, start_mark) {
var char, chunks, length;
chunks = [];
length = 0;
char = this.peek(length);
while (('0' <= char && char <= '9') || ('A' <= char && char <= 'Z') || ('a' <= char && char <= 'z') || __indexOf.call('-;/?:@&=+$,_.!~*\'()[]%', char) >= 0) {
if (char === '%') {
chunks.push(this.prefix(length));
this.forward(length);
length = 0;
chunks.push(this.scan_uri_escapes(name, start_mark));
} else {
length++;
}
char = this.peek(length);
}
if (length !== 0) {
chunks.push(this.prefix(length));
this.forward(length);
length = 0;
}
if (chunks.length === 0) {
throw new exports.ScannerError("while parsing a " + name, start_mark, "expected URI but found " + char, this.get_mark());
}
return chunks.join('');
};
/*
See the specification for details.
*/
Scanner.prototype.scan_uri_escapes = function(name, start_mark) {
var bytes, k, mark, _i;
bytes = [];
mark = this.get_mark();
while (this.peek() === '%') {
this.forward();
for (k = _i = 0; _i <= 2; k = ++_i) {
throw new exports.ScannerError("while scanning a " + name, start_mark, "expected URI escape sequence of 2 hexadecimal numbers but found " + (this.peek(k)), this.get_mark());
}
bytes.push(String.fromCharCode(parseInt(this.prefix(2), 16)));
this.forward(2);
}
return bytes.join('');
};
/*
Transforms:
'\r\n' : '\n'
'\r' : '\n'
'\n' : '\n'
'\x85' : '\n'
'\u2028' : '\u2028'
'\u2029 : '\u2029'
default : ''
*/
Scanner.prototype.scan_line_break = function() {
var char;
char = this.peek();
if (__indexOf.call('\r\n\x85', char) >= 0) {
if (this.prefix(2) === '\r\n') {
this.forward(2);
} else {
this.forward();
}
return '\n';
} else if (__indexOf.call('\u2028\u2029', char) >= 0) {
this.forward();
return char;
}
return '';
};
return Scanner;
})();
}).call(this);