1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-21 04:52:26 -05:00
This commit is contained in:
Marvin Hagemeister 2025-01-03 23:56:21 +01:00
parent 9124e0a0df
commit fd600e0dab
8 changed files with 2145 additions and 884 deletions

View file

@ -38,12 +38,20 @@ const PropFlags = {
* the string table that was included in the message.
*/
String: 2,
/**
* A numnber field. Numbers are represented as strings internally.
*/
Number: 3,
/** This value is either 0 = false, or 1 = true */
Bool: 3,
Bool: 4,
/** No value, it's null */
Null: 4,
Null: 5,
/** No value, it's undefined */
Undefined: 5,
Undefined: 6,
/** An object */
Obj: 7,
/** A regex obj */
Regex: 8,
};
/** @typedef {import("./40_lint_types.d.ts").AstContext} AstContext */
@ -291,18 +299,28 @@ function findPropOffset(buf, offset, search) {
const propCount = buf[offset];
offset += 1;
let skip = 0;
for (let i = 0; i < propCount; i++) {
const maybe = offset;
const prop = buf[offset++];
const kind = buf[offset++];
if (prop === search) return maybe;
if (skip === 0 && prop === search) return maybe;
if (skip > 0) skip--;
if (kind === PropFlags.Ref) {
offset += 4;
} else if (kind === PropFlags.RefArr) {
const len = readU32(buf, offset);
offset += 4 + (len * 4);
} else if (kind === PropFlags.String) {
} else if (kind === PropFlags.Obj) {
const len = readU32(buf, offset);
skip += len;
offset += 4;
} else if (
kind === PropFlags.String || kind === PropFlags.Number ||
kind === PropFlags.Regex
) {
offset += 4;
} else if (kind === PropFlags.Bool) {
offset++;
@ -398,6 +416,10 @@ function toJsValue(ctx, offset) {
range: readValue(ctx, offset, AST_PROP_RANGE),
};
/** @type {Record<string, any>} */
let out = node;
let skip = 0;
// type + parentId + SpanLo + SpanHi
offset += 1 + 4 + 4 + 4;
@ -406,11 +428,18 @@ function toJsValue(ctx, offset) {
const prop = buf[offset++];
const kind = buf[offset++];
const name = getString(ctx.strTable, ctx.strByProp[prop]);
if (skip > 0) {
skip--;
if (skip === 0) {
// TODO(@marvinhagemeister): Support recursiveness
out = node;
}
}
if (kind === PropFlags.Ref) {
const v = readU32(buf, offset);
offset += 4;
node[name] = v === 0 ? null : toJsValue(ctx, v);
out[name] = v === 0 ? null : toJsValue(ctx, v);
} else if (kind === PropFlags.RefArr) {
const len = readU32(buf, offset);
offset += 4;
@ -421,24 +450,126 @@ function toJsValue(ctx, offset) {
nodes[i] = toJsValue(ctx, v);
offset += 4;
}
node[name] = nodes;
out[name] = nodes;
} else if (kind === PropFlags.Bool) {
const v = buf[offset++];
node[name] = v === 1;
out[name] = v === 1;
} else if (kind === PropFlags.String) {
const v = readU32(buf, offset);
offset += 4;
node[name] = getString(ctx.strTable, v);
out[name] = getString(ctx.strTable, v);
} else if (kind === PropFlags.Number) {
const v = readU32(buf, offset);
offset += 4;
out[name] = Number(getString(ctx.strTable, v));
} else if (kind === PropFlags.Regex) {
const v = readU32(buf, offset);
offset += 4;
out[name] = readRegex(ctx.strTable, v);
} else if (kind === PropFlags.Null) {
node[name] = null;
out[name] = null;
} else if (kind === PropFlags.Undefined) {
node[name] = undefined;
out[name] = undefined;
} else if (kind === PropFlags.Obj) {
const v = readU32(buf, offset);
skip += v;
offset += 4;
const obj = {};
out = obj;
out[name] = obj;
}
}
return node;
}
/**
* @param {AstContext["strTable"]} strTable
* @param {number} strId
* @returns {RegExp}
*/
function readRegex(strTable, strId) {
const raw = getString(strTable, strId);
const idx = raw.lastIndexOf("/");
const pattern = raw.slice(1, idx);
const flags = idx < raw.length - 1 ? raw.slice(idx) : undefined;
return new RegExp(pattern, flags);
}
/**
* @param {AstContext} ctx
* @param {number} offset
* @returns {Record<string, any>}
*/
function readObject(ctx, offset) {
const { buf, strTable, strByProp } = ctx;
/** @type {Record<string, any>} */
const obj = {};
const count = readU32(buf, offset);
offset += 4;
for (let i = 0; i < count; i++) {
const start = offset;
const prop = buf[offset++];
const name = getString(strTable, strByProp[prop]);
const value = readProperty(ctx, start);
obj[name] = value;
}
return obj;
}
/**
* @param {AstContext} ctx
* @param {number} offset
* @returns {any}
*/
function readProperty(ctx, offset) {
const { buf } = ctx;
const kind = buf[offset + 1];
offset += 2;
if (kind === PropFlags.Ref) {
const value = readU32(buf, offset);
return getNode(ctx, value);
} else if (kind === PropFlags.RefArr) {
const len = readU32(buf, offset);
offset += 4;
const nodes = new Array(len);
for (let i = 0; i < len; i++) {
nodes[i] = getNode(ctx, readU32(buf, offset));
offset += 4;
}
return nodes;
} else if (kind === PropFlags.Bool) {
return buf[offset] === 1;
} else if (kind === PropFlags.String) {
const v = readU32(buf, offset);
return getString(ctx.strTable, v);
} else if (kind === PropFlags.Number) {
const v = readU32(buf, offset);
return Number(getString(ctx.strTable, v));
} else if (kind === PropFlags.Regex) {
const v = readU32(buf, offset);
return readRegex(ctx.strTable, v);
} else if (kind === PropFlags.Null) {
return null;
} else if (kind === PropFlags.Undefined) {
return undefined;
} else if (kind === PropFlags.Obj) {
return readObject(ctx, offset);
}
throw new Error(`Unknown prop kind: ${kind}`);
}
/**
* Read a specific property from a node
* @param {AstContext} ctx
@ -464,34 +595,7 @@ function readValue(ctx, offset, search) {
offset = findPropOffset(ctx.buf, offset, search);
if (offset === -1) return undefined;
const kind = buf[offset + 1];
offset += 2;
if (kind === PropFlags.Ref) {
const value = readU32(buf, offset);
return getNode(ctx, value);
} else if (kind === PropFlags.RefArr) {
const len = readU32(buf, offset);
offset += 4;
const nodes = new Array(len);
for (let i = 0; i < len; i++) {
nodes[i] = getNode(ctx, readU32(buf, offset));
offset += 4;
}
return nodes;
} else if (kind === PropFlags.Bool) {
return buf[offset] === 1;
} else if (kind === PropFlags.String) {
const v = readU32(buf, offset);
return getString(ctx.strTable, v);
} else if (kind === PropFlags.Null) {
return null;
} else if (kind === PropFlags.Undefined) {
return undefined;
}
throw new Error(`Unknown prop kind: ${kind}`);
return readProperty(ctx, offset);
}
const DECODER = new TextDecoder();
@ -564,7 +668,9 @@ function findChildOffset(buf, child) {
break;
}
case PropFlags.Number:
case PropFlags.String:
case PropFlags.Regex:
offset += 4;
break;
case PropFlags.Bool:
@ -573,6 +679,8 @@ function findChildOffset(buf, child) {
case PropFlags.Null:
case PropFlags.Undefined:
break;
case PropFlags.Obj:
break;
}
}
@ -656,6 +764,12 @@ class MatchCtx {
if (kind === PropFlags.String) {
const s = readU32(buf, offset);
return getString(this.strTable, s);
} else if (kind === PropFlags.Number) {
const s = readU32(buf, offset);
return Number(getString(this.strTable, s));
} else if (kind === PropFlags.Regex) {
const v = readU32(buf, offset);
return readRegex(this.strTable, v);
} else if (kind === PropFlags.Bool) {
return buf[offset] === 1;
} else if (kind === PropFlags.Null) {
@ -747,7 +861,9 @@ class MatchCtx {
return len;
}
case PropFlags.Number:
case PropFlags.String:
case PropFlags.Regex:
offset += 4;
break;
case PropFlags.Bool:
@ -799,6 +915,8 @@ class MatchCtx {
}
case PropFlags.String:
case PropFlags.Number:
case PropFlags.Regex:
offset += 4;
break;
case PropFlags.Bool:
@ -1133,7 +1251,10 @@ function traverse(ctx, visitors, offset, cancellationToken) {
offset += 4;
traverse(ctx, visitors, child, cancellationToken);
}
} else if (kind === PropFlags.String) {
} else if (
kind === PropFlags.String || kind === PropFlags.Number ||
kind === PropFlags.Regex
) {
offset += 4;
} else if (kind === PropFlags.Bool) {
offset += 1;
@ -1257,6 +1378,22 @@ function _dump(ctx) {
console.log(
` ${name}: ${getString(ctx.strTable, v)} (${kindName}, ${prop})`,
);
} else if (kind === PropFlags.Number) {
const v = readU32(buf, offset);
offset += 4;
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(
` ${name}: ${getString(ctx.strTable, v)} (${kindName}, ${prop})`,
);
} else if (kind === PropFlags.Regex) {
const v = readU32(buf, offset);
offset += 4;
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(
` ${name}: ${getString(ctx.strTable, v)} (${kindName}, ${prop})`,
);
} else if (kind === PropFlags.Null) {
// @ts-ignore dump fn
// deno-lint-ignore no-console

View file

@ -14,9 +14,12 @@ pub enum PropFlags {
Ref,
RefArr,
String,
Number,
Bool,
Null,
Undefined,
Obj,
Regex,
}
impl From<PropFlags> for u8 {
@ -33,9 +36,12 @@ impl TryFrom<u8> for PropFlags {
0 => Ok(PropFlags::Ref),
1 => Ok(PropFlags::RefArr),
2 => Ok(PropFlags::String),
3 => Ok(PropFlags::Bool),
4 => Ok(PropFlags::Null),
5 => Ok(PropFlags::Undefined),
3 => Ok(PropFlags::Number),
4 => Ok(PropFlags::Bool),
5 => Ok(PropFlags::Null),
6 => Ok(PropFlags::Undefined),
7 => Ok(PropFlags::Obj),
8 => Ok(PropFlags::Regex),
_ => Err("Unknown Prop flag"),
}
}
@ -137,6 +143,14 @@ pub struct StrPos(pub usize);
pub struct UndefPos(pub usize);
#[derive(Debug)]
pub struct NullPos(pub usize);
#[derive(Debug)]
pub struct NumPos(pub usize);
#[derive(Debug)]
pub struct ObjPos(pub usize);
#[derive(Debug)]
pub struct RegexPos(pub usize);
pub struct AllocNode(pub usize, pub usize);
#[derive(Debug)]
pub enum NodePos {
@ -149,6 +163,12 @@ pub enum NodePos {
Undef(UndefPos),
#[allow(dead_code)]
Null(NullPos),
#[allow(dead_code)]
Num(NumPos),
#[allow(dead_code)]
Obj(ObjPos),
#[allow(dead_code)]
Regex(RegexPos),
}
pub trait AstBufSerializer<K, P>
@ -160,11 +180,13 @@ where
-> PendingNodeRef;
fn ref_field(&mut self, prop: P) -> FieldPos;
fn ref_vec_field(&mut self, prop: P, len: usize) -> FieldArrPos;
fn obj_field(&mut self, prop: P, len: usize) -> ObjPos;
fn str_field(&mut self, prop: P) -> StrPos;
fn num_field(&mut self, prop: P) -> NumPos;
fn bool_field(&mut self, prop: P) -> BoolPos;
fn undefined_field(&mut self, prop: P) -> UndefPos;
#[allow(dead_code)]
fn null_field(&mut self, prop: P) -> NullPos;
fn regex_field(&mut self, prop: P) -> RegexPos;
fn commit_schema(&mut self, offset: PendingNodeRef) -> NodeRef;
fn write_ref(&mut self, pos: FieldPos, value: NodeRef);
@ -172,17 +194,27 @@ where
fn write_refs(&mut self, pos: FieldArrPos, value: Vec<NodeRef>);
fn write_str(&mut self, pos: StrPos, value: &str);
fn write_bool(&mut self, pos: BoolPos, value: bool);
fn write_num(&mut self, pos: NumPos, value: &str);
fn write_regex(&mut self, pos: RegexPos, value: &str);
fn serialize(&mut self) -> Vec<u8>;
}
#[derive(Debug)]
pub struct SerializeCtx {
buf: Vec<u8>,
id: u32,
start_buf: NodeRef,
buf: Vec<u8>,
field_buf: Vec<u8>,
schema_map: Vec<usize>,
spans: Vec<u8>,
str_table: StringTable,
kind_map: Vec<usize>,
prop_map: Vec<usize>,
kind_name_map: Vec<usize>,
prop_name_map: Vec<usize>,
// Internal, used for creating schemas
field_count: u8,
}
@ -198,19 +230,23 @@ impl SerializeCtx {
let kind_size = kind_len as usize;
let prop_size = prop_len as usize;
let mut ctx = Self {
id: 0,
spans: vec![],
start_buf: NodeRef(0),
buf: vec![],
field_buf: vec![],
schema_map: vec![0; kind_size],
str_table: StringTable::new(),
kind_map: vec![0; kind_size],
prop_map: vec![0; prop_size],
kind_name_map: vec![0; kind_size],
prop_name_map: vec![0; prop_size],
field_count: 0,
};
let empty_str = ctx.str_table.insert("");
// Placeholder node is always 0
ctx.append_node(0, NodeRef(0), &DUMMY_SP, 0);
ctx.kind_map[0] = empty_str;
ctx.reserve_props(0, NodeRef(0), &DUMMY_SP, 0);
ctx.kind_name_map[0] = empty_str;
ctx.start_buf = NodeRef(ctx.buf.len());
// Insert default props that are always present
@ -220,15 +256,23 @@ impl SerializeCtx {
let length_str = ctx.str_table.insert("length");
// These values are expected to be in this order on the JS side
ctx.prop_map[0] = empty_str;
ctx.prop_map[1] = type_str;
ctx.prop_map[2] = parent_str;
ctx.prop_map[3] = range_str;
ctx.prop_map[4] = length_str;
ctx.prop_name_map[0] = empty_str;
ctx.prop_name_map[1] = type_str;
ctx.prop_name_map[2] = parent_str;
ctx.prop_name_map[3] = range_str;
ctx.prop_name_map[4] = length_str;
ctx
}
pub fn has_schema<N>(&self, kind: &N) -> bool
where
N: Into<u8> + Display + Clone,
{
let n: u8 = kind.clone().into();
self.schema_map.get(n).is_none()
}
/// Allocate a node's header
fn field_header<P>(&mut self, prop: P, prop_flags: PropFlags) -> usize
where
@ -241,10 +285,10 @@ impl SerializeCtx {
let n: u8 = prop.clone().into();
self.buf.push(n);
if let Some(v) = self.prop_map.get::<usize>(n.into()) {
if let Some(v) = self.prop_name_map.get::<usize>(n.into()) {
if *v == 0 {
let id = self.str_table.insert(&format!("{prop}"));
self.prop_map[n as usize] = id;
self.prop_name_map[n as usize] = id;
}
}
@ -266,25 +310,15 @@ impl SerializeCtx {
offset
}
fn append_node(
&mut self,
kind: u8,
parent: NodeRef,
span: &Span,
prop_count: usize,
) -> PendingNodeRef {
fn get_id(&mut self) -> u32 {
let id = self.id;
self.id += 1;
id
}
fn reserve_props(&mut self, prop_count: usize) -> PendingNodeRef {
let offset = self.buf.len();
// Node type fits in a u8
self.buf.push(kind);
// Offset to the parent node. Will be 0 if none exists
append_usize(&mut self.buf, parent.0);
// Span, the start and end location of this node
append_u32(&mut self.buf, span.lo.0);
append_u32(&mut self.buf, span.hi.0);
// No node has more than <10 properties
debug_assert!(prop_count < 10);
self.buf.push(prop_count as u8);
@ -292,24 +326,76 @@ impl SerializeCtx {
PendingNodeRef(NodeRef(offset))
}
pub fn commit_schema(&mut self, node_ref: PendingNodeRef) -> NodeRef {
let mut offset = node_ref.0 .0;
/// The node buffer contains enough information for traversal
/// <type u8>
/// <id u32>
/// <parent offset u32>
/// <child offset u32>
/// <next offset u32>
pub fn append_node<N>(
&mut self,
kind: &N,
parent: NodeRef,
span: &Span,
) -> NodeRef
where
N: Into<u8> + Display + Clone,
{
let offset = NodeRef(self.buf.len());
let n = kind.clone().into();
self.buf.push(n);
// type + parentId + span lo + span hi
offset += 1 + 4 + 4 + 4;
let id = self.get_id();
append_u32(&mut self.buf, id);
self.buf[offset] = self.field_count;
// Offset to the parent node. Will be 0 if none exists
append_usize(&mut self.buf, parent.0);
// Reserve child
append_usize(&mut self.buf, 0);
// Reserve next
append_usize(&mut self.buf, 0);
// Append span
append_u32(&mut self.spans, span.lo.0);
append_u32(&mut self.spans, span.hi.0);
offset
}
pub fn get_alloc_pos(&self) -> AllocNode {
AllocNode(self.buf.len(), self.field_buf.len())
}
pub fn begin_schema<N>(&mut self, kind: &N) -> usize
where
N: Into<u8> + Display + Clone,
{
#[cfg(debug_assertions)]
{
if self.field_count > 0 {
panic!("Uncommitted schema");
}
}
let offset = self.field_buf.len();
let n = usize::try_from(kind.clone().into());
self.schema_map[n] = offset;
// prop count
self.field_buf.push(0);
offset
}
pub fn commit_schema(&mut self, offset: usize) {
self.field_buf[offset] = self.field_count;
self.field_count = 0;
node_ref.0
}
/// Allocate the node header. It's always the same for every node.
/// <type u8>
/// <parent offset u32>
/// <span lo u32>
/// <span high u32>
/// <property count u8> (There is no node with more than 10 properties)
pub fn header<N>(
&mut self,
kind: N,
@ -319,18 +405,21 @@ impl SerializeCtx {
where
N: Into<u8> + Display + Clone,
{
let n: u8 = kind.clone().into();
let kind_u8: u8 = kind.clone().into();
if let Some(v) = self.kind_map.get::<usize>(n.into()) {
if let Some(v) = self.kind_name_map.get::<usize>(kind_u8.into()) {
if *v == 0 {
let id = self.str_table.insert(&format!("{kind}"));
self.kind_map[n as usize] = id;
self.kind_name_map[kind_u8 as usize] = id;
}
}
self.append_node(kind_u8, parent);
self.append_span(span);
// Prop count will be filled with the actual value when the
// schema is committed.
self.append_node(n, parent, span, 0)
self.reserve_props(kind_u8, 0)
}
/// Allocate a reference property that will hold the offset of
@ -344,15 +433,20 @@ impl SerializeCtx {
/// Allocate a property that is a vec of node offsets pointing to other
/// nodes.
pub fn ref_vec_field<P>(&mut self, prop: P, len: usize) -> usize
pub fn ref_vec_field<P>(&mut self, prop: P) -> usize
where
P: Into<u8> + Display + Clone,
{
let offset = self.field(prop, PropFlags::RefArr);
self.field(prop, PropFlags::RefArr)
}
for _ in 0..len {
append_u32(&mut self.buf, 0);
}
// Allocate a number field. Numbers are internally represented as strings
pub fn obj_field<P>(&mut self, prop: P, len: usize) -> usize
where
P: Into<u8> + Display + Clone,
{
let offset = self.field(prop, PropFlags::Obj);
append_usize(&mut self.buf, len);
offset
}
@ -366,6 +460,22 @@ impl SerializeCtx {
self.field(prop, PropFlags::String)
}
// Allocate a number field. Numbers are internally represented as strings
pub fn num_field<P>(&mut self, prop: P) -> usize
where
P: Into<u8> + Display + Clone,
{
self.field(prop, PropFlags::Number)
}
// Allocate a regex field. Regexes are internally represented as strings
pub fn regex_field<P>(&mut self, prop: P) -> usize
where
P: Into<u8> + Display + Clone,
{
self.field(prop, PropFlags::Regex)
}
/// Allocate a bool field
pub fn bool_field<P>(&mut self, prop: P) -> usize
where
@ -393,49 +503,25 @@ impl SerializeCtx {
self.field_header(prop, PropFlags::Null)
}
pub fn begin_write(&mut self, offset: &NodeRef) {
//
}
/// Replace the placeholder of a reference field with the actual offset
/// to the node we want to point to.
pub fn write_ref(&mut self, field_offset: usize, value: NodeRef) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::Ref {
panic!("Trying to write a ref into a non-ref field")
}
}
write_usize(&mut self.buf, value.0, field_offset + 2);
pub fn write_ref(&mut self, value: NodeRef) {
append_usize(&mut self.buf, value.0);
}
/// Helper for writing optional node offsets
pub fn write_maybe_ref(
&mut self,
field_offset: usize,
value: Option<NodeRef>,
) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::Ref {
panic!("Trying to write a ref into a non-ref field")
}
}
pub fn write_maybe_ref(&mut self, value: Option<NodeRef>) {
let ref_value = if let Some(v) = value { v } else { NodeRef(0) };
write_usize(&mut self.buf, ref_value.0, field_offset + 2);
append_usize(&mut self.buf, ref_value.0);
}
/// Write a vec of node offsets into the property. The necessary space
/// has been reserved earlier.
pub fn write_refs(&mut self, field_offset: usize, value: Vec<NodeRef>) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::RefArr {
panic!("Trying to write a ref into a non-ref array field")
}
}
pub fn write_ref_vec(&mut self, value: Vec<NodeRef>) {
let mut offset = field_offset + 2;
write_usize(&mut self.buf, value.len(), offset);
offset += 4;
@ -448,30 +534,15 @@ impl SerializeCtx {
/// Store the string in our string table and save the id of the string
/// in the current field.
pub fn write_str(&mut self, field_offset: usize, value: &str) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::String {
panic!("Trying to write a ref into a non-string field")
}
}
pub fn write_str(&mut self, value: &str) {
let id = self.str_table.insert(value);
write_usize(&mut self.buf, id, field_offset + 2);
append_usize(&mut self.field_buf, id);
}
/// Write a bool to a field.
pub fn write_bool(&mut self, field_offset: usize, value: bool) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::Bool {
panic!("Trying to write a ref into a non-bool field")
}
}
self.buf[field_offset + 2] = if value { 1 } else { 0 };
pub fn write_bool(&mut self, value: bool) {
let n = if value { 1 } else { 0 };
self.field_buf.push(n);
}
/// Serialize all information we have into a buffer that can be sent to JS.
@ -507,8 +578,8 @@ impl SerializeCtx {
// Write the total number of entries in the kind -> str mapping table
// TODO: make this a u8
append_usize(&mut buf, self.kind_map.len());
for v in &self.kind_map {
append_usize(&mut buf, self.kind_name_map.len());
for v in &self.kind_name_map {
append_usize(&mut buf, *v);
}
@ -517,8 +588,8 @@ impl SerializeCtx {
// as u8.
let offset_prop_map = buf.len();
// Write the total number of entries in the kind -> str mapping table
append_usize(&mut buf, self.prop_map.len());
for v in &self.prop_map {
append_usize(&mut buf, self.prop_name_map.len());
for v in &self.prop_name_map {
append_usize(&mut buf, *v);
}

View file

@ -247,9 +247,7 @@ fn serialize_stmt(
) -> NodeRef {
match stmt {
Stmt::Block(node) => {
let raw = ctx.header(AstNode::BlockStatement, parent, &node.span);
let body_pos = ctx.ref_vec_field(AstProp::Body, node.stmts.len());
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_block_stmt(parent, &node.span);
let children = node
.stmts
@ -257,103 +255,64 @@ fn serialize_stmt(
.map(|stmt| serialize_stmt(ctx, stmt, pos))
.collect::<Vec<_>>();
ctx.write_refs(body_pos, children);
pos
ctx.write_block_stmt(pos, children)
}
Stmt::Empty(_) => NodeRef(0),
Stmt::Debugger(node) => {
let raw = ctx.header(AstNode::DebuggerStatement, parent, &node.span);
ctx.commit_schema(raw)
}
Stmt::Debugger(node) => ctx.alloc_debugger_stmt(parent, &node.span),
Stmt::With(node) => {
let raw = ctx.header(AstNode::WithStatement, parent, &node.span);
let obj_pos = ctx.ref_field(AstProp::Object);
let body_pos = ctx.ref_field(AstProp::Body);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_with_stmt(parent, &node.span);
let obj = serialize_expr(ctx, &node.obj, pos);
let body = serialize_stmt(ctx, &node.body, pos);
ctx.write_ref(obj_pos, obj);
ctx.write_ref(body_pos, body);
pos
ctx.write_with_stmt(pos, obj, body)
}
Stmt::Return(node) => {
let raw = ctx.header(AstNode::ReturnStatement, parent, &node.span);
let arg_pos = ctx.ref_field(AstProp::Argument);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_return_stmt(parent, &node.span);
let arg = node.arg.as_ref().map(|arg| serialize_expr(ctx, arg, pos));
ctx.write_maybe_ref(arg_pos, arg);
pos
ctx.write_return_stmt(pos, arg)
}
Stmt::Labeled(node) => {
let raw = ctx.header(AstNode::LabeledStatement, parent, &node.span);
let label_pos = ctx.ref_field(AstProp::Label);
let body_pos = ctx.ref_field(AstProp::Body);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_labeled_stmt(parent, &node.span);
let ident = serialize_ident(ctx, &node.label, pos);
let stmt = serialize_stmt(ctx, &node.body, pos);
ctx.write_ref(label_pos, ident);
ctx.write_ref(body_pos, stmt);
pos
ctx.write_labeled_stmt(pos, ident, stmt)
}
Stmt::Break(node) => {
let raw = ctx.header(AstNode::BreakStatement, parent, &node.span);
let label_pos = ctx.ref_field(AstProp::Label);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_break_stmt(parent, &node.span);
let arg = node
.label
.as_ref()
.map(|label| serialize_ident(ctx, label, pos));
ctx.write_maybe_ref(label_pos, arg);
pos
ctx.write_break_stmt(pos, arg)
}
Stmt::Continue(node) => {
let raw = ctx.header(AstNode::ContinueStatement, parent, &node.span);
let label_pos = ctx.ref_field(AstProp::Label);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_continue_stmt(parent, &node.span);
let arg = node
.label
.as_ref()
.map(|label| serialize_ident(ctx, label, pos));
ctx.write_maybe_ref(label_pos, arg);
pos
ctx.write_continue_stmt(pos, arg)
}
Stmt::If(node) => {
let raw = ctx.header(AstNode::IfStatement, parent, &node.span);
let test_pos = ctx.ref_field(AstProp::Test);
let cons_pos = ctx.ref_field(AstProp::Consequent);
let alt_pos = ctx.ref_field(AstProp::Alternate);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_if_stmt(parent, &node.span);
let test = serialize_expr(ctx, node.test.as_ref(), pos);
let cons = serialize_stmt(ctx, node.cons.as_ref(), pos);
let alt = node.alt.as_ref().map(|alt| serialize_stmt(ctx, alt, pos));
ctx.write_ref(test_pos, test);
ctx.write_ref(cons_pos, cons);
ctx.write_maybe_ref(alt_pos, alt);
pos
ctx.write_if_stmt(pos, test, cons, alt)
}
Stmt::Switch(node) => {
let raw = ctx.header(AstNode::SwitchStatement, parent, &node.span);
let disc_pos = ctx.ref_field(AstProp::Discriminant);
let cases_pos = ctx.ref_vec_field(AstProp::Cases, node.cases.len());
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_switch_stmt(parent, &node.span);
let disc = serialize_expr(ctx, &node.discriminant, pos);
@ -361,11 +320,7 @@ fn serialize_stmt(
.cases
.iter()
.map(|case| {
let raw = ctx.header(AstNode::SwitchCase, pos, &case.span);
let test_pos = ctx.ref_field(AstProp::Test);
let cons_pos =
ctx.ref_vec_field(AstProp::Consequent, case.cons.len());
let case_pos = ctx.commit_schema(raw);
let case_pos = ctx.alloc_switch_case(pos, &case.span);
let test = case
.test
@ -378,27 +333,16 @@ fn serialize_stmt(
.map(|cons| serialize_stmt(ctx, cons, case_pos))
.collect::<Vec<_>>();
ctx.write_maybe_ref(test_pos, test);
ctx.write_refs(cons_pos, cons);
case_pos
ctx.write_switch_case(pos, test, cons)
})
.collect::<Vec<_>>();
ctx.write_ref(disc_pos, disc);
ctx.write_refs(cases_pos, cases);
pos
ctx.write_switch_stmt(pos, disc, cases)
}
Stmt::Throw(node) => {
let raw = ctx.header(AstNode::ThrowStatement, parent, &node.span);
let arg_pos = ctx.ref_field(AstProp::Argument);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_throw_stmt(parent, &node.span);
let arg = serialize_expr(ctx, &node.arg, pos);
ctx.write_ref(arg_pos, arg);
pos
ctx.write_throw_stmt(pos, arg)
}
Stmt::Try(node) => {
let raw = ctx.header(AstNode::TryStatement, parent, &node.span);
@ -555,10 +499,7 @@ fn serialize_expr(
parent: NodeRef,
) -> NodeRef {
match expr {
Expr::This(node) => {
let raw = ctx.header(AstNode::ThisExpression, parent, &node.span);
ctx.commit_schema(raw)
}
Expr::This(node) => ctx.alloc_this_expr(parent, &node.span),
Expr::Array(node) => {
let raw = ctx.header(AstNode::ArrayExpression, parent, &node.span);
let elems_pos = ctx.ref_vec_field(AstProp::Elements, node.elems.len());
@ -639,47 +580,33 @@ fn serialize_expr(
pos
}
Expr::Unary(node) => {
let raw = ctx.header(AstNode::UnaryExpression, parent, &node.span);
let flag_pos = ctx.str_field(AstProp::Operator);
let arg_pos = ctx.ref_field(AstProp::Argument);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_unary_expr(parent, &node.span);
let arg = serialize_expr(ctx, &node.arg, pos);
let op = match node.op {
UnaryOp::Minus => "-",
UnaryOp::Plus => "+",
UnaryOp::Bang => "!",
UnaryOp::Tilde => "~",
UnaryOp::TypeOf => "typeof",
UnaryOp::Void => "void",
UnaryOp::Delete => "delete",
};
ctx.write_str(
flag_pos,
match node.op {
UnaryOp::Minus => "-",
UnaryOp::Plus => "+",
UnaryOp::Bang => "!",
UnaryOp::Tilde => "~",
UnaryOp::TypeOf => "typeof",
UnaryOp::Void => "void",
UnaryOp::Delete => "delete",
},
);
ctx.write_ref(arg_pos, arg);
ctx.write_unary_expr(pos, op, arg);
pos
}
Expr::Update(node) => {
let raw = ctx.header(AstNode::UpdateExpression, parent, &node.span);
let prefix_pos = ctx.bool_field(AstProp::Prefix);
let arg_pos = ctx.ref_field(AstProp::Argument);
let op_ops = ctx.str_field(AstProp::Operator);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_update_expr(parent, &node.span);
let arg = serialize_expr(ctx, node.arg.as_ref(), pos);
let op = match node.op {
UpdateOp::PlusPlus => "++",
UpdateOp::MinusMinus => "--",
};
ctx.write_bool(prefix_pos, node.prefix);
ctx.write_ref(arg_pos, arg);
ctx.write_str(
op_ops,
match node.op {
UpdateOp::PlusPlus => "++",
UpdateOp::MinusMinus => "--",
},
);
ctx.write_update_expr(pos, node.prefix, op, arg);
pos
}
@ -728,11 +655,7 @@ fn serialize_expr(
pos
}
Expr::Assign(node) => {
let raw = ctx.header(AstNode::AssignmentExpression, parent, &node.span);
let op_pos = ctx.str_field(AstProp::Operator);
let left_pos = ctx.ref_field(AstProp::Left);
let right_pos = ctx.ref_field(AstProp::Right);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_assignment_expr(parent, &node.span);
let left = match &node.left {
AssignTarget::Simple(simple_assign_target) => {
@ -783,29 +706,26 @@ fn serialize_expr(
let right = serialize_expr(ctx, node.right.as_ref(), pos);
ctx.write_str(
op_pos,
match node.op {
AssignOp::Assign => "=",
AssignOp::AddAssign => "+=",
AssignOp::SubAssign => "-=",
AssignOp::MulAssign => "*=",
AssignOp::DivAssign => "/=",
AssignOp::ModAssign => "%=",
AssignOp::LShiftAssign => "<<=",
AssignOp::RShiftAssign => ">>=",
AssignOp::ZeroFillRShiftAssign => ">>>=",
AssignOp::BitOrAssign => "|=",
AssignOp::BitXorAssign => "^=",
AssignOp::BitAndAssign => "&=",
AssignOp::ExpAssign => "**=",
AssignOp::AndAssign => "&&=",
AssignOp::OrAssign => "||=",
AssignOp::NullishAssign => "??=",
},
);
ctx.write_ref(left_pos, left);
ctx.write_ref(right_pos, right);
let op = match node.op {
AssignOp::Assign => "=",
AssignOp::AddAssign => "+=",
AssignOp::SubAssign => "-=",
AssignOp::MulAssign => "*=",
AssignOp::DivAssign => "/=",
AssignOp::ModAssign => "%=",
AssignOp::LShiftAssign => "<<=",
AssignOp::RShiftAssign => ">>=",
AssignOp::ZeroFillRShiftAssign => ">>>=",
AssignOp::BitOrAssign => "|=",
AssignOp::BitXorAssign => "^=",
AssignOp::BitAndAssign => "&=",
AssignOp::ExpAssign => "**=",
AssignOp::AndAssign => "&&=",
AssignOp::OrAssign => "||=",
AssignOp::NullishAssign => "??=",
};
ctx.write_assignment_expr(pos, op, left, right);
pos
}
@ -838,19 +758,13 @@ fn serialize_expr(
pos
}
Expr::Cond(node) => {
let raw = ctx.header(AstNode::ConditionalExpression, parent, &node.span);
let test_pos = ctx.ref_field(AstProp::Test);
let cons_pos = ctx.ref_field(AstProp::Consequent);
let alt_pos = ctx.ref_field(AstProp::Alternate);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_conditional_expr(parent, &node.span);
let test = serialize_expr(ctx, node.test.as_ref(), pos);
let cons = serialize_expr(ctx, node.cons.as_ref(), pos);
let alt = serialize_expr(ctx, node.alt.as_ref(), pos);
ctx.write_ref(test_pos, test);
ctx.write_ref(cons_pos, cons);
ctx.write_ref(alt_pos, alt);
ctx.write_conditional_expr(pos, test, cons, alt);
pos
}
@ -937,9 +851,7 @@ fn serialize_expr(
pos
}
Expr::Seq(node) => {
let raw = ctx.header(AstNode::SequenceExpression, parent, &node.span);
let exprs_pos = ctx.ref_vec_field(AstProp::Expressions, node.exprs.len());
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_sequence_expr(parent, &node.span);
let children = node
.exprs
@ -947,32 +859,25 @@ fn serialize_expr(
.map(|expr| serialize_expr(ctx, expr, pos))
.collect::<Vec<_>>();
ctx.write_refs(exprs_pos, children);
ctx.write_sequence_expr(pos, children);
pos
}
Expr::Ident(node) => serialize_ident(ctx, node, parent),
Expr::Lit(node) => serialize_lit(ctx, node, parent),
Expr::Tpl(node) => {
let raw = ctx.header(AstNode::TemplateLiteral, parent, &node.span);
let quasis_pos = ctx.ref_vec_field(AstProp::Quasis, node.quasis.len());
let exprs_pos = ctx.ref_vec_field(AstProp::Expressions, node.exprs.len());
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_template_lit(parent, &node.span);
let quasis = node
.quasis
.iter()
.map(|quasi| {
let raw = ctx.header(AstNode::TemplateElement, pos, &quasi.span);
let tail_pos = ctx.bool_field(AstProp::Tail);
let raw_pos = ctx.str_field(AstProp::Raw);
let cooked_pos = ctx.str_field(AstProp::Cooked);
let tpl_pos = ctx.commit_schema(raw);
let tpl_pos = ctx.alloc_template_elem(pos, &quasi.span);
ctx.write_bool(tail_pos, quasi.tail);
ctx.write_str(raw_pos, &quasi.raw);
ctx.write_str(
cooked_pos,
ctx.write_template_elem(
tpl_pos,
quasi.tail,
&quasi.raw,
&quasi
.cooked
.as_ref()
@ -989,30 +894,21 @@ fn serialize_expr(
.map(|expr| serialize_expr(ctx, expr, pos))
.collect::<Vec<_>>();
ctx.write_refs(quasis_pos, quasis);
ctx.write_refs(exprs_pos, exprs);
ctx.write_template_lit(pos, quasis, exprs);
pos
}
Expr::TaggedTpl(node) => {
let raw =
ctx.header(AstNode::TaggedTemplateExpression, parent, &node.span);
let tag_pos = ctx.ref_field(AstProp::Tag);
let type_arg_pos = ctx.ref_field(AstProp::TypeArguments);
let quasi_pos = ctx.ref_field(AstProp::Quasi);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_tagged_template_expr(parent, &node.span);
let tag = serialize_expr(ctx, &node.tag, pos);
let type_param_id = node
let type_param = node
.type_params
.clone()
.map(|params| serialize_ts_param_inst(ctx, params.as_ref(), pos));
let quasi = serialize_expr(ctx, &Expr::Tpl(*node.tpl.clone()), pos);
ctx.write_ref(tag_pos, tag);
ctx.write_maybe_ref(type_arg_pos, type_param_id);
ctx.write_ref(quasi_pos, quasi);
ctx.write_tagged_template_expr(pos, tag, type_param, quasi);
pos
}
@ -1061,18 +957,14 @@ fn serialize_expr(
ctx.commit_schema(raw)
}
Expr::Yield(node) => {
let raw = ctx.header(AstNode::YieldExpression, parent, &node.span);
let delegate_pos = ctx.bool_field(AstProp::Delegate);
let arg_pos = ctx.ref_field(AstProp::Argument);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_yield_expr(parent, &node.span);
let arg = node
.arg
.as_ref()
.map(|arg| serialize_expr(ctx, arg.as_ref(), pos));
ctx.write_bool(delegate_pos, node.delegate);
ctx.write_maybe_ref(arg_pos, arg);
ctx.write_yield_expr(pos, node.delegate, arg);
pos
}
@ -1081,13 +973,9 @@ fn serialize_expr(
ctx.commit_schema(raw)
}
Expr::Await(node) => {
let raw = ctx.header(AstNode::AwaitExpression, parent, &node.span);
let arg_pos = ctx.ref_field(AstProp::Argument);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_await_expr(parent, &node.span);
let arg = serialize_expr(ctx, node.arg.as_ref(), pos);
ctx.write_ref(arg_pos, arg);
ctx.write_await_expr(pos, arg);
pos
}
@ -1100,7 +988,7 @@ fn serialize_expr(
Expr::JSXNamespacedName(node) => {
serialize_jsx_namespaced_name(ctx, node, parent)
}
Expr::JSXEmpty(node) => serialize_jsx_empty_expr(ctx, node, parent),
Expr::JSXEmpty(node) => ctx.alloc_jsx_empty_expr(parent, &node.span),
Expr::JSXElement(node) => serialize_jsx_element(ctx, node, parent),
Expr::JSXFragment(node) => serialize_jsx_fragment(ctx, node, parent),
Expr::TsTypeAssertion(node) => {
@ -1118,14 +1006,14 @@ fn serialize_expr(
pos
}
Expr::TsConstAssertion(node) => {
let raw = ctx.header(AstNode::TsConstAssertion, parent, &node.span);
let arg_pos = ctx.ref_field(AstProp::Argument);
let raw = ctx.header(AstNode::TSAsExpression, parent, &node.span);
let expr_pos = ctx.ref_field(AstProp::Expression);
ctx.null_field(AstProp::TypeAnnotation);
let pos = ctx.commit_schema(raw);
let arg = serialize_expr(ctx, node.expr.as_ref(), pos);
let expr = serialize_expr(ctx, node.expr.as_ref(), pos);
// FIXME
ctx.write_ref(arg_pos, arg);
ctx.write_ref(expr_pos, expr);
pos
}
@ -1154,20 +1042,21 @@ fn serialize_expr(
pos
}
Expr::TsInstantiation(node) => {
let raw = ctx.header(AstNode::TsInstantiation, parent, &node.span);
let expr_pos = ctx.ref_field(AstProp::Expression);
let type_args_pos = ctx.ref_field(AstProp::TypeArguments);
let pos = ctx.commit_schema(raw);
Expr::TsInstantiation(_) => {
// let raw = ctx.header(AstNode::TsInstantiation, parent, &node.span);
// let expr_pos = ctx.ref_field(AstProp::Expression);
// let type_args_pos = ctx.ref_field(AstProp::TypeArguments);
// let pos = ctx.commit_schema(raw);
let expr = serialize_expr(ctx, node.expr.as_ref(), pos);
// let expr = serialize_expr(ctx, node.expr.as_ref(), pos);
let type_arg = serialize_ts_param_inst(ctx, node.type_args.as_ref(), pos);
// let type_arg = serialize_ts_param_inst(ctx, node.type_args.as_ref(), pos);
ctx.write_ref(expr_pos, expr);
ctx.write_ref(type_args_pos, type_arg);
// ctx.write_ref(expr_pos, expr);
// ctx.write_ref(type_args_pos, type_arg);
pos
// pos
todo!()
}
Expr::TsSatisfies(node) => {
let raw = ctx.header(AstNode::TSSatisfiesExpression, parent, &node.span);
@ -1533,13 +1422,8 @@ fn serialize_ident(
ident: &Ident,
parent: NodeRef,
) -> NodeRef {
let raw = ctx.header(AstNode::Identifier, parent, &ident.span);
let name_pos = ctx.str_field(AstProp::Name);
let pos = ctx.commit_schema(raw);
ctx.write_str(name_pos, ident.sym.as_str());
pos
let pos = ctx.alloc_identifier(parent, &ident.span);
ctx.write_identifier(pos, ident.sym.as_str(), false, None)
}
fn serialize_module_exported_name(
@ -2068,32 +1952,20 @@ fn serialize_jsx_element(
node: &JSXElement,
parent: NodeRef,
) -> NodeRef {
let raw = ctx.header(AstNode::JSXElement, parent, &node.span);
let open_pos = ctx.ref_field(AstProp::OpeningElement);
let close_pos = ctx.ref_field(AstProp::ClosingElement);
let children_pos = ctx.ref_vec_field(AstProp::Children, node.children.len());
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_jsx_elem(parent, &node.span);
let open = serialize_jsx_opening_element(ctx, &node.opening, pos);
let close = node.closing.as_ref().map(|closing| {
let raw = ctx.header(AstNode::JSXClosingElement, pos, &closing.span);
let name_pos = ctx.ref_field(AstProp::Name);
let closing_pos = ctx.commit_schema(raw);
let closing_pos = ctx.alloc_jsx_closing_elem(pos, &closing.span);
let name = serialize_jsx_element_name(ctx, &closing.name, closing_pos);
ctx.write_ref(name_pos, name);
closing_pos
ctx.write_jsx_closing_elem(closing_pos, name)
});
let children = serialize_jsx_children(ctx, &node.children, pos);
ctx.write_ref(open_pos, open);
ctx.write_maybe_ref(close_pos, close);
ctx.write_refs(children_pos, children);
pos
ctx.write_jsx_elem(pos, open, close, children)
}
fn serialize_jsx_fragment(
@ -2101,26 +1973,13 @@ fn serialize_jsx_fragment(
node: &JSXFragment,
parent: NodeRef,
) -> NodeRef {
let raw = ctx.header(AstNode::JSXFragment, parent, &node.span);
let opening_pos = ctx.ref_field(AstProp::OpeningFragment);
let closing_pos = ctx.ref_field(AstProp::ClosingFragment);
let children_pos = ctx.ref_vec_field(AstProp::Children, node.children.len());
let pos = ctx.commit_schema(raw);
let raw = ctx.header(AstNode::JSXOpeningFragment, pos, &node.opening.span);
let opening_id = ctx.commit_schema(raw);
let raw = ctx.header(AstNode::JSXClosingFragment, pos, &node.closing.span);
let closing_id = ctx.commit_schema(raw);
let pos = ctx.alloc_jsx_frag(parent, &node.span);
let opening = ctx.alloc_jsx_opening_frag(pos, &node.opening.span);
let closing = ctx.alloc_jsx_closing_frag(pos, &node.closing.span);
let children = serialize_jsx_children(ctx, &node.children, pos);
ctx.write_ref(opening_pos, opening_id);
ctx.write_ref(closing_pos, closing_id);
ctx.write_refs(children_pos, children);
pos
ctx.write_jsx_frag(pos, opening, closing, children)
}
fn serialize_jsx_children(
@ -2133,15 +1992,8 @@ fn serialize_jsx_children(
.map(|child| {
match child {
JSXElementChild::JSXText(text) => {
let raw = ctx.header(AstNode::JSXText, parent, &text.span);
let raw_pos = ctx.str_field(AstProp::Raw);
let value_pos = ctx.str_field(AstProp::Value);
let pos = ctx.commit_schema(raw);
ctx.write_str(raw_pos, &text.raw);
ctx.write_str(value_pos, &text.value);
pos
let pos = ctx.alloc_jsx_text(parent, &text.span);
ctx.write_jsx_text(pos, &text.raw, &text.value)
}
JSXElementChild::JSXExprContainer(container) => {
serialize_jsx_container_expr(ctx, container, parent)
@ -2164,10 +2016,7 @@ fn serialize_jsx_member_expr(
node: &JSXMemberExpr,
parent: NodeRef,
) -> NodeRef {
let raw = ctx.header(AstNode::JSXMemberExpression, parent, &node.span);
let obj_ref = ctx.ref_field(AstProp::Object);
let prop_ref = ctx.ref_field(AstProp::Property);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_jsx_member_expr(parent, &node.span);
let obj = match &node.obj {
JSXObject::JSXMemberExpr(member) => {
@ -2178,10 +2027,7 @@ fn serialize_jsx_member_expr(
let prop = serialize_ident_name_as_jsx_identifier(ctx, &node.prop, pos);
ctx.write_ref(obj_ref, obj);
ctx.write_ref(prop_ref, prop);
pos
ctx.write_jsx_member_expr(pos, obj, prop)
}
fn serialize_jsx_element_name(
@ -2207,12 +2053,7 @@ fn serialize_jsx_opening_element(
node: &JSXOpeningElement,
parent: NodeRef,
) -> NodeRef {
let raw = ctx.header(AstNode::JSXOpeningElement, parent, &node.span);
let sclose_pos = ctx.bool_field(AstProp::SelfClosing);
let name_pos = ctx.ref_field(AstProp::Name);
let attrs_pos = ctx.ref_vec_field(AstProp::Attributes, node.attrs.len());
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_jsx_opening_elem(parent, &node.span);
let name = serialize_jsx_element_name(ctx, &node.name, pos);
// FIXME: type args
@ -2222,10 +2063,7 @@ fn serialize_jsx_opening_element(
.iter()
.map(|attr| match attr {
JSXAttrOrSpread::JSXAttr(attr) => {
let raw = ctx.header(AstNode::JSXAttribute, pos, &attr.span);
let name_pos = ctx.ref_field(AstProp::Name);
let value_pos = ctx.ref_field(AstProp::Value);
let attr_pos = ctx.commit_schema(raw);
let attr_pos = ctx.alloc_jsx_attr(pos, &attr.span);
let name = match &attr.name {
JSXAttrName::Ident(name) => {
@ -2249,30 +2087,17 @@ fn serialize_jsx_opening_element(
}
});
ctx.write_ref(name_pos, name);
ctx.write_maybe_ref(value_pos, value);
attr_pos
ctx.write_jsx_attr(attr_pos, name, value)
}
JSXAttrOrSpread::SpreadElement(spread) => {
let raw = ctx.header(AstNode::JSXAttribute, pos, &spread.dot3_token);
let arg_pos = ctx.ref_field(AstProp::Argument);
let attr_pos = ctx.commit_schema(raw);
let attr_pos = ctx.alloc_jsx_spread_attr(pos, &spread.dot3_token);
let arg = serialize_expr(ctx, &spread.expr, attr_pos);
ctx.write_ref(arg_pos, arg);
attr_pos
ctx.write_jsx_spread_attr(attr_pos, arg)
}
})
.collect::<Vec<_>>();
ctx.write_bool(sclose_pos, node.self_closing);
ctx.write_ref(name_pos, name);
ctx.write_refs(attrs_pos, attrs);
pos
ctx.write_jsx_opening_elem(pos, node.self_closing, name, attrs)
}
fn serialize_jsx_container_expr(
@ -2280,27 +2105,14 @@ fn serialize_jsx_container_expr(
node: &JSXExprContainer,
parent: NodeRef,
) -> NodeRef {
let raw = ctx.header(AstNode::JSXExpressionContainer, parent, &node.span);
let expr_pos = ctx.ref_field(AstProp::Expression);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_jsx_expr_container(parent, &node.span);
let expr = match &node.expr {
JSXExpr::JSXEmptyExpr(expr) => serialize_jsx_empty_expr(ctx, expr, pos),
JSXExpr::JSXEmptyExpr(expr) => ctx.alloc_jsx_empty_expr(pos, &expr.span),
JSXExpr::Expr(expr) => serialize_expr(ctx, expr, pos),
};
ctx.write_ref(expr_pos, expr);
pos
}
fn serialize_jsx_empty_expr(
ctx: &mut TsEsTreeBuilder,
node: &JSXEmptyExpr,
parent: NodeRef,
) -> NodeRef {
let raw = ctx.header(AstNode::JSXEmptyExpression, parent, &node.span);
ctx.commit_schema(raw)
ctx.write_jsx_expr_container(pos, expr)
}
fn serialize_jsx_namespaced_name(
@ -2308,18 +2120,12 @@ fn serialize_jsx_namespaced_name(
node: &JSXNamespacedName,
parent: NodeRef,
) -> NodeRef {
let raw = ctx.header(AstNode::JSXNamespacedName, parent, &node.span);
let ns_pos = ctx.ref_field(AstProp::Namespace);
let name_pos = ctx.ref_field(AstProp::Name);
let pos = ctx.commit_schema(raw);
let pos = ctx.alloc_jsx_namespaced_name(parent, &node.span);
let ns_id = serialize_ident_name_as_jsx_identifier(ctx, &node.ns, pos);
let name_id = serialize_ident_name_as_jsx_identifier(ctx, &node.name, pos);
let ns = serialize_ident_name_as_jsx_identifier(ctx, &node.ns, pos);
let name = serialize_ident_name_as_jsx_identifier(ctx, &node.name, pos);
ctx.write_ref(ns_pos, ns_id);
ctx.write_ref(name_pos, name_id);
pos
ctx.write_jsx_namespaced_name(pos, ns, name)
}
fn serialize_ident_name_as_jsx_identifier(
@ -2327,13 +2133,8 @@ fn serialize_ident_name_as_jsx_identifier(
node: &IdentName,
parent: NodeRef,
) -> NodeRef {
let raw = ctx.header(AstNode::JSXIdentifier, parent, &node.span);
let name_pos = ctx.str_field(AstProp::Name);
let pos = ctx.commit_schema(raw);
ctx.write_str(name_pos, &node.sym);
pos
let pos = ctx.alloc_jsx_identifier(parent, &node.span);
ctx.write_jsx_identifier(pos, &node.sym)
}
fn serialize_jsx_identifier(
@ -2341,13 +2142,8 @@ fn serialize_jsx_identifier(
node: &Ident,
parent: NodeRef,
) -> NodeRef {
let raw = ctx.header(AstNode::JSXIdentifier, parent, &node.span);
let name_pos = ctx.str_field(AstProp::Name);
let pos = ctx.commit_schema(raw);
ctx.write_str(name_pos, &node.sym);
pos
let pos = ctx.alloc_jsx_identifier(parent, &node.span);
ctx.write_jsx_identifier(pos, &node.sym)
}
fn serialize_pat(
@ -2536,10 +2332,7 @@ fn serialize_prop_name(
serialize_ident_name(ctx, ident_name, parent)
}
PropName::Str(str_prop) => {
let raw = ctx.header(AstNode::StringLiteral, parent, &str_prop.span);
let value_pos = ctx.str_field(AstProp::Value);
ctx.write_str(value_pos, &str_prop.value);
ctx.commit_schema(raw)
serialize_lit(ctx, &Lit::Str(str_prop.clone()), parent)
}
PropName::Num(number) => {
serialize_lit(ctx, &Lit::Num(number.clone()), parent)
@ -2558,54 +2351,105 @@ fn serialize_lit(
) -> NodeRef {
match lit {
Lit::Str(node) => {
let raw = ctx.header(AstNode::StringLiteral, parent, &node.span);
let raw = ctx.header(AstNode::Literal, parent, &node.span);
let value_pos = ctx.str_field(AstProp::Value);
let raw_pos = ctx.str_field(AstProp::Raw);
let pos = ctx.commit_schema(raw);
let raw_value = if let Some(v) = &node.raw {
v.to_string()
} else {
format!("{}", node.value).to_string()
};
ctx.write_str(value_pos, &node.value);
ctx.write_str(raw_pos, &raw_value);
pos
}
Lit::Bool(lit_bool) => {
let raw = ctx.header(AstNode::Bool, parent, &lit_bool.span);
Lit::Bool(node) => {
let raw = ctx.header(AstNode::Literal, parent, &node.span);
let value_pos = ctx.bool_field(AstProp::Value);
let raw_pos = ctx.str_field(AstProp::Raw);
let pos = ctx.commit_schema(raw);
ctx.write_bool(value_pos, lit_bool.value);
ctx.write_bool(value_pos, node.value);
ctx.write_str(raw_pos, &format!("{}", node.value));
pos
}
Lit::Null(node) => {
let raw = ctx.header(AstNode::Null, parent, &node.span);
ctx.commit_schema(raw)
}
Lit::Num(node) => {
let raw = ctx.header(AstNode::NumericLiteral, parent, &node.span);
let value_pos = ctx.str_field(AstProp::Value);
let raw = ctx.header(AstNode::Literal, parent, &node.span);
ctx.null_field(AstProp::Value);
let raw_pos = ctx.str_field(AstProp::Raw);
let pos = ctx.commit_schema(raw);
ctx.write_str(raw_pos, "null");
pos
}
Lit::Num(node) => {
let raw = ctx.header(AstNode::Literal, parent, &node.span);
let value_pos = ctx.num_field(AstProp::Value);
let raw_pos = ctx.str_field(AstProp::Raw);
let pos = ctx.commit_schema(raw);
let raw_value = if let Some(v) = &node.raw {
v.to_string()
} else {
format!("{}", node.value).to_string()
};
let value = node.raw.as_ref().unwrap();
ctx.write_str(value_pos, value);
ctx.write_num(value_pos, value);
ctx.write_str(raw_pos, &raw_value);
pos
}
Lit::BigInt(node) => {
let raw = ctx.header(AstNode::BigIntLiteral, parent, &node.span);
let raw = ctx.header(AstNode::Literal, parent, &node.span);
let value_pos = ctx.str_field(AstProp::Value);
let raw_pos = ctx.str_field(AstProp::Raw);
let bigint_pos = ctx.str_field(AstProp::BigInt);
let pos = ctx.commit_schema(raw);
let raw_bigint_value = if let Some(v) = &node.raw {
let mut s = v.to_string();
s.pop();
s.to_string()
} else {
format!("{}", node.value).to_string()
};
let raw_value = if let Some(v) = &node.raw {
v.to_string()
} else {
format!("{}", node.value).to_string()
};
// FIXME
ctx.write_str(value_pos, &node.value.to_string());
ctx.write_str(bigint_pos, &raw_bigint_value);
ctx.write_str(raw_pos, &raw_value);
pos
}
Lit::Regex(node) => {
let raw = ctx.header(AstNode::RegExpLiteral, parent, &node.span);
let pattern_pos = ctx.str_field(AstProp::Pattern);
let raw = ctx.header(AstNode::Literal, parent, &node.span);
let _obj_pos = ctx.obj_field(AstProp::Regex, 2);
let flags_pos = ctx.str_field(AstProp::Flags);
let pattern_pos = ctx.str_field(AstProp::Pattern);
let raw_pos = ctx.str_field(AstProp::Raw);
let value_pos = ctx.regex_field(AstProp::Value);
let pos = ctx.commit_schema(raw);
let raw = format!("/{}/{}", node.exp.as_str(), node.flags.as_str());
ctx.write_str(pattern_pos, node.exp.as_str());
ctx.write_str(flags_pos, node.flags.as_str());
ctx.write_str(raw_pos, &raw);
ctx.write_regex(value_pos, &raw);
pos
}
@ -3024,6 +2868,9 @@ fn extract_pos(pos: NodePos) -> usize {
NodePos::Str(str_pos) => str_pos.0,
NodePos::Undef(undef_pos) => undef_pos.0,
NodePos::Null(null_pos) => null_pos.0,
NodePos::Num(num_pos) => num_pos.0,
NodePos::Obj(obj_pos) => obj_pos.0,
NodePos::Regex(reg_pos) => reg_pos.0,
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,3 @@
{
"deno.path": "/Users/ib/dev/deno/target/debug/deno"
"deno.path": "/Users/marvinh/dev/denoland/deno/target/debug/deno"
}

View file

@ -4,7 +4,7 @@
"rules": {
"exclude": [
"ban-ts-comment",
"prefix/whatever"
"test-plugin-local/first-rule"
]
}
}

View file

@ -0,0 +1,99 @@
export const snapshot = {};
snapshot[`Plugin - Literal 1`] = `
{
range: [
1,
2,
],
raw: "1",
type: "Literal",
value: 1,
}
`;
snapshot[`Plugin - Literal 2`] = `
{
range: [
1,
6,
],
raw: "'foo'",
type: "Literal",
value: "foo",
}
`;
snapshot[`Plugin - Literal 3`] = `
{
range: [
1,
6,
],
raw: '"foo"',
type: "Literal",
value: "foo",
}
`;
snapshot[`Plugin - Literal 4`] = `
{
range: [
1,
5,
],
raw: "true",
type: "Literal",
value: true,
}
`;
snapshot[`Plugin - Literal 5`] = `
{
range: [
1,
6,
],
raw: "false",
type: "Literal",
value: false,
}
`;
snapshot[`Plugin - Literal 6`] = `
{
range: [
1,
5,
],
raw: "null",
type: "Literal",
value: null,
}
`;
snapshot[`Plugin - Literal 7`] = `
{
bigint: "1",
range: [
1,
3,
],
raw: "1n",
type: "Literal",
value: "1",
}
`;
snapshot[`Plugin - Literal 8`] = `
{
flags: "g",
pattern: "foo",
range: [
1,
7,
],
raw: "/foo/g",
type: "Literal",
}
`;

View file

@ -1,6 +1,7 @@
// Copyright 2018-2025 the Deno authors. MIT license.
import { assertEquals } from "./test_util.ts";
import { assertSnapshot } from "@std/testing/snapshot";
// TODO(@marvinhagemeister) Remove once we land "official" types
export interface LintReportData {
@ -103,6 +104,8 @@ function testLintNode(source: string, ...selectors: string[]) {
},
});
assertEquals(log.length > 0, true);
return log;
}
@ -323,292 +326,85 @@ Deno.test("Plugin - Program", () => {
});
});
Deno.test("Plugin - BlockStatement", () => {
Deno.test("Plugin - BlockStatement", async (t) => {
const node = testLintNode("{ foo; }", "BlockStatement");
assertEquals(node[0], {
type: "BlockStatement",
range: [1, 9],
body: [{
type: "ExpressionStatement",
range: [3, 7],
expression: {
type: "Identifier",
name: "foo",
range: [3, 6],
},
}],
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - BreakStatement", () => {
Deno.test("Plugin - BreakStatement", async (t) => {
let node = testLintNode("break;", "BreakStatement");
assertEquals(node[0], {
type: "BreakStatement",
range: [1, 7],
label: null,
});
await assertSnapshot(t, node[0]);
node = testLintNode("break foo;", "BreakStatement");
assertEquals(node[0], {
type: "BreakStatement",
range: [1, 11],
label: {
type: "Identifier",
range: [7, 10],
name: "foo",
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ContinueStatement", () => {
Deno.test("Plugin - ContinueStatement", async (t) => {
let node = testLintNode("continue;", "ContinueStatement");
assertEquals(node[0], {
type: "ContinueStatement",
range: [1, 10],
label: null,
});
await assertSnapshot(t, node[0]);
node = testLintNode("continue foo;", "ContinueStatement");
assertEquals(node[0], {
type: "ContinueStatement",
range: [1, 14],
label: {
type: "Identifier",
range: [10, 13],
name: "foo",
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - DebuggerStatement", () => {
Deno.test("Plugin - DebuggerStatement", async (t) => {
const node = testLintNode("debugger;", "DebuggerStatement");
assertEquals(node[0], {
type: "DebuggerStatement",
range: [1, 10],
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - DoWhileStatement", () => {
Deno.test("Plugin - DoWhileStatement", async (t) => {
const node = testLintNode("do {} while (foo);", "DoWhileStatement");
assertEquals(node[0], {
type: "DoWhileStatement",
range: [1, 19],
test: {
type: "Identifier",
range: [14, 17],
name: "foo",
},
body: {
type: "BlockStatement",
range: [4, 6],
body: [],
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ExpressionStatement", () => {
Deno.test("Plugin - ExpressionStatement", async (t) => {
const node = testLintNode("foo;", "ExpressionStatement");
assertEquals(node[0], {
type: "ExpressionStatement",
range: [1, 5],
expression: {
type: "Identifier",
range: [1, 4],
name: "foo",
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ForInStatement", () => {
Deno.test("Plugin - ForInStatement", async (t) => {
const node = testLintNode("for (a in b) {}", "ForInStatement");
assertEquals(node[0], {
type: "ForInStatement",
range: [1, 16],
left: {
type: "Identifier",
range: [6, 7],
name: "a",
},
right: {
type: "Identifier",
range: [11, 12],
name: "b",
},
body: {
type: "BlockStatement",
range: [14, 16],
body: [],
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ForOfStatement", () => {
Deno.test("Plugin - ForOfStatement", async (t) => {
let node = testLintNode("for (a of b) {}", "ForOfStatement");
assertEquals(node[0], {
type: "ForOfStatement",
range: [1, 16],
await: false,
left: {
type: "Identifier",
range: [6, 7],
name: "a",
},
right: {
type: "Identifier",
range: [11, 12],
name: "b",
},
body: {
type: "BlockStatement",
range: [14, 16],
body: [],
},
});
await assertSnapshot(t, node[0]);
node = testLintNode("for await (a of b) {}", "ForOfStatement");
assertEquals(node[0], {
type: "ForOfStatement",
range: [1, 22],
await: true,
left: {
type: "Identifier",
range: [12, 13],
name: "a",
},
right: {
type: "Identifier",
range: [17, 18],
name: "b",
},
body: {
type: "BlockStatement",
range: [20, 22],
body: [],
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ForStatement", () => {
Deno.test("Plugin - ForStatement", async (t) => {
let node = testLintNode("for (;;) {}", "ForStatement");
assertEquals(node[0], {
type: "ForStatement",
range: [1, 12],
init: null,
test: null,
update: null,
body: {
type: "BlockStatement",
range: [10, 12],
body: [],
},
});
await assertSnapshot(t, node[0]);
node = testLintNode("for (a; b; c) {}", "ForStatement");
assertEquals(node[0], {
type: "ForStatement",
range: [1, 17],
init: {
type: "Identifier",
range: [6, 7],
name: "a",
},
test: {
type: "Identifier",
range: [9, 10],
name: "b",
},
update: {
type: "Identifier",
range: [12, 13],
name: "c",
},
body: {
type: "BlockStatement",
range: [15, 17],
body: [],
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - IfStatement", () => {
Deno.test("Plugin - IfStatement", async (t) => {
let node = testLintNode("if (foo) {}", "IfStatement");
assertEquals(node[0], {
type: "IfStatement",
range: [1, 12],
test: {
type: "Identifier",
name: "foo",
range: [5, 8],
},
consequent: {
type: "BlockStatement",
range: [10, 12],
body: [],
},
alternate: null,
});
await assertSnapshot(t, node[0]);
node = testLintNode("if (foo) {} else {}", "IfStatement");
assertEquals(node[0], {
type: "IfStatement",
range: [1, 20],
test: {
type: "Identifier",
name: "foo",
range: [5, 8],
},
consequent: {
type: "BlockStatement",
range: [10, 12],
body: [],
},
alternate: {
type: "BlockStatement",
range: [18, 20],
body: [],
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - LabeledStatement", () => {
Deno.test("Plugin - LabeledStatement", async (t) => {
const node = testLintNode("foo: {};", "LabeledStatement");
assertEquals(node[0], {
type: "LabeledStatement",
range: [1, 8],
label: {
type: "Identifier",
name: "foo",
range: [1, 4],
},
body: {
type: "BlockStatement",
range: [6, 8],
body: [],
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ReturnStatement", () => {
Deno.test("Plugin - ReturnStatement", async (t) => {
let node = testLintNode("return", "ReturnStatement");
assertEquals(node[0], {
type: "ReturnStatement",
range: [1, 7],
argument: null,
});
await assertSnapshot(t, node[0]);
node = testLintNode("return foo;", "ReturnStatement");
assertEquals(node[0], {
type: "ReturnStatement",
range: [1, 12],
argument: {
type: "Identifier",
name: "foo",
range: [8, 11],
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - SwitchStatement", () => {
Deno.test("Plugin - SwitchStatement", async (t) => {
const node = testLintNode(
`switch (foo) {
case foo:
@ -619,151 +415,388 @@ Deno.test("Plugin - SwitchStatement", () => {
}`,
"SwitchStatement",
);
assertEquals(node[0], {
type: "SwitchStatement",
range: [1, 94],
discriminant: {
type: "Identifier",
range: [9, 12],
name: "foo",
},
cases: [
{
type: "SwitchCase",
range: [22, 31],
test: {
type: "Identifier",
range: [27, 30],
name: "foo",
},
consequent: [],
},
{
type: "SwitchCase",
range: [38, 62],
test: {
type: "Identifier",
range: [43, 46],
name: "bar",
},
consequent: [
{
type: "BreakStatement",
label: null,
range: [56, 62],
},
],
},
{
type: "SwitchCase",
range: [69, 88],
test: null,
consequent: [
{
type: "BlockStatement",
range: [86, 88],
body: [],
},
],
},
],
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ThrowStatement", () => {
Deno.test("Plugin - ThrowStatement", async (t) => {
const node = testLintNode("throw foo;", "ThrowStatement");
assertEquals(node[0], {
type: "ThrowStatement",
range: [1, 11],
argument: {
type: "Identifier",
range: [7, 10],
name: "foo",
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - TryStatement", () => {
Deno.test("Plugin - TryStatement", async (t) => {
let node = testLintNode("try {} catch {};", "TryStatement");
assertEquals(node[0], {
type: "TryStatement",
range: [1, 16],
block: {
type: "BlockStatement",
range: [5, 7],
body: [],
},
handler: {
type: "CatchClause",
range: [8, 16],
param: null,
body: {
type: "BlockStatement",
range: [14, 16],
body: [],
},
},
finalizer: null,
});
await assertSnapshot(t, node[0]);
node = testLintNode("try {} catch (e) {};", "TryStatement");
assertEquals(node[0], {
type: "TryStatement",
range: [1, 20],
block: {
type: "BlockStatement",
range: [5, 7],
body: [],
},
handler: {
type: "CatchClause",
range: [8, 20],
param: {
type: "Identifier",
range: [15, 16],
name: "e",
},
body: {
type: "BlockStatement",
range: [18, 20],
body: [],
},
},
finalizer: null,
});
await assertSnapshot(t, node[0]);
node = testLintNode("try {} finally {};", "TryStatement");
assertEquals(node[0], {
type: "TryStatement",
range: [1, 18],
block: {
type: "BlockStatement",
range: [5, 7],
body: [],
},
handler: null,
finalizer: {
type: "BlockStatement",
range: [16, 18],
body: [],
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - WhileStatement", () => {
Deno.test("Plugin - WhileStatement", async (t) => {
const node = testLintNode("while (foo) {}", "WhileStatement");
assertEquals(node[0], {
type: "WhileStatement",
range: [1, 15],
test: {
type: "Identifier",
range: [8, 11],
name: "foo",
},
body: {
type: "BlockStatement",
range: [13, 15],
body: [],
},
});
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - WithStatement", async (t) => {
const node = testLintNode("with ([]) {}", "WithStatement");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ArrayExpression", async (t) => {
const node = testLintNode("[[],,[]]", "ArrayExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ArrowFunctionExpression", async (t) => {
let node = testLintNode("() => {}", "ArrowFunctionExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("async () => {}", "ArrowFunctionExpression");
await assertSnapshot(t, node[0]);
node = testLintNode(
"(a: number, ...b: any[]): any => {}",
"ArrowFunctionExpression",
);
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - AssignmentExpression", async (t) => {
let node = testLintNode("a = b", "AssignmentExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a = a ??= b", "AssignmentExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - AwaitExpression", async (t) => {
const node = testLintNode("await foo;", "AwaitExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - BinaryExpression", async (t) => {
let node = testLintNode("a > b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a >= b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a < b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a <= b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a == b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a === b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a != b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a !== b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a << b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a >> b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a >>> b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a + b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a - b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a * b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a / b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a % b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a | b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a ^ b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a & b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a in b", "BinaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a ** b", "BinaryExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - CallExpression", async (t) => {
let node = testLintNode("foo();", "CallExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("foo(a, ...b);", "CallExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("foo?.();", "CallExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ChainExpression", async (t) => {
const node = testLintNode("a?.b", "ChainExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ClassExpression", async (t) => {
let node = testLintNode("a = class {}", "ClassExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a = class Foo {}", "ClassExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a = class Foo extends Bar {}", "ClassExpression");
await assertSnapshot(t, node[0]);
node = testLintNode(
"a = class Foo extends Bar implements Baz, Baz2 {}",
"ClassExpression",
);
await assertSnapshot(t, node[0]);
node = testLintNode("a = class Foo<T> {}", "ClassExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a = class { foo() {} }", "ClassExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a = class { #foo() {} }", "ClassExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a = class { foo: number }", "ClassExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a = class { foo = bar }", "ClassExpression");
await assertSnapshot(t, node[0]);
node = testLintNode(
"a = class { constructor(public foo: string) {} }",
"ClassExpression",
);
await assertSnapshot(t, node[0]);
node = testLintNode("a = class { #foo: number = bar }", "ClassExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a = class { static foo = bar }", "ClassExpression");
await assertSnapshot(t, node[0]);
node = testLintNode(
"a = class { static foo; static { foo = bar } }",
"ClassExpression",
);
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ConditionalExpression", async (t) => {
const node = testLintNode("a ? b : c", "ConditionalExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - FunctionExpression", async (t) => {
let node = testLintNode("a = function () {}", "FunctionExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a = function foo() {}", "FunctionExpression");
await assertSnapshot(t, node[0]);
node = testLintNode(
"a = function (a?: number, ...b: any[]): any {}",
"FunctionExpression",
);
await assertSnapshot(t, node[0]);
node = testLintNode("a = async function* () {}", "FunctionExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - Identifier", async (t) => {
const node = testLintNode("a", "Identifier");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ImportExpression", async (t) => {
const node = testLintNode(
"import('foo', { with: { type: 'json' }}",
"ImportExpression",
);
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - LogicalExpression", async (t) => {
let node = testLintNode("a && b", "LogicalExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a || b", "LogicalExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a ?? b", "LogicalExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - MemberExpression", async (t) => {
let node = testLintNode("a.b", "MemberExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a['b']", "MemberExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - MetaProp", async (t) => {
const node = testLintNode("import.meta", "MetaProp");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - NewExpression", async (t) => {
let node = testLintNode("new Foo()", "NewExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("new Foo(a?: any, ...b: any[])", "NewExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ObjectExpression", async (t) => {
let node = testLintNode("{}", "ObjectExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("{ a, b: c, [c]: d }", "ObjectExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - PrivateIdentifier", async (t) => {
const node = testLintNode("class Foo { #foo = foo }", "PrivateIdentifier");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - SequenceExpression", async (t) => {
const node = testLintNode("(a, b)", "SequenceExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - Super", async (t) => {
const node = testLintNode(
"class Foo extends Bar { constructor() { super(); } }",
"Super",
);
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - TaggedTemplateExpression", async (t) => {
const node = testLintNode(
"foo`foo ${bar} baz`",
"TaggedTemplateExpression",
);
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - TemplateLiteral", async (t) => {
const node = testLintNode(
"`foo ${bar} baz`",
"TemplateLiteral",
);
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - ThisExpression", async (t) => {
const node = testLintNode("this", "ThisExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - TSAsExpression", async (t) => {
let node = testLintNode("a as b", "TSAsExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a as const", "TSAsExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - TSNonNullExpression", async (t) => {
const node = testLintNode("a!", "TSNonNullExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - TSSatisfiesExpression", async (t) => {
const node = testLintNode("a satisfies b", "TSSatisfiesExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - UnaryExpression", async (t) => {
let node = testLintNode("typeof a", "UnaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("void 0", "UnaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("-a", "UnaryExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("+a", "UnaryExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - UpdateExpression", async (t) => {
let node = testLintNode("a++", "UpdateExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("++a", "UpdateExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("a--", "UpdateExpression");
await assertSnapshot(t, node[0]);
node = testLintNode("--a", "UpdateExpression");
await assertSnapshot(t, node[0]);
});
Deno.test("Plugin - YieldExpression", async (t) => {
const node = testLintNode(
"function* foo() { yield bar; }",
"YieldExpression",
);
await assertSnapshot(t, node[0]);
});
Deno.test.only("Plugin - Literal", async (t) => {
let node = testLintNode("1", "Literal");
await assertSnapshot(t, node[0]);
node = testLintNode("'foo'", "Literal");
await assertSnapshot(t, node[0]);
node = testLintNode('"foo"', "Literal");
await assertSnapshot(t, node[0]);
node = testLintNode("true", "Literal");
await assertSnapshot(t, node[0]);
node = testLintNode("false", "Literal");
await assertSnapshot(t, node[0]);
node = testLintNode("null", "Literal");
await assertSnapshot(t, node[0]);
node = testLintNode("1n", "Literal");
await assertSnapshot(t, node[0]);
node = testLintNode("/foo/g", "Literal");
await assertSnapshot(t, node[0]);
});