tenko
Version:
A "pixel perfect" 100% spec compliant ES2021 JavaScript parser written in JS.
137 lines (120 loc) • 10.1 kB
JavaScript
// Test a build, relying only on build imports
import {
Tenko,
Lexer,
toktypeToString,
COLLECT_TOKENS_NONE,
COLLECT_TOKENS_SOLID,
COLLECT_TOKENS_ALL,
COLLECT_TOKENS_TYPES,
GOAL_MODULE,
GOAL_SCRIPT,
WEB_COMPAT_OFF,
WEB_COMPAT_ON,
isWhiteToken,
isNewlineToken,
isCommentToken,
isIdentToken,
isNumberToken,
isBigintToken,
isStringToken,
isPunctuatorToken,
isRegexToken,
isTickToken,
isBadTickToken,
isNumberStringToken,
isNumberStringRegex,
} from '../build/tenko.prod.mjs';
// } from '../src/index.mjs';
if (typeof Tenko !== 'function') throw new Error('Bad Tenko export');
if (typeof Lexer !== 'function') throw new Error('Bad Lexer export');
if (typeof toktypeToString !== 'function') throw new Error('Bad toktypeToString export');
if (typeof COLLECT_TOKENS_NONE === 'undefined') throw new Error('Bad COLLECT_TOKENS_NONE export');
if (typeof COLLECT_TOKENS_SOLID === 'undefined') throw new Error('Bad COLLECT_TOKENS_SOLID export');
if (typeof COLLECT_TOKENS_ALL === 'undefined') throw new Error('Bad COLLECT_TOKENS_ALL export');
if (typeof COLLECT_TOKENS_TYPES === 'undefined') throw new Error('Bad COLLECT_TOKENS_TYPES export');
if (typeof GOAL_MODULE === 'undefined') throw new Error('Bad COLLECT_TOKENS_NONE export');
if (typeof GOAL_SCRIPT === 'undefined') throw new Error('Bad COLLECT_TOKENS_NONE export');
if (typeof WEB_COMPAT_OFF === 'undefined') throw new Error('Bad COLLECT_TOKENS_NONE export');
if (typeof WEB_COMPAT_ON === 'undefined') throw new Error('Bad COLLECT_TOKENS_NONE export');
function pass(...args) {
try {
console.log('####');
Tenko(...args);
return true;
} catch {
return false;
}
}
function _pass(...args) {
try {
console.log('####');
return Tenko(...args);
} catch {
return false;
}
}
// No args
if (!pass('foo')) throw new Error('Basic parse step with all defaults failed');
// Defaults
if (!pass('"\\04"')) throw new Error('Web compat should be enabled as default');
if (pass('import x from "y"')) throw new Error('Script goal should be used as default');
if (!pass('eval = x')) throw new Error('Sloppy mode should be used by default');
// Goals (needs two tests because there is no code that throws in non-strict or module, and does not throw in strict-script
if (!pass('import x from "y"', {goalMode: GOAL_MODULE, strictMode: false, webCompat: false})) throw new Error('`import` should be supported by module goal');
if (pass('import x from "y"', {goalMode: GOAL_SCRIPT, strictMode: false, webCompat: false})) throw new Error('`import` should not be supported by script goal, sloppy');
if (pass('import x from "y"', {goalMode: GOAL_SCRIPT, strictMode: true, webCompat: false})) throw new Error('`import` should not be supported by script goal, strict');
if (!pass('let await = 1', {goalMode: GOAL_SCRIPT, strictMode: false, webCompat: false})) throw new Error('`await` is only keyword in module goal');
if (!pass('let await = 1', {goalMode: GOAL_SCRIPT, strictMode: false, webCompat: false})) throw new Error('`await` is only keyword in module goal');
if (pass('let await = 1', {goalMode: GOAL_MODULE, strictMode: false, webCompat: false})) throw new Error('`await` is keyword in module goal');
// Strict
if (!pass('let arguments = 1', {goalMode: GOAL_SCRIPT, strictMode: false, webCompat: false})) throw new Error('`arguments` only keyword in strict');
if (pass('let arguments = 1', {goalMode: GOAL_SCRIPT, strictMode: true, webCompat: false})) throw new Error('`arguments` is keyword in strict');
if (pass('let arguments = 1', {goalMode: GOAL_MODULE, strictMode: false, webCompat: false})) throw new Error('`arguments` is keyword in module, which enforces strict mode');
// Web
if (pass('"\\04"', {goalMode: GOAL_SCRIPT, strictMode: false, webCompat: false})) throw new Error('octal escapes only legal in web compat mode, not just sloppy-script');
if (pass('"\\04"', {goalMode: GOAL_SCRIPT, strictMode: true, webCompat: false})) throw new Error('octal escapes only legal in web compat mode, not just strict-script');
if (pass('"\\04"', {goalMode: GOAL_MODULE, strictMode: false, webCompat: false})) throw new Error('octal escapes only legal in web compat mode, not module');
if (!pass('"\\04"', {goalMode: GOAL_SCRIPT, strictMode: false, webCompat: true})) throw new Error('octal escapes are legal in web compat mode');
if (pass('"\\04"', {goalMode: GOAL_SCRIPT, strictMode: true, webCompat: true})) throw new Error('octal escapes only legal in non-strict web compat mode');
// Tokens
if (_pass('a // c\nd;', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens.length === 6) throw new Error('When collecting all tokens it should collect the spaces and single-comments too');
if (_pass('a /* c */.d;', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens.length === 6) throw new Error('When collecting all tokens it should collect the spaces and multi-comments too');
if (_pass('a. // c\nd /* xyz */;', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_SOLID}).tokens.length === 4) throw new Error('When collecting solid tokens it should ignore whitespace');
if (_pass('a. // c\nd /* xyz */;', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_NONE}).tokens !== undefined) throw new Error('When collecting no tokens it should not return anything');
if (_pass('a // c\nd;', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_TYPES}).tokens.every(t => typeof t === 'number') === true) throw new Error('COLLECT_TOKENS_TYPES should return int token type ids only');
// Token types
if (typeof isWhiteToken !== 'function') throw new Error('isWhiteToken should be a function');
if (typeof isNewlineToken !== 'function') throw new Error('isNewlineToken should be a function');
if (typeof isCommentToken !== 'function') throw new Error('isCommentToken should be a function');
if (typeof isIdentToken !== 'function') throw new Error('isIdentToken should be a function');
if (typeof isNumberToken !== 'function') throw new Error('isNumberToken should be a function');
if (typeof isBigintToken !== 'function') throw new Error('isBigintToken should be a function');
if (typeof isStringToken !== 'function') throw new Error('isStringToken should be a function');
if (typeof isPunctuatorToken !== 'function') throw new Error('isPunctuatorToken should be a function');
if (typeof isRegexToken !== 'function') throw new Error('isRegexToken should be a function');
if (typeof isTickToken !== 'function') throw new Error('isTickToken should be a function');
if (typeof isBadTickToken !== 'function') throw new Error('isBadTickToken should be a function');
if (typeof isNumberStringToken !== 'function') throw new Error('isNumberStringToken should be a function');
if (typeof isNumberStringRegex !== 'function') throw new Error('isNumberStringRegex should be a function');
// Confirm tokens are passing as they ought to
if (!isWhiteToken(_pass(' ', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('Space should be a whitespace token');
if (!isNewlineToken(_pass('\n', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('Newline should be a newline token');
if (!isWhiteToken(_pass('\n', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('Newline should be a whitespace token');
if (!isCommentToken(_pass('// foo', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('Single line comment should be a comment token');
if (!isWhiteToken(_pass('// foo', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('Single line comment should be a whitespace token');
if (!isCommentToken(_pass('/* foo */', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('Multi line comment should be a comment token');
if (!isWhiteToken(_pass('/* foo */', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('Multi line comment should be a whitespace token');
if (!isIdentToken(_pass('foo', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('`foo` should be an ident token');
if (!isNumberToken(_pass('200', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('200 should be a number token');
if (!isBigintToken(_pass('200n', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('200n should be a bigint token');
if (isBigintToken(_pass('200', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('200 should not be a bigint token');
if (!isStringToken(_pass('"foo"', {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('Double string should be a string token');
if (!isStringToken(_pass("'foo'", {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('Single string should be a string token');
if (!isPunctuatorToken(_pass("+1", {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('`+` should be a punctuator token');
if (!isRegexToken(_pass("/x/", {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('`/x/` should be a punctuator token');
if (!isTickToken(_pass("`x`", {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('`x` should be a punctuator token');
if (!isTickToken(_pass("`x${a}`", {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[0].type)) throw new Error('`x${ should be a punctuator token');
if (!isBadTickToken(_pass("x`\\03`", {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[1].type)) throw new Error('Tagged template with octal escape should be a bad template token');
if (!isTickToken(_pass("x`\\03`", {goalMode: GOAL_SCRIPT, collectTokens: COLLECT_TOKENS_ALL}).tokens[1].type)) throw new Error('Tagged template with octal escape should be a template token');
console.log('Finished tests');