mirror of
https://github.com/crazy-max/ghaction-upx.git
synced 2024-11-23 10:56:09 -07:00
2689 lines
81 KiB
JavaScript
2689 lines
81 KiB
JavaScript
|
"use strict";
|
|||
|
|
|||
|
Object.defineProperty(exports, "__esModule", {
|
|||
|
value: true
|
|||
|
});
|
|||
|
exports.default = void 0;
|
|||
|
|
|||
|
var _types = require("../tokenizer/types");
|
|||
|
|
|||
|
var N = _interopRequireWildcard(require("../types"));
|
|||
|
|
|||
|
var _context = require("../tokenizer/context");
|
|||
|
|
|||
|
var _identifier = require("../util/identifier");
|
|||
|
|
|||
|
var _scopeflags = require("../util/scopeflags");
|
|||
|
|
|||
|
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
|||
|
|
|||
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|||
|
|
|||
|
const reservedTypes = new Set(["_", "any", "bool", "boolean", "empty", "extends", "false", "interface", "mixed", "null", "number", "static", "string", "true", "typeof", "void"]);
|
|||
|
|
|||
|
function isEsModuleType(bodyElement) {
|
|||
|
return bodyElement.type === "DeclareExportAllDeclaration" || bodyElement.type === "DeclareExportDeclaration" && (!bodyElement.declaration || bodyElement.declaration.type !== "TypeAlias" && bodyElement.declaration.type !== "InterfaceDeclaration");
|
|||
|
}
|
|||
|
|
|||
|
function hasTypeImportKind(node) {
|
|||
|
return node.importKind === "type" || node.importKind === "typeof";
|
|||
|
}
|
|||
|
|
|||
|
function isMaybeDefaultImport(state) {
|
|||
|
return (state.type === _types.types.name || !!state.type.keyword) && state.value !== "from";
|
|||
|
}
|
|||
|
|
|||
|
const exportSuggestions = {
|
|||
|
const: "declare export var",
|
|||
|
let: "declare export var",
|
|||
|
type: "export type",
|
|||
|
interface: "export interface"
|
|||
|
};
|
|||
|
|
|||
|
function partition(list, test) {
|
|||
|
const list1 = [];
|
|||
|
const list2 = [];
|
|||
|
|
|||
|
for (let i = 0; i < list.length; i++) {
|
|||
|
(test(list[i], i, list) ? list1 : list2).push(list[i]);
|
|||
|
}
|
|||
|
|
|||
|
return [list1, list2];
|
|||
|
}
|
|||
|
|
|||
|
const FLOW_PRAGMA_REGEX = /\*?\s*@((?:no)?flow)\b/;
|
|||
|
|
|||
|
var _default = superClass => class extends superClass {
|
|||
|
constructor(options, input) {
|
|||
|
super(options, input);
|
|||
|
this.flowPragma = undefined;
|
|||
|
}
|
|||
|
|
|||
|
shouldParseTypes() {
|
|||
|
return this.getPluginOption("flow", "all") || this.flowPragma === "flow";
|
|||
|
}
|
|||
|
|
|||
|
shouldParseEnums() {
|
|||
|
return !!this.getPluginOption("flow", "enums");
|
|||
|
}
|
|||
|
|
|||
|
finishToken(type, val) {
|
|||
|
if (type !== _types.types.string && type !== _types.types.semi && type !== _types.types.interpreterDirective) {
|
|||
|
if (this.flowPragma === undefined) {
|
|||
|
this.flowPragma = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return super.finishToken(type, val);
|
|||
|
}
|
|||
|
|
|||
|
addComment(comment) {
|
|||
|
if (this.flowPragma === undefined) {
|
|||
|
const matches = FLOW_PRAGMA_REGEX.exec(comment.value);
|
|||
|
|
|||
|
if (!matches) {} else if (matches[1] === "flow") {
|
|||
|
this.flowPragma = "flow";
|
|||
|
} else if (matches[1] === "noflow") {
|
|||
|
this.flowPragma = "noflow";
|
|||
|
} else {
|
|||
|
throw new Error("Unexpected flow pragma");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return super.addComment(comment);
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeInitialiser(tok) {
|
|||
|
const oldInType = this.state.inType;
|
|||
|
this.state.inType = true;
|
|||
|
this.expect(tok || _types.types.colon);
|
|||
|
const type = this.flowParseType();
|
|||
|
this.state.inType = oldInType;
|
|||
|
return type;
|
|||
|
}
|
|||
|
|
|||
|
flowParsePredicate() {
|
|||
|
const node = this.startNode();
|
|||
|
const moduloLoc = this.state.startLoc;
|
|||
|
const moduloPos = this.state.start;
|
|||
|
this.expect(_types.types.modulo);
|
|||
|
const checksLoc = this.state.startLoc;
|
|||
|
this.expectContextual("checks");
|
|||
|
|
|||
|
if (moduloLoc.line !== checksLoc.line || moduloLoc.column !== checksLoc.column - 1) {
|
|||
|
this.raise(moduloPos, "Spaces between ´%´ and ´checks´ are not allowed here.");
|
|||
|
}
|
|||
|
|
|||
|
if (this.eat(_types.types.parenL)) {
|
|||
|
node.value = this.parseExpression();
|
|||
|
this.expect(_types.types.parenR);
|
|||
|
return this.finishNode(node, "DeclaredPredicate");
|
|||
|
} else {
|
|||
|
return this.finishNode(node, "InferredPredicate");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeAndPredicateInitialiser() {
|
|||
|
const oldInType = this.state.inType;
|
|||
|
this.state.inType = true;
|
|||
|
this.expect(_types.types.colon);
|
|||
|
let type = null;
|
|||
|
let predicate = null;
|
|||
|
|
|||
|
if (this.match(_types.types.modulo)) {
|
|||
|
this.state.inType = oldInType;
|
|||
|
predicate = this.flowParsePredicate();
|
|||
|
} else {
|
|||
|
type = this.flowParseType();
|
|||
|
this.state.inType = oldInType;
|
|||
|
|
|||
|
if (this.match(_types.types.modulo)) {
|
|||
|
predicate = this.flowParsePredicate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return [type, predicate];
|
|||
|
}
|
|||
|
|
|||
|
flowParseDeclareClass(node) {
|
|||
|
this.next();
|
|||
|
this.flowParseInterfaceish(node, true);
|
|||
|
return this.finishNode(node, "DeclareClass");
|
|||
|
}
|
|||
|
|
|||
|
flowParseDeclareFunction(node) {
|
|||
|
this.next();
|
|||
|
const id = node.id = this.parseIdentifier();
|
|||
|
const typeNode = this.startNode();
|
|||
|
const typeContainer = this.startNode();
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
typeNode.typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
} else {
|
|||
|
typeNode.typeParameters = null;
|
|||
|
}
|
|||
|
|
|||
|
this.expect(_types.types.parenL);
|
|||
|
const tmp = this.flowParseFunctionTypeParams();
|
|||
|
typeNode.params = tmp.params;
|
|||
|
typeNode.rest = tmp.rest;
|
|||
|
this.expect(_types.types.parenR);
|
|||
|
[typeNode.returnType, node.predicate] = this.flowParseTypeAndPredicateInitialiser();
|
|||
|
typeContainer.typeAnnotation = this.finishNode(typeNode, "FunctionTypeAnnotation");
|
|||
|
id.typeAnnotation = this.finishNode(typeContainer, "TypeAnnotation");
|
|||
|
this.resetEndLocation(id);
|
|||
|
this.semicolon();
|
|||
|
return this.finishNode(node, "DeclareFunction");
|
|||
|
}
|
|||
|
|
|||
|
flowParseDeclare(node, insideModule) {
|
|||
|
if (this.match(_types.types._class)) {
|
|||
|
return this.flowParseDeclareClass(node);
|
|||
|
} else if (this.match(_types.types._function)) {
|
|||
|
return this.flowParseDeclareFunction(node);
|
|||
|
} else if (this.match(_types.types._var)) {
|
|||
|
return this.flowParseDeclareVariable(node);
|
|||
|
} else if (this.eatContextual("module")) {
|
|||
|
if (this.match(_types.types.dot)) {
|
|||
|
return this.flowParseDeclareModuleExports(node);
|
|||
|
} else {
|
|||
|
if (insideModule) {
|
|||
|
this.raise(this.state.lastTokStart, "`declare module` cannot be used inside another `declare module`");
|
|||
|
}
|
|||
|
|
|||
|
return this.flowParseDeclareModule(node);
|
|||
|
}
|
|||
|
} else if (this.isContextual("type")) {
|
|||
|
return this.flowParseDeclareTypeAlias(node);
|
|||
|
} else if (this.isContextual("opaque")) {
|
|||
|
return this.flowParseDeclareOpaqueType(node);
|
|||
|
} else if (this.isContextual("interface")) {
|
|||
|
return this.flowParseDeclareInterface(node);
|
|||
|
} else if (this.match(_types.types._export)) {
|
|||
|
return this.flowParseDeclareExportDeclaration(node, insideModule);
|
|||
|
} else {
|
|||
|
throw this.unexpected();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowParseDeclareVariable(node) {
|
|||
|
this.next();
|
|||
|
node.id = this.flowParseTypeAnnotatableIdentifier(true);
|
|||
|
this.scope.declareName(node.id.name, _scopeflags.BIND_VAR, node.id.start);
|
|||
|
this.semicolon();
|
|||
|
return this.finishNode(node, "DeclareVariable");
|
|||
|
}
|
|||
|
|
|||
|
flowParseDeclareModule(node) {
|
|||
|
this.scope.enter(_scopeflags.SCOPE_OTHER);
|
|||
|
|
|||
|
if (this.match(_types.types.string)) {
|
|||
|
node.id = this.parseExprAtom();
|
|||
|
} else {
|
|||
|
node.id = this.parseIdentifier();
|
|||
|
}
|
|||
|
|
|||
|
const bodyNode = node.body = this.startNode();
|
|||
|
const body = bodyNode.body = [];
|
|||
|
this.expect(_types.types.braceL);
|
|||
|
|
|||
|
while (!this.match(_types.types.braceR)) {
|
|||
|
let bodyNode = this.startNode();
|
|||
|
|
|||
|
if (this.match(_types.types._import)) {
|
|||
|
this.next();
|
|||
|
|
|||
|
if (!this.isContextual("type") && !this.match(_types.types._typeof)) {
|
|||
|
this.raise(this.state.lastTokStart, "Imports within a `declare module` body must always be `import type` or `import typeof`");
|
|||
|
}
|
|||
|
|
|||
|
this.parseImport(bodyNode);
|
|||
|
} else {
|
|||
|
this.expectContextual("declare", "Only declares and type imports are allowed inside declare module");
|
|||
|
bodyNode = this.flowParseDeclare(bodyNode, true);
|
|||
|
}
|
|||
|
|
|||
|
body.push(bodyNode);
|
|||
|
}
|
|||
|
|
|||
|
this.scope.exit();
|
|||
|
this.expect(_types.types.braceR);
|
|||
|
this.finishNode(bodyNode, "BlockStatement");
|
|||
|
let kind = null;
|
|||
|
let hasModuleExport = false;
|
|||
|
const errorMessage = "Found both `declare module.exports` and `declare export` in the same module. " + "Modules can only have 1 since they are either an ES module or they are a CommonJS module";
|
|||
|
body.forEach(bodyElement => {
|
|||
|
if (isEsModuleType(bodyElement)) {
|
|||
|
if (kind === "CommonJS") {
|
|||
|
this.raise(bodyElement.start, errorMessage);
|
|||
|
}
|
|||
|
|
|||
|
kind = "ES";
|
|||
|
} else if (bodyElement.type === "DeclareModuleExports") {
|
|||
|
if (hasModuleExport) {
|
|||
|
this.raise(bodyElement.start, "Duplicate `declare module.exports` statement");
|
|||
|
}
|
|||
|
|
|||
|
if (kind === "ES") this.raise(bodyElement.start, errorMessage);
|
|||
|
kind = "CommonJS";
|
|||
|
hasModuleExport = true;
|
|||
|
}
|
|||
|
});
|
|||
|
node.kind = kind || "CommonJS";
|
|||
|
return this.finishNode(node, "DeclareModule");
|
|||
|
}
|
|||
|
|
|||
|
flowParseDeclareExportDeclaration(node, insideModule) {
|
|||
|
this.expect(_types.types._export);
|
|||
|
|
|||
|
if (this.eat(_types.types._default)) {
|
|||
|
if (this.match(_types.types._function) || this.match(_types.types._class)) {
|
|||
|
node.declaration = this.flowParseDeclare(this.startNode());
|
|||
|
} else {
|
|||
|
node.declaration = this.flowParseType();
|
|||
|
this.semicolon();
|
|||
|
}
|
|||
|
|
|||
|
node.default = true;
|
|||
|
return this.finishNode(node, "DeclareExportDeclaration");
|
|||
|
} else {
|
|||
|
if (this.match(_types.types._const) || this.isLet() || (this.isContextual("type") || this.isContextual("interface")) && !insideModule) {
|
|||
|
const label = this.state.value;
|
|||
|
const suggestion = exportSuggestions[label];
|
|||
|
this.unexpected(this.state.start, `\`declare export ${label}\` is not supported. Use \`${suggestion}\` instead`);
|
|||
|
}
|
|||
|
|
|||
|
if (this.match(_types.types._var) || this.match(_types.types._function) || this.match(_types.types._class) || this.isContextual("opaque")) {
|
|||
|
node.declaration = this.flowParseDeclare(this.startNode());
|
|||
|
node.default = false;
|
|||
|
return this.finishNode(node, "DeclareExportDeclaration");
|
|||
|
} else if (this.match(_types.types.star) || this.match(_types.types.braceL) || this.isContextual("interface") || this.isContextual("type") || this.isContextual("opaque")) {
|
|||
|
node = this.parseExport(node);
|
|||
|
|
|||
|
if (node.type === "ExportNamedDeclaration") {
|
|||
|
node.type = "ExportDeclaration";
|
|||
|
node.default = false;
|
|||
|
delete node.exportKind;
|
|||
|
}
|
|||
|
|
|||
|
node.type = "Declare" + node.type;
|
|||
|
return node;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
throw this.unexpected();
|
|||
|
}
|
|||
|
|
|||
|
flowParseDeclareModuleExports(node) {
|
|||
|
this.next();
|
|||
|
this.expectContextual("exports");
|
|||
|
node.typeAnnotation = this.flowParseTypeAnnotation();
|
|||
|
this.semicolon();
|
|||
|
return this.finishNode(node, "DeclareModuleExports");
|
|||
|
}
|
|||
|
|
|||
|
flowParseDeclareTypeAlias(node) {
|
|||
|
this.next();
|
|||
|
this.flowParseTypeAlias(node);
|
|||
|
node.type = "DeclareTypeAlias";
|
|||
|
return node;
|
|||
|
}
|
|||
|
|
|||
|
flowParseDeclareOpaqueType(node) {
|
|||
|
this.next();
|
|||
|
this.flowParseOpaqueType(node, true);
|
|||
|
node.type = "DeclareOpaqueType";
|
|||
|
return node;
|
|||
|
}
|
|||
|
|
|||
|
flowParseDeclareInterface(node) {
|
|||
|
this.next();
|
|||
|
this.flowParseInterfaceish(node);
|
|||
|
return this.finishNode(node, "DeclareInterface");
|
|||
|
}
|
|||
|
|
|||
|
flowParseInterfaceish(node, isClass = false) {
|
|||
|
node.id = this.flowParseRestrictedIdentifier(!isClass, true);
|
|||
|
this.scope.declareName(node.id.name, isClass ? _scopeflags.BIND_FUNCTION : _scopeflags.BIND_LEXICAL, node.id.start);
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
} else {
|
|||
|
node.typeParameters = null;
|
|||
|
}
|
|||
|
|
|||
|
node.extends = [];
|
|||
|
node.implements = [];
|
|||
|
node.mixins = [];
|
|||
|
|
|||
|
if (this.eat(_types.types._extends)) {
|
|||
|
do {
|
|||
|
node.extends.push(this.flowParseInterfaceExtends());
|
|||
|
} while (!isClass && this.eat(_types.types.comma));
|
|||
|
}
|
|||
|
|
|||
|
if (this.isContextual("mixins")) {
|
|||
|
this.next();
|
|||
|
|
|||
|
do {
|
|||
|
node.mixins.push(this.flowParseInterfaceExtends());
|
|||
|
} while (this.eat(_types.types.comma));
|
|||
|
}
|
|||
|
|
|||
|
if (this.isContextual("implements")) {
|
|||
|
this.next();
|
|||
|
|
|||
|
do {
|
|||
|
node.implements.push(this.flowParseInterfaceExtends());
|
|||
|
} while (this.eat(_types.types.comma));
|
|||
|
}
|
|||
|
|
|||
|
node.body = this.flowParseObjectType({
|
|||
|
allowStatic: isClass,
|
|||
|
allowExact: false,
|
|||
|
allowSpread: false,
|
|||
|
allowProto: isClass,
|
|||
|
allowInexact: false
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
flowParseInterfaceExtends() {
|
|||
|
const node = this.startNode();
|
|||
|
node.id = this.flowParseQualifiedTypeIdentifier();
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
node.typeParameters = this.flowParseTypeParameterInstantiation();
|
|||
|
} else {
|
|||
|
node.typeParameters = null;
|
|||
|
}
|
|||
|
|
|||
|
return this.finishNode(node, "InterfaceExtends");
|
|||
|
}
|
|||
|
|
|||
|
flowParseInterface(node) {
|
|||
|
this.flowParseInterfaceish(node);
|
|||
|
return this.finishNode(node, "InterfaceDeclaration");
|
|||
|
}
|
|||
|
|
|||
|
checkNotUnderscore(word) {
|
|||
|
if (word === "_") {
|
|||
|
this.raise(this.state.start, "`_` is only allowed as a type argument to call or new");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
checkReservedType(word, startLoc, declaration) {
|
|||
|
if (!reservedTypes.has(word)) return;
|
|||
|
|
|||
|
if (declaration) {
|
|||
|
this.raise(startLoc, `Cannot overwrite reserved type ${word}`);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
this.raise(startLoc, `Unexpected reserved type ${word}`);
|
|||
|
}
|
|||
|
|
|||
|
flowParseRestrictedIdentifier(liberal, declaration) {
|
|||
|
this.checkReservedType(this.state.value, this.state.start, declaration);
|
|||
|
return this.parseIdentifier(liberal);
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeAlias(node) {
|
|||
|
node.id = this.flowParseRestrictedIdentifier(false, true);
|
|||
|
this.scope.declareName(node.id.name, _scopeflags.BIND_LEXICAL, node.id.start);
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
} else {
|
|||
|
node.typeParameters = null;
|
|||
|
}
|
|||
|
|
|||
|
node.right = this.flowParseTypeInitialiser(_types.types.eq);
|
|||
|
this.semicolon();
|
|||
|
return this.finishNode(node, "TypeAlias");
|
|||
|
}
|
|||
|
|
|||
|
flowParseOpaqueType(node, declare) {
|
|||
|
this.expectContextual("type");
|
|||
|
node.id = this.flowParseRestrictedIdentifier(true, true);
|
|||
|
this.scope.declareName(node.id.name, _scopeflags.BIND_LEXICAL, node.id.start);
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
} else {
|
|||
|
node.typeParameters = null;
|
|||
|
}
|
|||
|
|
|||
|
node.supertype = null;
|
|||
|
|
|||
|
if (this.match(_types.types.colon)) {
|
|||
|
node.supertype = this.flowParseTypeInitialiser(_types.types.colon);
|
|||
|
}
|
|||
|
|
|||
|
node.impltype = null;
|
|||
|
|
|||
|
if (!declare) {
|
|||
|
node.impltype = this.flowParseTypeInitialiser(_types.types.eq);
|
|||
|
}
|
|||
|
|
|||
|
this.semicolon();
|
|||
|
return this.finishNode(node, "OpaqueType");
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeParameter(requireDefault = false) {
|
|||
|
const nodeStart = this.state.start;
|
|||
|
const node = this.startNode();
|
|||
|
const variance = this.flowParseVariance();
|
|||
|
const ident = this.flowParseTypeAnnotatableIdentifier();
|
|||
|
node.name = ident.name;
|
|||
|
node.variance = variance;
|
|||
|
node.bound = ident.typeAnnotation;
|
|||
|
|
|||
|
if (this.match(_types.types.eq)) {
|
|||
|
this.eat(_types.types.eq);
|
|||
|
node.default = this.flowParseType();
|
|||
|
} else {
|
|||
|
if (requireDefault) {
|
|||
|
this.raise(nodeStart, "Type parameter declaration needs a default, since a preceding type parameter declaration has a default.");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return this.finishNode(node, "TypeParameter");
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeParameterDeclaration() {
|
|||
|
const oldInType = this.state.inType;
|
|||
|
const node = this.startNode();
|
|||
|
node.params = [];
|
|||
|
this.state.inType = true;
|
|||
|
|
|||
|
if (this.isRelational("<") || this.match(_types.types.jsxTagStart)) {
|
|||
|
this.next();
|
|||
|
} else {
|
|||
|
this.unexpected();
|
|||
|
}
|
|||
|
|
|||
|
let defaultRequired = false;
|
|||
|
|
|||
|
do {
|
|||
|
const typeParameter = this.flowParseTypeParameter(defaultRequired);
|
|||
|
node.params.push(typeParameter);
|
|||
|
|
|||
|
if (typeParameter.default) {
|
|||
|
defaultRequired = true;
|
|||
|
}
|
|||
|
|
|||
|
if (!this.isRelational(">")) {
|
|||
|
this.expect(_types.types.comma);
|
|||
|
}
|
|||
|
} while (!this.isRelational(">"));
|
|||
|
|
|||
|
this.expectRelational(">");
|
|||
|
this.state.inType = oldInType;
|
|||
|
return this.finishNode(node, "TypeParameterDeclaration");
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeParameterInstantiation() {
|
|||
|
const node = this.startNode();
|
|||
|
const oldInType = this.state.inType;
|
|||
|
node.params = [];
|
|||
|
this.state.inType = true;
|
|||
|
this.expectRelational("<");
|
|||
|
const oldNoAnonFunctionType = this.state.noAnonFunctionType;
|
|||
|
this.state.noAnonFunctionType = false;
|
|||
|
|
|||
|
while (!this.isRelational(">")) {
|
|||
|
node.params.push(this.flowParseType());
|
|||
|
|
|||
|
if (!this.isRelational(">")) {
|
|||
|
this.expect(_types.types.comma);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this.state.noAnonFunctionType = oldNoAnonFunctionType;
|
|||
|
this.expectRelational(">");
|
|||
|
this.state.inType = oldInType;
|
|||
|
return this.finishNode(node, "TypeParameterInstantiation");
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeParameterInstantiationCallOrNew() {
|
|||
|
const node = this.startNode();
|
|||
|
const oldInType = this.state.inType;
|
|||
|
node.params = [];
|
|||
|
this.state.inType = true;
|
|||
|
this.expectRelational("<");
|
|||
|
|
|||
|
while (!this.isRelational(">")) {
|
|||
|
node.params.push(this.flowParseTypeOrImplicitInstantiation());
|
|||
|
|
|||
|
if (!this.isRelational(">")) {
|
|||
|
this.expect(_types.types.comma);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this.expectRelational(">");
|
|||
|
this.state.inType = oldInType;
|
|||
|
return this.finishNode(node, "TypeParameterInstantiation");
|
|||
|
}
|
|||
|
|
|||
|
flowParseInterfaceType() {
|
|||
|
const node = this.startNode();
|
|||
|
this.expectContextual("interface");
|
|||
|
node.extends = [];
|
|||
|
|
|||
|
if (this.eat(_types.types._extends)) {
|
|||
|
do {
|
|||
|
node.extends.push(this.flowParseInterfaceExtends());
|
|||
|
} while (this.eat(_types.types.comma));
|
|||
|
}
|
|||
|
|
|||
|
node.body = this.flowParseObjectType({
|
|||
|
allowStatic: false,
|
|||
|
allowExact: false,
|
|||
|
allowSpread: false,
|
|||
|
allowProto: false,
|
|||
|
allowInexact: false
|
|||
|
});
|
|||
|
return this.finishNode(node, "InterfaceTypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
flowParseObjectPropertyKey() {
|
|||
|
return this.match(_types.types.num) || this.match(_types.types.string) ? this.parseExprAtom() : this.parseIdentifier(true);
|
|||
|
}
|
|||
|
|
|||
|
flowParseObjectTypeIndexer(node, isStatic, variance) {
|
|||
|
node.static = isStatic;
|
|||
|
|
|||
|
if (this.lookahead().type === _types.types.colon) {
|
|||
|
node.id = this.flowParseObjectPropertyKey();
|
|||
|
node.key = this.flowParseTypeInitialiser();
|
|||
|
} else {
|
|||
|
node.id = null;
|
|||
|
node.key = this.flowParseType();
|
|||
|
}
|
|||
|
|
|||
|
this.expect(_types.types.bracketR);
|
|||
|
node.value = this.flowParseTypeInitialiser();
|
|||
|
node.variance = variance;
|
|||
|
return this.finishNode(node, "ObjectTypeIndexer");
|
|||
|
}
|
|||
|
|
|||
|
flowParseObjectTypeInternalSlot(node, isStatic) {
|
|||
|
node.static = isStatic;
|
|||
|
node.id = this.flowParseObjectPropertyKey();
|
|||
|
this.expect(_types.types.bracketR);
|
|||
|
this.expect(_types.types.bracketR);
|
|||
|
|
|||
|
if (this.isRelational("<") || this.match(_types.types.parenL)) {
|
|||
|
node.method = true;
|
|||
|
node.optional = false;
|
|||
|
node.value = this.flowParseObjectTypeMethodish(this.startNodeAt(node.start, node.loc.start));
|
|||
|
} else {
|
|||
|
node.method = false;
|
|||
|
|
|||
|
if (this.eat(_types.types.question)) {
|
|||
|
node.optional = true;
|
|||
|
}
|
|||
|
|
|||
|
node.value = this.flowParseTypeInitialiser();
|
|||
|
}
|
|||
|
|
|||
|
return this.finishNode(node, "ObjectTypeInternalSlot");
|
|||
|
}
|
|||
|
|
|||
|
flowParseObjectTypeMethodish(node) {
|
|||
|
node.params = [];
|
|||
|
node.rest = null;
|
|||
|
node.typeParameters = null;
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
}
|
|||
|
|
|||
|
this.expect(_types.types.parenL);
|
|||
|
|
|||
|
while (!this.match(_types.types.parenR) && !this.match(_types.types.ellipsis)) {
|
|||
|
node.params.push(this.flowParseFunctionTypeParam());
|
|||
|
|
|||
|
if (!this.match(_types.types.parenR)) {
|
|||
|
this.expect(_types.types.comma);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (this.eat(_types.types.ellipsis)) {
|
|||
|
node.rest = this.flowParseFunctionTypeParam();
|
|||
|
}
|
|||
|
|
|||
|
this.expect(_types.types.parenR);
|
|||
|
node.returnType = this.flowParseTypeInitialiser();
|
|||
|
return this.finishNode(node, "FunctionTypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
flowParseObjectTypeCallProperty(node, isStatic) {
|
|||
|
const valueNode = this.startNode();
|
|||
|
node.static = isStatic;
|
|||
|
node.value = this.flowParseObjectTypeMethodish(valueNode);
|
|||
|
return this.finishNode(node, "ObjectTypeCallProperty");
|
|||
|
}
|
|||
|
|
|||
|
flowParseObjectType({
|
|||
|
allowStatic,
|
|||
|
allowExact,
|
|||
|
allowSpread,
|
|||
|
allowProto,
|
|||
|
allowInexact
|
|||
|
}) {
|
|||
|
const oldInType = this.state.inType;
|
|||
|
this.state.inType = true;
|
|||
|
const nodeStart = this.startNode();
|
|||
|
nodeStart.callProperties = [];
|
|||
|
nodeStart.properties = [];
|
|||
|
nodeStart.indexers = [];
|
|||
|
nodeStart.internalSlots = [];
|
|||
|
let endDelim;
|
|||
|
let exact;
|
|||
|
let inexact = false;
|
|||
|
|
|||
|
if (allowExact && this.match(_types.types.braceBarL)) {
|
|||
|
this.expect(_types.types.braceBarL);
|
|||
|
endDelim = _types.types.braceBarR;
|
|||
|
exact = true;
|
|||
|
} else {
|
|||
|
this.expect(_types.types.braceL);
|
|||
|
endDelim = _types.types.braceR;
|
|||
|
exact = false;
|
|||
|
}
|
|||
|
|
|||
|
nodeStart.exact = exact;
|
|||
|
|
|||
|
while (!this.match(endDelim)) {
|
|||
|
let isStatic = false;
|
|||
|
let protoStart = null;
|
|||
|
let inexactStart = null;
|
|||
|
const node = this.startNode();
|
|||
|
|
|||
|
if (allowProto && this.isContextual("proto")) {
|
|||
|
const lookahead = this.lookahead();
|
|||
|
|
|||
|
if (lookahead.type !== _types.types.colon && lookahead.type !== _types.types.question) {
|
|||
|
this.next();
|
|||
|
protoStart = this.state.start;
|
|||
|
allowStatic = false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (allowStatic && this.isContextual("static")) {
|
|||
|
const lookahead = this.lookahead();
|
|||
|
|
|||
|
if (lookahead.type !== _types.types.colon && lookahead.type !== _types.types.question) {
|
|||
|
this.next();
|
|||
|
isStatic = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const variance = this.flowParseVariance();
|
|||
|
|
|||
|
if (this.eat(_types.types.bracketL)) {
|
|||
|
if (protoStart != null) {
|
|||
|
this.unexpected(protoStart);
|
|||
|
}
|
|||
|
|
|||
|
if (this.eat(_types.types.bracketL)) {
|
|||
|
if (variance) {
|
|||
|
this.unexpected(variance.start);
|
|||
|
}
|
|||
|
|
|||
|
nodeStart.internalSlots.push(this.flowParseObjectTypeInternalSlot(node, isStatic));
|
|||
|
} else {
|
|||
|
nodeStart.indexers.push(this.flowParseObjectTypeIndexer(node, isStatic, variance));
|
|||
|
}
|
|||
|
} else if (this.match(_types.types.parenL) || this.isRelational("<")) {
|
|||
|
if (protoStart != null) {
|
|||
|
this.unexpected(protoStart);
|
|||
|
}
|
|||
|
|
|||
|
if (variance) {
|
|||
|
this.unexpected(variance.start);
|
|||
|
}
|
|||
|
|
|||
|
nodeStart.callProperties.push(this.flowParseObjectTypeCallProperty(node, isStatic));
|
|||
|
} else {
|
|||
|
let kind = "init";
|
|||
|
|
|||
|
if (this.isContextual("get") || this.isContextual("set")) {
|
|||
|
const lookahead = this.lookahead();
|
|||
|
|
|||
|
if (lookahead.type === _types.types.name || lookahead.type === _types.types.string || lookahead.type === _types.types.num) {
|
|||
|
kind = this.state.value;
|
|||
|
this.next();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const propOrInexact = this.flowParseObjectTypeProperty(node, isStatic, protoStart, variance, kind, allowSpread, allowInexact != null ? allowInexact : !exact);
|
|||
|
|
|||
|
if (propOrInexact === null) {
|
|||
|
inexact = true;
|
|||
|
inexactStart = this.state.lastTokStart;
|
|||
|
} else {
|
|||
|
nodeStart.properties.push(propOrInexact);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this.flowObjectTypeSemicolon();
|
|||
|
|
|||
|
if (inexactStart && !this.match(_types.types.braceR) && !this.match(_types.types.braceBarR)) {
|
|||
|
this.raise(inexactStart, "Explicit inexact syntax must appear at the end of an inexact object");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this.expect(endDelim);
|
|||
|
|
|||
|
if (allowSpread) {
|
|||
|
nodeStart.inexact = inexact;
|
|||
|
}
|
|||
|
|
|||
|
const out = this.finishNode(nodeStart, "ObjectTypeAnnotation");
|
|||
|
this.state.inType = oldInType;
|
|||
|
return out;
|
|||
|
}
|
|||
|
|
|||
|
flowParseObjectTypeProperty(node, isStatic, protoStart, variance, kind, allowSpread, allowInexact) {
|
|||
|
if (this.eat(_types.types.ellipsis)) {
|
|||
|
const isInexactToken = this.match(_types.types.comma) || this.match(_types.types.semi) || this.match(_types.types.braceR) || this.match(_types.types.braceBarR);
|
|||
|
|
|||
|
if (isInexactToken) {
|
|||
|
if (!allowSpread) {
|
|||
|
this.raise(this.state.lastTokStart, "Explicit inexact syntax cannot appear in class or interface definitions");
|
|||
|
} else if (!allowInexact) {
|
|||
|
this.raise(this.state.lastTokStart, "Explicit inexact syntax cannot appear inside an explicit exact object type");
|
|||
|
}
|
|||
|
|
|||
|
if (variance) {
|
|||
|
this.raise(variance.start, "Explicit inexact syntax cannot have variance");
|
|||
|
}
|
|||
|
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
if (!allowSpread) {
|
|||
|
this.raise(this.state.lastTokStart, "Spread operator cannot appear in class or interface definitions");
|
|||
|
}
|
|||
|
|
|||
|
if (protoStart != null) {
|
|||
|
this.unexpected(protoStart);
|
|||
|
}
|
|||
|
|
|||
|
if (variance) {
|
|||
|
this.raise(variance.start, "Spread properties cannot have variance");
|
|||
|
}
|
|||
|
|
|||
|
node.argument = this.flowParseType();
|
|||
|
return this.finishNode(node, "ObjectTypeSpreadProperty");
|
|||
|
} else {
|
|||
|
node.key = this.flowParseObjectPropertyKey();
|
|||
|
node.static = isStatic;
|
|||
|
node.proto = protoStart != null;
|
|||
|
node.kind = kind;
|
|||
|
let optional = false;
|
|||
|
|
|||
|
if (this.isRelational("<") || this.match(_types.types.parenL)) {
|
|||
|
node.method = true;
|
|||
|
|
|||
|
if (protoStart != null) {
|
|||
|
this.unexpected(protoStart);
|
|||
|
}
|
|||
|
|
|||
|
if (variance) {
|
|||
|
this.unexpected(variance.start);
|
|||
|
}
|
|||
|
|
|||
|
node.value = this.flowParseObjectTypeMethodish(this.startNodeAt(node.start, node.loc.start));
|
|||
|
|
|||
|
if (kind === "get" || kind === "set") {
|
|||
|
this.flowCheckGetterSetterParams(node);
|
|||
|
}
|
|||
|
} else {
|
|||
|
if (kind !== "init") this.unexpected();
|
|||
|
node.method = false;
|
|||
|
|
|||
|
if (this.eat(_types.types.question)) {
|
|||
|
optional = true;
|
|||
|
}
|
|||
|
|
|||
|
node.value = this.flowParseTypeInitialiser();
|
|||
|
node.variance = variance;
|
|||
|
}
|
|||
|
|
|||
|
node.optional = optional;
|
|||
|
return this.finishNode(node, "ObjectTypeProperty");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowCheckGetterSetterParams(property) {
|
|||
|
const paramCount = property.kind === "get" ? 0 : 1;
|
|||
|
const start = property.start;
|
|||
|
const length = property.value.params.length + (property.value.rest ? 1 : 0);
|
|||
|
|
|||
|
if (length !== paramCount) {
|
|||
|
if (property.kind === "get") {
|
|||
|
this.raise(start, "getter must not have any formal parameters");
|
|||
|
} else {
|
|||
|
this.raise(start, "setter must have exactly one formal parameter");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (property.kind === "set" && property.value.rest) {
|
|||
|
this.raise(start, "setter function argument must not be a rest parameter");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowObjectTypeSemicolon() {
|
|||
|
if (!this.eat(_types.types.semi) && !this.eat(_types.types.comma) && !this.match(_types.types.braceR) && !this.match(_types.types.braceBarR)) {
|
|||
|
this.unexpected();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowParseQualifiedTypeIdentifier(startPos, startLoc, id) {
|
|||
|
startPos = startPos || this.state.start;
|
|||
|
startLoc = startLoc || this.state.startLoc;
|
|||
|
let node = id || this.flowParseRestrictedIdentifier(true);
|
|||
|
|
|||
|
while (this.eat(_types.types.dot)) {
|
|||
|
const node2 = this.startNodeAt(startPos, startLoc);
|
|||
|
node2.qualification = node;
|
|||
|
node2.id = this.flowParseRestrictedIdentifier(true);
|
|||
|
node = this.finishNode(node2, "QualifiedTypeIdentifier");
|
|||
|
}
|
|||
|
|
|||
|
return node;
|
|||
|
}
|
|||
|
|
|||
|
flowParseGenericType(startPos, startLoc, id) {
|
|||
|
const node = this.startNodeAt(startPos, startLoc);
|
|||
|
node.typeParameters = null;
|
|||
|
node.id = this.flowParseQualifiedTypeIdentifier(startPos, startLoc, id);
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
node.typeParameters = this.flowParseTypeParameterInstantiation();
|
|||
|
}
|
|||
|
|
|||
|
return this.finishNode(node, "GenericTypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeofType() {
|
|||
|
const node = this.startNode();
|
|||
|
this.expect(_types.types._typeof);
|
|||
|
node.argument = this.flowParsePrimaryType();
|
|||
|
return this.finishNode(node, "TypeofTypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
flowParseTupleType() {
|
|||
|
const node = this.startNode();
|
|||
|
node.types = [];
|
|||
|
this.expect(_types.types.bracketL);
|
|||
|
|
|||
|
while (this.state.pos < this.length && !this.match(_types.types.bracketR)) {
|
|||
|
node.types.push(this.flowParseType());
|
|||
|
if (this.match(_types.types.bracketR)) break;
|
|||
|
this.expect(_types.types.comma);
|
|||
|
}
|
|||
|
|
|||
|
this.expect(_types.types.bracketR);
|
|||
|
return this.finishNode(node, "TupleTypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
flowParseFunctionTypeParam() {
|
|||
|
let name = null;
|
|||
|
let optional = false;
|
|||
|
let typeAnnotation = null;
|
|||
|
const node = this.startNode();
|
|||
|
const lh = this.lookahead();
|
|||
|
|
|||
|
if (lh.type === _types.types.colon || lh.type === _types.types.question) {
|
|||
|
name = this.parseIdentifier();
|
|||
|
|
|||
|
if (this.eat(_types.types.question)) {
|
|||
|
optional = true;
|
|||
|
}
|
|||
|
|
|||
|
typeAnnotation = this.flowParseTypeInitialiser();
|
|||
|
} else {
|
|||
|
typeAnnotation = this.flowParseType();
|
|||
|
}
|
|||
|
|
|||
|
node.name = name;
|
|||
|
node.optional = optional;
|
|||
|
node.typeAnnotation = typeAnnotation;
|
|||
|
return this.finishNode(node, "FunctionTypeParam");
|
|||
|
}
|
|||
|
|
|||
|
reinterpretTypeAsFunctionTypeParam(type) {
|
|||
|
const node = this.startNodeAt(type.start, type.loc.start);
|
|||
|
node.name = null;
|
|||
|
node.optional = false;
|
|||
|
node.typeAnnotation = type;
|
|||
|
return this.finishNode(node, "FunctionTypeParam");
|
|||
|
}
|
|||
|
|
|||
|
flowParseFunctionTypeParams(params = []) {
|
|||
|
let rest = null;
|
|||
|
|
|||
|
while (!this.match(_types.types.parenR) && !this.match(_types.types.ellipsis)) {
|
|||
|
params.push(this.flowParseFunctionTypeParam());
|
|||
|
|
|||
|
if (!this.match(_types.types.parenR)) {
|
|||
|
this.expect(_types.types.comma);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (this.eat(_types.types.ellipsis)) {
|
|||
|
rest = this.flowParseFunctionTypeParam();
|
|||
|
}
|
|||
|
|
|||
|
return {
|
|||
|
params,
|
|||
|
rest
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
flowIdentToTypeAnnotation(startPos, startLoc, node, id) {
|
|||
|
switch (id.name) {
|
|||
|
case "any":
|
|||
|
return this.finishNode(node, "AnyTypeAnnotation");
|
|||
|
|
|||
|
case "bool":
|
|||
|
case "boolean":
|
|||
|
return this.finishNode(node, "BooleanTypeAnnotation");
|
|||
|
|
|||
|
case "mixed":
|
|||
|
return this.finishNode(node, "MixedTypeAnnotation");
|
|||
|
|
|||
|
case "empty":
|
|||
|
return this.finishNode(node, "EmptyTypeAnnotation");
|
|||
|
|
|||
|
case "number":
|
|||
|
return this.finishNode(node, "NumberTypeAnnotation");
|
|||
|
|
|||
|
case "string":
|
|||
|
return this.finishNode(node, "StringTypeAnnotation");
|
|||
|
|
|||
|
default:
|
|||
|
this.checkNotUnderscore(id.name);
|
|||
|
return this.flowParseGenericType(startPos, startLoc, id);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowParsePrimaryType() {
|
|||
|
const startPos = this.state.start;
|
|||
|
const startLoc = this.state.startLoc;
|
|||
|
const node = this.startNode();
|
|||
|
let tmp;
|
|||
|
let type;
|
|||
|
let isGroupedType = false;
|
|||
|
const oldNoAnonFunctionType = this.state.noAnonFunctionType;
|
|||
|
|
|||
|
switch (this.state.type) {
|
|||
|
case _types.types.name:
|
|||
|
if (this.isContextual("interface")) {
|
|||
|
return this.flowParseInterfaceType();
|
|||
|
}
|
|||
|
|
|||
|
return this.flowIdentToTypeAnnotation(startPos, startLoc, node, this.parseIdentifier());
|
|||
|
|
|||
|
case _types.types.braceL:
|
|||
|
return this.flowParseObjectType({
|
|||
|
allowStatic: false,
|
|||
|
allowExact: false,
|
|||
|
allowSpread: true,
|
|||
|
allowProto: false,
|
|||
|
allowInexact: true
|
|||
|
});
|
|||
|
|
|||
|
case _types.types.braceBarL:
|
|||
|
return this.flowParseObjectType({
|
|||
|
allowStatic: false,
|
|||
|
allowExact: true,
|
|||
|
allowSpread: true,
|
|||
|
allowProto: false,
|
|||
|
allowInexact: false
|
|||
|
});
|
|||
|
|
|||
|
case _types.types.bracketL:
|
|||
|
this.state.noAnonFunctionType = false;
|
|||
|
type = this.flowParseTupleType();
|
|||
|
this.state.noAnonFunctionType = oldNoAnonFunctionType;
|
|||
|
return type;
|
|||
|
|
|||
|
case _types.types.relational:
|
|||
|
if (this.state.value === "<") {
|
|||
|
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
this.expect(_types.types.parenL);
|
|||
|
tmp = this.flowParseFunctionTypeParams();
|
|||
|
node.params = tmp.params;
|
|||
|
node.rest = tmp.rest;
|
|||
|
this.expect(_types.types.parenR);
|
|||
|
this.expect(_types.types.arrow);
|
|||
|
node.returnType = this.flowParseType();
|
|||
|
return this.finishNode(node, "FunctionTypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case _types.types.parenL:
|
|||
|
this.next();
|
|||
|
|
|||
|
if (!this.match(_types.types.parenR) && !this.match(_types.types.ellipsis)) {
|
|||
|
if (this.match(_types.types.name)) {
|
|||
|
const token = this.lookahead().type;
|
|||
|
isGroupedType = token !== _types.types.question && token !== _types.types.colon;
|
|||
|
} else {
|
|||
|
isGroupedType = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (isGroupedType) {
|
|||
|
this.state.noAnonFunctionType = false;
|
|||
|
type = this.flowParseType();
|
|||
|
this.state.noAnonFunctionType = oldNoAnonFunctionType;
|
|||
|
|
|||
|
if (this.state.noAnonFunctionType || !(this.match(_types.types.comma) || this.match(_types.types.parenR) && this.lookahead().type === _types.types.arrow)) {
|
|||
|
this.expect(_types.types.parenR);
|
|||
|
return type;
|
|||
|
} else {
|
|||
|
this.eat(_types.types.comma);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (type) {
|
|||
|
tmp = this.flowParseFunctionTypeParams([this.reinterpretTypeAsFunctionTypeParam(type)]);
|
|||
|
} else {
|
|||
|
tmp = this.flowParseFunctionTypeParams();
|
|||
|
}
|
|||
|
|
|||
|
node.params = tmp.params;
|
|||
|
node.rest = tmp.rest;
|
|||
|
this.expect(_types.types.parenR);
|
|||
|
this.expect(_types.types.arrow);
|
|||
|
node.returnType = this.flowParseType();
|
|||
|
node.typeParameters = null;
|
|||
|
return this.finishNode(node, "FunctionTypeAnnotation");
|
|||
|
|
|||
|
case _types.types.string:
|
|||
|
return this.parseLiteral(this.state.value, "StringLiteralTypeAnnotation");
|
|||
|
|
|||
|
case _types.types._true:
|
|||
|
case _types.types._false:
|
|||
|
node.value = this.match(_types.types._true);
|
|||
|
this.next();
|
|||
|
return this.finishNode(node, "BooleanLiteralTypeAnnotation");
|
|||
|
|
|||
|
case _types.types.plusMin:
|
|||
|
if (this.state.value === "-") {
|
|||
|
this.next();
|
|||
|
|
|||
|
if (this.match(_types.types.num)) {
|
|||
|
return this.parseLiteral(-this.state.value, "NumberLiteralTypeAnnotation", node.start, node.loc.start);
|
|||
|
}
|
|||
|
|
|||
|
if (this.match(_types.types.bigint)) {
|
|||
|
return this.parseLiteral(-this.state.value, "BigIntLiteralTypeAnnotation", node.start, node.loc.start);
|
|||
|
}
|
|||
|
|
|||
|
throw this.raise(this.state.start, `Unexpected token, expected "number" or "bigint"`);
|
|||
|
}
|
|||
|
|
|||
|
this.unexpected();
|
|||
|
|
|||
|
case _types.types.num:
|
|||
|
return this.parseLiteral(this.state.value, "NumberLiteralTypeAnnotation");
|
|||
|
|
|||
|
case _types.types.bigint:
|
|||
|
return this.parseLiteral(this.state.value, "BigIntLiteralTypeAnnotation");
|
|||
|
|
|||
|
case _types.types._void:
|
|||
|
this.next();
|
|||
|
return this.finishNode(node, "VoidTypeAnnotation");
|
|||
|
|
|||
|
case _types.types._null:
|
|||
|
this.next();
|
|||
|
return this.finishNode(node, "NullLiteralTypeAnnotation");
|
|||
|
|
|||
|
case _types.types._this:
|
|||
|
this.next();
|
|||
|
return this.finishNode(node, "ThisTypeAnnotation");
|
|||
|
|
|||
|
case _types.types.star:
|
|||
|
this.next();
|
|||
|
return this.finishNode(node, "ExistsTypeAnnotation");
|
|||
|
|
|||
|
default:
|
|||
|
if (this.state.type.keyword === "typeof") {
|
|||
|
return this.flowParseTypeofType();
|
|||
|
} else if (this.state.type.keyword) {
|
|||
|
const label = this.state.type.label;
|
|||
|
this.next();
|
|||
|
return super.createIdentifier(node, label);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
throw this.unexpected();
|
|||
|
}
|
|||
|
|
|||
|
flowParsePostfixType() {
|
|||
|
const startPos = this.state.start,
|
|||
|
startLoc = this.state.startLoc;
|
|||
|
let type = this.flowParsePrimaryType();
|
|||
|
|
|||
|
while (this.match(_types.types.bracketL) && !this.canInsertSemicolon()) {
|
|||
|
const node = this.startNodeAt(startPos, startLoc);
|
|||
|
node.elementType = type;
|
|||
|
this.expect(_types.types.bracketL);
|
|||
|
this.expect(_types.types.bracketR);
|
|||
|
type = this.finishNode(node, "ArrayTypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
return type;
|
|||
|
}
|
|||
|
|
|||
|
flowParsePrefixType() {
|
|||
|
const node = this.startNode();
|
|||
|
|
|||
|
if (this.eat(_types.types.question)) {
|
|||
|
node.typeAnnotation = this.flowParsePrefixType();
|
|||
|
return this.finishNode(node, "NullableTypeAnnotation");
|
|||
|
} else {
|
|||
|
return this.flowParsePostfixType();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowParseAnonFunctionWithoutParens() {
|
|||
|
const param = this.flowParsePrefixType();
|
|||
|
|
|||
|
if (!this.state.noAnonFunctionType && this.eat(_types.types.arrow)) {
|
|||
|
const node = this.startNodeAt(param.start, param.loc.start);
|
|||
|
node.params = [this.reinterpretTypeAsFunctionTypeParam(param)];
|
|||
|
node.rest = null;
|
|||
|
node.returnType = this.flowParseType();
|
|||
|
node.typeParameters = null;
|
|||
|
return this.finishNode(node, "FunctionTypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
return param;
|
|||
|
}
|
|||
|
|
|||
|
flowParseIntersectionType() {
|
|||
|
const node = this.startNode();
|
|||
|
this.eat(_types.types.bitwiseAND);
|
|||
|
const type = this.flowParseAnonFunctionWithoutParens();
|
|||
|
node.types = [type];
|
|||
|
|
|||
|
while (this.eat(_types.types.bitwiseAND)) {
|
|||
|
node.types.push(this.flowParseAnonFunctionWithoutParens());
|
|||
|
}
|
|||
|
|
|||
|
return node.types.length === 1 ? type : this.finishNode(node, "IntersectionTypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
flowParseUnionType() {
|
|||
|
const node = this.startNode();
|
|||
|
this.eat(_types.types.bitwiseOR);
|
|||
|
const type = this.flowParseIntersectionType();
|
|||
|
node.types = [type];
|
|||
|
|
|||
|
while (this.eat(_types.types.bitwiseOR)) {
|
|||
|
node.types.push(this.flowParseIntersectionType());
|
|||
|
}
|
|||
|
|
|||
|
return node.types.length === 1 ? type : this.finishNode(node, "UnionTypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
flowParseType() {
|
|||
|
const oldInType = this.state.inType;
|
|||
|
this.state.inType = true;
|
|||
|
const type = this.flowParseUnionType();
|
|||
|
this.state.inType = oldInType;
|
|||
|
this.state.exprAllowed = this.state.exprAllowed || this.state.noAnonFunctionType;
|
|||
|
return type;
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeOrImplicitInstantiation() {
|
|||
|
if (this.state.type === _types.types.name && this.state.value === "_") {
|
|||
|
const startPos = this.state.start;
|
|||
|
const startLoc = this.state.startLoc;
|
|||
|
const node = this.parseIdentifier();
|
|||
|
return this.flowParseGenericType(startPos, startLoc, node);
|
|||
|
} else {
|
|||
|
return this.flowParseType();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeAnnotation() {
|
|||
|
const node = this.startNode();
|
|||
|
node.typeAnnotation = this.flowParseTypeInitialiser();
|
|||
|
return this.finishNode(node, "TypeAnnotation");
|
|||
|
}
|
|||
|
|
|||
|
flowParseTypeAnnotatableIdentifier(allowPrimitiveOverride) {
|
|||
|
const ident = allowPrimitiveOverride ? this.parseIdentifier() : this.flowParseRestrictedIdentifier();
|
|||
|
|
|||
|
if (this.match(_types.types.colon)) {
|
|||
|
ident.typeAnnotation = this.flowParseTypeAnnotation();
|
|||
|
this.resetEndLocation(ident);
|
|||
|
}
|
|||
|
|
|||
|
return ident;
|
|||
|
}
|
|||
|
|
|||
|
typeCastToParameter(node) {
|
|||
|
node.expression.typeAnnotation = node.typeAnnotation;
|
|||
|
this.resetEndLocation(node.expression, node.typeAnnotation.end, node.typeAnnotation.loc.end);
|
|||
|
return node.expression;
|
|||
|
}
|
|||
|
|
|||
|
flowParseVariance() {
|
|||
|
let variance = null;
|
|||
|
|
|||
|
if (this.match(_types.types.plusMin)) {
|
|||
|
variance = this.startNode();
|
|||
|
|
|||
|
if (this.state.value === "+") {
|
|||
|
variance.kind = "plus";
|
|||
|
} else {
|
|||
|
variance.kind = "minus";
|
|||
|
}
|
|||
|
|
|||
|
this.next();
|
|||
|
this.finishNode(variance, "Variance");
|
|||
|
}
|
|||
|
|
|||
|
return variance;
|
|||
|
}
|
|||
|
|
|||
|
parseFunctionBody(node, allowExpressionBody, isMethod = false) {
|
|||
|
if (allowExpressionBody) {
|
|||
|
return this.forwardNoArrowParamsConversionAt(node, () => super.parseFunctionBody(node, true, isMethod));
|
|||
|
}
|
|||
|
|
|||
|
return super.parseFunctionBody(node, false, isMethod);
|
|||
|
}
|
|||
|
|
|||
|
parseFunctionBodyAndFinish(node, type, isMethod = false) {
|
|||
|
if (this.match(_types.types.colon)) {
|
|||
|
const typeNode = this.startNode();
|
|||
|
[typeNode.typeAnnotation, node.predicate] = this.flowParseTypeAndPredicateInitialiser();
|
|||
|
node.returnType = typeNode.typeAnnotation ? this.finishNode(typeNode, "TypeAnnotation") : null;
|
|||
|
}
|
|||
|
|
|||
|
super.parseFunctionBodyAndFinish(node, type, isMethod);
|
|||
|
}
|
|||
|
|
|||
|
parseStatement(context, topLevel) {
|
|||
|
if (this.state.strict && this.match(_types.types.name) && this.state.value === "interface") {
|
|||
|
const node = this.startNode();
|
|||
|
this.next();
|
|||
|
return this.flowParseInterface(node);
|
|||
|
} else if (this.shouldParseEnums() && this.isContextual("enum")) {
|
|||
|
const node = this.startNode();
|
|||
|
this.next();
|
|||
|
return this.flowParseEnumDeclaration(node);
|
|||
|
} else {
|
|||
|
const stmt = super.parseStatement(context, topLevel);
|
|||
|
|
|||
|
if (this.flowPragma === undefined && !this.isValidDirective(stmt)) {
|
|||
|
this.flowPragma = null;
|
|||
|
}
|
|||
|
|
|||
|
return stmt;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
parseExpressionStatement(node, expr) {
|
|||
|
if (expr.type === "Identifier") {
|
|||
|
if (expr.name === "declare") {
|
|||
|
if (this.match(_types.types._class) || this.match(_types.types.name) || this.match(_types.types._function) || this.match(_types.types._var) || this.match(_types.types._export)) {
|
|||
|
return this.flowParseDeclare(node);
|
|||
|
}
|
|||
|
} else if (this.match(_types.types.name)) {
|
|||
|
if (expr.name === "interface") {
|
|||
|
return this.flowParseInterface(node);
|
|||
|
} else if (expr.name === "type") {
|
|||
|
return this.flowParseTypeAlias(node);
|
|||
|
} else if (expr.name === "opaque") {
|
|||
|
return this.flowParseOpaqueType(node, false);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return super.parseExpressionStatement(node, expr);
|
|||
|
}
|
|||
|
|
|||
|
shouldParseExportDeclaration() {
|
|||
|
return this.isContextual("type") || this.isContextual("interface") || this.isContextual("opaque") || this.shouldParseEnums() && this.isContextual("enum") || super.shouldParseExportDeclaration();
|
|||
|
}
|
|||
|
|
|||
|
isExportDefaultSpecifier() {
|
|||
|
if (this.match(_types.types.name) && (this.state.value === "type" || this.state.value === "interface" || this.state.value === "opaque" || this.shouldParseEnums() && this.state.value === "enum")) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return super.isExportDefaultSpecifier();
|
|||
|
}
|
|||
|
|
|||
|
parseExportDefaultExpression() {
|
|||
|
if (this.shouldParseEnums() && this.isContextual("enum")) {
|
|||
|
const node = this.startNode();
|
|||
|
this.next();
|
|||
|
return this.flowParseEnumDeclaration(node);
|
|||
|
}
|
|||
|
|
|||
|
return super.parseExportDefaultExpression();
|
|||
|
}
|
|||
|
|
|||
|
parseConditional(expr, noIn, startPos, startLoc, refNeedsArrowPos) {
|
|||
|
if (!this.match(_types.types.question)) return expr;
|
|||
|
|
|||
|
if (refNeedsArrowPos) {
|
|||
|
const result = this.tryParse(() => super.parseConditional(expr, noIn, startPos, startLoc));
|
|||
|
|
|||
|
if (!result.node) {
|
|||
|
refNeedsArrowPos.start = result.error.pos || this.state.start;
|
|||
|
return expr;
|
|||
|
}
|
|||
|
|
|||
|
if (result.error) this.state = result.failState;
|
|||
|
return result.node;
|
|||
|
}
|
|||
|
|
|||
|
this.expect(_types.types.question);
|
|||
|
const state = this.state.clone();
|
|||
|
const originalNoArrowAt = this.state.noArrowAt;
|
|||
|
const node = this.startNodeAt(startPos, startLoc);
|
|||
|
let {
|
|||
|
consequent,
|
|||
|
failed
|
|||
|
} = this.tryParseConditionalConsequent();
|
|||
|
let [valid, invalid] = this.getArrowLikeExpressions(consequent);
|
|||
|
|
|||
|
if (failed || invalid.length > 0) {
|
|||
|
const noArrowAt = [...originalNoArrowAt];
|
|||
|
|
|||
|
if (invalid.length > 0) {
|
|||
|
this.state = state;
|
|||
|
this.state.noArrowAt = noArrowAt;
|
|||
|
|
|||
|
for (let i = 0; i < invalid.length; i++) {
|
|||
|
noArrowAt.push(invalid[i].start);
|
|||
|
}
|
|||
|
|
|||
|
({
|
|||
|
consequent,
|
|||
|
failed
|
|||
|
} = this.tryParseConditionalConsequent());
|
|||
|
[valid, invalid] = this.getArrowLikeExpressions(consequent);
|
|||
|
}
|
|||
|
|
|||
|
if (failed && valid.length > 1) {
|
|||
|
this.raise(state.start, "Ambiguous expression: wrap the arrow functions in parentheses to disambiguate.");
|
|||
|
}
|
|||
|
|
|||
|
if (failed && valid.length === 1) {
|
|||
|
this.state = state;
|
|||
|
this.state.noArrowAt = noArrowAt.concat(valid[0].start);
|
|||
|
({
|
|||
|
consequent,
|
|||
|
failed
|
|||
|
} = this.tryParseConditionalConsequent());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this.getArrowLikeExpressions(consequent, true);
|
|||
|
this.state.noArrowAt = originalNoArrowAt;
|
|||
|
this.expect(_types.types.colon);
|
|||
|
node.test = expr;
|
|||
|
node.consequent = consequent;
|
|||
|
node.alternate = this.forwardNoArrowParamsConversionAt(node, () => this.parseMaybeAssign(noIn, undefined, undefined, undefined));
|
|||
|
return this.finishNode(node, "ConditionalExpression");
|
|||
|
}
|
|||
|
|
|||
|
tryParseConditionalConsequent() {
|
|||
|
this.state.noArrowParamsConversionAt.push(this.state.start);
|
|||
|
const consequent = this.parseMaybeAssign();
|
|||
|
const failed = !this.match(_types.types.colon);
|
|||
|
this.state.noArrowParamsConversionAt.pop();
|
|||
|
return {
|
|||
|
consequent,
|
|||
|
failed
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
getArrowLikeExpressions(node, disallowInvalid) {
|
|||
|
const stack = [node];
|
|||
|
const arrows = [];
|
|||
|
|
|||
|
while (stack.length !== 0) {
|
|||
|
const node = stack.pop();
|
|||
|
|
|||
|
if (node.type === "ArrowFunctionExpression") {
|
|||
|
if (node.typeParameters || !node.returnType) {
|
|||
|
this.finishArrowValidation(node);
|
|||
|
} else {
|
|||
|
arrows.push(node);
|
|||
|
}
|
|||
|
|
|||
|
stack.push(node.body);
|
|||
|
} else if (node.type === "ConditionalExpression") {
|
|||
|
stack.push(node.consequent);
|
|||
|
stack.push(node.alternate);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (disallowInvalid) {
|
|||
|
arrows.forEach(node => this.finishArrowValidation(node));
|
|||
|
return [arrows, []];
|
|||
|
}
|
|||
|
|
|||
|
return partition(arrows, node => node.params.every(param => this.isAssignable(param, true)));
|
|||
|
}
|
|||
|
|
|||
|
finishArrowValidation(node) {
|
|||
|
var _node$extra;
|
|||
|
|
|||
|
this.toAssignableList(node.params, true, "arrow function parameters", (_node$extra = node.extra) == null ? void 0 : _node$extra.trailingComma);
|
|||
|
this.scope.enter((0, _scopeflags.functionFlags)(false, false) | _scopeflags.SCOPE_ARROW);
|
|||
|
super.checkParams(node, false, true);
|
|||
|
this.scope.exit();
|
|||
|
}
|
|||
|
|
|||
|
forwardNoArrowParamsConversionAt(node, parse) {
|
|||
|
let result;
|
|||
|
|
|||
|
if (this.state.noArrowParamsConversionAt.indexOf(node.start) !== -1) {
|
|||
|
this.state.noArrowParamsConversionAt.push(this.state.start);
|
|||
|
result = parse();
|
|||
|
this.state.noArrowParamsConversionAt.pop();
|
|||
|
} else {
|
|||
|
result = parse();
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
parseParenItem(node, startPos, startLoc) {
|
|||
|
node = super.parseParenItem(node, startPos, startLoc);
|
|||
|
|
|||
|
if (this.eat(_types.types.question)) {
|
|||
|
node.optional = true;
|
|||
|
this.resetEndLocation(node);
|
|||
|
}
|
|||
|
|
|||
|
if (this.match(_types.types.colon)) {
|
|||
|
const typeCastNode = this.startNodeAt(startPos, startLoc);
|
|||
|
typeCastNode.expression = node;
|
|||
|
typeCastNode.typeAnnotation = this.flowParseTypeAnnotation();
|
|||
|
return this.finishNode(typeCastNode, "TypeCastExpression");
|
|||
|
}
|
|||
|
|
|||
|
return node;
|
|||
|
}
|
|||
|
|
|||
|
assertModuleNodeAllowed(node) {
|
|||
|
if (node.type === "ImportDeclaration" && (node.importKind === "type" || node.importKind === "typeof") || node.type === "ExportNamedDeclaration" && node.exportKind === "type" || node.type === "ExportAllDeclaration" && node.exportKind === "type") {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
super.assertModuleNodeAllowed(node);
|
|||
|
}
|
|||
|
|
|||
|
parseExport(node) {
|
|||
|
const decl = super.parseExport(node);
|
|||
|
|
|||
|
if (decl.type === "ExportNamedDeclaration" || decl.type === "ExportAllDeclaration") {
|
|||
|
decl.exportKind = decl.exportKind || "value";
|
|||
|
}
|
|||
|
|
|||
|
return decl;
|
|||
|
}
|
|||
|
|
|||
|
parseExportDeclaration(node) {
|
|||
|
if (this.isContextual("type")) {
|
|||
|
node.exportKind = "type";
|
|||
|
const declarationNode = this.startNode();
|
|||
|
this.next();
|
|||
|
|
|||
|
if (this.match(_types.types.braceL)) {
|
|||
|
node.specifiers = this.parseExportSpecifiers();
|
|||
|
this.parseExportFrom(node);
|
|||
|
return null;
|
|||
|
} else {
|
|||
|
return this.flowParseTypeAlias(declarationNode);
|
|||
|
}
|
|||
|
} else if (this.isContextual("opaque")) {
|
|||
|
node.exportKind = "type";
|
|||
|
const declarationNode = this.startNode();
|
|||
|
this.next();
|
|||
|
return this.flowParseOpaqueType(declarationNode, false);
|
|||
|
} else if (this.isContextual("interface")) {
|
|||
|
node.exportKind = "type";
|
|||
|
const declarationNode = this.startNode();
|
|||
|
this.next();
|
|||
|
return this.flowParseInterface(declarationNode);
|
|||
|
} else if (this.shouldParseEnums() && this.isContextual("enum")) {
|
|||
|
node.exportKind = "value";
|
|||
|
const declarationNode = this.startNode();
|
|||
|
this.next();
|
|||
|
return this.flowParseEnumDeclaration(declarationNode);
|
|||
|
} else {
|
|||
|
return super.parseExportDeclaration(node);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
eatExportStar(node) {
|
|||
|
if (super.eatExportStar(...arguments)) return true;
|
|||
|
|
|||
|
if (this.isContextual("type") && this.lookahead().type === _types.types.star) {
|
|||
|
node.exportKind = "type";
|
|||
|
this.next();
|
|||
|
this.next();
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
maybeParseExportNamespaceSpecifier(node) {
|
|||
|
const pos = this.state.start;
|
|||
|
const hasNamespace = super.maybeParseExportNamespaceSpecifier(node);
|
|||
|
|
|||
|
if (hasNamespace && node.exportKind === "type") {
|
|||
|
this.unexpected(pos);
|
|||
|
}
|
|||
|
|
|||
|
return hasNamespace;
|
|||
|
}
|
|||
|
|
|||
|
parseClassId(node, isStatement, optionalId) {
|
|||
|
super.parseClassId(node, isStatement, optionalId);
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
getTokenFromCode(code) {
|
|||
|
const next = this.input.charCodeAt(this.state.pos + 1);
|
|||
|
|
|||
|
if (code === 123 && next === 124) {
|
|||
|
return this.finishOp(_types.types.braceBarL, 2);
|
|||
|
} else if (this.state.inType && (code === 62 || code === 60)) {
|
|||
|
return this.finishOp(_types.types.relational, 1);
|
|||
|
} else if ((0, _identifier.isIteratorStart)(code, next)) {
|
|||
|
this.state.isIterator = true;
|
|||
|
return super.readWord();
|
|||
|
} else {
|
|||
|
return super.getTokenFromCode(code);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
isAssignable(node, isBinding) {
|
|||
|
switch (node.type) {
|
|||
|
case "Identifier":
|
|||
|
case "ObjectPattern":
|
|||
|
case "ArrayPattern":
|
|||
|
case "AssignmentPattern":
|
|||
|
return true;
|
|||
|
|
|||
|
case "ObjectExpression":
|
|||
|
{
|
|||
|
const last = node.properties.length - 1;
|
|||
|
return node.properties.every((prop, i) => {
|
|||
|
return prop.type !== "ObjectMethod" && (i === last || prop.type === "SpreadElement") && this.isAssignable(prop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
case "ObjectProperty":
|
|||
|
return this.isAssignable(node.value);
|
|||
|
|
|||
|
case "SpreadElement":
|
|||
|
return this.isAssignable(node.argument);
|
|||
|
|
|||
|
case "ArrayExpression":
|
|||
|
return node.elements.every(element => this.isAssignable(element));
|
|||
|
|
|||
|
case "AssignmentExpression":
|
|||
|
return node.operator === "=";
|
|||
|
|
|||
|
case "ParenthesizedExpression":
|
|||
|
case "TypeCastExpression":
|
|||
|
return this.isAssignable(node.expression);
|
|||
|
|
|||
|
case "MemberExpression":
|
|||
|
case "OptionalMemberExpression":
|
|||
|
return !isBinding;
|
|||
|
|
|||
|
default:
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
toAssignable(node, isBinding, contextDescription) {
|
|||
|
if (node.type === "TypeCastExpression") {
|
|||
|
return super.toAssignable(this.typeCastToParameter(node), isBinding, contextDescription);
|
|||
|
} else {
|
|||
|
return super.toAssignable(node, isBinding, contextDescription);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
toAssignableList(exprList, isBinding, contextDescription, trailingCommaPos) {
|
|||
|
for (let i = 0; i < exprList.length; i++) {
|
|||
|
const expr = exprList[i];
|
|||
|
|
|||
|
if (expr && expr.type === "TypeCastExpression") {
|
|||
|
exprList[i] = this.typeCastToParameter(expr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return super.toAssignableList(exprList, isBinding, contextDescription, trailingCommaPos);
|
|||
|
}
|
|||
|
|
|||
|
toReferencedList(exprList, isParenthesizedExpr) {
|
|||
|
for (let i = 0; i < exprList.length; i++) {
|
|||
|
const expr = exprList[i];
|
|||
|
|
|||
|
if (expr && expr.type === "TypeCastExpression" && (!expr.extra || !expr.extra.parenthesized) && (exprList.length > 1 || !isParenthesizedExpr)) {
|
|||
|
this.raise(expr.typeAnnotation.start, "The type cast expression is expected to be wrapped with parenthesis");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return exprList;
|
|||
|
}
|
|||
|
|
|||
|
checkLVal(expr, bindingType = _scopeflags.BIND_NONE, checkClashes, contextDescription) {
|
|||
|
if (expr.type !== "TypeCastExpression") {
|
|||
|
return super.checkLVal(expr, bindingType, checkClashes, contextDescription);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
parseClassProperty(node) {
|
|||
|
if (this.match(_types.types.colon)) {
|
|||
|
node.typeAnnotation = this.flowParseTypeAnnotation();
|
|||
|
}
|
|||
|
|
|||
|
return super.parseClassProperty(node);
|
|||
|
}
|
|||
|
|
|||
|
parseClassPrivateProperty(node) {
|
|||
|
if (this.match(_types.types.colon)) {
|
|||
|
node.typeAnnotation = this.flowParseTypeAnnotation();
|
|||
|
}
|
|||
|
|
|||
|
return super.parseClassPrivateProperty(node);
|
|||
|
}
|
|||
|
|
|||
|
isClassMethod() {
|
|||
|
return this.isRelational("<") || super.isClassMethod();
|
|||
|
}
|
|||
|
|
|||
|
isClassProperty() {
|
|||
|
return this.match(_types.types.colon) || super.isClassProperty();
|
|||
|
}
|
|||
|
|
|||
|
isNonstaticConstructor(method) {
|
|||
|
return !this.match(_types.types.colon) && super.isNonstaticConstructor(method);
|
|||
|
}
|
|||
|
|
|||
|
pushClassMethod(classBody, method, isGenerator, isAsync, isConstructor, allowsDirectSuper) {
|
|||
|
if (method.variance) {
|
|||
|
this.unexpected(method.variance.start);
|
|||
|
}
|
|||
|
|
|||
|
delete method.variance;
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
method.typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
}
|
|||
|
|
|||
|
super.pushClassMethod(classBody, method, isGenerator, isAsync, isConstructor, allowsDirectSuper);
|
|||
|
}
|
|||
|
|
|||
|
pushClassPrivateMethod(classBody, method, isGenerator, isAsync) {
|
|||
|
if (method.variance) {
|
|||
|
this.unexpected(method.variance.start);
|
|||
|
}
|
|||
|
|
|||
|
delete method.variance;
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
method.typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
}
|
|||
|
|
|||
|
super.pushClassPrivateMethod(classBody, method, isGenerator, isAsync);
|
|||
|
}
|
|||
|
|
|||
|
parseClassSuper(node) {
|
|||
|
super.parseClassSuper(node);
|
|||
|
|
|||
|
if (node.superClass && this.isRelational("<")) {
|
|||
|
node.superTypeParameters = this.flowParseTypeParameterInstantiation();
|
|||
|
}
|
|||
|
|
|||
|
if (this.isContextual("implements")) {
|
|||
|
this.next();
|
|||
|
const implemented = node.implements = [];
|
|||
|
|
|||
|
do {
|
|||
|
const node = this.startNode();
|
|||
|
node.id = this.flowParseRestrictedIdentifier(true);
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
node.typeParameters = this.flowParseTypeParameterInstantiation();
|
|||
|
} else {
|
|||
|
node.typeParameters = null;
|
|||
|
}
|
|||
|
|
|||
|
implemented.push(this.finishNode(node, "ClassImplements"));
|
|||
|
} while (this.eat(_types.types.comma));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
parsePropertyName(node, isPrivateNameAllowed) {
|
|||
|
const variance = this.flowParseVariance();
|
|||
|
const key = super.parsePropertyName(node, isPrivateNameAllowed);
|
|||
|
node.variance = variance;
|
|||
|
return key;
|
|||
|
}
|
|||
|
|
|||
|
parseObjPropValue(prop, startPos, startLoc, isGenerator, isAsync, isPattern, refShorthandDefaultPos, containsEsc) {
|
|||
|
if (prop.variance) {
|
|||
|
this.unexpected(prop.variance.start);
|
|||
|
}
|
|||
|
|
|||
|
delete prop.variance;
|
|||
|
let typeParameters;
|
|||
|
|
|||
|
if (this.isRelational("<")) {
|
|||
|
typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
if (!this.match(_types.types.parenL)) this.unexpected();
|
|||
|
}
|
|||
|
|
|||
|
super.parseObjPropValue(prop, startPos, startLoc, isGenerator, isAsync, isPattern, refShorthandDefaultPos, containsEsc);
|
|||
|
|
|||
|
if (typeParameters) {
|
|||
|
(prop.value || prop).typeParameters = typeParameters;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
parseAssignableListItemTypes(param) {
|
|||
|
if (this.eat(_types.types.question)) {
|
|||
|
if (param.type !== "Identifier") {
|
|||
|
this.raise(param.start, "A binding pattern parameter cannot be optional in an implementation signature.");
|
|||
|
}
|
|||
|
|
|||
|
param.optional = true;
|
|||
|
}
|
|||
|
|
|||
|
if (this.match(_types.types.colon)) {
|
|||
|
param.typeAnnotation = this.flowParseTypeAnnotation();
|
|||
|
}
|
|||
|
|
|||
|
this.resetEndLocation(param);
|
|||
|
return param;
|
|||
|
}
|
|||
|
|
|||
|
parseMaybeDefault(startPos, startLoc, left) {
|
|||
|
const node = super.parseMaybeDefault(startPos, startLoc, left);
|
|||
|
|
|||
|
if (node.type === "AssignmentPattern" && node.typeAnnotation && node.right.start < node.typeAnnotation.start) {
|
|||
|
this.raise(node.typeAnnotation.start, "Type annotations must come before default assignments, " + "e.g. instead of `age = 25: number` use `age: number = 25`");
|
|||
|
}
|
|||
|
|
|||
|
return node;
|
|||
|
}
|
|||
|
|
|||
|
shouldParseDefaultImport(node) {
|
|||
|
if (!hasTypeImportKind(node)) {
|
|||
|
return super.shouldParseDefaultImport(node);
|
|||
|
}
|
|||
|
|
|||
|
return isMaybeDefaultImport(this.state);
|
|||
|
}
|
|||
|
|
|||
|
parseImportSpecifierLocal(node, specifier, type, contextDescription) {
|
|||
|
specifier.local = hasTypeImportKind(node) ? this.flowParseRestrictedIdentifier(true, true) : this.parseIdentifier();
|
|||
|
this.checkLVal(specifier.local, _scopeflags.BIND_LEXICAL, undefined, contextDescription);
|
|||
|
node.specifiers.push(this.finishNode(specifier, type));
|
|||
|
}
|
|||
|
|
|||
|
maybeParseDefaultImportSpecifier(node) {
|
|||
|
node.importKind = "value";
|
|||
|
let kind = null;
|
|||
|
|
|||
|
if (this.match(_types.types._typeof)) {
|
|||
|
kind = "typeof";
|
|||
|
} else if (this.isContextual("type")) {
|
|||
|
kind = "type";
|
|||
|
}
|
|||
|
|
|||
|
if (kind) {
|
|||
|
const lh = this.lookahead();
|
|||
|
|
|||
|
if (kind === "type" && lh.type === _types.types.star) {
|
|||
|
this.unexpected(lh.start);
|
|||
|
}
|
|||
|
|
|||
|
if (isMaybeDefaultImport(lh) || lh.type === _types.types.braceL || lh.type === _types.types.star) {
|
|||
|
this.next();
|
|||
|
node.importKind = kind;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return super.maybeParseDefaultImportSpecifier(node);
|
|||
|
}
|
|||
|
|
|||
|
parseImportSpecifier(node) {
|
|||
|
const specifier = this.startNode();
|
|||
|
const firstIdentLoc = this.state.start;
|
|||
|
const firstIdent = this.parseIdentifier(true);
|
|||
|
let specifierTypeKind = null;
|
|||
|
|
|||
|
if (firstIdent.name === "type") {
|
|||
|
specifierTypeKind = "type";
|
|||
|
} else if (firstIdent.name === "typeof") {
|
|||
|
specifierTypeKind = "typeof";
|
|||
|
}
|
|||
|
|
|||
|
let isBinding = false;
|
|||
|
|
|||
|
if (this.isContextual("as") && !this.isLookaheadContextual("as")) {
|
|||
|
const as_ident = this.parseIdentifier(true);
|
|||
|
|
|||
|
if (specifierTypeKind !== null && !this.match(_types.types.name) && !this.state.type.keyword) {
|
|||
|
specifier.imported = as_ident;
|
|||
|
specifier.importKind = specifierTypeKind;
|
|||
|
specifier.local = as_ident.__clone();
|
|||
|
} else {
|
|||
|
specifier.imported = firstIdent;
|
|||
|
specifier.importKind = null;
|
|||
|
specifier.local = this.parseIdentifier();
|
|||
|
}
|
|||
|
} else if (specifierTypeKind !== null && (this.match(_types.types.name) || this.state.type.keyword)) {
|
|||
|
specifier.imported = this.parseIdentifier(true);
|
|||
|
specifier.importKind = specifierTypeKind;
|
|||
|
|
|||
|
if (this.eatContextual("as")) {
|
|||
|
specifier.local = this.parseIdentifier();
|
|||
|
} else {
|
|||
|
isBinding = true;
|
|||
|
specifier.local = specifier.imported.__clone();
|
|||
|
}
|
|||
|
} else {
|
|||
|
isBinding = true;
|
|||
|
specifier.imported = firstIdent;
|
|||
|
specifier.importKind = null;
|
|||
|
specifier.local = specifier.imported.__clone();
|
|||
|
}
|
|||
|
|
|||
|
const nodeIsTypeImport = hasTypeImportKind(node);
|
|||
|
const specifierIsTypeImport = hasTypeImportKind(specifier);
|
|||
|
|
|||
|
if (nodeIsTypeImport && specifierIsTypeImport) {
|
|||
|
this.raise(firstIdentLoc, "The `type` and `typeof` keywords on named imports can only be used on regular " + "`import` statements. It cannot be used with `import type` or `import typeof` statements");
|
|||
|
}
|
|||
|
|
|||
|
if (nodeIsTypeImport || specifierIsTypeImport) {
|
|||
|
this.checkReservedType(specifier.local.name, specifier.local.start, true);
|
|||
|
}
|
|||
|
|
|||
|
if (isBinding && !nodeIsTypeImport && !specifierIsTypeImport) {
|
|||
|
this.checkReservedWord(specifier.local.name, specifier.start, true, true);
|
|||
|
}
|
|||
|
|
|||
|
this.checkLVal(specifier.local, _scopeflags.BIND_LEXICAL, undefined, "import specifier");
|
|||
|
node.specifiers.push(this.finishNode(specifier, "ImportSpecifier"));
|
|||
|
}
|
|||
|
|
|||
|
parseFunctionParams(node, allowModifiers) {
|
|||
|
const kind = node.kind;
|
|||
|
|
|||
|
if (kind !== "get" && kind !== "set" && this.isRelational("<")) {
|
|||
|
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
}
|
|||
|
|
|||
|
super.parseFunctionParams(node, allowModifiers);
|
|||
|
}
|
|||
|
|
|||
|
parseVarId(decl, kind) {
|
|||
|
super.parseVarId(decl, kind);
|
|||
|
|
|||
|
if (this.match(_types.types.colon)) {
|
|||
|
decl.id.typeAnnotation = this.flowParseTypeAnnotation();
|
|||
|
this.resetEndLocation(decl.id);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
parseAsyncArrowFromCallExpression(node, call) {
|
|||
|
if (this.match(_types.types.colon)) {
|
|||
|
const oldNoAnonFunctionType = this.state.noAnonFunctionType;
|
|||
|
this.state.noAnonFunctionType = true;
|
|||
|
node.returnType = this.flowParseTypeAnnotation();
|
|||
|
this.state.noAnonFunctionType = oldNoAnonFunctionType;
|
|||
|
}
|
|||
|
|
|||
|
return super.parseAsyncArrowFromCallExpression(node, call);
|
|||
|
}
|
|||
|
|
|||
|
shouldParseAsyncArrow() {
|
|||
|
return this.match(_types.types.colon) || super.shouldParseAsyncArrow();
|
|||
|
}
|
|||
|
|
|||
|
parseMaybeAssign(noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos) {
|
|||
|
let state = null;
|
|||
|
let jsx;
|
|||
|
|
|||
|
if (this.hasPlugin("jsx") && (this.match(_types.types.jsxTagStart) || this.isRelational("<"))) {
|
|||
|
state = this.state.clone();
|
|||
|
jsx = this.tryParse(() => super.parseMaybeAssign(noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos), state);
|
|||
|
if (!jsx.error) return jsx.node;
|
|||
|
const {
|
|||
|
context
|
|||
|
} = this.state;
|
|||
|
|
|||
|
if (context[context.length - 1] === _context.types.j_oTag) {
|
|||
|
context.length -= 2;
|
|||
|
} else if (context[context.length - 1] === _context.types.j_expr) {
|
|||
|
context.length -= 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (jsx && jsx.error || this.isRelational("<")) {
|
|||
|
state = state || this.state.clone();
|
|||
|
let typeParameters;
|
|||
|
const arrow = this.tryParse(() => {
|
|||
|
typeParameters = this.flowParseTypeParameterDeclaration();
|
|||
|
const arrowExpression = this.forwardNoArrowParamsConversionAt(typeParameters, () => super.parseMaybeAssign(noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos));
|
|||
|
arrowExpression.typeParameters = typeParameters;
|
|||
|
this.resetStartLocationFromNode(arrowExpression, typeParameters);
|
|||
|
return arrowExpression;
|
|||
|
}, state);
|
|||
|
const arrowExpression = arrow.node && arrow.node.type === "ArrowFunctionExpression" ? arrow.node : null;
|
|||
|
if (!arrow.error && arrowExpression) return arrowExpression;
|
|||
|
|
|||
|
if (jsx && jsx.node) {
|
|||
|
this.state = jsx.failState;
|
|||
|
return jsx.node;
|
|||
|
}
|
|||
|
|
|||
|
if (arrowExpression) {
|
|||
|
this.state = arrow.failState;
|
|||
|
return arrowExpression;
|
|||
|
}
|
|||
|
|
|||
|
if (jsx && jsx.thrown) throw jsx.error;
|
|||
|
if (arrow.thrown) throw arrow.error;
|
|||
|
throw this.raise(typeParameters.start, "Expected an arrow function after this type parameter declaration");
|
|||
|
}
|
|||
|
|
|||
|
return super.parseMaybeAssign(noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos);
|
|||
|
}
|
|||
|
|
|||
|
parseArrow(node) {
|
|||
|
if (this.match(_types.types.colon)) {
|
|||
|
const result = this.tryParse(() => {
|
|||
|
const oldNoAnonFunctionType = this.state.noAnonFunctionType;
|
|||
|
this.state.noAnonFunctionType = true;
|
|||
|
const typeNode = this.startNode();
|
|||
|
[typeNode.typeAnnotation, node.predicate] = this.flowParseTypeAndPredicateInitialiser();
|
|||
|
this.state.noAnonFunctionType = oldNoAnonFunctionType;
|
|||
|
if (this.canInsertSemicolon()) this.unexpected();
|
|||
|
if (!this.match(_types.types.arrow)) this.unexpected();
|
|||
|
return typeNode;
|
|||
|
});
|
|||
|
if (result.thrown) return null;
|
|||
|
if (result.error) this.state = result.failState;
|
|||
|
node.returnType = result.node.typeAnnotation ? this.finishNode(result.node, "TypeAnnotation") : null;
|
|||
|
}
|
|||
|
|
|||
|
return super.parseArrow(node);
|
|||
|
}
|
|||
|
|
|||
|
shouldParseArrow() {
|
|||
|
return this.match(_types.types.colon) || super.shouldParseArrow();
|
|||
|
}
|
|||
|
|
|||
|
setArrowFunctionParameters(node, params) {
|
|||
|
if (this.state.noArrowParamsConversionAt.indexOf(node.start) !== -1) {
|
|||
|
node.params = params;
|
|||
|
} else {
|
|||
|
super.setArrowFunctionParameters(node, params);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
checkParams(node, allowDuplicates, isArrowFunction) {
|
|||
|
if (isArrowFunction && this.state.noArrowParamsConversionAt.indexOf(node.start) !== -1) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
return super.checkParams(...arguments);
|
|||
|
}
|
|||
|
|
|||
|
parseParenAndDistinguishExpression(canBeArrow) {
|
|||
|
return super.parseParenAndDistinguishExpression(canBeArrow && this.state.noArrowAt.indexOf(this.state.start) === -1);
|
|||
|
}
|
|||
|
|
|||
|
parseSubscripts(base, startPos, startLoc, noCalls) {
|
|||
|
if (base.type === "Identifier" && base.name === "async" && this.state.noArrowAt.indexOf(startPos) !== -1) {
|
|||
|
this.next();
|
|||
|
const node = this.startNodeAt(startPos, startLoc);
|
|||
|
node.callee = base;
|
|||
|
node.arguments = this.parseCallExpressionArguments(_types.types.parenR, false);
|
|||
|
base = this.finishNode(node, "CallExpression");
|
|||
|
} else if (base.type === "Identifier" && base.name === "async" && this.isRelational("<")) {
|
|||
|
const state = this.state.clone();
|
|||
|
const arrow = this.tryParse(abort => this.parseAsyncArrowWithTypeParameters(startPos, startLoc) || abort(), state);
|
|||
|
if (!arrow.error && !arrow.aborted) return arrow.node;
|
|||
|
const result = this.tryParse(() => super.parseSubscripts(base, startPos, startLoc, noCalls), state);
|
|||
|
if (result.node && !result.error) return result.node;
|
|||
|
|
|||
|
if (arrow.node) {
|
|||
|
this.state = arrow.failState;
|
|||
|
return arrow.node;
|
|||
|
}
|
|||
|
|
|||
|
if (result.node) {
|
|||
|
this.state = result.failState;
|
|||
|
return result.node;
|
|||
|
}
|
|||
|
|
|||
|
throw arrow.error || result.error;
|
|||
|
}
|
|||
|
|
|||
|
return super.parseSubscripts(base, startPos, startLoc, noCalls);
|
|||
|
}
|
|||
|
|
|||
|
parseSubscript(base, startPos, startLoc, noCalls, subscriptState) {
|
|||
|
if (this.match(_types.types.questionDot) && this.isLookaheadRelational("<")) {
|
|||
|
subscriptState.optionalChainMember = true;
|
|||
|
|
|||
|
if (noCalls) {
|
|||
|
subscriptState.stop = true;
|
|||
|
return base;
|
|||
|
}
|
|||
|
|
|||
|
this.next();
|
|||
|
const node = this.startNodeAt(startPos, startLoc);
|
|||
|
node.callee = base;
|
|||
|
node.typeArguments = this.flowParseTypeParameterInstantiation();
|
|||
|
this.expect(_types.types.parenL);
|
|||
|
node.arguments = this.parseCallExpressionArguments(_types.types.parenR, false);
|
|||
|
node.optional = true;
|
|||
|
return this.finishCallExpression(node, true);
|
|||
|
} else if (!noCalls && this.shouldParseTypes() && this.isRelational("<")) {
|
|||
|
const node = this.startNodeAt(startPos, startLoc);
|
|||
|
node.callee = base;
|
|||
|
const result = this.tryParse(() => {
|
|||
|
node.typeArguments = this.flowParseTypeParameterInstantiationCallOrNew();
|
|||
|
this.expect(_types.types.parenL);
|
|||
|
node.arguments = this.parseCallExpressionArguments(_types.types.parenR, false);
|
|||
|
if (subscriptState.optionalChainMember) node.optional = false;
|
|||
|
return this.finishCallExpression(node, subscriptState.optionalChainMember);
|
|||
|
});
|
|||
|
|
|||
|
if (result.node) {
|
|||
|
if (result.error) this.state = result.failState;
|
|||
|
return result.node;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return super.parseSubscript(base, startPos, startLoc, noCalls, subscriptState);
|
|||
|
}
|
|||
|
|
|||
|
parseNewArguments(node) {
|
|||
|
let targs = null;
|
|||
|
|
|||
|
if (this.shouldParseTypes() && this.isRelational("<")) {
|
|||
|
targs = this.tryParse(() => this.flowParseTypeParameterInstantiationCallOrNew()).node;
|
|||
|
}
|
|||
|
|
|||
|
node.typeArguments = targs;
|
|||
|
super.parseNewArguments(node);
|
|||
|
}
|
|||
|
|
|||
|
parseAsyncArrowWithTypeParameters(startPos, startLoc) {
|
|||
|
const node = this.startNodeAt(startPos, startLoc);
|
|||
|
this.parseFunctionParams(node);
|
|||
|
if (!this.parseArrow(node)) return;
|
|||
|
return this.parseArrowExpression(node, undefined, true);
|
|||
|
}
|
|||
|
|
|||
|
readToken_mult_modulo(code) {
|
|||
|
const next = this.input.charCodeAt(this.state.pos + 1);
|
|||
|
|
|||
|
if (code === 42 && next === 47 && this.state.hasFlowComment) {
|
|||
|
this.state.hasFlowComment = false;
|
|||
|
this.state.pos += 2;
|
|||
|
this.nextToken();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
super.readToken_mult_modulo(code);
|
|||
|
}
|
|||
|
|
|||
|
readToken_pipe_amp(code) {
|
|||
|
const next = this.input.charCodeAt(this.state.pos + 1);
|
|||
|
|
|||
|
if (code === 124 && next === 125) {
|
|||
|
this.finishOp(_types.types.braceBarR, 2);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
super.readToken_pipe_amp(code);
|
|||
|
}
|
|||
|
|
|||
|
parseTopLevel(file, program) {
|
|||
|
const fileNode = super.parseTopLevel(file, program);
|
|||
|
|
|||
|
if (this.state.hasFlowComment) {
|
|||
|
this.raise(this.state.pos, "Unterminated flow-comment");
|
|||
|
}
|
|||
|
|
|||
|
return fileNode;
|
|||
|
}
|
|||
|
|
|||
|
skipBlockComment() {
|
|||
|
if (this.hasPlugin("flowComments") && this.skipFlowComment()) {
|
|||
|
if (this.state.hasFlowComment) {
|
|||
|
this.unexpected(null, "Cannot have a flow comment inside another flow comment");
|
|||
|
}
|
|||
|
|
|||
|
this.hasFlowCommentCompletion();
|
|||
|
this.state.pos += this.skipFlowComment();
|
|||
|
this.state.hasFlowComment = true;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (this.state.hasFlowComment) {
|
|||
|
const end = this.input.indexOf("*-/", this.state.pos += 2);
|
|||
|
|
|||
|
if (end === -1) {
|
|||
|
throw this.raise(this.state.pos - 2, "Unterminated comment");
|
|||
|
}
|
|||
|
|
|||
|
this.state.pos = end + 3;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
super.skipBlockComment();
|
|||
|
}
|
|||
|
|
|||
|
skipFlowComment() {
|
|||
|
const {
|
|||
|
pos
|
|||
|
} = this.state;
|
|||
|
let shiftToFirstNonWhiteSpace = 2;
|
|||
|
|
|||
|
while ([32, 9].includes(this.input.charCodeAt(pos + shiftToFirstNonWhiteSpace))) {
|
|||
|
shiftToFirstNonWhiteSpace++;
|
|||
|
}
|
|||
|
|
|||
|
const ch2 = this.input.charCodeAt(shiftToFirstNonWhiteSpace + pos);
|
|||
|
const ch3 = this.input.charCodeAt(shiftToFirstNonWhiteSpace + pos + 1);
|
|||
|
|
|||
|
if (ch2 === 58 && ch3 === 58) {
|
|||
|
return shiftToFirstNonWhiteSpace + 2;
|
|||
|
}
|
|||
|
|
|||
|
if (this.input.slice(shiftToFirstNonWhiteSpace + pos, shiftToFirstNonWhiteSpace + pos + 12) === "flow-include") {
|
|||
|
return shiftToFirstNonWhiteSpace + 12;
|
|||
|
}
|
|||
|
|
|||
|
if (ch2 === 58 && ch3 !== 58) {
|
|||
|
return shiftToFirstNonWhiteSpace;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
hasFlowCommentCompletion() {
|
|||
|
const end = this.input.indexOf("*/", this.state.pos);
|
|||
|
|
|||
|
if (end === -1) {
|
|||
|
throw this.raise(this.state.pos, "Unterminated comment");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowEnumErrorBooleanMemberNotInitialized(pos, {
|
|||
|
enumName,
|
|||
|
memberName
|
|||
|
}) {
|
|||
|
this.raise(pos, `Boolean enum members need to be initialized. Use either \`${memberName} = true,\` ` + `or \`${memberName} = false,\` in enum \`${enumName}\`.`);
|
|||
|
}
|
|||
|
|
|||
|
flowEnumErrorInvalidMemberName(pos, {
|
|||
|
enumName,
|
|||
|
memberName
|
|||
|
}) {
|
|||
|
const suggestion = memberName[0].toUpperCase() + memberName.slice(1);
|
|||
|
this.raise(pos, `Enum member names cannot start with lowercase 'a' through 'z'. Instead of using ` + `\`${memberName}\`, consider using \`${suggestion}\`, in enum \`${enumName}\`.`);
|
|||
|
}
|
|||
|
|
|||
|
flowEnumErrorDuplicateMemberName(pos, {
|
|||
|
enumName,
|
|||
|
memberName
|
|||
|
}) {
|
|||
|
this.raise(pos, `Enum member names need to be unique, but the name \`${memberName}\` has already been used ` + `before in enum \`${enumName}\`.`);
|
|||
|
}
|
|||
|
|
|||
|
flowEnumErrorInconsistentMemberValues(pos, {
|
|||
|
enumName
|
|||
|
}) {
|
|||
|
this.raise(pos, `Enum \`${enumName}\` has inconsistent member initializers. Either use no initializers, or ` + `consistently use literals (either booleans, numbers, or strings) for all member initializers.`);
|
|||
|
}
|
|||
|
|
|||
|
flowEnumErrorInvalidExplicitType(pos, {
|
|||
|
enumName,
|
|||
|
suppliedType
|
|||
|
}) {
|
|||
|
const suggestion = `Use one of \`boolean\`, \`number\`, \`string\`, or \`symbol\` in ` + `enum \`${enumName}\`.`;
|
|||
|
const message = suppliedType === null ? `Supplied enum type is not valid. ${suggestion}` : `Enum type \`${suppliedType}\` is not valid. ${suggestion}`;
|
|||
|
return this.raise(pos, message);
|
|||
|
}
|
|||
|
|
|||
|
flowEnumErrorInvalidMemberInitializer(pos, {
|
|||
|
enumName,
|
|||
|
explicitType,
|
|||
|
memberName
|
|||
|
}) {
|
|||
|
let message = null;
|
|||
|
|
|||
|
switch (explicitType) {
|
|||
|
case "boolean":
|
|||
|
case "number":
|
|||
|
case "string":
|
|||
|
message = `Enum \`${enumName}\` has type \`${explicitType}\`, so the initializer of ` + `\`${memberName}\` needs to be a ${explicitType} literal.`;
|
|||
|
break;
|
|||
|
|
|||
|
case "symbol":
|
|||
|
message = `Symbol enum members cannot be initialized. Use \`${memberName},\` in ` + `enum \`${enumName}\`.`;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
message = `The enum member initializer for \`${memberName}\` needs to be a literal (either ` + `a boolean, number, or string) in enum \`${enumName}\`.`;
|
|||
|
}
|
|||
|
|
|||
|
return this.raise(pos, message);
|
|||
|
}
|
|||
|
|
|||
|
flowEnumErrorNumberMemberNotInitialized(pos, {
|
|||
|
enumName,
|
|||
|
memberName
|
|||
|
}) {
|
|||
|
this.raise(pos, `Number enum members need to be initialized, e.g. \`${memberName} = 1\` in enum \`${enumName}\`.`);
|
|||
|
}
|
|||
|
|
|||
|
flowEnumErrorStringMemberInconsistentlyInitailized(pos, {
|
|||
|
enumName
|
|||
|
}) {
|
|||
|
this.raise(pos, `String enum members need to consistently either all use initializers, or use no initializers, ` + `in enum \`${enumName}\`.`);
|
|||
|
}
|
|||
|
|
|||
|
flowEnumMemberInit() {
|
|||
|
const startPos = this.state.start;
|
|||
|
|
|||
|
const endOfInit = () => this.match(_types.types.comma) || this.match(_types.types.braceR);
|
|||
|
|
|||
|
switch (this.state.type) {
|
|||
|
case _types.types.num:
|
|||
|
{
|
|||
|
const literal = this.parseLiteral(this.state.value, "NumericLiteral");
|
|||
|
|
|||
|
if (endOfInit()) {
|
|||
|
return {
|
|||
|
type: "number",
|
|||
|
pos: literal.start,
|
|||
|
value: literal
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
return {
|
|||
|
type: "invalid",
|
|||
|
pos: startPos
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
case _types.types.string:
|
|||
|
{
|
|||
|
const literal = this.parseLiteral(this.state.value, "StringLiteral");
|
|||
|
|
|||
|
if (endOfInit()) {
|
|||
|
return {
|
|||
|
type: "string",
|
|||
|
pos: literal.start,
|
|||
|
value: literal
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
return {
|
|||
|
type: "invalid",
|
|||
|
pos: startPos
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
case _types.types._true:
|
|||
|
case _types.types._false:
|
|||
|
{
|
|||
|
const literal = this.parseBooleanLiteral();
|
|||
|
|
|||
|
if (endOfInit()) {
|
|||
|
return {
|
|||
|
type: "boolean",
|
|||
|
pos: literal.start,
|
|||
|
value: literal
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
return {
|
|||
|
type: "invalid",
|
|||
|
pos: startPos
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
default:
|
|||
|
return {
|
|||
|
type: "invalid",
|
|||
|
pos: startPos
|
|||
|
};
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowEnumMemberRaw() {
|
|||
|
const pos = this.state.start;
|
|||
|
const id = this.parseIdentifier(true);
|
|||
|
const init = this.eat(_types.types.eq) ? this.flowEnumMemberInit() : {
|
|||
|
type: "none",
|
|||
|
pos
|
|||
|
};
|
|||
|
return {
|
|||
|
id,
|
|||
|
init
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
flowEnumCheckExplicitTypeMismatch(pos, context, expectedType) {
|
|||
|
const {
|
|||
|
explicitType
|
|||
|
} = context;
|
|||
|
|
|||
|
if (explicitType === null) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (explicitType !== expectedType) {
|
|||
|
this.flowEnumErrorInvalidMemberInitializer(pos, context);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowEnumMembers({
|
|||
|
enumName,
|
|||
|
explicitType
|
|||
|
}) {
|
|||
|
const seenNames = new Set();
|
|||
|
const members = {
|
|||
|
booleanMembers: [],
|
|||
|
numberMembers: [],
|
|||
|
stringMembers: [],
|
|||
|
defaultedMembers: []
|
|||
|
};
|
|||
|
|
|||
|
while (!this.match(_types.types.braceR)) {
|
|||
|
const memberNode = this.startNode();
|
|||
|
const {
|
|||
|
id,
|
|||
|
init
|
|||
|
} = this.flowEnumMemberRaw();
|
|||
|
const memberName = id.name;
|
|||
|
|
|||
|
if (memberName === "") {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (/^[a-z]/.test(memberName)) {
|
|||
|
this.flowEnumErrorInvalidMemberName(id.start, {
|
|||
|
enumName,
|
|||
|
memberName
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
if (seenNames.has(memberName)) {
|
|||
|
this.flowEnumErrorDuplicateMemberName(id.start, {
|
|||
|
enumName,
|
|||
|
memberName
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
seenNames.add(memberName);
|
|||
|
const context = {
|
|||
|
enumName,
|
|||
|
explicitType,
|
|||
|
memberName
|
|||
|
};
|
|||
|
memberNode.id = id;
|
|||
|
|
|||
|
switch (init.type) {
|
|||
|
case "boolean":
|
|||
|
{
|
|||
|
this.flowEnumCheckExplicitTypeMismatch(init.pos, context, "boolean");
|
|||
|
memberNode.init = init.value;
|
|||
|
members.booleanMembers.push(this.finishNode(memberNode, "EnumBooleanMember"));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case "number":
|
|||
|
{
|
|||
|
this.flowEnumCheckExplicitTypeMismatch(init.pos, context, "number");
|
|||
|
memberNode.init = init.value;
|
|||
|
members.numberMembers.push(this.finishNode(memberNode, "EnumNumberMember"));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case "string":
|
|||
|
{
|
|||
|
this.flowEnumCheckExplicitTypeMismatch(init.pos, context, "string");
|
|||
|
memberNode.init = init.value;
|
|||
|
members.stringMembers.push(this.finishNode(memberNode, "EnumStringMember"));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case "invalid":
|
|||
|
{
|
|||
|
throw this.flowEnumErrorInvalidMemberInitializer(init.pos, context);
|
|||
|
}
|
|||
|
|
|||
|
case "none":
|
|||
|
{
|
|||
|
switch (explicitType) {
|
|||
|
case "boolean":
|
|||
|
this.flowEnumErrorBooleanMemberNotInitialized(init.pos, context);
|
|||
|
break;
|
|||
|
|
|||
|
case "number":
|
|||
|
this.flowEnumErrorNumberMemberNotInitialized(init.pos, context);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
members.defaultedMembers.push(this.finishNode(memberNode, "EnumDefaultedMember"));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!this.match(_types.types.braceR)) {
|
|||
|
this.expect(_types.types.comma);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return members;
|
|||
|
}
|
|||
|
|
|||
|
flowEnumStringMembers(initializedMembers, defaultedMembers, {
|
|||
|
enumName
|
|||
|
}) {
|
|||
|
if (initializedMembers.length === 0) {
|
|||
|
return defaultedMembers;
|
|||
|
} else if (defaultedMembers.length === 0) {
|
|||
|
return initializedMembers;
|
|||
|
} else if (defaultedMembers.length > initializedMembers.length) {
|
|||
|
for (let _i = 0; _i < initializedMembers.length; _i++) {
|
|||
|
const member = initializedMembers[_i];
|
|||
|
this.flowEnumErrorStringMemberInconsistentlyInitailized(member.start, {
|
|||
|
enumName
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
return defaultedMembers;
|
|||
|
} else {
|
|||
|
for (let _i2 = 0; _i2 < defaultedMembers.length; _i2++) {
|
|||
|
const member = defaultedMembers[_i2];
|
|||
|
this.flowEnumErrorStringMemberInconsistentlyInitailized(member.start, {
|
|||
|
enumName
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
return initializedMembers;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowEnumParseExplicitType({
|
|||
|
enumName
|
|||
|
}) {
|
|||
|
if (this.eatContextual("of")) {
|
|||
|
if (!this.match(_types.types.name)) {
|
|||
|
throw this.flowEnumErrorInvalidExplicitType(this.state.start, {
|
|||
|
enumName,
|
|||
|
suppliedType: null
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
const {
|
|||
|
value
|
|||
|
} = this.state;
|
|||
|
this.next();
|
|||
|
|
|||
|
if (value !== "boolean" && value !== "number" && value !== "string" && value !== "symbol") {
|
|||
|
this.flowEnumErrorInvalidExplicitType(this.state.start, {
|
|||
|
enumName,
|
|||
|
suppliedType: value
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
return value;
|
|||
|
}
|
|||
|
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
flowEnumBody(node, {
|
|||
|
enumName,
|
|||
|
nameLoc
|
|||
|
}) {
|
|||
|
const explicitType = this.flowEnumParseExplicitType({
|
|||
|
enumName
|
|||
|
});
|
|||
|
this.expect(_types.types.braceL);
|
|||
|
const members = this.flowEnumMembers({
|
|||
|
enumName,
|
|||
|
explicitType
|
|||
|
});
|
|||
|
|
|||
|
switch (explicitType) {
|
|||
|
case "boolean":
|
|||
|
node.explicitType = true;
|
|||
|
node.members = members.booleanMembers;
|
|||
|
this.expect(_types.types.braceR);
|
|||
|
return this.finishNode(node, "EnumBooleanBody");
|
|||
|
|
|||
|
case "number":
|
|||
|
node.explicitType = true;
|
|||
|
node.members = members.numberMembers;
|
|||
|
this.expect(_types.types.braceR);
|
|||
|
return this.finishNode(node, "EnumNumberBody");
|
|||
|
|
|||
|
case "string":
|
|||
|
node.explicitType = true;
|
|||
|
node.members = this.flowEnumStringMembers(members.stringMembers, members.defaultedMembers, {
|
|||
|
enumName
|
|||
|
});
|
|||
|
this.expect(_types.types.braceR);
|
|||
|
return this.finishNode(node, "EnumStringBody");
|
|||
|
|
|||
|
case "symbol":
|
|||
|
node.members = members.defaultedMembers;
|
|||
|
this.expect(_types.types.braceR);
|
|||
|
return this.finishNode(node, "EnumSymbolBody");
|
|||
|
|
|||
|
default:
|
|||
|
{
|
|||
|
const empty = () => {
|
|||
|
node.members = [];
|
|||
|
this.expect(_types.types.braceR);
|
|||
|
return this.finishNode(node, "EnumStringBody");
|
|||
|
};
|
|||
|
|
|||
|
node.explicitType = false;
|
|||
|
const boolsLen = members.booleanMembers.length;
|
|||
|
const numsLen = members.numberMembers.length;
|
|||
|
const strsLen = members.stringMembers.length;
|
|||
|
const defaultedLen = members.defaultedMembers.length;
|
|||
|
|
|||
|
if (!boolsLen && !numsLen && !strsLen && !defaultedLen) {
|
|||
|
return empty();
|
|||
|
} else if (!boolsLen && !numsLen) {
|
|||
|
node.members = this.flowEnumStringMembers(members.stringMembers, members.defaultedMembers, {
|
|||
|
enumName
|
|||
|
});
|
|||
|
this.expect(_types.types.braceR);
|
|||
|
return this.finishNode(node, "EnumStringBody");
|
|||
|
} else if (!numsLen && !strsLen && boolsLen >= defaultedLen) {
|
|||
|
for (let _i3 = 0, _members$defaultedMem = members.defaultedMembers; _i3 < _members$defaultedMem.length; _i3++) {
|
|||
|
const member = _members$defaultedMem[_i3];
|
|||
|
this.flowEnumErrorBooleanMemberNotInitialized(member.start, {
|
|||
|
enumName,
|
|||
|
memberName: member.id.name
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
node.members = members.booleanMembers;
|
|||
|
this.expect(_types.types.braceR);
|
|||
|
return this.finishNode(node, "EnumBooleanBody");
|
|||
|
} else if (!boolsLen && !strsLen && numsLen >= defaultedLen) {
|
|||
|
for (let _i4 = 0, _members$defaultedMem2 = members.defaultedMembers; _i4 < _members$defaultedMem2.length; _i4++) {
|
|||
|
const member = _members$defaultedMem2[_i4];
|
|||
|
this.flowEnumErrorNumberMemberNotInitialized(member.start, {
|
|||
|
enumName,
|
|||
|
memberName: member.id.name
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
node.members = members.numberMembers;
|
|||
|
this.expect(_types.types.braceR);
|
|||
|
return this.finishNode(node, "EnumNumberBody");
|
|||
|
} else {
|
|||
|
this.flowEnumErrorInconsistentMemberValues(nameLoc, {
|
|||
|
enumName
|
|||
|
});
|
|||
|
return empty();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flowParseEnumDeclaration(node) {
|
|||
|
const id = this.parseIdentifier();
|
|||
|
node.id = id;
|
|||
|
node.body = this.flowEnumBody(this.startNode(), {
|
|||
|
enumName: id.name,
|
|||
|
nameLoc: id.start
|
|||
|
});
|
|||
|
return this.finishNode(node, "EnumDeclaration");
|
|||
|
}
|
|||
|
|
|||
|
};
|
|||
|
|
|||
|
exports.default = _default;
|