@gulujs/toml
Version:
TOML parser and serializer
102 lines (101 loc) • 3.76 kB
JavaScript
import { INVALID_CHARACTER_MESSAGE, INVALID_ESCAPE_CODES_MESSAGE, SYNTAX_ERROR_MESSAGE } from '../errors/index.js';
import { ESCAPE_CHARACTER_MAP, RE_ESCAPE_CHARACTER, RE_INVALID_CHARACTER_WITHOUT_REPLACEMENT_CHARACTER, RE_INVALID_CHARACTER_WITH_REPLACEMENT_CHARACTER, RE_WHITESPACE_OR_COMMENT } from './constants.js';
export class Source {
constructor(source, options) {
this.source = source;
this.nextPos = 0;
this.end = false;
this.RE_INVALID_CHARACTER = RE_INVALID_CHARACTER_WITH_REPLACEMENT_CHARACTER;
this.lineNum = 0;
this.line = '';
this.disableCheckReplacementCharacter = !!options?.disableCheckReplacementCharacter;
if (this.disableCheckReplacementCharacter) {
this.RE_INVALID_CHARACTER = RE_INVALID_CHARACTER_WITHOUT_REPLACEMENT_CHARACTER;
}
}
next() {
if (this.end) {
return false;
}
const start = this.nextPos;
const i = this.source.indexOf('\n', start);
this.lineNum++;
if (i >= 0) {
this.nextPos = i + 1;
}
else {
this.nextPos = this.source.length;
this.end = true;
}
this.line = this.source.substring(start, this.nextPos);
return true;
}
assertWhitespaceOrComment(offset) {
RE_WHITESPACE_OR_COMMENT.lastIndex = offset;
const matches = RE_WHITESPACE_OR_COMMENT.exec(this.line);
if (!matches || matches.index !== offset) {
throw new SyntaxError(SYNTAX_ERROR_MESSAGE(this, offset));
}
if (matches[2]) {
this.assertValidString(matches[2], offset + matches[1].length + 1);
}
return matches[2];
}
assertValidString(str, offset) {
this.RE_INVALID_CHARACTER.lastIndex = 0;
const matches = this.RE_INVALID_CHARACTER.exec(str);
if (!matches) {
return;
}
throw new SyntaxError(INVALID_CHARACTER_MESSAGE(this, offset + matches.index));
}
getKey(offset, re) {
const path = [];
re.lastIndex = offset;
let matches = re.exec(this.line);
while (matches && matches.index === offset) {
if (matches[2]) {
path.push(matches[2]);
}
else if (typeof matches[3] !== 'undefined') {
path.push(matches[3]);
}
else if (typeof matches[4] !== 'undefined') {
path.push(this.unescapeString(matches[4], matches[1].length + 1));
}
if (matches[5]) {
return {
path,
nextIndex: re.lastIndex
};
}
offset = re.lastIndex;
matches = re.exec(this.line);
}
return null;
}
unescapeString(str, offset) {
const replacer = (match, u1, u2, matchOffset) => {
if (u1) {
const code = parseInt(u1, 16);
if ((0 <= code && code <= 0xD7FF) || (0xE000 <= code && code <= 0x10FFFF)) {
return String.fromCodePoint(code);
}
}
else if (u2) {
const code = parseInt(u2, 16);
if ((0 <= code && code <= 0xD7FF) || (0xE000 <= code && code <= 0x10FFFF)) {
return String.fromCodePoint(code);
}
}
else {
const c = ESCAPE_CHARACTER_MAP[match];
if (c) {
return c;
}
}
throw new SyntaxError(INVALID_ESCAPE_CODES_MESSAGE(match, this, offset + matchOffset));
};
return str.replace(RE_ESCAPE_CHARACTER, replacer);
}
}