0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-04 09:57:11 -05:00
deno/cli/js/40_lint.js

4209 lines
95 KiB
JavaScript
Raw Normal View History

2024-12-04 02:59:39 +01:00
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2024-12-06 23:26:11 +01:00
// @ts-check
2024-12-04 02:59:39 +01:00
import { core } from "ext:core/mod.js";
const {
2024-12-03 13:45:31 +01:00
op_lint_get_rule,
op_lint_get_source,
op_lint_report,
2024-12-04 02:59:39 +01:00
} = core.ops;
2024-12-01 04:53:47 +01:00
2024-12-10 04:33:33 +01:00
/** @typedef {{ plugins: Deno.LintPlugin[], installedPlugins: Set<string> }} LintState */
2024-12-04 12:42:55 +01:00
/** @type {LintState} */
const state = {
2024-12-04 12:42:55 +01:00
plugins: [],
2024-12-10 04:33:33 +01:00
installedPlugins: new Set(),
};
2024-12-07 00:24:36 +01:00
/** @implements {Deno.LintRuleContext} */
2024-12-01 04:53:47 +01:00
export class Context {
id;
fileName;
2024-12-04 12:42:55 +01:00
#source = null;
2024-12-06 23:26:11 +01:00
/**
* @param {string} id
* @param {string} fileName
*/
2024-12-01 04:53:47 +01:00
constructor(id, fileName) {
this.id = id;
this.fileName = fileName;
}
2024-12-03 13:45:31 +01:00
source() {
2024-12-04 12:42:55 +01:00
if (this.#source === null) {
this.#source = op_lint_get_source();
}
2024-12-07 00:24:36 +01:00
return /** @type {*} */ (this.#source);
2024-12-03 13:45:31 +01:00
}
2024-12-02 02:27:30 +01:00
report(data) {
2024-12-03 03:11:26 +01:00
let start, end;
if (data.node) {
2024-12-12 20:53:08 +01:00
start = data.node.range[0] - 1;
end = data.node.range[1] - 1;
} else if (data.range) {
start = data.range[0] - 1;
end = data.range[1] - 1;
2024-12-03 03:11:26 +01:00
} else {
throw new Error(
"Either `node` or `span` must be provided when reporting an error",
);
}
2024-12-02 18:29:30 +01:00
op_lint_report(
this.id,
this.fileName,
data.message,
2024-12-03 03:11:26 +01:00
start,
end,
2024-12-02 18:29:30 +01:00
);
2024-12-01 04:53:47 +01:00
}
}
2024-12-10 04:33:33 +01:00
/**
* @param {Deno.LintPlugin} plugin
*/
2024-12-04 04:30:32 +01:00
export function installPlugin(plugin) {
if (typeof plugin !== "object") {
throw new Error("Linter plugin must be an object");
}
if (typeof plugin.name !== "string") {
throw new Error("Linter plugin name must be a string");
}
if (typeof plugin.rules !== "object") {
throw new Error("Linter plugin rules must be an object");
}
2024-12-10 04:33:33 +01:00
if (state.installedPlugins.has(plugin.name)) {
2024-12-04 04:30:32 +01:00
throw new Error(`Linter plugin ${plugin.name} has already been registered`);
}
2024-12-10 04:33:33 +01:00
state.plugins.push(plugin);
state.installedPlugins.add(plugin.name);
}
2024-12-10 21:17:02 +01:00
// Keep in sync with Rust
/**
* @enum {number}
*/
const Flags = {
ProgramModule: 0b00000001,
FnAsync: 0b00000001,
FnGenerator: 0b00000010,
FnDeclare: 0b00000100,
2024-12-12 15:20:36 +01:00
FnOptional: 0b00001000,
2024-12-10 21:17:02 +01:00
MemberComputed: 0b00000001,
2024-12-12 15:20:36 +01:00
MemberOptional: 0b00000010,
2024-12-10 21:17:02 +01:00
PropShorthand: 0b00000001,
PropComputed: 0b00000010,
PropGetter: 0b00000100,
PropSetter: 0b00001000,
PropMethod: 0b00010000,
VarVar: 0b00000001,
VarConst: 0b00000010,
VarLet: 0b00000100,
VarDeclare: 0b00001000,
2024-12-10 22:48:54 +01:00
ExportType: 0b000000001,
TplTail: 0b000000001,
2024-12-10 23:05:38 +01:00
ForAwait: 0b000000001,
LogicalOr: 0b000000001,
LogicalAnd: 0b000000010,
LogicalNullishCoalescin: 0b000000100,
2024-12-11 12:47:45 +01:00
JSXSelfClosing: 0b000000001,
2024-12-11 17:10:05 +01:00
BinEqEq: 1,
BinNotEq: 2,
BinEqEqEq: 3,
BinNotEqEq: 4,
BinLt: 5,
BinLtEq: 6,
BinGt: 7,
BinGtEq: 8,
BinLShift: 9,
BinRShift: 10,
BinZeroFillRShift: 11,
BinAdd: 12,
BinSub: 13,
BinMul: 14,
BinDiv: 15,
BinMod: 16,
BinBitOr: 17,
BinBitXor: 18,
BinBitAnd: 19,
BinIn: 20,
BinInstanceOf: 21,
BinExp: 22,
UnaryMinus: 1,
UnaryPlus: 2,
UnaryBang: 3,
UnaryTilde: 4,
UnaryTypeOf: 5,
UnaryVoid: 6,
UnaryDelete: 7,
2024-12-11 17:41:33 +01:00
UpdatePrefix: 0b000000001,
UpdatePlusPlus: 0b000000010,
UpdateMinusMinus: 0b000000100,
2024-12-11 17:47:46 +01:00
YieldDelegate: 1,
2024-12-12 01:35:57 +01:00
ParamOptional: 1,
ClassDeclare: 0b000000001,
ClassAbstract: 0b000000010,
ClassConstructor: 0b000000100,
ClassMethod: 0b000001000,
ClassPublic: 0b001000000,
ClassProtected: 0b010000000,
ClassPrivate: 0b100000000,
2024-12-10 21:17:02 +01:00
};
2024-12-05 01:18:08 +01:00
// Keep in sync with Rust
2024-12-06 23:26:11 +01:00
/**
* @enum {number}
*/
2024-12-10 04:33:33 +01:00
const AstType = {
2024-12-05 01:18:08 +01:00
Invalid: 0,
Program: 1,
Import: 2,
2024-12-10 04:33:33 +01:00
ImportDecl: 3,
ExportDecl: 4,
ExportNamed: 5,
ExportDefaultDecl: 6,
ExportDefaultExpr: 7,
ExportAll: 8,
TSImportEquals: 9,
TSExportAssignment: 10,
TSNamespaceExport: 11,
2024-12-05 01:18:08 +01:00
// Decls
2024-12-12 01:35:57 +01:00
ClassDeclaration: 12,
2024-12-11 17:10:05 +01:00
FunctionDeclaration: 13,
2024-12-10 21:17:02 +01:00
VariableDeclaration: 14,
2024-12-10 04:33:33 +01:00
Using: 15,
TsInterface: 16,
TsTypeAlias: 17,
TsEnum: 18,
TsModule: 19,
2024-12-05 01:18:08 +01:00
// Statements
2024-12-06 23:26:11 +01:00
BlockStatement: 20,
2024-12-05 01:18:08 +01:00
Empty: 21,
2024-12-06 23:26:11 +01:00
DebuggerStatement: 22,
WithStatement: 23,
ReturnStatement: 24,
LabeledStatement: 25,
BreakStatement: 26,
ContinueStatement: 27,
IfStatement: 28,
SwitchStatement: 29,
2024-12-05 01:18:08 +01:00
SwitchCase: 30,
2024-12-06 23:26:11 +01:00
ThrowStatement: 31,
TryStatement: 32,
WhileStatement: 33,
DoWhileStatement: 34,
ForStatement: 35,
ForInStatement: 36,
ForOfStatement: 37,
2024-12-05 01:18:08 +01:00
Decl: 38,
2024-12-06 23:26:11 +01:00
ExpressionStatement: 39,
2024-12-05 01:18:08 +01:00
// Expressions
This: 40,
2024-12-06 23:26:11 +01:00
ArrayExpression: 41,
ObjectExpression: 42,
FunctionExpression: 43,
2024-12-11 17:10:05 +01:00
UnaryExpression: 44,
2024-12-11 17:41:33 +01:00
UpdateExpression: 45,
2024-12-06 23:26:11 +01:00
BinaryExpression: 46,
AssignmentExpression: 47,
MemberExpression: 48,
2024-12-07 00:24:36 +01:00
Super: 49,
2024-12-06 23:26:11 +01:00
ConditionalExpression: 50,
CallExpression: 51,
NewExpression: 52,
2024-12-10 04:33:33 +01:00
ParenthesisExpression: 53,
SequenceExpression: 54,
Identifier: 55,
TemplateLiteral: 56,
TaggedTemplateExpression: 57,
ArrowFunctionExpression: 58,
ClassExpr: 59,
2024-12-11 17:47:46 +01:00
YieldExpression: 60,
2024-12-10 04:33:33 +01:00
MetaProperty: 61,
AwaitExpression: 62,
LogicalExpression: 63,
TSTypeAssertion: 64,
TSConstAssertion: 65,
TSNonNull: 66,
TSAs: 67,
TSInstantiation: 68,
TSSatisfies: 69,
PrivateIdentifier: 70,
2024-12-12 15:20:36 +01:00
ChainExpression: 71,
2024-12-10 04:33:33 +01:00
StringLiteral: 72,
BooleanLiteral: 73,
NullLiteral: 74,
NumericLiteral: 75,
BigIntLiteral: 76,
RegExpLiteral: 77,
2024-12-05 01:18:08 +01:00
// Custom
2024-12-11 12:47:45 +01:00
EmptyExpr: 78,
SpreadElement: 79,
Property: 80,
VariableDeclarator: 81,
CatchClause: 82,
RestElement: 83,
ExportSpecifier: 84,
TemplateElement: 85,
2024-12-12 01:35:57 +01:00
MethodDefinition: 86,
2024-12-10 21:17:02 +01:00
// Patterns
2024-12-12 01:35:57 +01:00
ArrayPattern: 87,
AssignmentPattern: 88,
ObjectPattern: 89,
2024-12-07 00:24:36 +01:00
// JSX
2024-12-12 01:35:57 +01:00
JSXAttribute: 90,
JSXClosingElement: 91,
JSXClosingFragment: 92,
JSXElement: 93,
JSXEmptyExpression: 94,
JSXExpressionContainer: 95,
JSXFragment: 96,
JSXIdentifier: 97,
JSXMemberExpression: 98,
JSXNamespacedName: 99,
JSXOpeningElement: 100,
JSXOpeningFragment: 101,
JSXSpreadAttribute: 102,
JSXSpreadChild: 103,
JSXText: 104,
2024-12-04 16:21:17 +01:00
};
2024-12-12 22:16:49 +01:00
const AstTypeName = Object.keys(AstType);
// Keep in sync with Rust
const AstProp = [
// Base
"parent",
"range",
"type",
"_InternalFlags", // Internal
// Node
"alternate",
"argument",
"arguments",
"async",
"attributes",
"await",
"block",
"body",
"callee",
"cases",
"children",
"closingElement",
"closingFragment",
"computed",
"consequent",
"declarations",
"declare",
"definite",
"delegate",
"discrimininant",
"elements",
"expression",
"expressions",
"finalizer",
"flags",
"generator",
"handler",
"id",
"init",
"key",
"kind",
"label",
"left",
"members",
"meta",
"method",
"name",
"namespace",
"object",
"openingElement",
"openingFragment",
"operator",
"optional",
"params",
"pattern",
"prefix",
"properties",
"property",
"quasi",
"quasis",
"raw",
"returnType",
"right",
"selfClosing",
"shorthand",
"source",
"specifiers",
"tag",
"tail",
"test",
"typeAnnotation",
"typeArguments",
"typeParameters",
"update",
"value",
];
const AST_PROP_PARENT = AstProp.indexOf("parent");
const AST_PROP_TYPE = AstProp.indexOf("type");
const AST_PROP_RANGE = AstProp.indexOf("range");
const AST_PROP_INTERNAL_FLAGS = AstProp.indexOf("_InternalFlags");
const AST_PROP_ATTRIBUTE = AstProp.indexOf("attribute");
2024-12-10 04:33:33 +01:00
/**
* @param {AstContext} ctx
2024-12-12 22:16:49 +01:00
* @param {number} offset
* @param {number} propId
2024-12-10 04:33:33 +01:00
*/
2024-12-12 22:16:49 +01:00
function readValue(ctx, offset, propId) {
const { buf } = ctx;
2024-12-10 04:33:33 +01:00
2024-12-12 22:16:49 +01:00
// FIXME
if (propId === AST_PROP_TYPE) {
const type = buf[offset];
return AstTypeName[type];
} else if (propId === AST_PROP_RANGE) {
const start = readU32(buf, offset + 1 + 4);
const end = readU32(buf, offset + 1 + 4 + 4);
return [start, end];
} else if (propId === AST_PROP_PARENT) {
const id = readU32(buf, offset + 1);
if (id === 0) return null;
const target = ctx.idTable[id];
return new Node(ctx, target);
} else if (propId === AST_PROP_INTERNAL_FLAGS) {
//
} else {
const type = buf[offset];
// type + parentId + SpanLo + SpanHi
offset += 1 + 4 + 4 + 4;
// Check for arrays
if (propId === AST_PROP_ATTRIBUTE && type === AstType.JSXOpeningElement) {
}
//
const target = 0;
return new Node(ctx, target);
}
2024-12-10 04:33:33 +01:00
}
2024-12-12 22:16:49 +01:00
class Node {
2024-12-10 04:33:33 +01:00
#ctx;
2024-12-12 22:16:49 +01:00
#offset;
static {
for (let i = 0; i < AstProp.length; i++) {
const name = AstProp[i];
Object.defineProperty(this, name, {
get() {
return readValue(this.#ctx, this.#offset, i);
},
});
}
2024-12-10 04:33:33 +01:00
}
/**
* @param {AstContext} ctx
2024-12-12 22:16:49 +01:00
* @param {number} offset
2024-12-10 04:33:33 +01:00
*/
2024-12-12 22:16:49 +01:00
constructor(ctx, offset) {
2024-12-10 04:33:33 +01:00
this.#ctx = ctx;
2024-12-12 22:16:49 +01:00
this.#offset = offset;
2024-12-10 04:33:33 +01:00
}
}
2024-12-05 01:18:08 +01:00
2024-12-12 22:16:49 +01:00
/**
* @param {AstContext} ctx
* @param {number[]} ids
* @returns {any[]}
*/
function createChildNodes(ctx, ids) {
/** @type {any[]} */
const out = [];
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
out.push(createAstNode(ctx, id));
}
return out;
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.Program} */
2024-12-12 22:16:49 +01:00
class Program extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("Program");
range;
get body() {
2024-12-10 04:33:33 +01:00
return createChildNodes(this.#ctx, this.#childIds);
2024-12-05 01:18:08 +01:00
}
2024-12-10 04:33:33 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
2024-12-10 04:33:33 +01:00
#childIds;
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {Deno.Program["sourceType"]} sourceType
2024-12-10 04:33:33 +01:00
* @param {number[]} childIds
2024-12-06 23:26:11 +01:00
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, sourceType, childIds) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.range = range;
this.sourceType = sourceType;
2024-12-10 04:33:33 +01:00
this.#childIds = childIds;
2024-12-05 01:18:08 +01:00
}
}
2024-12-10 21:17:02 +01:00
// Declarations
2024-12-11 17:41:33 +01:00
/** @implements {Deno.FunctionDeclaration} */
2024-12-12 22:16:49 +01:00
class FunctionDeclaration extends Node {
2024-12-11 17:41:33 +01:00
type = /** @type {const} */ ("FunctionDeclaration");
range;
get id() {
if (this.#identId === 0) return null;
return /** @type {*} */ (createAstNode(this.#ctx, this.#identId));
}
get typeParameters() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#typeParamsId));
}
get params() {
return createChildNodes(this.#ctx, this.#paramIds);
}
get body() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#bodyId));
}
get returnType() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#returnTypeId));
}
declare = false; // FIXME
#ctx;
#identId;
#typeParamsId;
#paramIds;
#returnTypeId;
#bodyId;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} flags
* @param {number} identId
* @param {number} typeParamsId
* @param {number[]} paramIds
* @param {number} returnTypeId
* @param {number} bodyId
*/
constructor(
ctx,
parentId,
range,
flags,
identId,
typeParamsId,
paramIds,
returnTypeId,
bodyId,
) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
// FIXME: Flags
this.#identId = identId;
this.#typeParamsId = typeParamsId;
this.#paramIds = paramIds;
this.#returnTypeId = returnTypeId;
this.#bodyId = bodyId;
}
}
2024-12-10 21:17:02 +01:00
/** @implements {Deno.VariableDeclaration} */
2024-12-12 22:16:49 +01:00
class VariableDeclaration extends Node {
2024-12-10 21:17:02 +01:00
type = /** @type {const} */ ("VariableDeclaration");
range;
get declarations() {
return createChildNodes(this.#ctx, this.#childIds);
}
#ctx;
#childIds;
kind;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} flags
* @param {number[]} childIds
*/
constructor(ctx, parentId, range, flags, childIds) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.kind = (Flags.VarConst & flags) != 0
? /** @type {const} */ ("const")
: (Flags.VarLet & flags) != 0
? /** @type {const} */ ("let")
: /** @type {const} */ ("var");
// FIXME: Declare
this.#childIds = childIds;
}
}
/** @implements {Deno.VariableDeclarator} */
2024-12-12 22:16:49 +01:00
class VariableDeclarator extends Node {
2024-12-10 21:17:02 +01:00
type = /** @type {const} */ ("VariableDeclarator");
range;
get id() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#nameId));
}
get init() {
if (this.#initId === 0) return null;
return /** @type {*} */ (createAstNode(this.#ctx, this.#initId));
}
#ctx;
#nameId;
#initId;
2024-12-10 22:48:54 +01:00
definite = false;
2024-12-10 21:17:02 +01:00
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} nameId
* @param {number} initId
*/
constructor(ctx, parentId, range, nameId, initId) {
// FIXME: Definite
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.#nameId = nameId;
this.#initId = initId;
}
}
// Statements
2024-12-06 23:26:11 +01:00
/** @implements {Deno.BlockStatement} */
2024-12-12 22:16:49 +01:00
class BlockStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("BlockStatement");
2024-12-10 04:33:33 +01:00
get body() {
return createChildNodes(this.#ctx, this.#childIds);
}
2024-12-06 23:26:11 +01:00
range;
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
2024-12-10 04:33:33 +01:00
#childIds;
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
2024-12-10 04:33:33 +01:00
* @param {number[]} childIds
2024-12-06 23:26:11 +01:00
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, childIds) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.range = range;
2024-12-10 04:33:33 +01:00
this.#childIds = childIds;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.BreakStatement} */
2024-12-12 22:16:49 +01:00
class BreakStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("BreakStatement");
get label() {
if (this.#labelId === 0) return null;
return /** @type {Deno.Identifier} */ (createAstNode(
this.#ctx,
this.#labelId,
));
}
range;
#ctx;
#labelId;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} labelId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, labelId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#labelId = labelId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ContinueStatement} */
2024-12-12 22:16:49 +01:00
class ContinueStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ContinueStatement");
range;
get label() {
return /** @type {Deno.Identifier} */ (createAstNode(
this.#ctx,
this.#labelId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#labelId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} labelId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, labelId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#labelId = labelId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.DebuggerStatement} */
2024-12-12 22:16:49 +01:00
class DebuggerStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("DebuggerStatement");
range;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.DoWhileStatement} */
2024-12-12 22:16:49 +01:00
class DoWhileStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("DoWhileStatement");
range;
get test() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#exprId,
));
}
get body() {
return /** @type {Deno.Statement} */ (createAstNode(
this.#ctx,
this.#bodyId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#exprId = 0;
#bodyId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} exprId
* @param {number} bodyId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, exprId, bodyId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#exprId = exprId;
this.#bodyId = bodyId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ExpressionStatement} */
2024-12-12 22:16:49 +01:00
class ExpressionStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ExpressionStatement");
range;
get expression() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#exprId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#exprId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} exprId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, exprId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#exprId = exprId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ForInStatement} */
2024-12-12 22:16:49 +01:00
class ForInStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ForInStatement");
range;
get left() {
return /** @type {Deno.Expression | Deno.VariableDeclaration} */ (createAstNode(
this.#ctx,
this.#leftId,
));
}
get right() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#rightId,
));
}
get body() {
return /** @type {Deno.Statement} */ (createAstNode(
this.#ctx,
this.#bodyId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#leftId = 0;
#rightId = 0;
#bodyId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} leftId
* @param {number} rightId
* @param {number} bodyId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, leftId, rightId, bodyId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#leftId = leftId;
this.#rightId = rightId;
this.#bodyId = bodyId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ForOfStatement} */
2024-12-12 22:16:49 +01:00
class ForOfStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ForOfStatement");
range;
get left() {
return /** @type {Deno.Expression | Deno.VariableDeclaration | Deno.UsingDeclaration} */ (createAstNode(
this.#ctx,
this.#leftId,
));
}
get right() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#rightId,
));
}
get body() {
return /** @type {Deno.Statement} */ (createAstNode(
this.#ctx,
this.#bodyId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
await;
#ctx;
#leftId = 0;
#rightId = 0;
#bodyId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {boolean} isAwait
* @param {number} leftId
* @param {number} rightId
* @param {number} bodyId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, isAwait, leftId, rightId, bodyId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#leftId = leftId;
this.#rightId = rightId;
this.#bodyId = bodyId;
this.range = range;
this.await = isAwait;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ForStatement} */
2024-12-12 22:16:49 +01:00
class ForStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ForStatement");
range;
get init() {
if (this.#initId === 0) return null;
return /** @type {Deno.Expression | Deno.VariableDeclaration} */ (createAstNode(
this.#ctx,
this.#initId,
));
}
get test() {
if (this.#initId === 0) return null;
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#testId,
));
}
get update() {
if (this.#updateId === 0) return null;
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#updateId,
));
}
get body() {
return /** @type {Deno.Statement} */ (createAstNode(
this.#ctx,
this.#bodyId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#initId = 0;
#testId = 0;
#updateId = 0;
#bodyId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} initId
* @param {number} testId
* @param {number} updateId
* @param {number} bodyId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, initId, testId, updateId, bodyId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#initId = initId;
this.#testId = testId;
this.#updateId = updateId;
this.#bodyId = bodyId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.IfStatement} */
2024-12-12 22:16:49 +01:00
class IfStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("IfStatement");
range;
get test() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#testId,
));
}
get consequent() {
return /** @type {Deno.Statement} */ (createAstNode(
this.#ctx,
this.#consequentId,
));
}
get alternate() {
if (this.#alternateId === 0) return null;
return /** @type {Deno.Statement} */ (createAstNode(
this.#ctx,
this.#alternateId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#testId = 0;
#consequentId = 0;
#alternateId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} testId
* @param {number} updateId
* @param {number} alternateId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, testId, updateId, alternateId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#testId = testId;
this.#consequentId = updateId;
this.#alternateId = alternateId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.LabeledStatement} */
2024-12-12 22:16:49 +01:00
class LabeledStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("LabeledStatement");
range;
get label() {
return /** @type {Deno.Identifier} */ (createAstNode(
this.#ctx,
this.#labelId,
));
}
get body() {
return /** @type {Deno.Statement} */ (createAstNode(
this.#ctx,
this.#bodyId,
));
}
2024-12-05 02:24:26 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#labelId = 0;
#bodyId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} testId
* @param {number} bodyId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, testId, bodyId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#labelId = testId;
this.#bodyId = bodyId;
this.range = range;
2024-12-05 02:24:26 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ReturnStatement} */
2024-12-12 22:16:49 +01:00
class ReturnStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ReturnStatement");
range;
get argument() {
if (this.#exprId === 0) return null;
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#exprId,
));
}
2024-12-05 02:24:26 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#exprId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} argId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, argId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#exprId = argId;
this.range = range;
2024-12-05 02:24:26 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.SwitchStatement} */
2024-12-12 22:16:49 +01:00
class SwitchStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("SwitchStatement");
range;
get discriminant() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#discriminantId,
));
}
get cases() {
2024-12-12 01:35:57 +01:00
return createChildNodes(this.#ctx, this.#caseIds);
2024-12-06 23:26:11 +01:00
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#discriminantId = 0;
2024-12-12 01:35:57 +01:00
#caseIds;
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} discriminantId
2024-12-12 01:35:57 +01:00
* @param {number[]} caseIds
2024-12-06 23:26:11 +01:00
*/
2024-12-12 01:35:57 +01:00
constructor(ctx, parentId, range, discriminantId, caseIds) {
2024-12-10 04:33:33 +01:00
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#discriminantId = discriminantId;
2024-12-12 01:35:57 +01:00
this.#caseIds = caseIds;
this.range = range;
}
}
/** @implements {Deno.SwitchCase} */
2024-12-12 22:16:49 +01:00
class SwitchCase extends Node {
2024-12-12 01:35:57 +01:00
type = /** @type {const} */ ("SwitchCase");
range;
get test() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#testId,
));
}
get consequent() {
return createChildNodes(this.#ctx, this.#consIds);
}
#ctx;
#testId = 0;
#consIds;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} testId
* @param {number[]} consIds
*/
constructor(ctx, parentId, range, testId, consIds) {
super(ctx, parentId);
this.#ctx = ctx;
this.#testId = testId;
this.#consIds = consIds;
2024-12-06 23:26:11 +01:00
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ThrowStatement} */
2024-12-12 22:16:49 +01:00
class ThrowStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ThrowStatement");
range;
get argument() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#argId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#argId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} argId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, argId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#argId = argId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.TryStatement} */
2024-12-12 22:16:49 +01:00
class TryStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("TryStatement");
range;
get block() {
return /** @type {Deno.BlockStatement} */ (createAstNode(
this.#ctx,
this.#blockId,
));
}
get finalizer() {
if (this.#finalizerId === 0) return null;
return /** @type {Deno.BlockStatement} */ (createAstNode(
this.#ctx,
this.#finalizerId,
));
}
get handler() {
if (this.#handlerId === 0) return null;
return /** @type {Deno.CatchClause} */ (createAstNode(
this.#ctx,
this.#handlerId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#blockId = 0;
#finalizerId = 0;
#handlerId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} blockId
* @param {number} finalizerId
* @param {number} handlerId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, blockId, finalizerId, handlerId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#blockId = blockId;
this.#finalizerId = finalizerId;
this.#handlerId = handlerId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.WhileStatement} */
2024-12-12 22:16:49 +01:00
class WhileStatement extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("WhileStatement");
range;
get test() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#testId,
));
}
get body() {
return /** @type {Deno.Statement} */ (createAstNode(
this.#ctx,
this.#bodyId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#testId = 0;
#bodyId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} testId
* @param {number} bodyId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, testId, bodyId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#testId = testId;
this.#bodyId = bodyId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.WithStatement} */
class WithStatement {
type = /** @type {const} */ ("WithStatement");
range;
get body() {
return /** @type {Deno.Statement} */ (createAstNode(
this.#ctx,
this.#bodyId,
));
}
get object() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#objectId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#bodyId = 0;
#objectId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} bodyId
* @param {number} objectId
*/
constructor(ctx, range, bodyId, objectId) {
this.#ctx = ctx;
this.#bodyId = bodyId;
this.#objectId = objectId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
// Expressions
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ArrayExpression} */
2024-12-12 22:16:49 +01:00
class ArrayExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ArrayExpression");
range;
get elements() {
2024-12-10 04:33:33 +01:00
return createChildNodes(this.#ctx, this.#elemIds);
2024-12-05 01:18:08 +01:00
}
2024-12-06 23:26:11 +01:00
#ctx;
2024-12-10 04:33:33 +01:00
#elemIds;
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
2024-12-10 04:33:33 +01:00
* @param {number[]} elemIds
2024-12-06 23:26:11 +01:00
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, elemIds) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.range = range;
2024-12-10 04:33:33 +01:00
this.#elemIds = elemIds;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ArrowFunctionExpression} */
2024-12-12 22:16:49 +01:00
class ArrowFunctionExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ArrowFunctionExpression");
range;
async = false;
generator = false;
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
get body() {
2024-12-10 04:33:33 +01:00
return /** @type {*} */ (createAstNode(
2024-12-06 23:26:11 +01:00
this.#ctx,
this.#bodyId,
));
2024-12-05 01:18:08 +01:00
}
2024-12-06 23:26:11 +01:00
get params() {
2024-12-10 04:33:33 +01:00
return createChildNodes(this.#ctx, this.#paramIds);
2024-12-06 23:26:11 +01:00
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
get returnType() {
2024-12-10 04:33:33 +01:00
if (this.#returnTypeId === 0) return null;
return /** @type {*} */ (createAstNode(
this.#ctx,
this.#returnTypeId,
));
2024-12-05 01:18:08 +01:00
}
2024-12-06 23:26:11 +01:00
get typeParameters() {
2024-12-10 04:33:33 +01:00
if (this.#typeParamId === 0) return null;
return /** @type {*} */ (createAstNode(
this.#ctx,
this.#typeParamId,
));
2024-12-06 23:26:11 +01:00
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#bodyId;
2024-12-10 04:33:33 +01:00
#typeParamId;
#paramIds;
#returnTypeId;
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {boolean} isAsync
* @param {boolean} isGenerator
2024-12-10 04:33:33 +01:00
* @param {number} typeParamId
* @param {number[]} paramIds
2024-12-06 23:26:11 +01:00
* @param {number} bodyId
2024-12-10 04:33:33 +01:00
* @param {number} returnTypeId
2024-12-06 23:26:11 +01:00
*/
2024-12-10 04:33:33 +01:00
constructor(
ctx,
parentId,
range,
isAsync,
isGenerator,
typeParamId,
paramIds,
bodyId,
returnTypeId,
) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#bodyId = bodyId;
2024-12-10 04:33:33 +01:00
this.#typeParamId = typeParamId;
this.#paramIds = paramIds;
this.#returnTypeId = returnTypeId;
2024-12-06 23:26:11 +01:00
this.asnyc = isAsync;
this.generator = isGenerator;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.AssignmentExpression} */
2024-12-12 22:16:49 +01:00
class AssignmentExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("AssignmentExpression");
range;
get left() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#leftId,
));
}
get right() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#rightId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
operator;
#ctx;
#leftId = 0;
#rightId = 0;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 05:34:12 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} flags
* @param {number} leftId
* @param {number} rightId
*/
2024-12-10 05:34:12 +01:00
constructor(ctx, parentId, range, flags, leftId, rightId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#leftId = leftId;
this.#rightId = rightId;
this.range = range;
this.operator = getAssignOperator(flags);
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/**
* @param {number} n
* @returns {Deno.AssignmentExpression["operator"]}
*/
function getAssignOperator(n) {
switch (n) {
case 0:
2024-12-10 05:34:12 +01:00
return "=";
2024-12-06 23:26:11 +01:00
case 1:
2024-12-10 05:34:12 +01:00
return "+=";
2024-12-06 23:26:11 +01:00
case 2:
2024-12-10 05:34:12 +01:00
return "-=";
2024-12-06 23:26:11 +01:00
case 3:
return "*=";
case 4:
2024-12-10 05:34:12 +01:00
return "/=";
2024-12-06 23:26:11 +01:00
case 5:
2024-12-10 05:34:12 +01:00
return "%=";
2024-12-06 23:26:11 +01:00
case 6:
2024-12-10 05:34:12 +01:00
return "<<=";
2024-12-06 23:26:11 +01:00
case 7:
return ">>=";
2024-12-10 05:34:12 +01:00
case 8:
2024-12-06 23:26:11 +01:00
return ">>>=";
2024-12-10 05:34:12 +01:00
case 9:
return "|=";
2024-12-06 23:26:11 +01:00
case 10:
2024-12-10 05:34:12 +01:00
return "^=";
2024-12-06 23:26:11 +01:00
case 11:
2024-12-10 05:34:12 +01:00
return "&=";
2024-12-06 23:26:11 +01:00
case 12:
2024-12-10 05:34:12 +01:00
return "**=";
2024-12-06 23:26:11 +01:00
case 13:
2024-12-10 05:34:12 +01:00
return "&&=";
2024-12-06 23:26:11 +01:00
case 14:
2024-12-10 05:34:12 +01:00
return "||=";
2024-12-06 23:26:11 +01:00
case 15:
2024-12-10 05:34:12 +01:00
return "??=";
2024-12-06 23:26:11 +01:00
default:
throw new Error(`Unknown operator: ${n}`);
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.AwaitExpression} */
2024-12-12 22:16:49 +01:00
class AwaitExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("AwaitExpression");
range;
get argument() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#argId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
2024-12-11 17:10:05 +01:00
#argId;
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} argId
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, argId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#argId = argId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-11 17:41:33 +01:00
/** @implements {Deno.UpdateExpression} */
2024-12-12 22:16:49 +01:00
class UpdateExpression extends Node {
2024-12-11 17:41:33 +01:00
type = /** @type {const} */ ("UpdateExpression");
range;
get argument() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#argId));
}
#ctx;
#argId;
prefix;
operator;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} flags
* @param {number} argId
*/
constructor(ctx, parentId, range, flags, argId) {
super(ctx, parentId);
this.#ctx = ctx;
this.#argId = argId;
this.range = range;
this.prefix = (flags & Flags.UpdatePrefix) !== 0;
this.operator = (flags & Flags.UpdatePlusPlus) !== 0
? /** @type {const} */ ("++")
: /** @type {const} */ ("--");
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.BinaryExpression} */
2024-12-12 22:16:49 +01:00
class BinaryExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("BinaryExpression");
range;
get left() {
return /** @type {Deno.Expression | Deno.PrivateIdentifier} */ (createAstNode(
this.#ctx,
this.#leftId,
));
}
get right() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#rightId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
operator;
#ctx;
#leftId;
#rightId;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} flags
* @param {number} leftId
* @param {number} rightId
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, flags, leftId, rightId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#leftId = leftId;
this.#rightId = rightId;
this.operator = getBinaryOperator(flags);
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/**
* @param {number} n
* @returns {Deno.BinaryExpression["operator"]}
*/
function getBinaryOperator(n) {
switch (n) {
case 1:
2024-12-11 17:10:05 +01:00
return "==";
2024-12-06 23:26:11 +01:00
case 2:
2024-12-11 17:10:05 +01:00
return "!=";
2024-12-06 23:26:11 +01:00
case 3:
2024-12-11 17:10:05 +01:00
return "===";
2024-12-06 23:26:11 +01:00
case 4:
2024-12-11 17:10:05 +01:00
return "!==";
2024-12-06 23:26:11 +01:00
case 5:
2024-12-11 17:10:05 +01:00
return "<";
2024-12-06 23:26:11 +01:00
case 6:
2024-12-11 17:10:05 +01:00
return "<=";
2024-12-06 23:26:11 +01:00
case 7:
2024-12-11 17:10:05 +01:00
return ">";
2024-12-06 23:26:11 +01:00
case 8:
return ">=";
2024-12-11 17:10:05 +01:00
case 9:
return "<<";
2024-12-06 23:26:11 +01:00
case 10:
return ">>";
2024-12-11 17:10:05 +01:00
case 11:
return ">>>";
2024-12-06 23:26:11 +01:00
case 12:
2024-12-11 17:10:05 +01:00
return "+";
2024-12-06 23:26:11 +01:00
case 13:
2024-12-11 17:10:05 +01:00
return "-";
2024-12-06 23:26:11 +01:00
case 14:
2024-12-11 17:10:05 +01:00
return "*";
2024-12-06 23:26:11 +01:00
case 15:
2024-12-11 17:10:05 +01:00
return "/";
2024-12-06 23:26:11 +01:00
case 16:
2024-12-11 17:10:05 +01:00
return "%";
2024-12-06 23:26:11 +01:00
case 17:
2024-12-11 17:10:05 +01:00
return "|";
2024-12-06 23:26:11 +01:00
case 18:
2024-12-11 17:10:05 +01:00
return "^";
2024-12-06 23:26:11 +01:00
case 19:
2024-12-11 17:10:05 +01:00
return "&";
2024-12-06 23:26:11 +01:00
case 20:
2024-12-11 17:10:05 +01:00
return "in";
2024-12-06 23:26:11 +01:00
case 21:
2024-12-11 17:10:05 +01:00
return "instanceof";
case 22:
return "**";
2024-12-06 23:26:11 +01:00
default:
throw new Error(`Unknown operator: ${n}`);
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.CallExpression} */
2024-12-12 22:16:49 +01:00
class CallExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("CallExpression");
range;
get callee() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#calleeId,
));
}
get arguments() {
2024-12-10 04:33:33 +01:00
return createChildNodes(this.#ctx, this.#argumentIds);
2024-12-06 23:26:11 +01:00
}
get typeArguments() {
2024-12-10 04:33:33 +01:00
if (this.#typeArgId === 0) return null;
return createAstNode(this.#ctx, this.#typeArgId);
2024-12-06 23:26:11 +01:00
}
2024-12-12 15:20:36 +01:00
optional = false;
2024-12-06 23:26:11 +01:00
#ctx;
#calleeId;
2024-12-10 04:33:33 +01:00
#typeArgId;
#argumentIds;
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
2024-12-12 15:20:36 +01:00
* @param {number} flags
2024-12-06 23:26:11 +01:00
* @param {number} calleeId
2024-12-10 04:33:33 +01:00
* @param {number} typeArgId
* @param {number[]} argumentIds
2024-12-06 23:26:11 +01:00
*/
2024-12-12 15:20:36 +01:00
constructor(ctx, parentId, range, flags, calleeId, typeArgId, argumentIds) {
2024-12-10 04:33:33 +01:00
super(ctx, parentId);
2024-12-12 15:20:36 +01:00
this.optional = (flags & Flags.FnOptional) !== 0;
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#calleeId = calleeId;
this.range = range;
2024-12-10 04:33:33 +01:00
this.#typeArgId = typeArgId;
this.#argumentIds = argumentIds;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ChainExpression} */
2024-12-12 22:16:49 +01:00
class ChainExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ChainExpression");
range;
2024-12-12 15:20:36 +01:00
get expression() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#exprId));
}
2024-12-06 23:26:11 +01:00
#ctx;
2024-12-12 15:20:36 +01:00
#exprId;
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-12 15:20:36 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
2024-12-12 15:20:36 +01:00
* @param {number} exprId
2024-12-06 23:26:11 +01:00
*/
2024-12-12 15:20:36 +01:00
constructor(ctx, parentId, range, exprId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.range = range;
2024-12-12 15:20:36 +01:00
this.#exprId = exprId;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.ConditionalExpression} */
2024-12-12 22:16:49 +01:00
class ConditionalExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("ConditionalExpression");
range;
get test() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#testId,
));
}
get consequent() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#consequentId,
));
}
get alternate() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#alternateId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#testId;
#consequentId;
#alternateId;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-11 11:02:21 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} testId
* @param {number} consequentId
* @param {number} alternateId
*/
2024-12-11 11:02:21 +01:00
constructor(ctx, parentId, range, testId, consequentId, alternateId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.#testId = testId;
this.#consequentId = consequentId;
this.#alternateId = alternateId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.FunctionExpression} */
2024-12-12 22:16:49 +01:00
class FunctionExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("FunctionExpression");
range;
2024-12-12 01:35:57 +01:00
get body() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#bodyId));
}
get returnType() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#returnId));
}
get id() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#identId));
}
get params() {
return createChildNodes(this.#ctx, this.#paramIds);
}
get typeParameters() {
if (this.#typeParamId === null) return null;
return /** @type {*} */ (createAstNode(this.#ctx, this.#typeParamId));
}
async = false;
generator = false;
2024-12-06 23:26:11 +01:00
#ctx;
2024-12-12 01:35:57 +01:00
#identId;
#typeParamId;
#returnId;
#bodyId;
#paramIds;
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-12 01:35:57 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
2024-12-12 01:35:57 +01:00
* @param {number} flags
* @param {number} identId
* @param {number} typeParamId
* @param {number} returnId
* @param {number} bodyId
* @param {number[]} paramIds
2024-12-06 23:26:11 +01:00
*/
2024-12-12 01:35:57 +01:00
constructor(
ctx,
parentId,
range,
flags,
identId,
typeParamId,
returnId,
bodyId,
paramIds,
) {
super(ctx, parentId);
this.async = (flags & Flags.FnAsync) !== 0;
this.generator = (flags & Flags.FnGenerator) !== 0;
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.range = range;
2024-12-12 01:35:57 +01:00
this.#identId = identId;
this.#typeParamId = typeParamId;
this.#returnId = returnId;
this.#bodyId = bodyId;
this.#paramIds = paramIds;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.Identifier} */
2024-12-12 22:16:49 +01:00
class Identifier extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("Identifier");
range;
name = "";
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
2024-12-07 00:24:36 +01:00
* @param {number} nameId
2024-12-06 23:26:11 +01:00
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, nameId) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.name = getString(ctx, nameId);
2024-12-06 23:26:11 +01:00
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.LogicalExpression} */
2024-12-12 22:16:49 +01:00
class LogicalExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("LogicalExpression");
range;
get left() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#leftId,
));
}
get right() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#rightId,
));
}
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
#ctx;
#leftId;
#rightId;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} flags
* @param {number} leftId
* @param {number} rightId
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, flags, leftId, rightId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
this.operator = getLogicalOperator(flags);
this.#leftId = leftId;
this.#rightId = rightId;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-07 00:24:36 +01:00
/**
* @param {number} n
* @returns {Deno.LogicalExpression["operator"]}
*/
function getLogicalOperator(n) {
2024-12-10 23:05:38 +01:00
if ((n & Flags.LogicalAnd) !== 0) {
return "&&";
} else if ((n & Flags.LogicalOr) !== 0) {
return "||";
} else if ((n & Flags.LogicalNullishCoalescin) !== 0) {
return "??";
2024-12-07 00:24:36 +01:00
}
2024-12-10 23:05:38 +01:00
throw new Error(`Unknown operator: ${n}`);
2024-12-07 00:24:36 +01:00
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.MemberExpression} */
2024-12-12 22:16:49 +01:00
class MemberExpression extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("MemberExpression");
range;
get object() {
2024-12-10 04:33:33 +01:00
return /** @type {*} */ (createAstNode(
2024-12-06 23:26:11 +01:00
this.#ctx,
this.#objId,
));
}
get property() {
2024-12-10 04:33:33 +01:00
return /** @type {*} */ (createAstNode(
2024-12-06 23:26:11 +01:00
this.#ctx,
this.#propId,
));
}
2024-12-12 15:20:36 +01:00
optional = false;
computed = false;
2024-12-06 23:26:11 +01:00
#ctx;
#objId;
#propId;
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} flags
* @param {number} objId
* @param {number} propId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, flags, objId, propId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.#ctx = ctx;
2024-12-10 21:17:02 +01:00
this.computed = (flags & Flags.MemberComputed) !== 0;
2024-12-12 15:20:36 +01:00
this.optional = (flags & Flags.MemberOptional) !== 0;
2024-12-06 23:26:11 +01:00
this.#objId = objId;
this.#propId = propId;
this.range = range;
}
}
2024-12-05 01:18:08 +01:00
2024-12-07 00:24:36 +01:00
/** @implements {Deno.MetaProperty} */
class MetaProperty {
type = /** @type {const} */ ("MetaProperty");
range;
get meta() {
return /** @type {Deno.Identifier} */ (createAstNode(
this.#ctx,
this.#metaId,
));
}
get property() {
return /** @type {Deno.Identifier} */ (createAstNode(
this.#ctx,
this.#propId,
));
}
#ctx;
#metaId;
#propId;
/**
* @param {AstContext} ctx
* @param {Deno.Range} range
* @param {number} metaId
* @param {number} propId
*/
constructor(ctx, range, metaId, propId) {
this.#ctx = ctx;
this.#metaId = metaId;
this.#propId = propId;
this.range = range;
}
}
/** @implements {Deno.NewExpression} */
2024-12-12 22:16:49 +01:00
class NewExpression extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("NewExpression");
range;
get arguments() {
2024-12-11 17:10:05 +01:00
return createChildNodes(this.#ctx, this.#childIds);
2024-12-07 00:24:36 +01:00
}
get callee() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#calleeId,
));
}
#ctx;
#calleeId;
2024-12-11 17:10:05 +01:00
#childIds;
2024-12-07 00:24:36 +01:00
/**
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
* @param {number} calleeId
2024-12-11 17:10:05 +01:00
* @param {number[]} childIds
2024-12-07 00:24:36 +01:00
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, calleeId, childIds) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.#ctx = ctx;
this.#calleeId = calleeId;
2024-12-11 17:10:05 +01:00
this.#childIds = childIds;
2024-12-07 00:24:36 +01:00
this.range = range;
}
}
2024-12-10 05:34:12 +01:00
/** @implements {Deno.ObjectExpression} */
2024-12-12 22:16:49 +01:00
class ObjectExpression extends Node {
2024-12-10 05:34:12 +01:00
type = /** @type {const} */ ("ObjectExpression");
range;
get properties() {
return createChildNodes(this.#ctx, this.#elemIds);
}
#ctx;
#elemIds;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number[]} elemIds
*/
constructor(ctx, parentId, range, elemIds) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.#elemIds = elemIds;
}
}
2024-12-10 04:33:33 +01:00
/** @implements {Deno.ParenthesisExpression} */
2024-12-12 22:16:49 +01:00
class ParenthesisExpression extends Node {
2024-12-10 04:33:33 +01:00
type = /** @type {const} */ ("ParenthesisExpression");
range;
#ctx;
#exprId;
get expression() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#exprId));
}
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} exprId
*/
constructor(ctx, parentId, range, exprId) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.#exprId = exprId;
}
}
/** @implements {Deno.PrivateIdentifier} */
2024-12-12 22:16:49 +01:00
class PrivateIdentifier extends Node {
2024-12-10 04:33:33 +01:00
type = /** @type {const} */ ("PrivateIdentifier");
range;
#ctx;
name;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} nameId
*/
constructor(ctx, parentId, range, nameId) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.name = getString(ctx, nameId);
}
}
2024-12-10 05:34:12 +01:00
/** @implements {Deno.Property} */
2024-12-12 22:16:49 +01:00
class Property extends Node {
2024-12-10 05:34:12 +01:00
type = /** @type {const} */ ("Property");
range;
#ctx;
get key() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#keyId));
}
get value() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#valueId));
}
#keyId;
#valueId;
// FIXME
computed = false;
method = false;
shorthand = false;
kind = /** @type {const} */ ("get");
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} keyId
* @param {number} valueId
*/
constructor(ctx, parentId, range, keyId, valueId) {
super(ctx, parentId);
// FIXME flags
this.#ctx = ctx;
this.range = range;
this.#keyId = keyId;
this.#valueId = valueId;
}
}
2024-12-12 01:35:57 +01:00
/** @implements {Deno.RestElement} */
2024-12-12 22:16:49 +01:00
class RestElement extends Node {
2024-12-12 01:35:57 +01:00
type = /** @type {const} */ ("RestElement");
range;
#ctx;
#exprId;
#typeId;
get argument() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#exprId));
}
get typeAnnotation() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#typeId));
}
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} exprId
* @param {number} typeId
*/
constructor(ctx, parentId, range, exprId, typeId) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.#exprId = exprId;
this.#typeId = typeId;
}
}
2024-12-10 04:33:33 +01:00
/** @implements {Deno.SequenceExpression} */
2024-12-12 22:16:49 +01:00
class SequenceExpression extends Node {
2024-12-10 04:33:33 +01:00
type = /** @type {const} */ ("SequenceExpression");
range;
#ctx;
#childIds;
get expressions() {
return createChildNodes(this.#ctx, this.#childIds);
}
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number[]} childIds
*/
constructor(ctx, parentId, range, childIds) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.#childIds = childIds;
}
}
2024-12-10 21:17:02 +01:00
/** @implements {Deno.SpreadElement} */
2024-12-12 22:16:49 +01:00
class SpreadElement extends Node {
2024-12-10 21:17:02 +01:00
type = /** @type {const} */ ("SpreadElement");
range;
#ctx;
#exprId;
get argument() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#exprId));
}
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} exprId
*/
constructor(ctx, parentId, range, exprId) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.#exprId = exprId;
}
}
2024-12-07 00:24:36 +01:00
/** @implements {Deno.Super} */
2024-12-12 22:16:49 +01:00
class Super extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("Super");
range;
/**
* @param {AstContext} ctx
2024-12-10 22:48:54 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
*/
2024-12-10 22:48:54 +01:00
constructor(ctx, parentId, range) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-12 20:53:08 +01:00
/** @implements {Deno.TaggedTemplateExpression} */
2024-12-12 22:16:49 +01:00
class TaggedTemplateExpression extends Node {
2024-12-12 20:53:08 +01:00
type = /** @type {const} */ ("TaggedTemplateExpression");
range;
get tag() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#tagId));
}
get quasi() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#quasiId));
}
get typeArguments() {
if (this.#typeParamId === 0) return null;
return /** @type {*} */ (createAstNode(this.#ctx, this.#typeParamId));
}
#ctx;
#tagId;
#typeParamId;
#quasiId;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} tagId
* @param {number} typeParamId
* @param {number} quasiId
*/
constructor(ctx, parentId, range, tagId, typeParamId, quasiId) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.#tagId = tagId;
this.#typeParamId = typeParamId;
this.#quasiId = quasiId;
}
}
2024-12-11 17:10:05 +01:00
/** @implements {Deno.UnaryExpression} */
2024-12-12 22:16:49 +01:00
class UnaryExpression extends Node {
2024-12-11 17:10:05 +01:00
type = /** @type {const} */ ("UnaryExpression");
range;
get argument() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#exprId));
}
#ctx;
#exprId;
operator;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} flags
* @param {number} exprId
*/
constructor(ctx, parentId, range, flags, exprId) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.operator = getUnaryOperator(flags);
this.#exprId = exprId;
}
}
/**
* @param {number} n
* @returns {Deno.UnaryExpression["operator"]}
*/
function getUnaryOperator(n) {
switch (n) {
case 1:
return "-";
case 2:
return "+";
case 3:
return "!";
case 4:
return "~";
case 5:
return "typeof";
case 6:
return "void";
case 7:
return "delete";
}
}
2024-12-11 17:47:46 +01:00
/** @implements {Deno.YieldExpression} */
2024-12-12 22:16:49 +01:00
class YieldExpression extends Node {
2024-12-11 17:47:46 +01:00
type = /** @type {const} */ ("YieldExpression");
range;
get argument() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#argId,
));
}
delegate = false;
#ctx;
#argId;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} flags
* @param {number} argId
*/
constructor(ctx, parentId, range, flags, argId) {
super(ctx, parentId);
this.#ctx = ctx;
this.#argId = argId;
this.range = range;
this.delegate = (flags & Flags.YieldDelegate) !== 0;
}
}
2024-12-06 23:26:11 +01:00
// Literals
/** @implements {Deno.BooleanLiteral} */
2024-12-12 22:16:49 +01:00
class BooleanLiteral extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("BooleanLiteral");
range;
2024-12-05 01:18:08 +01:00
value = false;
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} flags
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, flags) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.value = flags === 1;
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-10 04:33:33 +01:00
/** @implements {Deno.BigIntLiteral} */
2024-12-12 22:16:49 +01:00
class BigIntLiteral extends Node {
2024-12-10 04:33:33 +01:00
type = /** @type {const} */ ("BigIntLiteral");
range;
value;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} strId
*/
constructor(ctx, parentId, range, strId) {
super(ctx, parentId);
this.range = range;
this.value = BigInt(getString(ctx, strId));
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.NullLiteral} */
2024-12-12 22:16:49 +01:00
class NullLiteral extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("NullLiteral");
range;
value = null;
2024-12-05 01:18:08 +01:00
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.range = range;
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.NumericLiteral} */
2024-12-12 22:16:49 +01:00
class NumericLiteral extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("NumericLiteral");
range;
2024-12-05 01:18:08 +01:00
value = 0;
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
2024-12-10 04:33:33 +01:00
* @param {number} strId
2024-12-06 23:26:11 +01:00
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, strId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.range = range;
2024-12-10 04:33:33 +01:00
this.value = Number(getString(ctx, strId));
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.RegExpLiteral} */
2024-12-12 22:16:49 +01:00
class RegExpLiteral extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("RegExpLiteral");
range;
2024-12-05 01:18:08 +01:00
pattern = "";
flags = "";
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
* @param {number} patternId
* @param {number} flagsId
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, patternId, flagsId) {
super(ctx, parentId);
2024-12-06 23:26:11 +01:00
this.range = range;
this.pattern = getString(ctx, patternId);
this.flags = getString(ctx, flagsId);
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
/** @implements {Deno.StringLiteral} */
2024-12-12 22:16:49 +01:00
class StringLiteral extends Node {
2024-12-06 23:26:11 +01:00
type = /** @type {const} */ ("StringLiteral");
range;
value = "";
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-10 04:33:33 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
2024-12-10 04:33:33 +01:00
* @param {number} strId
2024-12-07 00:24:36 +01:00
*/
2024-12-10 04:33:33 +01:00
constructor(ctx, parentId, range, strId) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.range = range;
2024-12-10 04:33:33 +01:00
this.value = getString(ctx, strId);
2024-12-07 00:24:36 +01:00
}
}
2024-12-10 22:48:54 +01:00
/** @implements {Deno.TemplateLiteral} */
2024-12-12 22:16:49 +01:00
class TemplateLiteral extends Node {
2024-12-10 22:48:54 +01:00
type = /** @type {const} */ ("TemplateLiteral");
range;
#ctx;
#exprIds;
#quasiIds;
get expressions() {
return createChildNodes(this.#ctx, this.#exprIds);
}
get quasis() {
return createChildNodes(this.#ctx, this.#quasiIds);
}
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number[]} quasiIds
* @param {number[]} exprIds
*/
constructor(ctx, parentId, range, quasiIds, exprIds) {
super(ctx, parentId);
this.#ctx = ctx;
this.#quasiIds = quasiIds;
this.#exprIds = exprIds;
this.range = range;
}
}
/** @implements {Deno.TemplateElement} */
2024-12-12 22:16:49 +01:00
class TemplateElement extends Node {
2024-12-10 22:48:54 +01:00
type = /** @type {const} */ ("TemplateElement");
range;
tail = false;
value;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} rawId
* @param {number} cookedId
* @param {boolean} tail
*/
constructor(ctx, parentId, range, rawId, cookedId, tail) {
super(ctx, parentId);
const raw = getString(ctx, rawId);
this.value = {
raw,
cooked: cookedId === 0 ? raw : getString(ctx, cookedId),
};
this.tail = tail;
this.range = range;
}
}
2024-12-12 01:35:57 +01:00
// Patterns
/** @implements {Deno.AssignmentPattern} */
2024-12-12 22:16:49 +01:00
class AssignmentPattern extends Node {
2024-12-12 01:35:57 +01:00
type = /** @type {const} */ ("AssignmentPattern");
range;
get left() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#leftId));
}
get right() {
return /** @type {*} */ (createAstNode(this.#ctx, this.#rightId));
}
#ctx;
#leftId;
#rightId;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} leftId
* @param {number} rightId
*/
constructor(ctx, parentId, range, leftId, rightId) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.#leftId = leftId;
this.#rightId = rightId;
}
}
/** @implements {Deno.ArrayPattern} */
2024-12-12 22:16:49 +01:00
class ArrayPattern extends Node {
2024-12-12 01:35:57 +01:00
type = /** @type {const} */ ("ArrayPattern");
range;
get elements() {
return createChildNodes(this.#ctx, this.#elemIds);
}
get typeAnnotation() {
if (this.#typeId === 0) return 0;
return /** @type {*} */ (createAstNode(this.#ctx, this.#typeId));
}
#ctx;
#elemIds;
#typeId;
optional = false;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} flags
* @param {number[]} elemIds
* @param {number} typeId
*/
constructor(ctx, parentId, range, flags, elemIds, typeId) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.optional = (flags & Flags.ParamOptional) !== 0;
this.#elemIds = elemIds;
this.#typeId = typeId;
}
}
/** @implements {Deno.ObjectPattern} */
2024-12-12 22:16:49 +01:00
class ObjectPattern extends Node {
2024-12-12 01:35:57 +01:00
type = /** @type {const} */ ("ObjectPattern");
range;
get properties() {
return createChildNodes(this.#ctx, this.#elemIds);
}
get typeAnnotation() {
if (this.#typeId === 0) return 0;
return /** @type {*} */ (createAstNode(this.#ctx, this.#typeId));
}
#ctx;
#elemIds;
#typeId;
optional = false;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
* @param {number} flags
* @param {number[]} elemIds
* @param {number} typeId
*/
constructor(ctx, parentId, range, flags, elemIds, typeId) {
super(ctx, parentId);
this.#ctx = ctx;
this.range = range;
this.optional = (flags & Flags.ParamOptional) !== 0;
this.#elemIds = elemIds;
this.#typeId = typeId;
}
}
2024-12-07 00:24:36 +01:00
// JSX
/** @implements {Deno.JSXAttribute} */
2024-12-12 22:16:49 +01:00
class JSXAttribute extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXAttribute");
range;
get name() {
return /** @type {Deno.JSXIdentifier | Deno.JSXNamespacedName} */ (createAstNode(
this.#ctx,
this.#nameId,
));
}
get value() {
if (this.#valueId === 0) return null;
return /** @type {Deno.JSXElement | Deno.JSXExpressionContainer | Deno.JSXSpreadChild | Deno.Literal} */ (createAstNode(
this.#ctx,
this.#valueId,
));
}
#ctx;
#nameId;
#valueId;
/**
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
* @param {number} nameId
* @param {number} valueId
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, nameId, valueId) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.#ctx = ctx;
this.range = range;
this.#nameId = nameId;
this.#valueId = valueId;
}
}
/** @implements {Deno.JSXClosingElement} */
2024-12-12 22:16:49 +01:00
class JSXClosingElement extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXClosingElement");
range;
get name() {
return /** @type {Deno.JSXIdentifier | Deno.JSXMemberExpression | Deno.JSXNamespacedName} */ (createAstNode(
this.#ctx,
this.#nameId,
));
}
#ctx;
#nameId;
/**
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
* @param {number} nameId
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, nameId) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.#ctx = ctx;
this.range = range;
this.#nameId = nameId;
}
}
/** @implements {Deno.JSXClosingFragment} */
2024-12-12 22:16:49 +01:00
class JSXClosingFragment extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXClosingFragment");
range;
/**
* @param {AstContext} ctx
2024-12-11 12:47:45 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
*/
2024-12-11 12:47:45 +01:00
constructor(ctx, parentId, range) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.range = range;
}
}
/** @implements {Deno.JSXElement} */
2024-12-12 22:16:49 +01:00
class JSXElement extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXElement");
range;
get children() {
2024-12-11 12:47:45 +01:00
return createChildNodes(this.#ctx, this.#childIds);
2024-12-07 00:24:36 +01:00
}
get openingElement() {
return /** @type {Deno.JSXOpeningElement} */ (createAstNode(
this.#ctx,
this.#openId,
));
}
get closingElement() {
return /** @type {Deno.JSXClosingElement} */ (createAstNode(
this.#ctx,
this.#closingId,
));
}
#ctx;
#openId;
#closingId;
2024-12-11 12:47:45 +01:00
#childIds;
2024-12-07 00:24:36 +01:00
/**
* @param {AstContext} ctx
2024-12-11 12:47:45 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
* @param {number} openId
* @param {number} closingId
2024-12-11 12:47:45 +01:00
* @param {number[]} childIds
2024-12-07 00:24:36 +01:00
*/
2024-12-11 12:47:45 +01:00
constructor(ctx, parentId, range, openId, closingId, childIds) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.#ctx = ctx;
this.range = range;
this.#openId = openId;
this.#closingId = closingId;
2024-12-11 12:47:45 +01:00
this.#childIds = childIds;
2024-12-07 00:24:36 +01:00
}
}
2024-12-11 17:10:05 +01:00
/** @implements {Deno.JSXEmptyExpression} */
2024-12-12 22:16:49 +01:00
class JSXEmptyExpression extends Node {
2024-12-11 17:10:05 +01:00
type = /** @type {const} */ ("JSXEmptyExpression");
range;
/**
* @param {AstContext} ctx
* @param {number} parentId
* @param {Deno.Range} range
*/
constructor(ctx, parentId, range) {
super(ctx, parentId);
this.range = range;
}
}
2024-12-07 00:24:36 +01:00
/** @implements {Deno.JSXExpressionContainer} */
2024-12-12 22:16:49 +01:00
class JSXExpressionContainer extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXExpressionContainer");
range;
get expression() {
return /** @type {Deno.Expression | Deno.JSXEmptyExpression} */ (createAstNode(
this.#ctx,
this.#exprId,
));
}
#ctx;
#exprId;
/**
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
* @param {number} exprId
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, exprId) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.#ctx = ctx;
this.range = range;
this.#exprId = exprId;
}
}
/** @implements {Deno.JSXFragment} */
2024-12-12 22:16:49 +01:00
class JSXFragment extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXFragment");
2024-12-11 17:10:05 +01:00
range;
get children() {
return createChildNodes(this.#ctx, this.#childIds);
}
get openingFragment() {
return /** @type {*} */ (createAstNode(
this.#ctx,
this.#openId,
));
}
get closingFragment() {
return /** @type {*} */ (createAstNode(
this.#ctx,
this.#closingId,
));
}
#ctx;
#childIds;
#openId;
#closingId;
2024-12-07 00:24:36 +01:00
/**
* @param {AstContext} ctx
2024-12-11 12:47:45 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
2024-12-11 12:47:45 +01:00
* @param {number} openId
2024-12-07 00:24:36 +01:00
* @param {number} closingId
2024-12-11 12:47:45 +01:00
* @param {number[]} childIds
2024-12-07 00:24:36 +01:00
*/
2024-12-11 12:47:45 +01:00
constructor(ctx, parentId, range, openId, closingId, childIds) {
2024-12-11 17:10:05 +01:00
super(ctx, parentId);
2024-12-11 12:47:45 +01:00
2024-12-11 17:10:05 +01:00
this.#ctx = ctx;
this.range = range;
this.#openId = openId;
this.#closingId = closingId;
this.#childIds = childIds;
2024-12-07 00:24:36 +01:00
}
}
/** @implements {Deno.JSXIdentifier} */
2024-12-12 22:16:49 +01:00
class JSXIdentifier extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXIdentifier");
range;
name;
/**
* @param {AstContext} ctx
2024-12-11 12:47:45 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
* @param {number} nameId
*/
2024-12-11 12:47:45 +01:00
constructor(ctx, parentId, range, nameId) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.range = range;
this.name = getString(ctx, nameId);
}
}
/** @implements {Deno.JSXMemberExpression} */
2024-12-12 22:16:49 +01:00
class JSXMemberExpression extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXMemberExpression");
range;
get object() {
return /** @type {Deno.JSXMemberExpression["object"]} */ (createAstNode(
this.#ctx,
this.#objId,
));
}
get property() {
return /** @type {Deno.JSXIdentifier} */ (createAstNode(
this.#ctx,
this.#propertyId,
));
}
#ctx;
#objId;
#propertyId;
/**
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
* @param {number} objId
* @param {number} propId
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, objId, propId) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.#ctx = ctx;
this.range = range;
this.#objId = objId;
this.#propertyId = propId;
}
}
/** @implements {Deno.JSXNamespacedName} */
2024-12-12 22:16:49 +01:00
class JSXNamespacedName extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXNamespacedName");
range;
get name() {
return /** @type {Deno.JSXIdentifier} */ (createAstNode(
this.#ctx,
this.#nameId,
));
}
get namespace() {
return /** @type {Deno.JSXIdentifier} */ (createAstNode(
this.#ctx,
this.#namespaceId,
));
}
#ctx;
#nameId;
#namespaceId;
/**
* @param {AstContext} ctx
2024-12-12 20:53:08 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
* @param {number} nameId
* @param {number} nsId
*/
2024-12-12 20:53:08 +01:00
constructor(ctx, parentId, range, nameId, nsId) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.#ctx = ctx;
this.range = range;
this.#nameId = nameId;
this.#namespaceId = nsId;
}
}
/** @implements {Deno.JSXOpeningElement} */
2024-12-12 22:16:49 +01:00
class JSXOpeningElement extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXOpeningElement");
range;
get attributes() {
2024-12-11 17:10:05 +01:00
return createChildNodes(this.#ctx, this.#attrIds);
2024-12-07 00:24:36 +01:00
}
get name() {
return /** @type {Deno.JSXIdentifier} */ (createAstNode(
this.#ctx,
this.#nameId,
));
}
#ctx;
#nameId;
2024-12-11 17:10:05 +01:00
#attrIds;
2024-12-07 00:24:36 +01:00
selfClosing = false;
/**
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-06 23:26:11 +01:00
* @param {Deno.Range} range
2024-12-11 17:10:05 +01:00
* @param {boolean} isSelfClosing
2024-12-07 00:24:36 +01:00
* @param {number} nameId
2024-12-11 17:10:05 +01:00
* @param {number[]} attrIds
2024-12-06 23:26:11 +01:00
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, isSelfClosing, nameId, attrIds) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.#ctx = ctx;
2024-12-11 17:10:05 +01:00
this.selfClosing = isSelfClosing;
2024-12-07 00:24:36 +01:00
this.#nameId = nameId;
2024-12-11 17:10:05 +01:00
this.#attrIds = attrIds;
2024-12-07 00:24:36 +01:00
this.range = range;
}
}
/** @implements {Deno.JSXOpeningFragment} */
2024-12-12 22:16:49 +01:00
class JSXOpeningFragment extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXOpeningFragment");
range;
/**
* @param {AstContext} ctx
2024-12-11 12:47:45 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
*/
2024-12-11 12:47:45 +01:00
constructor(ctx, parentId, range) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.range = range;
}
}
/** @implements {Deno.JSXSpreadAttribute} */
2024-12-12 22:16:49 +01:00
class JSXSpreadAttribute extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXSpreadAttribute");
range;
get argument() {
return /** @type {Deno.Expression} */ (createAstNode(
this.#ctx,
this.#argId,
));
}
#ctx;
#argId;
/**
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
* @param {number} argId
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, argId) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.#ctx = ctx;
this.range = range;
this.#argId = argId;
}
}
/** @implements {Deno.JSXText} */
2024-12-12 22:16:49 +01:00
class JSXText extends Node {
2024-12-07 00:24:36 +01:00
type = /** @type {const} */ ("JSXText");
range;
value = "";
raw = "";
/**
* @param {AstContext} ctx
2024-12-11 17:10:05 +01:00
* @param {number} parentId
2024-12-07 00:24:36 +01:00
* @param {Deno.Range} range
* @param {number} valueId
* @param {number} rawId
*/
2024-12-11 17:10:05 +01:00
constructor(ctx, parentId, range, valueId, rawId) {
super(ctx, parentId);
2024-12-07 00:24:36 +01:00
this.range = range;
this.value = getString(ctx, valueId);
this.raw = getString(ctx, rawId);
2024-12-05 01:18:08 +01:00
}
}
2024-12-06 23:26:11 +01:00
const DECODER = new TextDecoder();
2024-12-05 02:24:26 +01:00
2024-12-06 23:26:11 +01:00
/**
* @typedef {{
* buf: Uint8Array,
* strTable: Map<number, string>,
2024-12-07 00:24:36 +01:00
* idTable: number[],
2024-12-12 20:53:08 +01:00
* rootId: number
2024-12-07 00:24:36 +01:00
* }} AstContext
2024-12-06 23:26:11 +01:00
*/
2024-12-05 02:24:26 +01:00
2024-12-06 23:26:11 +01:00
/**
* @param {Uint8Array} buf
* @param {number} i
* @returns {number}
*/
function readU32(buf, i) {
return (buf[i] << 24) + (buf[i + 1] << 16) + (buf[i + 2] << 8) +
buf[i + 3];
2024-12-05 02:24:26 +01:00
}
2024-12-10 04:33:33 +01:00
/**
* @param {Uint8Array} buf
* @param {number} offset
* @returns {number[]}
*/
function readChildIds(buf, offset) {
const count = readU32(buf, offset);
offset += 4;
2024-12-10 21:17:02 +01:00
// console.log("read children count:", count, offset);
2024-12-10 04:33:33 +01:00
/** @type {number[]} */
const out = new Array(count);
for (let i = 0; i < count; i++) {
out[i] = readU32(buf, offset);
offset += 4;
}
2024-12-10 21:17:02 +01:00
// console.log("read children", out);
2024-12-10 04:33:33 +01:00
return out;
}
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-06 23:26:11 +01:00
* @param {number} id
* @returns {string}
*/
function getString(ctx, id) {
const name = ctx.strTable.get(id);
if (name === undefined) {
throw new Error(`Missing string id: ${id}`);
2024-12-05 01:18:08 +01:00
}
2024-12-06 23:26:11 +01:00
return name;
2024-12-05 01:18:08 +01:00
}
2024-12-06 23:26:11 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-06 23:26:11 +01:00
* @param {number} id
* @returns {Deno.AstNode}
*/
function createAstNode(ctx, id) {
const { buf, idTable } = ctx;
2024-12-10 04:33:33 +01:00
let offset = idTable[id];
2024-12-10 22:48:54 +01:00
if (offset >= buf.length) {
throw new Error(
`Could not find id: ${id}. Offset ${offset} bigger than buffer length: ${buf.length}`,
);
}
2024-12-10 21:17:02 +01:00
// console.log({ id, offset });
2024-12-10 04:33:33 +01:00
/** @type {AstType} */
const kind = buf[offset];
2024-12-11 13:00:47 +01:00
console.log("creating node", id, kind);
2024-12-10 04:33:33 +01:00
const parentId = readU32(buf, offset + 1);
const rangeStart = readU32(buf, offset + 5);
const rangeEnd = readU32(buf, offset + 9);
2024-12-06 23:26:11 +01:00
const range = /** @type {Deno.Range} */ ([rangeStart, rangeEnd]);
2024-12-10 04:33:33 +01:00
offset += 13;
2024-12-06 23:26:11 +01:00
switch (kind) {
2024-12-10 04:33:33 +01:00
case AstType.Program: {
const moduleType = buf[offset] === 1 ? "module" : "script";
const childIds = readChildIds(buf, offset + 1);
return new Program(ctx, parentId, range, moduleType, childIds);
}
case AstType.Import:
2024-12-11 17:10:05 +01:00
case AstType.ImportDecl:
case AstType.ExportDecl:
case AstType.ExportNamed:
case AstType.ExportDefaultDecl:
case AstType.ExportDefaultExpr:
case AstType.ExportAll:
throw new Error("FIXME");
2024-12-06 23:26:11 +01:00
2024-12-10 21:17:02 +01:00
// Declarations
2024-12-11 17:41:33 +01:00
case AstType.FunctionDeclaration: {
const flags = buf[offset];
const identId = readU32(buf, offset + 1);
const typeParamsId = readU32(buf, offset + 5);
const returnTypeId = readU32(buf, offset + 9);
const bodyId = readU32(buf, offset + 13);
const paramIds = readChildIds(buf, offset + 17);
return new FunctionDeclaration(
ctx,
parentId,
range,
flags,
identId,
typeParamsId,
paramIds,
returnTypeId,
bodyId,
);
}
2024-12-10 21:17:02 +01:00
case AstType.VariableDeclaration: {
const flags = buf[offset];
const childIds = readChildIds(buf, offset + 1);
return new VariableDeclaration(ctx, parentId, range, flags, childIds);
}
case AstType.VariableDeclarator: {
const nameId = readU32(buf, offset);
const initId = readU32(buf, offset + 4);
return new VariableDeclarator(ctx, parentId, range, nameId, initId);
}
2024-12-06 23:26:11 +01:00
// Statements
2024-12-10 04:33:33 +01:00
case AstType.BlockStatement: {
const childIds = readChildIds(buf, offset);
return new BlockStatement(ctx, parentId, range, childIds);
}
case AstType.BreakStatement: {
const labelId = readU32(buf, offset);
return new BreakStatement(ctx, parentId, range, labelId);
}
case AstType.ContinueStatement: {
const labelId = readU32(buf, offset);
return new ContinueStatement(ctx, parentId, range, labelId);
}
case AstType.DebuggerStatement:
return new DebuggerStatement(ctx, parentId, range);
case AstType.DoWhileStatement: {
const exprId = readU32(buf, offset);
const bodyId = readU32(buf, offset + 4);
return new DoWhileStatement(ctx, parentId, range, exprId, bodyId);
}
case AstType.ExpressionStatement: {
const exprId = readU32(buf, offset);
return new ExpressionStatement(ctx, parentId, range, exprId);
}
case AstType.ForInStatement: {
const leftId = readU32(buf, offset);
const rightId = readU32(buf, offset + 4);
const bodyId = readU32(buf, offset + 8);
return new ForInStatement(ctx, parentId, range, leftId, rightId, bodyId);
}
2024-12-10 23:05:38 +01:00
case AstType.ForOfStatement: {
const flags = buf[offset];
const isAwait = (flags & Flags.ForAwait) !== 0;
const leftId = readU32(buf, offset + 1);
const rightId = readU32(buf, offset + 5);
const bodyId = readU32(buf, offset + 9);
return new ForOfStatement(
ctx,
parentId,
range,
isAwait,
leftId,
rightId,
bodyId,
);
}
2024-12-10 04:33:33 +01:00
case AstType.ForStatement: {
const initId = readU32(buf, offset);
const testId = readU32(buf, offset + 4);
const updateId = readU32(buf, offset + 8);
const bodyId = readU32(buf, offset + 12);
return new ForStatement(
ctx,
parentId,
range,
initId,
testId,
updateId,
bodyId,
);
}
case AstType.IfStatement: {
const testId = readU32(buf, offset);
const consequentId = readU32(buf, offset + 4);
const alternateId = readU32(buf, offset + 8);
return new IfStatement(
ctx,
parentId,
range,
testId,
consequentId,
alternateId,
);
}
case AstType.LabeledStatement: {
const labelId = readU32(buf, offset);
const stmtId = readU32(buf, offset + 4);
return new LabeledStatement(ctx, parentId, range, labelId, stmtId);
}
case AstType.ReturnStatement: {
const argId = readU32(buf, offset);
return new ReturnStatement(ctx, parentId, range, argId);
}
2024-12-12 01:35:57 +01:00
case AstType.SwitchStatement: {
const exprId = readU32(buf, offset);
const caseIds = readChildIds(buf, offset + 4);
return new SwitchStatement(ctx, parentId, range, exprId, caseIds);
}
case AstType.SwitchCase: {
const testId = readU32(buf, offset);
const consIds = readChildIds(buf, offset + 4);
return new SwitchCase(ctx, parentId, range, testId, consIds);
}
2024-12-10 04:33:33 +01:00
case AstType.ThrowStatement: {
const argId = readU32(buf, offset);
return new ThrowStatement(ctx, parentId, range, argId);
}
case AstType.TryStatement: {
const blockId = readU32(buf, offset);
const catchId = readU32(buf, offset + 4);
const finalId = readU32(buf, offset + 8);
2024-12-11 17:10:05 +01:00
return new TryStatement(ctx, parentId, range, blockId, catchId, finalId);
2024-12-10 04:33:33 +01:00
}
case AstType.WhileStatement: {
const testId = readU32(buf, offset);
const stmtId = readU32(buf, offset + 4);
return new WhileStatement(ctx, parentId, range, testId, stmtId);
}
case AstType.WithStatement:
return new WithStatement(ctx, range, 0, 0);
2024-12-06 23:26:11 +01:00
// Expressions
2024-12-10 04:33:33 +01:00
case AstType.ArrayExpression: {
const elemIds = readChildIds(buf, offset);
return new ArrayExpression(ctx, parentId, range, elemIds);
}
case AstType.ArrowFunctionExpression: {
const flags = buf[offset];
offset += 1;
2024-12-10 21:17:02 +01:00
const isAsync = (flags & Flags.FnAsync) !== 0;
const isGenerator = (flags & Flags.FnGenerator) !== 0;
2024-12-10 04:33:33 +01:00
const typeParamId = readU32(buf, offset);
offset += 4;
const paramIds = readChildIds(buf, offset);
2024-12-10 22:48:54 +01:00
offset += 4;
2024-12-10 04:33:33 +01:00
offset += paramIds.length * 4;
const bodyId = readU32(buf, offset);
offset += 4;
const returnTypeId = readU32(buf, offset);
offset += 4;
return new ArrowFunctionExpression(
ctx,
parentId,
range,
isAsync,
isGenerator,
typeParamId,
paramIds,
bodyId,
returnTypeId,
);
}
2024-12-10 05:34:12 +01:00
case AstType.AssignmentExpression: {
const flags = buf[offset];
const leftId = readU32(buf, offset + 1);
const rightId = readU32(buf, offset + 5);
return new AssignmentExpression(
ctx,
parentId,
range,
flags,
leftId,
rightId,
);
}
2024-12-11 17:10:05 +01:00
case AstType.AwaitExpression: {
const argId = readU32(buf, offset);
return new AwaitExpression(ctx, parentId, range, argId);
}
case AstType.BinaryExpression: {
const flags = buf[offset];
const leftId = readU32(buf, offset + 1);
const rightId = readU32(buf, offset + 5);
return new BinaryExpression(ctx, parentId, range, flags, leftId, rightId);
}
2024-12-10 04:33:33 +01:00
case AstType.CallExpression: {
2024-12-12 15:20:36 +01:00
const flags = buf[offset];
offset += 1;
2024-12-10 04:33:33 +01:00
const calleeId = readU32(buf, offset);
const typeArgId = readU32(buf, offset + 4);
const childIds = readChildIds(buf, offset + 8);
return new CallExpression(
ctx,
parentId,
range,
2024-12-12 15:20:36 +01:00
flags,
2024-12-10 04:33:33 +01:00
calleeId,
typeArgId,
childIds,
);
}
2024-12-12 15:20:36 +01:00
case AstType.ChainExpression: {
const argId = readU32(buf, offset);
return new ChainExpression(ctx, parentId, range, argId);
}
2024-12-11 11:02:21 +01:00
case AstType.ConditionalExpression: {
const testId = readU32(buf, offset);
const consId = readU32(buf, offset + 4);
const altId = readU32(buf, offset + 8);
return new ConditionalExpression(
ctx,
parentId,
range,
testId,
consId,
altId,
);
}
2024-12-12 01:35:57 +01:00
case AstType.FunctionExpression: {
const flags = buf[offset];
const identId = readU32(buf, offset + 1);
const typeParamId = readU32(buf, offset + 5);
const returnTypeId = readU32(buf, offset + 9);
const bodyId = readU32(buf, offset + 13);
const paramIds = readChildIds(buf, offset + 17);
return new FunctionExpression(
ctx,
parentId,
range,
flags,
identId,
typeParamId,
returnTypeId,
bodyId,
paramIds,
);
}
2024-12-10 04:33:33 +01:00
case AstType.Identifier: {
const strId = readU32(buf, offset);
return new Identifier(ctx, parentId, range, strId);
}
2024-12-10 23:05:38 +01:00
case AstType.LogicalExpression: {
const flags = buf[offset];
const leftId = readU32(buf, offset + 1);
const rightId = readU32(buf, offset + 5);
2024-12-11 17:10:05 +01:00
return new LogicalExpression(
ctx,
parentId,
range,
flags,
leftId,
rightId,
);
2024-12-10 23:05:38 +01:00
}
2024-12-10 04:33:33 +01:00
case AstType.MemberExpression: {
const flags = buf[offset];
offset += 1;
const objId = readU32(buf, offset);
offset += 4;
const propId = readU32(buf, offset);
return new MemberExpression(ctx, parentId, range, flags, objId, propId);
}
case AstType.MetaProperty:
2024-12-11 17:10:05 +01:00
throw new MetaProperty(ctx, parentId, range, 0, 0); // FIXME
case AstType.NewExpression: {
const calleeId = readU32(buf, offset);
const typeId = readU32(buf, offset + 4); // FIXME
const childIds = readChildIds(buf, offset + 8);
throw new NewExpression(ctx, parentId, range, calleeId, childIds);
}
2024-12-10 05:34:12 +01:00
case AstType.ObjectExpression: {
const elemIds = readChildIds(buf, offset);
return new ObjectExpression(ctx, parentId, range, elemIds);
}
2024-12-10 04:33:33 +01:00
case AstType.ParenthesisExpression: {
const exprId = readU32(buf, offset);
return new ParenthesisExpression(ctx, parentId, range, exprId);
}
case AstType.PrivateIdentifier: {
const strId = readU32(buf, offset);
return new PrivateIdentifier(ctx, parentId, range, strId);
}
2024-12-10 05:34:12 +01:00
case AstType.Property: {
const flags = buf[offset]; // FIXME
const keyId = readU32(buf, offset + 1);
const valueId = readU32(buf, offset + 5);
return new Property(ctx, parentId, range, keyId, valueId);
}
2024-12-12 01:35:57 +01:00
case AstType.RestElement: {
const typeId = readU32(buf, offset);
const argId = readU32(buf, offset + 4);
return new RestElement(ctx, parentId, range, argId, typeId);
}
2024-12-10 04:33:33 +01:00
case AstType.SequenceExpression: {
const childIds = readChildIds(buf, offset);
return new SequenceExpression(ctx, parentId, range, childIds);
}
2024-12-10 21:17:02 +01:00
case AstType.SpreadElement: {
const exprId = readU32(buf, offset);
return new SpreadElement(ctx, parentId, range, exprId);
}
2024-12-10 04:33:33 +01:00
case AstType.Super:
2024-12-10 22:48:54 +01:00
throw new Super(ctx, parentId, range);
2024-12-12 20:53:08 +01:00
case AstType.TaggedTemplateExpression: {
const tagId = readU32(buf, offset);
const typeParamId = readU32(buf, offset + 4);
const quasiId = readU32(buf, offset + 8);
return new TaggedTemplateExpression(
ctx,
parentId,
range,
tagId,
typeParamId,
quasiId,
);
}
2024-12-10 22:48:54 +01:00
case AstType.TemplateElement: {
const flags = buf[offset];
const tail = (flags & Flags.TplTail) !== 0;
const rawId = readU32(buf, offset + 1);
const cookedId = readU32(buf, offset + 5);
return new TemplateElement(ctx, parentId, range, rawId, cookedId, tail);
}
case AstType.TemplateLiteral: {
const quasiIds = readChildIds(buf, offset);
offset += 4;
offset += quasiIds.length * 4;
const exprIds = readChildIds(buf, offset);
return new TemplateLiteral(ctx, parentId, range, quasiIds, exprIds);
}
2024-12-11 17:10:05 +01:00
case AstType.UnaryExpression: {
const flags = buf[offset];
const exprId = readU32(buf, offset + 1);
return new UnaryExpression(ctx, parentId, range, flags, exprId);
}
2024-12-11 17:41:33 +01:00
case AstType.UpdateExpression: {
const flags = buf[offset];
const exprId = readU32(buf, offset + 1);
return new UpdateExpression(ctx, parentId, range, flags, exprId);
}
2024-12-11 17:47:46 +01:00
case AstType.YieldExpression: {
const flags = buf[offset];
const exprId = readU32(buf, offset + 1);
return new YieldExpression(ctx, parentId, range, flags, exprId);
}
2024-12-06 23:26:11 +01:00
// Literals
2024-12-10 04:33:33 +01:00
case AstType.BooleanLiteral: {
const flags = buf[offset];
return new BooleanLiteral(ctx, parentId, range, flags);
}
case AstType.BigIntLiteral: {
const strId = readU32(buf, offset);
return new BigIntLiteral(ctx, parentId, range, strId);
}
case AstType.NullLiteral:
return new NullLiteral(ctx, parentId, range);
case AstType.NumericLiteral: {
const strId = readU32(buf, offset);
return new NumericLiteral(ctx, parentId, range, strId);
}
case AstType.RegExpLiteral: {
const patternId = readU32(buf, offset);
const flagsId = readU32(buf, offset + 4);
return new RegExpLiteral(ctx, parentId, range, patternId, flagsId);
}
case AstType.StringLiteral: {
const strId = readU32(buf, offset);
return new StringLiteral(ctx, parentId, range, strId);
}
2024-12-12 01:35:57 +01:00
// Patterns
case AstType.ArrayPattern: {
const flags = buf[offset];
const typeId = readU32(buf, offset + 1);
const elemIds = readChildIds(buf, offset + 5);
return new ArrayPattern(ctx, parentId, range, flags, elemIds, typeId);
}
case AstType.ObjectPattern: {
const flags = buf[offset];
const typeId = readU32(buf, offset + 1);
const elemIds = readChildIds(buf, offset + 5);
return new ObjectPattern(ctx, parentId, range, flags, elemIds, typeId);
}
case AstType.AssignmentPattern: {
const leftId = readU32(buf, offset);
const rightId = readU32(buf, offset + 4);
return new AssignmentPattern(ctx, parentId, range, leftId, rightId);
}
2024-12-10 04:33:33 +01:00
// JSX
2024-12-11 17:10:05 +01:00
case AstType.JSXAttribute: {
const nameId = readU32(buf, offset);
const valueId = readU32(buf, offset + 4);
return new JSXAttribute(ctx, parentId, range, nameId, valueId);
}
case AstType.JSXClosingElement: {
const nameId = readU32(buf, offset);
return new JSXClosingElement(ctx, parentId, range, nameId);
}
2024-12-10 04:33:33 +01:00
case AstType.JSXClosingFragment:
2024-12-11 12:47:45 +01:00
return new JSXClosingFragment(ctx, parentId, range);
case AstType.JSXElement: {
const openingId = readU32(buf, offset);
const closingId = readU32(buf, offset + 4);
const childIds = readChildIds(buf, offset + 8);
return new JSXElement(
ctx,
parentId,
range,
openingId,
closingId,
childIds,
);
}
2024-12-11 17:10:05 +01:00
case AstType.JSXEmptyExpression: {
return new JSXEmptyExpression(ctx, parentId, range);
}
case AstType.JSXExpressionContainer: {
const exprId = readU32(buf, offset);
return new JSXExpressionContainer(ctx, parentId, range, exprId);
}
2024-12-11 12:47:45 +01:00
case AstType.JSXFragment: {
const openingId = readU32(buf, offset);
const closingId = readU32(buf, offset + 4);
const childIds = readChildIds(buf, offset + 8);
return new JSXFragment(
ctx,
parentId,
range,
openingId,
closingId,
childIds,
);
}
case AstType.JSXIdentifier: {
const strId = readU32(buf, offset);
2024-12-11 17:10:05 +01:00
return new JSXIdentifier(ctx, parentId, range, strId);
}
case AstType.JSXMemberExpression: {
const objId = readU32(buf, offset);
const propId = readU32(buf, offset + 4);
return new JSXMemberExpression(ctx, parentId, range, objId, propId);
2024-12-11 12:47:45 +01:00
}
2024-12-10 04:33:33 +01:00
case AstType.JSXNamespacedName:
2024-12-07 00:24:36 +01:00
throw new JSXNamespacedName(ctx, range, 0, 0); // FIXME
2024-12-11 17:10:05 +01:00
case AstType.JSXOpeningElement: {
const flags = buf[offset];
const nameId = readU32(buf, offset + 1);
const attrIds = readChildIds(buf, offset + 5);
const isSelfClosing = (flags & Flags.JSXSelfClosing) !== 0;
return new JSXOpeningElement(
ctx,
parentId,
range,
isSelfClosing,
nameId,
attrIds,
);
}
2024-12-10 04:33:33 +01:00
case AstType.JSXOpeningFragment:
2024-12-11 12:47:45 +01:00
return new JSXOpeningFragment(ctx, parentId, range);
2024-12-11 17:10:05 +01:00
case AstType.JSXSpreadAttribute: {
const childId = readU32(buf, offset);
return new JSXSpreadAttribute(ctx, parentId, range, childId);
}
2024-12-10 04:33:33 +01:00
case AstType.JSXSpreadChild:
2024-12-11 12:47:45 +01:00
throw new Error(`JSXSpreadChild not supported`);
2024-12-11 17:10:05 +01:00
case AstType.JSXText: {
const rawId = readU32(buf, offset);
const valueId = readU32(buf, offset + 4);
return new JSXText(ctx, parentId, range, rawId, valueId);
}
2024-12-07 00:24:36 +01:00
2024-12-06 23:26:11 +01:00
default:
throw new Error(`Unknown ast node ${kind}`);
2024-12-05 01:18:08 +01:00
}
}
2024-12-04 16:21:17 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {Uint8Array} buf
* @param {AstContext} buf
2024-12-04 16:21:17 +01:00
*/
2024-12-07 00:24:36 +01:00
function createAstContext(buf) {
2024-12-10 21:17:02 +01:00
// console.log(buf);
2024-12-05 11:21:34 +01:00
// Extract string table
/** @type {Map<number, string>} */
const strTable = new Map();
2024-12-12 20:53:08 +01:00
// console.log(JSON.stringify(buf, null, 2));
const strTableOffset = readU32(buf, buf.length - 12);
const idTableOffset = readU32(buf, buf.length - 8);
const rootId = readU32(buf, buf.length - 4);
// console.log({ strTableOffset, idTableOffset, rootId });
let offset = strTableOffset;
const stringCount = readU32(buf, offset);
2024-12-10 04:33:33 +01:00
offset += 4;
2024-12-05 11:21:34 +01:00
let id = 0;
2024-12-10 04:33:33 +01:00
for (let i = 0; i < stringCount; i++) {
const len = readU32(buf, offset);
offset += 4;
2024-12-05 11:21:34 +01:00
2024-12-10 04:33:33 +01:00
const strBytes = buf.slice(offset, offset + len);
offset += len;
2024-12-05 11:21:34 +01:00
const s = DECODER.decode(strBytes);
strTable.set(id, s);
id++;
}
2024-12-10 21:17:02 +01:00
// console.log({ stringCount, strTable });
2024-12-05 11:21:34 +01:00
if (strTable.size !== stringCount) {
throw new Error(
`Could not deserialize string table. Expected ${stringCount} items, but got ${strTable.size}`,
);
}
2024-12-10 04:33:33 +01:00
// Build id table
2024-12-12 20:53:08 +01:00
const idCount = readU32(buf, idTableOffset);
2024-12-10 04:33:33 +01:00
offset += 4;
const idTable = new Array(idCount);
for (let i = 0; i < idCount; i++) {
const id = readU32(buf, offset);
idTable[i] = id;
offset += 4;
}
2024-12-10 21:17:02 +01:00
// console.log({ idCount, idTable });
2024-12-10 04:33:33 +01:00
if (idTable.length !== idCount) {
throw new Error(
`Could not deserialize id table. Expected ${idCount} items, but got ${idTable.length}`,
);
}
2024-12-07 00:24:36 +01:00
/** @type {AstContext} */
2024-12-12 20:53:08 +01:00
const ctx = { buf, idTable, strTable, rootId };
// console.log({ strTable, idTable });
2024-12-05 01:18:08 +01:00
2024-12-07 00:24:36 +01:00
return ctx;
2024-12-04 16:21:17 +01:00
}
2024-12-07 00:24:36 +01:00
/**
* @param {string} fileName
* @param {Uint8Array} serializedAst
*/
2024-12-05 11:21:34 +01:00
export function runPluginsForFile(fileName, serializedAst) {
2024-12-07 00:24:36 +01:00
const ctx = createAstContext(serializedAst);
2024-12-10 21:17:02 +01:00
// console.log(JSON.stringify(ctx, null, 2));
2024-12-10 04:33:33 +01:00
/** @type {Record<string, (node: any) => void>} */
2024-12-04 12:42:55 +01:00
const mergedVisitor = {};
const destroyFns = [];
2024-12-10 21:17:02 +01:00
// console.log(state);
2024-12-10 04:33:33 +01:00
2024-12-04 12:42:55 +01:00
// Instantiate and merge visitors. This allows us to only traverse
// the AST once instead of per plugin.
2024-12-07 00:24:36 +01:00
for (let i = 0; i < state.plugins.length; i++) {
2024-12-04 12:42:55 +01:00
const plugin = state.plugins[i];
2024-12-10 04:33:33 +01:00
for (const name of Object.keys(plugin.rules)) {
2024-12-04 12:42:55 +01:00
const rule = plugin.rules[name];
2024-12-07 00:24:36 +01:00
const id = `${plugin.name}/${name}`;
2024-12-04 12:42:55 +01:00
const ctx = new Context(id, fileName);
const visitor = rule.create(ctx);
2024-12-10 21:17:02 +01:00
// console.log({ visitor });
2024-12-10 04:33:33 +01:00
2024-12-04 12:42:55 +01:00
for (const name in visitor) {
const prev = mergedVisitor[name];
mergedVisitor[name] = (node) => {
if (typeof prev === "function") {
prev(node);
}
try {
visitor[name](node);
} catch (err) {
2024-12-10 21:17:02 +01:00
// FIXME: console here doesn't support error cause
console.log(err);
2024-12-04 12:42:55 +01:00
throw new Error(`Visitor "${name}" of plugin "${id}" errored`, {
cause: err,
});
}
};
}
if (typeof rule.destroy === "function") {
2024-12-10 04:33:33 +01:00
const destroyFn = rule.destroy.bind(rule);
2024-12-04 12:42:55 +01:00
destroyFns.push(() => {
try {
2024-12-10 04:33:33 +01:00
destroyFn(ctx);
2024-12-04 12:42:55 +01:00
} catch (err) {
throw new Error(`Destroy hook of "${id}" errored`, { cause: err });
}
});
}
}
2024-12-04 12:42:55 +01:00
}
2024-12-04 12:42:55 +01:00
// Traverse ast with all visitors at the same time to avoid traversing
// multiple times.
2024-12-07 00:24:36 +01:00
try {
traverse(ctx, mergedVisitor);
} finally {
// Optional: Destroy rules
for (let i = 0; i < destroyFns.length; i++) {
destroyFns[i]();
}
}
}
2024-12-04 12:42:55 +01:00
/**
2024-12-07 00:24:36 +01:00
* @param {AstContext} ctx
2024-12-04 12:42:55 +01:00
* @param {*} visitor
* @returns {void}
*/
2024-12-07 00:24:36 +01:00
function traverse(ctx, visitor) {
2024-12-10 04:33:33 +01:00
const visitTypes = new Map();
2024-12-07 00:24:36 +01:00
// TODO: create visiting types
2024-12-10 04:33:33 +01:00
for (const name in visitor) {
const id = AstType[name];
visitTypes.set(id, name);
}
2024-12-11 13:35:37 +01:00
console.log("buffer len", ctx.buf.length, ctx.buf.byteLength);
2024-12-10 22:48:54 +01:00
console.log("merged visitor", visitor);
console.log("visiting types", visitTypes);
2024-12-10 04:33:33 +01:00
2024-12-12 20:53:08 +01:00
traverseInner(ctx, visitTypes, visitor, ctx.rootId);
2024-12-10 04:33:33 +01:00
}
/**
* @param {AstContext} ctx
* @param {Map<number, string>} visitTypes
* @param {Record<string, (x: any) => void>} visitor
* @param {number} id
*/
function traverseInner(ctx, visitTypes, visitor, id) {
2024-12-12 01:35:57 +01:00
// console.log("traversing id", id);
2024-12-10 04:33:33 +01:00
// Empty id
if (id === 0) return;
2024-12-10 05:34:12 +01:00
const { idTable, buf } = ctx;
2024-12-10 04:33:33 +01:00
if (id >= idTable.length) {
2024-12-10 21:17:02 +01:00
throw new Error(`Invalid node id: ${id}`);
2024-12-10 04:33:33 +01:00
}
let offset = idTable[id];
if (offset === undefined) throw new Error(`Unknown id: ${id}`);
const type = buf[offset];
2024-12-12 01:35:57 +01:00
// console.log({ id, type, offset });
2024-12-10 04:33:33 +01:00
const name = visitTypes.get(type);
if (name !== undefined) {
const node = createAstNode(ctx, id);
visitor[name](node);
}
// type + parentId + SpanLo + SpanHi
offset += 1 + 4 + 4 + 4;
2024-12-07 00:24:36 +01:00
2024-12-10 04:33:33 +01:00
// Children
switch (type) {
case AstType.Program: {
// skip flag reading during traversal
offset += 1;
const childIds = readChildIds(buf, offset);
2024-12-12 20:53:08 +01:00
traverseChildren(ctx, visitTypes, visitor, childIds);
return;
2024-12-01 05:14:46 +01:00
}
2024-12-11 17:41:33 +01:00
case AstType.FunctionDeclaration: {
// Skip flags
offset += 1;
const identId = readU32(buf, offset);
const typeParamsId = readU32(buf, offset + 4);
const returnTypeId = readU32(buf, offset + 8);
const bodyId = readU32(buf, offset + 12);
const paramIds = readChildIds(buf, offset + 16);
traverseInner(ctx, visitTypes, visitor, identId);
traverseInner(ctx, visitTypes, visitor, typeParamsId);
traverseChildren(ctx, visitTypes, visitor, paramIds);
traverseInner(ctx, visitTypes, visitor, returnTypeId);
traverseInner(ctx, visitTypes, visitor, bodyId);
return;
}
2024-12-10 21:17:02 +01:00
case AstType.VariableDeclaration: {
// Skip flags
offset += 1;
const childIds = readChildIds(buf, offset);
traverseChildren(ctx, visitTypes, visitor, childIds);
return;
}
2024-12-11 17:41:33 +01:00
case AstType.ForStatement: {
const initId = readU32(buf, offset);
const testId = readU32(buf, offset + 4);
const updateId = readU32(buf, offset + 8);
const bodyId = readU32(buf, offset + 12);
traverseInner(ctx, visitTypes, visitor, initId);
traverseInner(ctx, visitTypes, visitor, testId);
traverseInner(ctx, visitTypes, visitor, updateId);
traverseInner(ctx, visitTypes, visitor, bodyId);
return;
}
2024-12-03 02:51:29 +01:00
2024-12-12 01:35:57 +01:00
case AstType.SwitchStatement: {
const exprId = readU32(buf, offset);
const caseIds = readChildIds(buf, offset + 4);
traverseInner(ctx, visitTypes, visitor, exprId);
traverseChildren(ctx, visitTypes, visitor, caseIds);
return;
}
case AstType.SwitchCase: {
const testId = readU32(buf, offset);
const consIds = readChildIds(buf, offset + 4);
traverseInner(ctx, visitTypes, visitor, testId);
traverseChildren(ctx, visitTypes, visitor, consIds);
return;
}
2024-12-10 04:33:33 +01:00
// Multiple children only
case AstType.ArrayExpression:
case AstType.BlockStatement:
2024-12-10 05:34:12 +01:00
case AstType.ObjectExpression:
2024-12-10 04:33:33 +01:00
case AstType.SequenceExpression: {
const stmtsIds = readChildIds(buf, offset);
2024-12-12 01:35:57 +01:00
traverseChildren(ctx, visitTypes, visitor, stmtsIds);
return;
2024-12-10 04:33:33 +01:00
}
// Expressions
case AstType.CallExpression: {
2024-12-12 15:20:36 +01:00
offset += 1; // skip flags
2024-12-12 20:53:08 +01:00
const calleeId = readU32(buf, offset);
const typeArgId = readU32(buf, offset + 4);
const childIds = readChildIds(buf, offset + 8);
2024-12-12 04:19:11 +01:00
traverseInner(ctx, visitTypes, visitor, calleeId);
traverseInner(ctx, visitTypes, visitor, typeArgId);
traverseChildren(ctx, visitTypes, visitor, childIds);
return;
2024-12-10 04:33:33 +01:00
}
case AstType.ArrowFunctionExpression: {
// Skip flags
offset += 1;
const typeParamId = readU32(buf, offset);
offset += 4;
if (typeParamId > 0) {
traverseInner(ctx, visitTypes, visitor, typeParamId);
}
const childIds = readChildIds(buf, offset);
2024-12-10 22:48:54 +01:00
offset += 4;
2024-12-10 04:33:33 +01:00
offset += childIds.length * 4;
traverseChildren(ctx, visitTypes, visitor, childIds);
const bodyId = readU32(buf, offset);
offset += 4;
traverseInner(ctx, visitTypes, visitor, bodyId);
const returnTypeId = readU32(buf, offset);
traverseInner(ctx, visitTypes, visitor, returnTypeId);
return;
}
case AstType.MemberExpression: {
// Skip flags
offset += 1;
const objId = readU32(buf, offset);
const propId = readU32(buf, offset + 4);
traverseInner(ctx, visitTypes, visitor, objId);
traverseInner(ctx, visitTypes, visitor, propId);
return;
}
2024-12-10 05:34:12 +01:00
case AstType.AssignmentExpression: {
// Skip flags
offset += 1;
const leftId = readU32(buf, offset);
const rightId = readU32(buf, offset + 4);
traverseInner(ctx, visitTypes, visitor, leftId);
traverseInner(ctx, visitTypes, visitor, rightId);
return;
}
2024-12-11 17:10:05 +01:00
case AstType.BinaryExpression:
case AstType.LogicalExpression: {
// Skip flags
offset += 1;
const leftId = readU32(buf, offset);
const rightId = readU32(buf, offset + 4);
traverseInner(ctx, visitTypes, visitor, leftId);
traverseInner(ctx, visitTypes, visitor, rightId);
return;
}
2024-12-10 05:34:12 +01:00
case AstType.Property: {
// Skip flags
offset += 1;
const keyId = readU32(buf, offset);
const valueId = readU32(buf, offset + 4);
traverseInner(ctx, visitTypes, visitor, keyId);
traverseInner(ctx, visitTypes, visitor, valueId);
return;
}
2024-12-10 04:33:33 +01:00
2024-12-11 12:47:45 +01:00
case AstType.JSXElement:
case AstType.JSXFragment: {
const openingId = readU32(buf, offset);
const closingId = readU32(buf, offset + 4);
const childIds = readChildIds(buf, offset + 8);
traverseInner(ctx, visitTypes, visitor, openingId);
traverseInner(ctx, visitTypes, visitor, closingId);
traverseChildren(ctx, visitTypes, visitor, childIds);
return;
}
2024-12-11 17:10:05 +01:00
case AstType.JSXOpeningElement: {
// Skip flags
offset += 1;
const nameId = readU32(buf, offset);
const childIds = readChildIds(buf, offset + 4);
traverseInner(ctx, visitTypes, visitor, nameId);
traverseChildren(ctx, visitTypes, visitor, childIds);
return;
}
2024-12-11 17:41:33 +01:00
case AstType.UnaryExpression:
2024-12-11 17:47:46 +01:00
case AstType.UpdateExpression:
case AstType.YieldExpression: {
2024-12-11 17:10:05 +01:00
// Skip flags
offset += 1;
const exprId = readU32(buf, offset);
traverseInner(ctx, visitTypes, visitor, exprId);
return;
}
case AstType.ForOfStatement: {
// Skip flags
offset += 1;
const firstId = readU32(buf, offset);
const secondId = readU32(buf, offset + 4);
const thirdId = readU32(buf, offset + 8);
traverseInner(ctx, visitTypes, visitor, firstId);
traverseInner(ctx, visitTypes, visitor, secondId);
traverseInner(ctx, visitTypes, visitor, thirdId);
return;
}
case AstType.NewExpression: {
const calleeId = readU32(buf, offset);
const typeId = readU32(buf, offset + 4);
const childIds = readChildIds(buf, offset + 8);
traverseInner(ctx, visitTypes, visitor, calleeId);
traverseInner(ctx, visitTypes, visitor, typeId);
traverseChildren(ctx, visitTypes, visitor, childIds);
return;
}
2024-12-12 01:35:57 +01:00
case AstType.FunctionExpression: {
offset += 1; // Flag
const identId = readU32(buf, offset);
const typeParamId = readU32(buf, offset + 4);
const returnTypeId = readU32(buf, offset + 8);
const bodyId = readU32(buf, offset + 12);
const paramIds = readChildIds(buf, offset + 16);
traverseInner(ctx, visitTypes, visitor, identId);
traverseInner(ctx, visitTypes, visitor, typeParamId);
traverseChildren(ctx, visitTypes, visitor, paramIds);
traverseInner(ctx, visitTypes, visitor, returnTypeId);
traverseInner(ctx, visitTypes, visitor, bodyId);
return;
}
// Patterns
case AstType.ArrayPattern:
case AstType.ObjectPattern: {
// Skip flags
offset += 1;
const typeId = readU32(buf, offset);
const elemIds = readChildIds(buf, offset + 4);
traverseChildren(ctx, visitTypes, visitor, elemIds);
traverseInner(ctx, visitTypes, visitor, typeId);
return;
}
2024-12-11 17:10:05 +01:00
// Three children
2024-12-11 17:41:33 +01:00
case AstType.ConditionalExpression:
2024-12-11 17:10:05 +01:00
case AstType.ForInStatement:
2024-12-12 20:53:08 +01:00
case AstType.IfStatement:
case AstType.TaggedTemplateExpression: {
2024-12-11 17:10:05 +01:00
const firstId = readU32(buf, offset);
const secondId = readU32(buf, offset + 4);
const thirdId = readU32(buf, offset + 8);
traverseInner(ctx, visitTypes, visitor, firstId);
traverseInner(ctx, visitTypes, visitor, secondId);
traverseInner(ctx, visitTypes, visitor, thirdId);
return;
}
2024-12-11 12:47:45 +01:00
2024-12-10 04:33:33 +01:00
// Two children
2024-12-10 05:34:12 +01:00
case AstType.AssignmentPattern:
2024-12-12 01:35:57 +01:00
case AstType.DoWhileStatement:
2024-12-11 17:10:05 +01:00
case AstType.JSXAttribute:
case AstType.JSXMemberExpression:
2024-12-10 04:33:33 +01:00
case AstType.LabeledStatement:
2024-12-12 01:35:57 +01:00
case AstType.RestElement:
2024-12-10 21:17:02 +01:00
case AstType.VariableDeclarator:
2024-12-10 04:33:33 +01:00
case AstType.WhileStatement: {
const firstId = readU32(buf, offset);
const secondId = readU32(buf, offset + 4);
2024-12-11 17:10:05 +01:00
traverseInner(ctx, visitTypes, visitor, firstId);
traverseInner(ctx, visitTypes, visitor, secondId);
return;
2024-12-10 04:33:33 +01:00
}
// Single child
2024-12-11 17:10:05 +01:00
case AstType.AwaitExpression:
2024-12-10 04:33:33 +01:00
case AstType.BreakStatement:
case AstType.ContinueStatement:
2024-12-12 15:20:36 +01:00
case AstType.ChainExpression:
2024-12-10 04:33:33 +01:00
case AstType.ExpressionStatement:
2024-12-11 17:10:05 +01:00
case AstType.JSXClosingElement:
case AstType.JSXExpressionContainer:
2024-12-11 12:47:45 +01:00
case AstType.JSXIdentifier:
2024-12-11 17:10:05 +01:00
case AstType.JSXSpreadAttribute:
2024-12-10 04:33:33 +01:00
case AstType.ReturnStatement:
2024-12-10 21:17:02 +01:00
case AstType.SpreadElement:
2024-12-12 01:35:57 +01:00
case AstType.ThrowStatement:
2024-12-10 04:33:33 +01:00
case AstType.ParenthesisExpression: {
const childId = readU32(buf, offset);
return traverseInner(ctx, visitTypes, visitor, childId);
}
// These have no children
case AstType.BooleanLiteral:
case AstType.BigIntLiteral:
case AstType.DebuggerStatement:
case AstType.Identifier:
2024-12-11 12:47:45 +01:00
case AstType.JSXClosingFragment:
2024-12-11 17:10:05 +01:00
case AstType.JSXEmptyExpression:
2024-12-11 12:47:45 +01:00
case AstType.JSXOpeningFragment:
2024-12-11 17:10:05 +01:00
case AstType.JSXText:
2024-12-10 04:33:33 +01:00
case AstType.NullLiteral:
case AstType.NumericLiteral:
case AstType.PrivateIdentifier:
case AstType.RegExpLiteral:
case AstType.StringLiteral:
case AstType.TemplateLiteral:
case AstType.This:
return;
default:
throw new Error(`Unknown ast type: ${type}`);
}
}
/**
* @param {AstContext} ctx
* @param {Map<number, string>} visitTypes
* @param {Record<string, *>} visitor
* @param {number[]} ids
*/
function traverseChildren(ctx, visitTypes, visitor, ids) {
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
traverseInner(ctx, visitTypes, visitor, id);
2024-12-01 05:14:46 +01:00
}
2024-12-01 04:53:47 +01:00
}