tynder
Version:
TypeScript friendly Data validator for JavaScript.
255 lines • 26.8 kB
JavaScript
// Copyright (c) 2019 Shellyl_N and Authors
// license: ISC
// https://github.com/shellyln
import { getStringParsers } from 'fruitsconfits/modules/lib/string-parser';
import { getObjectParsers } from 'fruitsconfits/modules/lib/object-parser';
import { dummyTargetObject, isUnsafeVarNames } from './protection';
const $s = getStringParsers({
rawToToken: rawToken => rawToken,
concatTokens: tokens => (tokens.length ?
[tokens.reduce((a, b) => String(a) + b)] : []),
});
const $o = getObjectParsers({
rawToToken: rawToken => rawToken,
concatTokens: tokens => (tokens.length ?
[tokens.reduce((a, b) => String(a) + b)] : []),
comparator: (a, b) => a === b,
});
const { seq, cls, notCls, clsFn, classes, numbers, cat, once, repeat, qty, zeroWidth, err, beginning, end, first, or, combine, erase, trans, ahead, rules, makeProgram } = $s;
const directiveLineComment = trans(tokens => [[{ symbol: 'directive' }, ...tokens]])(erase(qty(2)(cls('/'))), erase(repeat(classes.space)), cat(seq('@tynder-'), repeat(first(classes.alnum, cls('-')))), // [0]
erase(repeat(classes.space)), cat(repeat(notCls('\r\n', '\n', '\r'))), // [1]
erase(first(classes.newline, ahead(end()))));
const directiveBlockComment = trans(tokens => [[{ symbol: 'directive' }, ...tokens]])(erase(seq('/*')), erase(repeat(classes.space)), cat(seq('@tynder-'), repeat(first(classes.alnum, cls('-')))), // [0]
erase(repeat(classes.space)), cat(repeat(notCls('*/'))), // [1]
erase(seq('*/')));
const lineComment = combine(erase(qty(2)(cls('/'))), first(combine(ahead(repeat(classes.space), notCls('@tynder-')), repeat(notCls('\r\n', '\n', '\r')), first(classes.newline, ahead(end()))), first(classes.newline, ahead(end()))));
const hashLineComment = combine(seq('#'), repeat(notCls('\r\n', '\n', '\r')), first(classes.newline, ahead(end())));
const docComment = combine(seq('/**'), repeat(classes.space), input => {
const ret = cat(repeat(notCls('*/')))(input);
if (ret.succeeded) {
// define a reducer
const ctx2 = Object.assign({}, ret.next.context); // NOTE: context is immutable
ctx2.docComment = (ret.tokens[0] || '').trim();
ret.next.context = ctx2;
}
return ret;
}, seq('*/'));
const blockComment = combine(seq('/*'), ahead(repeat(classes.space), notCls('@tynder-')), repeat(notCls('*/')), seq('*/'));
const commentOrSpace = first(classes.space, lineComment, hashLineComment, docComment, blockComment);
const trueValue = trans(tokens => [true])(seq('true'));
const falseValue = trans(tokens => [false])(seq('false'));
const nullValue = trans(tokens => [null])(seq('null'));
const undefinedValue = trans(tokens => [void 0])(seq('undefined'));
const positiveInfinityValue = trans(tokens => [Number.POSITIVE_INFINITY])(qty(0, 1)(seq('+')), seq('Infinity'));
const negativeInfinityValue = trans(tokens => [Number.NEGATIVE_INFINITY])(seq('-Infinity'));
const nanValue = trans(tokens => [Number.NaN])(seq('NaN'));
const binaryIntegerValue = trans(tokens => [Number.parseInt(tokens[0].replace(/_/g, ''), 2)])(numbers.bin(seq('0b')));
const octalIntegerValue = trans(tokens => [Number.parseInt(tokens[0].replace(/_/g, ''), 8)])(numbers.oct(seq('0o'), seq('0')));
const hexIntegerValue = trans(tokens => [Number.parseInt(tokens[0].replace(/_/g, ''), 16)])(numbers.hex(seq('0x'), seq('0X')));
const decimalIntegerValue = trans(tokens => [Number.parseInt(tokens[0].replace(/_/g, ''), 10)])(numbers.int);
const bigDecimalIntegerValue = trans(tokens => [BigInt(tokens[0].replace(/_/g, ''))])(numbers.bigint);
const floatingPointNumberValue = trans(tokens => [Number.parseFloat(tokens[0].replace(/_/g, ''))])(numbers.float);
const numberValue = first(octalIntegerValue, hexIntegerValue, binaryIntegerValue, bigDecimalIntegerValue, floatingPointNumberValue, decimalIntegerValue, positiveInfinityValue, negativeInfinityValue, nanValue);
const stringEscapeSeq = first(trans(t => ['\''])(seq('\\\'')), trans(t => ['\"'])(seq('\\"')), trans(t => ['\`'])(seq('\\`')), trans(t => ['/'])(seq('\\/')), trans(t => ['\\'])(seq('\\\\')), trans(t => [''])(seq('\\\r\n')), trans(t => [''])(seq('\\\r')), trans(t => [''])(seq('\\\n')), trans(t => ['\n'])(seq('\\n')), trans(t => ['\r'])(seq('\\r')), trans(t => ['\v'])(seq('\\v')), trans(t => ['\t'])(seq('\\t')), trans(t => ['\b'])(seq('\\b')), trans(t => ['\f'])(seq('\\f')), trans(t => [String.fromCodePoint(Number.parseInt(t[0], 16))])(cat(erase(seq('\\u')), qty(4, 4)(classes.hex))), trans(t => [String.fromCodePoint(Number.parseInt(t[0], 16))])(cat(erase(seq('\\u{')), qty(1, 6)(classes.hex), erase(seq('}')))), trans(t => [String.fromCodePoint(Number.parseInt(t[0], 16))])(cat(erase(seq('\\x')), qty(2, 2)(classes.hex))), trans(t => [String.fromCodePoint(Number.parseInt(t[0], 8))])(cat(erase(seq('\\')), qty(3, 3)(classes.oct))));
const signleQuotStringValue = trans(tokens => { var _a; return [(_a = tokens[0]) !== null && _a !== void 0 ? _a : '']; })(erase(seq("'")), cat(repeat(first(stringEscapeSeq, combine(cls('\r', '\n'), err('Line breaks within strings are not allowed.')), notCls("'")))), erase(seq("'")));
const doubleQuotStringValue = trans(tokens => { var _a; return [(_a = tokens[0]) !== null && _a !== void 0 ? _a : '']; })(erase(seq('"')), cat(repeat(first(stringEscapeSeq, combine(cls('\r', '\n'), err('Line breaks within strings are not allowed.')), notCls('"')))), erase(seq('"')));
const backQuotStringValue = trans(tokens => { var _a; return [(_a = tokens[0]) !== null && _a !== void 0 ? _a : '']; })(erase(seq('`')), cat(repeat(first(stringEscapeSeq, notCls('`')))), erase(seq('`')));
const stringValue = first(signleQuotStringValue, doubleQuotStringValue, backQuotStringValue);
const regexpStringValue =
// TODO: '/' ']' '\\' in character class '[]' is not parsed correctly.
trans(tokens => {
var _a, _b;
return [{ value: tokens[1] ?
new RegExp(((_a = tokens[0]) !== null && _a !== void 0 ? _a : ''), tokens[1]) :
new RegExp(((_b = tokens[0]) !== null && _b !== void 0 ? _b : '')) }];
})(erase(seq('/')), cat(repeat(first(stringEscapeSeq, notCls('/')))), erase(seq('/')), cat(qty(0)(cls('g', 'i', 'm', 's', 'u', 'y'))));
const symbolName = trans(tokens => tokens)(cat(combine(first(classes.alpha, cls('$', '_')), repeat(first(classes.alnum, cls('$', '_'))))));
const decoratorSymbolName = trans(tokens => [{ symbol: tokens[0] }])(cat(combine(seq('@'), first(classes.alpha, cls('$', '_')), repeat(first(classes.alnum, cls('$', '_'))))));
const simpleConstExpr = first(trueValue, falseValue, nullValue, undefinedValue, numberValue, stringValue);
const objKey = first(stringValue, symbolName);
const listValue = first(trans(tokens => [[]])(erase(seq('['), repeat(commentOrSpace), seq(']'))), trans(tokens => {
const ast = [{ symbol: '$list' }];
for (const token of tokens) {
ast.push(token);
}
return [ast];
})(erase(seq('[')), combine(erase(repeat(commentOrSpace)), first(input => listValue(input), // NOTE: recursive definitions
// NOTE: recursive definitions
input => objectValue(input), // should place as lambda.
simpleConstExpr), erase(repeat(commentOrSpace))), repeat(combine(erase(repeat(commentOrSpace), seq(','), repeat(commentOrSpace)), first(input => listValue(input), // NOTE: recursive definitions
// NOTE: recursive definitions
input => objectValue(input), // should place as lambda.
simpleConstExpr), erase(repeat(commentOrSpace)))), qty(0, 1)(erase(seq(','), repeat(commentOrSpace))), first(ahead(seq(']')), err('listValue: Unexpected token has appeared.')), erase(seq(']'))));
const objectKeyValuePair = combine(objKey, erase(repeat(commentOrSpace), first(seq(':'), err('":" is needed.')), repeat(commentOrSpace)), first(input => listValue(input), // NOTE: recursive definitions
// NOTE: recursive definitions
input => objectValue(input), // should place as lambda.
simpleConstExpr, err('object value is needed.')));
const objectValue = first(trans(tokens => [[{ symbol: '#' }]])(erase(seq('{'), repeat(commentOrSpace), seq('}'))), trans(tokens => {
const ast = [{ symbol: '#' }];
for (let i = 0; i < tokens.length; i += 2) {
if (isUnsafeVarNames(dummyTargetObject, tokens[i])) {
throw new Error(`Unsafe symbol name is appeared in object literal: ${tokens[i]}`);
}
ast.push([tokens[i], tokens[i + 1]]);
}
return [ast];
})(erase(seq('{')), combine(erase(repeat(commentOrSpace)), objectKeyValuePair, erase(repeat(commentOrSpace))), repeat(combine(erase(seq(','), repeat(commentOrSpace)), objectKeyValuePair, erase(repeat(commentOrSpace)))), qty(0, 1)(erase(seq(','), repeat(commentOrSpace))), first(ahead(seq('}')), err('objectValue: Unexpected token has appeared.')), erase(seq('}'))));
const constExpr = first(simpleConstExpr, listValue, objectValue);
// const primitiveValue = trans(tokens => [[{symbol: 'primitiveValue'}, tokens[0]]])(
// first(trueValue, falseValue, nullValue, undefinedValue,
// numberValue, stringValue, ));
const primitiveValueNoNullUndefined = trans(tokens => [[{ symbol: 'primitiveValue' }, tokens[0]]])(first(trueValue, falseValue, numberValue, stringValue));
const primitiveTypeName = trans(tokens => [[{ symbol: 'primitive' }, tokens[0]]])(first(seq('number?'), seq('integer?'), seq('bigint?'), seq('string?'), seq('boolean?'), // TODO: '?' is allowed in the sequence assertion
seq('number'), seq('integer'), seq('bigint'), seq('string'), seq('boolean'))); // TODO: function
const additionalPropPrimitiveTypeName = first(seq('number'), seq('string'));
const nullUndefinedTypeName = trans(tokens => [[{ symbol: 'primitive' }, tokens[0]]])(first(seq('null'), seq('undefined'), seq('any'), seq('unknown'), seq('never')));
const simpleOrDottedTypeName = first(primitiveTypeName, nullUndefinedTypeName, trans(tokens => [[{ symbol: 'ref' }, ...tokens]])(ahead(notCls('Array', 'Partial', 'Pick', 'Omit')), combine(symbolName, repeat(combine(erase(repeat(commentOrSpace), seq('.'), repeat(commentOrSpace)), symbolName)))));
const sequenceType = trans(tokens => [[{ symbol: 'sequenceOf' }, ...tokens]])(combine(erase(seq('[')), combine(erase(repeat(commentOrSpace)), input => spreadOrComplexType(first(seq(','), seq(']')))(input), erase(repeat(commentOrSpace))), repeat(combine(erase(seq(','), repeat(commentOrSpace)), input => spreadOrComplexType(first(seq(','), seq(']')))(input), erase(repeat(commentOrSpace)))), qty(0, 1)(erase(seq(','), repeat(commentOrSpace))), first(ahead(seq(']')), err('sequenceType: Unexpected token has appeared.')), erase(seq(']'))));
const arraySizeFactorInner = first(trans(tokens => [[{ symbol: '#' }, ['max', tokens[0]]]])(erase(seq('..')), erase(repeat(commentOrSpace)), decimalIntegerValue), trans(tokens => [[{ symbol: '#' }, ['min', tokens[0]], ['max', tokens[1]]]])(decimalIntegerValue, erase(repeat(commentOrSpace)), erase(seq('..')), erase(repeat(commentOrSpace)), decimalIntegerValue), trans(tokens => [[{ symbol: '#' }, ['min', tokens[0]]]])(decimalIntegerValue, erase(repeat(commentOrSpace)), erase(seq('..'))), trans(tokens => [[{ symbol: '#' }, ['min', tokens[0]], ['max', tokens[0]]]])(decimalIntegerValue));
const arraySizeFactor = trans(tokens => tokens.length > 0 ?
tokens :
[[{ symbol: '#' }]])(erase(seq('[')), erase(repeat(commentOrSpace)), qty(0, 1)(arraySizeFactorInner), erase(repeat(commentOrSpace)), erase(seq(']')));
const complexArrayType = trans(tokens => [[{ symbol: 'repeated' }, tokens[0], tokens[1]]])(erase(seq('Array')), erase(repeat(commentOrSpace)), erase(seq('<')), erase(repeat(commentOrSpace)), first(input => complexType(first(seq(','), seq('>')))(input), err('type is expected in Array type.')), // [0]
erase(repeat(commentOrSpace)), qty(0, 1)(combine(erase(seq(',')), erase(repeat(commentOrSpace)), first(arraySizeFactorInner, // [1]
err('complexArrayType: Unexpected token has appeared. Expect array size.')), erase(repeat(commentOrSpace)))), first(ahead(seq('>')), err('\'>\' is expected in Array type.')), erase(seq('>')));
const partialType = trans(tokens => [[{ symbol: 'partial' }, tokens[0], tokens[1]]])(erase(seq('Partial')), erase(repeat(commentOrSpace)), erase(seq('<')), erase(repeat(commentOrSpace)), first(input => complexType(first(seq(','), seq('>')))(input), err('type is expected in Partial type.')), // [0]
erase(repeat(commentOrSpace)), first(ahead(seq('>')), err('\'>\' is expected in Partial type.')), erase(seq('>')));
const pickOrOmitType = trans(tokens => [[{ symbol: tokens[0] === 'Pick' ? 'picked' : 'omit' }, tokens[1], ...tokens.slice(2)]])(first(seq('Pick'), seq('Omit')), // [0]
erase(repeat(commentOrSpace)), erase(seq('<')), erase(repeat(commentOrSpace)), first(input => complexType(first(seq(','), seq('>')))(input), err('type is expected in Partial type.')), // [1]
erase(repeat(commentOrSpace)), combine(erase(seq(',')), erase(repeat(commentOrSpace)), stringValue, // [2]
qty(0)(combine(erase(repeat(commentOrSpace)), erase(seq('|')), erase(repeat(commentOrSpace)), stringValue)), // [3],...
erase(repeat(commentOrSpace))), first(ahead(seq('>')), err('\'>\' is expected in Pick|Omit type.')), erase(seq('>')));
const genericOrSimpleType = trans(tokens => [tokens[0]])(// remove generics parameters
simpleOrDottedTypeName, // [0]
erase(repeat(commentOrSpace)), qty(0, 1)(combine(erase(seq('<')), combine(// [1]
erase(repeat(commentOrSpace)), first(input => complexType(first(seq(','), seq('>')))(input), err('type is expected in generic type.')), erase(repeat(commentOrSpace))), repeat(combine(// [2]...
erase(seq(','), repeat(commentOrSpace)), first(input => complexType(first(seq(','), seq('>')))(input), err('type is expected in generic type.')), erase(repeat(commentOrSpace)))), qty(0, 1)(erase(seq(','), repeat(commentOrSpace))), first(ahead(seq('>')), err('genericType: Unexpected token has appeared.')), erase(seq('>')))));
const spreadType = trans(tokens => [[{ symbol: 'spread' }, tokens[0], tokens[1]]])(erase(seq('...')), erase(repeat(commentOrSpace)), erase(seq('<')), erase(repeat(commentOrSpace)), input => complexType(first(seq(','), seq('>')))(input), erase(repeat(commentOrSpace)), qty(0, 1)(combine(erase(seq(',')), erase(repeat(commentOrSpace)), first(arraySizeFactorInner, err('spreadType: Unexpected token has appeared. Expect array size.')), erase(repeat(commentOrSpace)))), first(ahead(seq('>')), err('spreadType: Unexpected token has appeared.')), erase(seq('>')));
const decorator = trans(tokens => [tokens])(decoratorSymbolName, qty(0, 1)(first(combine(erase(seq('('), repeat(commentOrSpace), seq(')'))), combine(erase(seq('(')), first(combine(combine(erase(repeat(commentOrSpace)), first(regexpStringValue, constExpr), erase(repeat(commentOrSpace))), repeat(combine(erase(repeat(commentOrSpace)), erase(seq(',')), erase(repeat(commentOrSpace)), first(regexpStringValue, constExpr), erase(repeat(commentOrSpace)))), qty(0, 1)(erase(seq(','), repeat(commentOrSpace))), first(ahead(seq(')')), err('decorator: Unexpected token has appeared. Expect ")".'))), err('decorator: Unexpected token has appeared.')), erase(seq(')'))))));
const decoratorsClause = trans(tokens => tokens)(repeat(combine(decorator, erase(repeat(commentOrSpace)))));
const complexTypeInnerWOSinpleArrayType = (edge) => first(primitiveValueNoNullUndefined, genericOrSimpleType, partialType, pickOrOmitType, complexArrayType, sequenceType, input => interfaceDefInner(first(seq(';'), seq(',')))(input));
const complexTypeInnerRoot = (edge) => trans(tokens => {
let ty = [{ symbol: '$pipe' }, tokens[1], ...tokens[0]];
if (tokens[2] !== null) {
for (const z of tokens[2]) {
ty = [{ symbol: 'repeated' }, ty, z];
}
}
return ([[
ty,
...(tokens[3] ? [tokens[3]] : []),
...tokens.slice(4),
]]);
})(trans(tokens => [tokens])(qty(0, 1)(decoratorsClause)), // [0]
first(// [1]
// [1]
input => complexTypeInnerWOSinpleArrayType(edge)(input), combine(erase(seq('(')), erase(repeat(commentOrSpace)), input => complexType(edge)(input), erase(repeat(commentOrSpace)), erase(seq(')')))), combine(trans(tokens => tokens[0] !== null ? [tokens] : [null])(// [2]
first(qty(1)(combine(erase(repeat(commentOrSpace)), arraySizeFactor)), zeroWidth(() => null))), combine(first(// [3]...
trans(tokens => [tokens[0], ...tokens[1]])(qty(1)(combine(erase(repeat(commentOrSpace)), trans(tokens => [{ op: tokens[0] }])(or(seq('&'), seq('|'), seq('-'))), erase(repeat(commentOrSpace)), input => complexTypeInnerRoot(edge)(input)))), trans(tokens => [])()))));
const binaryOp = (op, op1, op2) => {
return [{ symbol: op }, op1, op2];
};
const isOperator = (v, op) => {
if (typeof v === 'object' && v.op === op) {
return true;
}
return false;
};
const isValue = (v) => {
// TODO: check type
return true;
};
// production rules:
// S -> S "&" S
const complexTypeExprRule3 = $o.trans(tokens => [binaryOp('intersect', tokens[0], tokens[2])])($o.clsFn(t => isValue(t)), $o.clsFn(t => isOperator(t, '&')), $o.clsFn(t => isValue(t)));
// production rules:
// S -> S "|" S
const complexTypeExprRule2 = $o.trans(tokens => [binaryOp('oneOf', tokens[0], tokens[2])])($o.clsFn(t => isValue(t)), $o.clsFn(t => isOperator(t, '|')), $o.clsFn(t => isValue(t)));
// production rules:
// S -> S "-" S
const complexTypeExprRule1 = $o.trans(tokens => [binaryOp('subtract', tokens[0], tokens[2])])($o.clsFn(t => isValue(t)), $o.clsFn(t => isOperator(t, '-')), $o.clsFn(t => isValue(t)));
const complexType = (edge) => rules({
rules: [
complexTypeExprRule3,
complexTypeExprRule2,
complexTypeExprRule1,
],
check: $o.combine($o.classes.any, $o.end()),
})(trans(tokens => tokens[0])(complexTypeInnerRoot(edge)));
const spreadOrComplexType = (edge) => first(spreadType, complexType(edge));
const setDocComment = (input) => {
const ret = zeroWidth(() => [])(input);
if (ret.succeeded) {
const text = ret.next.context.docComment;
ret.next.context = Object.assign({}, ret.next.context);
delete ret.next.context.docComment;
ret.tokens.length = 0;
ret.tokens.push(text ? text : null);
}
return ret;
};
const typeDef = trans(tokens => [[{ symbol: 'def' }, tokens[1], [{ symbol: 'docComment' }, tokens[2], tokens[0]]]])(erase(seq('type')), setDocComment, // [0]
erase(qty(1)(commentOrSpace)), first(symbolName, // [1]
err('typeDef: Unexpected token has appeared. Expect symbol name.')), erase(repeat(commentOrSpace)), first(ahead(seq('=')), err('typeDef: Unexpected token has appeared. Expect "=".')), erase(seq('=')), first(combine(erase(repeat(commentOrSpace)), input => complexType(first(seq(','), seq(';')))(input), // [2]
erase(repeat(commentOrSpace))), err('typeDef: Unexpected token has appeared.')), first(ahead(seq(';')), err('typeDef: Unexpected token has appeared. Expect ";".')), erase(seq(';')));
const interfaceExtendsClause = trans(tokens => [
[{ symbol: '$list' },
...tokens.map(x => [{ symbol: 'ref' }, x])],
])(erase(first(seq('extends'), combine(symbolName, err('interfaceExtendsClause: Unexpected token has appeared. Expect "extends" keyword.')))), erase(qty(1)(commentOrSpace)), first(symbolName, err('interfaceExtendsClause: Unexpected token has appeared. Expect symbol name.')), repeat(combine(erase(repeat(commentOrSpace)), erase(seq(',')), erase(repeat(commentOrSpace)), first(symbolName, err('interfaceExtendsClause: Unexpected token has appeared. Expect symbol name.')))));
const interfaceKey = first(trans(tokens => [[{ symbol: '$list' }, ...tokens]])(erase(seq('[')), erase(repeat(commentOrSpace), objKey, repeat(commentOrSpace), first(seq(':'), err('":" is needed.')), repeat(commentOrSpace)), repeat(combine(first(regexpStringValue, additionalPropPrimitiveTypeName), erase(repeat(commentOrSpace), seq('|'), repeat(commentOrSpace)))), first(regexpStringValue, additionalPropPrimitiveTypeName), erase(repeat(commentOrSpace)), first(ahead(seq(']')), err('interfaceKey: Unexpected token has appeared. Expect "]".')), erase(seq(']'))), objKey);
const interfaceKeyTypePair = (separator) => trans(tokens => [
[{ symbol: '$list' },
tokens[2], [{ symbol: '$pipe' },
tokens[3] === '?' ?
[{ symbol: 'optional' }, tokens[4]] :
tokens[4], ...tokens[0],], tokens[1],]
])(trans(tokens => [tokens])(first(decoratorsClause, zeroWidth(() => []))), // [0] decorators
setDocComment, // [1]
interfaceKey, // [2] key
first(// [3] '?' | ''
combine(erase(repeat(commentOrSpace)), seq('?'), erase(repeat(commentOrSpace))), zeroWidth(() => [''])), erase(repeat(commentOrSpace), first(seq(':'), err('":" is needed.')), repeat(commentOrSpace)), first(// [4] type
// [4] type
input => complexType(first(separator, seq('}')))(input), err('interface member type is needed.')));
const interfaceDefInner = (separator) => trans(tokens => [[{ symbol: 'objectType' }, ...tokens]])(first(combine(erase(seq('{'), repeat(commentOrSpace), seq('}'))), combine(erase(seq('{')), combine(erase(repeat(commentOrSpace)), interfaceKeyTypePair(separator), erase(repeat(commentOrSpace))), repeat(combine(erase(separator, repeat(commentOrSpace)), interfaceKeyTypePair(separator), erase(repeat(commentOrSpace)))), qty(0, 1)(erase(separator, repeat(commentOrSpace))), first(ahead(seq('}')), err('interfaceDefInner: Unexpected token has appeared. Expect "}".')), erase(seq('}')))));
const interfaceDef = trans(tokens => [
[{ symbol: 'def' },
tokens[1],
[{ symbol: 'docComment' },
[{ symbol: 'derived' }, tokens[3], [{ symbol: '$spread' }, tokens[2]]],
tokens[0],]]
])(erase(seq('interface')), setDocComment, // [0] base types
erase(qty(1)(commentOrSpace)), first(symbolName, // [1] symbol
err('interfaceDef: Unexpected token has appeared. Expect symbol name.')), erase(repeat(commentOrSpace)), first(interfaceExtendsClause, // [2]
zeroWidth(() => [])), erase(repeat(commentOrSpace)), first(input => interfaceDefInner(first(seq(';'), seq(',')))(input), // [3]
err('interfaceDef: Unexpected token has appeared.')));
const enumKeyValue = trans(tokens => [[{ symbol: '$list' }, tokens[1], tokens[2], tokens[0]]])(setDocComment, // [0]
symbolName, erase(repeat(commentOrSpace)), first(combine(erase(seq('=')), first(combine(erase(repeat(commentOrSpace)), first(decimalIntegerValue, stringValue), erase(repeat(commentOrSpace))), err('enumKeyValue: Unexpected token has appeared.'))), zeroWidth(() => null)));
const enumDef = trans(tokens => [
[{ symbol: 'def' }, tokens[1],
[{ symbol: 'docComment' },
[{ symbol: 'enumType' }, ...tokens.slice(2)],
tokens[0],]]
])(erase(seq('enum')), setDocComment, // [0]
erase(qty(1)(commentOrSpace)), first(symbolName, err('enumDef: Unexpected token has appeared. Expect symbol name.')), erase(repeat(commentOrSpace)), first(combine(erase(seq('{'), repeat(commentOrSpace), seq('}'))), combine(erase(seq('{')), combine(erase(repeat(commentOrSpace)), enumKeyValue, erase(repeat(commentOrSpace))), repeat(combine(erase(seq(','), repeat(commentOrSpace)), enumKeyValue, erase(repeat(commentOrSpace)))), qty(0, 1)(erase(seq(','), repeat(commentOrSpace))), first(ahead(seq('}')), err('enumDef: Unexpected token has appeared. Expect "}".')), erase(seq('}'))), err('enumDef: Unexpected token has appeared.')));
const internalDef = first(typeDef, interfaceDef, enumDef);
const constDef = trans(tokens => [[{ symbol: 'asConst' }, tokens[0]]])(erase(seq('const'), qty(1)(commentOrSpace)), first(enumDef, err('constDef: Unexpected token has appeared.')));
const constDefNoErr = trans(tokens => [[{ symbol: 'asConst' }, tokens[0]]])(erase(seq('const'), qty(1)(commentOrSpace)), first(enumDef));
const exportedDef = trans(tokens => [[{ symbol: 'export' }, tokens[0]]])(erase(seq('export'), qty(1)(commentOrSpace)), first(constDef, internalDef, input => declareTypeAndEnumStatement(input), input => declareVarStatement(input), err('exportedDef: Unexpected token has appeared.')));
const defStatement = trans(tokens => [
[{ symbol: '$local' }, [
[{ symbol: '_ty' }, tokens[1]],
], [{ symbol: 'redef' },
{ symbol: '_ty' }, [{ symbol: '$pipe' }, { symbol: '_ty' }, ...tokens[0]],]]
])(trans(tokens => [tokens])(first(decoratorsClause, zeroWidth(() => []))), // [0] decorators
first(exportedDef, // [1] body
// [1] body
input => declareTypeAndEnumStatement(input), constDef, internalDef));
const externalSymbolAndType = trans(tokens => [[{ symbol: '$list' }, ...tokens]])(symbolName, erase(repeat(commentOrSpace)), qty(0, 1)(combine(erase(seq(':')), erase(repeat(commentOrSpace)), input => complexType(first(seq(';'), seq(',')))(input))));
export const externalTypeDef = trans(tokens => [[{ symbol: 'external' }, ...tokens]])(erase(seq('external')), erase(qty(1)(commentOrSpace)), externalSymbolAndType, repeat(combine(erase(repeat(commentOrSpace)), erase(cls(',')), erase(repeat(commentOrSpace)), first(externalSymbolAndType, err('externalTypeDef: Unexpected token has appeared. Expect symbol name.')), erase(repeat(commentOrSpace)))), erase(repeat(commentOrSpace)), first(ahead(cls(';')), err('externalTypeDef: Unexpected token has appeared. Expect ";".')), erase(cls(';')));
const declareTypeAndEnumStatement = trans(tokens => [[{ symbol: 'asDeclare' }, ...tokens]])(erase(seq('declare')), erase(qty(1)(commentOrSpace)), first(constDefNoErr, // NOTE: There is still the possibility of "const varName". -> `declareVarStatement` will be called.
internalDef));
const declareVarStatement = trans(tokens => [[{ symbol: 'passthru' }, tokens[0], tokens[1]]])(cat(seq('declare'), qty(1)(commentOrSpace), first(seq('var'), seq('let'), seq('const'), err('declareVarStatement: Unexpected token has appeared. Expect "var|let|const".')), qty(1)(commentOrSpace), cat(repeat(notCls(';'))), first(ahead(seq(';')), err('declareVarStatement: Unexpected token has appeared. Expect ";".')), cls(';')), setDocComment); // [1]
const importStatement = trans(tokens => [[{ symbol: 'passthru' }, tokens[0]]])(cat(seq('import'), qty(1)(commentOrSpace), cat(repeat(notCls(';'))), first(ahead(seq(';')), err('importStatement: Unexpected token has appeared. Expect ";".')), cls(';')));
const definition = first(directiveLineComment, directiveBlockComment, defStatement, externalTypeDef, declareVarStatement, importStatement);
export const program = makeProgram(combine(erase(repeat(commentOrSpace)), repeat(combine(definition, erase(repeat(commentOrSpace)))), erase(repeat(commentOrSpace)), first(ahead(end()), err('program: Unexpected token has appeared.')), end()));
//# sourceMappingURL=compiler.js.map