use std::str;
use std::collections::{HashSet, HashMap};
use dprint_core::formatting::{Info, ConditionReference};
use swc_common::{BytePos, comments::{Comment, CommentKind}, SourceFile, Spanned, Span};
use swc_ecmascript::ast::*;
use swc_ecmascript::parser::{token::TokenAndSpan};
use super::*;
use super::super::configuration::*;
use super::super::utils::Stack;
pub struct Context<'a> {
pub config: &'a Configuration,
pub comments: CommentCollection<'a>,
pub token_finder: TokenFinder<'a>,
pub file_bytes: &'a [u8],
pub current_node: Node<'a>,
pub parent_stack: Stack<Node<'a>>,
handled_comments: HashSet<BytePos>,
pub info: &'a SourceFile,
stored_infos: HashMap<(BytePos, BytePos), Info>,
stored_info_ranges: HashMap<(BytePos, BytePos), (Info, Info)>,
pub end_statement_or_member_infos: Stack<Info>,
before_comments_start_info_stack: Stack<(Span, Info)>,
if_stmt_last_brace_condition_ref: Option<ConditionReference>,
#[cfg(debug_assertions)]
pub last_parsed_node_pos: u32,
}
impl<'a> Context<'a> {
pub fn new(
config: &'a Configuration,
leading_comments: &'a HashMap<BytePos, Vec<Comment>>,
trailing_comments: &'a HashMap<BytePos, Vec<Comment>>,
tokens: &'a Vec<TokenAndSpan>,
file_bytes: &'a [u8],
current_node: Node<'a>,
info: &'a SourceFile
) -> Context<'a> {
Context {
config,
comments: CommentCollection::new(leading_comments, trailing_comments, tokens, file_bytes),
token_finder: TokenFinder::new(tokens, file_bytes),
file_bytes,
current_node,
parent_stack: Stack::new(),
handled_comments: HashSet::new(),
info,
stored_infos: HashMap::new(),
stored_info_ranges: HashMap::new(),
end_statement_or_member_infos: Stack::new(),
before_comments_start_info_stack: Stack::new(),
if_stmt_last_brace_condition_ref: None,
#[cfg(debug_assertions)]
last_parsed_node_pos: 0,
}
}
pub fn parent(&self) -> &Node<'a> {
self.parent_stack.peek().unwrap()
}
pub fn has_handled_comment(&self, comment: &Comment) -> bool {
self.handled_comments.contains(&comment.lo())
}
pub fn mark_comment_handled(&mut self, comment: &Comment) {
self.handled_comments.insert(comment.lo());
}
pub fn get_text(&self, lo: BytePos, hi: BytePos) -> &str {
let bytes = &self.file_bytes[(lo.0 as usize)..(hi.0 as usize)];
str::from_utf8(&bytes).unwrap()
}
pub fn store_info_for_node(&mut self, node: &dyn Ranged, info: Info) {
self.stored_infos.insert((node.lo(), node.hi()), info);
}
pub fn get_info_for_node(&self, node: &dyn Ranged) -> Option<Info> {
self.stored_infos.get(&(node.lo(), node.hi())).map(|x| x.to_owned())
}
pub fn store_info_range_for_node(&mut self, node: &dyn Ranged, infos: (Info, Info)) {
self.stored_info_ranges.insert((node.lo(), node.hi()), infos);
}
pub fn get_info_range_for_node(&self, node: &dyn Ranged) -> Option<(Info, Info)> {
self.stored_info_ranges.get(&(node.lo(), node.hi())).map(|x| x.to_owned())
}
pub fn store_if_stmt_last_brace_condition_ref(&mut self, condition_reference: ConditionReference) {
self.if_stmt_last_brace_condition_ref = Some(condition_reference);
}
pub fn take_if_stmt_last_brace_condition_ref(&mut self) -> Option<ConditionReference> {
self.if_stmt_last_brace_condition_ref.take()
}
pub fn get_or_create_current_before_comments_start_info(&mut self) -> Info {
let current_span_data = self.current_node.span_data();
if let Some((span_data, info)) = self.before_comments_start_info_stack.peek() {
if *span_data == current_span_data {
return *info;
}
}
let new_info = Info::new("beforeComments");
self.before_comments_start_info_stack.push((current_span_data, new_info));
new_info
}
pub fn take_current_before_comments_start_info(&mut self) -> Option<Info> {
let mut had_span_data = false;
if let Some((span_data, _)) = self.before_comments_start_info_stack.peek() {
if *span_data == self.current_node.span_data() {
had_span_data = true;
}
}
if had_span_data {
Some(self.before_comments_start_info_stack.pop().1)
} else {
None
}
}
#[cfg(debug_assertions)]
pub fn assert_end_of_file_state(&self) {
if self.before_comments_start_info_stack.iter().next().is_some() {
panic!("There were infos in the before comments start info stack.");
}
}
#[cfg(debug_assertions)]
pub fn assert_text(&self, start_pos: BytePos, end_pos: BytePos, expected_text: &str) {
let actual_text = self.get_text(start_pos, end_pos);
if actual_text != expected_text {
panic!("Expected text `{}`, but found `{}`", expected_text, actual_text)
}
}
}
pub trait NodeKinded {
fn kind(&self) -> NodeKind;
}
pub trait SpanDataContainer {
fn span_data(&self) -> Span;
}
impl SpanDataContainer for &dyn SpanDataContainer {
fn span_data(&self) -> Span {
(**self).span_data()
}
}
impl SpanDataContainer for TokenAndSpan {
fn span_data(&self) -> Span {
self.span
}
}
impl SpanDataContainer for Comment {
fn span_data(&self) -> Span {
self.span
}
}
impl SpanDataContainer for BytePos {
fn span_data(&self) -> Span {
Span {
lo: *self,
hi: *self,
ctxt: Default::default(),
}
}
}
impl<T> SpanDataContainer for std::boxed::Box<T> where T : SpanDataContainer {
fn span_data(&self) -> Span {
(**self).span_data()
}
}
pub trait Ranged : SpanDataContainer {
fn lo(&self) -> BytePos;
fn hi(&self) -> BytePos;
fn start_line(&self, context: &mut Context) -> usize;
fn start_line_with_comments(&self, context: &mut Context) -> usize;
fn end_line(&self, context: &mut Context) -> usize;
fn end_line_with_comments(&self, context: &mut Context) -> usize;
fn start_column(&self, context: &mut Context) -> usize;
fn text<'a>(&self, context: &'a Context) -> &'a str;
fn leading_comments<'a>(&self, context: &mut Context<'a>) -> CommentsIterator<'a>;
fn trailing_comments<'a>(&self, context: &mut Context<'a>) -> CommentsIterator<'a>;
}
impl<T> Ranged for T where T : SpanDataContainer {
fn lo(&self) -> BytePos {
self.span_data().lo
}
fn hi(&self) -> BytePos {
self.span_data().hi
}
fn start_line(&self, context: &mut Context) -> usize {
context.info.lookup_line(self.lo()).unwrap_or(0) + 1
}
fn start_line_with_comments(&self, context: &mut Context) -> usize {
let mut leading_comments = self.leading_comments(context);
if leading_comments.is_empty() {
self.start_line(context)
} else {
let lo = self.lo();
let previous_token = context.token_finder.get_previous_token(&lo);
if let Some(previous_token) = previous_token {
let previous_end_line = previous_token.end_line(context);
let mut past_trailing_comments = false;
for comment in leading_comments {
let comment_start_line = comment.start_line(context);
if !past_trailing_comments && comment_start_line <= previous_end_line {
let comment_end_line = comment.end_line(context);
if comment_end_line > previous_end_line {
past_trailing_comments = true;
}
} else {
return comment_start_line;
}
}
self.start_line(context)
} else {
leading_comments.next().unwrap().start_line(context)
}
}
}
fn end_line(&self, context: &mut Context) -> usize {
context.info.lookup_line(self.hi()).unwrap_or(0) + 1
}
fn end_line_with_comments(&self, context: &mut Context) -> usize {
let search_end = context.token_finder.get_next_token_if_comma(self).map(|x| x.hi()).unwrap_or(self.hi());
let trailing_comments = search_end.trailing_comments(context);
let previous_end_line = search_end.end_line(context);
for comment in trailing_comments {
if comment.kind == CommentKind::Line { break; }
let comment_start_line = comment.start_line(context);
if comment_start_line <= previous_end_line {
let comment_end_line = comment.end_line(context);
if comment_end_line > previous_end_line {
return comment_end_line;
}
} else {
break;
}
}
previous_end_line
}
fn start_column(&self, context: &mut Context) -> usize {
let pos = self.lo().0 as usize;
for i in (0..pos).rev() {
if context.file_bytes[i] == '\n' as u8 {
return pos - i + 1;
}
}
return pos;
}
fn text<'a>(&self, context: &'a Context) -> &'a str {
let span_data = self.span_data();
context.get_text(span_data.lo, span_data.hi)
}
fn leading_comments<'a>(&self, context: &mut Context<'a>) -> CommentsIterator<'a> {
context.comments.leading_comments(self.lo())
}
fn trailing_comments<'a>(&self, context: &mut Context<'a>) -> CommentsIterator<'a> {
context.comments.trailing_comments(self.hi())
}
}
macro_rules! generate_node {
($($node_name:ident),*) => {
#[derive(Clone, PartialEq, Debug)]
pub enum NodeKind {
$($node_name),*,
}
#[derive(Clone)]
pub enum Node<'a> {
$($node_name(&'a $node_name)),*
}
impl<'a> NodeKinded for Node<'a> {
fn kind(&self) -> NodeKind {
match self {
$(Node::$node_name(_) => NodeKind::$node_name),*
}
}
}
$(
impl NodeKinded for $node_name {
fn kind(&self) -> NodeKind {
NodeKind::$node_name
}
}
impl SpanDataContainer for $node_name {
fn span_data(&self) -> Span {
self.span()
}
}
)*
$(
impl<'a> From<&'a $node_name> for Node<'a> {
fn from(node: &'a $node_name) -> Node<'a> {
Node::$node_name(node)
}
}
impl<'a> From<&'a Box<$node_name>> for Node<'a> {
fn from(boxed_node: &'a Box<$node_name>) -> Node<'a> {
(&**boxed_node).into()
}
}
)*
impl<'a> SpanDataContainer for Node<'a> {
fn span_data(&self) -> Span {
match self {
$(Node::$node_name(node) => node.span()),*
}
}
}
};
}
generate_node! [
ClassMethod,
ClassProp,
Constructor,
Decorator,
PrivateMethod,
PrivateProp,
TsParamProp,
CatchClause,
ComputedPropName,
Ident,
Invalid,
PrivateName,
TsQualifiedName,
ClassDecl,
ExportDecl,
ExportDefaultDecl,
ExportDefaultExpr,
FnDecl,
Function,
Param,
NamedExport,
ImportDecl,
TsEnumDecl,
TsEnumMember,
TsImportEqualsDecl,
TsInterfaceDecl,
TsTypeAliasDecl,
TsModuleDecl,
TsModuleBlock,
TsNamespaceDecl,
ExportDefaultSpecifier,
ExportNamespaceSpecifier,
ExportNamedSpecifier,
ArrayLit,
ArrowExpr,
AssignExpr,
AssignProp,
AwaitExpr,
BinExpr,
CallExpr,
ClassExpr,
CondExpr,
ExprOrSpread,
FnExpr,
GetterProp,
KeyValueProp,
MemberExpr,
MetaPropExpr,
MethodProp,
NewExpr,
ParenExpr,
ObjectLit,
OptChainExpr,
SeqExpr,
SetterProp,
SpreadElement,
Super,
TaggedTpl,
ThisExpr,
Tpl,
TplElement,
TsAsExpr,
TsConstAssertion,
TsTypeCastExpr,
TsExprWithTypeArgs,
TsNonNullExpr,
TsTypeAssertion,
UnaryExpr,
UpdateExpr,
YieldExpr,
ImportDefaultSpecifier,
ImportNamedSpecifier,
ImportStarAsSpecifier,
TsExternalModuleRef,
TsInterfaceBody,
TsCallSignatureDecl,
TsConstructSignatureDecl,
TsIndexSignature,
TsMethodSignature,
TsPropertySignature,
TsTypeLit,
JSXAttr,
JSXClosingElement,
JSXClosingFragment,
JSXElement,
JSXEmptyExpr,
JSXExprContainer,
JSXFragment,
JSXMemberExpr,
JSXNamespacedName,
JSXOpeningElement,
JSXOpeningFragment,
JSXSpreadChild,
JSXText,
BigInt,
Bool,
Null,
Number,
Regex,
Str,
Module,
ArrayPat,
AssignPat,
AssignPatProp,
KeyValuePatProp,
ObjectPat,
RestPat,
BlockStmt,
BreakStmt,
ContinueStmt,
DebuggerStmt,
DoWhileStmt,
EmptyStmt,
ExportAll,
ExprStmt,
ForStmt,
ForInStmt,
ForOfStmt,
IfStmt,
LabeledStmt,
ReturnStmt,
SwitchStmt,
SwitchCase,
ThrowStmt,
TryStmt,
TsExportAssignment,
TsNamespaceExportDecl,
VarDecl,
VarDeclarator,
WithStmt,
WhileStmt,
TsArrayType,
TsConditionalType,
TsConstructorType,
TsKeywordType,
TsFnType,
TsImportType,
TsIndexedAccessType,
TsInferType,
TsIntersectionType,
TsLitType,
TsMappedType,
TsOptionalType,
TsParenthesizedType,
TsRestType,
TsThisType,
TsTplLitType,
TsTupleType,
TsTypeAnn,
TsTypeOperator,
TsTypeParamInstantiation,
TsTypeParamDecl,
TsTypeParam,
TsTypePredicate,
TsTypeQuery,
TsTypeRef,
TsUnionType,
TsTupleElement,
Span
];
pub enum TypeParamNode<'a> {
Instantiation(&'a TsTypeParamInstantiation),
Decl(&'a TsTypeParamDecl)
}
impl<'a> TypeParamNode<'a> {
pub fn params(&self) -> Vec<Node<'a>> {
match self {
TypeParamNode::Instantiation(node) => node.params.iter().map(|p| p.into()).collect(),
TypeParamNode::Decl(node) => node.params.iter().map(|p| p.into()).collect(),
}
}
pub fn span(&self) -> Span {
match self {
TypeParamNode::Instantiation(node) => node.span,
TypeParamNode::Decl(node) => node.span,
}
}
}
macro_rules! generate_traits {
($enum_name:ident, $($member_name:ident),*) => {
impl<'a> From<&'a $enum_name> for Node<'a> {
fn from(id: &'a $enum_name) -> Node<'a> {
match id {
$($enum_name::$member_name(node) => node.into()),*
}
}
}
impl<'a> From<&'a Box<$enum_name>> for Node<'a> {
fn from(boxed_node: &'a Box<$enum_name>) -> Node<'a> {
(&**boxed_node).into()
}
}
impl NodeKinded for $enum_name {
fn kind(&self) -> NodeKind {
match self {
$($enum_name::$member_name(node) => node.kind()),*
}
}
}
impl SpanDataContainer for $enum_name {
fn span_data(&self) -> Span {
match self {
$($enum_name::$member_name(node) => node.span()),*
}
}
}
};
}
generate_traits![BlockStmtOrExpr, BlockStmt, Expr];
generate_traits![ClassMember, Constructor, Method, PrivateMethod, ClassProp, PrivateProp, TsIndexSignature, Empty];
generate_traits![Decl, Class, Fn, Var, TsInterface, TsTypeAlias, TsEnum, TsModule];
generate_traits![Lit, BigInt, Bool, JSXText, Null, Num, Regex, Str];
generate_traits![ImportSpecifier, Named, Default, Namespace];
generate_traits![ModuleItem, Stmt, ModuleDecl];
generate_traits![ObjectPatProp, KeyValue, Assign, Rest];
generate_traits![PatOrExpr, Pat, Expr];
generate_traits![TsEnumMemberId, Ident, Str];
generate_traits![TsLit, Number, Str, Bool, Tpl, BigInt];
generate_traits![TsTypeElement, TsCallSignatureDecl, TsConstructSignatureDecl, TsPropertySignature, TsMethodSignature, TsIndexSignature];
generate_traits![TsFnParam, Ident, Array, Rest, Object];
generate_traits![Expr, This, Array, Object, Fn, Unary, Update, Bin, Assign, Member, Cond, Call, New, Seq, Ident, Lit, Tpl, TaggedTpl, Arrow,
Class, Yield, MetaProp, Await, Paren, JSXMember, JSXNamespacedName, JSXEmpty, JSXElement, JSXFragment, TsTypeAssertion, TsConstAssertion,
TsNonNull, TsTypeCast, TsAs, PrivateName, OptChain, Invalid];
generate_traits![PropOrSpread, Spread, Prop];
generate_traits![Prop, Shorthand, KeyValue, Assign, Getter, Setter, Method];
generate_traits![PropName, Ident, Str, Num, Computed, BigInt];
generate_traits![Pat, Ident, Array, Rest, Object, Assign, Invalid, Expr];
generate_traits![TsType, TsKeywordType, TsThisType, TsFnOrConstructorType, TsTypeRef, TsTypeQuery, TsTypeLit, TsArrayType, TsTupleType,
TsOptionalType, TsRestType, TsUnionOrIntersectionType, TsConditionalType, TsInferType, TsParenthesizedType, TsTypeOperator, TsIndexedAccessType,
TsMappedType, TsLitType, TsTypePredicate, TsImportType];
generate_traits![TsFnOrConstructorType, TsFnType, TsConstructorType];
generate_traits![TsParamPropParam, Ident, Assign];
generate_traits![TsThisTypeOrIdent, TsThisType, Ident];
generate_traits![TsTypeQueryExpr, TsEntityName, Import];
generate_traits![TsUnionOrIntersectionType, TsUnionType, TsIntersectionType];
generate_traits![DefaultDecl, Class, Fn, TsInterfaceDecl];
generate_traits![TsEntityName, TsQualifiedName, Ident];
generate_traits![ExprOrSuper, Super, Expr];
generate_traits![TsModuleName, Ident, Str];
generate_traits![VarDeclOrPat, VarDecl, Pat];
generate_traits![VarDeclOrExpr, VarDecl, Expr];
generate_traits![TsNamespaceBody, TsModuleBlock, TsNamespaceDecl];
generate_traits![ParamOrTsParamProp, Param, TsParamProp];
generate_traits![ModuleDecl, Import, ExportDecl, ExportNamed, ExportDefaultDecl, ExportDefaultExpr, ExportAll, TsImportEquals, TsExportAssignment,
TsNamespaceExport];
generate_traits![TsModuleRef, TsEntityName, TsExternalModuleRef];
generate_traits![Stmt, Block, Empty, Debugger, With, Return, Labeled, Break, Continue, If, Switch, Throw, Try, While, DoWhile, For, ForIn, ForOf,
Decl, Expr];
generate_traits![JSXElementChild, JSXText, JSXExprContainer, JSXSpreadChild, JSXElement, JSXFragment];
generate_traits![JSXAttrName, Ident, JSXNamespacedName];
generate_traits![JSXAttrOrSpread, JSXAttr, SpreadElement];
generate_traits![JSXElementName, Ident, JSXMemberExpr, JSXNamespacedName];
generate_traits![JSXAttrValue, Lit, JSXExprContainer, JSXElement, JSXFragment];
generate_traits![JSXExpr, JSXEmptyExpr, Expr];
generate_traits![JSXObject, JSXMemberExpr, Ident];
pub trait InnerSpanned {
fn get_inner_span_data(&self, context: &mut Context) -> Span;
}
impl InnerSpanned for BlockStmt {
fn get_inner_span_data(&self, _: &mut Context) -> Span {
get_inner_span_for_object_like(&self.span)
}
}
impl InnerSpanned for ObjectLit {
fn get_inner_span_data(&self, _: &mut Context) -> Span {
get_inner_span_for_object_like(&self.span)
}
}
impl InnerSpanned for ObjectPat {
fn get_inner_span_data(&self, _: &mut Context) -> Span {
get_inner_span_for_object_like(&self.span)
}
}
fn get_inner_span_for_object_like(span: &Span) -> Span {
Span {
lo: BytePos(span.lo.0 + 1),
hi: BytePos(span.hi.0 - 1),
ctxt: Default::default()
}
}
impl<'a> Node<'a> {
pub fn get_type_parameters(&self) -> &Option<TsTypeParamDecl> {
match self {
Node::ClassDecl(node) => &node.class.type_params,
Node::TsInterfaceDecl(node) => &node.type_params,
Node::ClassExpr(node) => &node.class.type_params,
Node::FnDecl(node) => &node.function.type_params,
Node::ClassMethod(node) => &node.function.type_params,
Node::TsTypeAliasDecl(node) => &node.type_params,
Node::ArrowExpr(node) => &node.type_params,
Node::TsCallSignatureDecl(node) => &node.type_params,
Node::TsConstructSignatureDecl(node) => &node.type_params,
Node::TsMethodSignature(node) => &node.type_params,
Node::MethodProp(node) => &node.function.type_params,
Node::TsConstructorType(node) => &node.type_params,
Node::TsFnType(node) => &node.type_params,
_ => &None
}
}
}
pub trait ParametersSpanned {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span>;
}
impl ParametersSpanned for Function {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
self.params.iter().map(|x| x.span_data()).collect(),
self.return_type.as_ref().map(|t| t.lo())
.or(self.body.as_ref().map(|b| b.lo()))
.unwrap_or(self.span.hi()),
context
)
}
}
impl ParametersSpanned for PrivateMethod {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
self.function.get_parameters_span_data(context)
}
}
impl ParametersSpanned for ClassMethod {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
self.function.get_parameters_span_data(context)
}
}
impl ParametersSpanned for Constructor {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
self.params.iter().map(|x| x.span_data()).collect(),
self.body.as_ref().map(|t| t.lo())
.unwrap_or(self.span.hi()),
context
)
}
}
impl ParametersSpanned for MethodProp {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
self.function.get_parameters_span_data(context)
}
}
impl ParametersSpanned for GetterProp {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
vec![],
self.type_ann.as_ref().map(|t| t.lo())
.or(self.body.as_ref().map(|t| t.lo()))
.unwrap_or(self.hi()),
context
)
}
}
impl ParametersSpanned for SetterProp {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
vec![self.param.span_data()],
self.body.as_ref().map(|t| t.lo()).unwrap_or(self.hi()),
context
)
}
}
impl ParametersSpanned for ArrowExpr {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
self.params.iter().map(|x| x.span_data()).collect(),
self.return_type.as_ref().map(|t| t.lo()).unwrap_or(self.body.lo()),
context
)
}
}
impl ParametersSpanned for CallExpr {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
self.args.iter().map(|a| a.span_data()).collect(),
self.hi(),
context
)
}
}
impl ParametersSpanned for NewExpr {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
self.args.as_ref().map(|args| args.iter().map(|a| a.span_data()).collect()).unwrap_or_default(),
self.hi(),
context
)
}
}
impl ParametersSpanned for TsCallSignatureDecl {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
self.params.iter().map(|x| x.span_data()).collect(),
self.type_ann.as_ref().map(|t| t.lo()).unwrap_or(self.hi()),
context
)
}
}
impl ParametersSpanned for TsConstructSignatureDecl {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
self.params.iter().map(|x| x.span_data()).collect(),
self.type_ann.as_ref().map(|t| t.lo()).unwrap_or(self.hi()),
context
)
}
}
impl ParametersSpanned for TsMethodSignature {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
self.params.iter().map(|x| x.span_data()).collect(),
self.type_ann.as_ref().map(|t| t.lo()).unwrap_or(self.hi()),
context
)
}
}
impl ParametersSpanned for TsConstructorType {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
self.params.iter().map(|x| x.span_data()).collect(),
self.type_ann.lo(),
context
)
}
}
impl ParametersSpanned for TsFnType {
fn get_parameters_span_data(&self, context: &mut Context) -> Option<Span> {
get_params_or_args_span_data(
self.lo(),
self.params.iter().map(|x| x.span_data()).collect(),
self.type_ann.lo(),
context
)
}
}
fn get_params_or_args_span_data(start_pos: BytePos, params: Vec<Span>, following_pos: BytePos, context: &mut Context) -> Option<Span> {
let close_token_end = {
let close_paren = if let Some(last_param) = params.last() {
context.token_finder.get_first_close_paren_after(last_param)
} else {
context.token_finder.get_first_close_paren_before(&following_pos)
};
if let Some(close_paren) = close_paren {
let end = close_paren.hi();
if end > start_pos {
Some(end)
} else {
None
}
} else {
None
}
}?;
let close_token_start = {
let open_paren = context.token_finder.get_first_open_paren_before(&{
if let Some(first_param) = params.first() {
first_param.lo()
} else {
close_token_end
}
});
if let Some(open_paren) = open_paren {
let pos = open_paren.lo();
if pos >= start_pos {
Some(pos)
} else {
None
}
} else {
None
}
}?;
Some(Span {
lo: close_token_start,
hi: close_token_end,
ctxt: Default::default(),
})
}