Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

coffee-lex

Package Overview
Dependencies
Maintainers
2
Versions
71
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

coffee-lex - npm Package Compare versions

Comparing version 9.1.5 to 9.2.0

281

dist/index.d.ts

@@ -1,17 +0,276 @@

import SourceLocation from './SourceLocation';
import SourceTokenList from './SourceTokenList';
import SourceType from './SourceType';
export declare type Options = {
useCS2: boolean;
};
export declare const DEFAULT_OPTIONS: Options;
/**
* Represents a particular type of CoffeeScript code.
*/
declare enum SourceType {
AT = "AT",
BOOL = "BOOL",
BREAK = "BREAK",
CATCH = "CATCH",
CALL_END = "CALL_END",
CALL_START = "CALL_START",
CLASS = "CLASS",
COLON = "COLON",
COMMA = "COMMA",
COMMENT = "COMMENT",
CONTINUATION = "CONTINUATION",
CONTINUE = "CONTINUE",
CSX_BODY = "CSX_BODY",
CSX_CLOSE_TAG_START = "CSX_CLOSE_TAG_START",
CSX_CLOSE_TAG_END = "CSX_CLOSE_TAG_END",
CSX_OPEN_TAG_START = "CSX_OPEN_TAG_START",
CSX_OPEN_TAG_END = "CSX_OPEN_TAG_END",
CSX_SELF_CLOSING_TAG_END = "CSX_SELF_CLOSING_TAG_END",
DECREMENT = "DECREMENT",
DEFAULT = "DEFAULT",
DELETE = "DELETE",
DO = "DO",
DOT = "DOT",
DSTRING_START = "DSTRING_START",
DSTRING_END = "DSTRING_END",
ELSE = "ELSE",
EXPORT = "EXPORT",
EOF = "EOF",
EXISTENCE = "EXISTENCE",
EXTENDS = "EXTENDS",
FINALLY = "FINALLY",
FOR = "FOR",
FUNCTION = "FUNCTION",
HERECOMMENT = "HERECOMMENT",
HEREJS = "HEREJS",
HEREGEXP_COMMENT = "HEREGEXP_COMMENT",
HEREGEXP_START = "HEREGEXP_START",
HEREGEXP_END = "HEREGEXP_END",
IF = "IF",
IMPORT = "IMPORT",
INCREMENT = "INCREMENT",
INTERPOLATION_START = "INTERPOLATION_START",
INTERPOLATION_END = "INTERPOLATION_END",
JS = "JS",
LBRACE = "LBRACE",
LBRACKET = "LBRACKET",
LOOP = "LOOP",
LPAREN = "LPAREN",
NEW = "NEW",
NEWLINE = "NEWLINE",
NORMAL = "NORMAL",
NULL = "NULL",
NUMBER = "NUMBER",
OPERATOR = "OPERATOR",
OWN = "OWN",
PROTO = "PROTO",
RANGE = "RANGE",
REGEXP = "REGEXP",
RBRACE = "RBRACE",
RBRACKET = "RBRACKET",
RELATION = "RELATION",
RETURN = "RETURN",
RPAREN = "RPAREN",
SEMICOLON = "SEMICOLON",
SPACE = "SPACE",
SUPER = "SUPER",
SWITCH = "SWITCH",
SSTRING_START = "SSTRING_START",
SSTRING_END = "SSTRING_END",
STRING_CONTENT = "STRING_CONTENT",
STRING_LINE_SEPARATOR = "STRING_LINE_SEPARATOR",
STRING_PADDING = "STRING_PADDING",
TDSTRING_START = "TDSTRING_START",
TDSTRING_END = "TDSTRING_END",
THEN = "THEN",
THIS = "THIS",
THROW = "THROW",
TRY = "TRY",
TSSTRING_START = "TSSTRING_START",
TSSTRING_END = "TSSTRING_END",
UNDEFINED = "UNDEFINED",
UNKNOWN = "UNKNOWN",
WHEN = "WHEN",
WHILE = "WHILE",
IDENTIFIER = "IDENTIFIER",
YIELD = "YIELD",
YIELDFROM = "YIELDFROM"
}
/**
* Represents a change in source code type at a particular index.
*/
declare class SourceLocation {
readonly type: SourceType;
readonly index: number;
constructor(type: SourceType, index: number);
}
declare class SourceToken {
readonly type: SourceType;
readonly start: number;
readonly end: number;
constructor(type: SourceType, start: number, end: number);
}
/**
* Represents a token at a particular index within a list of tokens.
*/
declare class SourceTokenListIndex {
private _sourceTokenList;
private _index;
constructor(sourceTokenList: SourceTokenList, index: number);
/**
* Get a new index offset from this one, if the resulting offset is within
* the list range.
*/
advance(offset: number): SourceTokenListIndex | null;
/**
* Get the index of the token after this one, if it's not the last one.
*/
next(): SourceTokenListIndex | null;
/**
* Get the index of the token before this one, if it's not the first one.
*/
previous(): SourceTokenListIndex | null;
/**
* Determines whether this index comes before another.
*/
isBefore(other: SourceTokenListIndex): boolean;
/**
* Determines whether this index comes after another.
*/
isAfter(other: SourceTokenListIndex): boolean;
/**
* Compare this index to another, returning 0 for equality, a negative number
* if this is less than `other`, and a positive number otherwise.
*/
compare(other: SourceTokenListIndex): number;
/**
* Returns an int of the relative distance between this index and the other
* index (positive if the other one is later, negative if the other one is
* earlier).
*/
distance(other: SourceTokenListIndex): number;
}
declare type SourceTokenListIndexRange = [
SourceTokenListIndex,
SourceTokenListIndex
];
/**
* Represents a list of tokens and provides various utility functions for
* finding tokens within it.
*/
declare class SourceTokenList {
private _tokens;
private _indexCache;
private _indexBySourceIndex;
private _indexByStartSourceIndex;
private _indexByEndSourceIndex;
readonly length: number;
readonly startIndex: SourceTokenListIndex;
readonly endIndex: SourceTokenListIndex;
constructor(tokens: Array<SourceToken>);
/**
* Iterate over each token.
*/
forEach(iterator: (token: SourceToken, index: SourceTokenListIndex, list: SourceTokenList) => void): void;
/**
* Map each token to an element of an array.
*/
map<T>(mapper: (token: SourceToken, index: SourceTokenListIndex, list: SourceTokenList) => T): Array<T>;
/**
* Filter tokens by a predicate.
*/
filter(predicate: (token: SourceToken, index: SourceTokenListIndex, list: SourceTokenList) => boolean): SourceTokenList;
/**
* Get a slice of this token list using the given indexes.
*/
slice(start: SourceTokenListIndex, end: SourceTokenListIndex): SourceTokenList;
/**
* Get the token at the given index, if it exists.
*
* NOTE: The only value for which this should return `null` is this list's
* `endIndex`.
*/
tokenAtIndex(index: SourceTokenListIndex): SourceToken | null;
/**
* Get the range of tokens representing an interpolated string that contains
* the token at `index`. This will return the innermost interpolated string in
* the case of nesting.
*/
rangeOfInterpolatedStringTokensContainingTokenIndex(index: SourceTokenListIndex): SourceTokenListIndexRange | null;
/**
* Get the range of tokens starting with a token of type `startType` and
* ending one past a token of type `endType`, ensuring that the tokens match.
* That is, it ensures they are balanced and properly account for nesting.
* This range will contain `index`. If no such range can be found, `null` is
* returned.
*/
rangeOfMatchingTokensContainingTokenIndex(startType: SourceType, endType: SourceType, index: SourceTokenListIndex): SourceTokenListIndexRange | null;
/**
* Finds the index of the token whose source range includes the given index.
* If the given index does not correspond to the range of a token, returns
* null.
*/
indexOfTokenContainingSourceIndex(index: number): SourceTokenListIndex | null;
/**
* If the given source index lands on a token, return the index of that token.
* Otherwise, return the index of the previous token in the source code, or
* the first token if there is no previous token.
*/
indexOfTokenNearSourceIndex(index: number): SourceTokenListIndex;
/**
* Finds the index of the token whose source range starts at the given index.
*/
indexOfTokenStartingAtSourceIndex(index: number): SourceTokenListIndex | null;
/**
* Finds the index of the token whose source range ends at the given index.
*/
indexOfTokenEndingAtSourceIndex(index: number): SourceTokenListIndex | null;
/**
* Finds the index of the first token matching a predicate.
*/
indexOfTokenMatchingPredicate(predicate: (token: SourceToken) => boolean, start?: SourceTokenListIndex | null, end?: SourceTokenListIndex | null): SourceTokenListIndex | null;
/**
* Finds the index of the first token matching a predicate, traversing
* backwards.
*/
lastIndexOfTokenMatchingPredicate(predicate: (token: SourceToken) => boolean, start?: SourceTokenListIndex | null, end?: SourceTokenListIndex | null): SourceTokenListIndex | null;
/**
* Allow iterating over the tokens in this list using e.g. `for (… of …)`.
*/
[Symbol.iterator](): Iterator<SourceToken>;
/**
* @internal
*/
private _validateTokens;
/**
* @internal
*/
private _validateIndex;
/**
* @internal
*/
private _validateSourceIndex;
/**
* @internal
*/
private _getIndex;
/**
* Get the list of tokens.
*/
toArray(): Array<SourceToken>;
}
interface Options {
readonly useCS2: boolean;
}
declare const DEFAULT_OPTIONS: Options;
/**
* Generate a list of tokens from CoffeeScript source code.
*/
export default function lex(source: string, options?: Options): SourceTokenList;
export { SourceType };
declare function lex(source: string, options?: Options): SourceTokenList;
/**
* Provides a stream of source type change locations.
*/
export declare function stream(source: string, index?: number, options?: Options): () => SourceLocation;
export declare function consumeStream(lexer: () => SourceLocation): Array<SourceLocation>;
declare function stream(source: string, index?: number, options?: Options): () => SourceLocation;
declare function consumeStream(lexer: () => SourceLocation): Array<SourceLocation>;
export { DEFAULT_OPTIONS, Options, SourceType, consumeStream, lex as default, lex, stream };

2357

dist/index.js

@@ -1,142 +0,904 @@

"use strict";
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
Object.defineProperty(exports, "__esModule", { value: true });
var SourceLocation_1 = require("./SourceLocation");
var SourceToken_1 = require("./SourceToken");
var SourceTokenList_1 = require("./SourceTokenList");
var SourceType_1 = require("./SourceType");
exports.SourceType = SourceType_1.default;
var BufferedStream_1 = require("./utils/BufferedStream");
var calculateHeregexpPadding_1 = require("./utils/calculateHeregexpPadding");
var calculateNormalStringPadding_1 = require("./utils/calculateNormalStringPadding");
var calculateTripleQuotedStringPadding_1 = require("./utils/calculateTripleQuotedStringPadding");
var ContextType;
(function (ContextType) {
ContextType["STRING"] = "STRING";
ContextType["INTERPOLATION"] = "INTERPOLATION";
ContextType["CSX_OPEN_TAG"] = "CSX_OPEN_TAG";
ContextType["CSX_CLOSE_TAG"] = "CSX_CLOSE_TAG";
ContextType["CSX_BODY"] = "CSX_BODY";
ContextType["BRACE"] = "BRACE";
ContextType["PAREN"] = "PAREN";
})(ContextType || (ContextType = {}));
exports.DEFAULT_OPTIONS = {
useCS2: false
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
/**
* Generate a list of tokens from CoffeeScript source code.
*/
function lex(source, options) {
if (options === void 0) { options = exports.DEFAULT_OPTIONS; }
var location;
var previousLocation;
var tokens = [];
var pending = new BufferedStream_1.default(stream(source, 0, options));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
DEFAULT_OPTIONS: () => DEFAULT_OPTIONS,
SourceType: () => SourceType,
consumeStream: () => consumeStream,
default: () => lex,
lex: () => lex,
stream: () => stream
});
module.exports = __toCommonJS(src_exports);
// src/SourceLocation.ts
var SourceLocation = class {
constructor(type, index) {
this.type = type;
this.index = index;
}
};
// src/SourceToken.ts
var SourceToken = class {
constructor(type, start, end) {
this.type = type;
this.start = start;
this.end = end;
if (start > end) {
throw new Error(`Token start may not be after end. Got ${type}, ${start}, ${end}`);
}
}
};
// src/SourceTokenListIndex.ts
var SourceTokenListIndex = class {
constructor(sourceTokenList, index) {
this._sourceTokenList = sourceTokenList;
this._index = index;
}
advance(offset) {
const newIndex = this._index + offset;
if (newIndex < 0 || this._sourceTokenList.length < newIndex) {
return null;
}
return this._sourceTokenList["_getIndex"](newIndex);
}
next() {
return this.advance(1);
}
previous() {
return this.advance(-1);
}
isBefore(other) {
return this.compare(other) > 0;
}
isAfter(other) {
return this.compare(other) < 0;
}
compare(other) {
return this.distance(other);
}
distance(other) {
if (other._sourceTokenList !== this._sourceTokenList) {
throw new Error("cannot compare indexes from different lists");
}
return other._index - this._index;
}
};
// src/SourceType.ts
var SourceType = /* @__PURE__ */ ((SourceType2) => {
SourceType2["AT"] = "AT";
SourceType2["BOOL"] = "BOOL";
SourceType2["BREAK"] = "BREAK";
SourceType2["CATCH"] = "CATCH";
SourceType2["CALL_END"] = "CALL_END";
SourceType2["CALL_START"] = "CALL_START";
SourceType2["CLASS"] = "CLASS";
SourceType2["COLON"] = "COLON";
SourceType2["COMMA"] = "COMMA";
SourceType2["COMMENT"] = "COMMENT";
SourceType2["CONTINUATION"] = "CONTINUATION";
SourceType2["CONTINUE"] = "CONTINUE";
SourceType2["CSX_BODY"] = "CSX_BODY";
SourceType2["CSX_CLOSE_TAG_START"] = "CSX_CLOSE_TAG_START";
SourceType2["CSX_CLOSE_TAG_END"] = "CSX_CLOSE_TAG_END";
SourceType2["CSX_OPEN_TAG_START"] = "CSX_OPEN_TAG_START";
SourceType2["CSX_OPEN_TAG_END"] = "CSX_OPEN_TAG_END";
SourceType2["CSX_SELF_CLOSING_TAG_END"] = "CSX_SELF_CLOSING_TAG_END";
SourceType2["DECREMENT"] = "DECREMENT";
SourceType2["DEFAULT"] = "DEFAULT";
SourceType2["DELETE"] = "DELETE";
SourceType2["DO"] = "DO";
SourceType2["DOT"] = "DOT";
SourceType2["DSTRING_START"] = "DSTRING_START";
SourceType2["DSTRING_END"] = "DSTRING_END";
SourceType2["ELSE"] = "ELSE";
SourceType2["EXPORT"] = "EXPORT";
SourceType2["EOF"] = "EOF";
SourceType2["EXISTENCE"] = "EXISTENCE";
SourceType2["EXTENDS"] = "EXTENDS";
SourceType2["FINALLY"] = "FINALLY";
SourceType2["FOR"] = "FOR";
SourceType2["FUNCTION"] = "FUNCTION";
SourceType2["HERECOMMENT"] = "HERECOMMENT";
SourceType2["HEREJS"] = "HEREJS";
SourceType2["HEREGEXP_COMMENT"] = "HEREGEXP_COMMENT";
SourceType2["HEREGEXP_START"] = "HEREGEXP_START";
SourceType2["HEREGEXP_END"] = "HEREGEXP_END";
SourceType2["IF"] = "IF";
SourceType2["IMPORT"] = "IMPORT";
SourceType2["INCREMENT"] = "INCREMENT";
SourceType2["INTERPOLATION_START"] = "INTERPOLATION_START";
SourceType2["INTERPOLATION_END"] = "INTERPOLATION_END";
SourceType2["JS"] = "JS";
SourceType2["LBRACE"] = "LBRACE";
SourceType2["LBRACKET"] = "LBRACKET";
SourceType2["LOOP"] = "LOOP";
SourceType2["LPAREN"] = "LPAREN";
SourceType2["NEW"] = "NEW";
SourceType2["NEWLINE"] = "NEWLINE";
SourceType2["NORMAL"] = "NORMAL";
SourceType2["NULL"] = "NULL";
SourceType2["NUMBER"] = "NUMBER";
SourceType2["OPERATOR"] = "OPERATOR";
SourceType2["OWN"] = "OWN";
SourceType2["PROTO"] = "PROTO";
SourceType2["RANGE"] = "RANGE";
SourceType2["REGEXP"] = "REGEXP";
SourceType2["RBRACE"] = "RBRACE";
SourceType2["RBRACKET"] = "RBRACKET";
SourceType2["RELATION"] = "RELATION";
SourceType2["RETURN"] = "RETURN";
SourceType2["RPAREN"] = "RPAREN";
SourceType2["SEMICOLON"] = "SEMICOLON";
SourceType2["SPACE"] = "SPACE";
SourceType2["SUPER"] = "SUPER";
SourceType2["SWITCH"] = "SWITCH";
SourceType2["SSTRING_START"] = "SSTRING_START";
SourceType2["SSTRING_END"] = "SSTRING_END";
SourceType2["STRING_CONTENT"] = "STRING_CONTENT";
SourceType2["STRING_LINE_SEPARATOR"] = "STRING_LINE_SEPARATOR";
SourceType2["STRING_PADDING"] = "STRING_PADDING";
SourceType2["TDSTRING_START"] = "TDSTRING_START";
SourceType2["TDSTRING_END"] = "TDSTRING_END";
SourceType2["THEN"] = "THEN";
SourceType2["THIS"] = "THIS";
SourceType2["THROW"] = "THROW";
SourceType2["TRY"] = "TRY";
SourceType2["TSSTRING_START"] = "TSSTRING_START";
SourceType2["TSSTRING_END"] = "TSSTRING_END";
SourceType2["UNDEFINED"] = "UNDEFINED";
SourceType2["UNKNOWN"] = "UNKNOWN";
SourceType2["WHEN"] = "WHEN";
SourceType2["WHILE"] = "WHILE";
SourceType2["IDENTIFIER"] = "IDENTIFIER";
SourceType2["YIELD"] = "YIELD";
SourceType2["YIELDFROM"] = "YIELDFROM";
return SourceType2;
})(SourceType || {});
// src/SourceTokenList.ts
var SourceTokenList = class {
constructor(tokens) {
this._validateTokens(tokens);
this._tokens = tokens;
this._indexCache = new Array(tokens.length);
this.length = tokens.length;
this.startIndex = this._getIndex(0);
this.endIndex = this._getIndex(tokens.length);
this._indexBySourceIndex = [];
this._indexByStartSourceIndex = [];
this._indexByEndSourceIndex = [];
for (let tokenIndex = tokens.length - 1; tokenIndex >= 0; tokenIndex--) {
const token = tokens[tokenIndex];
for (let sourceIndex = token.start; sourceIndex < token.end; sourceIndex++) {
this._indexBySourceIndex[sourceIndex] = this._getIndex(tokenIndex);
}
this._indexByStartSourceIndex[token.start] = this._getIndex(tokenIndex);
this._indexByEndSourceIndex[token.end] = this._getIndex(tokenIndex);
}
}
forEach(iterator) {
this._tokens.forEach((token, i) => iterator(token, this._getIndex(i), this));
}
map(mapper) {
const result = [];
this.forEach((token, index, list) => {
result.push(mapper(token, index, list));
});
return result;
}
filter(predicate) {
const result = [];
this.forEach((token, index, list) => {
if (predicate(token, index, list)) {
result.push(token);
}
});
return new SourceTokenList(result);
}
slice(start, end) {
if (start["_sourceTokenList"] !== this || end["_sourceTokenList"] !== this) {
throw new Error("cannot slice a list using indexes from another list");
}
return new SourceTokenList(this._tokens.slice(start["_index"], end["_index"]));
}
tokenAtIndex(index) {
this._validateIndex(index);
return this._tokens[index["_index"]] || null;
}
rangeOfInterpolatedStringTokensContainingTokenIndex(index) {
let bestRange = null;
for (const [startType, endType] of [
["DSTRING_START" /* DSTRING_START */, "DSTRING_END" /* DSTRING_END */],
["TDSTRING_START" /* TDSTRING_START */, "TDSTRING_END" /* TDSTRING_END */],
["HEREGEXP_START" /* HEREGEXP_START */, "HEREGEXP_END" /* HEREGEXP_END */]
]) {
const range = this.rangeOfMatchingTokensContainingTokenIndex(startType, endType, index);
if (bestRange === null || bestRange === void 0 || range !== null && range !== void 0 && range[0].distance(range[1]) < bestRange[0].distance(bestRange[1])) {
bestRange = range;
}
}
return bestRange;
}
rangeOfMatchingTokensContainingTokenIndex(startType, endType, index) {
this._validateIndex(index);
const token = this.tokenAtIndex(index);
if (!token) {
return null;
}
switch (token.type) {
case startType: {
let level = 0;
const start = index;
const endIndex = this.indexOfTokenMatchingPredicate((token2) => {
if (token2.type === startType) {
level += 1;
} else if (token2.type === endType) {
level -= 1;
if (level === 0) {
return true;
}
}
return false;
}, start);
if (!endIndex) {
return null;
} else {
const rangeEnd = endIndex.next();
if (!rangeEnd) {
return null;
}
return [start, rangeEnd];
}
}
case endType: {
let level = 0;
const endIndex = index;
const startIndex = this.lastIndexOfTokenMatchingPredicate((token2) => {
if (token2.type === startType) {
level -= 1;
if (level === 0) {
return true;
}
} else if (token2.type === endType) {
level += 1;
}
return false;
}, endIndex);
if (!startIndex) {
return null;
} else {
const rangeEnd = endIndex.next();
if (!rangeEnd) {
return null;
} else {
return [startIndex, rangeEnd];
}
}
}
default: {
let level = 0;
const startIndex = this.lastIndexOfTokenMatchingPredicate((token2) => {
if (token2.type === startType) {
if (level === 0) {
return true;
}
level -= 1;
} else if (token2.type === endType) {
level += 1;
}
return false;
}, index);
if (!startIndex) {
return null;
} else {
return this.rangeOfMatchingTokensContainingTokenIndex(startType, endType, startIndex);
}
}
}
}
indexOfTokenContainingSourceIndex(index) {
this._validateSourceIndex(index);
return this._indexBySourceIndex[index] || null;
}
indexOfTokenNearSourceIndex(index) {
this._validateSourceIndex(index);
for (let searchIndex = index; searchIndex >= 0; searchIndex--) {
const tokenIndex = this._indexBySourceIndex[searchIndex];
if (tokenIndex) {
return tokenIndex;
}
}
return this.startIndex;
}
indexOfTokenStartingAtSourceIndex(index) {
this._validateSourceIndex(index);
return this._indexByStartSourceIndex[index] || null;
}
indexOfTokenEndingAtSourceIndex(index) {
this._validateSourceIndex(index);
return this._indexByEndSourceIndex[index] || null;
}
indexOfTokenMatchingPredicate(predicate, start = null, end = null) {
if (!start) {
start = this.startIndex;
}
if (!end) {
end = this.endIndex;
}
this._validateIndex(start);
this._validateIndex(end);
for (let i = start; i && i !== end; i = i.next()) {
const token = this.tokenAtIndex(i);
if (!token) {
break;
} else if (predicate(token)) {
return i;
}
}
return null;
}
lastIndexOfTokenMatchingPredicate(predicate, start = null, end = null) {
if (!start) {
start = this.endIndex.previous();
if (!start) {
return null;
}
}
this._validateIndex(start);
if (end) {
this._validateIndex(end);
}
let i = start;
do {
pending.unshift.apply(pending, calculateNormalStringPadding_1.default(source, pending));
pending.unshift.apply(pending, calculateTripleQuotedStringPadding_1.default(source, pending));
pending.unshift.apply(pending, calculateHeregexpPadding_1.default(source, pending));
pending.unshift.apply(pending, combinedLocationsForNegatedOperators(pending, source));
location = pending.shift();
if (previousLocation && previousLocation.type !== SourceType_1.default.SPACE) {
tokens.push(new SourceToken_1.default(previousLocation.type, previousLocation.index, location.index));
const token = this.tokenAtIndex(i);
if (!token) {
break;
} else if (predicate(token)) {
return i;
} else {
i = i.previous();
}
} while (i && i !== end);
return null;
}
[Symbol.iterator]() {
let index = this.startIndex;
const { endIndex } = this;
return {
next() {
if (index === endIndex) {
return { done: true, value: void 0 };
} else {
const result = { done: false, value: this.tokenAtIndex(index) };
const nextIndex = index.next();
if (!nextIndex) {
throw new Error(`unexpected null index before the end index`);
}
index = nextIndex;
return result;
}
previousLocation = location;
} while (location.type !== SourceType_1.default.EOF);
return new SourceTokenList_1.default(tokens);
}
};
}
_validateTokens(tokens) {
for (let i = 0; i < tokens.length - 1; i++) {
if (tokens[i].end > tokens[i + 1].start) {
throw new Error(`Tokens not in order. Expected ${JSON.stringify(tokens[i])} before ${JSON.stringify(tokens[i + 1])}`);
}
}
}
_validateIndex(index) {
if (!index) {
throw new Error(`unexpected 'null' index, perhaps you forgot to check the result of 'indexOfTokenContainingSourceIndex'?`);
}
if (typeof index === "number") {
throw new Error(`to get a token at index ${index}, use list.tokenAtIndex(list.startIndex.advance(${index}))`);
}
if (index["_sourceTokenList"] !== this) {
throw new Error("cannot get token in one list using an index from another");
}
}
_validateSourceIndex(index) {
if (typeof index !== "number") {
throw new Error(`expected source index to be a number, got: ${index}`);
}
}
_getIndex(index) {
let cached = this._indexCache[index];
if (!cached) {
cached = new SourceTokenListIndex(this, index);
this._indexCache[index] = cached;
}
return cached;
}
toArray() {
return this._tokens.slice();
}
};
// src/utils/assertNever.ts
function assertNever(value, message = `unexpected value: ${value}`) {
throw new Error(message);
}
exports.default = lex;
function combinedLocationsForNegatedOperators(stream, source) {
if (!stream.hasNext(SourceType_1.default.OPERATOR)) {
return [];
// src/utils/BufferedStream.ts
var BufferedStream = class {
constructor(stream2) {
this.pending = [];
this._getNextLocation = stream2;
}
shift() {
return this.pending.shift() || this._getNextLocation();
}
hasNext(...types) {
const locationsToPutBack = [];
const result = types.every((type) => {
const next = this.shift();
locationsToPutBack.push(next);
return next.type === type;
});
this.unshift(...locationsToPutBack);
return result;
}
peek() {
const result = this.shift();
this.unshift(result);
return result;
}
unshift(...tokens) {
this.pending.unshift(...tokens);
}
};
// src/utils/PaddingTracker.ts
var PaddingTracker = class {
constructor(source, stream2, endType) {
this.fragments = [];
this._originalLocations = [];
let interpolationLevel = 0;
let location;
do {
location = stream2.shift();
this._originalLocations.push(location);
if (interpolationLevel === 0 && location.type === "STRING_CONTENT" /* STRING_CONTENT */) {
const start = location.index;
const end = stream2.peek().index;
const content = source.slice(start, end);
const index = this.fragments.length;
this.fragments.push(new TrackedFragment(content, start, end, index));
} else if (location.type === "INTERPOLATION_START" /* INTERPOLATION_START */) {
interpolationLevel += 1;
} else if (location.type === "INTERPOLATION_END" /* INTERPOLATION_END */) {
interpolationLevel -= 1;
}
} while (interpolationLevel > 0 || location.type !== endType);
}
computeSourceLocations() {
const resultLocations = [];
let rangeIndex = 0;
for (const location of this._originalLocations) {
const currentRange = this.fragments[rangeIndex];
if (location.type === "STRING_CONTENT" /* STRING_CONTENT */ && currentRange && location.index === currentRange.start) {
resultLocations.push(...currentRange.computeSourceLocations());
rangeIndex++;
} else {
resultLocations.push(location);
}
}
var locationsToRestore = [];
function shift() {
var location = stream.shift();
locationsToRestore.push(location);
return location;
if (rangeIndex !== this.fragments.length) {
throw new Error("Expected ranges to correspond to original locations.");
}
var not = shift();
var space = shift();
var text = source.slice(not.index, space.index);
var operator;
if (text === 'not') {
if (space.type === SourceType_1.default.SPACE) {
// It is a space, so the operator is at the next location.
operator = shift();
return resultLocations;
}
};
var TrackedFragment = class {
constructor(content, start, end, index) {
this.content = content;
this.start = start;
this.end = end;
this.index = index;
this._paddingRanges = [];
this._lineSeparators = [];
}
markPadding(startIndex, endIndex) {
this._paddingRanges.push({ start: startIndex, end: endIndex });
}
markLineSeparator(index) {
this._lineSeparators.push(index);
}
computeSourceLocations() {
if (this.start === this.end) {
return [new SourceLocation("STRING_CONTENT" /* STRING_CONTENT */, this.start)];
}
const eventsByIndex = [];
for (let i = 0; i < this.end - this.start + 1; i++) {
eventsByIndex.push([]);
}
for (const range of this._paddingRanges) {
eventsByIndex[range.start].push("START_PADDING");
eventsByIndex[range.end].push("END_PADDING");
}
for (const separatorIndex of this._lineSeparators) {
eventsByIndex[separatorIndex].push("START_LINE_SEPARATOR");
eventsByIndex[separatorIndex + 1].push("END_LINE_SEPARATOR");
}
const resultLocations = [];
let lastSourceType = null;
let paddingDepth = 0;
let lineSeparatorDepth = 0;
for (let sourceIndex = this.start; sourceIndex < this.end; sourceIndex++) {
for (const event of eventsByIndex[sourceIndex - this.start]) {
if (event === "START_PADDING") {
paddingDepth += 1;
} else if (event === "END_PADDING") {
paddingDepth -= 1;
} else if (event === "START_LINE_SEPARATOR") {
lineSeparatorDepth += 1;
} else if (event === "END_LINE_SEPARATOR") {
lineSeparatorDepth -= 1;
}
else {
// `not` must be followed by a space, so this isn't a match.
return locationsToRestore;
}
if (paddingDepth < 0 || lineSeparatorDepth < 0 || paddingDepth > 0 && lineSeparatorDepth > 0) {
throw new Error(`Illegal padding state: paddingDepth: ${paddingDepth}, lineSeparatorDepth: ${lineSeparatorDepth}`);
}
let sourceType;
if (paddingDepth > 0) {
sourceType = "STRING_PADDING" /* STRING_PADDING */;
} else if (lineSeparatorDepth > 0) {
sourceType = "STRING_LINE_SEPARATOR" /* STRING_LINE_SEPARATOR */;
} else {
sourceType = "STRING_CONTENT" /* STRING_CONTENT */;
}
if (sourceType !== lastSourceType) {
resultLocations.push(new SourceLocation(sourceType, sourceIndex));
lastSourceType = sourceType;
}
}
return resultLocations;
}
};
// src/utils/calculateHeregexpPadding.ts
function calculateHeregexpPadding(source, stream2) {
if (!stream2.hasNext("HEREGEXP_START" /* HEREGEXP_START */)) {
return [];
}
const paddingTracker = new PaddingTracker(source, stream2, "HEREGEXP_END" /* HEREGEXP_END */);
for (const fragment of paddingTracker.fragments) {
const content = fragment.content;
let pos = 0;
while (pos < content.length) {
if (/\s/.test(content[pos])) {
if (isWhitespaceEscaped(content, pos)) {
fragment.markPadding(pos - 1, pos);
} else {
fragment.markPadding(pos, pos + 1);
}
pos++;
} else if (content[pos] === "#" && (pos === 0 || /\s/.test(content[pos - 1]))) {
const commentStart = pos;
while (pos < content.length && content[pos] !== "\n") {
pos++;
}
fragment.markPadding(commentStart, pos);
} else {
pos++;
}
}
else if (text === '!') {
if (space.type === SourceType_1.default.SPACE) {
// It is a space, so the operator is at the next location.
operator = shift();
}
return paddingTracker.computeSourceLocations();
}
function isWhitespaceEscaped(content, whitespacePos) {
let prevPos = whitespacePos - 1;
while (prevPos >= 0 && content[prevPos] === "\\") {
prevPos--;
}
return (whitespacePos - prevPos) % 2 === 0;
}
// src/utils/isNewlineEscaped.ts
function isNewlineEscaped(content, newlinePos) {
let numSeenBackslashes = 0;
let prevPos = newlinePos - 1;
while (prevPos >= 0) {
const char = content[prevPos];
if (numSeenBackslashes === 0 && (char === " " || char === " ")) {
prevPos--;
} else if (char === "\\") {
numSeenBackslashes++;
prevPos--;
} else {
break;
}
}
return numSeenBackslashes % 2 === 1;
}
// src/utils/calculateNormalStringPadding.ts
function calculateNormalStringPadding(source, stream2) {
let paddingTracker;
if (stream2.hasNext("SSTRING_START" /* SSTRING_START */)) {
paddingTracker = new PaddingTracker(source, stream2, "SSTRING_END" /* SSTRING_END */);
} else if (stream2.hasNext("DSTRING_START" /* DSTRING_START */)) {
paddingTracker = new PaddingTracker(source, stream2, "DSTRING_END" /* DSTRING_END */);
} else {
return [];
}
for (let fragmentIndex = 0; fragmentIndex < paddingTracker.fragments.length; fragmentIndex++) {
const fragment = paddingTracker.fragments[fragmentIndex];
const content = fragment.content;
let lastNonWhitespace = -1;
let pos = 0;
while (pos < content.length) {
if (content[pos] === "\n") {
const startIndex = lastNonWhitespace + 1;
fragment.markPadding(lastNonWhitespace + 1, pos);
const newlinePos = pos;
pos++;
while (pos < content.length && " \n".includes(content[pos]) || content.slice(pos, pos + 2) === "\\\n") {
pos++;
}
else {
// The optional space is missing, so the next thing must be the operator.
operator = space;
const endIndex = pos;
if (isNewlineEscaped(content, newlinePos)) {
const backslashPos = content.lastIndexOf("\\", newlinePos);
fragment.markPadding(backslashPos, endIndex);
} else if (fragmentIndex === 0 && startIndex === 0 || fragmentIndex === paddingTracker.fragments.length - 1 && endIndex === content.length) {
fragment.markPadding(startIndex, endIndex);
} else {
fragment.markPadding(startIndex, newlinePos);
fragment.markLineSeparator(newlinePos);
fragment.markPadding(newlinePos + 1, endIndex);
}
lastNonWhitespace = pos;
} else {
if (content[pos] !== " " && content[pos] !== " ") {
lastNonWhitespace = pos;
}
pos++;
}
}
else {
// Not a negation token, so put them back.
return locationsToRestore;
}
return paddingTracker.computeSourceLocations();
}
// src/utils/calculateTripleQuotedStringPadding.ts
function calculateTripleQuotedStringPadding(source, stream2) {
let paddingTracker;
if (stream2.hasNext("TSSTRING_START" /* TSSTRING_START */)) {
paddingTracker = new PaddingTracker(source, stream2, "TSSTRING_END" /* TSSTRING_END */);
} else if (stream2.hasNext("TDSTRING_START" /* TDSTRING_START */)) {
paddingTracker = new PaddingTracker(source, stream2, "TDSTRING_END" /* TDSTRING_END */);
} else {
return [];
}
const firstFragment = paddingTracker.fragments[0];
const firstContent = firstFragment.content;
const lastFragment = paddingTracker.fragments[paddingTracker.fragments.length - 1];
const lastContent = lastFragment.content;
const sharedIndent = getIndentForFragments(paddingTracker.fragments);
const firstContentLines = splitUnescapedNewlines(firstContent);
if (firstContentLines.length > 1 && isWhitespace(firstContentLines[0])) {
firstFragment.markPadding(0, firstContentLines[0].length + 1);
}
if (!shouldSkipRemovingLastLine(paddingTracker)) {
const lastLines = splitUnescapedNewlines(lastContent);
if (lastLines.length > 1) {
const lastLine = lastLines[lastLines.length - 1];
if (isWhitespace(lastLine)) {
lastFragment.markPadding(lastFragment.content.length - lastLine.length - 1, lastFragment.content.length);
}
}
var next = stream.peek();
var op = source.slice(operator.index, next.index);
switch (op) {
case 'in':
case 'of':
return [new SourceLocation_1.default(SourceType_1.default.RELATION, not.index)];
case 'instanceof':
return [new SourceLocation_1.default(SourceType_1.default.OPERATOR, not.index)];
}
for (const fragment of paddingTracker.fragments) {
for (let i = 0; i < fragment.content.length; i++) {
if (fragment.content[i] === "\n" && isNewlineEscaped(fragment.content, i)) {
const backslashPos = fragment.content.lastIndexOf("\\", i);
let paddingEnd = i;
while (paddingEnd < fragment.content.length && " \n".includes(fragment.content[paddingEnd])) {
paddingEnd++;
}
fragment.markPadding(backslashPos, paddingEnd);
}
const isStartOfLine = i > 0 && fragment.content[i - 1] === "\n";
if (isStartOfLine) {
const paddingStart = i;
const paddingEnd = i + sharedIndent.length;
if (fragment.content.slice(paddingStart, paddingEnd) === sharedIndent) {
fragment.markPadding(paddingStart, paddingEnd);
}
}
}
// Doesn't match, so put them back.
}
return paddingTracker.computeSourceLocations();
}
function getIndentForFragments(fragments) {
let hasSeenLine = false;
let smallestIndent = null;
for (const fragment of fragments) {
const lines = fragment.content.split("\n");
for (let i = 1; i < lines.length; i++) {
const line = lines[i];
const indent = getLineIndent(line);
if (!hasSeenLine && indent.length === 0 && line.length > 0) {
return "";
}
hasSeenLine = true;
const isFullLine = i < lines.length - 1 || fragment.index === fragments.length - 1;
if (indent.length === 0 || isFullLine && indent === line) {
continue;
}
if (smallestIndent === null || indent.length < smallestIndent.length) {
smallestIndent = indent;
}
}
}
if (smallestIndent === null) {
return "";
}
return smallestIndent;
}
function shouldSkipRemovingLastLine(paddingTracker) {
if (paddingTracker.fragments.length !== 1) {
return false;
}
const lines = paddingTracker.fragments[0].content.split("\n");
return lines.length === 2 && isWhitespace(lines[0]) && isWhitespace(lines[1]);
}
function getLineIndent(line) {
const match = /[^\n\S]*/.exec(line);
if (match) {
return match[0];
} else {
return "";
}
}
function splitUnescapedNewlines(str) {
const lines = [""];
let numBackslashes = 0;
let isEatingWhitespace = false;
for (const chr of str) {
if (chr === "\n" && numBackslashes % 2 === 0 && !isEatingWhitespace) {
lines.push("");
} else {
if (chr === "\n" && numBackslashes % 2 === 1) {
isEatingWhitespace = true;
}
if (chr === "\\") {
numBackslashes++;
} else {
numBackslashes = 0;
}
if (!" \n".includes(chr)) {
isEatingWhitespace = false;
}
lines[lines.length - 1] += chr;
}
}
return lines;
}
function isWhitespace(line) {
for (let i = 0; i < line.length; i++) {
if (!" \n".includes(line[i]) && !(line[i] === "\\" && line[i + 1] === "\n")) {
return false;
}
}
return true;
}
// src/lex.ts
var DEFAULT_OPTIONS = {
useCS2: false
};
function lex(source, options = DEFAULT_OPTIONS) {
let location;
let previousLocation;
const tokens = [];
const pending = new BufferedStream(stream(source, 0, options));
do {
pending.unshift(...calculateNormalStringPadding(source, pending));
pending.unshift(...calculateTripleQuotedStringPadding(source, pending));
pending.unshift(...calculateHeregexpPadding(source, pending));
pending.unshift(...combinedLocationsForNegatedOperators(pending, source));
location = pending.shift();
if (previousLocation && previousLocation.type !== "SPACE" /* SPACE */) {
tokens.push(new SourceToken(previousLocation.type, previousLocation.index, location.index));
}
previousLocation = location;
} while (location.type !== "EOF" /* EOF */);
return new SourceTokenList(tokens);
}
function combinedLocationsForNegatedOperators(stream2, source) {
if (!stream2.hasNext("OPERATOR" /* OPERATOR */)) {
return [];
}
const locationsToRestore = [];
function shift() {
const location = stream2.shift();
locationsToRestore.push(location);
return location;
}
const not = shift();
const space = shift();
const text = source.slice(not.index, space.index);
let operator;
if (text === "not") {
if (space.type === "SPACE" /* SPACE */) {
operator = shift();
} else {
return locationsToRestore;
}
} else if (text === "!") {
if (space.type === "SPACE" /* SPACE */) {
operator = shift();
} else {
operator = space;
}
} else {
return locationsToRestore;
}
const next = stream2.peek();
const op = source.slice(operator.index, next.index);
switch (op) {
case "in":
case "of":
return [new SourceLocation("RELATION" /* RELATION */, not.index)];
case "instanceof":
return [new SourceLocation("OPERATOR" /* OPERATOR */, not.index)];
}
return locationsToRestore;
}
var REGEXP_FLAGS = ['i', 'g', 'm', 'u', 'y'];
/**
* Borrowed, with tweaks, from CoffeeScript's lexer.coffee.
*/
var REGEXP_FLAGS = ["i", "g", "m", "u", "y"];
var STRING = [
SourceType_1.default.SSTRING_END,
SourceType_1.default.DSTRING_END,
SourceType_1.default.TSSTRING_END,
SourceType_1.default.TDSTRING_END
"SSTRING_END" /* SSTRING_END */,
"DSTRING_END" /* DSTRING_END */,
"TSSTRING_END" /* TSSTRING_END */,
"TDSTRING_END" /* TDSTRING_END */
];
var CALLABLE = [
SourceType_1.default.IDENTIFIER,
SourceType_1.default.CALL_END,
SourceType_1.default.RPAREN,
SourceType_1.default.RBRACKET,
SourceType_1.default.EXISTENCE,
SourceType_1.default.AT,
SourceType_1.default.THIS,
SourceType_1.default.SUPER
"IDENTIFIER" /* IDENTIFIER */,
"CALL_END" /* CALL_END */,
"RPAREN" /* RPAREN */,
"RBRACKET" /* RBRACKET */,
"EXISTENCE" /* EXISTENCE */,
"AT" /* AT */,
"THIS" /* THIS */,
"SUPER" /* SUPER */
];
var INDEXABLE = CALLABLE.concat(__spreadArrays([
SourceType_1.default.NUMBER
], STRING, [
SourceType_1.default.REGEXP,
SourceType_1.default.HEREGEXP_END,
SourceType_1.default.BOOL,
SourceType_1.default.NULL,
SourceType_1.default.UNDEFINED,
SourceType_1.default.RBRACE,
SourceType_1.default.PROTO
]));
var INDEXABLE = CALLABLE.concat([
"NUMBER" /* NUMBER */,
...STRING,
"REGEXP" /* REGEXP */,
"HEREGEXP_END" /* HEREGEXP_END */,
"BOOL" /* BOOL */,
"NULL" /* NULL */,
"UNDEFINED" /* UNDEFINED */,
"RBRACE" /* RBRACE */,
"PROTO" /* PROTO */
]);
var NOT_REGEXP = INDEXABLE.concat([
SourceType_1.default.INCREMENT,
SourceType_1.default.DECREMENT
"INCREMENT" /* INCREMENT */,
"DECREMENT" /* DECREMENT */
]);
var IDENTIFIER_PATTERN = /^(?!\d)((?:(?!\s)[$\w\x7f-\uffff])+)/;
// Like identifier, but includes '-' and '.'.
var CSX_IDENTIFIER_PATTERN = /^(?!\d)((?:(?!\s)[.\-$\w\x7f-\uffff])+)/;

@@ -148,750 +910,653 @@ var NUMBER_PATTERN = /^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i;

var OPERATORS = [
// equality
'===',
'==',
'!==',
'!=',
// assignment
'=',
'+=',
'-=',
'/=',
'*=',
'%=',
'%%=',
'||=',
'&&=',
'^=',
'or=',
'and=',
'?=',
'|=',
'&=',
'~=',
'<<=',
'>>>=',
'>>=',
// increment/decrement
'++',
'--',
// math
'+',
'-',
'//',
'/',
'*',
'%',
'%%',
// logical
'||',
'&&',
'^',
'!',
// existence
'?',
// bitwise
'|',
'&',
'~',
'<<',
'>>>',
'>>',
// comparison
'<=',
'<',
'>=',
'>',
// prototype access
'::'
"===",
"==",
"!==",
"!=",
"=",
"+=",
"-=",
"/=",
"*=",
"%=",
"%%=",
"||=",
"&&=",
"^=",
"or=",
"and=",
"?=",
"|=",
"&=",
"~=",
"<<=",
">>>=",
">>=",
"++",
"--",
"+",
"-",
"//",
"/",
"*",
"%",
"%%",
"||",
"&&",
"^",
"!",
"?",
"|",
"&",
"~",
"<<",
">>>",
">>",
"<=",
"<",
">=",
">",
"::"
];
/**
* Provides a stream of source type change locations.
*/
function stream(source, index, options) {
if (index === void 0) { index = 0; }
if (options === void 0) { options = exports.DEFAULT_OPTIONS; }
var location = new SourceLocation_1.default(SourceType_1.default.NORMAL, index);
var contextStack = [];
var start = index;
var locations = [];
function currentContext() {
return contextStack[contextStack.length - 1] || null;
}
function currentContextType() {
var context = currentContext();
return context ? context.type : null;
}
return function step() {
var lastLocation = location;
var shouldStepAgain = false;
do {
start = index;
if (index >= source.length) {
setType(SourceType_1.default.EOF);
function stream(source, index = 0, options = DEFAULT_OPTIONS) {
let location = new SourceLocation("NORMAL" /* NORMAL */, index);
const contextStack = [];
let start = index;
const locations = [];
function currentContext() {
return contextStack[contextStack.length - 1] || null;
}
function currentContextType() {
const context = currentContext();
return context ? context.type : null;
}
return function step() {
const lastLocation = location;
let shouldStepAgain = false;
do {
start = index;
if (index >= source.length) {
setType("EOF" /* EOF */);
}
switch (location.type) {
case "NORMAL" /* NORMAL */:
case "SPACE" /* SPACE */:
case "IDENTIFIER" /* IDENTIFIER */:
case "DOT" /* DOT */:
case "NUMBER" /* NUMBER */:
case "OPERATOR" /* OPERATOR */:
case "INCREMENT" /* INCREMENT */:
case "DECREMENT" /* DECREMENT */:
case "COMMA" /* COMMA */:
case "LPAREN" /* LPAREN */:
case "RPAREN" /* RPAREN */:
case "CALL_START" /* CALL_START */:
case "CALL_END" /* CALL_END */:
case "NEW" /* NEW */:
case "LBRACE" /* LBRACE */:
case "RBRACE" /* RBRACE */:
case "LBRACKET" /* LBRACKET */:
case "RBRACKET" /* RBRACKET */:
case "NEWLINE" /* NEWLINE */:
case "COLON" /* COLON */:
case "FUNCTION" /* FUNCTION */:
case "THIS" /* THIS */:
case "AT" /* AT */:
case "SEMICOLON" /* SEMICOLON */:
case "IF" /* IF */:
case "ELSE" /* ELSE */:
case "THEN" /* THEN */:
case "FOR" /* FOR */:
case "OWN" /* OWN */:
case "WHILE" /* WHILE */:
case "BOOL" /* BOOL */:
case "NULL" /* NULL */:
case "UNDEFINED" /* UNDEFINED */:
case "REGEXP" /* REGEXP */:
case "SSTRING_END" /* SSTRING_END */:
case "DSTRING_END" /* DSTRING_END */:
case "TSSTRING_END" /* TSSTRING_END */:
case "TDSTRING_END" /* TDSTRING_END */:
case "INTERPOLATION_START" /* INTERPOLATION_START */:
case "SUPER" /* SUPER */:
case "TRY" /* TRY */:
case "CATCH" /* CATCH */:
case "FINALLY" /* FINALLY */:
case "SWITCH" /* SWITCH */:
case "WHEN" /* WHEN */:
case "BREAK" /* BREAK */:
case "CONTINUE" /* CONTINUE */:
case "EXISTENCE" /* EXISTENCE */:
case "CLASS" /* CLASS */:
case "PROTO" /* PROTO */:
case "RANGE" /* RANGE */:
case "DELETE" /* DELETE */:
case "RETURN" /* RETURN */:
case "RELATION" /* RELATION */:
case "LOOP" /* LOOP */:
case "DO" /* DO */:
case "YIELD" /* YIELD */:
case "YIELDFROM" /* YIELDFROM */:
case "THROW" /* THROW */:
case "EXTENDS" /* EXTENDS */:
case "IMPORT" /* IMPORT */:
case "EXPORT" /* EXPORT */:
case "DEFAULT" /* DEFAULT */:
case "CSX_OPEN_TAG_START" /* CSX_OPEN_TAG_START */:
case "CSX_CLOSE_TAG_START" /* CSX_CLOSE_TAG_START */:
case "CONTINUATION" /* CONTINUATION */:
if (consume(SPACE_PATTERN)) {
setType("SPACE" /* SPACE */);
} else if (consume("\n")) {
setType("NEWLINE" /* NEWLINE */);
} else if (consume("...") || consume("..")) {
setType("RANGE" /* RANGE */);
} else if (consume(NUMBER_PATTERN)) {
setType("NUMBER" /* NUMBER */);
} else if (consume(".")) {
setType("DOT" /* DOT */);
} else if (consume('"""')) {
contextStack.push({
type: "STRING" /* STRING */,
allowComments: false,
allowInterpolations: true,
endingDelimiter: '"""',
endSourceType: "TDSTRING_END" /* TDSTRING_END */
});
setType("TDSTRING_START" /* TDSTRING_START */);
} else if (consume('"')) {
contextStack.push({
type: "STRING" /* STRING */,
allowComments: false,
allowInterpolations: true,
endingDelimiter: '"',
endSourceType: "DSTRING_END" /* DSTRING_END */
});
setType("DSTRING_START" /* DSTRING_START */);
} else if (consume("'''")) {
contextStack.push({
type: "STRING" /* STRING */,
allowComments: false,
allowInterpolations: false,
endingDelimiter: "'''",
endSourceType: "TSSTRING_END" /* TSSTRING_END */
});
setType("TSSTRING_START" /* TSSTRING_START */);
} else if (consume("'")) {
contextStack.push({
type: "STRING" /* STRING */,
allowComments: false,
allowInterpolations: false,
endingDelimiter: "'",
endSourceType: "SSTRING_END" /* SSTRING_END */
});
setType("SSTRING_START" /* SSTRING_START */);
} else if (consume(/^###[^#]/)) {
setType("HERECOMMENT" /* HERECOMMENT */);
} else if (consume("#")) {
setType("COMMENT" /* COMMENT */);
} else if (consume("///")) {
contextStack.push({
type: "STRING" /* STRING */,
allowComments: true,
allowInterpolations: true,
endingDelimiter: "///",
endSourceType: "HEREGEXP_END" /* HEREGEXP_END */
});
setType("HEREGEXP_START" /* HEREGEXP_START */);
} else if (consume("(")) {
if (CALLABLE.indexOf(location.type) >= 0) {
contextStack.push({
type: "PAREN" /* PAREN */,
sourceType: "CALL_START" /* CALL_START */
});
setType("CALL_START" /* CALL_START */);
} else {
contextStack.push({
type: "PAREN" /* PAREN */,
sourceType: "LPAREN" /* LPAREN */
});
setType("LPAREN" /* LPAREN */);
}
switch (location.type) {
case SourceType_1.default.NORMAL:
case SourceType_1.default.SPACE:
case SourceType_1.default.IDENTIFIER:
case SourceType_1.default.DOT:
case SourceType_1.default.NUMBER:
case SourceType_1.default.OPERATOR:
case SourceType_1.default.INCREMENT:
case SourceType_1.default.DECREMENT:
case SourceType_1.default.COMMA:
case SourceType_1.default.LPAREN:
case SourceType_1.default.RPAREN:
case SourceType_1.default.CALL_START:
case SourceType_1.default.CALL_END:
case SourceType_1.default.NEW:
case SourceType_1.default.LBRACE:
case SourceType_1.default.RBRACE:
case SourceType_1.default.LBRACKET:
case SourceType_1.default.RBRACKET:
case SourceType_1.default.NEWLINE:
case SourceType_1.default.COLON:
case SourceType_1.default.FUNCTION:
case SourceType_1.default.THIS:
case SourceType_1.default.AT:
case SourceType_1.default.SEMICOLON:
case SourceType_1.default.IF:
case SourceType_1.default.ELSE:
case SourceType_1.default.THEN:
case SourceType_1.default.FOR:
case SourceType_1.default.OWN:
case SourceType_1.default.WHILE:
case SourceType_1.default.BOOL:
case SourceType_1.default.NULL:
case SourceType_1.default.UNDEFINED:
case SourceType_1.default.REGEXP:
case SourceType_1.default.SSTRING_END:
case SourceType_1.default.DSTRING_END:
case SourceType_1.default.TSSTRING_END:
case SourceType_1.default.TDSTRING_END:
case SourceType_1.default.INTERPOLATION_START:
case SourceType_1.default.SUPER:
case SourceType_1.default.TRY:
case SourceType_1.default.CATCH:
case SourceType_1.default.FINALLY:
case SourceType_1.default.SWITCH:
case SourceType_1.default.WHEN:
case SourceType_1.default.BREAK:
case SourceType_1.default.CONTINUE:
case SourceType_1.default.EXISTENCE:
case SourceType_1.default.CLASS:
case SourceType_1.default.PROTO:
case SourceType_1.default.RANGE:
case SourceType_1.default.DELETE:
case SourceType_1.default.RETURN:
case SourceType_1.default.RELATION:
case SourceType_1.default.LOOP:
case SourceType_1.default.DO:
case SourceType_1.default.YIELD:
case SourceType_1.default.YIELDFROM:
case SourceType_1.default.THROW:
case SourceType_1.default.EXTENDS:
case SourceType_1.default.IMPORT:
case SourceType_1.default.EXPORT:
case SourceType_1.default.DEFAULT:
case SourceType_1.default.CSX_OPEN_TAG_START:
case SourceType_1.default.CSX_CLOSE_TAG_START:
case SourceType_1.default.CONTINUATION:
if (consume(SPACE_PATTERN)) {
setType(SourceType_1.default.SPACE);
}
else if (consume('\n')) {
setType(SourceType_1.default.NEWLINE);
}
else if (consume('...') || consume('..')) {
setType(SourceType_1.default.RANGE);
}
else if (consume(NUMBER_PATTERN)) {
setType(SourceType_1.default.NUMBER);
}
else if (consume('.')) {
setType(SourceType_1.default.DOT);
}
else if (consume('"""')) {
contextStack.push({
type: ContextType.STRING,
allowComments: false,
allowInterpolations: true,
endingDelimiter: '"""',
endSourceType: SourceType_1.default.TDSTRING_END
});
setType(SourceType_1.default.TDSTRING_START);
}
else if (consume('"')) {
contextStack.push({
type: ContextType.STRING,
allowComments: false,
allowInterpolations: true,
endingDelimiter: '"',
endSourceType: SourceType_1.default.DSTRING_END
});
setType(SourceType_1.default.DSTRING_START);
}
else if (consume("'''")) {
contextStack.push({
type: ContextType.STRING,
allowComments: false,
allowInterpolations: false,
endingDelimiter: "'''",
endSourceType: SourceType_1.default.TSSTRING_END
});
setType(SourceType_1.default.TSSTRING_START);
}
else if (consume("'")) {
contextStack.push({
type: ContextType.STRING,
allowComments: false,
allowInterpolations: false,
endingDelimiter: "'",
endSourceType: SourceType_1.default.SSTRING_END
});
setType(SourceType_1.default.SSTRING_START);
}
else if (consume(/^###[^#]/)) {
setType(SourceType_1.default.HERECOMMENT);
}
else if (consume('#')) {
setType(SourceType_1.default.COMMENT);
}
else if (consume('///')) {
contextStack.push({
type: ContextType.STRING,
allowComments: true,
allowInterpolations: true,
endingDelimiter: '///',
endSourceType: SourceType_1.default.HEREGEXP_END
});
setType(SourceType_1.default.HEREGEXP_START);
}
else if (consume('(')) {
if (CALLABLE.indexOf(location.type) >= 0) {
contextStack.push({
type: ContextType.PAREN,
sourceType: SourceType_1.default.CALL_START
});
setType(SourceType_1.default.CALL_START);
}
else {
contextStack.push({
type: ContextType.PAREN,
sourceType: SourceType_1.default.LPAREN
});
setType(SourceType_1.default.LPAREN);
}
}
else if (consume(')')) {
var context = contextStack.pop();
if (!context || context.type !== ContextType.PAREN) {
throw new Error("unexpected ')' at " + start);
}
var sourceType = context.sourceType;
switch (sourceType) {
case SourceType_1.default.LPAREN:
setType(SourceType_1.default.RPAREN);
break;
case SourceType_1.default.CALL_START:
setType(SourceType_1.default.CALL_END);
break;
default:
throw new Error("unexpected token type for '(' matching ')' at " + start + ": " + (sourceType ? sourceType.toString() : '??'));
}
}
else if (consume('[')) {
setType(SourceType_1.default.LBRACKET);
}
else if (consume(']')) {
setType(SourceType_1.default.RBRACKET);
}
else if (consume('{')) {
contextStack.push({ type: ContextType.BRACE });
setType(SourceType_1.default.LBRACE);
}
else if (consume('}')) {
if (currentContextType() === ContextType.INTERPOLATION) {
popInterpolation();
}
else if (currentContextType() === ContextType.BRACE) {
contextStack.pop();
setType(SourceType_1.default.RBRACE);
}
else {
throw new Error("Unexpected context type: " + currentContextType());
}
}
else if (consumeCSXOpenTagStart()) {
contextStack.push({ type: ContextType.CSX_OPEN_TAG });
setType(SourceType_1.default.CSX_OPEN_TAG_START);
}
else if (currentContextType() === ContextType.CSX_OPEN_TAG &&
consume('>')) {
contextStack.pop();
setType(SourceType_1.default.CSX_OPEN_TAG_END);
}
else if (currentContextType() === ContextType.CSX_OPEN_TAG &&
consume('/>')) {
contextStack.pop();
setType(SourceType_1.default.CSX_SELF_CLOSING_TAG_END);
}
else if (currentContextType() === ContextType.CSX_CLOSE_TAG &&
consume('>')) {
contextStack.pop();
setType(SourceType_1.default.CSX_CLOSE_TAG_END);
}
else if (consumeAny(['->', '=>'])) {
setType(SourceType_1.default.FUNCTION);
}
else if (consumeRegexp()) {
setType(SourceType_1.default.REGEXP);
}
else if (consume('::')) {
setType(SourceType_1.default.PROTO);
}
else if (consume(':')) {
setType(SourceType_1.default.COLON);
}
else if (consume(',')) {
setType(SourceType_1.default.COMMA);
}
else if (consume('@')) {
setType(SourceType_1.default.AT);
}
else if (consume(';')) {
setType(SourceType_1.default.SEMICOLON);
}
else if (consume('```')) {
setType(SourceType_1.default.HEREJS);
}
else if (consume('`')) {
setType(SourceType_1.default.JS);
}
else if (consumeAny(OPERATORS)) {
if (consumed() === '?') {
setType(SourceType_1.default.EXISTENCE);
}
else if (consumed() === '++') {
setType(SourceType_1.default.INCREMENT);
}
else if (consumed() === '--') {
setType(SourceType_1.default.DECREMENT);
}
else {
setType(SourceType_1.default.OPERATOR);
}
}
else if (consume(YIELDFROM_PATTERN)) {
setType(SourceType_1.default.YIELDFROM);
}
else if (currentContextType() === ContextType.CSX_OPEN_TAG &&
consume(CSX_IDENTIFIER_PATTERN)) {
setType(SourceType_1.default.IDENTIFIER);
}
else if (consume(IDENTIFIER_PATTERN)) {
var prevLocationIndex = locations.length - 1;
while (prevLocationIndex > 0 &&
(locations[prevLocationIndex].type === SourceType_1.default.NEWLINE ||
locations[prevLocationIndex].type === SourceType_1.default.SPACE)) {
prevLocationIndex--;
}
var prev = locations[prevLocationIndex];
var nextIsColon = match(/^\s*:/);
if (nextIsColon ||
(prev &&
// i.e. `a.b` or `a.\nb`
(prev.type === SourceType_1.default.DOT ||
// i.e. `a::b` or `a::\nb`
prev.type === SourceType_1.default.PROTO ||
// i.e. `@a` (but not `@\na`, since that's `this\na`–see #175)
(prev.type === SourceType_1.default.AT &&
prevLocationIndex === locations.length - 1)))) {
setType(SourceType_1.default.IDENTIFIER);
}
else {
switch (consumed()) {
case 'if':
case 'unless':
setType(SourceType_1.default.IF);
break;
case 'else':
setType(SourceType_1.default.ELSE);
break;
case 'return':
setType(SourceType_1.default.RETURN);
break;
case 'for':
setType(SourceType_1.default.FOR);
break;
case 'own':
setType(SourceType_1.default.OWN);
break;
case 'while':
case 'until':
setType(SourceType_1.default.WHILE);
break;
case 'loop':
setType(SourceType_1.default.LOOP);
break;
case 'then':
setType(SourceType_1.default.THEN);
break;
case 'switch':
setType(SourceType_1.default.SWITCH);
break;
case 'when':
setType(SourceType_1.default.WHEN);
break;
case 'null':
setType(SourceType_1.default.NULL);
break;
case 'undefined':
setType(SourceType_1.default.UNDEFINED);
break;
case 'this':
setType(SourceType_1.default.THIS);
break;
case 'new':
setType(SourceType_1.default.NEW);
break;
case 'super':
setType(SourceType_1.default.SUPER);
break;
case 'true':
case 'false':
case 'yes':
case 'no':
case 'on':
case 'off':
setType(SourceType_1.default.BOOL);
break;
case 'and':
case 'or':
case 'not':
case 'is':
case 'isnt':
case 'instanceof':
setType(SourceType_1.default.OPERATOR);
break;
case 'class':
setType(SourceType_1.default.CLASS);
break;
case 'break':
setType(SourceType_1.default.BREAK);
break;
case 'continue':
setType(SourceType_1.default.CONTINUE);
break;
case 'try':
setType(SourceType_1.default.TRY);
break;
case 'catch':
setType(SourceType_1.default.CATCH);
break;
case 'finally':
setType(SourceType_1.default.FINALLY);
break;
case 'delete':
setType(SourceType_1.default.DELETE);
break;
case 'in':
case 'of':
setType(SourceType_1.default.RELATION);
break;
case 'do':
setType(SourceType_1.default.DO);
break;
case 'yield':
setType(SourceType_1.default.YIELD);
break;
case 'throw':
setType(SourceType_1.default.THROW);
break;
case 'extends':
setType(SourceType_1.default.EXTENDS);
break;
case 'import':
setType(SourceType_1.default.IMPORT);
break;
case 'export':
setType(SourceType_1.default.EXPORT);
break;
case 'default':
setType(SourceType_1.default.DEFAULT);
break;
default:
setType(SourceType_1.default.IDENTIFIER);
}
}
}
else if (consume('\\')) {
setType(SourceType_1.default.CONTINUATION);
}
else {
setType(SourceType_1.default.UNKNOWN);
}
break;
case SourceType_1.default.SSTRING_START:
case SourceType_1.default.DSTRING_START:
case SourceType_1.default.TSSTRING_START:
case SourceType_1.default.TDSTRING_START:
case SourceType_1.default.HEREGEXP_START:
setType(SourceType_1.default.STRING_CONTENT);
break;
case SourceType_1.default.STRING_CONTENT: {
var context = currentContext();
if (!context || context.type !== ContextType.STRING) {
throw new Error('Unexpected STRING_CONTENT without anything on the string stack.');
}
var allowComments = context.allowComments, allowInterpolations = context.allowInterpolations, endingDelimiter = context.endingDelimiter, endSourceType = context.endSourceType;
if (consume('\\')) {
index++;
}
else if (consume(endingDelimiter)) {
contextStack.pop();
setType(endSourceType);
}
else if (allowInterpolations && consume('#{')) {
pushInterpolation();
}
else if (options.useCS2 &&
allowComments &&
source[index - 1].match(/\s/) &&
match('#') &&
!match('#{')) {
setType(SourceType_1.default.HEREGEXP_COMMENT);
}
else {
index++;
}
break;
}
case SourceType_1.default.COMMENT:
if (consume('\n')) {
setType(SourceType_1.default.NEWLINE);
}
else {
index++;
}
break;
case SourceType_1.default.HERECOMMENT:
if (consume('###')) {
setType(SourceType_1.default.NORMAL);
}
else {
index++;
}
break;
case SourceType_1.default.HEREGEXP_COMMENT:
if (consume('\n')) {
setType(SourceType_1.default.STRING_CONTENT);
}
else {
index++;
}
break;
case SourceType_1.default.INTERPOLATION_END: {
var context = contextStack.pop();
if (!context || context.type !== ContextType.INTERPOLATION) {
throw new Error("found interpolation end without any interpolation start");
}
setType(context.interpolationType);
break;
}
case SourceType_1.default.HEREGEXP_END:
while (consumeAny(REGEXP_FLAGS)) {
// condition has side-effect
}
setType(SourceType_1.default.NORMAL);
break;
case SourceType_1.default.JS:
if (consume('\\')) {
index++;
}
else if (consume('`')) {
setType(SourceType_1.default.NORMAL);
}
else {
index++;
}
break;
case SourceType_1.default.HEREJS:
if (consume('\\')) {
index++;
}
else if (consume('```')) {
setType(SourceType_1.default.NORMAL);
}
else {
index++;
}
break;
case SourceType_1.default.CSX_OPEN_TAG_END:
setType(SourceType_1.default.CSX_BODY);
contextStack.push({ type: ContextType.CSX_BODY });
break;
case SourceType_1.default.CSX_BODY: {
if (consume('</')) {
contextStack.pop();
setType(SourceType_1.default.CSX_CLOSE_TAG_START);
contextStack.push({ type: ContextType.CSX_CLOSE_TAG });
}
else if (consumeCSXOpenTagStart()) {
setType(SourceType_1.default.CSX_OPEN_TAG_START);
contextStack.push({ type: ContextType.CSX_OPEN_TAG });
}
else if (consume('{')) {
pushInterpolation();
}
else {
index++;
}
break;
}
case SourceType_1.default.CSX_SELF_CLOSING_TAG_END:
case SourceType_1.default.CSX_CLOSE_TAG_END:
if (currentContextType() === ContextType.CSX_BODY) {
setType(SourceType_1.default.CSX_BODY);
}
else {
setType(SourceType_1.default.NORMAL);
}
break;
case SourceType_1.default.EOF: {
var context = currentContext();
if (context !== null) {
throw new Error("unexpected EOF while in context " + context.type);
}
break;
}
case SourceType_1.default.UNKNOWN:
// Jump to the end.
index = source.length;
break;
default:
throw new Error("unknown source type at offset " + location.index + ": " + SourceType_1.default[location.type]);
} else if (consume(")")) {
const context = contextStack.pop();
if (!context || context.type !== "PAREN" /* PAREN */) {
throw new Error(`unexpected ')' at ${start}`);
}
shouldStepAgain =
// Don't report on going back to "normal" source code.
location.type === SourceType_1.default.NORMAL ||
// Don't report if nothing has changed, unless we're at the end.
(location === lastLocation && location.type !== SourceType_1.default.EOF);
} while (shouldStepAgain);
locations.push(location);
return location;
};
function consumeAny(strings) {
return strings.some(function (string) { return consume(string); });
}
function consume(value) {
var matchData = match(value);
if (matchData) {
index += matchData[0].length;
return true;
}
else {
return false;
}
}
function consumeRegexp() {
var matchData = match(REGEXP_PATTERN);
if (!matchData) {
return false;
}
var regex = matchData[0], closed = matchData[2];
var prev = locations[locations.length - 1];
if (prev) {
var spaced = false;
if (prev.type === SourceType_1.default.SPACE) {
spaced = true;
prev = locations[locations.length - 2];
const { sourceType } = context;
switch (sourceType) {
case "LPAREN" /* LPAREN */:
setType("RPAREN" /* RPAREN */);
break;
case "CALL_START" /* CALL_START */:
setType("CALL_END" /* CALL_END */);
break;
default:
throw new Error(`unexpected token type for '(' matching ')' at ${start}: ${sourceType ? sourceType.toString() : "??"}`);
}
if (spaced && CALLABLE.indexOf(prev.type) >= 0) {
if (!closed || /^\/=?\s/.test(regex)) {
return false;
}
} else if (consume("[")) {
setType("LBRACKET" /* LBRACKET */);
} else if (consume("]")) {
setType("RBRACKET" /* RBRACKET */);
} else if (consume("{")) {
contextStack.push({ type: "BRACE" /* BRACE */ });
setType("LBRACE" /* LBRACE */);
} else if (consume("}")) {
if (currentContextType() === "INTERPOLATION" /* INTERPOLATION */) {
popInterpolation();
} else if (currentContextType() === "BRACE" /* BRACE */) {
contextStack.pop();
setType("RBRACE" /* RBRACE */);
} else {
throw new Error(`Unexpected context type: ${currentContextType()}`);
}
else if (NOT_REGEXP.indexOf(prev.type) >= 0) {
return false;
} else if (consumeCSXOpenTagStart()) {
contextStack.push({ type: "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ });
setType("CSX_OPEN_TAG_START" /* CSX_OPEN_TAG_START */);
} else if (currentContextType() === "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ && consume(">")) {
contextStack.pop();
setType("CSX_OPEN_TAG_END" /* CSX_OPEN_TAG_END */);
} else if (currentContextType() === "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ && consume("/>")) {
contextStack.pop();
setType("CSX_SELF_CLOSING_TAG_END" /* CSX_SELF_CLOSING_TAG_END */);
} else if (currentContextType() === "CSX_CLOSE_TAG" /* CSX_CLOSE_TAG */ && consume(">")) {
contextStack.pop();
setType("CSX_CLOSE_TAG_END" /* CSX_CLOSE_TAG_END */);
} else if (consumeAny(["->", "=>"])) {
setType("FUNCTION" /* FUNCTION */);
} else if (consumeRegexp()) {
setType("REGEXP" /* REGEXP */);
} else if (consume("::")) {
setType("PROTO" /* PROTO */);
} else if (consume(":")) {
setType("COLON" /* COLON */);
} else if (consume(",")) {
setType("COMMA" /* COMMA */);
} else if (consume("@")) {
setType("AT" /* AT */);
} else if (consume(";")) {
setType("SEMICOLON" /* SEMICOLON */);
} else if (consume("```")) {
setType("HEREJS" /* HEREJS */);
} else if (consume("`")) {
setType("JS" /* JS */);
} else if (consumeAny(OPERATORS)) {
if (consumed() === "?") {
setType("EXISTENCE" /* EXISTENCE */);
} else if (consumed() === "++") {
setType("INCREMENT" /* INCREMENT */);
} else if (consumed() === "--") {
setType("DECREMENT" /* DECREMENT */);
} else {
setType("OPERATOR" /* OPERATOR */);
}
} else if (consume(YIELDFROM_PATTERN)) {
setType("YIELDFROM" /* YIELDFROM */);
} else if (currentContextType() === "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ && consume(CSX_IDENTIFIER_PATTERN)) {
setType("IDENTIFIER" /* IDENTIFIER */);
} else if (consume(IDENTIFIER_PATTERN)) {
let prevLocationIndex = locations.length - 1;
while (prevLocationIndex > 0 && (locations[prevLocationIndex].type === "NEWLINE" /* NEWLINE */ || locations[prevLocationIndex].type === "SPACE" /* SPACE */)) {
prevLocationIndex--;
}
const prev = locations[prevLocationIndex];
const nextIsColon = match(/^\s*:/);
if (nextIsColon || prev && (prev.type === "DOT" /* DOT */ || prev.type === "PROTO" /* PROTO */ || prev.type === "AT" /* AT */ && prevLocationIndex === locations.length - 1)) {
setType("IDENTIFIER" /* IDENTIFIER */);
} else {
switch (consumed()) {
case "if":
case "unless":
setType("IF" /* IF */);
break;
case "else":
setType("ELSE" /* ELSE */);
break;
case "return":
setType("RETURN" /* RETURN */);
break;
case "for":
setType("FOR" /* FOR */);
break;
case "own":
setType("OWN" /* OWN */);
break;
case "while":
case "until":
setType("WHILE" /* WHILE */);
break;
case "loop":
setType("LOOP" /* LOOP */);
break;
case "then":
setType("THEN" /* THEN */);
break;
case "switch":
setType("SWITCH" /* SWITCH */);
break;
case "when":
setType("WHEN" /* WHEN */);
break;
case "null":
setType("NULL" /* NULL */);
break;
case "undefined":
setType("UNDEFINED" /* UNDEFINED */);
break;
case "this":
setType("THIS" /* THIS */);
break;
case "new":
setType("NEW" /* NEW */);
break;
case "super":
setType("SUPER" /* SUPER */);
break;
case "true":
case "false":
case "yes":
case "no":
case "on":
case "off":
setType("BOOL" /* BOOL */);
break;
case "and":
case "or":
case "not":
case "is":
case "isnt":
case "instanceof":
setType("OPERATOR" /* OPERATOR */);
break;
case "class":
setType("CLASS" /* CLASS */);
break;
case "break":
setType("BREAK" /* BREAK */);
break;
case "continue":
setType("CONTINUE" /* CONTINUE */);
break;
case "try":
setType("TRY" /* TRY */);
break;
case "catch":
setType("CATCH" /* CATCH */);
break;
case "finally":
setType("FINALLY" /* FINALLY */);
break;
case "delete":
setType("DELETE" /* DELETE */);
break;
case "in":
case "of":
setType("RELATION" /* RELATION */);
break;
case "do":
setType("DO" /* DO */);
break;
case "yield":
setType("YIELD" /* YIELD */);
break;
case "throw":
setType("THROW" /* THROW */);
break;
case "extends":
setType("EXTENDS" /* EXTENDS */);
break;
case "import":
setType("IMPORT" /* IMPORT */);
break;
case "export":
setType("EXPORT" /* EXPORT */);
break;
case "default":
setType("DEFAULT" /* DEFAULT */);
break;
default:
setType("IDENTIFIER" /* IDENTIFIER */);
}
}
} else if (consume("\\")) {
setType("CONTINUATION" /* CONTINUATION */);
} else {
setType("UNKNOWN" /* UNKNOWN */);
}
break;
case "SSTRING_START" /* SSTRING_START */:
case "DSTRING_START" /* DSTRING_START */:
case "TSSTRING_START" /* TSSTRING_START */:
case "TDSTRING_START" /* TDSTRING_START */:
case "HEREGEXP_START" /* HEREGEXP_START */:
setType("STRING_CONTENT" /* STRING_CONTENT */);
break;
case "STRING_CONTENT" /* STRING_CONTENT */: {
const context = currentContext();
if (!context || context.type !== "STRING" /* STRING */) {
throw new Error("Unexpected STRING_CONTENT without anything on the string stack.");
}
const {
allowComments,
allowInterpolations,
endingDelimiter,
endSourceType
} = context;
if (consume("\\")) {
index++;
} else if (consume(endingDelimiter)) {
contextStack.pop();
setType(endSourceType);
} else if (allowInterpolations && consume("#{")) {
pushInterpolation();
} else if (options.useCS2 && allowComments && source[index - 1].match(/\s/) && match("#") && !match("#{")) {
setType("HEREGEXP_COMMENT" /* HEREGEXP_COMMENT */);
} else {
index++;
}
break;
}
if (!closed) {
throw new Error('missing / (unclosed regex)');
case "COMMENT" /* COMMENT */:
if (consume("\n")) {
setType("NEWLINE" /* NEWLINE */);
} else {
index++;
}
break;
case "HERECOMMENT" /* HERECOMMENT */:
if (consume("###")) {
setType("NORMAL" /* NORMAL */);
} else {
index++;
}
break;
case "HEREGEXP_COMMENT" /* HEREGEXP_COMMENT */:
if (consume("\n")) {
setType("STRING_CONTENT" /* STRING_CONTENT */);
} else {
index++;
}
break;
case "INTERPOLATION_END" /* INTERPOLATION_END */: {
const context = contextStack.pop();
if (!context || context.type !== "INTERPOLATION" /* INTERPOLATION */) {
throw new Error(`found interpolation end without any interpolation start`);
}
setType(context.interpolationType);
break;
}
index += regex.length;
while (consumeAny(REGEXP_FLAGS)) {
// condition has side-effect
case "HEREGEXP_END" /* HEREGEXP_END */:
while (consumeAny(REGEXP_FLAGS)) {
}
setType("NORMAL" /* NORMAL */);
break;
case "JS" /* JS */:
if (consume("\\")) {
index++;
} else if (consume("`")) {
setType("NORMAL" /* NORMAL */);
} else {
index++;
}
break;
case "HEREJS" /* HEREJS */:
if (consume("\\")) {
index++;
} else if (consume("```")) {
setType("NORMAL" /* NORMAL */);
} else {
index++;
}
break;
case "CSX_OPEN_TAG_END" /* CSX_OPEN_TAG_END */:
setType("CSX_BODY" /* CSX_BODY */);
contextStack.push({ type: "CSX_BODY" /* CSX_BODY */ });
break;
case "CSX_BODY" /* CSX_BODY */: {
if (consume("</")) {
contextStack.pop();
setType("CSX_CLOSE_TAG_START" /* CSX_CLOSE_TAG_START */);
contextStack.push({ type: "CSX_CLOSE_TAG" /* CSX_CLOSE_TAG */ });
} else if (consumeCSXOpenTagStart()) {
setType("CSX_OPEN_TAG_START" /* CSX_OPEN_TAG_START */);
contextStack.push({ type: "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ });
} else if (consume("{")) {
pushInterpolation();
} else {
index++;
}
break;
}
return true;
case "CSX_SELF_CLOSING_TAG_END" /* CSX_SELF_CLOSING_TAG_END */:
case "CSX_CLOSE_TAG_END" /* CSX_CLOSE_TAG_END */:
if (currentContextType() === "CSX_BODY" /* CSX_BODY */) {
setType("CSX_BODY" /* CSX_BODY */);
} else {
setType("NORMAL" /* NORMAL */);
}
break;
case "EOF" /* EOF */: {
const context = currentContext();
if (context !== null) {
throw new Error(`unexpected EOF while in context ${context.type}`);
}
break;
}
case "UNKNOWN" /* UNKNOWN */:
index = source.length;
break;
case "STRING_LINE_SEPARATOR" /* STRING_LINE_SEPARATOR */:
case "STRING_PADDING" /* STRING_PADDING */:
throw new Error(`unexpected source type at offset ${location.index}: ${location.type}`);
default:
assertNever(location.type, `unexpected source type at offset ${location.index}: ${location.type}`);
}
shouldStepAgain = location.type === "NORMAL" /* NORMAL */ || location === lastLocation && location.type !== "EOF" /* EOF */;
} while (shouldStepAgain);
locations.push(location);
return location;
};
function consumeAny(strings) {
return strings.some((string) => consume(string));
}
function consume(value) {
const matchData = match(value);
if (matchData) {
index += matchData[0].length;
return true;
} else {
return false;
}
/**
* CSX starts are identified by a less-than sign followed by a CSX identifier
* or `<>` token (no space allowed after the less-than).
*
* We also bail in cases like `a<b`: if we're not already in a CSX context,
* the less-than needs to be preceded by a space or a token other than identifier,
* close-paren, close-bracket, or number.
*/
function consumeCSXOpenTagStart() {
if (!match('<')) {
return false;
}
function consumeRegexp() {
const matchData = match(REGEXP_PATTERN);
if (!matchData) {
return false;
}
const [regex, , closed] = matchData;
let prev = locations[locations.length - 1];
if (prev) {
let spaced = false;
if (prev.type === "SPACE" /* SPACE */) {
spaced = true;
prev = locations[locations.length - 2];
}
if (spaced && CALLABLE.indexOf(prev.type) >= 0) {
if (!closed || /^\/=?\s/.test(regex)) {
return false;
}
if (source[index + 1] !== '>' &&
!source.slice(index + 1).match(CSX_IDENTIFIER_PATTERN)) {
return false;
}
var contextType = currentContextType();
if (contextType !== ContextType.CSX_BODY &&
contextType !== ContextType.CSX_OPEN_TAG &&
[
SourceType_1.default.IDENTIFIER,
SourceType_1.default.RPAREN,
SourceType_1.default.RBRACKET,
SourceType_1.default.NUMBER
].includes(location.type)) {
return false;
}
consume('<');
return true;
} else if (NOT_REGEXP.indexOf(prev.type) >= 0) {
return false;
}
}
function consumed() {
return source.slice(start, index);
if (!closed) {
throw new Error("missing / (unclosed regex)");
}
function setType(newType) {
location = new SourceLocation_1.default(newType, start);
index += regex.length;
while (consumeAny(REGEXP_FLAGS)) {
}
function match(value) {
if (typeof value === 'string') {
var matches = source.slice(index, index + value.length) === value;
return matches ? [value] : null;
}
else {
return source.slice(index).match(value);
}
return true;
}
function consumeCSXOpenTagStart() {
if (!match("<")) {
return false;
}
function pushInterpolation() {
contextStack.push({
type: ContextType.INTERPOLATION,
interpolationType: location.type
});
setType(SourceType_1.default.INTERPOLATION_START);
if (source[index + 1] !== ">" && !source.slice(index + 1).match(CSX_IDENTIFIER_PATTERN)) {
return false;
}
function popInterpolation() {
if (currentContextType() !== ContextType.INTERPOLATION) {
throw new Error("unexpected '}' found in string at " + index + ": " + JSON.stringify(source));
}
setType(SourceType_1.default.INTERPOLATION_END);
const contextType = currentContextType();
if (contextType !== "CSX_BODY" /* CSX_BODY */ && contextType !== "CSX_OPEN_TAG" /* CSX_OPEN_TAG */ && [
"IDENTIFIER" /* IDENTIFIER */,
"RPAREN" /* RPAREN */,
"RBRACKET" /* RBRACKET */,
"NUMBER" /* NUMBER */
].includes(location.type)) {
return false;
}
consume("<");
return true;
}
function consumed() {
return source.slice(start, index);
}
function setType(newType) {
location = new SourceLocation(newType, start);
}
function match(value) {
if (typeof value === "string") {
const matches = source.slice(index, index + value.length) === value;
return matches ? [value] : null;
} else {
return source.slice(index).match(value);
}
}
function pushInterpolation() {
contextStack.push({
type: "INTERPOLATION" /* INTERPOLATION */,
interpolationType: location.type
});
setType("INTERPOLATION_START" /* INTERPOLATION_START */);
}
function popInterpolation() {
if (currentContextType() !== "INTERPOLATION" /* INTERPOLATION */) {
throw new Error(`unexpected '}' found in string at ${index}: ${JSON.stringify(source)}`);
}
setType("INTERPOLATION_END" /* INTERPOLATION_END */);
}
}
exports.stream = stream;
function consumeStream(lexer) {
var result = [];
var location;
do {
location = lexer();
result.push(location);
} while (location.type !== SourceType_1.default.EOF);
return result;
const result = [];
let location;
do {
location = lexer();
result.push(location);
} while (location.type !== "EOF" /* EOF */);
return result;
}
exports.consumeStream = consumeStream;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
DEFAULT_OPTIONS,
SourceType,
consumeStream,
lex,
stream
});
{
"name": "coffee-lex",
"version": "9.1.5",
"version": "9.2.0",
"description": "Stupid lexer for CoffeeScript.",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"scripts": {
"reformat": "yarn lint --fix",
"lint": "eslint 'src/**/*.ts'",
"lint:fix": "yarn lint --fix",
"pretest": "yarn lint",
"test": "jest",
"prepare": "script/build.ts"
},
"repository": {
"type": "git",
"url": "https://github.com/decaffeinate/coffee-lex.git"
},
"keywords": [

@@ -26,37 +11,75 @@ "coffee",

],
"homepage": "https://github.com/decaffeinate/coffee-lex",
"bugs": {
"url": "https://github.com/decaffeinate/coffee-lex/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/decaffeinate/coffee-lex.git"
},
"license": "MIT",
"author": "Brian Donovan",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
},
"files": [
"dist"
],
"author": "Brian Donovan",
"license": "MIT",
"bugs": {
"url": "https://github.com/decaffeinate/coffee-lex/issues"
"scripts": {
"lint": "eslint 'src/**/*.ts'",
"lint:fix": "pnpm lint --fix",
"build": "tsup",
"prepublishOnly": "pnpm build",
"reformat": "pnpm lint --fix",
"pretest": "pnpm lint",
"test": "jest",
"test:ci": "jest --ci"
},
"homepage": "https://github.com/decaffeinate/coffee-lex",
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{ts,md,json}": [
"prettier --write"
],
"package.json": [
"sort-package-json"
]
},
"devDependencies": {
"@microsoft/node-core-library": "^3.7.1",
"@types/fs-extra": "^8.0.0",
"@types/globby": "^9.1.0",
"@types/jest": "^24.0.18",
"@types/node": "^12.0.8",
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"@types/jest": "^28.1.1",
"@types/node": "14",
"@typescript-eslint/eslint-plugin": "^5.27.1",
"@typescript-eslint/parser": "^5.27.1",
"decaffeinate-coffeescript": "1.12.7-patch.3",
"eslint": "^6.1.0",
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-jest": "^22.12.0",
"eslint-plugin-prettier": "^3.1.0",
"fs-extra": "^8.0.1",
"globby": "^10.0.0",
"jest": "^24.9.0",
"jest-junit": "^8.0.0",
"prettier": "^1.15.2",
"prettier-check": "2.0.0",
"ts-jest": "^24.0.0",
"ts-node": "^8.0.2",
"typescript": "^3.5.2"
"eslint": "^8.17.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest": "^26.5.3",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^8.0.1",
"jest": "^28.1.1",
"lint-staged": "^13.0.0",
"prettier": "^2.6.2",
"sort-package-json": "^1.57.0",
"ts-jest": "^28.0.4",
"tsup": "^6.1.0",
"typescript": "^4.7.3"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"release": {
"branches": [
"main"
]
}
}

@@ -19,9 +19,9 @@ # coffee-lex [![Build Status](https://circleci.com/gh/decaffeinate/coffee-lex/tree/master.svg?style=svg)](https://circleci.com/gh/decaffeinate/coffee-lex/tree/master) [![package version](https://badge.fury.io/js/coffee-lex.svg)](https://badge.fury.io/js/coffee-lex) [![Greenkeeper badge](https://badges.greenkeeper.io/decaffeinate/coffee-lex.svg)](https://greenkeeper.io/)

```js
import lex, { SourceType } from 'coffee-lex';
import lex, { SourceType } from 'coffee-lex'
let source = 'a?(b: c)';
let tokens = lex(source);
const source = 'a?(b: c)'
const tokens = lex(source)
// Print tokens along with their source.
tokens.forEach(token =>
tokens.forEach((token) =>
console.log(

@@ -32,3 +32,3 @@ SourceType[token.type],

)
);
)
// IDENTIFIER "a" 0→1

@@ -49,5 +49,5 @@ // EXISTENCE "?" 1→2

let source = 'a?(b: c)';
let step = stream(source);
let location;
const source = 'a?(b: c)';
const step = stream(source);
const location;

@@ -88,3 +88,3 @@ do {

```js
[
;[
[

@@ -94,19 +94,40 @@ 'STRING_START',

{ first_line: 0, first_column: 0, last_line: 0, last_column: 0 },
(origin: ['STRING', null, [Object]])
(origin: ['STRING', null, [Object]]),
],
['STRING', '"a"', { first_line: 0, first_column: 0, last_line: 0, last_column: 1 }],
[
'STRING',
'"a"',
{ first_line: 0, first_column: 0, last_line: 0, last_column: 1 },
],
['+', '+', { first_line: 0, first_column: 3, last_line: 0, last_column: 3 }],
['(', '(', { first_line: 0, first_column: 3, last_line: 0, last_column: 3 }],
['IDENTIFIER', 'b', { first_line: 0, first_column: 4, last_line: 0, last_column: 4 }, (variable: true)],
[
'IDENTIFIER',
'b',
{ first_line: 0, first_column: 4, last_line: 0, last_column: 4 },
(variable: true),
],
[
')',
')',
{ first_line: 0, first_column: 5, last_line: 0, last_column: 5 },
(origin: ['', 'end of interpolation', [Object]])
(origin: ['', 'end of interpolation', [Object]]),
],
['+', '+', { first_line: 0, first_column: 6, last_line: 0, last_column: 6 }],
['STRING', '"c"', { first_line: 0, first_column: 6, last_line: 0, last_column: 7 }],
['STRING_END', ')', { first_line: 0, first_column: 7, last_line: 0, last_column: 7 }],
['TERMINATOR', '\n', { first_line: 0, first_column: 8, last_line: 0, last_column: 8 }]
];
[
'STRING',
'"c"',
{ first_line: 0, first_column: 6, last_line: 0, last_column: 7 },
],
[
'STRING_END',
')',
{ first_line: 0, first_column: 7, last_line: 0, last_column: 7 },
],
[
'TERMINATOR',
'\n',
{ first_line: 0, first_column: 8, last_line: 0, last_column: 8 },
],
]
```

@@ -113,0 +134,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc