From 963abe986a9bdab7fe7ad2b43f02ec466b4913dd Mon Sep 17 00:00:00 2001 From: Marvin Hagemeister Date: Sun, 15 Dec 2024 19:15:29 +0100 Subject: [PATCH] wip --- cli/js/40_lint.js | 377 ++++++++------------------- cli/tools/lint/ast_buf.rs | 495 +++++++++++------------------------- cli/tools/lint/mod.rs | 1 + cli/tools/lint/swc.rs | 140 +++++----- cli/tools/lint/ts_estree.rs | 467 ++++++++++++++++++++++++++++++++++ 5 files changed, 796 insertions(+), 684 deletions(-) create mode 100644 cli/tools/lint/ts_estree.rs diff --git a/cli/js/40_lint.js b/cli/js/40_lint.js index ac47fbd666..ef7504429e 100644 --- a/cli/js/40_lint.js +++ b/cli/js/40_lint.js @@ -10,252 +10,9 @@ const { } = core.ops; // Keep in sync with Rust -/** - * @enum {number} - */ -const AstTypeName = [ - "Invalid", - "Program", - - "Import", - "ImportDecl", - "ExportDecl", - "ExportNamed", - "ExportDefaultDecl", - "ExportDefaultExpr", - "ExportAll", - "TSImportEquals", - "TSExportAssignment", - "TSNamespaceExport", - - // Decls - "ClassDeclaration", - "FunctionDeclaration", - "VariableDeclaration", - "Using", - "TsInterface", - "TsTypeAlias", - "TsEnum", - "TsModule", - - // Statements - "BlockStatement", - "Empty", - "DebuggerStatement", - "WithStatement", - "ReturnStatement", - "LabeledStatement", - "BreakStatement", - "ContinueStatement", - "IfStatement", - "SwitchStatement", - "SwitchCase", - "ThrowStatement", - "TryStatement", - "WhileStatement", - "DoWhileStatement", - "ForStatement", - "ForInStatement", - "ForOfStatement", - "Decl", - "ExpressionStatement", - - // Expressions - "This", - "ArrayExpression", - "ObjectExpression", - "FunctionExpression", - "UnaryExpression", - "UpdateExpression", - "BinaryExpression", - "AssignmentExpression", - "MemberExpression", - "Super", - "ConditionalExpression", - "CallExpression", - "NewExpression", - "ParenthesisExpression", - "SequenceExpression", - "Identifier", - "TemplateLiteral", - "TaggedTemplateExpression", - "ArrowFunctionExpression", - "ClassExpr", - "YieldExpression", - "MetaProperty", - "AwaitExpression", - "LogicalExpression", - "TSTypeAssertion", - "TSConstAssertion", - "TSNonNull", - "TSAs", - "TSInstantiation", - "TSSatisfies", - "PrivateIdentifier", - "ChainExpression", - - "StringLiteral", - "BooleanLiteral", - "NullLiteral", - "NumericLiteral", - "BigIntLiteral", - "RegExpLiteral", - - // Custom - "EmptyExpr", - "SpreadElement", - "Property", - "VariableDeclarator", - "CatchClause", - "RestElement", - "ExportSpecifier", - "TemplateElement", - "MethodDefinition", - - // Patterns - "ArrayPattern", - "AssignmentPattern", - "ObjectPattern", - - // JSX - "JSXAttribute", - "JSXClosingElement", - "JSXClosingFragment", - "JSXElement", - "JSXEmptyExpression", - "JSXExpressionContainer", - "JSXFragment", - "JSXIdentifier", - "JSXMemberExpression", - "JSXNamespacedName", - "JSXOpeningElement", - "JSXOpeningFragment", - "JSXSpreadAttribute", - "JSXSpreadChild", - "JSXText", -]; - -/** @type {Map} */ -const AstType = new Map(); -for (let i = 0; i < AstTypeName.length; i++) { - AstType.set(AstTypeName[i], i); -} - -// Keep in sync with Rust -const AstPropArr = [ - // Base - "parent", - "range", - "type", - "_InternalFlags", - - // Node - "abstract", - "accessibility", - "alternate", - "argument", - "arguments", - "async", - "attributes", - "await", - "block", - "body", - "callee", - "cases", - "children", - "checkType", - "closingElement", - "closingFragment", - "computed", - "consequent", - "const", - "constraint", - "cooked", - "declarations", - "declare", - "default", - "definite", - "delegate", - "discriminant", - "elements", - "elementTypes", - "exprName", - "expression", - "expressions", - "exported", - "extendsType", - "falseType", - "finalizer", - "flags", - "generator", - "handler", - "id", - "in", - "init", - "initializer", - "implements", - "key", - "kind", - "label", - "left", - "literal", - "local", - "members", - "meta", - "method", - "name", - "namespace", - "nameType", - "object", - "openingElement", - "openingFragment", - "operator", - "optional", - "out", - "param", - "params", - "pattern", - "prefix", - "properties", - "property", - "quasi", - "quasis", - "raw", - "readonly", - "returnType", - "right", - "selfClosing", - "shorthand", - "source", - "sourceType", - "specifiers", - "superClass", - "superTypeArguments", - "tag", - "tail", - "test", - "trueType", - "typeAnnotation", - "typeArguments", - "typeName", - "typeParameter", - "typeParameters", - "types", - "update", - "value", -]; - -/** @type {Map} */ -const AstProp = new Map(); -for (let i = 0; i < AstPropArr.length; i++) { - AstProp.set(AstPropArr[i], i); -} - -const AST_PROP_TYPE = /** @type {number} */ (AstProp.get("type")); -const AST_PROP_PARENT = /** @type {number} */ (AstProp.get("parent")); -const AST_PROP_RANGE = /** @type {number} */ (AstProp.get("range")); - -const AstPropName = Array.from(AstProp.keys()); +const AST_PROP_TYPE = 0; +const AST_PROP_PARENT = 1; +const AST_PROP_RANGE = 2; // Keep in sync with Rust /** @enum {number} */ @@ -274,7 +31,10 @@ const PropFlags = { * strTable: Map, * strTableOffset: number, * rootId: number, - * nodes: Map + * nodes: Map, + * strByType: number[], + * typeByStr: Map, + * strByProp: number[] * }} AstContext */ @@ -421,7 +181,7 @@ function readValue(ctx, offset, search) { const type = buf[offset]; if (search === AST_PROP_TYPE) { - return AstTypeName[type]; + return getString(ctx, ctx.strByType[type]); } else if (search === AST_PROP_RANGE) { const start = readU32(buf, offset + 1 + 4); const end = readU32(buf, offset + 1 + 4 + 4); @@ -484,7 +244,7 @@ function toJsValue(ctx, offset) { for (let i = 0; i < count; i++) { const prop = buf[offset++]; const kind = buf[offset++]; - const name = AstPropName[prop]; + const name = getString(ctx, ctx.strByProp[prop]); if (kind === PropFlags.Ref) { const v = readU32(buf, offset); @@ -545,13 +305,28 @@ class Node { } } -for (let i = 0; i < AstPropName.length; i++) { - const name = AstPropName[i]; - Object.defineProperty(Node.prototype, name, { - get() { - return readValue(this[INTERNAL_CTX], this[INTERNAL_OFFSET], i); - }, - }); +/** @type {Set} */ +const appliedGetters = new Set(); + +/** + * @param {AstContext} ctx + */ +function setNodeGetters(ctx) { + if (appliedGetters.size === ctx.strByProp.length) return; + + for (let i = 0; i < ctx.strByProp.length; i++) { + const id = ctx.strByProp[i]; + if (id === 0 || appliedGetters.has(i)) continue; + appliedGetters.add(i); + + const name = getString(ctx, id); + + Object.defineProperty(Node.prototype, name, { + get() { + return readValue(this[INTERNAL_CTX], this[INTERNAL_OFFSET], i); + }, + }); + } } const DECODER = new TextDecoder(); @@ -590,6 +365,8 @@ function createAstContext(buf) { // console.log(JSON.stringify(buf, null, 2)); + const typeMapOffset = readU32(buf, buf.length - 16); + const propMapOffset = readU32(buf, buf.length - 12); const strTableOffset = readU32(buf, buf.length - 8); const rootId = readU32(buf, buf.length - 4); // console.log({ strTableOffset, rootId }); @@ -618,10 +395,48 @@ function createAstContext(buf) { ); } - /** @type {AstContext} */ - const ctx = { buf, strTable, rootId, nodes: new Map(), strTableOffset }; + offset = typeMapOffset; + const typeCount = readU32(buf, offset); + offset += 4; - // dump(ctx); + const typeByStr = new Map(); + const strByType = new Array(typeCount).fill(0); + for (let i = 0; i < typeCount; i++) { + const v = readU32(buf, offset); + offset += 4; + + // console.log("type: ", i, v, strTable.get(v)); + strByType[i] = v; + typeByStr.set(strTable.get(v), i); + } + + offset = propMapOffset; + const propCount = readU32(buf, offset); + offset += 4; + + const strByProp = new Array(propCount).fill(0); + for (let i = 0; i < propCount; i++) { + const v = readU32(buf, offset); + offset += 4; + + strByProp[i] = v; + } + + /** @type {AstContext} */ + const ctx = { + buf, + strTable, + rootId, + nodes: new Map(), + strTableOffset, + strByProp, + strByType, + typeByStr, + }; + + setNodeGetters(ctx); + + // _dump(ctx); return ctx; } @@ -709,11 +524,11 @@ function traverse(ctx, visitor) { // TODO: create visiting types for (const name in visitor) { - const id = AstType.get(name); + const id = ctx.typeByStr.get(name); + if (id === undefined) continue; visitTypes.set(id, name); } - // console.log("buffer len", ctx.buf.length, ctx.buf.byteLength); console.log("merged visitor", visitor); console.log("visiting types", visitTypes); @@ -779,13 +594,31 @@ function traverseInner(ctx, visitTypes, visitor, offset) { * @param {AstContext} ctx */ function _dump(ctx) { - const { buf, strTableOffset } = ctx; + const { buf, strTableOffset, strTable, strByType, strByProp } = ctx; + + // @ts-ignore dump fn + console.log(strTable); + + for (let i = 0; i < strByType.length; i++) { + const v = strByType[i]; + // @ts-ignore dump fn + if (v > 0) console.log(" > type:", i, getString(ctx, v), v); + } + // @ts-ignore dump fn + console.log(); + for (let i = 0; i < strByProp.length; i++) { + const v = strByProp[i]; + // @ts-ignore dump fn + if (v > 0) console.log(" > prop:", i, getString(ctx, v), v); + } + // @ts-ignore dump fn + console.log(); let offset = 0; while (offset < strTableOffset) { const type = buf[offset]; - const name = AstTypeName[type]; + const name = getString(ctx, ctx.strByType[type]); // @ts-ignore dump fn console.log(`${name}, offset: ${offset}, type: ${type}`); offset += 1; @@ -800,7 +633,7 @@ function _dump(ctx) { const end = readU32(buf, offset); offset += 4; // @ts-ignore dump fn - console.log(` range: ${start} -> ${end}}`); + console.log(` range: ${start} -> ${end}`); const count = buf[offset++]; // @ts-ignore dump fn @@ -809,7 +642,7 @@ function _dump(ctx) { for (let i = 0; i < count; i++) { const prop = buf[offset++]; const kind = buf[offset++]; - const name = AstPropName[prop]; + const name = getString(ctx, ctx.strByProp[prop]); let kindName = "unknown"; for (const k in PropFlags) { @@ -823,35 +656,35 @@ function _dump(ctx) { const v = readU32(buf, offset); offset += 4; // @ts-ignore dump fn - console.log(` ${name}: ${v} (${kindName})`); + console.log(` ${name}: ${v} (${kindName}, ${prop})`); } else if (kind === PropFlags.RefArr) { const len = readU32(buf, offset); offset += 4; // @ts-ignore dump fn - console.log(` ${name}: Array(${len}) (${kindName})`); + console.log(` ${name}: Array(${len}) (${kindName}, ${prop})`); for (let j = 0; j < len; j++) { const v = readU32(buf, offset); offset += 4; // @ts-ignore dump fn - console.log(` - ${v}`); + console.log(` - ${v} (${prop})`); } } else if (kind === PropFlags.Bool) { const v = buf[offset]; offset += 1; // @ts-ignore dump fn - console.log(` ${name}: ${v} (${kindName})`); + console.log(` ${name}: ${v} (${kindName}, ${prop})`); } else if (kind === PropFlags.String) { const v = readU32(buf, offset); offset += 4; // @ts-ignore dump fn - console.log(` ${name}: ${getString(ctx, v)} (${kindName})`); + console.log(` ${name}: ${getString(ctx, v)} (${kindName}, ${prop})`); } else if (kind === PropFlags.Null) { // @ts-ignore dump fn - console.log(` ${name}: null (${kindName})`); + console.log(` ${name}: null (${kindName}, ${prop})`); } else if (kind === PropFlags.Undefined) { // @ts-ignore dump fn - console.log(` ${name}: undefined (${kindName})`); + console.log(` ${name}: undefined (${kindName}, ${prop})`); } } } diff --git a/cli/tools/lint/ast_buf.rs b/cli/tools/lint/ast_buf.rs index 9a51ce58d1..c13eff7d84 100644 --- a/cli/tools/lint/ast_buf.rs +++ b/cli/tools/lint/ast_buf.rs @@ -1,283 +1,8 @@ +use std::fmt::Display; + use deno_ast::swc::common::{Span, DUMMY_SP}; use indexmap::IndexMap; -// Keep in sync with JS -#[derive(Debug, PartialEq)] -pub enum AstNode { - Invalid, - // - Program, - - // Module declarations - Import, - ImportDecl, - ExportDecl, - ExportNamedDeclaration, - ExportDefaultDecl, - ExportDefaultExpr, - ExportAll, - TsImportEquals, - TsExportAssignment, - TsNamespaceExport, - - // Decls - ClassDeclaration, - Fn, - Var, - Using, - TSInterface, - TsTypeAlias, - TSEnumDeclaration, - TsModule, - - // Statements - Block, - Empty, - Debugger, - With, - Return, - Labeled, - Break, - Continue, - IfStatement, - Switch, - SwitchCase, - Throw, - TryStatement, - WhileStatement, - DoWhileStatement, - ForStatement, - ForInStatement, - ForOfStatement, - Decl, - ExpressionStatement, - - // Expressions - This, - ArrayExpression, - Object, - FunctionExpression, - UnaryExpression, - UpdateExpression, - BinaryExpression, - Assign, - MemberExpression, - Super, - ConditionalExpression, - CallExpression, - New, - Paren, - SequenceExpression, - Identifier, - TemplateLiteral, - TaggedTemplateExpression, - ArrowFunctionExpression, - ClassExpr, - YieldExpression, - MetaProp, - AwaitExpression, - LogicalExpression, - TSTypeAssertion, - TsConstAssertion, - TSNonNullExpression, - TSAsExpression, - TsInstantiation, - TSSatisfiesExpression, - PrivateIdentifier, - ChainExpression, - - // Literals - StringLiteral, - Bool, - Null, - NumericLiteral, - BigIntLiteral, - RegExpLiteral, - - // Custom - EmptyExpr, - Spread, - Property, - VariableDeclarator, - CatchClause, - RestElement, - ExportSpecifier, - TemplateElement, - MethodDefinition, - - // Patterns - ArrayPattern, - AssignmentPattern, - ObjectPattern, - - // JSX - JSXAttribute, - JSXClosingElement, - JSXClosingFragment, - JSXElement, - JSXEmptyExpression, - JSXExpressionContainer, - JSXFragment, - JSXIdentifier, - JSXMemberExpression, - JSXNamespacedName, - JSXOpeningElement, - JSXOpeningFragment, - JSXSpreadAttribute, - JSXSpreadChild, - JSXText, - - TSTypeAnnotation, - TSTypeParameterDeclaration, - TSTypeParameter, - TSEnumMember, - TSInterfaceBody, - TSInterfaceHeritage, - TSTypeReference, - TSThisType, - TSLiteralType, - TSInferType, - TSConditionalType, - TSUnionType, - TSIntersectionType, - TSMappedType, - TSTypeQuery, - TSTupleType, - TSFunctionType, - TsCallSignatureDeclaration, - - TSAnyKeyword, - TSBigIntKeyword, - TSBooleanKeyword, - TSIntrinsicKeyword, - TSNeverKeyword, - TSNullKeyword, - TSNumberKeyword, - TSObjectKeyword, - TSStringKeyword, - TSSymbolKeyword, - TSUndefinedKeyword, - TSUnknownKeyword, - TSVoidKeyword, - TSEnumBody, -} - -impl From for u8 { - fn from(m: AstNode) -> u8 { - m as u8 - } -} - -// Keep in sync with JS -pub enum AstProp { - // Base - Parent, - Range, - Type, - _InternalFlags, // Private - - // Node - Abstract, - Accessibility, - Alternate, - Argument, - Arguments, - Async, - Attributes, - Await, - Block, - Body, - Callee, - Cases, - Children, - CheckType, - ClosingElement, - ClosingFragment, - Computed, - Consequent, - Const, - Constraint, - Cooked, - Declarations, - Declare, - Default, - Definite, - Delegate, - Discriminant, - Elements, - ElementTypes, - ExprName, - Expression, - Expressions, - Exported, - ExtendsType, - FalseType, - Finalizer, - Flags, - Generator, - Handler, - Id, - In, - Init, - Initializer, - Implements, - Key, - Kind, - Label, - Left, - Literal, - Local, - Members, - Meta, - Method, - Name, - Namespace, - NameType, - Object, - OpeningElement, - OpeningFragment, - Operator, - Optional, - Out, - Param, - Params, - Pattern, - Prefix, - Properties, - Property, - Quasi, - Quasis, - Raw, - Readonly, - ReturnType, - Right, - SelfClosing, - Shorthand, - Source, - SourceType, - Specifiers, - SuperClass, - SuperTypeArguments, - Tag, - Tail, - Test, - TrueType, - TypeAnnotation, - TypeArguments, - TypeName, - TypeParameter, - TypeParameters, - Types, - Update, - Value, -} - -impl From for u8 { - fn from(m: AstProp) -> u8 { - m as u8 - } -} - #[derive(Debug, PartialEq)] pub enum PropFlags { Ref, @@ -346,26 +71,6 @@ pub fn write_usize(result: &mut [u8], value: usize, idx: usize) { result[idx + 3] = v4; } -#[derive(Debug, Clone)] -pub struct FlagValue(pub u8); - -impl FlagValue { - pub fn new() -> Self { - Self(0) - } - - pub fn set(&mut self, flag: impl Into) { - let value: u8 = flag.into(); - self.0 |= value; - } -} - -impl From for u8 { - fn from(item: FlagValue) -> Self { - item.0 - } -} - #[derive(Debug)] pub struct StringTable { id: usize, @@ -411,42 +116,118 @@ impl StringTable { #[derive(Debug, Clone, Copy, PartialEq)] pub struct NodeRef(pub usize); +pub trait AstBufSerializer +where + K: Into + Display, + P: Into + Display, +{ + fn header( + &mut self, + kind: K, + parent: NodeRef, + span: &Span, + prop_count: usize, + ) -> NodeRef; + fn ref_field(&mut self, prop: P) -> usize; + fn ref_vec_field(&mut self, prop: P, len: usize) -> usize; + fn str_field(&mut self, prop: P) -> usize; + fn bool_field(&mut self, prop: P) -> usize; + fn undefined_field(&mut self, prop: P) -> usize; + #[allow(dead_code)] + fn null_field(&mut self, prop: P) -> usize; + + fn write_ref(&mut self, pos: usize, value: NodeRef); + fn write_maybe_ref(&mut self, pos: usize, value: Option); + fn write_refs(&mut self, pos: usize, value: Vec); + fn write_str(&mut self, pos: usize, value: &str); + fn write_bool(&mut self, pos: usize, value: bool); + + fn serialize(&mut self) -> Vec; +} + #[derive(Debug)] pub struct SerializeCtx { - pub buf: Vec, - pub start_buf: NodeRef, - pub str_table: StringTable, + buf: Vec, + start_buf: NodeRef, + str_table: StringTable, + kind_map: Vec, + prop_map: Vec, } impl SerializeCtx { - pub fn new() -> Self { + pub fn new(kind_len: u8, prop_len: u8) -> Self { + let kind_size = kind_len as usize; + let prop_size = prop_len as usize; let mut ctx = Self { start_buf: NodeRef(0), buf: vec![], str_table: StringTable::new(), + kind_map: vec![0; kind_size + 1], + prop_map: vec![0; prop_size + 1], }; ctx.str_table.insert(""); - // Placeholder node - ctx.push_node(AstNode::Invalid, NodeRef(0), &DUMMY_SP); + // Placeholder node is always 0 + ctx.append_node(0, NodeRef(0), &DUMMY_SP, 0); + ctx.kind_map[0] = 0; ctx.start_buf = NodeRef(ctx.buf.len()); + // Insert default props that are always present + let type_str = ctx.str_table.insert("type"); + let parent_str = ctx.str_table.insert("parent"); + let range_str = ctx.str_table.insert("range"); + + ctx.prop_map[0] = type_str; + ctx.prop_map[1] = parent_str; + ctx.prop_map[2] = range_str; + ctx } - /// Begin writing a node - pub fn header( + fn field_header

(&mut self, prop: P, prop_flags: PropFlags) -> usize + where + P: Into + Display + Clone, + { + let offset = self.buf.len(); + + let n: u8 = prop.clone().into(); + self.buf.push(n); + + if let Some(v) = self.prop_map.get::(n.into()) { + if *v == 0 { + let id = self.str_table.insert(&format!("{prop}")); + self.prop_map[n as usize] = id; + } + } + + let flags: u8 = prop_flags.into(); + self.buf.push(flags); + + offset + } + + fn field

(&mut self, prop: P, prop_flags: PropFlags) -> usize + where + P: Into + Display + Clone, + { + let offset = self.field_header(prop, prop_flags); + + append_usize(&mut self.buf, 0); + + offset + } + + fn append_node( &mut self, - kind: AstNode, + kind: u8, parent: NodeRef, span: &Span, prop_count: usize, ) -> NodeRef { let offset = self.buf.len(); - let kind_value: u8 = kind.into(); - self.buf.push(kind_value); + self.buf.push(kind); append_usize(&mut self.buf, parent.0); @@ -460,11 +241,42 @@ impl SerializeCtx { NodeRef(offset) } - pub fn ref_field(&mut self, prop: AstProp) -> usize { + /// Begin writing a node + pub fn header( + &mut self, + kind: N, + parent: NodeRef, + span: &Span, + prop_count: usize, + ) -> NodeRef + where + N: Into + Display + Clone, + { + let n: u8 = kind.clone().into(); + + if let Some(v) = self.kind_map.get::(n.into()) { + if *v == 0 { + let id = self.str_table.insert(&format!("{kind}")); + self.kind_map[n as usize] = id; + } + } + + let offset = self.append_node(n, parent, span, prop_count); + + offset + } + + pub fn ref_field

(&mut self, prop: P) -> usize + where + P: Into + Display + Clone, + { self.field(prop, PropFlags::Ref) } - pub fn ref_vec_field(&mut self, prop: AstProp, len: usize) -> usize { + pub fn ref_vec_field

(&mut self, prop: P, len: usize) -> usize + where + P: Into + Display + Clone, + { let offset = self.field(prop, PropFlags::RefArr); for _ in 0..len { @@ -474,45 +286,37 @@ impl SerializeCtx { offset } - pub fn str_field(&mut self, prop: AstProp) -> usize { + pub fn str_field

(&mut self, prop: P) -> usize + where + P: Into + Display + Clone, + { self.field(prop, PropFlags::String) } - fn field_header(&mut self, prop: AstProp, prop_flags: PropFlags) -> usize { - let offset = self.buf.len(); - - let kind: u8 = prop.into(); - self.buf.push(kind); - - let flags: u8 = prop_flags.into(); - self.buf.push(flags); - - offset - } - - pub fn bool_field(&mut self, prop: AstProp) -> usize { + pub fn bool_field

(&mut self, prop: P) -> usize + where + P: Into + Display + Clone, + { let offset = self.field_header(prop, PropFlags::Bool); self.buf.push(0); offset } - pub fn undefined_field(&mut self, prop: AstProp) -> usize { + pub fn undefined_field

(&mut self, prop: P) -> usize + where + P: Into + Display + Clone, + { self.field_header(prop, PropFlags::Undefined) } #[allow(dead_code)] - pub fn null_field(&mut self, prop: AstProp) -> usize { + pub fn null_field

(&mut self, prop: P) -> usize + where + P: Into + Display + Clone, + { self.field_header(prop, PropFlags::Null) } - fn field(&mut self, prop: AstProp, prop_flags: PropFlags) -> usize { - let offset = self.field_header(prop, prop_flags); - - append_usize(&mut self.buf, 0); - - offset - } - pub fn write_ref(&mut self, field_offset: usize, value: NodeRef) { #[cfg(debug_assertions)] { @@ -586,15 +390,6 @@ impl SerializeCtx { self.buf[field_offset + 2] = if value { 1 } else { 0 }; } - pub fn push_node( - &mut self, - kind: AstNode, - parent: NodeRef, - span: &Span, - ) -> NodeRef { - self.header(kind, parent, span, 0) - } - pub fn serialize(&mut self) -> Vec { let mut buf: Vec = vec![]; @@ -607,6 +402,20 @@ impl SerializeCtx { // eprintln!("STRING {:#?}", self.str_table); buf.append(&mut self.str_table.serialize()); + let offset_kind_map = buf.len(); + append_usize(&mut buf, self.kind_map.len()); + for v in &self.kind_map { + append_usize(&mut buf, *v); + } + + let offset_prop_map = buf.len(); + append_usize(&mut buf, self.prop_map.len()); + for v in &self.prop_map { + append_usize(&mut buf, *v); + } + + append_usize(&mut buf, offset_kind_map); + append_usize(&mut buf, offset_prop_map); append_usize(&mut buf, offset_str_table); append_usize(&mut buf, self.start_buf.0); diff --git a/cli/tools/lint/mod.rs b/cli/tools/lint/mod.rs index ba4db0887e..cadbc0cb7f 100644 --- a/cli/tools/lint/mod.rs +++ b/cli/tools/lint/mod.rs @@ -59,6 +59,7 @@ mod plugins; mod reporters; mod rules; mod swc; +mod ts_estree; pub use linter::CliLinter; pub use linter::CliLinterOptions; diff --git a/cli/tools/lint/swc.rs b/cli/tools/lint/swc.rs index 446bac52cc..7e5d73e19a 100644 --- a/cli/tools/lint/swc.rs +++ b/cli/tools/lint/swc.rs @@ -23,10 +23,13 @@ use deno_ast::{ ParsedSource, }; -use super::ast_buf::{append_usize, AstNode, AstProp, NodeRef, SerializeCtx}; +use super::{ + ast_buf::{AstBufSerializer, NodeRef}, + ts_estree::{AstNode, AstProp, TsEsTreeBuilder}, +}; pub fn serialize_ast_bin(parsed_source: &ParsedSource) -> Vec { - let mut ctx = SerializeCtx::new(); + let mut ctx = TsEsTreeBuilder::new(); let program = &parsed_source.program(); @@ -70,16 +73,16 @@ pub fn serialize_ast_bin(parsed_source: &ParsedSource) -> Vec { } fn serialize_module_decl( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, module_decl: &ModuleDecl, parent: NodeRef, ) -> NodeRef { match module_decl { ModuleDecl::Import(node) => { - ctx.push_node(AstNode::Import, parent, &node.span) + ctx.header(AstNode::Import, parent, &node.span, 0) } ModuleDecl::ExportDecl(node) => { - ctx.push_node(AstNode::ExportDecl, parent, &node.span) + ctx.header(AstNode::ExportDecl, parent, &node.span, 0) } ModuleDecl::ExportNamed(node) => { let id = @@ -139,28 +142,28 @@ fn serialize_module_decl( id } ModuleDecl::ExportDefaultDecl(node) => { - ctx.push_node(AstNode::ExportDefaultDecl, parent, &node.span) + ctx.header(AstNode::ExportDefaultDecl, parent, &node.span, 0) } ModuleDecl::ExportDefaultExpr(node) => { - ctx.push_node(AstNode::ExportDefaultExpr, parent, &node.span) + ctx.header(AstNode::ExportDefaultExpr, parent, &node.span, 0) } ModuleDecl::ExportAll(node) => { - ctx.push_node(AstNode::ExportAll, parent, &node.span) + ctx.header(AstNode::ExportAll, parent, &node.span, 0) } ModuleDecl::TsImportEquals(node) => { - ctx.push_node(AstNode::TsImportEquals, parent, &node.span) + ctx.header(AstNode::TsImportEquals, parent, &node.span, 0) } ModuleDecl::TsExportAssignment(node) => { - ctx.push_node(AstNode::TsExportAssignment, parent, &node.span) + ctx.header(AstNode::TsExportAssignment, parent, &node.span, 0) } ModuleDecl::TsNamespaceExport(node) => { - ctx.push_node(AstNode::TsNamespaceExport, parent, &node.span) + ctx.header(AstNode::TsNamespaceExport, parent, &node.span, 0) } } } fn serialize_stmt( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, stmt: &Stmt, parent: NodeRef, ) -> NodeRef { @@ -181,7 +184,7 @@ fn serialize_stmt( } Stmt::Empty(_) => NodeRef(0), Stmt::Debugger(node) => { - ctx.push_node(AstNode::Debugger, parent, &node.span) + ctx.header(AstNode::Debugger, parent, &node.span, 0) } Stmt::With(_) => todo!(), Stmt::Return(node) => { @@ -438,12 +441,12 @@ fn serialize_stmt( } fn serialize_expr( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, expr: &Expr, parent: NodeRef, ) -> NodeRef { match expr { - Expr::This(node) => ctx.push_node(AstNode::This, parent, &node.span), + Expr::This(node) => ctx.header(AstNode::This, parent, &node.span, 0), Expr::Array(node) => { let pos = ctx.header(AstNode::ArrayExpression, parent, &node.span, 1); let elems_pos = ctx.ref_vec_field(AstProp::Elements, node.elems.len()); @@ -681,7 +684,7 @@ fn serialize_expr( let obj_pos = ctx.ref_field(AstProp::Object); let prop_pos = ctx.ref_field(AstProp::Property); - let obj = ctx.push_node(AstNode::Super, pos, &node.obj.span); + let obj = ctx.header(AstNode::Super, pos, &node.obj.span, 0); let mut computed = false; let prop = match &node.prop { @@ -726,7 +729,7 @@ fn serialize_expr( let callee = match &node.callee { Callee::Super(super_node) => { - ctx.push_node(AstNode::Super, pos, &super_node.span) + ctx.header(AstNode::Super, pos, &super_node.span, 0) } Callee::Import(import) => todo!(), Callee::Expr(expr) => serialize_expr(ctx, expr, pos), @@ -891,7 +894,7 @@ fn serialize_expr( pos } Expr::Class(node) => { - let id = ctx.push_node(AstNode::ClassExpr, parent, &node.class.span); + let id = ctx.header(AstNode::ClassExpr, parent, &node.class.span, 0); // FIXME @@ -913,7 +916,7 @@ fn serialize_expr( pos } Expr::MetaProp(node) => { - ctx.push_node(AstNode::MetaProp, parent, &node.span) + ctx.header(AstNode::MetaProp, parent, &node.span, 0) } Expr::Await(node) => { let pos = ctx.header(AstNode::AwaitExpression, parent, &node.span, 1); @@ -1061,7 +1064,7 @@ fn serialize_expr( } fn serialize_prop_or_spread( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, prop: &PropOrSpread, parent: NodeRef, ) -> NodeRef { @@ -1204,7 +1207,7 @@ fn serialize_prop_or_spread( } fn serialize_member_expr( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &MemberExpr, parent: NodeRef, optional: bool, @@ -1239,7 +1242,7 @@ fn serialize_member_expr( } fn serialize_class_member( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, member: &ClassMember, parent: NodeRef, ) -> NodeRef { @@ -1334,7 +1337,7 @@ fn serialize_class_member( } fn serialize_expr_or_spread( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, arg: &ExprOrSpread, parent: NodeRef, ) -> NodeRef { @@ -1346,7 +1349,7 @@ fn serialize_expr_or_spread( } fn serialize_ident( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, ident: &Ident, parent: NodeRef, ) -> NodeRef { @@ -1358,7 +1361,7 @@ fn serialize_ident( } fn serialize_module_exported_name( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, name: &ModuleExportName, parent: NodeRef, ) -> NodeRef { @@ -1371,7 +1374,7 @@ fn serialize_module_exported_name( } fn serialize_decl( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, decl: &Decl, parent: NodeRef, ) -> NodeRef { @@ -1521,7 +1524,7 @@ fn serialize_decl( id } Decl::Using(node) => { - let id = ctx.push_node(AstNode::Using, parent, &node.span); + let id = ctx.header(AstNode::Using, parent, &node.span, 0); for (i, decl) in node.decls.iter().enumerate() { // FIXME @@ -1687,7 +1690,7 @@ fn serialize_decl( pos } Decl::TsModule(ts_module_decl) => { - ctx.push_node(AstNode::TsModule, parent, &ts_module_decl.span) + ctx.header(AstNode::TsModule, parent, &ts_module_decl.span, 0) } } } @@ -1701,7 +1704,7 @@ fn accessibility_to_str(accessibility: Accessibility) -> String { } fn serialize_private_name( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &PrivateName, parent: NodeRef, ) -> NodeRef { @@ -1714,7 +1717,7 @@ fn serialize_private_name( } fn serialize_jsx_element( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &JSXElement, parent: NodeRef, ) -> NodeRef { @@ -1746,7 +1749,7 @@ fn serialize_jsx_element( } fn serialize_jsx_fragment( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &JSXFragment, parent: NodeRef, ) -> NodeRef { @@ -1757,9 +1760,9 @@ fn serialize_jsx_fragment( let children_pos = ctx.ref_vec_field(AstProp::Children, node.children.len()); let opening_id = - ctx.push_node(AstNode::JSXOpeningFragment, pos, &node.opening.span); + ctx.header(AstNode::JSXOpeningFragment, pos, &node.opening.span, 0); let closing_id = - ctx.push_node(AstNode::JSXClosingFragment, pos, &node.closing.span); + ctx.header(AstNode::JSXClosingFragment, pos, &node.closing.span, 0); let children = serialize_jsx_children(ctx, &node.children, pos); @@ -1771,7 +1774,7 @@ fn serialize_jsx_fragment( } fn serialize_jsx_children( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, children: &[JSXElementChild], parent: NodeRef, ) -> Vec { @@ -1806,7 +1809,7 @@ fn serialize_jsx_children( } fn serialize_jsx_member_expr( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &JSXMemberExpr, parent: NodeRef, ) -> NodeRef { @@ -1830,7 +1833,7 @@ fn serialize_jsx_member_expr( } fn serialize_jsx_element_name( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &JSXElementName, parent: NodeRef, ) -> NodeRef { @@ -1848,7 +1851,7 @@ fn serialize_jsx_element_name( } fn serialize_jsx_opening_element( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &JSXOpeningElement, parent: NodeRef, ) -> NodeRef { @@ -1919,7 +1922,7 @@ fn serialize_jsx_opening_element( } fn serialize_jsx_container_expr( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &JSXExprContainer, parent: NodeRef, ) -> NodeRef { @@ -1937,15 +1940,15 @@ fn serialize_jsx_container_expr( } fn serialize_jsx_empty_expr( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &JSXEmptyExpr, parent: NodeRef, ) -> NodeRef { - ctx.push_node(AstNode::JSXEmptyExpression, parent, &node.span) + ctx.header(AstNode::JSXEmptyExpression, parent, &node.span, 0) } fn serialize_jsx_namespaced_name( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &JSXNamespacedName, parent: NodeRef, ) -> NodeRef { @@ -1963,7 +1966,7 @@ fn serialize_jsx_namespaced_name( } fn serialize_ident_name_as_jsx_identifier( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &IdentName, parent: NodeRef, ) -> NodeRef { @@ -1976,7 +1979,7 @@ fn serialize_ident_name_as_jsx_identifier( } fn serialize_jsx_identifier( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &Ident, parent: NodeRef, ) -> NodeRef { @@ -1989,7 +1992,7 @@ fn serialize_jsx_identifier( } fn serialize_pat( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, pat: &Pat, parent: NodeRef, ) -> NodeRef { @@ -2116,7 +2119,7 @@ fn serialize_pat( } fn serialize_for_head( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, for_head: &ForHead, parent: NodeRef, ) -> NodeRef { @@ -2132,7 +2135,7 @@ fn serialize_for_head( } fn serialize_spread( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, expr: &Expr, span: &Span, parent: NodeRef, @@ -2147,7 +2150,7 @@ fn serialize_spread( } fn serialize_ident_name( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, ident_name: &IdentName, parent: NodeRef, ) -> NodeRef { @@ -2159,7 +2162,7 @@ fn serialize_ident_name( } fn serialize_prop_name( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, prop_name: &PropName, parent: NodeRef, ) -> NodeRef { @@ -2168,13 +2171,12 @@ fn serialize_prop_name( serialize_ident_name(ctx, ident_name, parent) } PropName::Str(str_prop) => { - let child_id = - ctx.push_node(AstNode::StringLiteral, parent, &str_prop.span); + let child_pos = + ctx.header(AstNode::StringLiteral, parent, &str_prop.span, 1); + let value_pos = ctx.str_field(AstProp::Value); + ctx.write_str(value_pos, &str_prop.value); - let str_id = ctx.str_table.insert(str_prop.value.as_str()); - append_usize(&mut ctx.buf, str_id); - - child_id + child_pos } PropName::Num(number) => { serialize_lit(ctx, &Lit::Num(number.clone()), parent) @@ -2187,7 +2189,7 @@ fn serialize_prop_name( } fn serialize_lit( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, lit: &Lit, parent: NodeRef, ) -> NodeRef { @@ -2208,7 +2210,7 @@ fn serialize_lit( pos } - Lit::Null(node) => ctx.push_node(AstNode::Null, parent, &node.span), + Lit::Null(node) => ctx.header(AstNode::Null, parent, &node.span, 0), Lit::Num(node) => { let pos = ctx.header(AstNode::NumericLiteral, parent, &node.span, 1); let value_pos = ctx.str_field(AstProp::Value); @@ -2237,13 +2239,13 @@ fn serialize_lit( pos } Lit::JSXText(jsxtext) => { - ctx.push_node(AstNode::JSXText, parent, &jsxtext.span) + ctx.header(AstNode::JSXText, parent, &jsxtext.span, 0) } } } fn serialize_ts_type( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &TsType, parent: NodeRef, ) -> NodeRef { @@ -2265,10 +2267,10 @@ fn serialize_ts_type( TsKeywordTypeKind::TsIntrinsicKeyword => AstNode::TSIntrinsicKeyword, }; - ctx.push_node(kind, parent, &node.span) + ctx.header(kind, parent, &node.span, 0) } TsType::TsThisType(node) => { - ctx.push_node(AstNode::TSThisType, parent, &node.span) + ctx.header(AstNode::TSThisType, parent, &node.span, 0) } TsType::TsFnOrConstructorType(node) => match node { TsFnOrConstructorType::TsFnType(node) => { @@ -2455,7 +2457,7 @@ fn serialize_ts_type( } fn create_true_plus_minus_field( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, prop: AstProp, value: Option, ) -> usize { @@ -2470,7 +2472,7 @@ fn create_true_plus_minus_field( } fn write_true_plus_minus( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, pos: usize, value: Option, ) { @@ -2486,7 +2488,7 @@ fn write_true_plus_minus( } fn serialize_ts_entity_name( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &TsEntityName, parent: NodeRef, ) -> NodeRef { @@ -2497,7 +2499,7 @@ fn serialize_ts_entity_name( } fn maybe_serialize_ts_type_ann( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &Option>, parent: NodeRef, ) -> Option { @@ -2507,7 +2509,7 @@ fn maybe_serialize_ts_type_ann( } fn serialize_ts_type_ann( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &TsTypeAnn, parent: NodeRef, ) -> NodeRef { @@ -2522,7 +2524,7 @@ fn serialize_ts_type_ann( } fn maybe_serialize_ts_type( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &Option>, parent: NodeRef, ) -> Option { @@ -2532,7 +2534,7 @@ fn maybe_serialize_ts_type( } fn serialize_ts_type_param( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &TsTypeParam, parent: NodeRef, ) -> NodeRef { @@ -2559,7 +2561,7 @@ fn serialize_ts_type_param( } fn maybe_serialize_ts_type_param( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &Option>, parent: NodeRef, ) -> Option { @@ -2581,7 +2583,7 @@ fn maybe_serialize_ts_type_param( } fn serialize_ts_fn_param( - ctx: &mut SerializeCtx, + ctx: &mut TsEsTreeBuilder, node: &TsFnParam, parent: NodeRef, ) -> NodeRef { diff --git a/cli/tools/lint/ts_estree.rs b/cli/tools/lint/ts_estree.rs new file mode 100644 index 0000000000..79ec1d4126 --- /dev/null +++ b/cli/tools/lint/ts_estree.rs @@ -0,0 +1,467 @@ +use std::fmt::{self, Debug, Display}; + +use deno_ast::swc::common::Span; + +use super::ast_buf::{AstBufSerializer, NodeRef, SerializeCtx}; + +// Keep in sync with JS +#[derive(Debug, Clone, PartialEq)] +pub enum AstNode { + Invalid, + // + Program, + + // Module declarations + Import, + ImportDecl, + ExportDecl, + ExportNamedDeclaration, + ExportDefaultDecl, + ExportDefaultExpr, + ExportAll, + TsImportEquals, + TsExportAssignment, + TsNamespaceExport, + + // Decls + ClassDeclaration, + Fn, + Var, + Using, + TSInterface, + TsTypeAlias, + TSEnumDeclaration, + TsModule, + + // Statements + Block, + Empty, + Debugger, + With, + Return, + Labeled, + Break, + Continue, + IfStatement, + Switch, + SwitchCase, + Throw, + TryStatement, + WhileStatement, + DoWhileStatement, + ForStatement, + ForInStatement, + ForOfStatement, + Decl, + ExpressionStatement, + + // Expressions + This, + ArrayExpression, + Object, + FunctionExpression, + UnaryExpression, + UpdateExpression, + BinaryExpression, + Assign, + MemberExpression, + Super, + ConditionalExpression, + CallExpression, + New, + Paren, + SequenceExpression, + Identifier, + TemplateLiteral, + TaggedTemplateExpression, + ArrowFunctionExpression, + ClassExpr, + YieldExpression, + MetaProp, + AwaitExpression, + LogicalExpression, + TSTypeAssertion, + TsConstAssertion, + TSNonNullExpression, + TSAsExpression, + TsInstantiation, + TSSatisfiesExpression, + PrivateIdentifier, + ChainExpression, + + // Literals + StringLiteral, + Bool, + Null, + NumericLiteral, + BigIntLiteral, + RegExpLiteral, + + // Custom + EmptyExpr, + Spread, + Property, + VariableDeclarator, + CatchClause, + RestElement, + ExportSpecifier, + TemplateElement, + MethodDefinition, + + // Patterns + ArrayPattern, + AssignmentPattern, + ObjectPattern, + + // JSX + JSXAttribute, + JSXClosingElement, + JSXClosingFragment, + JSXElement, + JSXEmptyExpression, + JSXExpressionContainer, + JSXFragment, + JSXIdentifier, + JSXMemberExpression, + JSXNamespacedName, + JSXOpeningElement, + JSXOpeningFragment, + JSXSpreadAttribute, + JSXSpreadChild, + JSXText, + + TSTypeAnnotation, + TSTypeParameterDeclaration, + TSTypeParameter, + TSEnumMember, + TSInterfaceBody, + TSInterfaceHeritage, + TSTypeReference, + TSThisType, + TSLiteralType, + TSInferType, + TSConditionalType, + TSUnionType, + TSIntersectionType, + TSMappedType, + TSTypeQuery, + TSTupleType, + TSFunctionType, + TsCallSignatureDeclaration, + + TSAnyKeyword, + TSBigIntKeyword, + TSBooleanKeyword, + TSIntrinsicKeyword, + TSNeverKeyword, + TSNullKeyword, + TSNumberKeyword, + TSObjectKeyword, + TSStringKeyword, + TSSymbolKeyword, + TSUndefinedKeyword, + TSUnknownKeyword, + TSVoidKeyword, + TSEnumBody, // Last value is used for max value +} + +impl Display for AstNode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(self, f) + } +} + +impl From for u8 { + fn from(m: AstNode) -> u8 { + m as u8 + } +} + +#[derive(Debug, Clone)] +pub enum AstProp { + // Base, these three must be in sync with JS + Type, + Parent, + Range, + + // Node + Abstract, + Accessibility, + Alternate, + Argument, + Arguments, + Async, + Attributes, + Await, + Block, + Body, + Callee, + Cases, + Children, + CheckType, + ClosingElement, + ClosingFragment, + Computed, + Consequent, + Const, + Constraint, + Cooked, + Declarations, + Declare, + Default, + Definite, + Delegate, + Discriminant, + Elements, + ElementTypes, + ExprName, + Expression, + Expressions, + Exported, + ExtendsType, + FalseType, + Finalizer, + Flags, + Generator, + Handler, + Id, + In, + Init, + Initializer, + Implements, + Key, + Kind, + Label, + Left, + Literal, + Local, + Members, + Meta, + Method, + Name, + Namespace, + NameType, + Object, + OpeningElement, + OpeningFragment, + Operator, + Optional, + Out, + Param, + Params, + Pattern, + Prefix, + Properties, + Property, + Quasi, + Quasis, + Raw, + Readonly, + ReturnType, + Right, + SelfClosing, + Shorthand, + Source, + SourceType, + Specifiers, + SuperClass, + SuperTypeArguments, + Tag, + Tail, + Test, + TrueType, + TypeAnnotation, + TypeArguments, + TypeName, + TypeParameter, + TypeParameters, + Types, + Update, + Value, // Last value is used for max value +} + +impl Display for AstProp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match self { + AstProp::Parent => "parent", + AstProp::Range => "range", + AstProp::Type => "type", + AstProp::Abstract => "abstract", + AstProp::Accessibility => "accessibility", + AstProp::Alternate => "alternate", + AstProp::Argument => "argument", + AstProp::Arguments => "arguments", + AstProp::Async => "async", + AstProp::Attributes => "attributes", + AstProp::Await => "await", + AstProp::Block => "block", + AstProp::Body => "body", + AstProp::Callee => "callee", + AstProp::Cases => "cases", + AstProp::Children => "children", + AstProp::CheckType => "checkType", + AstProp::ClosingElement => "closingElement", + AstProp::ClosingFragment => "closingFragment", + AstProp::Computed => "computed", + AstProp::Consequent => "consequent", + AstProp::Const => "const", + AstProp::Constraint => "constraint", + AstProp::Cooked => "cooked", + AstProp::Declarations => "declarations", + AstProp::Declare => "declare", + AstProp::Default => "default", + AstProp::Definite => "definite", + AstProp::Delegate => "delegate", + AstProp::Discriminant => "discriminant", + AstProp::Elements => "elements", + AstProp::ElementTypes => "elementTypes", + AstProp::ExprName => "exprName", + AstProp::Expression => "expression", + AstProp::Expressions => "expressions", + AstProp::Exported => "exported", + AstProp::ExtendsType => "extendsType", + AstProp::FalseType => "falseType", + AstProp::Finalizer => "finalizer", + AstProp::Flags => "flags", + AstProp::Generator => "generator", + AstProp::Handler => "handler", + AstProp::Id => "id", + AstProp::In => "in", + AstProp::Init => "init", + AstProp::Initializer => "initializer", + AstProp::Implements => "implements", + AstProp::Key => "key", + AstProp::Kind => "kind", + AstProp::Label => "label", + AstProp::Left => "left", + AstProp::Literal => "literal", + AstProp::Local => "local", + AstProp::Members => "members", + AstProp::Meta => "meta", + AstProp::Method => "method", + AstProp::Name => "name", + AstProp::Namespace => "namespace", + AstProp::NameType => "nameType", + AstProp::Object => "object", + AstProp::OpeningElement => "openingElement", + AstProp::OpeningFragment => "openingFragment", + AstProp::Operator => "operator", + AstProp::Optional => "optional", + AstProp::Out => "out", + AstProp::Param => "param", + AstProp::Params => "params", + AstProp::Pattern => "pattern", + AstProp::Prefix => "prefix", + AstProp::Properties => "properties", + AstProp::Property => "property", + AstProp::Quasi => "quasi", + AstProp::Quasis => "quasis", + AstProp::Raw => "raw", + AstProp::Readonly => "readonly", + AstProp::ReturnType => "returnType", + AstProp::Right => "right", + AstProp::SelfClosing => "selfClosing", + AstProp::Shorthand => "shorthand", + AstProp::Source => "source", + AstProp::SourceType => "sourceType", + AstProp::Specifiers => "specifiers", + AstProp::SuperClass => "superClass", + AstProp::SuperTypeArguments => "superTypeArguments", + AstProp::Tag => "tag", + AstProp::Tail => "tail", + AstProp::Test => "test", + AstProp::TrueType => "trueType", + AstProp::TypeAnnotation => "typeAnnotation", + AstProp::TypeArguments => "typeArguments", + AstProp::TypeName => "typeName", + AstProp::TypeParameter => "typeParameter", + AstProp::TypeParameters => "typeParameters", + AstProp::Types => "types", + AstProp::Update => "update", + AstProp::Value => "value", + }; + + write!(f, "{}", s) + } +} + +impl From for u8 { + fn from(m: AstProp) -> u8 { + m as u8 + } +} + +pub struct TsEsTreeBuilder { + ctx: SerializeCtx, +} + +impl TsEsTreeBuilder { + pub fn new() -> Self { + // Max values + let kind_count: u8 = AstNode::TSEnumBody.into(); + let prop_count: u8 = AstProp::Value.into(); + Self { + ctx: SerializeCtx::new(kind_count, prop_count), + } + } +} + +impl AstBufSerializer for TsEsTreeBuilder { + fn header( + &mut self, + kind: AstNode, + parent: NodeRef, + span: &Span, + prop_count: usize, + ) -> NodeRef { + self.ctx.header(kind, parent, span, prop_count) + } + + fn ref_field(&mut self, prop: AstProp) -> usize { + self.ctx.ref_field(prop) + } + + fn ref_vec_field(&mut self, prop: AstProp, len: usize) -> usize { + self.ctx.ref_vec_field(prop, len) + } + + fn str_field(&mut self, prop: AstProp) -> usize { + self.ctx.str_field(prop) + } + + fn bool_field(&mut self, prop: AstProp) -> usize { + self.ctx.bool_field(prop) + } + + fn undefined_field(&mut self, prop: AstProp) -> usize { + self.ctx.undefined_field(prop) + } + + fn null_field(&mut self, prop: AstProp) -> usize { + self.ctx.null_field(prop) + } + + fn write_ref(&mut self, pos: usize, value: NodeRef) { + self.ctx.write_ref(pos, value); + } + + fn write_maybe_ref(&mut self, pos: usize, value: Option) { + self.ctx.write_maybe_ref(pos, value); + } + + fn write_refs(&mut self, pos: usize, value: Vec) { + self.ctx.write_refs(pos, value); + } + + fn write_str(&mut self, pos: usize, value: &str) { + self.ctx.write_str(pos, value); + } + + fn write_bool(&mut self, pos: usize, value: bool) { + self.ctx.write_bool(pos, value); + } + + fn serialize(&mut self) -> Vec { + self.ctx.serialize() + } +}