261020.1 · 1d7e0126f3e601103d93586a6f872144f2789dad
chore: self-maintain Node.js features
reading declarations
Changes to deps/swc/crates/. All files
deps/swc/crates/ast_node/Cargo.toml
@@ -1,21 +0,0 @@-[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>"]-description = "Macros for ast nodes."-documentation = "https://rustdoc.swc.rs/ast_node/"-edition = { workspace = true }-license = { workspace = true }-name = "ast_node"-repository = { workspace = true }-version = "7.0.0"--[lib]-bench = false-proc-macro = true--[dependencies]-quote = { workspace = true }--swc_macros_common = { version = "1.0.1", path = "../swc_macros_common" }-[dependencies.syn]-features = ["derive", "fold", "parsing", "printing", "visit-mut"]-workspace = true
deps/swc/crates/ast_node/src/ast_node_macro.rs
@@ -1,181 +0,0 @@-use swc_macros_common::prelude::*;-use syn::{- parse::{Parse, ParseStream},- *,-};--#[derive(Clone)]-pub struct Args {- pub ty: Literal,- pub no_partial_eq: bool,-}--impl Parse for Args {- fn parse(i: ParseStream<'_>) -> syn::Result<Self> {- let ty = i.parse()?;- let mut no_partial_eq = false;-- if i.parse::<Option<Token![,]>>()?.is_some() {- let option: Ident = i.parse()?;-- if option == "no_partial_eq" {- no_partial_eq = true;- } else {- return Err(Error::new(option.span(), "unknown ast_node option"));- }- }-- if !i.is_empty() {- return Err(i.error("unexpected ast_node arguments"));- }-- Ok(Args { ty, no_partial_eq })- }-}--pub fn expand_struct(args: Args, i: DeriveInput) -> Vec<ItemImpl> {- let mut items = Vec::new();- let generics = i.generics.clone();- // let item_ident = Ident::new("Item", i.ident.span());-- {- let ty = &i.ident;- let type_str = &args.ty;- let item: ItemImpl = parse_quote!(- impl ::swc_common::AstNode for #ty {- const TYPE: &'static str = #type_str;- }- );- items.push(item.with_generics(generics));- }-- // let ident = i.ident.clone();- // let cloned = i.clone();-- // items.push({- // let (fields, item_data) = match i.data {- // Data::Struct(DataStruct {- // struct_token,- // semi_token,- // fields: Fields::Named(FieldsNamed { brace_token, named }),- // }) => {- // let fields: Punctuated<_, token::Comma> = named- // .clone()- // .into_iter()- // .map(|field| FieldValue {- // member: Member::Named(field.ident.clone().unwrap()),- // expr: Quote::new_call_site()- // .quote_with(smart_quote!(- // Vars {- // field: &field.ident- // },- // { node.node.field }- // ))- // .parse(),-- // attrs: field- // .attrs- // .into_iter()- // .filter(|attr| is_attr_name(attr, "cfg"))- // .collect(),- // colon_token: Some(call_site()),- // })- // .collect();-- // let item_data = Data::Struct(DataStruct {- // struct_token,- // semi_token,- // fields: Fields::Named(FieldsNamed {- // brace_token,- // named: named- // .into_pairs()- // .map(|pair| {- // let handle = |v: Field| Field {- // vis: Visibility::Inherited,- // attrs: v- // .attrs- // .into_iter()- // .filter(|attr| {- // is_attr_name(attr, "serde") ||- // is_attr_name(attr, "cfg") })- // .collect(),- // ..v- // };-- // match pair {- // Pair::End(v) => Pair::End(handle(v)),- // Pair::Punctuated(v, p) =>- // Pair::Punctuated(handle(v), p), }- // })- // .collect(),- // }),- // });-- // (fields, item_data)- // }- // _ => unreachable!("enum / tuple struct / union with- // #[ast_node(\"Foo\")]"), };-- // let convert_item_to_self =- // Quote::new_call_site().quote_with(smart_quote!( Vars {- // fields,- // Type: &ident- // },- // { Type { fields } }- // ));-- // let body = Quote::new_call_site().quote_with(smart_quote!(- // Vars {- // convert_item_to_self- // },- // {- // let node =- // ::swc_common::serializer::Node::<Item>::deserialize(deserializer)?;-- // if node.ty != <Self as ::swc_common::AstNode>::TYPE {- // return Err(D::Error::unknown_variant(- // &node.ty,- // &[<Self as ::swc_common::AstNode>::TYPE],- // ));- // }-- // Ok(convert_item_to_self)- // }- // ));-- // let item = DeriveInput {- // vis: Visibility::Inherited,- // ident: item_ident,- // attrs: Vec::new(),- // data: item_data,- // ..cloned- // };- // Quote::new_call_site()- // .quote_with(smart_quote!(- // Vars {- // // A new item which implements Deserialize- // item,- // Type: ident,- // body- // },- // {- // impl<'de> ::serde::Deserialize<'de> for Type {- // fn deserialize<D>(deserializer: D) -> Result<Self,- // D::Error> where- // D: ::serde::Deserializer<'de>,- // {- // use ::serde::de::Error;- // #[derive(::serde::Deserialize)]- // #[serde(rename_all = "camelCase")]- // ite- // body- // }- // }- // }- // ))- // .parse::<ItemImpl>()- // .with_generics(generics)- // });-- items-}
deps/swc/crates/ast_node/src/encoding/decode.rs
@@ -1,284 +0,0 @@-use syn::{spanned::Spanned, Data, DeriveInput};--use super::{is_ignore, is_unknown, is_with, EnumType};--pub fn expand(DeriveInput { ident, data, .. }: DeriveInput) -> syn::ItemImpl {- match data {- Data::Struct(data) => {- let is_named = data.fields.iter().any(|field| field.ident.is_some());- let names = data- .fields- .iter()- .enumerate()- .map(|(idx, field)| match field.ident.as_ref() {- Some(name) => name.clone(),- None => {- let name = format!("unit{idx}");- syn::Ident::new(&name, field.span())- }- })- .collect::<Vec<_>>();-- let fields = data.fields.iter()- .zip(names.iter())- .map(|(field, field_name)| -> syn::Stmt {- let ty = &field.ty;- let value: syn::Expr = match (is_with(&field.attrs), is_ignore(&field.attrs)) {- (Some(with_type), false) => syn::parse_quote!(<#with_type<#ty> as cbor4ii::core::dec::Decode<'_>>::decode(reader)?.0),- (None, false) => syn::parse_quote!(<#ty as cbor4ii::core::dec::Decode<'_>>::decode(reader)?),- (None, true) => syn::parse_quote!(<#ty as Default>::default()),- (Some(_), true) => panic!("Cannot use both #[encoding(with)] and #[encoding(ignore)] attributes on the same field")- };-- syn::parse_quote!{- let #field_name = #value;- }- });- let build_struct: syn::Expr = if is_named {- syn::parse_quote! { #ident { #(#names),* } }- } else {- syn::parse_quote! { #ident ( #(#names),* ) }- };-- let count = data- .fields- .iter()- .filter(|field| !is_ignore(&field.attrs))- .count();- let head: Option<syn::Stmt> = (count != 1).then(|| {- syn::parse_quote! {- let len = <cbor4ii::core::types::Array<()>>::len(reader)?.unwrap();- }- });- let tail: Option<syn::Stmt> = head.is_some().then(|| {- syn::parse_quote! {- // ignore unknown field- for _ in 0..(len - #count) {- cbor4ii::core::dec::IgnoredAny::decode(reader)?;- }- }- });-- syn::parse_quote! {- impl<'de> cbor4ii::core::dec::Decode<'de> for #ident {- #[inline]- fn decode<R: cbor4ii::core::dec::Read<'de>>(reader: &mut R)- -> Result<Self, cbor4ii::core::error::DecodeError<R::Error>>- {- #head;- let value = {- #(#fields)*- #build_struct- };- #tail- Ok(value)- }- }- }- }- Data::Enum(data) => {- let enum_type = data.variants.iter().filter(|v| !is_unknown(&v.attrs)).fold(- None,- |mut sum, next| {- let ty = match &next.fields {- syn::Fields::Named(_) => EnumType::Struct,- syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => EnumType::One,- syn::Fields::Unit => EnumType::Unit,- syn::Fields::Unnamed(_) => {- panic!("more than 1 unnamed member field are not allowed")- }- };- match (*sum.get_or_insert(ty), ty) {- (EnumType::Struct, EnumType::Struct)- | (EnumType::Struct, EnumType::Unit)- | (EnumType::Unit, EnumType::Unit)- | (EnumType::One, EnumType::One) => (),- (EnumType::Unit, EnumType::One)- | (EnumType::One, EnumType::Unit)- | (_, EnumType::Struct) => sum = Some(EnumType::Struct),- _ => panic!("enum member types must be consistent: {:?}", (sum, ty)),- }- sum- },- );- let enum_type = enum_type.expect("enum cannot be empty");- let mut iter = data.variants.iter().peekable();-- let unknown_arm: Option<syn::Arm> = iter.next_if(|variant| is_unknown(&variant.attrs))- .map(|unknown| {- let name = &unknown.ident;- assert!(- unknown.discriminant.is_none(),- "unknown member is not allowed custom discriminant"- );- assert!(- is_with(&unknown.attrs).is_none(),- "unknown member is not allowed with type"- );-- match &unknown.fields {- syn::Fields::Unnamed(fields) => match fields.unnamed.len() {- 1 => {- assert_eq!(enum_type, EnumType::Unit);- syn::parse_quote! {- tag => #ident::#name(tag),- }- }- 2 => {- assert_eq!(enum_type, EnumType::One);- let val_ty = &fields.unnamed[1].ty;- syn::parse_quote! {- tag => {- let tag: u32 = tag.try_into().map_err(|_| cbor4ii::core::error::DecodeError::CastOverflow {- name: &"unknown-tag",- })?;- let val = <#val_ty as cbor4ii::core::dec::Decode<'_>>::decode(reader)?;- #ident::#name(tag, val)- },- }- }- _ => panic!("unknown member must be a tag and a value"),- },- _ => panic!("named enum unsupported"),- }- });-- if matches!(enum_type, EnumType::Struct) {- assert!(- unknown_arm.is_none(),- "struct enum does not allow unknown variants"- );- }-- let mut discriminant: u32 = 0;- let fields = iter- .map(|field| -> syn::Arm {- match field.discriminant.as_ref() {- Some((_, syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(lit), .. }))) => {- discriminant = lit.base10_parse::<u32>().unwrap();- },- Some(_) => panic!("unsupported discriminant type"),- None => (),- };- discriminant += 1;- let idx = discriminant as u64;- let name = &field.ident;-- assert!(!is_unknown(&field.attrs), "unknown member must be first");-- match enum_type {- EnumType::Unit => {- assert!(is_with(&field.attrs).is_none(), "unit member is not allowed with type");- syn::parse_quote!{- #idx => #ident::#name,- }- },- EnumType::One => {- let val_ty = &field.fields.iter().next().unwrap().ty;- let value: syn::Expr = match is_with(&field.attrs) {- Some(with_type)- => syn::parse_quote!(<#with_type<#val_ty> as cbor4ii::core::dec::Decode<'_>>::decode(reader)?.0),- None => syn::parse_quote!(<#val_ty as cbor4ii::core::dec::Decode<'_>>::decode(reader)?)- };-- syn::parse_quote!{- #idx => #ident::#name(#value),- }- },- EnumType::Struct => {- let is_named = field.fields.iter().all(|field| field.ident.is_some());- let names = field.fields.iter()- .enumerate()- .map(|(idx, field)| match field.ident.as_ref() {- Some(name) => name.clone(),- None => {- let name = format!("unit{idx}");- syn::Ident::new(&name, field.span())- }- })- .collect::<Vec<_>>();- let count = names.len();-- let stmt = field.fields.iter()- .zip(names.iter())- .map(|(field, field_name)| -> syn::Stmt {- let val_ty = &field.ty;- match is_with(&field.attrs) {- Some(with_type) => syn::parse_quote!{- let #field_name = <#with_type<#val_ty> as cbor4ii::core::dec::Decode<'_>>::decode(reader)?.0;- },- None => syn::parse_quote!{- let #field_name = <#val_ty as cbor4ii::core::dec::Decode<'_>>::decode(reader)?;- }- }- });- let build_struct: syn::Expr = if is_named {- syn::parse_quote! { #ident::#name { #(#names),* } }- } else {- syn::parse_quote! { #ident::#name ( #(#names),* ) }- };-- syn::parse_quote!{- #idx => {- let len = cbor4ii::core::types::Array::len(reader)?.unwrap();- let value = {- #(#stmt)*- #build_struct- };-- // ignore unknown field- for _ in 0..(len - #count) {- cbor4ii::core::dec::IgnoredAny::decode(reader)?;- }-- value- },- }- }- }- });-- let unknown_arm = match unknown_arm {- Some(arm) => arm,- None => {- syn::parse_quote! {- tag => {- let err = cbor4ii::core::error::DecodeError::Custom {- name: &stringify!(#ident),- num: tag as u32- };- return Err(err);- }- }- }- };-- let tag: syn::Stmt = if matches!(enum_type, EnumType::Unit) {- syn::parse_quote! {- let tag = <u64 as cbor4ii::core::dec::Decode<'_>>::decode(reader)?;- }- } else {- syn::parse_quote! {- let tag = <cbor4ii::core::types::Tag<()>>::tag(reader)?;- }- };-- syn::parse_quote! {- impl<'de> cbor4ii::core::dec::Decode<'de> for #ident {- #[inline]- fn decode<R: cbor4ii::core::dec::Read<'de>>(reader: &mut R)- -> Result<Self, cbor4ii::core::error::DecodeError<R::Error>>- {- #tag- let value = match tag {- #(#fields)*- #unknown_arm- };- Ok(value)- }- }- }- }- Data::Union(_) => panic!("union unsupported"),- }-}
deps/swc/crates/ast_node/src/encoding/encode.rs
@@ -1,237 +0,0 @@-use syn::{spanned::Spanned, Data, DeriveInput};--use super::{is_ignore, is_unknown, is_with, EnumType};--pub fn expand(DeriveInput { ident, data, .. }: DeriveInput) -> syn::ItemImpl {- match data {- Data::Struct(data) => {- let fields = data- .fields- .iter()- .enumerate()- .filter(|(_, field)| !is_ignore(&field.attrs))- .map(|(idx, field)| -> syn::Stmt {- let fieldpath: syn::ExprField = match field.ident.as_ref() {- Some(name) => syn::parse_quote!(self.#name),- None => {- let name = format!("{idx}");- let name = syn::LitInt::new(&name, field.span());- syn::parse_quote!(self.#name)- }- };-- match is_with(&field.attrs) {- Some(with_type) => syn::parse_quote! {- cbor4ii::core::enc::Encode::encode(&#with_type(&#fieldpath), writer)?;- },- None => syn::parse_quote! {- cbor4ii::core::enc::Encode::encode(&#fieldpath, writer)?;- },- }- })- .collect::<Vec<_>>();- let count = fields.len();- let head: Option<syn::Stmt> = (count != 1).then(|| {- syn::parse_quote! {- <cbor4ii::core::types::Array<()>>::bounded(#count, writer)?;- }- });-- syn::parse_quote! {- impl cbor4ii::core::enc::Encode for #ident {- #[inline]- fn encode<W: cbor4ii::core::enc::Write>(&self, writer: &mut W)- -> Result<(), cbor4ii::core::error::EncodeError<W::Error>>- {- #head- #(#fields)*;- Ok(())- }- }- }- }- Data::Enum(data) => {- let enum_type = data.variants.iter().filter(|v| !is_unknown(&v.attrs)).fold(- None,- |mut sum, next| {- let ty = match &next.fields {- syn::Fields::Named(_) => EnumType::Struct,- syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => EnumType::One,- syn::Fields::Unit => EnumType::Unit,- syn::Fields::Unnamed(_) => {- panic!("more than 1 unnamed member field are not allowed")- }- };- match (*sum.get_or_insert(ty), ty) {- (EnumType::Struct, EnumType::Struct)- | (EnumType::Struct, EnumType::Unit)- | (EnumType::Unit, EnumType::Unit)- | (EnumType::One, EnumType::One) => (),- (EnumType::Unit, EnumType::One)- | (EnumType::One, EnumType::Unit)- | (_, EnumType::Struct) => sum = Some(EnumType::Struct),- _ => panic!("enum member types must be consistent: {:?}", (sum, ty)),- }- sum- },- );- let enum_type = enum_type.expect("enum cannot be empty");- let mut iter = data.variants.iter().peekable();-- let unknown_arm: Option<syn::Arm> = iter.next_if(|variant| is_unknown(&variant.attrs))- .map(|unknown| {- let name = &unknown.ident;- assert!(- unknown.discriminant.is_none(),- "unknown member is not allowed custom discriminant"- );- assert!(- is_with(&unknown.attrs).is_none(),- "unknown member is not allowed with type"- );-- match &unknown.fields {- syn::Fields::Unnamed(fields) => match fields.unnamed.len() {- 1 => {- assert_eq!(enum_type, EnumType::Unit);- syn::parse_quote! {- #ident::#name(tag)- => tag.encode(writer)?,- }- }- 2 => {- assert_eq!(enum_type, EnumType::One);- syn::parse_quote! {- #ident::#name(tag, value)- => cbor4ii::core::types::Tag((*tag).into(), &*value).encode(writer)?,- }- }- _ => panic!("unknown member must be a tag and a value"),- },- _ => panic!("named enum unsupported"),- }- });-- if matches!(enum_type, EnumType::Struct) {- assert!(- unknown_arm.is_none(),- "struct enum does not allow unknown variants"- );- }-- let mut discriminant: u32 = 0;- let fields = iter.map(|field| -> syn::Arm {- match field.discriminant.as_ref() {- Some((_, syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(lit), .. }))) => {- discriminant = lit.base10_parse::<u32>().unwrap();- },- Some(_) => panic!("unsupported discriminant type"),- None => (),- };- discriminant += 1;- let idx = discriminant;- let name = &field.ident;-- assert!(- !is_unknown(&field.attrs),- "unknown member must be first: {:?}",- field.attrs.len()- );-- match enum_type {- EnumType::Unit => {- assert!(- is_with(&field.attrs).is_none(),- "unit member is not allowed with type"- );-- syn::parse_quote! {- #ident::#name => #idx.encode(writer)?,- }- },- EnumType::One => {- let value: syn::Expr = match is_with(&field.attrs) {- Some(ty) => syn::parse_quote! {- &#ty(&*value)- },- None => syn::parse_quote! {- &*value- },- };-- syn::parse_quote! {- #ident::#name(value) => {- cbor4ii::core::types::Tag(- #idx.into(),- #value- ).encode(writer)?;- },- }- },- EnumType::Struct => {- let is_named = field.fields.iter().all(|field| field.ident.is_some());- let names = field.fields.iter()- .enumerate()- .map(|(idx, field)| match field.ident.as_ref() {- Some(name) => name.clone(),- None => {- let name = format!("unit{idx}");- syn::Ident::new(&name, field.span())- }- })- .collect::<Vec<_>>();- let stmt = field.fields.iter()- .zip(names.iter())- .map(|(field, field_name)| -> syn::Stmt {- match is_with(&field.attrs) {- Some(ty) => syn::parse_quote! {- cbor4ii::core::enc::Encode::encode(&#ty(&*#field_name), writer)?;- },- None => syn::parse_quote! {- cbor4ii::core::enc::Encode::encode(&*#field_name, writer)?;- },- }- });- let count = stmt.len();- let head: syn::Expr = syn::parse_quote!{{- cbor4ii::core::types::Tag(#idx.into(), cbor4ii::core::types::Nothing).encode(writer)?;- cbor4ii::core::types::Array::bounded(#count, writer)?;- }};-- if is_named {- syn::parse_quote!{- #ident::#name { #(#names),* } => {- #head;- #(#stmt)*- },- }- } else {- syn::parse_quote!{- #ident::#name ( #(#names),* ) => {- #head;- #(#stmt)*- },- }- }- }- }- });-- syn::parse_quote! {- impl cbor4ii::core::enc::Encode for #ident {- #[inline]- fn encode<W: cbor4ii::core::enc::Write>(&self, writer: &mut W)- -> Result<(), cbor4ii::core::error::EncodeError<W::Error>>- {- match self {- #(#fields)*- #unknown_arm- }- Ok(())- }- }- }- }- Data::Union(_) => panic!("union unsupported"),- }-}
deps/swc/crates/ast_node/src/encoding/mod.rs
@@ -1,59 +0,0 @@-pub(crate) mod decode;-pub(crate) mod encode;--#[derive(Clone, Copy, PartialEq, Eq, Debug)]-enum EnumType {- Unit,- One,- Struct,-}--pub(crate) fn is_unknown(attrs: &[syn::Attribute]) -> bool {- attrs- .iter()- .filter(|attr| attr.path().is_ident("encoding"))- .any(|attr| {- let mut is_unknown = false;- attr.parse_nested_meta(|meta| {- is_unknown |= meta.path.is_ident("unknown");- Ok(())- })- .unwrap();- is_unknown- })-}--fn is_with(attrs: &[syn::Attribute]) -> Option<syn::Path> {- attrs- .iter()- .filter(|attr| attr.path().is_ident("encoding"))- .find_map(|attr| {- let mut with_type = None;- attr.parse_nested_meta(|meta| {- if meta.path.is_ident("with") {- let val = meta.value()?;- let val: syn::LitStr = val.parse()?;- let val: syn::Path = val.parse()?;- with_type = Some(val);- }-- Ok(())- })- .ok()?;- with_type- })-}--fn is_ignore(attrs: &[syn::Attribute]) -> bool {- attrs- .iter()- .filter(|attr| attr.path().is_ident("encoding"))- .any(|attr| {- let mut has_ignore = false;- let _ = attr.parse_nested_meta(|meta| {- has_ignore |= meta.path.is_ident("ignore");- Ok(())- });- has_ignore- })-}
deps/swc/crates/ast_node/src/enum_deserialize.rs
@@ -1,400 +0,0 @@-use swc_macros_common::prelude::*;-use syn::{- parse::{Parse, ParseStream},- *,-};--struct VariantAttr {- tags: Punctuated<Lit, Token![,]>,-}--impl Parse for VariantAttr {- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {- Ok(VariantAttr {- tags: input.call(Punctuated::parse_terminated)?,- })- }-}--pub fn expand(- DeriveInput {- generics,- ident,- data,- ..- }: DeriveInput,-) -> ItemImpl {- let data = match data {- Data::Enum(data) => data,- _ => unreachable!("expand_enum is called with none-enum item"),- };-- let mut has_wildcard = false;-- let deserialize = {- let mut all_tags: Punctuated<_, token::Comma> = Default::default();- let tag_match_arms = data- .variants- .iter()- .filter(|v| !crate::encoding::is_unknown(&v.attrs))- .map(|variant| {- let field_type = match variant.fields {- Fields::Unnamed(ref fields) => {- assert_eq!(- fields.unnamed.len(),- 1,- "#[ast_node] enum cannot contain variant with multiple fields"- );-- fields.unnamed.last().unwrap().ty.clone()- }- _ => {- unreachable!("#[ast_node] enum cannot contain named fields or unit variant")- }- };- let tags = variant- .attrs- .iter()- .filter_map(|attr| -> Option<VariantAttr> {- if !is_attr_name(attr, "tag") {- return None;- }- let tokens = match &attr.meta {- Meta::List(meta) => meta.tokens.clone(),- _ => {- panic!("#[tag] attribute must be in form of #[tag(..)]")- }- };- let tags = parse2(tokens).expect("failed to parse #[tag] attribute");-- Some(tags)- })- .flat_map(|v| v.tags)- .collect::<Punctuated<_, token::Comma>>();-- assert!(- !tags.is_empty(),- "All #[ast_node] enum variants have one or more tag"- );-- // TODO: Clean up this code- if tags.len() == 1- && match tags.first() {- Some(Lit::Str(s)) => &*s.value() == "*",- _ => false,- }- {- has_wildcard = true;- } else {- for tag in tags.iter() {- all_tags.push(tag.clone());- }- }-- let vi = &variant.ident;-- Arm {- attrs: Default::default(),- pat: Pat::Path(parse_quote!(__TypeVariant::#vi)),- guard: Default::default(),- fat_arrow_token: Token),- body: parse_quote!(- swc_common::private::serde::Result::map(- <#field_type as serde::Deserialize>::deserialize(- swc_common::private::serde::de::ContentDeserializer::<- __D::Error,- >::new(__content),- ),- Self::#vi,- )- ),- comma: Some(Token)),- }- })- .collect::<Vec<Arm>>();-- let tag_expr: Expr = {- let mut visit_str_arms = Vec::new();- let mut visit_bytes_arms = Vec::new();-- for variant in &data.variants {- if crate::encoding::is_unknown(&variant.attrs) {- continue;- }-- let tags = variant- .attrs- .iter()- .filter_map(|attr| -> Option<VariantAttr> {- if !is_attr_name(attr, "tag") {- return None;- }- let tokens = match &attr.meta {- Meta::List(meta) => meta.tokens.clone(),- _ => {- panic!("#[tag] attribute must be in form of #[tag(..)]")- }- };- let tags = parse2(tokens).expect("failed to parse #[tag] attribute");-- Some(tags)- })- .flat_map(|v| v.tags)- .collect::<Punctuated<_, token::Comma>>();-- assert!(- !tags.is_empty(),- "All #[ast_node] enum variants have one or more tag"- );- let (str_pat, bytes_pat) = {- if tags.len() == 1- && match tags.first() {- Some(Lit::Str(s)) => &*s.value() == "*",- _ => false,- }- {- (- Pat::Wild(PatWild {- attrs: Default::default(),- underscore_token: Token),- }),- Pat::Wild(PatWild {- attrs: Default::default(),- underscore_token: Token),- }),- )- } else {- fn make_pat(lit: Lit) -> (Pat, Pat) {- let s = match lit.clone() {- Lit::Str(s) => s.value(),- _ => {- unreachable!()- }- };- (- Pat::Lit(PatLit {- attrs: Default::default(),- lit,- }),- Pat::Lit(PatLit {- attrs: Default::default(),- lit: Lit::ByteStr(LitByteStr::new(s.as_bytes(), call_site())),- }),- )- }- if tags.len() == 1 {- make_pat(tags.into_iter().next().unwrap())- } else {- let mut str_cases = Punctuated::new();- let mut bytes_cases = Punctuated::new();-- for tag in tags {- let (str_pat, bytes_pat) = make_pat(tag);- str_cases.push(str_pat);- bytes_cases.push(bytes_pat);- }-- (- Pat::Or(PatOr {- attrs: Default::default(),- leading_vert: Default::default(),- cases: str_cases,- }),- Pat::Or(PatOr {- attrs: Default::default(),- leading_vert: Default::default(),- cases: bytes_cases,- }),- )- }- }- };- visit_str_arms.push(Arm {- attrs: Default::default(),- pat: str_pat,- guard: None,- fat_arrow_token: Token),- body: {- let vi = &variant.ident;-- parse_quote!(Ok(__TypeVariant::#vi))- },- comma: Some(Token)),- });- visit_bytes_arms.push(Arm {- attrs: Default::default(),- pat: bytes_pat,- guard: None,- fat_arrow_token: Token),- body: {- let vi = &variant.ident;-- parse_quote!(Ok(__TypeVariant::#vi))- },- comma: Some(Token)),- });- }-- if !has_wildcard {- visit_str_arms.push(Arm {- attrs: Default::default(),- pat: Pat::Wild(PatWild {- attrs: Default::default(),- underscore_token: Token),- }),- guard: None,- fat_arrow_token: Token),- body: parse_quote!(swc_common::private::serde::Err(- serde::de::Error::unknown_variant(__value, VARIANTS,)- )),- comma: Some(Token)),- });- visit_bytes_arms.push(Arm {- attrs: Default::default(),- pat: Pat::Wild(PatWild {- attrs: Default::default(),- underscore_token: Token!(_)(ident.span()),- }),- guard: None,- fat_arrow_token: Token),- body: parse_quote!({- let __value = &swc_common::private::serde::from_utf8_lossy(__value);- swc_common::private::serde::Err(serde::de::Error::unknown_variant(- __value, VARIANTS,- ))- }),- comma: Some(Token)),- });- }-- let visit_str_body = Expr::Match(ExprMatch {- attrs: Default::default(),- match_token: Default::default(),- expr: parse_quote!(__value),- brace_token: Default::default(),- arms: visit_str_arms,- });- let visit_bytes_body = Expr::Match(ExprMatch {- attrs: Default::default(),- match_token: Default::default(),- expr: parse_quote!(__value),- brace_token: Default::default(),- arms: visit_bytes_arms,- });-- parse_quote!({- static VARIANTS: &[&str] = &[#all_tags];-- struct __TypeVariantVisitor;-- impl<'de> serde::de::Visitor<'de> for __TypeVariantVisitor {- type Value = __TypeVariant;-- fn expecting(- &self,- __formatter: &mut swc_common::private::serde::Formatter,- ) -> swc_common::private::serde::fmt::Result {- swc_common::private::serde::Formatter::write_str(- __formatter,- "variant identifier",- )- }-- fn visit_str<__E>(- self,- __value: &str,- ) -> swc_common::private::serde::Result<Self::Value, __E>- where- __E: serde::de::Error,- {- #visit_str_body- }-- fn visit_bytes<__E>(- self,- __value: &[u8],- ) -> swc_common::private::serde::Result<Self::Value, __E>- where- __E: serde::de::Error,- {- #visit_bytes_body- }- }-- impl<'de> serde::Deserialize<'de> for __TypeVariant {- #[inline]- fn deserialize<__D>(- __deserializer: __D,- ) -> swc_common::private::serde::Result<Self, __D::Error>- where- __D: serde::Deserializer<'de>,- {- serde::Deserializer::deserialize_identifier(- __deserializer,- __TypeVariantVisitor,- )- }- }-- let ty = swc_common::serializer::Type::deserialize(- swc_common::private::serde::de::ContentRefDeserializer::<__D::Error>::new(- &__content,- ),- )?;-- let __tagged = __TypeVariant::deserialize(- swc_common::private::serde::de::ContentDeserializer::<__D::Error>::new(- swc_common::private::serde::de::Content::Str(&ty.ty),- ),- )?;-- __tagged- })- };-- let match_type_expr = Expr::Match(ExprMatch {- attrs: Default::default(),- match_token: Default::default(),- expr: parse_quote!(__tagged),- brace_token: Default::default(),- arms: tag_match_arms,- });-- let variants: Punctuated<Variant, Token![,]> = {- data.variants- .iter()- .filter(|v| !crate::encoding::is_unknown(&v.attrs))- .cloned()- .map(|variant| Variant {- attrs: Default::default(),- fields: Fields::Unit,- ..variant- })- .collect()- };- let item: ItemImpl = parse_quote!(- #[cfg(feature = "serde-impl")]- impl<'de> serde::Deserialize<'de> for #ident {- #[allow(unreachable_code)]- fn deserialize<__D>(__deserializer: __D) -> ::std::result::Result<Self, __D::Error>- where- __D: serde::Deserializer<'de>,- {- enum __TypeVariant {- #variants,- }-- let __content = swc_common::private::content::deserialize_content(__deserializer)?;-- let __tagged = #tag_expr;-- #match_type_expr- }- }- );-- item.with_generics(generics)- };-- deserialize-}
deps/swc/crates/ast_node/src/lib.rs
@@ -1,327 +0,0 @@-#![deny(clippy::all)]-#![recursion_limit = "1024"]--extern crate proc_macro;--use quote::quote;-use swc_macros_common::prelude::*;-use syn::*;--mod ast_node_macro;-mod encoding;-mod enum_deserialize;-mod spanned;--/// Derives [`swc_common::Spanned`]. See [`swc_common::Spanned`] for-/// documentation.-#[proc_macro_derive(Spanned, attributes(span))]-pub fn derive_spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream {- let input = parse::<DeriveInput>(input).expect("failed to parse input as DeriveInput");-- let item = self::spanned::derive(input);-- print("derive(Spanned)", item.into_token_stream())-}--/// Derives `serde::Deserialize` which is aware of `tag` based deserialization.-#[proc_macro_derive(DeserializeEnum, attributes(tag, encoding))]-pub fn derive_deserialize_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {- let input = parse::<DeriveInput>(input).expect("failed to parse input as DeriveInput");-- let item = enum_deserialize::expand(input);-- print("derive(DeserializeEnum)", item.into_token_stream())-}--#[proc_macro_derive(Encode, attributes(encoding))]-pub fn derive_encode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {- let input =- syn::parse::<syn::DeriveInput>(input).expect("failed to parse input as DeriveInput");-- let item = encoding::encode::expand(input);- print("derive(Encode)", item.into_token_stream())-}--#[proc_macro_derive(Decode, attributes(encoding))]-pub fn derive_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {- let input =- syn::parse::<syn::DeriveInput>(input).expect("failed to parse input as DeriveInput");-- let item = encoding::decode::expand(input);- print("derive(Decode)", item.into_token_stream())-}--/// Derives `serde::Serialize` and `serde::Deserialize`.-///-/// # Struct attributes-///-/// `#[ast_serde("A")]` adds `"type": "A"` to json when serialized, and-/// deserializes as the type only if `type` field of json string is `A`.-///-/// # Enum attributes-///-/// ## Type-level attributes-///-/// This macro does not accept arguments if used on enum.-///-/// ## Variant attributes-///-/// ### `#[tag("Expr")]`-///-/// You can tell "Use this variant if `type` is `Expr`".-///-/// This attribute can be applied multiple time, if a variant consumes multiple-/// `type`s.-///-/// For example, `Lit` of swc_ecma_ast is an enum, but `Expr`, which contains-/// `Lit` as a variant, is also an enum.-/// So the `Lit` variant has multiple `#[tag]`-s like-///-/// ```rust,ignore-/// enum Expr {-/// #[tag("StringLiteral")]-/// #[tag("NumericLiteral")]-/// #[tag("BooleanLiteral")]-/// Lit(Lit),-/// }-/// ```-///-/// so the deserializer can decide which variant to use.-///-///-/// `#[tag]` also supports wildcard like `#[tag("*")]`. You can use this if-/// there are two many variants.-#[proc_macro_attribute]-pub fn ast_serde(- args: proc_macro::TokenStream,- input: proc_macro::TokenStream,-) -> proc_macro::TokenStream {- let input: DeriveInput = parse(input).expect("failed to parse input as a DeriveInput");-- // we should use call_site- let mut item = TokenStream::new();- match input.data {- Data::Enum(..) => {- if !args.is_empty() {- panic!("#[ast_serde] on enum does not accept any argument")- }-- item.extend(quote!(- #[derive(::serde::Serialize, ::swc_common::DeserializeEnum)]- #[serde(untagged)]- #input- ));- }- _ => {- let args: Option<ast_node_macro::Args> = if args.is_empty() {- None- } else {- Some(parse(args).expect("failed to parse args of #[ast_serde]"))- };-- let serde_tag = match input.data {- Data::Struct(DataStruct {- fields: Fields::Named(..),- ..- }) => {- if args.is_some() {- Some(quote!(#[serde(tag = "type")]))- } else {- None- }- }- _ => None,- };-- let serde_rename = args.as_ref().map(|args| {- let name = &args.ty;- quote!(#[serde(rename = #name)])- });-- item.extend(quote!(- #[derive(::serde::Serialize, ::serde::Deserialize)]- #serde_tag- #[serde(rename_all = "camelCase")]- #serde_rename- #input- ));- }- };-- print("ast_serde", item)-}--/// Adds the standard AST node derives and serialization metadata.-///-/// Structs derive `PartialEq` by default. Pass `no_partial_eq` after the node-/// tag when the type provides a manual implementation:-/// `#[ast_node("CustomNode", no_partial_eq)]`.-#[proc_macro_attribute]-pub fn ast_node(- args: proc_macro::TokenStream,- input: proc_macro::TokenStream,-) -> proc_macro::TokenStream {- let mut input: DeriveInput = parse(input).expect("failed to parse input as a DeriveInput");-- // we should use call_site- let mut item = TokenStream::new();- match &input.data {- Data::Enum(data) => {- use syn::parse::Parser;-- let attrs = <syn::punctuated::Punctuated<syn::Ident, syn::Token![,]>>::parse_terminated- .parse(args)- .expect("failed to parse #[ast_node]");-- let mut has_no_clone = false;- let mut has_no_unknown = false;- for attr in &attrs {- if attr == "no_clone" {- has_no_clone = true;- } else if attr == "no_unknown" {- has_no_unknown = true;- } else {- panic!("unknown attribute: {attr:?}")- }- }-- let clone = if !has_no_clone {- Some(quote!(#[derive(Clone)]))- } else {- None- };- let non_exhaustive = if !has_no_unknown {- Some(quote!(#[cfg_attr(swc_ast_unknown, non_exhaustive)]))- } else {- None- };-- let mut data = data.clone();- if !has_no_unknown {- let unknown: syn::Variant = if data- .variants- .iter()- .all(|variant| variant.fields.is_empty())- {- syn::parse_quote! {- #[cfg(all(swc_ast_unknown, feature = "encoding-impl"))]- #[from_variant(ignore)]- #[span(unknown)]- #[encoding(unknown)]- Unknown(u32)- }- } else {- syn::parse_quote! {- #[cfg(all(swc_ast_unknown, feature = "encoding-impl"))]- #[from_variant(ignore)]- #[span(unknown)]- #[encoding(unknown)]- Unknown(u32, swc_common::unknown::Unknown)- }- };-- // insert unknown member- data.variants.insert(0, unknown);- input.data = Data::Enum(data);- }-- item.extend(quote!(- #[allow(clippy::derive_partial_eq_without_eq)]- #[cfg_attr(- feature = "serde-impl",- derive(- ::serde::Serialize,- )- )]- #[derive(- ::swc_common::FromVariant,- ::swc_common::Spanned,- Debug,- PartialEq,- ::swc_common::DeserializeEnum,- )]- #clone- #non_exhaustive- #[cfg_attr(- feature = "serde-impl",- serde(untagged)- )]- #[cfg_attr(- feature = "encoding-impl",- derive(::swc_common::Encode, ::swc_common::Decode)- )]- #input- ));- }- _ => {- let args: Option<ast_node_macro::Args> = if args.is_empty() {- None- } else {- Some(parse(args).expect("failed to parse args of #[ast_node]"))- };-- let serde_tag = match input.data {- Data::Struct(DataStruct {- fields: Fields::Named(..),- ..- }) => {- if args.is_some() {- Some(quote!(#[cfg_attr(- feature = "serde-impl",- serde(tag = "type")- )]))- } else {- None- }- }- _ => None,- };-- let serde_rename = args.as_ref().map(|args| {- let name = &args.ty;-- quote!(#[cfg_attr(- feature = "serde-impl",- serde(rename = #name)- )])- });-- let ast_node_impl = args- .as_ref()- .map(|args| ast_node_macro::expand_struct(args.clone(), input.clone()));-- let partial_eq = match &args {- Some(args) if args.no_partial_eq => None,- _ => Some(quote!(PartialEq,)),- };-- item.extend(quote!(- #[allow(clippy::derive_partial_eq_without_eq)]- #[derive(::swc_common::Spanned, Clone, Debug, #partial_eq)]- #[cfg_attr(- feature = "serde-impl",- derive(::serde::Serialize, ::serde::Deserialize)- )]- #serde_tag- #[cfg_attr(- feature = "serde-impl",- serde(rename_all = "camelCase")- )]- #serde_rename- #[cfg_attr(- feature = "encoding-impl",- derive(::swc_common::Encode, ::swc_common::Decode)- )]- #input- ));-- if let Some(items) = ast_node_impl {- for item_impl in items {- item.extend(item_impl.into_token_stream());- }- }- }- };-- print("ast_node", item)-}
deps/swc/crates/ast_node/src/spanned.rs
@@ -1,224 +0,0 @@-#![allow(dead_code)]--use swc_macros_common::prelude::*;-use syn::{parse::Parse, spanned::Spanned, *};--struct MyField {- /// Name of the field.- pub ident: Option<Ident>,- /// Type of the field.- pub ty: Type,-- /// `#[span(lo)]`- pub lo: bool,- /// `#[span(hi)]`- pub hi: bool,-}--struct InputFieldAttr {- kinds: Punctuated<Ident, Token![,]>,-}--impl Parse for InputFieldAttr {- fn parse(input: parse::ParseStream) -> Result<Self> {- let kinds = input.call(Punctuated::parse_terminated)?;-- Ok(Self { kinds })- }-}--fn is_unknown(attrs: &[syn::Attribute]) -> bool {- attrs- .iter()- .filter(|attr| attr.path().is_ident("span"))- .any(|attr| {- let mut is_unknown = false;- attr.parse_nested_meta(|meta| {- is_unknown |= meta.path.is_ident("unknown");- Ok(())- })- .unwrap();- is_unknown- })-}--impl MyField {- fn from_field(f: &Field) -> Self {- let mut lo = false;- let mut hi = false;-- for attr in &f.attrs {- if !is_attr_name(attr, "span") {- continue;- }-- match &attr.meta {- Meta::Path(..) => {}- Meta::List(list) => {- let input = parse2::<InputFieldAttr>(list.tokens.clone())- .expect("failed to parse as `InputFieldAttr`");-- for kind in input.kinds {- if kind == "lo" {- lo = true- } else if kind == "hi" {- hi = true- } else {- panic!("Unknown span attribute: {kind:?}")- }- }- }- _ => panic!("Unknown span attribute"),- }- }-- Self {- ident: f.ident.clone(),- ty: f.ty.clone(),- lo,- hi,- }- }-}--pub fn derive(input: DeriveInput) -> ItemImpl {- let arms = Binder::new_from(&input)- .variants()- .into_iter()- .map(|v| {- let (pat, bindings) = v.bind("_", Some(Token)), None);-- let body = make_body_for_variant(&v, bindings);-- Arm {- body,- attrs: v- .attrs()- .iter()- .filter(|attr| is_attr_name(attr, "cfg"))- .cloned()- .collect(),- pat,- guard: None,- fat_arrow_token: Default::default(),- comma: Some(Token ! [ , ](def_site())),- }- })- .collect();-- let body = Expr::Match(ExprMatch {- attrs: Default::default(),- match_token: Default::default(),- brace_token: Default::default(),- expr: Box::new(parse_quote!(self)),- arms,- });-- let ty = &input.ident;-- let item: ItemImpl = parse_quote! {- #[automatically_derived]- impl swc_common::Spanned for #ty {- #[inline]- fn span(&self) -> swc_common::Span {- #body- }- }- };- item.with_generics(input.generics)-}--fn make_body_for_variant(v: &VariantBinder<'_>, bindings: Vec<BindedField<'_>>) -> Box<Expr> {- /// `swc_common::Spanned::span(#field)`- fn simple_field(field: &dyn ToTokens) -> Box<Expr> {- Box::new(parse_quote_spanned! (def_site() => {- swc_common::Spanned::span(#field)- }))- }-- if is_unknown(v.attrs()) {- return Box::new(parse_quote_spanned! { v.data().span() => {- swc_common::DUMMY_SP- }});- }-- if bindings.is_empty() {- panic!("#[derive(Spanned)] requires a field to get span from")- }-- if bindings.len() == 1 {- if let Fields::Unnamed(..) = *v.data() {- // Call self.0.span()- return simple_field(&bindings[0]);- }- }-- // Handle #[span] attribute.- if let Some(f) = bindings- .iter()- .find(|b| has_empty_span_attr(&b.field().attrs))- {- //TODO: Verify that there's no more #[span]- return simple_field(f);- }-- // If all fields do not have `#[span(..)]`, check for field named `span`.- let has_any_span_attr = bindings.iter().any(|b| {- b.field()- .attrs- .iter()- .any(|attr| is_attr_name(attr, "span"))- });- if !has_any_span_attr {- let span_field = bindings- .iter()- .find(|b| {- b.field()- .ident- .as_ref()- .map(|ident| ident == "span")- .unwrap_or(false)- })- .unwrap_or_else(|| {- panic!(- "#[derive(Spanned)]: cannot determine span field to use for {}",- v.qual_path().into_token_stream()- )- });-- return simple_field(span_field);- }-- let fields: Vec<_> = bindings- .iter()- .map(|b| (b, MyField::from_field(b.field())))- .collect();-- // TODO: Only one field should be `#[span(lo)]`.- let lo = fields.iter().find(|&(_, f)| f.lo);- let hi = fields.iter().find(|&(_, f)| f.hi);-- match (lo, hi) {- (Some((lo_field, _)), Some((hi_field, _))) => {- // Create a new span from lo_field.lo(), hi_field.hi()- Box::new(parse_quote!(swc_common::Spanned::span(#lo_field)- .with_hi(swc_common::Spanned::span(#hi_field).hi())))- }- _ => panic!("#[derive(Spanned)]: #[span(lo)] and #[span(hi)] is required"),- }-}--/// Search for `#[span]`-fn has_empty_span_attr(attrs: &[Attribute]) -> bool {- attrs.iter().any(|attr| {- if !is_attr_name(attr, "span") {- return false;- }-- match &attr.meta {- Meta::Path(..) => true,- Meta::List(t) => t.tokens.is_empty(),- _ => false,- }- })-}
deps/swc/crates/better_scoped_tls/Cargo.toml
@@ -1,15 +0,0 @@-[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>"]-description = "scoped-tls, but with good error message"-documentation = "https://rustdoc.swc.rs/better_scoped_tls/"-edition = { workspace = true }-license = { workspace = true }-name = "better_scoped_tls"-repository = { workspace = true }-version = "1.0.1"--[lib]-bench = false--[dependencies]-scoped-tls = { workspace = true }
deps/swc/crates/better_scoped_tls/README.md
@@ -1,11 +0,0 @@-# better_scoped_tls--This crate provides an opinionated version of [scoped-tls](https://docs.rs/scoped-tls/1.0.0/scoped_tls/index.html).--Scoped thread local variables created by this crate will panic with a good message on usage without `.set`, like--```-You should perform this operation in the closure passed to `set` of better_scoped_tls::tests::TESTTLS-```--Syntax is exactly same to the original scoped-tls.
deps/swc/crates/better_scoped_tls/src/lib.rs
@@ -1,109 +0,0 @@-//! Better scoped thread local storage.--#[doc(hidden)]-pub extern crate scoped_tls;--/// See [scoped_tls::scoped_thread_local] for actual documentation.-///-/// This is identical as [scoped_tls::scoped_thread_local] on release builds.-#[macro_export]-macro_rules! scoped_tls {- ($(#[$attrs:meta])* $vis:vis static $name:ident: $ty:ty) => {- $crate::scoped_tls::scoped_thread_local!(- static INNER: $ty- );--- $(#[$attrs])*- $vis static $name: $crate::ScopedKey<$ty> = $crate::ScopedKey {- inner: &INNER,- #[cfg(debug_assertions)]- module_path: module_path!(),- #[cfg(debug_assertions)]- name: stringify!($name),- };- };-}--/// Wrapper for [scoped_tls::ScopedKey] with better error messages.-pub struct ScopedKey<T>-where- T: 'static,-{- #[doc(hidden)]- pub inner: &'static scoped_tls::ScopedKey<T>,-- #[cfg(debug_assertions)]- #[doc(hidden)]- pub module_path: &'static str,-- #[cfg(debug_assertions)]- #[doc(hidden)]- pub name: &'static str,-}--impl<T> ScopedKey<T>-where- T: 'static,-{- /// See [scoped_tls::ScopedKey] for actual documentation.- #[cfg_attr(not(debug_assertions), inline(always))]- pub fn set<F, R>(&'static self, t: &T, f: F) -> R- where- F: FnOnce() -> R,- {- self.inner.set(t, f)- }-- /// See [scoped_tls::ScopedKey] for actual documentation.- #[track_caller]- #[cfg_attr(not(debug_assertions), inline(always))]- pub fn with<F, R>(&'static self, f: F) -> R- where- F: FnOnce(&T) -> R,- {- #[cfg(debug_assertions)]- if !self.inner.is_set() {- // Override panic message- panic!(- "You should perform this operation in the closure passed to `set` of {}::{}",- self.module_path, self.name- )- }-- self.inner.with(f)- }-- /// See [scoped_tls::ScopedKey] for actual documentation.- #[cfg_attr(not(debug_assertions), inline(always))]- pub fn is_set(&'static self) -> bool {- self.inner.is_set()- }-}--#[cfg(test)]-mod tests {-- scoped_tls!(- pub static TESTTLS: String- );-- #[cfg(debug_assertions)]- #[test]- #[should_panic = "You should perform this operation in the closure passed to `set` of \- better_scoped_tls::tests::TESTTLS"]- fn panic_on_with() {- TESTTLS.with(|s| {- println!("S: {s}");- })- }- #[test]-- fn valid() {- TESTTLS.set(&String::new(), || {- TESTTLS.with(|s| {- assert_eq!(*s, String::new());- })- })- }-}
deps/swc/crates/binding_macros/Cargo.toml
@@ -1,58 +0,0 @@-[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>", "OJ Kwon <kwon.ohjoong@gmail.com>"]-description = "Macros to build customized bindings interface"-edition = { workspace = true }-license = { workspace = true }-name = "binding_macros"-repository = { workspace = true }-version = "80.0.0"--[lib]-bench = false--[features]-binding_native = []-binding_wasm = [- # SWC features- "swc",- "swc_common",- "swc_ecma_transforms",- "swc_ecma_ast",- "swc_ecma_visit",-- # Optional packages- "once_cell",- "wasm-bindgen",- "wasm-bindgen-futures",- "js-sys",- "serde",- "serde-wasm-bindgen",- "anyhow",- "console_error_panic_hook",-]--[dependencies]-# Common deps for the SWC imports-swc = { optional = true, version = "80.0.0", path = "../swc", default-features = false }-swc_common = { optional = true, version = "26.0.0", path = "../swc_common", default-features = false }-swc_ecma_ast = { optional = true, version = "29.0.2", path = "../swc_ecma_ast", default-features = false }-swc_ecma_transforms = { optional = true, version = "64.0.0", path = "../swc_ecma_transforms", default-features = false }-swc_ecma_visit = { optional = true, version = "29.0.0", path = "../swc_ecma_visit", default-features = false }--# Optional deps for the wasm binding macro-anyhow = { workspace = true, optional = true }-console_error_panic_hook = { workspace = true, optional = true }-js-sys = { workspace = true, optional = true }-once_cell = { workspace = true, optional = true }-serde = { workspace = true, features = ["derive"], optional = true }-serde-wasm-bindgen = { workspace = true, optional = true }---[dependencies.wasm-bindgen]-features = ["enable-interning"]-optional = true-workspace = true--[dependencies.wasm-bindgen-futures]-optional = true-workspace = true
deps/swc/crates/binding_macros/src/lib.rs
@@ -1,2 +0,0 @@-#[cfg(feature = "binding_wasm")]-pub mod wasm;
deps/swc/crates/binding_macros/src/wasm.rs
@@ -1,431 +0,0 @@-use std::sync::Arc;--#[doc(hidden)]-pub use anyhow;-use anyhow::Error;-#[doc(hidden)]-pub use js_sys;-use once_cell::sync::Lazy;-#[doc(hidden)]-pub use serde_wasm_bindgen;-use serde_wasm_bindgen::Serializer;-#[doc(hidden)]-pub use swc::PrintArgs;-use swc::{config::ErrorFormat, Compiler, HandlerOpts};-#[doc(hidden)]-pub use swc::{- config::{Options, ParseOptions, SourceMapsConfig},- try_with_handler,-};-#[doc(hidden)]-pub use swc_common::{- comments::{self, SingleThreadedComments},- errors::Handler,- FileName, Mark, GLOBALS,-};-use swc_common::{sync::Lrc, FilePathMapping, SourceMap};-#[doc(hidden)]-pub use swc_ecma_ast::noop_pass;-#[doc(hidden)]-pub use swc_ecma_ast::{EsVersion, Program};-#[doc(hidden)]-pub use swc_ecma_transforms::resolver;-#[doc(hidden)]-pub use swc_ecma_visit::VisitMutWith;-#[doc(hidden)]-pub use wasm_bindgen::{JsCast, JsValue};-#[doc(hidden)]-pub use wasm_bindgen_futures::future_to_promise;--// A serializer with options to provide backward compat for the input / output-// from the bindgen generated swc interfaces.-#[doc(hidden)]-pub fn compat_serializer() -> Arc<Serializer> {- static V: Lazy<Arc<Serializer>> = Lazy::new(|| {- let s = Serializer::new()- .serialize_maps_as_objects(true)- .serialize_missing_as_null(true);- Arc::new(s)- });-- V.clone()-}--#[doc(hidden)]-pub fn try_with_handler_globals<F, Ret>(- cm: Lrc<SourceMap>,- config: HandlerOpts,- op: F,-) -> Result<Ret, Error>-where- F: FnOnce(&Handler) -> Result<Ret, Error>,-{- GLOBALS- .set(&Default::default(), || {- swc::try_with_handler(cm, config, op)- })- .map_err(|e| e.to_pretty_error())-}--/// Get global sourcemap-pub fn compiler() -> Arc<Compiler> {- console_error_panic_hook::set_once();-- static C: Lazy<Arc<Compiler>> = Lazy::new(|| {- let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));-- Arc::new(Compiler::new(cm))- });-- C.clone()-}--#[doc(hidden)]-pub fn convert_err(- err: Error,- error_format: Option<ErrorFormat>,-) -> wasm_bindgen::prelude::JsValue {- error_format- .unwrap_or(ErrorFormat::Normal)- .format(&err)- .into()-}--#[macro_export]-macro_rules! build_minify_sync {- ($(#[$m:meta])*) => {- build_minify_sync!($(#[$m])*, Default::default());- };- ($(#[$m:meta])*, $opt: expr) => {- $(#[$m])*- pub fn minify_sync(s: $crate::wasm::js_sys::JsString, opts: $crate::wasm::JsValue) -> Result<$crate::wasm::JsValue, $crate::wasm::JsValue> {- use serde::Serialize;-- let c = $crate::wasm::compiler();-- $crate::wasm::try_with_handler_globals(- c.cm.clone(),- $opt,- |handler| {- c.run(|| {- let opts = if opts.is_null() || opts.is_undefined() {- Default::default()- } else {- $crate::wasm::serde_wasm_bindgen::from_value(opts)- .map_err(|e| $crate::wasm::anyhow::anyhow!("failed to parse options: {}", e))?- };-- let fm = c.cm.new_source_file($crate::wasm::FileName::Anon.into(), String::from(s));- let program = $crate::wasm::anyhow::Context::context(c.minify(fm, handler, &opts, Default::default()), "failed to minify file")?;-- program- .serialize($crate::wasm::compat_serializer().as_ref())- .map_err(|e| $crate::wasm::anyhow::anyhow!("failed to serialize program: {}", e))- })- },- )- .map_err(|e| $crate::wasm::convert_err(e, None))- }- };-}--/// Currently this relies on existence of minify_sync.-#[macro_export]-macro_rules! build_minify {- ($(#[$m:meta])*) => {- build_minify!($(#[$m])*, Default::default());- };- ($(#[$m:meta])*, $opt: expr) => {- $(#[$m])*- pub fn minify(s: $crate::wasm::js_sys::JsString, opts: $crate::wasm::JsValue) -> $crate::wasm::js_sys::Promise {- // TODO: This'll be properly scheduled once wasm have standard backed thread- // support.- $crate::wasm::future_to_promise(async { minify_sync(s, opts) })- }- };-}--#[macro_export]-macro_rules! build_parse_sync {- ($(#[$m:meta])*) => {- build_parse_sync!($(#[$m])*, Default::default());- };- ($(#[$m:meta])*, $opt: expr) => {- $(#[$m])*- pub fn parse_sync(s: $crate::wasm::js_sys::JsString, opts: $crate::wasm::JsValue) -> Result<$crate::wasm::JsValue, $crate::wasm::JsValue> {- use serde::Serialize;- use $crate::wasm::VisitMutWith;- use $crate::wasm::PrintArgs;-- let c = $crate::wasm::compiler();-- $crate::wasm::try_with_handler_globals(- c.cm.clone(),- $opt,- |handler| {- c.run(|| {- let opts: $crate::wasm::ParseOptions = if opts.is_null() || opts.is_undefined() {- Default::default()- } else {- $crate::wasm::serde_wasm_bindgen::from_value(opts)- .map_err(|e| $crate::wasm::anyhow::anyhow!("failed to parse options: {}", e))?- };-- let fm = c.cm.new_source_file($crate::wasm::FileName::Anon.into(), String::from(s));-- let cmts = c.comments().clone();- let comments = if opts.comments {- Some(&cmts as &dyn $crate::wasm::comments::Comments)- } else {- None- };-- let mut program = $crate::wasm::anyhow::Context::context(- c.parse_js(- fm,- handler,- opts.target,- opts.syntax,- opts.is_module,- comments,- ),- "failed to parse code"- )?;-- program.visit_mut_with(&mut $crate::wasm::resolver(- $crate::wasm::Mark::new(),- $crate::wasm::Mark::new(),- opts.syntax.typescript(),- ));-- program- .serialize($crate::wasm::compat_serializer().as_ref())- .map_err(|e| $crate::wasm::anyhow::anyhow!("failed to serialize program: {}", e))- })- },- )- .map_err(|e| $crate::wasm::convert_err(e, None))- }- };-}--/// Currently this relies on existence of parse_sync.-#[macro_export]-macro_rules! build_parse {- ($(#[$m:meta])*) => {- build_parse!($(#[$m])*, Default::default());- };- ($(#[$m:meta])*, $opt: expr) => {- $(#[$m])*- pub fn parse(s: $crate::wasm::js_sys::JsString, opts: $crate::wasm::JsValue) -> $crate::wasm::js_sys::Promise {- // TODO: This'll be properly scheduled once wasm have standard backed thread- // support.- $crate::wasm::future_to_promise(async { parse_sync(s, opts) })- }- };-}--#[macro_export]-macro_rules! build_print_sync {- ($(#[$m:meta])*) => {- build_print_sync!($(#[$m])*, Default::default());- };- ($(#[$m:meta])*, $opt: expr) => {- $(#[$m])*- pub fn print_sync(s: $crate::wasm::JsValue, opts: $crate::wasm::JsValue) -> Result<$crate::wasm::JsValue, $crate::wasm::JsValue> {- use $crate::wasm::PrintArgs;-- let c = $crate::wasm::compiler();-- $crate::wasm::try_with_handler_globals(- c.cm.clone(),- $opt,- |_handler| {- c.run(|| {- let opts: $crate::wasm::Options = if opts.is_null() || opts.is_undefined() {- Default::default()- } else {- $crate::wasm::serde_wasm_bindgen::from_value(opts)- .map_err(|e| $crate::wasm::anyhow::anyhow!("failed to parse options: {}", e))?- };-- let program: $crate::wasm::Program = $crate::wasm::serde_wasm_bindgen::from_value(s)- .map_err(|e| $crate::wasm::anyhow::anyhow!("failed to deserialize program: {}", e))?;- let s = $crate::wasm::anyhow::Context::context(c- .print(- &program,- PrintArgs {- inline_sources_content: true,- source_map: opts.source_maps- .clone()- .unwrap_or($crate::wasm::SourceMapsConfig::Bool(false)),- emit_source_map_columns: opts.config.emit_source_map_columns.into_bool(),- codegen_config: swc_core::ecma::codegen::Config::default()- .with_target(opts.codegen_target().unwrap_or($crate::wasm::EsVersion::Es2020))- .with_minify(opts.config.minify.into()),- ..Default::default()- },- ),"failed to print code")?;-- serde_wasm_bindgen::to_value(&s)- .map_err(|e| anyhow::anyhow!("failed to serialize json: {}", e))- })- },- )- .map_err(|e| $crate::wasm::convert_err(e, None))- }- };-}--/// Currently this relies on existence of print_sync.-#[macro_export]-macro_rules! build_print {- ($(#[$m:meta])*) => {- build_print!($(#[$m])*, Default::default());- };- ($(#[$m:meta])*, $opt: expr) => {-- $(#[$m])*- pub fn print(s: $crate::wasm::JsValue, opts: $crate::wasm::JsValue) -> $crate::wasm::js_sys::Promise {- // TODO: This'll be properly scheduled once wasm have standard backed thread- // support.- $crate::wasm::future_to_promise(async { print_sync(s, opts) })- }- };-}--#[macro_export]-macro_rules! build_transform_sync {- ($(#[$m:meta])*) => {- build_transform_sync!($(#[$m])*, |_| $crate::wasm::noop_pass(), |_| $crate::wasm::noop_pass(), Default::default());- };- ($(#[$m:meta])*, $before_pass: expr, $after_pass: expr) => {- build_transform_sync!($(#[$m])*, $before_pass, $after_pass, Default::default());- };- ($(#[$m:meta])*, $before_pass: expr, $after_pass: expr, $opt: expr) => {- $(#[$m])*- #[allow(unused_variables)]- pub fn transform_sync(- s: $crate::wasm::JsValue,- opts: $crate::wasm::JsValue,- experimental_plugin_bytes_resolver: $crate::wasm::JsValue,- ) -> Result<$crate::wasm::JsValue, $crate::wasm::JsValue> {- use serde::Serialize;-- let c = $crate::wasm::compiler();-- //[TODO]: refer binding_core_wasm/Cargo.toml,- //disables via renaming feature to arbitary name- #[cfg(feature = "__plugin")]- {- if experimental_plugin_bytes_resolver.is_object() {- use $crate::wasm::js_sys::{Array, Object, Uint8Array};-- // TODO: This is probably very inefficient, including each transform- // deserializes plugin bytes.- let plugin_bytes_resolver_object: Object = experimental_plugin_bytes_resolver- .try_into()- .expect("Resolver should be a js object");-- swc_core::plugin_runner::cache::init_plugin_module_cache_once();-- let entries = Object::entries(&plugin_bytes_resolver_object);- for entry in entries.iter() {- let entry: Array = entry- .try_into()- .expect("Resolver object missing either key or value");- let name: String = entry- .get(0)- .as_string()- .expect("Resolver key should be a string");- let buffer = entry.get(1);-- //https://github.com/rustwasm/wasm-bindgen/issues/2017#issue-573013044- //We may use https://github.com/cloudflare/serde-wasm-bindgen instead later- let data = if $crate::wasm::JsCast::is_instance_of::<Uint8Array>(&buffer) {- JsValue::from(Array::from(&buffer))- } else {- buffer- };-- let bytes: Vec<u8> = $crate::wasm::serde_wasm_bindgen::from_value(data).expect("Could not read byte from plugin resolver");-- // In here we 'inject' externally loaded bytes into the cache, so- // remaining plugin_runner execution path works as much as- // similar between embedded runtime.- swc_core::plugin_runner::cache::PLUGIN_MODULE_CACHE.store_once(&name, bytes);- }- }- }-- let opts: $crate::wasm::Options = if opts.is_null() || opts.is_undefined() {- Default::default()- } else {- $crate::wasm::serde_wasm_bindgen::from_value(opts)?- };-- let error_format = opts.experimental.error_format.unwrap_or_default();- $crate::wasm::try_with_handler_globals(- c.cm.clone(),- $opt,- |handler| {- c.run(|| {- let s = $crate::wasm::JsCast::dyn_into::<$crate::wasm::js_sys::JsString>(s);- let out = match s {- Ok(s) => {- let fm = c.cm.new_source_file(- if opts.filename.is_empty() {- $crate::wasm::FileName::Anon.into()- } else {- $crate::wasm::FileName::Real(opts.filename.clone().into()).into()- },- String::from(s),- );- let cm = c.cm.clone();- let file = fm.clone();- let comments = $crate::wasm::SingleThreadedComments::default();- $crate::wasm::anyhow::Context::context(- c.process_js_with_custom_pass(- fm,- None,- handler,- &opts,- comments,- $before_pass,- $after_pass,- ), "failed to process js file"- )?- }- Err(v) => unsafe { c.process_js(handler, $crate::wasm::serde_wasm_bindgen::from_value(v).expect(""), &opts)? },- };-- out- .serialize($crate::wasm::compat_serializer().as_ref())- .map_err(|e| $crate::wasm::anyhow::anyhow!("failed to serialize transform result: {}", e))- })- },- )- .map_err(|e| $crate::wasm::convert_err(e, Some(error_format)))- }- };-}--/// Currently this relies on existence of transform_sync.-#[macro_export]-macro_rules! build_transform {- ($(#[$m:meta])*) => {- build_transform!($(#[$m])*, Default::default());- };- ($(#[$m:meta])*, $opt: expr) => {- $(#[$m])*- pub fn transform(- s: $crate::wasm::JsValue,- opts: $crate::wasm::JsValue,- experimental_plugin_bytes_resolver: $crate::wasm::JsValue,- ) -> $crate::wasm::js_sys::Promise {- // TODO: This'll be properly scheduled once wasm have standard backed thread- // support.- $crate::wasm::future_to_promise(async { transform_sync(s, opts, experimental_plugin_bytes_resolver) })- }- };-}
deps/swc/crates/dbg-swc/.gitignore
@@ -1,13 +0,0 @@-/*.output.js-/input.js-*.orig-input.new.js-input.orig.js--*.txt--/.input-/.compare--# creduce-creduce_bug*
deps/swc/crates/dbg-swc/Cargo.toml
@@ -1,43 +0,0 @@-[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>"]-description = "Debug utilities"-edition = { workspace = true }-license = { workspace = true }-name = "dbg-swc"-repository = { workspace = true }-version = "64.0.0"--[[bin]]-bench = false-name = "dbg-swc"--[dependencies]-anyhow = { workspace = true }-clap = { version = "3", features = ["derive"] }-dialoguer = { workspace = true }-flate2 = { workspace = true }-par-core = { workspace = true, features = ["chili"] }-par-iter = { workspace = true }-rayon = { workspace = true }-serde = { workspace = true }-serde_json = { workspace = true }-sha1 = { workspace = true }-swc_common = { version = "26.0.0", features = [- "concurrent",- "tty-emitter",-], path = "../swc_common" }-swc_ecma_ast = { version = "29.0.2", path = "../swc_ecma_ast" }-swc_ecma_codegen = { version = "32.0.3", path = "../swc_ecma_codegen" }-swc_ecma_minifier = { version = "63.0.1", path = "../swc_ecma_minifier", features = [- "concurrent",-] }-swc_ecma_parser = { version = "46.0.0", path = "../swc_ecma_parser", features = [- "flow",-] }-swc_ecma_transforms_base = { version = "50.0.0", path = "../swc_ecma_transforms_base" }-swc_ecma_transforms_typescript = { version = "56.0.0", path = "../swc_ecma_transforms_typescript" }-swc_ecma_visit = { version = "29.0.0", path = "../swc_ecma_visit" }-swc_error_reporters = { version = "28.0.0", path = "../swc_error_reporters" }-tempfile = { workspace = true }-tracing = { workspace = true }-tracing-subscriber = { workspace = true, features = ["fmt", "env-filter"] }
deps/swc/crates/dbg-swc/scripts/check-semantics.sh
@@ -1,5 +0,0 @@-#!/usr/bin/env bash-set -eu--# cargo run -- minify ensure-size --no-terser $1 > list.txt-cat list.txt | xargs -L 1 cargo run --release -- minify reduce --mode semantics
deps/swc/crates/dbg-swc/scripts/reduce-list.sh
@@ -1,4 +0,0 @@-#!/usr/bin/env bash-set -eu--cat list.txt | xargs -L 1 -I {} ./scripts/reduce-size.sh {}
deps/swc/crates/dbg-swc/scripts/reduce-semantics.sh
@@ -1,5 +0,0 @@-#!/usr/bin/env bash-set -eu--cargo run --release -- minify reduce --mode semantics --remove $1-# mv data/*.js ./.input/
deps/swc/crates/dbg-swc/scripts/reduce-size.sh
@@ -1,5 +0,0 @@-#!/usr/bin/env bash-set -eu--cargo run --release -- minify reduce --mode size --remove $1-# mv data/*.js ./.input/
deps/swc/crates/dbg-swc/src/bundle.rs
@@ -1,32 +0,0 @@-use std::{- process::{Command, Stdio},- sync::Arc,-};--use anyhow::{bail, Context, Result};-use swc_common::{FileName, SourceMap};--use crate::util::{parse_js, wrap_task, ModuleRecord};--pub fn bundle(cm: Arc<SourceMap>, entry_url: &str) -> Result<ModuleRecord> {- wrap_task(|| {- let mut cmd = Command::new("deno");- cmd.arg("bundle");- cmd.arg(entry_url);-- cmd.stderr(Stdio::inherit());-- let output = cmd.output().context("failed to invoke `deno bundle`")?;-- if !output.status.success() {- bail!("`deno bundle` failed with status code {}", output.status);- }-- let code =- String::from_utf8(output.stdout).context("deno bundle emitted non-utf8 output")?;-- let fm = cm.new_source_file(FileName::Anon.into(), code);- parse_js(fm).context("failed to parse js filed emitted by `deno bundle`")- })- .with_context(|| format!("failed to bundle `{entry_url}`"))-}
deps/swc/crates/dbg-swc/src/es/flow/mod.rs
@@ -1,24 +0,0 @@-use std::sync::Arc;--use anyhow::Result;-use clap::Subcommand;-use swc_common::SourceMap;--use self::strip::StripCommand;--mod strip;--/// Debug modules related to Flow.-#[derive(Debug, Subcommand)]-pub enum FlowCommand {- /// Verify that Flow syntax is stripped into valid JavaScript.- Strip(StripCommand),-}--impl FlowCommand {- pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {- match self {- Self::Strip(cmd) => cmd.run(cm),- }- }-}
deps/swc/crates/dbg-swc/src/es/flow/strip.rs
@@ -1,420 +0,0 @@-use std::{- fmt::{self, Display, Formatter},- path::{Path, PathBuf},- sync::Arc,-};--use anyhow::{bail, Context, Result};-use clap::Args;-use swc_common::{FileName, Mark, SourceMap};-use swc_ecma_ast::{EsVersion, Program};-use swc_ecma_codegen::{text_writer::JsWriter, Config as CodegenConfig, Emitter};-use swc_ecma_parser::{- error::Error as ParseError, parse_file_as_program, EsSyntax, FlowSyntax, Syntax,-};-use swc_ecma_transforms_base::{fixer::fixer, resolver};-use swc_ecma_transforms_typescript::typescript;--/// Verify that Flow syntax is stripped into valid JavaScript.-#[derive(Debug, Args)]-pub struct StripCommand {- /// The path to verify. It can be a file or directory.- ///- /// If this is a directory, this command recursively checks all `.js` and- /// `.jsx` files.- pub path: PathBuf,-- #[clap(long)]- pub jsx: bool,-- #[clap(long)]- pub all: bool,-- #[clap(long)]- pub require_directive: bool,-- #[clap(long)]- pub enums: bool,-- #[clap(long)]- pub decorators: bool,-- #[clap(long)]- pub components: bool,-- #[clap(long)]- pub pattern_matching: bool,-}--impl StripCommand {- pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {- let files = collect_flow_files(&self.path)?;- if files.is_empty() {- bail!(- "No `.js` or `.jsx` files found in `{}`",- self.path.display()- );- }-- let flow_syntax = self.flow_syntax();- let mut failures = Vec::new();-- for path in files.iter() {- if let Err(err) = verify_file(cm.clone(), path, flow_syntax) {- failures.push(err);- }- }-- let total = files.len();- let failed = failures.len();- let passed = total - failed;-- println!("Checked {total} files: {passed} passed, {failed} failed");-- if !failures.is_empty() {- println!("Failures:");- for failure in failures {- println!(- "{} [{}] {}",- failure.path.display(),- failure.stage,- failure.message- );- }-- bail!("flow strip verification failed");- }-- Ok(())- }-- fn flow_syntax(&self) -> FlowSyntax {- FlowSyntax {- jsx: self.jsx,- all: self.all,- require_directive: self.require_directive,- enums: self.enums,- decorators: self.decorators,- components: self.components,- pattern_matching: self.pattern_matching,- }- }-}--#[derive(Debug)]-struct FlowStripFailure {- path: PathBuf,- stage: FailureStage,- message: String,-}--impl FlowStripFailure {- fn new(path: &Path, stage: FailureStage, message: impl Into<String>) -> Self {- Self {- path: path.to_path_buf(),- stage,- message: normalize_message(message.into()),- }- }-}--#[derive(Debug, Clone, Copy)]-enum FailureStage {- Parse,- Strip,- Reparse,- Leak,-}--impl Display for FailureStage {- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {- match self {- Self::Parse => write!(f, "parse"),- Self::Strip => write!(f, "strip"),- Self::Reparse => write!(f, "reparse"),- Self::Leak => write!(f, "leak"),- }- }-}--fn verify_file(- cm: Arc<SourceMap>,- path: &Path,- flow_syntax: FlowSyntax,-) -> std::result::Result<(), FlowStripFailure> {- let fm = cm.load_file(path).map_err(|err| {- FlowStripFailure::new(- path,- FailureStage::Parse,- format!("failed to load file: {err:#}"),- )- })?;-- let mut parse_recovered_errors = Vec::new();- let parsed = parse_file_as_program(- &fm,- Syntax::Flow(flow_syntax),- EsVersion::latest(),- None,- &mut parse_recovered_errors,- )- .map_err(|err| {- FlowStripFailure::new(- path,- FailureStage::Parse,- parse_error_message(&err, &parse_recovered_errors),- )- })?;-- if !parse_recovered_errors.is_empty() {- return Err(FlowStripFailure::new(- path,- FailureStage::Parse,- recovered_parse_message(&parse_recovered_errors),- ));- }-- let unresolved_mark = Mark::new();- let top_level_mark = Mark::new();-- let transformed = parsed- .apply(resolver(unresolved_mark, top_level_mark, false))- .apply(typescript::typescript(- typescript::Config {- flow_syntax: true,- ..Default::default()- },- unresolved_mark,- top_level_mark,- ))- .apply(fixer(None));-- let output = emit_program(cm.clone(), &transformed)- .map_err(|err| FlowStripFailure::new(path, FailureStage::Strip, format!("{err:#}")))?;-- if output.contains("__flow_") {- return Err(FlowStripFailure::new(- path,- FailureStage::Leak,- "flow synthetic symbol leaked into output: `__flow_`",- ));- }-- let output_fm = cm.new_source_file(FileName::Anon.into(), output);- let mut reparse_recovered_errors = Vec::new();- parse_file_as_program(- &output_fm,- Syntax::Es(es_reparse_syntax(flow_syntax.jsx)),- EsVersion::latest(),- None,- &mut reparse_recovered_errors,- )- .map_err(|err| {- FlowStripFailure::new(- path,- FailureStage::Reparse,- parse_error_message(&err, &reparse_recovered_errors),- )- })?;-- if !reparse_recovered_errors.is_empty() {- return Err(FlowStripFailure::new(- path,- FailureStage::Reparse,- recovered_parse_message(&reparse_recovered_errors),- ));- }-- Ok(())-}--fn parse_error_message(primary: &ParseError, recovered: &[ParseError]) -> String {- let mut message = format!("{primary:?}");- if let Some(first_recovered) = recovered.first() {- message.push_str("; recovered: ");- message.push_str(&format!("{first_recovered:?}"));- if recovered.len() > 1 {- message.push_str(&format!(" (+{} more)", recovered.len() - 1));- }- }- message-}--fn recovered_parse_message(recovered: &[ParseError]) -> String {- let first = recovered- .first()- .map(|err| format!("{err:?}"))- .unwrap_or_else(|| "unknown parse error".to_string());-- if recovered.len() > 1 {- format!("{first} (+{} more)", recovered.len() - 1)- } else {- first- }-}--fn emit_program(cm: Arc<SourceMap>, program: &Program) -> Result<String> {- let mut buf = Vec::new();- {- let wr = JsWriter::new(cm.clone(), "\n", &mut buf, None);- let mut emitter = Emitter {- cfg: CodegenConfig::default(),- comments: None,- cm,- wr,- };- emitter- .emit_program(program)- .context("failed to emit transformed program")?;- }-- String::from_utf8(buf).context("swc emitted non-utf8 output")-}--fn collect_flow_files(path: &Path) -> Result<Vec<PathBuf>> {- if !path.exists() {- bail!("path does not exist: `{}`", path.display());- }-- let mut files = Vec::new();- let mut stack = vec![path.to_path_buf()];-- while let Some(current) = stack.pop() {- if current.is_dir() {- let entries = current- .read_dir()- .with_context(|| format!("failed to read directory `{}`", current.display()))?;-- for entry in entries {- let entry = entry.with_context(|| {- format!("failed to read an entry in `{}`", current.display())- })?;- stack.push(entry.path());- }- continue;- }-- if is_flow_input_file(¤t) {- files.push(current);- }- }-- files.sort();- Ok(files)-}--fn is_flow_input_file(path: &Path) -> bool {- path.extension()- .and_then(|ext| ext.to_str())- .is_some_and(|ext| ext == "js" || ext == "jsx")-}--fn es_reparse_syntax(jsx: bool) -> EsSyntax {- EsSyntax {- jsx,- decorators: true,- decorators_before_export: true,- export_default_from: true,- import_attributes: true,- allow_super_outside_method: true,- auto_accessors: true,- explicit_resource_management: true,- ..Default::default()- }-}--fn normalize_message(message: String) -> String {- message.split_whitespace().collect::<Vec<_>>().join(" ")-}--#[cfg(test)]-mod tests {- use std::{fs, sync::Arc};-- use anyhow::Result;- use swc_common::{Globals, SourceMap, GLOBALS};- use tempfile::TempDir;-- use super::{collect_flow_files, StripCommand};-- #[test]- fn flow_syntax_is_mapped_from_cli_flags() {- let cmd = StripCommand {- path: "input.js".into(),- jsx: true,- all: true,- require_directive: true,- enums: true,- decorators: true,- components: true,- pattern_matching: true,- };-- let syntax = cmd.flow_syntax();-- assert!(syntax.jsx);- assert!(syntax.all);- assert!(syntax.require_directive);- assert!(syntax.enums);- assert!(syntax.decorators);- assert!(syntax.components);- assert!(syntax.pattern_matching);- }-- #[test]- fn collect_flow_files_only_returns_js_and_jsx() -> Result<()> {- let tmp = TempDir::new()?;- let root = tmp.path();-- fs::create_dir_all(root.join("nested"))?;- fs::write(root.join("a.js"), "const a = 1;")?;- fs::write(root.join("nested").join("b.jsx"), "const b = <div />;")?;- fs::write(root.join("nested").join("ignored.ts"), "type T = string;")?;-- let files = collect_flow_files(root)?;- let rel_paths = files- .iter()- .map(|file| {- file.strip_prefix(root)- .expect("file should be inside temp dir")- .to_string_lossy()- .replace('\\', "/")- })- .collect::<Vec<_>>();-- assert_eq!(rel_paths, vec!["a.js", "nested/b.jsx"]);-- Ok(())- }-- #[test]- fn strip_command_validates_simple_flow_input() -> Result<()> {- let tmp = TempDir::new()?;- let input = tmp.path().join("input.js");-- fs::write(- &input,- r#"-type ID = string;-const value: ID = ("hello": any);-export const out: ID = value;-"#,- )?;-- let cmd = StripCommand {- path: input,- jsx: false,- all: false,- require_directive: false,- enums: false,- decorators: false,- components: false,- pattern_matching: false,- };-- let cm = Arc::new(SourceMap::default());- let globals = Globals::default();-- GLOBALS.set(&globals, || cmd.run(cm))- }-}
deps/swc/crates/dbg-swc/src/es/minifier/compare.rs
@@ -1,53 +0,0 @@-use std::{path::PathBuf, process::Command, sync::Arc};--use anyhow::{Context, Result};-use clap::Args;-use swc_common::SourceMap;--use crate::util::{- make_pretty,- minifier::{get_minified, get_terser_output},- print_js,-};--/// [Experimental] Opens vscode for diffing output of swc minifier and-/// terser/esbuild-#[derive(Debug, Args)]-pub struct CompareCommand {- pub path: PathBuf,-}--impl CompareCommand {- pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {- let record = get_minified(cm.clone(), &self.path, true, false)?;- let code = print_js(cm, &record.module, true).context("failed to convert ast to code")?;-- let terser_mangled = get_terser_output(&self.path, true, false)?;-- eprintln!("swc: {} bytes", code.len());- eprintln!(- "swc: {} bytes (newline stripped)",- code.replace("\\n", "_").len()- );- std::fs::write("swc.output.js", code.as_bytes())- .context("failed to write swc.output.js")?;-- make_pretty("swc.output.js".as_ref())?;-- std::fs::write("terser.output.js", terser_mangled.as_bytes())- .context("failed to write terser.output.js")?;-- eprintln!("terser: {} bytes", terser_mangled.len());- make_pretty("terser.output.js".as_ref())?;-- {- let mut c = Command::new("code");- c.arg("--diff");- c.arg("swc.output.js");- c.arg("terser.output.js");- c.output().context("failed to run vscode")?;- }-- Ok(())- }-}
deps/swc/crates/dbg-swc/src/es/minifier/compare_opts.rs
@@ -1,62 +0,0 @@-use std::{path::PathBuf, sync::Arc};--use anyhow::{Context, Result};-use clap::Args;-use swc_common::SourceMap;-use swc_ecma_minifier::option::{CompressOptions, MangleOptions};--use crate::util::{- all_js_files,- minifier::{get_minified, get_minified_with_opts},- print_js,-};--/// [Experimental] Internal command to check the size difference caused by-/// options.-#[derive(Debug, Args)]-pub struct CompareOptsCommand {- pub path: PathBuf,-}--impl CompareOptsCommand {- pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {- let files = all_js_files(&self.path)?;-- let mut default_sum = 0;- let mut new_sum = 0;-- for file in files {- let default_record = get_minified(cm.clone(), &file, true, true)?;- let default_code = print_js(cm.clone(), &default_record.module, true)- .context("failed to convert ast to code")?;-- eprintln!("default: {} bytes", default_code.len());- default_sum += default_code.len();-- let new_record = get_minified_with_opts(- cm.clone(),- &file,- Some(CompressOptions {- keep_classnames: true,- keep_fnames: true,- ..Default::default()- }),- Some(MangleOptions {- keep_class_names: true,- keep_fn_names: true,- ..Default::default()- }),- )?;- let new_code = print_js(cm.clone(), &new_record.module, true)- .context("failed to convert ast to code")?;-- eprintln!("new: {} bytes", new_code.len());- new_sum += new_code.len();- }-- eprintln!("default (total): {default_sum} bytes");- eprintln!("new (total): {new_sum} bytes");-- Ok(())- }-}
deps/swc/crates/dbg-swc/src/es/minifier/ensure_size.rs
@@ -1,239 +0,0 @@-use std::{- path::{Path, PathBuf},- sync::Arc,-};--use anyhow::{Context, Result};-use clap::Args;-use par_iter::prelude::*;-use swc_common::{- errors::{ColorConfig, Handler, HANDLER},- SourceFile, SourceMap, GLOBALS,-};-use tracing::info;--use crate::util::{- all_js_files, gzipped_size,- minifier::{get_esbuild_output, get_minified, get_terser_output},- print_js, wrap_task,-};--/// [Experimental] Ensure that we are performing better than other minification-/// tools.-#[derive(Debug, Args)]-pub struct EnsureSize {- #[clap(long)]- pub no_terser: bool,-- #[clap(long)]- pub no_esbuild: bool,-- /// This can be a directyory or a file.- ///- /// If this is a directory, all `.js` files in it will be verified.- pub path: PathBuf,-}--impl EnsureSize {- pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {- let all_files = all_js_files(&self.path)?;-- #[cfg(debug_assertions)]- info!("Using {} files", all_files.len());-- let mut results = GLOBALS.with(|globals| {- all_files- .par_iter()- .map(|js_file| GLOBALS.set(globals, || self.check_file(cm.clone(), js_file)))- .filter_map(|v| v.transpose())- .collect::<Result<Vec<_>>>()- })?;-- results.sort_by_key(|f| {- if let Some(terser) = &f.terser {- f.swc.mangled_size as isize - terser.mangled_size as isize- } else {- 0- }- });-- for f in &results {- if let Some(terser) = &f.terser {- if f.swc.mangled_size > terser.mangled_size- || f.swc.no_mangle_size > terser.no_mangle_size- || f.swc.gzipped_size > terser.gzipped_size- {- println!();- println!("{}", f.fm.name);- }- if f.swc.gzipped_size > terser.gzipped_size {- println!(" Gzipped");- println!(" swc: {} bytes", f.swc.gzipped_size);- println!(" terser: {} bytes", terser.gzipped_size);- }-- if f.swc.mangled_size > terser.mangled_size {- println!(" Mangled");- println!(" swc: {} bytes", f.swc.mangled_size);- println!(" terser: {} bytes", terser.mangled_size);- }-- if f.swc.no_mangle_size > terser.no_mangle_size {- println!(" No-mangle");- println!(" swc: {} bytes", f.swc.no_mangle_size);- println!(" terser: {} bytes", terser.no_mangle_size);- }- }- }- {- let swc_total = results.iter().map(|f| f.swc.mangled_size).sum::<usize>();- let terser_total = results- .iter()- .flat_map(|f| f.terser.map(|v| v.mangled_size))- .sum::<usize>();-- println!("Total");- println!(" swc: {swc_total} bytes");- println!(" terser: {terser_total} bytes");- println!(" Size ratio: {}", swc_total as f64 / terser_total as f64);-- let swc_smaller_file_count = results- .iter()- .filter(|f| {- if let Some(terser) = &f.terser {- f.swc.mangled_size <= terser.mangled_size- } else {- false- }- })- .count();- println!(- "swc produced smaller or equal output for {} files out of {} files, {:.2}%",- swc_smaller_file_count,- all_files.len(),- 100.0 * swc_smaller_file_count as f64 / results.len() as f64- );- }- {- let swc_total = results.iter().map(|f| f.swc.gzipped_size).sum::<usize>();- let terser_total = results- .iter()- .flat_map(|f| f.terser.map(|v| v.gzipped_size))- .sum::<usize>();-- println!("Total (gzipped)");- println!(" swc: {swc_total} bytes");- println!(" terser: {terser_total} bytes");- println!(" Size ratio: {}", swc_total as f64 / terser_total as f64);-- let swc_smaller_file_count = results- .iter()- .filter(|f| {- if let Some(terser) = &f.terser {- f.swc.gzipped_size <= terser.gzipped_size- } else {- false- }- })- .count();- println!(- "swc produced smaller or equal output for {} files out of {} files, {:.2}%",- swc_smaller_file_count,- all_files.len(),- 100.0 * swc_smaller_file_count as f64 / results.len() as f64- );- }-- Ok(())- }-- fn check_file(&self, cm: Arc<SourceMap>, js_file: &Path) -> Result<Option<FileSize>> {- wrap_task(|| {- #[cfg(debug_assertions)]- info!("Checking {}", js_file.display());-- let fm = cm.load_file(js_file).context("failed to load file")?;- let handler =- Handler::with_tty_emitter(ColorConfig::Never, true, false, Some(cm.clone()));- HANDLER.set(&handler, || {- let code_mangled = {- let minified_mangled = get_minified(cm.clone(), js_file, true, true)?;-- print_js(cm.clone(), &minified_mangled.module, true)- .context("failed to convert ast to code")?- };-- let swc_no_mangle = {- let minified_no_mangled = get_minified(cm.clone(), js_file, true, false)?;-- print_js(cm, &minified_no_mangled.module, true)- .context("failed to convert ast to code")?- };-- // eprintln!("The output size of swc minifier: {}", code_mangled.len());-- let mut file_size = FileSize {- fm,- swc: MinifierOutput {- mangled_size: code_mangled.len(),- no_mangle_size: swc_no_mangle.len(),- gzipped_size: gzipped_size(&code_mangled),- },- terser: Default::default(),- esbuild: Default::default(),- };-- if !self.no_terser {- let terser_mangled = get_terser_output(js_file, true, true)?;- let terser_no_mangle = get_terser_output(js_file, true, false)?;-- file_size.terser = Some(MinifierOutput {- mangled_size: terser_mangled.len(),- no_mangle_size: terser_no_mangle.len(),- gzipped_size: gzipped_size(&terser_mangled),- });- }-- if !self.no_esbuild {- let esbuild_mangled = get_esbuild_output(js_file, true)?;- let esbuild_no_mangle = get_esbuild_output(js_file, false)?;-- file_size.esbuild = Some(MinifierOutput {- mangled_size: esbuild_mangled.len(),- no_mangle_size: esbuild_no_mangle.len(),- gzipped_size: gzipped_size(&esbuild_mangled),- });- }-- if file_size.terser.is_none() && file_size.esbuild.is_none() {- return Ok(None);- }-- Ok(Some(file_size))- })- })- .with_context(|| format!("failed to check file: {}", js_file.display()))- }-}--#[allow(unused)]-#[derive(Debug)]-struct FileSize {- fm: Arc<SourceFile>,-- swc: MinifierOutput,-- terser: Option<MinifierOutput>,-- esbuild: Option<MinifierOutput>,-}--#[allow(unused)]-#[derive(Debug, Clone, Copy)]-struct MinifierOutput {- mangled_size: usize,- no_mangle_size: usize,-- /// Minify + mangle + gzip- gzipped_size: usize,-}
deps/swc/crates/dbg-swc/src/es/minifier/mod.rs
@@ -1,39 +0,0 @@-use std::sync::Arc;--use anyhow::Result;-use clap::Subcommand;-use swc_common::SourceMap;--use self::{- compare::CompareCommand, compare_opts::CompareOptsCommand, ensure_size::EnsureSize,- next::NextCommand, reduce::ReduceCommand,-};--mod compare;-mod compare_opts;-mod ensure_size;-mod next;-mod reduce;--/// Debug the ECMAScript Minifier.-#[derive(Debug, Subcommand)]-pub enum MinifierCommand {- #[clap(subcommand)]- Next(NextCommand),- Reduce(ReduceCommand),- Compare(CompareCommand),- CompareOpts(CompareOptsCommand),- EnsureSize(EnsureSize),-}--impl MinifierCommand {- pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {- match self {- MinifierCommand::Next(cmd) => cmd.run(cm),- MinifierCommand::Reduce(cmd) => cmd.run(cm),- MinifierCommand::EnsureSize(cmd) => cmd.run(cm),- MinifierCommand::Compare(cmd) => cmd.run(cm),- MinifierCommand::CompareOpts(cmd) => cmd.run(cm),- }- }-}
deps/swc/crates/dbg-swc/src/es/minifier/next/check_size.rs
@@ -1,291 +0,0 @@-use std::{- cmp::Reverse,- env::current_dir,- fs::{self, create_dir_all, read_dir, remove_dir_all},- path::{Path, PathBuf},- process::{Command, Stdio},- sync::Arc,-};--use anyhow::{bail, Context, Result};-use clap::Args;-use dialoguer::{console::Term, theme::ColorfulTheme, Select};-use rayon::{- prelude::{IntoParallelIterator, ParallelBridge, ParallelIterator},- str::ParallelString,-};-use serde::{de::DeserializeOwned, Deserialize};-use swc_common::{errors::HANDLER, SourceMap, GLOBALS};-use tracing::info;--use crate::util::{- gzipped_size, make_pretty,- minifier::{get_minified, get_terser_output},- print_js, wrap_task,-};--#[derive(Debug, Args)]-pub struct CheckSizeCommand {- /// The directory store inputs to the swc minifier.- #[clap(long, short = 'w', default_value = ".next/dbg-swc/minifier-check-size")]- workspace: PathBuf,-- /// Rerun `npm run build` even if `workspace` is not empty.- #[clap(long)]- ensure_fresh: bool,-- /// Show every file, even if the output of swc minifier was smaller.- #[clap(long)]- show_all: bool,-}--impl CheckSizeCommand {- pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {- let app_dir = current_dir().context("failed to get current directory")?;-- let files = self.store_minifier_inputs(&app_dir)?;-- #[cfg(debug_assertions)]- info!("Running minifier");-- let mut files = GLOBALS.with(|globals| {- HANDLER.with(|handler| {- files- .into_par_iter()- .map(|file| {- GLOBALS.set(globals, || {- HANDLER.set(handler, || self.minify_file(cm.clone(), &file))- })- })- .collect::<Result<Vec<_>>>()- })- })?;-- if !self.show_all {- #[cfg(debug_assertions)]- info!(- "Skiping files which are smaller than terser output, as `--show-all` is not \- specified"- );-- files.retain(|f| f.swc > f.terser);- }- files.sort_by_key(|f| Reverse(f.swc as i32 - f.terser as i32));-- for file in &files {- println!(- "{}: {} bytes (swc) vs {} bytes (terser)",- file.path- .strip_prefix(self.workspace.join("inputs"))- .unwrap()- .display(),- file.swc,- file.terser- );- }-- if !files.is_empty() {- println!("Select a file to open diff");- }-- let items = files- .iter()- .map(|f| {- format!(- "{}: Diff: {} bytes; {} bytes (swc) vs {} bytes (terser)",- f.path- .strip_prefix(self.workspace.join("inputs"))- .unwrap()- .display(),- f.swc as i32 - f.terser as i32,- f.swc,- f.terser,- )- })- .collect::<Vec<_>>();-- let selection = Select::with_theme(&ColorfulTheme::default())- .items(&items)- .default(0)- .interact_on_opt(&Term::stderr())?;-- if let Some(selection) = selection {- let swc_path = self.workspace.join("swc.output.js");- let terser_path = self.workspace.join("terser.output.js");-- let swc = get_minified(cm.clone(), &files[selection].path, true, false)?;-- std::fs::write(&swc_path, print_js(cm, &swc.module, true)?.as_bytes())- .context("failed to write swc.output.js")?;-- make_pretty(&swc_path)?;-- let terser = get_terser_output(&files[selection].path, true, false)?;-- std::fs::write(&terser_path, terser.as_bytes())- .context("failed to write terser.output.js")?;-- make_pretty(&terser_path)?;-- {- let mut c = Command::new("code");- c.arg("--diff");- c.arg(swc_path);- c.arg(terser_path);- c.output().context("failed to run vscode")?;- }- }-- Ok(())- }-- /// Invokes `npm run build` with appropriate environment variables, and- /// store the result in `self.workspace`.- fn store_minifier_inputs(&self, app_dir: &Path) -> Result<Vec<PathBuf>> {- wrap_task(|| {- if !self.ensure_fresh- && self.workspace.is_dir()- && read_dir(self.workspace.join("inputs"))- .context("failed to read workspace directory")?- .count()- != 0- {- #[cfg(debug_assertions)]- info!(- "Skipping `npm run build` because the cache exists and `--ensure-fresh` is \- not set"- );-- return get_all_files(&self.workspace.join("inputs"))- .context("failed to get files from cache");- }-- let files = self.build_app(app_dir)?;-- files- .into_par_iter()- .map(|file| {- let file_path = self.workspace.join("inputs").join(file.name);- create_dir_all(file_path.parent().unwrap())- .context("failed to create a directory")?;- fs::write(&file_path, file.source).context("failed to write file")?;-- Ok(file_path)- })- .collect::<Result<_>>()- })- .context("failed to extract inputs for the swc minifier")- }-- /// Invokes `npm run build` and extacts the inputs for the swc minifier.- fn build_app(&self, app_dir: &Path) -> Result<Vec<InputFile>> {- wrap_task(|| {- #[cfg(debug_assertions)]- info!("Running `npm run build`");-- // Remove cache- let _ = remove_dir_all(app_dir.join(".next"));-- let mut c = Command::new("npm");- c.current_dir(app_dir);- c.env("FORCE_COLOR", "3");- c.env("NEXT_DEBUG_MINIFY", "1");- c.arg("run").arg("build");-- c.stderr(Stdio::inherit());-- let output = c- .output()- .context("failed to get output of `npm run build`")?;-- if !output.status.success() {- bail!("`npm run build` failed");- }-- let output = String::from_utf8_lossy(&output.stdout);-- output- .par_lines()- .filter(|line| line.contains("{ name:"))- .map(|line| {- parse_loose_json::<InputFile>(line).context("failed to parse input file")- })- .collect::<Result<_>>()- })- .with_context(|| format!("failed to build app in `{}`", app_dir.display()))- }-- fn minify_file(&self, cm: Arc<SourceMap>, js_file: &Path) -> Result<CompareResult> {- wrap_task(|| {- let terser_full =- get_terser_output(js_file, true, true).context("failed to get terser output")?;-- let swc_full = get_minified(cm.clone(), js_file, true, true)?;- let swc_full = print_js(cm.clone(), &swc_full.module, true)?;-- Ok(CompareResult {- terser: gzipped_size(&terser_full),- swc: gzipped_size(&swc_full),- path: js_file.to_owned(),- })- })- .with_context(|| format!("failed to minify `{}`", js_file.display()))- }-}--struct CompareResult {- path: PathBuf,- swc: usize,- terser: usize,-}--#[derive(Deserialize)]-struct InputFile {- name: String,- source: String,-}--fn parse_loose_json<T>(s: &str) -> Result<T>-where- T: DeserializeOwned,-{- wrap_task(|| {- let mut c = Command::new("node");-- c.arg("-e");- c.arg(- r#"- function looseJsonParse(obj) {- return Function('"use strict";return (' + obj + ")")();- }- console.log(JSON.stringify(looseJsonParse(process.argv[1])));- "#,- );-- c.arg(s);-- c.stderr(Stdio::inherit());-- let json_str = c- .output()- .context("failed to parse json loosely using node")?- .stdout;-- serde_json::from_slice(&json_str).context("failed to parse json")- })- .with_context(|| format!("failed to parse loose json: {s}"))-}--fn get_all_files(path: &Path) -> Result<Vec<PathBuf>> {- if path.is_dir() {- let v = read_dir(path)- .with_context(|| format!("failed to read directory at `{}`", path.display()))?- .par_bridge()- .map(|entry| get_all_files(&entry?.path()).context("failed get recurse"))- .collect::<Result<Vec<_>>>()?;-- Ok(v.into_iter().flatten().collect())- } else {- Ok(vec![path.to_path_buf()])- }-}
deps/swc/crates/dbg-swc/src/es/minifier/next/mod.rs
@@ -1,23 +0,0 @@-use std::sync::Arc;--use anyhow::Result;-use clap::Subcommand;-use swc_common::SourceMap;--use self::check_size::CheckSizeCommand;--mod check_size;--/// [Experimental] Debug the minifier issue related to next.js application.-#[derive(Debug, Subcommand)]-pub enum NextCommand {- CheckSize(CheckSizeCommand),-}--impl NextCommand {- pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {- match self {- NextCommand::CheckSize(cmd) => cmd.run(cm),- }- }-}
deps/swc/crates/dbg-swc/src/es/minifier/reduce.rs
@@ -1,148 +0,0 @@-use std::{- env::current_exe,- fs::{self, create_dir_all, read_to_string},- path::{Path, PathBuf},- process::Command,- sync::Arc,-};--use anyhow::{Context, Result};-use clap::{ArgEnum, Args};-use par_iter::prelude::*;-use sha1::{Digest, Sha1};-use swc_common::{SourceMap, GLOBALS};-use tempfile::TempDir;--use crate::{- util::{all_js_files, parse_js, print_js, ChildGuard},- CREDUCE_INPUT_ENV_VAR, CREDUCE_MODE_ENV_VAR,-};--/// Reduce input files to minimal reproduction cases-///-/// This command requires `creduce` and `terser` in PATH.-///-/// For `creduce`, see https://embed.cs.utah.edu/creduce/ for more information.-/// If you are using homebrew, install it with `brew install creduce`.-///-/// For `terser`, this command uses `npx terser` to invoke `terser` for-/// comparison.-///-/// After reducing, the reduced file will be moved to `.swc-reduce` directory.-///-///-/// Note: This tool is not perfect, and it may reduce input file way too much,-/// or fail to reduce an input file.-#[derive(Debug, Args)]-pub struct ReduceCommand {- /// The path to the input file. You can specify a directory if you want to- /// reduce every '.js' file within a directory, in a recursive manner.- pub path: PathBuf,-- /// In 'size' mode, this command tries to find the minimal input file where- /// the size of the output file of swc minifier is larger than the one from- /// terser.- ///- /// In 'semantics' mode, this command tries to reduce the input file to a- /// minimal reproduction case which triggers the bug.- #[clap(long, arg_enum)]- pub mode: ReduceMode,-- /// If true, the input file will be removed after the reduction. This can be- /// used for pausing and resuming the process of reducing.- #[clap(long)]- pub remove: bool,-}--#[derive(Debug, Clone, Copy, ArgEnum)]-pub enum ReduceMode {- Size,- Semantics,-}--impl ReduceCommand {- pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {- let js_files = all_js_files(&self.path)?;-- GLOBALS.with(|globals| {- js_files- .into_par_iter()- .map(|path| GLOBALS.set(globals, || self.reduce_file(cm.clone(), &path)))- .collect::<Result<Vec<_>>>()- })?;-- Ok(())- }-- fn reduce_file(&self, cm: Arc<SourceMap>, src_path: &Path) -> Result<()> {- // Strip comments to workaround a bug of creduce-- let fm = cm.load_file(src_path).context("failed to prepare file")?;- let m = parse_js(fm)?;- let code = print_js(cm, &m.module, false)?;-- fs::write(src_path, code.as_bytes()).context("failed to strip comments")?;-- //- let dir = TempDir::new().context("failed to create a temp directory")?;-- let input = dir.path().join("input.js");-- fs::copy(src_path, &input).context("failed to copy")?;-- let mut c = Command::new("creduce");-- c.arg("--not-c");-- c.env(- CREDUCE_MODE_ENV_VAR,- match self.mode {- ReduceMode::Size => "SIZE",- ReduceMode::Semantics => "SEMANTICS",- },- );- c.env(CREDUCE_INPUT_ENV_VAR, &input);-- let exe = current_exe()?;- c.arg(&exe);- c.arg(&input);- let mut child = ChildGuard(c.spawn().context("failed to run creduce")?);- let status = child.0.wait().context("failed to wait for creduce")?;-- if status.success() {- move_to_data_dir(&input)?;- }-- if let Some(1) = status.code() {- if self.remove {- fs::remove_file(src_path).context("failed to remove")?;- }- } else {- dbg!(&status, status.code());- }-- Ok(())- }-}--fn move_to_data_dir(input_path: &Path) -> Result<PathBuf> {- let src = read_to_string(input_path).context("failed to read input file")?;-- // create a Sha1 object- let mut hasher = Sha1::new();-- // process input message- hasher.update(src.as_bytes());-- // acquire hash digest in the form of GenericArray,- // which in this case is equivalent to [u8; 20]- let result = hasher.finalize();- let hash_str = format!("{result:x}");-- create_dir_all(format!(".swc-reduce/{hash_str}")).context("failed to create `.data`")?;-- let to = PathBuf::from(format!(".swc-reduce/{hash_str}/input.js"));- fs::write(&to, src.as_bytes()).context("failed to write")?;-- Ok(to)-}
deps/swc/crates/dbg-swc/src/es/mod.rs
@@ -1,32 +0,0 @@-use std::sync::Arc;--use anyhow::Result;-use clap::Subcommand;-use swc_common::SourceMap;--use self::{exec_test::ExecForTestingCommand, flow::FlowCommand, minifier::MinifierCommand};--mod exec_test;-mod flow;-mod minifier;--/// Debug modules related to ECMAScript-#[derive(Debug, Subcommand)]-pub(crate) enum EsCommand {- #[clap(subcommand)]- Minifier(MinifierCommand),- #[clap(subcommand)]- ExecForTesting(ExecForTestingCommand),- #[clap(subcommand)]- Flow(FlowCommand),-}--impl EsCommand {- pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {- match self {- Self::Minifier(cmd) => cmd.run(cm),- Self::ExecForTesting(cmd) => cmd.run(cm),- Self::Flow(cmd) => cmd.run(cm),- }- }-}
deps/swc/crates/dbg-swc/src/main.rs
@@ -1,133 +0,0 @@-#[cfg(debug_assertions)]-use std::str::FromStr;-use std::{env, path::PathBuf, sync::Arc};--use anyhow::{bail, Error, Result};-use clap::{StructOpt, Subcommand};-use es::EsCommand;-use swc_common::{- errors::{ColorConfig, HANDLER},- Globals, SourceMap, GLOBALS,-};-use swc_error_reporters::handler::{try_with_handler, HandlerOpts};-#[cfg(debug_assertions)]-use tracing_subscriber::EnvFilter;--use self::util::print_js;-use crate::util::minifier::{get_minified, get_terser_output};--mod bundle;-mod es;-mod util;--const CREDUCE_INPUT_ENV_VAR: &str = "CREDUCE_INPUT";--const CREDUCE_MODE_ENV_VAR: &str = "CREDUCE_COMPARE";--#[derive(Debug, clap::Parser)]-struct AppArgs {- #[clap(subcommand)]- cmd: Cmd,-}--#[derive(Debug, Subcommand)]-enum Cmd {- #[clap(subcommand)]- Es(EsCommand),-}--fn init() -> Result<()> {- #[cfg(debug_assertions)]- {- let log_env = env::var("RUST_LOG").unwrap_or_else(|_| "info,swc_ecma_minifier=warn".into());-- let logger = tracing_subscriber::FmtSubscriber::builder()- .without_time()- .with_target(false)- .with_ansi(true)- .with_env_filter(EnvFilter::from_str(&log_env).unwrap())- .with_writer(std::io::stderr)- .pretty()- .finish();-- tracing::subscriber::set_global_default(logger)?;- }-- Ok(())-}--fn main() -> Result<(), Error> {- init()?;-- let cm = Arc::new(SourceMap::default());-- if let Ok(mode) = env::var(CREDUCE_MODE_ENV_VAR) {- return try_with_handler(- cm.clone(),- HandlerOpts {- color: ColorConfig::Always,- skip_filename: false,- },- |handler| {- GLOBALS.set(&Globals::default(), || {- HANDLER.set(handler, || {- //- let input = PathBuf::from(- env::var(CREDUCE_INPUT_ENV_VAR)- .expect("creduce is invoked without the name of input file"),- );-- if mode == "SIZE" {- let m = get_minified(cm.clone(), &input, true, true)?;-- let swc_output = print_js(cm.clone(), &m.module, true)?;-- let terser_output = get_terser_output(&input, true, true)?;- if swc_output.trim().len() > terser_output.trim().len() {- // It's interesting, as our output is larger than terser's.- return Ok(());- }-- bail!("We don't care about this file")- } else if mode == "SEMANTICS" {- let m = get_minified(cm.clone(), &input, true, false)?;-- let swc_output = print_js(cm.clone(), &m.module, true)?;-- let terser_output = get_terser_output(&input, true, false)?;-- if swc_output.trim() == terser_output.trim() {- bail!("We don't care about this file")- }-- // It's interesting, as our output may have a bug-- Ok(())- } else {- unreachable!("Unknown mode `{}`", mode)- }- })- })- },- )- .map_err(|e| e.to_pretty_error());- }-- let args = AppArgs::parse();-- try_with_handler(- cm.clone(),- HandlerOpts {- color: ColorConfig::Always,- skip_filename: false,- },- |handler| {- GLOBALS.set(&Globals::default(), || {- HANDLER.set(handler, || match args.cmd {- Cmd::Es(cmd) => cmd.run(cm.clone()),- })- })- },- )- .map_err(|e| e.to_pretty_error())-}
deps/swc/crates/dbg-swc/src/util/minifier.rs
@@ -1,156 +0,0 @@-use std::{- path::Path,- process::{Command, Stdio},- sync::Arc,-};--use anyhow::{bail, Context, Result};-use swc_common::{FileName, SourceMap};-use swc_ecma_ast::*;-use swc_ecma_minifier::option::{CompressOptions, MangleOptions, MinifyOptions};-use swc_ecma_transforms_base::fixer::fixer;-use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};--use super::{parse_js, print_js, wrap_task, ModuleRecord};--pub fn get_minified(- cm: Arc<SourceMap>,- file: &Path,- compress: bool,- mangle: bool,-) -> Result<ModuleRecord> {- get_minified_with_opts(- cm,- file,- if compress {- Some(Default::default())- } else {- None- },- if mangle {- Some(Default::default())- } else {- None- },- )-}--pub fn get_minified_with_opts(- cm: Arc<SourceMap>,- file: &Path,- compress: Option<CompressOptions>,- mangle: Option<MangleOptions>,-) -> Result<ModuleRecord> {- let fm = cm.load_file(file)?;-- let m = parse_js(fm)?;-- let mut module = {- swc_ecma_minifier::optimize(- m.module.into(),- cm,- Some(&m.comments),- None,- &MinifyOptions {- compress,- mangle,- ..Default::default()- },- &swc_ecma_minifier::option::ExtraOptions {- unresolved_mark: m.unresolved_mark,- top_level_mark: m.top_level_mark,- mangle_name_cache: None,- },- )- .expect_module()- };-- module.visit_mut_with(&mut Normalizer {});- module.visit_mut_with(&mut fixer(None));-- Ok(ModuleRecord { module, ..m })-}--pub fn get_terser_output(file: &Path, compress: bool, mangle: bool) -> Result<String> {- wrap_task(|| {- let mut cmd = Command::new("npx");- cmd.arg("terser");- cmd.stderr(Stdio::inherit());-- if compress {- cmd.arg("--compress");- }- if mangle {- cmd.arg("--mangle");- }- cmd.args(["--comments", "false"]);- cmd.arg("--");- cmd.arg(file);-- let output = cmd.output().context("failed to get output")?;-- if !output.status.success() {- bail!("failed to run terser");- }-- let output = String::from_utf8(output.stdout).context("terser emitted non-utf8 string")?;-- // Drop comments- let cm = Arc::new(SourceMap::default());- let fm = cm.new_source_file(FileName::Anon.into(), output);- let m = parse_js(fm)?;-- let code = print_js(cm, &m.module, true)?;-- Ok(code)- })- .with_context(|| format!("failed to get output of {} from terser", file.display()))-}--pub fn get_esbuild_output(file: &Path, mangle: bool) -> Result<String> {- wrap_task(|| {- let mut cmd = Command::new("esbuild");- cmd.stderr(Stdio::inherit());-- cmd.arg(file);-- if mangle {- cmd.arg("--minify");- } else {- cmd.arg("--minify-syntax").arg("--minify-whitespace");- }-- let output = cmd.output().context("failed to get output")?;-- if !output.status.success() {- bail!("failed to run esbuild");- }-- String::from_utf8(output.stdout).context("esbuild emitted non-utf8 string")- })- .with_context(|| format!("failed to get output of {} from esbuild", file.display()))-}--/// We target es5 while esbuild does not support it.-///-/// Due to the difference, reducer generates something useless-struct Normalizer {}--impl VisitMut for Normalizer {- noop_visit_mut_type!(fail);-- fn visit_mut_prop(&mut self, p: &mut Prop) {- p.visit_mut_children_with(self);-- // if let Prop::KeyValue(kv) = p {- // if let PropName::Ident(k) = &kv.key {- // match &*kv.value {- // Expr::Ident(value) if k.sym == value.sym => {- // *p = Prop::Shorthand(k.clone());- // }- // _ => {}- // }- // }- // }- }-}
deps/swc/crates/dbg-swc/src/util/mod.rs
@@ -1,139 +0,0 @@-use std::{- io::Write,- path::{Path, PathBuf},- process::{Child, Command, Stdio},- sync::Arc,-};--use anyhow::{bail, Context, Result};-use flate2::{write::ZlibEncoder, Compression};-use swc_common::{comments::SingleThreadedComments, errors::HANDLER, Mark, SourceFile, SourceMap};-use swc_ecma_ast::{EsVersion, Module};-use swc_ecma_codegen::text_writer::{omit_trailing_semi, JsWriter, WriteJs};-use swc_ecma_parser::{parse_file_as_module, Syntax};-use swc_ecma_transforms_base::resolver;-use swc_ecma_visit::VisitMutWith;--pub mod minifier;--/// Type annotation-pub fn wrap_task<T, F>(op: F) -> Result<T>-where- F: FnOnce() -> Result<T>,-{- op()-}--pub fn gzipped_size(code: &str) -> usize {- let mut e = ZlibEncoder::new(Vec::new(), Compression::new(9));- e.write_all(code.as_bytes()).unwrap();- let compressed_bytes = e.finish().unwrap();- compressed_bytes.len()-}--pub fn make_pretty(f: &Path) -> Result<()> {- let mut c = Command::new("npx");- c.stderr(Stdio::inherit());- c.arg("js-beautify").arg("--replace").arg(f);-- let output = c.output().context("failed to run prettier")?;-- if !output.status.success() {- bail!("prettier failed");- }-- Ok(())-}--pub fn parse_js(fm: Arc<SourceFile>) -> Result<ModuleRecord> {- let unresolved_mark = Mark::new();- let top_level_mark = Mark::new();-- let mut errors = Vec::new();- let comments = SingleThreadedComments::default();- let res = parse_file_as_module(- &fm,- Syntax::Es(Default::default()),- EsVersion::latest(),- Some(&comments),- &mut errors,- )- .map_err(|err| HANDLER.with(|handler| err.into_diagnostic(handler).emit()));-- for err in errors {- HANDLER.with(|handler| err.into_diagnostic(handler).emit());- }-- let mut m = match res {- Ok(v) => v,- Err(()) => bail!("failed to parse a js file as a module"),- };-- m.visit_mut_with(&mut resolver(unresolved_mark, top_level_mark, false));-- Ok(ModuleRecord {- module: m,- comments,- top_level_mark,- unresolved_mark,- })-}--pub fn print_js(cm: Arc<SourceMap>, m: &Module, minify: bool) -> Result<String> {- let mut buf = Vec::new();-- {- let mut wr = Box::new(JsWriter::new(cm.clone(), "\n", &mut buf, None)) as Box<dyn WriteJs>;- if minify {- wr = Box::new(omit_trailing_semi(wr));- }-- let mut e = swc_ecma_codegen::Emitter {- cfg: swc_ecma_codegen::Config::default().with_minify(true),- cm,- comments: None,- wr,- };-- e.emit_module(m).unwrap();- }-- String::from_utf8(buf).context("swc emitted non-utf8 output")-}--#[derive(Debug, Clone)]-pub struct ModuleRecord {- pub module: Module,- pub comments: SingleThreadedComments,- pub top_level_mark: Mark,- pub unresolved_mark: Mark,-}--pub fn all_js_files(path: &Path) -> Result<Vec<PathBuf>> {- wrap_task(|| {- if path.is_dir() {- let mut files = Vec::new();- for entry in path.read_dir().context("failed to read dir")? {- let entry = entry.context("read_dir returned an error")?;- let path = entry.path();- files.extend(all_js_files(&path)?);- }- Ok(files)- } else if path.extension() == Some("js".as_ref()) {- Ok(vec![path.to_path_buf()])- } else {- Ok(Vec::new())- }- })- .with_context(|| format!("failed to get list of `.js` files in {}", path.display()))-}--pub(crate) struct ChildGuard(pub Child);--impl Drop for ChildGuard {- fn drop(&mut self) {- if let Err(e) = self.0.kill() {- eprintln!("Could not kill child process: {e}")- }- }-}
deps/swc/crates/from_variant/Cargo.toml
@@ -1,20 +0,0 @@-[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>"]-description = "Automatically derive From impls for enums"-documentation = "https://rustdoc.swc.rs/from_variant/"-edition = { workspace = true }-license = { workspace = true }-name = "from_variant"-repository = { workspace = true }-version = "3.0.0"--[lib]-bench = false-proc-macro = true--[dependencies]--swc_macros_common = { version = "1.0.1", path = "../swc_macros_common" }-[dependencies.syn]-features = ["derive", "fold", "parsing", "printing"]-workspace = true
deps/swc/crates/from_variant/src/lib.rs
@@ -1,89 +0,0 @@-extern crate proc_macro;--use swc_macros_common::prelude::*;-use syn::*;--/// Derives [`From`] for all variants. This only supports an enum where every-/// variant has a single field.-#[proc_macro_derive(FromVariant, attributes(from_variant))]-pub fn derive_from_variant(input: proc_macro::TokenStream) -> proc_macro::TokenStream {- let input = parse::<DeriveInput>(input).expect("failed to parse input as DeriveInput");-- let item = derive(input)- .into_iter()- .fold(TokenStream::new(), |mut t, item| {- item.to_tokens(&mut t);- t- });-- print("derive(FromVariant)", item)-}--fn is_ignored(attrs: &[syn::Attribute]) -> bool {- attrs- .iter()- .filter(|attr| attr.path().is_ident("from_variant"))- .any(|attr| {- let mut is_unknown = false;- attr.parse_nested_meta(|meta| {- is_unknown |= meta.path.is_ident("ignore");- Ok(())- })- .unwrap();- is_unknown- })-}--fn derive(- DeriveInput {- generics,- data,- ident,- ..- }: DeriveInput,-) -> Vec<ItemImpl> {- let variants = match data {- Data::Enum(DataEnum { variants, .. }) => variants,- _ => panic!("#[derive(FromVariant)] only works for an enum."),- };-- let mut from_impls: Vec<ItemImpl> = Vec::new();-- for v in variants {- if is_ignored(&v.attrs) {- continue;- }-- let variant_name = v.ident;- match v.fields {- Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {- if unnamed.len() != 1 {- panic!(- "#[derive(FromVariant)] requires all variants to be tuple with exactly \- one field"- )- }- let field = unnamed.into_iter().next().unwrap();-- let variant_type = &field.ty;-- let from_impl: ItemImpl = parse_quote!(- impl From<#variant_type> for #ident {- fn from(v: #variant_type) -> Self {- #ident::#variant_name(v)- }- }- );-- let from_impl = from_impl.with_generics(generics.clone());-- from_impls.push(from_impl);- }- _ => panic!(- "#[derive(FromVariant)] requires all variants to be tuple with exactly one field"- ),- }- }-- from_impls-}
deps/swc/crates/hstr/.gitignore
@@ -1 +0,0 @@-/target
deps/swc/crates/hstr/Cargo.toml
@@ -1,43 +0,0 @@-[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>"]-description = "A string type which is optimized for hash operations."-edition = { workspace = true }-license = { workspace = true }-name = "hstr"-repository = { workspace = true }-version = "4.0.2"--[lib]-bench = false---[features]-atom_size_128 = []-atom_size_64 = []-serde = ["dep:serde"]--[dependencies]-hashbrown = { workspace = true }-new_debug_unreachable = { workspace = true }-once_cell = { workspace = true }-rustc-hash = { workspace = true }-serde = { workspace = true, optional = true }-triomphe = { workspace = true }---[dev-dependencies]-compact_str = { workspace = true }-criterion = { workspace = true }-kstring = { workspace = true }-num_cpus = { workspace = true }-par-iter = { workspace = true }-rand = { workspace = true }-serde_json = { workspace = true }-smol_str = { workspace = true }-string_cache = { workspace = true }--swc_malloc = { version = "1.2.5", path = "../swc_malloc" }--[[bench]]-harness = false-name = "libs"
deps/swc/crates/hstr/LICENSE
@@ -1,202 +0,0 @@-- Apache License- Version 2.0, January 2004- http://www.apache.org/licenses/-- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION-- 1. Definitions.-- "License" shall mean the terms and conditions for use, reproduction,- and distribution as defined by Sections 1 through 9 of this document.-- "Licensor" shall mean the copyright owner or entity authorized by- the copyright owner that is granting the License.-- "Legal Entity" shall mean the union of the acting entity and all- other entities that control, are controlled by, or are under common- control with that entity. For the purposes of this definition,- "control" means (i) the power, direct or indirect, to cause the- direction or management of such entity, whether by contract or- otherwise, or (ii) ownership of fifty percent (50%) or more of the- outstanding shares, or (iii) beneficial ownership of such entity.-- "You" (or "Your") shall mean an individual or Legal Entity- exercising permissions granted by this License.-- "Source" form shall mean the preferred form for making modifications,- including but not limited to software source code, documentation- source, and configuration files.-- "Object" form shall mean any form resulting from mechanical- transformation or translation of a Source form, including but- not limited to compiled object code, generated documentation,- and conversions to other media types.-- "Work" shall mean the work of authorship, whether in Source or- Object form, made available under the License, as indicated by a- copyright notice that is included in or attached to the work- (an example is provided in the Appendix below).-- "Derivative Works" shall mean any work, whether in Source or Object- form, that is based on (or derived from) the Work and for which the- editorial revisions, annotations, elaborations, or other modifications- represent, as a whole, an original work of authorship. For the purposes- of this License, Derivative Works shall not include works that remain- separable from, or merely link (or bind by name) to the interfaces of,- the Work and Derivative Works thereof.-- "Contribution" shall mean any work of authorship, including- the original version of the Work and any modifications or additions- to that Work or Derivative Works thereof, that is intentionally- submitted to Licensor for inclusion in the Work by the copyright owner- or by an individual or Legal Entity authorized to submit on behalf of- the copyright owner. For the purposes of this definition, "submitted"- means any form of electronic, verbal, or written communication sent- to the Licensor or its representatives, including but not limited to- communication on electronic mailing lists, source code control systems,- and issue tracking systems that are managed by, or on behalf of, the- Licensor for the purpose of discussing and improving the Work, but- excluding communication that is conspicuously marked or otherwise- designated in writing by the copyright owner as "Not a Contribution."-- "Contributor" shall mean Licensor and any individual or Legal Entity- on behalf of whom a Contribution has been received by Licensor and- subsequently incorporated within the Work.-- 2. Grant of Copyright License. Subject to the terms and conditions of- this License, each Contributor hereby grants to You a perpetual,- worldwide, non-exclusive, no-charge, royalty-free, irrevocable- copyright license to reproduce, prepare Derivative Works of,- publicly display, publicly perform, sublicense, and distribute the- Work and such Derivative Works in Source or Object form.-- 3. Grant of Patent License. Subject to the terms and conditions of- this License, each Contributor hereby grants to You a perpetual,- worldwide, non-exclusive, no-charge, royalty-free, irrevocable- (except as stated in this section) patent license to make, have made,- use, offer to sell, sell, import, and otherwise transfer the Work,- where such license applies only to those patent claims licensable- by such Contributor that are necessarily infringed by their- Contribution(s) alone or by combination of their Contribution(s)- with the Work to which such Contribution(s) was submitted. If You- institute patent litigation against any entity (including a- cross-claim or counterclaim in a lawsuit) alleging that the Work- or a Contribution incorporated within the Work constitutes direct- or contributory patent infringement, then any patent licenses- granted to You under this License for that Work shall terminate- as of the date such litigation is filed.-- 4. Redistribution. You may reproduce and distribute copies of the- Work or Derivative Works thereof in any medium, with or without- modifications, and in Source or Object form, provided that You- meet the following conditions:-- (a) You must give any other recipients of the Work or- Derivative Works a copy of this License; and-- (b) You must cause any modified files to carry prominent notices- stating that You changed the files; and-- (c) You must retain, in the Source form of any Derivative Works- that You distribute, all copyright, patent, trademark, and- attribution notices from the Source form of the Work,- excluding those notices that do not pertain to any part of- the Derivative Works; and-- (d) If the Work includes a "NOTICE" text file as part of its- distribution, then any Derivative Works that You distribute must- include a readable copy of the attribution notices contained- within such NOTICE file, excluding those notices that do not- pertain to any part of the Derivative Works, in at least one- of the following places: within a NOTICE text file distributed- as part of the Derivative Works; within the Source form or- documentation, if provided along with the Derivative Works; or,- within a display generated by the Derivative Works, if and- wherever such third-party notices normally appear. The contents- of the NOTICE file are for informational purposes only and- do not modify the License. You may add Your own attribution- notices within Derivative Works that You distribute, alongside- or as an addendum to the NOTICE text from the Work, provided- that such additional attribution notices cannot be construed- as modifying the License.-- You may add Your own copyright statement to Your modifications and- may provide additional or different license terms and conditions- for use, reproduction, or distribution of Your modifications, or- for any such Derivative Works as a whole, provided Your use,- reproduction, and distribution of the Work otherwise complies with- the conditions stated in this License.-- 5. Submission of Contributions. Unless You explicitly state otherwise,- any Contribution intentionally submitted for inclusion in the Work- by You to the Licensor shall be under the terms and conditions of- this License, without any additional terms or conditions.- Notwithstanding the above, nothing herein shall supersede or modify- the terms of any separate license agreement you may have executed- with Licensor regarding such Contributions.-- 6. Trademarks. This License does not grant permission to use the trade- names, trademarks, service marks, or product names of the Licensor,- except as required for reasonable and customary use in describing the- origin of the Work and reproducing the content of the NOTICE file.-- 7. Disclaimer of Warranty. Unless required by applicable law or- agreed to in writing, Licensor provides the Work (and each- Contributor provides its Contributions) on an "AS IS" BASIS,- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or- implied, including, without limitation, any warranties or conditions- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A- PARTICULAR PURPOSE. You are solely responsible for determining the- appropriateness of using or redistributing the Work and assume any- risks associated with Your exercise of permissions under this License.-- 8. Limitation of Liability. In no event and under no legal theory,- whether in tort (including negligence), contract, or otherwise,- unless required by applicable law (such as deliberate and grossly- negligent acts) or agreed to in writing, shall any Contributor be- liable to You for damages, including any direct, indirect, special,- incidental, or consequential damages of any character arising as a- result of this License or out of the use or inability to use the- Work (including but not limited to damages for loss of goodwill,- work stoppage, computer failure or malfunction, or any and all- other commercial damages or losses), even if such Contributor- has been advised of the possibility of such damages.-- 9. Accepting Warranty or Additional Liability. While redistributing- the Work or Derivative Works thereof, You may choose to offer,- and charge a fee for, acceptance of support, warranty, indemnity,- or other liability obligations and/or rights consistent with this- License. However, in accepting such obligations, You may act only- on Your own behalf and on Your sole responsibility, not on behalf- of any other Contributor, and only if You agree to indemnify,- defend, and hold each Contributor harmless for any liability- incurred by, or claims asserted against, such Contributor by reason- of your accepting any such warranty or additional liability.-- END OF TERMS AND CONDITIONS-- APPENDIX: How to apply the Apache License to your work.-- To apply the Apache License to your work, attach the following- boilerplate notice, with the fields enclosed by brackets "[]"- replaced with your own identifying information. (Don't include- the brackets!) The text should be enclosed in the appropriate- comment syntax for the file format. We also recommend that a- file or class name and description of purpose be included on the- same "printed page" as the copyright notice for easier- identification within third-party archives.-- Copyright [yyyy] [name of copyright owner]-- Licensed under the Apache License, Version 2.0 (the "License");- you may not use this file except in compliance with the License.- You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0-- Unless required by applicable law or agreed to in writing, software- distributed under the License is distributed on an "AS IS" BASIS,- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.- See the License for the specific language governing permissions and- limitations under the License.
deps/swc/crates/hstr/README.md
@@ -1,9 +0,0 @@-# hstr--A high-performance string interning library for Rust. This crate is intended for the compilers or build tools like a bundler, written in Rust.--See the [documentation](https://docs.rs/hstr) for more information.--## License--Apache 2.0
deps/swc/crates/hstr/benches/libs.rs
@@ -1,308 +0,0 @@-#![allow(clippy::redundant_closure_call)]--extern crate swc_malloc;--#[macro_use]-extern crate criterion;-use std::{hash::Hash, mem::forget};--use compact_str::CompactString;-use criterion::{black_box, BatchSize, BenchmarkId, Criterion};-use par_iter::prelude::*;-use rand::distributions::{Alphanumeric, DistString};-use rustc_hash::FxHashSet;--macro_rules! string_creation {- ($group:expr, $len:expr, $setup:expr) => {{- let group = &mut $group;-- for len in $len {- group.bench_with_input(BenchmarkId::new("hstr", len), &len, |b, _| {- let mut store = hstr::AtomStore::default();-- b.iter_batched(- $setup(len),- |text| {- black_box(store.atom(text));- },- BatchSize::SmallInput,- );- });-- group.bench_with_input(BenchmarkId::new("hstr_slow", len), &len, |b, _| {- b.iter_batched(- $setup(len),- |text| {- black_box(hstr::Atom::from(text));- },- BatchSize::SmallInput,- );- });-- group.bench_with_input(BenchmarkId::new("string_cache", len), &len, |b, _| {- let mut prevent_drop = vec![];- b.iter_batched(- $setup(len),- |text| {- let atom = black_box(string_cache::DefaultAtom::from(text));- prevent_drop.push(atom);- },- BatchSize::SmallInput,- );- });-- group.bench_with_input(BenchmarkId::new("compact_str", len), &len, |b, _| {- b.iter_batched(- $setup(len),- |text| {- black_box(CompactString::from(text));- },- BatchSize::SmallInput,- );- });-- group.bench_with_input(BenchmarkId::new("smol_str", len), &len, |b, _| {- b.iter_batched(- $setup(len),- |text| {- black_box(smol_str::SmolStr::new(text));- },- BatchSize::SmallInput,- );- });-- group.bench_with_input(BenchmarkId::new("kstring", len), &len, |b, _| {- b.iter_batched(- $setup(len),- |text| {- black_box(kstring::KString::from(text));- },- BatchSize::SmallInput,- );- });- }- }};-}--fn bench_basic_creation(c: &mut Criterion) {- let length = [4usize, 8, 16, 32, 64, 128, 256, 512, 1024, 2048];-- {- let mut group = c.benchmark_group("single-thread/create/cached");-- string_creation!(group, length, |len| {- let text = random_string(len);- move || text.clone()- });-- group.finish();- }-- {- let mut group = c.benchmark_group("single-thread/create/not-cached");-- string_creation!(group, length, |len| { move || random_string(len) });-- group.finish();- }-- {- let mut group = c.benchmark_group("single-thread/create/mixed");-- string_creation!(group, length, |len| {- let text = random_string(len);- let mut i = 0;- move || {- i += 1;-- if black_box(i) % 5 == 0 {- text.clone()- } else {- random_string(len)- }- }- });-- group.finish();- }-}--fn bench_hash_operation(c: &mut Criterion) {- fn random_hashset<S>(items: Vec<S>) -> FxHashSet<S>- where- S: Eq + Hash,- {- let mut set = FxHashSet::default();-- set.extend(items);-- set- }-- fn random_keys<S>(len: usize, convert: &mut dyn FnMut(String) -> S) -> Vec<S> {- (0..len).map(|_| random_string(1024)).map(convert).collect()- }-- fn prepare<S>(len: usize, convert: &mut dyn FnMut(String) -> S) -> (FxHashSet<S>, Vec<S>)- where- S: Eq + Hash + Clone,- {- let items = random_keys(len, convert);-- let set = random_hashset(items.clone());- let mut keys = random_keys(9 * len, &mut *convert);-- keys.extend(items);-- (set, keys)- }-- let mut group = c.benchmark_group("single-thread/HashSet");-- let length = [1000, 10000];-- {- for len in length {- group.bench_with_input(BenchmarkId::new("hstr", len), &len, |b, _| {- let mut for_fairness = vec![];- let mut store = hstr::AtomStore::default();- b.iter_batched(- || prepare(len, &mut |s| store.atom(s)),- |(map, keys)| {- for key in &keys {- black_box(map.contains(key));- }- for_fairness.extend(map);- for_fairness.extend(keys);- },- BatchSize::SmallInput,- );- });- group.bench_with_input(BenchmarkId::new("string_cache", len), &len, |b, _| {- let mut for_fairness = vec![];- b.iter_batched(- || prepare(len, &mut string_cache::DefaultAtom::from),- |(map, keys)| {- for key in &keys {- black_box(map.contains(key));- }- for_fairness.extend(map);- for_fairness.extend(keys);- },- BatchSize::SmallInput,- );- });- group.bench_with_input(BenchmarkId::new("compact_str", len), &len, |b, _| {- b.iter_batched(- || prepare(len, &mut CompactString::from),- |(map, keys)| {- for key in keys {- black_box(map.contains(&key));- }- },- BatchSize::SmallInput,- );- });- group.bench_with_input(BenchmarkId::new("smol_str", len), &len, |b, _| {- b.iter_batched(- || prepare(len, &mut smol_str::SmolStr::from),- |(map, keys)| {- for key in keys {- black_box(map.contains(&key));- }- },- BatchSize::SmallInput,- );- });- group.bench_with_input(BenchmarkId::new("kstring", len), &len, |b, _| {- b.iter_batched(- || prepare(len, &mut kstring::KString::from),- |(map, keys)| {- for key in keys {- black_box(map.contains(&key));- }- },- BatchSize::SmallInput,- );- });- }- };-- group.finish();-}--fn bench_parallel_creation(c: &mut Criterion) {- {- let mut group = c.benchmark_group("parallel/create");-- for len in [64, 256, 1024] {- group.bench_with_input(BenchmarkId::new("hstr", len), &len, |b, _| {- b.iter_batched(- || {- (0..num_cpus::get())- .map(|_| hstr::AtomStore::default())- .collect::<Vec<_>>()- },- |stores| {- stores- .into_par_iter()- .map(|mut store| {- let atoms = (0..len)- .map(|_| store.atom(random_string(65)))- .collect::<Vec<_>>();-- (store, atoms)- })- .collect::<Vec<_>>()- .into_iter()- .for_each(|(store, atoms)| {- black_box(atoms);- forget(store);- });- },- BatchSize::SmallInput,- );- });-- group.bench_with_input(BenchmarkId::new("string_cache", len), &len, |b, _| {- b.iter_batched(- || {},- |_| {- let mut main_store = FxHashSet::default();- (0..num_cpus::get())- .into_par_iter()- .map(|_| {- (0..len)- .map(|_| {- black_box(string_cache::DefaultAtom::from(random_string(- 65,- )))- })- .collect::<Vec<_>>()- })- .collect::<Vec<_>>()- .into_iter()- .for_each(|v| {- main_store.extend(black_box(v));- });- },- BatchSize::SmallInput,- );- });- }-- group.finish();- }-}--criterion_group!(- benches,- bench_basic_creation,- bench_parallel_creation,- bench_hash_operation-);-criterion_main!(benches);--fn random_string(len: usize) -> String {- Alphanumeric.sample_string(&mut rand::thread_rng(), len)-}
deps/swc/crates/hstr/examples/fast_api.rs
@@ -1 +0,0 @@-fn main() {}
deps/swc/crates/hstr/examples/global_api.rs
@@ -1 +0,0 @@-fn main() {}
deps/swc/crates/hstr/src/dynamic.rs
@@ -1,337 +0,0 @@-use std::{- borrow::Cow,- cell::RefCell,- ffi::c_void,- hash::{BuildHasherDefault, Hash, Hasher},- mem::ManuallyDrop,- num::NonZeroU8,- ops::Deref,- ptr::NonNull,-};--use rustc_hash::FxHasher;-use triomphe::ThinArc;--use crate::{- tagged_value::{TaggedValue, MAX_INLINE_LEN},- wtf8::Wtf8,- Atom, Wtf8Atom, INLINE_TAG, INLINE_TAG_INIT, LEN_OFFSET, TAG_MASK,-};--#[derive(PartialEq, Eq)]-pub(crate) struct Metadata {- pub hash: u64,-}--#[derive(Clone, PartialEq, Eq)]-pub(crate) struct Item(pub ThinArc<Metadata, u8>);--impl Deref for Item {- type Target = <ThinArc<Metadata, u8> as Deref>::Target;-- fn deref(&self) -> &Self::Target {- &self.0- }-}--impl Hash for Item {- fn hash<H: Hasher>(&self, state: &mut H) {- state.write_u64(self.0.header.header.hash);- }-}--pub(crate) unsafe fn deref_from(ptr: TaggedValue) -> ManuallyDrop<Item> {- let item = restore_arc(ptr);-- ManuallyDrop::new(item)-}--pub(crate) unsafe fn restore_arc(v: TaggedValue) -> Item {- let ptr = v.get_ptr();- Item(ThinArc::from_raw(ptr))-}--/// A store that stores [Atom]s. Can be merged with other [AtomStore]s for-/// better performance.-///-///-/// # Merging [AtomStore]-pub struct AtomStore {- pub(crate) data: hashbrown::HashMap<Item, (), BuildEntryHasher>,-}--impl Default for AtomStore {- fn default() -> Self {- Self {- data: hashbrown::HashMap::with_capacity_and_hasher(64, BuildEntryHasher::default()),- }- }-}--impl AtomStore {- #[inline(always)]- pub fn atom<'a>(&mut self, text: impl Into<Cow<'a, str>>) -> Atom {- atom_in(self, &text.into())- }-- #[inline(always)]- pub fn wtf8_atom<'a>(&mut self, text: impl Into<Cow<'a, Wtf8>>) -> Wtf8Atom {- wtf8_atom_in(self, text.into().as_bytes())- }-- fn gc(&mut self) {- self.data.retain(|item, _| {- let count = ThinArc::strong_count(&item.0);- debug_assert!(count > 0);- count > 1- });- }-}--thread_local! {- static GLOBAL_DATA: RefCell<AtomStore> = Default::default();-}--/// Cleans up atoms in the global store that are no longer referenced.-pub fn global_atom_store_gc() {- GLOBAL_DATA.with(|global| {- let mut store = global.borrow_mut();- store.gc();- });-}--pub(crate) fn global_wtf8_atom(text: &[u8]) -> Wtf8Atom {- GLOBAL_DATA.with(|global| {- let mut store = global.borrow_mut();-- wtf8_atom_in(&mut *store, text)- })-}--pub(crate) fn global_atom(text: &str) -> Atom {- GLOBAL_DATA.with(|global| {- let mut store = global.borrow_mut();-- atom_in(&mut *store, text)- })-}--fn wtf8_atom_in<S>(storage: S, text: &[u8]) -> Wtf8Atom-where- S: Storage,-{- let len = text.len();-- if len <= MAX_INLINE_LEN {- // INLINE_TAG ensures this is never zero- let tag = INLINE_TAG_INIT | ((len as u8) << LEN_OFFSET);- let mut unsafe_data = TaggedValue::new_tag(tag);- unsafe {- unsafe_data.data_mut()[..len].copy_from_slice(text);- }- return Wtf8Atom { unsafe_data };- }-- let hash = calc_hash(text);- let entry = storage.insert_entry(text, hash);- let entry = ThinArc::into_raw(entry.0) as *mut c_void;-- let ptr: NonNull<c_void> = unsafe {- // Safety: Arc::into_raw returns a non-null pointer- NonNull::new_unchecked(entry)- };- debug_assert!(0 == ptr.as_ptr() as u8 & TAG_MASK);- Wtf8Atom {- unsafe_data: TaggedValue::new_ptr(ptr),- }-}--/// This can create any kind of [Atom], although this lives in the `dynamic`-/// module.-fn atom_in<S>(storage: S, text: &str) -> Atom-where- S: Storage,-{- // SAFETY: `text` is valid UTF-8- unsafe { Atom::from_wtf8_unchecked(wtf8_atom_in(storage, text.as_bytes())) }-}--/// Attempts to construct an [Atom] but only if it can be constructed inline.-/// This is primarily useful in constant contexts.-pub(crate) const fn inline_atom(text: &str) -> Option<Atom> {- let len = text.len();- if len <= MAX_INLINE_LEN {- // INLINE_TAG ensures this is never zero- let tag = INLINE_TAG | ((len as u8) << LEN_OFFSET);- let mut unsafe_data = TaggedValue::new_tag(match NonZeroU8::new(tag) {- Some(tag) => tag,- None => unreachable!(),- });- // This odd pattern is needed because we cannot create slices from ranges or- // ranges at all in constant context. So we write our own copying loop.- unsafe {- let data = unsafe_data.data_mut();- let bytes = text.as_bytes();- let mut i = 0;- while i < len {- data[i] = bytes[i];- i += 1;- }- }- return Some(Atom { unsafe_data });- }- None-}--trait Storage {- fn insert_entry(self, text: &[u8], hash: u64) -> Item;-}--impl Storage for &'_ mut AtomStore {- fn insert_entry(self, text: &[u8], hash: u64) -> Item {- // If the text is too long, interning is not worth it.- if text.len() > 512 {- return Item(ThinArc::from_header_and_slice(Metadata { hash }, text));- }-- let (entry, _) = self- .data- .raw_entry_mut()- .from_hash(hash, |key| {- key.header.header.hash == hash && key.slice.eq(text)- })- .or_insert_with(move || {- (- Item(ThinArc::from_header_and_slice(Metadata { hash }, text)),- (),- )- });- entry.clone()- }-}--#[inline(always)]-fn calc_hash(text: &[u8]) -> u64 {- let mut hasher = FxHasher::default();- text.hash(&mut hasher);- hasher.finish()-}--type BuildEntryHasher = BuildHasherDefault<EntryHasher>;--/// A "no-op" hasher for [Entry] that returns [Entry::hash]. The design is-/// inspired by the `nohash-hasher` crate.-///-/// Assumption: [Arc]'s implementation of [Hash] is a simple pass-through.-#[derive(Default)]-pub(crate) struct EntryHasher {- hash: u64,- #[cfg(debug_assertions)]- write_called: bool,-}--impl Hasher for EntryHasher {- fn finish(&self) -> u64 {- #[cfg(debug_assertions)]- debug_assert!(- self.write_called,- "EntryHasher expects write_u64 to have been called",- );- self.hash- }-- fn write(&mut self, _bytes: &[u8]) {- panic!("EntryHasher expects to be called with write_u64");- }-- fn write_u64(&mut self, val: u64) {- #[cfg(debug_assertions)]- {- debug_assert!(- !self.write_called,- "EntryHasher expects write_u64 to be called only once",- );- self.write_called = true;- }-- self.hash = val;- }-}--#[cfg(test)]-mod tests {- use crate::{dynamic::GLOBAL_DATA, global_atom_store_gc, Atom};-- fn expect_size(expected: usize) {- // This is a helper function to count the number of bytes in the global store.- GLOBAL_DATA.with(|global| {- let store = global.borrow();- assert_eq!(store.data.len(), expected);- })- }-- #[test]- fn global_ref_count_dynamic_0() {- expect_size(0);-- // The strings should be long enough so that they are not inline even under- // feature `atom_size_128`- let atom1 = Atom::new("Hello, beautiful world!");-- expect_size(1);-- let atom2 = Atom::new("Hello, beautiful world!");-- expect_size(1);-- // 2 for the two atoms, 1 for the global store- assert_eq!(atom1.ref_count(), 3);- assert_eq!(atom2.ref_count(), 3);-- drop(atom1);-- expect_size(1);-- // 1 for the atom2, 1 for the global store- assert_eq!(atom2.ref_count(), 2);-- drop(atom2);-- expect_size(1);- global_atom_store_gc();- expect_size(0);- }-- #[test]- fn global_ref_count_dynamic_1() {- expect_size(0);-- {- expect_size(0);- let atom = Atom::new("Hello, beautiful world!");- assert_eq!(atom.ref_count(), 2);- expect_size(1);- }-- expect_size(1);- global_atom_store_gc();- expect_size(0);-- {- let atom = Atom::new("Hello, beautiful world!");- assert_eq!(atom.ref_count(), 2);- expect_size(1);- }- let atom = Atom::new("Hello, beautiful world!");- assert_eq!(atom.ref_count(), 2);-- expect_size(1);- global_atom_store_gc();- expect_size(1);-- drop(atom);- expect_size(1);- global_atom_store_gc();- expect_size(0);- }-}
deps/swc/crates/hstr/src/global_store.rs
@@ -1,70 +0,0 @@-use std::{- borrow::Cow,- mem::{forget, ManuallyDrop},-};--use crate::{- dynamic::{global_atom, global_wtf8_atom},- wtf8::{Wtf8, Wtf8Buf},- Atom, Wtf8Atom,-};--macro_rules! direct_from_impl {- ($T:ty) => {- impl From<$T> for Atom {- fn from(s: $T) -> Self {- global_atom(&s)- }- }- };-}--direct_from_impl!(&'_ str);-direct_from_impl!(Cow<'_, str>);-direct_from_impl!(String);--impl From<Box<str>> for crate::Atom {- fn from(s: Box<str>) -> Self {- global_atom(&s)- }-}--macro_rules! direct_from_impl_wtf8 {- ($T:ty) => {- impl From<$T> for Wtf8Atom {- fn from(s: $T) -> Self {- global_wtf8_atom(s.as_bytes())- }- }- };-}--direct_from_impl_wtf8!(&'_ str);-direct_from_impl_wtf8!(Cow<'_, str>);-direct_from_impl_wtf8!(String);-direct_from_impl_wtf8!(&'_ Wtf8);-direct_from_impl_wtf8!(Wtf8Buf);--impl From<&Atom> for crate::Wtf8Atom {- fn from(s: &Atom) -> Self {- forget(s.clone());- Wtf8Atom {- unsafe_data: s.unsafe_data,- }- }-}--impl From<Atom> for crate::Wtf8Atom {- fn from(s: Atom) -> Self {- let s = ManuallyDrop::new(s);- Wtf8Atom {- unsafe_data: s.unsafe_data,- }- }-}--impl From<Box<str>> for crate::Wtf8Atom {- fn from(s: Box<str>) -> Self {- global_wtf8_atom(s.as_bytes())- }-}
deps/swc/crates/hstr/src/lib.rs
@@ -1,468 +0,0 @@-#![cfg_attr(feature = "atom_size_128", feature(integer_atomics))]-//! See [Atom] for more information.--use core::str;-use std::{- borrow::Borrow,- fmt::{Debug, Display},- hash::Hash,- mem::{forget, transmute, ManuallyDrop},- num::NonZeroU8,- ops::Deref,- str::from_utf8_unchecked,-};--use debug_unreachable::debug_unreachable;-use once_cell::sync::Lazy;--pub use crate::dynamic::{global_atom_store_gc, AtomStore};-use crate::{- macros::{get_hash, impl_from_alias},- tagged_value::TaggedValue,-};--mod dynamic;-mod global_store;-mod macros;-mod tagged_value;-#[cfg(test)]-mod tests;-pub mod wtf8;-mod wtf8_atom;--pub use wtf8_atom::Wtf8Atom;--/// An immutable string which is cheap to clone, compare, hash, and has small-/// size.-///-/// # Usecase-///-/// This type is designed for the compilers or build tools like a bundler-/// written in Rust. String interning is much costly than simply allocating a-/// string, but in compilers, hashing and comparison of strings are very-/// frequent operations for some of strings, and the other strings are mostly-/// just passed around. According to DoD, we should optimize types-/// for operations that occur frequently, and this type is the result.-///-/// # Features-///-/// ## No mutex on creation and destruction.-///-/// This type also considers concurrent processing of AST nodes. Parsers-/// generates lots of [Atom]s, so the creation of [Atom] should never involve a-/// global mutex, because parsers are embarrassingly parallel. Also, the AST-/// nodes are typically dropped in parallel. So [Drop] implementation of [Atom]-/// should not involve a global mutex, too.-///-///-/// ## Small size (One `u64`)-///-/// The most of strings are simply passed around, so the size of [Atom] should-/// be small as possible.-///-/// ```rust-/// # use std::mem::size_of;-/// # if !cfg!(feature = "atom_size_128") {-/// use hstr::Atom;-/// assert!(size_of::<Atom>() == size_of::<u64>());-/// assert!(size_of::<Option<Atom>>() == size_of::<u64>());-/// # }-/// ````-///-///-/// ## Fast equality check (in most cases)-///-/// Equality comparison is O(1) in most cases. If two atoms are from the same-/// [AtomStore], or they are from different stores but they are-/// [`AtomStore::merge`]d, they are compared by numeric equality.-///-/// If two strings are created from different [AtomStore]s, they are compared-/// using `strcmp` by default. But `hstr` allows you to make `==` faster --/// [`AtomStore::merge`].-///-///-/// ## Fast [Hash] implementation-///-/// [Atom] precompute the hash value of long strings when they are created, so-/// it is `O(1)` to compute hash.-///-///-/// ## Small strings as inline data-///-/// Small strings are stored in the [Atom] itself without any allocation.-///-///-/// ## Creating atoms-///-/// If you are working on a module which creates lots of [Atom]s, you are-/// recommended to use [AtomStore] API because it's faster. But if you are not,-/// you can use global APIs for convenience.-///-/// ## Dealloc-///-/// - Atoms stored in the local `AtomStore` have the same lifetime as the store-/// itself, and will be deallocated when the store is dropped.-/// - Atoms created via the `atom!` macro or `String::into` are stored in the-/// global atom store. By default, these atoms are never deallocated. To clean-/// up unused atoms, call [global_atom_store_gc].-#[repr(transparent)]-pub struct Atom {- // If this Atom is a dynamic one, this is *const Entry- unsafe_data: TaggedValue,-}--#[doc(hidden)]-pub type CachedAtom = Lazy<Atom>;--#[doc(hidden)]-pub const fn inline_atom(s: &str) -> Option<Atom> {- dynamic::inline_atom(s)-}--/// Create an atom from a string literal. This atom is never dropped.-#[macro_export]-macro_rules! atom {- ($s:expr) => {{- const INLINE: ::core::option::Option<$crate::Atom> = $crate::inline_atom($s);- // This condition can be evaluated at compile time to enable inlining as a- // simple constant- if INLINE.is_some() {- INLINE.unwrap()- } else {- // Otherwise we use a- #[inline(never)]- fn get_atom() -> $crate::Atom {- static CACHE: $crate::CachedAtom =- $crate::CachedAtom::new(|| $crate::Atom::from($s));-- (*CACHE).clone()- }-- get_atom()- }- }};-}--impl Default for Atom {- #[inline(never)]- fn default() -> Self {- atom!("")- }-}--/// Immutable, so it's safe to be shared between threads-unsafe impl Send for Atom {}--/// Immutable, so it's safe to be shared between threads-unsafe impl Sync for Atom {}--impl Display for Atom {- #[inline]- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {- Display::fmt(self.as_str(), f)- }-}--impl Debug for Atom {- #[inline]- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {- Debug::fmt(self.as_str(), f)- }-}--#[cfg(feature = "serde")]-impl serde::ser::Serialize for Atom {- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>- where- S: serde::ser::Serializer,- {- serializer.serialize_str(self)- }-}--#[cfg(feature = "serde")]-impl<'de> serde::de::Deserialize<'de> for Atom {- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>- where- D: serde::Deserializer<'de>,- {- String::deserialize(deserializer).map(Self::new)- }-}-const DYNAMIC_TAG: u8 = 0b_00;-const INLINE_TAG: u8 = 0b_01; // len in upper nybble-const INLINE_TAG_INIT: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(INLINE_TAG) };-const TAG_MASK: u8 = 0b_11;-const LEN_OFFSET: usize = 4;-const LEN_MASK: u8 = 0xf0;--// const STATIC_SHIFT_BITS: usize = 32;--impl Atom {- #[inline(always)]- pub fn new<S>(s: S) -> Self- where- Self: From<S>,- {- Self::from(s)- }-- #[inline(always)]- fn tag(&self) -> u8 {- self.unsafe_data.tag() & TAG_MASK- }-- /// Return true if this is a dynamic Atom.- #[inline(always)]- fn is_dynamic(&self) -> bool {- self.tag() == DYNAMIC_TAG- }-}--impl Atom {- fn from_mutated_str<F: FnOnce(&mut str)>(s: &str, f: F) -> Self {- let mut buffer = [0u8; 64];-- if let Some(buffer_prefix) = buffer.get_mut(..s.len()) {- buffer_prefix.copy_from_slice(s.as_bytes());- // SAFETY: `buffer_prefix` was just initialized from `s`, which is- // valid UTF-8. `f` receives a `str`, so it must preserve UTF-8.- let as_str = unsafe { ::std::str::from_utf8_unchecked_mut(buffer_prefix) };- f(as_str);- Atom::from(&*as_str)- } else {- let mut string = s.to_owned();- f(&mut string);- Atom::from(string)- }- }-- /// Like [`to_ascii_uppercase`].- ///- /// [`to_ascii_uppercase`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.to_ascii_uppercase- pub fn to_ascii_uppercase(&self) -> Self {- for (i, b) in self.bytes().enumerate() {- if let b'a'..=b'z' = b {- return Atom::from_mutated_str(self, |s| s[i..].make_ascii_uppercase());- }- }- self.clone()- }-- /// Like [`to_ascii_lowercase`].- ///- /// [`to_ascii_lowercase`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.to_ascii_lowercase- pub fn to_ascii_lowercase(&self) -> Self {- for (i, b) in self.bytes().enumerate() {- if let b'A'..=b'Z' = b {- return Atom::from_mutated_str(self, |s| s[i..].make_ascii_lowercase());- }- }- self.clone()- }-}--impl Atom {- fn get_hash(&self) -> u64 {- get_hash!(self)- }-- fn as_str(&self) -> &str {- match self.tag() {- DYNAMIC_TAG => unsafe {- let item = crate::dynamic::deref_from(self.unsafe_data);- from_utf8_unchecked(transmute::<&[u8], &'static [u8]>(&item.slice))- },- INLINE_TAG => {- let len = (self.unsafe_data.tag() & LEN_MASK) >> LEN_OFFSET;- let src = self.unsafe_data.data();- unsafe { std::str::from_utf8_unchecked(&src[..(len as usize)]) }- }- _ => unsafe { debug_unreachable!() },- }- }-}--#[cfg(test)]-impl Atom {- pub(crate) fn ref_count(&self) -> usize {- match self.tag() {- DYNAMIC_TAG => {- let ptr = unsafe { crate::dynamic::deref_from(self.unsafe_data) };-- triomphe::ThinArc::strong_count(&ptr.0)- }- _ => 1,- }- }-}--impl PartialEq for Atom {- #[inline]- fn eq(&self, other: &Self) -> bool {- let unsafe_data = self.unsafe_data;- let other_unsafe_data = other.unsafe_data;-- if unsafe_data == other_unsafe_data {- return true;- }-- let tag = unsafe_data.tag() & TAG_MASK;-- if tag != (other_unsafe_data.tag() & TAG_MASK) {- return false;- }-- match tag {- // Inline atoms encode both their length and bytes in `unsafe_data`, so- // different raw values mean different strings.- INLINE_TAG => false,- DYNAMIC_TAG => {- let this = unsafe { crate::dynamic::deref_from(unsafe_data) };- let other = unsafe { crate::dynamic::deref_from(other_unsafe_data) };-- if this.header.header.hash != other.header.header.hash {- return false;- }-- this.slice == other.slice- }- _ => unsafe { debug_unreachable!() },- }- }-}--impl Eq for Atom {}--impl Hash for Atom {- #[inline(always)]- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {- state.write_u64(self.get_hash());- }-}--impl Drop for Atom {- #[inline(always)]- fn drop(&mut self) {- if self.is_dynamic() {- unsafe { drop(crate::dynamic::restore_arc(self.unsafe_data)) }- }- }-}--impl Clone for Atom {- #[inline(always)]- fn clone(&self) -> Self {- Self::from_alias(self.unsafe_data)- }-}--impl_from_alias!(Atom);--impl Deref for Atom {- type Target = str;-- #[inline(always)]- fn deref(&self) -> &Self::Target {- self.as_str()- }-}--impl AsRef<str> for Atom {- #[inline(always)]- fn as_ref(&self) -> &str {- self.as_str()- }-}--impl PartialEq<str> for Atom {- #[inline]- fn eq(&self, other: &str) -> bool {- self.as_str() == other- }-}--impl PartialEq<&'_ str> for Atom {- #[inline]- fn eq(&self, other: &&str) -> bool {- self.as_str() == *other- }-}--impl PartialEq<Atom> for str {- #[inline]- fn eq(&self, other: &Atom) -> bool {- self == other.as_str()- }-}--impl Borrow<Wtf8Atom> for Atom {- #[inline(always)]- fn borrow(&self) -> &Wtf8Atom {- // SAFETY:- // 1. Wtf8Atom is #[repr(transparent)] over TaggedValue- // 2. Atom is #[repr(transparent)] over TaggedValue- // 3. hstr::Atom and hstr::Wtf8Atom share the same TaggedValue- const _: () = assert!(std::mem::size_of::<Atom>() == std::mem::size_of::<Wtf8Atom>());- const _: () = assert!(std::mem::align_of::<Atom>() == std::mem::align_of::<Wtf8Atom>());- unsafe { transmute::<&Atom, &Wtf8Atom>(self) }- }-}--impl Atom {- /// Converts a WTF-8 encoded [Wtf8Atom] to a regular UTF-8 [Atom] without- /// validation.- ///- /// # Safety- ///- /// The caller must ensure that the WTF-8 atom contains only valid UTF-8- /// data (no unpaired surrogates). This function performs no validation- /// and will create an invalid `Atom` if the input contains unpaired- /// surrogates.- ///- /// This is a zero-cost conversion that preserves all internal optimizations- /// (inline storage, precomputed hashes, etc.) since both types have- /// identical internal representation.- pub unsafe fn from_wtf8_unchecked(s: Wtf8Atom) -> Self {- let s = ManuallyDrop::new(s);- Atom {- unsafe_data: s.unsafe_data,- }- }-}--#[cfg(test)]-mod macro_tests {-- use super::*;- #[test]- fn test_atom() {- // Test enough to exceed the small string optimization- assert_eq!(atom!(""), Atom::default());- assert_eq!(atom!(""), Atom::from(""));- assert_eq!(atom!("a"), Atom::from("a"));- assert_eq!(atom!("ab"), Atom::from("ab"));- assert_eq!(atom!("abc"), Atom::from("abc"));- assert_eq!(atom!("abcd"), Atom::from("abcd"));- assert_eq!(atom!("abcde"), Atom::from("abcde"));- assert_eq!(atom!("abcdef"), Atom::from("abcdef"));- assert_eq!(atom!("abcdefg"), Atom::from("abcdefg"));- assert_eq!(atom!("abcdefgh"), Atom::from("abcdefgh"));- assert_eq!(atom!("abcdefghi"), Atom::from("abcdefghi"));- }-- #[test]- fn test_inline_atom() {- // This is a silly test, just asserts that rustc can evaluate the pattern from- // our macro in a constant context.- const STR: Atom = {- let inline = inline_atom("hello");- if inline.is_some() {- inline.unwrap()- } else {- unreachable!();- }- };- assert_eq!(STR, Atom::from("hello"));- }-}
deps/swc/crates/hstr/src/macros.rs
@@ -1,41 +0,0 @@-macro_rules! get_hash {- ($self:expr) => {- match $self.tag() {- DYNAMIC_TAG => {- let unsafe_data = $self.unsafe_data;- unsafe { $crate::dynamic::deref_from(unsafe_data) }- .header- .header- .hash- }- INLINE_TAG => {- // This is passed as input to the caller's `Hasher` implementation, so it's okay- // that this isn't really a hash- $self.unsafe_data.hash()- }- _ => unsafe { debug_unreachable!() },- }- };-}--macro_rules! impl_from_alias {- ($ty:ty) => {- impl $ty {- #[inline]- pub(crate) fn from_alias(alias: TaggedValue) -> Self {- if alias.tag() & TAG_MASK == DYNAMIC_TAG {- unsafe {- let arc = $crate::dynamic::restore_arc(alias);- forget(arc.clone());- forget(arc);- }- }-- Self { unsafe_data: alias }- }- }- };-}--pub(crate) use get_hash;-pub(crate) use impl_from_alias;
deps/swc/crates/hstr/src/tagged_value.rs
@@ -1,147 +0,0 @@-#![allow(clippy::missing_transmute_annotations)]--use std::{num::NonZeroU8, os::raw::c_void, ptr::NonNull, slice};--#[cfg(feature = "atom_size_128")]-type RawTaggedValue = u128;-#[cfg(any(- target_pointer_width = "32",- target_pointer_width = "16",- feature = "atom_size_64"-))]-type RawTaggedValue = u64;-#[cfg(not(any(- target_pointer_width = "32",- target_pointer_width = "16",- feature = "atom_size_64",- feature = "atom_size_128"-)))]-type RawTaggedValue = usize;--#[cfg(feature = "atom_size_128")]-type RawTaggedNonZeroValue = std::num::NonZeroU128;-#[cfg(any(- target_pointer_width = "32",- target_pointer_width = "16",- feature = "atom_size_64"-))]-type RawTaggedNonZeroValue = std::num::NonZeroU64;-#[cfg(not(any(- target_pointer_width = "32",- target_pointer_width = "16",- feature = "atom_size_64",- feature = "atom_size_128"-)))]-type RawTaggedNonZeroValue = std::ptr::NonNull<()>;--pub(crate) const MAX_INLINE_LEN: usize = std::mem::size_of::<TaggedValue>() - 1;--#[derive(Copy, Clone, Debug, PartialEq, Eq)]-#[repr(transparent)]-pub(crate) struct TaggedValue {- value: RawTaggedNonZeroValue,-}--impl TaggedValue {- #[inline(always)]- pub fn new_ptr<T>(value: NonNull<T>) -> Self {- #[cfg(any(- target_pointer_width = "32",- target_pointer_width = "16",- feature = "atom_size_64",- feature = "atom_size_128"- ))]- unsafe {- let value: std::num::NonZeroUsize = std::mem::transmute(value);- Self {- value: RawTaggedNonZeroValue::new_unchecked(value.get() as _),- }- }-- #[cfg(not(any(- target_pointer_width = "32",- target_pointer_width = "16",- feature = "atom_size_64",- feature = "atom_size_128"- )))]- {- Self {- value: value.cast(),- }- }- }-- #[inline(always)]- pub const fn new_tag(value: NonZeroU8) -> Self {- let value = value.get() as RawTaggedValue;- Self {- value: unsafe { std::mem::transmute(value) },- }- }-- #[inline(always)]- pub fn hash(&self) -> u64 {- self.get_value() as _- }-- #[inline(always)]- pub fn get_ptr(&self) -> *const c_void {- #[cfg(any(- target_pointer_width = "32",- target_pointer_width = "16",- feature = "atom_size_64",- feature = "atom_size_128"- ))]- {- self.value.get() as usize as _- }- #[cfg(not(any(- target_pointer_width = "32",- target_pointer_width = "16",- feature = "atom_size_64",- feature = "atom_size_128"- )))]- unsafe {- std::mem::transmute(Some(self.value))- }- }-- #[inline(always)]- fn get_value(&self) -> RawTaggedValue {- unsafe { std::mem::transmute(Some(self.value)) }- }-- #[inline(always)]- pub fn tag(&self) -> u8 {- (self.get_value() & 0xff) as u8- }-- pub fn data(&self) -> &[u8] {- let x: *const _ = &self.value;- let mut data = x as *const u8;- // All except the lowest byte, which is first in little-endian, last in- // big-endian.- if cfg!(target_endian = "little") {- unsafe {- data = data.offset(1);- }- }- let len = std::mem::size_of::<TaggedValue>() - 1;- unsafe { slice::from_raw_parts(data, len) }- }-- /// The `TaggedValue` is a non-zero number or pointer, so caution must be- /// used when setting the untagged slice part of this value. If tag is- /// zero and the slice is zeroed out, using this `TaggedValue` will be- /// UB!- pub const unsafe fn data_mut(&mut self) -> &mut [u8] {- let x: *mut _ = &mut self.value;- let mut data = x as *mut u8;- // All except the lowest byte, which is first in little-endian, last in- // big-endian.- if cfg!(target_endian = "little") {- data = data.offset(1);- }- &mut *data.cast::<[u8; MAX_INLINE_LEN]>()- }-}
deps/swc/crates/hstr/src/wtf8/mod.rs
@@ -1,1500 +0,0 @@-// Copyright (c) 2014 Simon Sapin-// Licensed under the MIT License-// Original source: https://github.com/SimonSapin/rust-wtf8--/*!--Implementation of [the WTF-8 encoding](https://simonsapin.github.io/wtf-8/).--This library uses Rust’s type system to maintain-[well-formedness](https://simonsapin.github.io/wtf-8/#well-formed),-like the `String` and `&str` types do for UTF-8.--Since [WTF-8 must not be used-for interchange](https://simonsapin.github.io/wtf-8/#intended-audience),-this library deliberately does not provide access to the underlying bytes-of WTF-8 strings,-nor can it decode WTF-8 from arbitrary bytes.-WTF-8 strings can be obtained from UTF-8, UTF-16, or code points.--*/--extern crate alloc;--use alloc::{- borrow::{Borrow, Cow},- string::String,- vec::Vec,-};-use core::{- fmt, hash,- iter::{FromIterator, IntoIterator},- mem::transmute,- ops::Deref,- slice, str,- str::FromStr,-};-use std::ops::Add;--mod not_quite_std;--static UTF8_REPLACEMENT_CHARACTER: &[u8] = b"\xEF\xBF\xBD";--/// A Unicode code point: from U+0000 to U+10FFFF.-///-/// Compare with the `char` type,-/// which represents a Unicode scalar value:-/// a code point that is not a surrogate (U+D800 to U+DFFF).-#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)]-pub struct CodePoint {- value: u32,-}--impl Copy for CodePoint {}--/// Format the code point as `U+` followed by four to six hexadecimal digits.-/// Example: `U+1F4A9`-impl fmt::Debug for CodePoint {- #[inline]- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {- write!(formatter, "U+{:04X}", self.value)- }-}--impl CodePoint {- /// Unsafely create a new `CodePoint` without checking the value.- ///- /// # Safety- ///- /// Only use when `value` is known to be less than or equal to 0x10FFFF.- #[inline]- pub const unsafe fn from_u32_unchecked(value: u32) -> CodePoint {- CodePoint { value }- }-- /// Create a new `CodePoint` if the value is a valid code point.- ///- /// Return `None` if `value` is above 0x10FFFF.- #[inline]- pub const fn from_u32(value: u32) -> Option<CodePoint> {- match value {- 0..=0x10ffff => Some(CodePoint { value }),- _ => None,- }- }-- /// Create a new `CodePoint` from a `char`.- ///- /// Since all Unicode scalar values are code points, this always succeds.- #[inline]- pub const fn from_char(value: char) -> CodePoint {- CodePoint {- value: value as u32,- }- }-- /// Return the numeric value of the code point.- #[inline]- pub fn to_u32(&self) -> u32 {- self.value- }-- /// Optionally return a Unicode scalar value for the code point.- ///- /// Return `None` if the code point is a surrogate (from U+D800 to U+DFFF).- #[inline]- pub fn to_char(&self) -> Option<char> {- match self.value {- 0xd800..=0xdfff => None,- _ => Some(unsafe { char::from_u32_unchecked(self.value) }),- }- }-- /// Return a Unicode scalar value for the code point.- ///- /// Return `'\u{FFFD}'` (the replacement character “�”)- /// if the code point is a surrogate (from U+D800 to U+DFFF).- #[inline]- pub fn to_char_lossy(&self) -> char {- self.to_char().unwrap_or('\u{FFFD}')- }-- /// Return `true` if the code point is in the ASCII range.- #[inline]- pub fn is_ascii(&self) -> bool {- self.value <= 0x7f- }-}--impl PartialEq<char> for CodePoint {- fn eq(&self, other: &char) -> bool {- self.value == *other as u32- }-}--/// An owned, growable string of well-formed WTF-8 data.-///-/// Similar to `String`, but can additionally contain surrogate code points-/// if they’re not in a surrogate pair.-#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)]-pub struct Wtf8Buf {- bytes: Vec<u8>,-}--impl Deref for Wtf8Buf {- type Target = Wtf8;-- fn deref(&self) -> &Wtf8 {- unsafe { transmute(&*self.bytes) }- }-}--/// Format the string with double quotes,-/// and surrogates as `\u` followed by four hexadecimal digits.-/// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800]-impl fmt::Debug for Wtf8Buf {- #[inline]- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {- Wtf8::fmt(self, formatter)- }-}--impl Default for Wtf8Buf {- #[inline]- fn default() -> Self {- Self::new()- }-}--impl FromStr for Wtf8Buf {- type Err = core::convert::Infallible;-- #[inline]- fn from_str(s: &str) -> Result<Self, Self::Err> {- Ok(Wtf8Buf {- bytes: s.as_bytes().to_vec(),- })- }-}--impl fmt::Write for Wtf8Buf {- fn write_str(&mut self, s: &str) -> std::fmt::Result {- self.push_str(s);- Ok(())- }-}--impl Add<&Wtf8> for Wtf8Buf {- type Output = Wtf8Buf;-- fn add(self, rhs: &Wtf8) -> Self::Output {- let mut result = self;- result.push_wtf8(rhs);- result- }-}--impl Wtf8Buf {- /// Create an new, empty WTF-8 string.- #[inline]- pub fn new() -> Wtf8Buf {- Wtf8Buf { bytes: Vec::new() }- }-- /// Create an new, empty WTF-8 string with pre-allocated capacity for `n`- /// bytes.- #[inline]- pub fn with_capacity(n: usize) -> Wtf8Buf {- Wtf8Buf {- bytes: Vec::with_capacity(n),- }- }-- /// Create a WTF-8 string from an UTF-8 `String`.- ///- /// This takes ownership of the `String` and does not copy.- ///- /// Since WTF-8 is a superset of UTF-8, this always succeeds.- #[inline]- pub fn from_string(string: String) -> Wtf8Buf {- Wtf8Buf {- bytes: string.into_bytes(),- }- }-- /// Create a WTF-8 string from an UTF-8 `&str` slice.- ///- /// This copies the content of the slice.- ///- /// Since WTF-8 is a superset of UTF-8, this always succeeds.- #[inline]- #[allow(clippy::should_implement_trait)]- pub fn from_str(s: &str) -> Wtf8Buf {- Wtf8Buf {- bytes: s.as_bytes().to_vec(),- }- }-- /// Create a WTF-8 string from a potentially ill-formed UTF-16 slice of- /// 16-bit code units.- ///- /// This is lossless: calling `.to_ill_formed_utf16()` on the resulting- /// string will always return the original code units.- pub fn from_ill_formed_utf16(v: &[u16]) -> Wtf8Buf {- let mut string = Wtf8Buf::with_capacity(v.len());- for item in not_quite_std::decode_utf16(v.iter().cloned()) {- match item {- Ok(c) => string.push_char(c),- Err(s) => {- // Surrogates are known to be in the code point range.- let code_point = unsafe { CodePoint::from_u32_unchecked(s as u32) };- // Skip the WTF-8 concatenation check,- // surrogate pairs are already decoded by utf16_items- not_quite_std::push_code_point(&mut string, code_point)- }- }- }- string- }-- /// Reserves capacity for at least `additional` more bytes to be inserted- /// in the given `Wtf8Buf`.- /// The collection may reserve more space to avoid frequent reallocations.- ///- /// # Panics- ///- /// Panics if the new capacity overflows `usize`.- #[inline]- pub fn reserve(&mut self, additional: usize) {- self.bytes.reserve(additional)- }-- /// Returns the number of bytes that this string buffer can hold without- /// reallocating.- #[inline]- pub fn capacity(&self) -> usize {- self.bytes.capacity()- }-- /// Append an UTF-8 slice at the end of the string.- #[inline]- pub fn push_str(&mut self, other: &str) {- self.bytes.extend_from_slice(other.as_bytes())- }-- /// Append a WTF-8 slice at the end of the string.- ///- /// This replaces newly paired surrogates at the boundary- /// with a supplementary code point,- /// like concatenating ill-formed UTF-16 strings effectively would.- #[inline]- pub fn push_wtf8(&mut self, other: &Wtf8) {- match (self.final_lead_surrogate(), other.initial_trail_surrogate()) {- // Replace newly paired surrogates by a supplementary code point.- (Some(lead), Some(trail)) => {- let len_without_lead_surrogate = self.len() - 3;- self.bytes.truncate(len_without_lead_surrogate);- let other_without_trail_surrogate = &other.bytes[3..];- // 4 bytes for the supplementary code point- self.bytes.reserve(4 + other_without_trail_surrogate.len());- self.push_char(decode_surrogate_pair(lead, trail));- self.bytes.extend_from_slice(other_without_trail_surrogate);- }- _ => self.bytes.extend_from_slice(&other.bytes),- }- }-- /// Append a Unicode scalar value at the end of the string.- #[inline]- pub fn push_char(&mut self, c: char) {- not_quite_std::push_code_point(self, CodePoint::from_char(c))- }-- /// Append a code point at the end of the string.- ///- /// This replaces newly paired surrogates at the boundary- /// with a supplementary code point,- /// like concatenating ill-formed UTF-16 strings effectively would.- #[inline]- pub fn push(&mut self, code_point: CodePoint) {- if let trail @ 0xdc00..=0xdfff = code_point.to_u32() {- if let Some(lead) = self.final_lead_surrogate() {- let len_without_lead_surrogate = self.len() - 3;- self.bytes.truncate(len_without_lead_surrogate);- self.push_char(decode_surrogate_pair(lead, trail as u16));- return;- }- }-- // No newly paired surrogates at the boundary.- not_quite_std::push_code_point(self, code_point)- }-- /// Shortens a string to the specified length.- ///- /// # Failure- ///- /// Fails if `new_len` > current length,- /// or if `new_len` is not a code point boundary.- #[inline]- pub fn truncate(&mut self, new_len: usize) {- assert!(not_quite_std::is_code_point_boundary(self, new_len));- self.bytes.truncate(new_len)- }-- /// Clear the WTF-8 vector, removing all contents.- #[inline]- pub fn clear(&mut self) {- self.bytes.clear();- }-- /// Consume the WTF-8 string and try to convert it to UTF-8.- ///- /// This does not copy the data.- ///- /// If the contents are not well-formed UTF-8- /// (that is, if the string contains surrogates),- /// the original WTF-8 string is returned instead.- pub fn into_string(self) -> Result<String, Wtf8Buf> {- match self.next_surrogate(0) {- None => Ok(unsafe { String::from_utf8_unchecked(self.bytes) }),- Some(_) => Err(self),- }- }-- /// Consume the WTF-8 string and convert it lossily to UTF-8.- ///- /// This does not copy the data (but may overwrite parts of it in place).- ///- /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character- /// “�”)- pub fn into_string_lossy(mut self) -> String {- let mut pos = 0;- loop {- match self.next_surrogate(pos) {- Some((surrogate_pos, _)) => {- pos = surrogate_pos + 3;- self.bytes[surrogate_pos..pos].copy_from_slice(UTF8_REPLACEMENT_CHARACTER);- }- None => return unsafe { String::from_utf8_unchecked(self.bytes) },- }- }- }-- /// Create a [Wtf8Buf] from a WTF-8 encoded byte vector.- ///- /// Returns `Ok(Wtf8Buf)` if the bytes are well-formed WTF-8, or- /// `Err(bytes)` with the original bytes if validation fails.- ///- /// This validates that:- /// - All bytes form valid UTF-8 sequences OR valid surrogate code point- /// encodings- /// - Surrogate code points may appear unpaired and be encoded separately,- /// but if they are paired, they must be encoded as a single 4-byte UTF-8- /// sequence. For example, the byte sequence `[0xED, 0xA0, 0x80, 0xED,- /// 0xB0, 0x80]` is not valid WTF-8 because WTF-8 forbids encoding a- /// surrogate pair as two separate 3-byte sequences.- pub fn from_bytes(bytes: Vec<u8>) -> Result<Self, Vec<u8>> {- if not_quite_std::validate_wtf8(&bytes) {- Ok(Self { bytes })- } else {- Err(bytes)- }- }-- /// Create a [Wtf8Buf] from a WTF-8 encoded byte vector without checking- /// that the bytes contain valid WTF-8.- ///- /// For the safe version, see [Wtf8Buf::from_bytes].- ///- /// # Safety- ///- /// The bytes passed in must be valid WTF-8. See [Wtf8Buf::from_bytes] for- /// the requirements.- #[inline]- pub unsafe fn from_bytes_unchecked(bytes: Vec<u8>) -> Self {- Self { bytes }- }-}--/// Create a new WTF-8 string from an iterator of code points.-///-/// This replaces surrogate code point pairs with supplementary code points,-/// like concatenating ill-formed UTF-16 strings effectively would.-impl FromIterator<CodePoint> for Wtf8Buf {- fn from_iter<T: IntoIterator<Item = CodePoint>>(iterable: T) -> Wtf8Buf {- let mut string = Wtf8Buf::new();- string.extend(iterable);- string- }-}--/// Append code points from an iterator to the string.-///-/// This replaces surrogate code point pairs with supplementary code points,-/// like concatenating ill-formed UTF-16 strings effectively would.-impl Extend<CodePoint> for Wtf8Buf {- fn extend<T: IntoIterator<Item = CodePoint>>(&mut self, iterable: T) {- let iterator = iterable.into_iter();- let (low, _high) = iterator.size_hint();- // Lower bound of one byte per code point (ASCII only)- self.bytes.reserve(low);- for code_point in iterator {- self.push(code_point);- }- }-}--/// A borrowed slice of well-formed WTF-8 data.-///-/// Similar to `&str`, but can additionally contain surrogate code points-/// if they're not in a surrogate pair.-#[repr(transparent)]-#[derive(PartialEq, Eq, PartialOrd, Ord)]-pub struct Wtf8 {- bytes: [u8],-}--/// Format the slice with double quotes,-/// and surrogates as `\u` followed by four hexadecimal digits.-/// Example: `"a\u{D800}"` for a slice with code points [U+0061, U+D800]-impl fmt::Debug for Wtf8 {- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {- formatter.write_str("\"")?;- let mut pos = 0;- loop {- match self.next_surrogate(pos) {- None => break,- Some((surrogate_pos, surrogate)) => {- formatter.write_str(unsafe {- str::from_utf8_unchecked(&self.bytes[pos..surrogate_pos])- })?;- write!(formatter, "\\u{{{surrogate:X}}}")?;- pos = surrogate_pos + 3;- }- }- }- formatter.write_str(unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) })?;- formatter.write_str("\"")- }-}--impl Wtf8 {- /// Create a WTF-8 slice from a UTF-8 `&str` slice.- ///- /// Since WTF-8 is a superset of UTF-8, this always succeeds.- #[inline]- pub const fn from_str(value: &str) -> &Wtf8 {- unsafe { transmute(value.as_bytes()) }- }-- /// Return the length, in WTF-8 bytes.- #[inline]- pub const fn len(&self) -> usize {- self.bytes.len()- }-- /// Return `true` if the string has a length of zero bytes.- #[inline]- pub const fn is_empty(&self) -> bool {- self.bytes.is_empty()- }-- /// Return `true` if the string contains only ASCII characters.- #[inline]- pub const fn is_ascii(&self) -> bool {- let mut i = 0;-- while i < self.bytes.len() {- if !self.bytes[i].is_ascii() {- return false;- }-- i += 1;- }-- true- }-- /// Return a slice of the given string for the byte range [`begin`..`end`).- ///- /// # Failure- ///- /// Fails when `begin` and `end` do not point to code point boundaries,- /// or point beyond the end of the string.- #[inline]- pub fn slice(&self, begin: usize, end: usize) -> &Wtf8 {- // is_code_point_boundary checks that the index is in [0, .len()]- if begin <= end- && not_quite_std::is_code_point_boundary(self, begin)- && not_quite_std::is_code_point_boundary(self, end)- {- unsafe { not_quite_std::slice_unchecked(self, begin, end) }- } else {- not_quite_std::slice_error_fail(self, begin, end)- }- }-- /// Return a slice of the given string from byte `begin` to its end.- ///- /// # Failure- ///- /// Fails when `begin` is not at a code point boundary,- /// or is beyond the end of the string.- #[inline]- pub fn slice_from(&self, begin: usize) -> &Wtf8 {- // is_code_point_boundary checks that the index is in [0, .len()]- if not_quite_std::is_code_point_boundary(self, begin) {- unsafe { not_quite_std::slice_unchecked(self, begin, self.len()) }- } else {- not_quite_std::slice_error_fail(self, begin, self.len())- }- }-- /// Return a slice of the given string from its beginning to byte `end`.- ///- /// # Failure- ///- /// Fails when `end` is not at a code point boundary,- /// or is beyond the end of the string.- #[inline]- pub fn slice_to(&self, end: usize) -> &Wtf8 {- // is_code_point_boundary checks that the index is in [0, .len()]- if not_quite_std::is_code_point_boundary(self, end) {- unsafe { not_quite_std::slice_unchecked(self, 0, end) }- } else {- not_quite_std::slice_error_fail(self, 0, end)- }- }-- /// Return the code point at `position` if it is in the ASCII range,- /// or `b'\xFF' otherwise.- ///- /// # Failure- ///- /// Fails if `position` is beyond the end of the string.- #[inline]- pub fn ascii_byte_at(&self, position: usize) -> u8 {- match self.bytes[position] {- ascii_byte @ 0x00..=0x7f => ascii_byte,- _ => 0xff,- }- }-- /// Return an iterator for the string’s code points.- #[inline]- pub fn code_points(&self) -> Wtf8CodePoints<'_> {- Wtf8CodePoints {- bytes: self.bytes.iter(),- }- }-- /// Returns `true` if this WTF-8 string contains the given character.- #[inline]- pub fn contains_char(&self, ch: char) -> bool {- let target = CodePoint::from_char(ch);- self.contains(target)- }-- /// Returns `true` if this WTF-8 string contains the given code point.- #[inline]- pub fn contains(&self, code_point: CodePoint) -> bool {- self.code_points().any(|cp| cp == code_point)- }-- /// Returns `true` if this WTF-8 string starts with the given UTF-8 string.- #[inline]- pub fn starts_with(&self, pattern: &str) -> bool {- self.as_bytes().starts_with(pattern.as_bytes())- }-- /// Try to convert the string to UTF-8 and return a `&str` slice.- ///- /// Return `None` if the string contains surrogates.- ///- /// This does not copy the data.- #[inline]- pub fn as_str(&self) -> Option<&str> {- // Well-formed WTF-8 is also well-formed UTF-8- // if and only if it contains no surrogate.- match self.next_surrogate(0) {- None => Some(unsafe { str::from_utf8_unchecked(&self.bytes) }),- Some(_) => None,- }- }-- /// Return the underlying WTF-8 bytes.- #[inline]- pub const fn as_bytes(&self) -> &[u8] {- &self.bytes- }-- /// Lossily convert the string to UTF-8.- /// Return an UTF-8 `&str` slice if the contents are well-formed in UTF-8.- ///- /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character- /// “�”).- ///- /// This only copies the data if necessary (if it contains any surrogate).- pub fn to_string_lossy(&self) -> Cow<'_, str> {- let surrogate_pos = match self.next_surrogate(0) {- None => return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }),- Some((pos, _)) => pos,- };- let wtf8_bytes = &self.bytes;- let mut utf8_bytes = Vec::with_capacity(self.len());- utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]);- utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER);- let mut pos = surrogate_pos + 3;- loop {- match self.next_surrogate(pos) {- Some((surrogate_pos, _)) => {- utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]);- utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER);- pos = surrogate_pos + 3;- }- None => {- utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]);- return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) });- }- }- }- }-- /// Convert the WTF-8 string to potentially ill-formed UTF-16- /// and return an iterator of 16-bit code units.- ///- /// This is lossless:- /// calling `Wtf8Buf::from_ill_formed_utf16` on the resulting code units- /// would always return the original WTF-8 string.- #[inline]- pub fn to_ill_formed_utf16(&self) -> IllFormedUtf16CodeUnits<'_> {- IllFormedUtf16CodeUnits {- code_points: self.code_points(),- extra: 0,- }- }-- /// Returns the uppercase equivalent of this wtf8 slice, as a new [Wtf8Buf].- #[inline]- pub fn to_uppercase(&self) -> Wtf8Buf {- let mut result = Wtf8Buf::with_capacity(self.len());- for cp in self.code_points() {- if let Some(ch) = cp.to_char() {- for upper_ch in ch.to_uppercase() {- result.push_char(upper_ch);- }- } else {- // Surrogates are known to be in the code point range.- let code_point = unsafe { CodePoint::from_u32_unchecked(cp.to_u32()) };- // Skip the WTF-8 concatenation check,- // surrogate pairs are already decoded by utf16_items- not_quite_std::push_code_point(&mut result, code_point)- }- }- result- }-- /// Returns the lowercase equivalent of this wtf8 slice, as a new [Wtf8Buf].- #[inline]- pub fn to_lowercase(&self) -> Wtf8Buf {- let mut result = Wtf8Buf::with_capacity(self.len());- for cp in self.code_points() {- if let Some(ch) = cp.to_char() {- for lower_ch in ch.to_lowercase() {- result.push_char(lower_ch);- }- } else {- // Surrogates are known to be in the code point range.- let code_point = unsafe { CodePoint::from_u32_unchecked(cp.to_u32()) };- // Skip the WTF-8 concatenation check,- // surrogate pairs are already decoded by utf16_items- not_quite_std::push_code_point(&mut result, code_point)- }- }- result- }-- /// Create a WTF-8 slice from a WTF-8 encoded byte slice.- ///- /// Returns `Ok(&Wtf8)` if the bytes are well-formed WTF-8, or- /// `Err(bytes)` with the original byte slice if validation fails.- ///- /// This validates that:- /// - All bytes form valid UTF-8 sequences OR valid surrogate code point- /// encodings- /// - Surrogate code points may appear unpaired and be encoded separately,- /// but if they are paired, they must be encoded as a single 4-byte UTF-8- /// sequence. For example, the byte sequence `[0xED, 0xA0, 0x80, 0xED,- /// 0xB0, 0x80]` is not valid WTF-8 because WTF-8 forbids encoding a- /// surrogate pair as two separate 3-byte sequences.- pub fn from_bytes(bytes: &[u8]) -> Result<&Wtf8, &[u8]> {- if not_quite_std::validate_wtf8(bytes) {- Ok(unsafe { transmute::<&[u8], &Wtf8>(bytes) })- } else {- Err(bytes)- }- }-- /// Create a WTF-8 slice from a WTF-8 encoded byte slice without checking- /// that the bytes contain valid WTF-8.- ///- /// For the safe version, see [Wtf8::from_bytes].- ///- /// # Safety- ///- /// The bytes passed in must be valid WTF-8. See [Wtf8::from_bytes] for- /// the requirements.- #[inline]- pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Wtf8 {- unsafe { transmute(bytes) }- }-- #[inline]- fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> {- let mut iter = self.bytes[pos..].iter();- loop {- let b = match iter.next() {- None => return None,- Some(&b) => b,- };- if b < 0x80 {- pos += 1;- } else if b < 0xe0 {- iter.next();- pos += 2;- } else if b == 0xed {- match (iter.next(), iter.next()) {- (Some(&b2), Some(&b3)) if b2 >= 0xa0 => {- return Some((pos, decode_surrogate(b2, b3)))- }- _ => pos += 3,- }- } else if b < 0xf0 {- iter.next();- iter.next();- pos += 3;- } else {- iter.next();- iter.next();- iter.next();- pos += 4;- }- }- }-- #[inline]- fn final_lead_surrogate(&self) -> Option<u16> {- let len = self.len();- if len < 3 {- return None;- }- let seq = &self.bytes[len - 3..];- if seq[0] == 0xed && 0xa0 <= seq[1] && seq[1] <= 0xaf {- Some(decode_surrogate(seq[1], seq[2]))- } else {- None- }- }-- #[inline]- fn initial_trail_surrogate(&self) -> Option<u16> {- let len = self.len();- if len < 3 {- return None;- }- let seq = &self.bytes[..3];- if seq[0] == 0xed && 0xb0 <= seq[1] && seq[1] <= 0xbf {- Some(decode_surrogate(seq[1], seq[2]))- } else {- None- }- }-}--#[inline]-fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 {- // The first byte is assumed to be 0xED- 0xd800 | (second_byte as u16 & 0x3f) << 6 | third_byte as u16 & 0x3f-}--#[inline]-fn decode_surrogate_pair(lead: u16, trail: u16) -> char {- let code_point = 0x10000 + (((lead as u32 - 0xd800) << 10) | (trail as u32 - 0xdc00));- unsafe { char::from_u32_unchecked(code_point) }-}--/// Iterator for the code points of a WTF-8 string.-///-/// Created with the method `.code_points()`.-#[derive(Clone)]-pub struct Wtf8CodePoints<'a> {- bytes: slice::Iter<'a, u8>,-}--impl<'a> Iterator for Wtf8CodePoints<'a> {- type Item = CodePoint;-- #[inline]- fn next(&mut self) -> Option<CodePoint> {- not_quite_std::next_code_point(&mut self.bytes).map(|value| {- // Wtf8 invariant says `value` is a valid code point- unsafe { CodePoint::from_u32_unchecked(value) }- })- }-- #[inline]- fn size_hint(&self) -> (usize, Option<usize>) {- let (len, _) = self.bytes.size_hint();- (len.saturating_add(3) / 4, Some(len))- }-}--#[derive(Clone)]-pub struct IllFormedUtf16CodeUnits<'a> {- code_points: Wtf8CodePoints<'a>,- extra: u16,-}--impl<'a> Iterator for IllFormedUtf16CodeUnits<'a> {- type Item = u16;-- #[inline]- fn next(&mut self) -> Option<u16> {- not_quite_std::next_utf16_code_unit(self)- }-- #[inline]- fn size_hint(&self) -> (usize, Option<usize>) {- let (low, high) = self.code_points.size_hint();- // every code point gets either one u16 or two u16,- // so this iterator is between 1 or 2 times as- // long as the underlying iterator.- (low, high.and_then(|n| n.checked_mul(2)))- }-}--impl PartialEq<&Wtf8> for Wtf8Buf {- fn eq(&self, other: &&Wtf8) -> bool {- **self == **other- }-}--impl PartialEq<Wtf8Buf> for &Wtf8 {- fn eq(&self, other: &Wtf8Buf) -> bool {- **self == **other- }-}--impl PartialEq<str> for &Wtf8 {- fn eq(&self, other: &str) -> bool {- match self.as_str() {- Some(s) => s == other,- None => false,- }- }-}--impl PartialEq<&str> for &Wtf8 {- fn eq(&self, other: &&str) -> bool {- match self.as_str() {- Some(s) => s == *other,- None => false,- }- }-}--impl hash::Hash for CodePoint {- #[inline]- fn hash<H: hash::Hasher>(&self, state: &mut H) {- self.value.hash(state)- }-}--impl hash::Hash for Wtf8Buf {- #[inline]- fn hash<H: hash::Hasher>(&self, state: &mut H) {- Wtf8::hash(self, state)- }-}--impl hash::Hash for Wtf8 {- #[inline]- fn hash<H: hash::Hasher>(&self, state: &mut H) {- state.write(&self.bytes);- 0xfeu8.hash(state)- }-}--impl Borrow<Wtf8> for Wtf8Buf {- #[inline]- fn borrow(&self) -> &Wtf8 {- self- }-}--impl ToOwned for Wtf8 {- type Owned = Wtf8Buf;-- #[inline]- fn to_owned(&self) -> Wtf8Buf {- Wtf8Buf {- bytes: self.bytes.to_vec(),- }- }-}--impl<'a> From<&'a Wtf8> for Cow<'a, Wtf8> {- #[inline]- fn from(s: &'a Wtf8) -> Cow<'a, Wtf8> {- Cow::Borrowed(s)- }-}--impl<'a> From<&'a str> for &'a Wtf8 {- #[inline]- fn from(s: &'a str) -> &'a Wtf8 {- Wtf8::from_str(s)- }-}--impl<'a> From<Wtf8Buf> for Cow<'a, Wtf8> {- #[inline]- fn from(s: Wtf8Buf) -> Cow<'a, Wtf8> {- Cow::Owned(s)- }-}--#[cfg(test)]-mod tests {- use alloc::{format, vec};- use core::mem::transmute;-- use super::*;-- #[test]- fn code_point_from_u32() {- assert!(CodePoint::from_u32(0).is_some());- assert!(CodePoint::from_u32(0xd800).is_some());- assert!(CodePoint::from_u32(0x10ffff).is_some());- assert!(CodePoint::from_u32(0x110000).is_none());- }-- #[test]- fn code_point_to_u32() {- fn c(value: u32) -> CodePoint {- CodePoint::from_u32(value).unwrap()- }- assert_eq!(c(0).to_u32(), 0);- assert_eq!(c(0xd800).to_u32(), 0xd800);- assert_eq!(c(0x10ffff).to_u32(), 0x10ffff);- }-- #[test]- fn code_point_from_char() {- assert_eq!(CodePoint::from_char('a').to_u32(), 0x61);- assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1f4a9);- }-- #[test]- fn code_point_to_string() {- let cp_a = CodePoint::from_char('a');- assert_eq!(format!("{cp_a:?}"), "U+0061");- let cp_poop = CodePoint::from_char('💩');- assert_eq!(format!("{cp_poop:?}"), "U+1F4A9");- }-- #[test]- fn code_point_to_char() {- fn c(value: u32) -> CodePoint {- CodePoint::from_u32(value).unwrap()- }- assert_eq!(c(0x61).to_char(), Some('a'));- assert_eq!(c(0x1f4a9).to_char(), Some('💩'));- assert_eq!(c(0xd800).to_char(), None);- }-- #[test]- fn code_point_to_char_lossy() {- fn c(value: u32) -> CodePoint {- CodePoint::from_u32(value).unwrap()- }- assert_eq!(c(0x61).to_char_lossy(), 'a');- assert_eq!(c(0x1f4a9).to_char_lossy(), '💩');- assert_eq!(c(0xd800).to_char_lossy(), '\u{FFFD}');- }-- #[test]- fn wtf8buf_new() {- assert_eq!(Wtf8Buf::new().bytes, b"");- }-- #[test]- fn wtf8buf_from_str() {- assert_eq!(Wtf8Buf::from_str("").bytes, b"");- assert_eq!(- Wtf8Buf::from_str("aé 💩").bytes,- b"a\xC3\xA9 \xF0\x9F\x92\xA9"- );- }-- #[test]- fn wtf8buf_from_string() {- assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b"");- assert_eq!(- Wtf8Buf::from_string(String::from("aé 💩")).bytes,- b"a\xC3\xA9 \xF0\x9F\x92\xA9"- );- }-- #[test]- fn wtf8buf_from_ill_formed_utf16() {- assert_eq!(Wtf8Buf::from_ill_formed_utf16(&[]).bytes, b"");- assert_eq!(- Wtf8Buf::from_ill_formed_utf16(&[0x61, 0xe9, 0x20, 0xd83d, 0xd83d, 0xdca9]).bytes,- b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9"- );- }-- #[test]- fn wtf8buf_push_str() {- let mut string = Wtf8Buf::new();- assert_eq!(string.bytes, b"");- string.push_str("aé 💩");- assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");- }-- #[test]- fn wtf8buf_push_char() {- let mut string = Wtf8Buf::from_str("aé ");- assert_eq!(string.bytes, b"a\xC3\xA9 ");- string.push_char('💩');- assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");- }-- #[test]- fn wtf8buf_push_code_points_of_each_encoded_width() {- fn code_point(value: u32) -> CodePoint {- CodePoint::from_u32(value).unwrap()- }-- let mut string = Wtf8Buf::new();-- string.push(code_point(0x7f));- assert_eq!(string.bytes, b"\x7f");-- string.push(code_point(0x80));- assert_eq!(string.bytes, b"\x7f\xc2\x80");-- string.push(code_point(0x800));- assert_eq!(string.bytes, b"\x7f\xc2\x80\xe0\xa0\x80");-- string.push(code_point(0xd800));- assert_eq!(string.bytes, b"\x7f\xc2\x80\xe0\xa0\x80\xed\xa0\x80");-- string.push(code_point(0x10000));- assert_eq!(- string.bytes,- b"\x7f\xc2\x80\xe0\xa0\x80\xed\xa0\x80\xf0\x90\x80\x80"- );- }-- #[test]- fn wtf8buf_push() {- let mut string = Wtf8Buf::from_str("aé ");- assert_eq!(string.bytes, b"a\xC3\xA9 ");- string.push(CodePoint::from_char('💩'));- assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");-- fn c(value: u32) -> CodePoint {- CodePoint::from_u32(value).unwrap()- }-- let mut string = Wtf8Buf::new();- string.push(c(0xd83d)); // lead- string.push(c(0xdca9)); // trail- assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!-- let mut string = Wtf8Buf::new();- string.push(c(0xd83d)); // lead- string.push(c(0x20)); // not surrogate- string.push(c(0xdca9)); // trail- assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");-- let mut string = Wtf8Buf::new();- string.push(c(0xd800)); // lead- string.push(c(0xdbff)); // lead- assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");-- let mut string = Wtf8Buf::new();- string.push(c(0xd800)); // lead- string.push(c(0xe000)); // not surrogate- assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");-- let mut string = Wtf8Buf::new();- string.push(c(0xd7ff)); // not surrogate- string.push(c(0xdc00)); // trail- assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");-- let mut string = Wtf8Buf::new();- string.push(c(0x61)); // not surrogate, < 3 bytes- string.push(c(0xdc00)); // trail- assert_eq!(string.bytes, b"\x61\xED\xB0\x80");-- let mut string = Wtf8Buf::new();- string.push(c(0xdc00)); // trail- assert_eq!(string.bytes, b"\xED\xB0\x80");- }-- #[test]- fn wtf8buf_push_wtf8() {- let mut string = Wtf8Buf::from_str("aé");- assert_eq!(string.bytes, b"a\xC3\xA9");- string.push_wtf8(Wtf8::from_str(" 💩"));- assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");-- fn w(value: &[u8]) -> &Wtf8 {- unsafe { transmute(value) }- }-- let mut string = Wtf8Buf::new();- string.push_wtf8(w(b"\xED\xA0\xBD")); // lead- string.push_wtf8(w(b"\xED\xB2\xA9")); // trail- assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!-- let mut string = Wtf8Buf::new();- string.push_wtf8(w(b"\xED\xA0\xBD")); // lead- string.push_wtf8(w(b" ")); // not surrogate- string.push_wtf8(w(b"\xED\xB2\xA9")); // trail- assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");-- let mut string = Wtf8Buf::new();- string.push_wtf8(w(b"\xED\xA0\x80")); // lead- string.push_wtf8(w(b"\xED\xAF\xBF")); // lead- assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");-- let mut string = Wtf8Buf::new();- string.push_wtf8(w(b"\xED\xA0\x80")); // lead- string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate- assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");-- let mut string = Wtf8Buf::new();- string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate- string.push_wtf8(w(b"\xED\xB0\x80")); // trail- assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");-- let mut string = Wtf8Buf::new();- string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes- string.push_wtf8(w(b"\xED\xB0\x80")); // trail- assert_eq!(string.bytes, b"\x61\xED\xB0\x80");-- let mut string = Wtf8Buf::new();- string.push_wtf8(w(b"\xED\xB0\x80")); // trail- assert_eq!(string.bytes, b"\xED\xB0\x80");- }-- #[test]- fn wtf8buf_truncate() {- let mut string = Wtf8Buf::from_str("aé");- string.truncate(1);- assert_eq!(string.bytes, b"a");- }-- #[test]- #[should_panic]- fn wtf8buf_truncate_fail_code_point_boundary() {- let mut string = Wtf8Buf::from_str("aé");- string.truncate(2);- }-- #[test]- #[should_panic]- fn wtf8buf_truncate_fail_longer() {- let mut string = Wtf8Buf::from_str("aé");- string.truncate(4);- }-- #[test]- fn wtf8buf_into_string() {- let mut string = Wtf8Buf::from_str("aé 💩");- assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩")));- string.push(CodePoint::from_u32(0xd800).unwrap());- assert_eq!(string.clone().into_string(), Err(string));- }-- #[test]- fn wtf8buf_into_string_lossy() {- let mut string = Wtf8Buf::from_str("aé 💩");- assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩"));- string.push(CodePoint::from_u32(0xd800).unwrap());- assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�"));- }-- #[test]- fn wtf8buf_from_iterator() {- fn f(values: &[u32]) -> Wtf8Buf {- values- .iter()- .map(|&c| CodePoint::from_u32(c).unwrap())- .collect::<Wtf8Buf>()- }- assert_eq!(- f(&[0x61, 0xe9, 0x20, 0x1f4a9]).bytes,- b"a\xC3\xA9 \xF0\x9F\x92\xA9"- );-- assert_eq!(f(&[0xd83d, 0xdca9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!- assert_eq!(- f(&[0xd83d, 0x20, 0xdca9]).bytes,- b"\xED\xA0\xBD \xED\xB2\xA9"- );- assert_eq!(f(&[0xd800, 0xdbff]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");- assert_eq!(f(&[0xd800, 0xe000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");- assert_eq!(f(&[0xd7ff, 0xdc00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");- assert_eq!(f(&[0x61, 0xdc00]).bytes, b"\x61\xED\xB0\x80");- assert_eq!(f(&[0xdc00]).bytes, b"\xED\xB0\x80");- }-- #[test]- fn wtf8buf_extend() {- fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf {- fn c(value: &u32) -> CodePoint {- CodePoint::from_u32(*value).unwrap()- }- let mut string = initial.iter().map(c).collect::<Wtf8Buf>();- string.extend(extended.iter().map(c));- string- }-- assert_eq!(- e(&[0x61, 0xe9], &[0x20, 0x1f4a9]).bytes,- b"a\xC3\xA9 \xF0\x9F\x92\xA9"- );-- assert_eq!(e(&[0xd83d], &[0xdca9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!- assert_eq!(- e(&[0xd83d, 0x20], &[0xdca9]).bytes,- b"\xED\xA0\xBD \xED\xB2\xA9"- );- assert_eq!(e(&[0xd800], &[0xdbff]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");- assert_eq!(e(&[0xd800], &[0xe000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");- assert_eq!(e(&[0xd7ff], &[0xdc00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");- assert_eq!(e(&[0x61], &[0xdc00]).bytes, b"\x61\xED\xB0\x80");- assert_eq!(e(&[], &[0xdc00]).bytes, b"\xED\xB0\x80");- }-- #[test]- fn wtf8buf_debug() {- let mut string = Wtf8Buf::from_str("aé 💩");- string.push(CodePoint::from_u32(0xd800).unwrap());- assert_eq!(format!("{string:?}"), r#""aé 💩\u{D800}""#);- }-- #[test]- fn wtf8buf_as_slice() {- assert_eq!(Wtf8Buf::from_str("aé"), Wtf8::from_str("aé"));- }-- #[test]- fn wtf8_debug() {- let mut string = Wtf8Buf::from_str("aé 💩");- string.push(CodePoint::from_u32(0xd800).unwrap());- let string_ref = &*string;- assert_eq!(format!("{string_ref:?}"), r#""aé 💩\u{D800}""#);- }-- #[test]- fn wtf8_from_str() {- assert_eq!(&Wtf8::from_str("").bytes, b"");- assert_eq!(- &Wtf8::from_str("aé 💩").bytes,- b"a\xC3\xA9 \xF0\x9F\x92\xA9"- );- }-- #[test]- fn wtf8_as_bytes() {- assert_eq!(Wtf8::from_str("").as_bytes(), b"");- assert_eq!(- Wtf8::from_str("aé 💩").as_bytes(),- b"a\xC3\xA9 \xF0\x9F\x92\xA9"- );- }-- #[test]- fn wtf8_starts_with() {- assert!(Wtf8::from_str("aé 💩").starts_with("aé"));- assert!(!Wtf8::from_str("aé 💩").starts_with("a💩"));- assert!(!Wtf8::from_str("aé 💩").starts_with("aé 💩!"));-- // The pattern length falls inside the first non-ASCII code point.- assert!(!Wtf8::from_str("/example/path/to/日本語").starts_with("next/dist/compiled"));- }-- #[test]- fn wtf8_from_bytes_unchecked() {- assert_eq!(unsafe { &Wtf8::from_bytes_unchecked(b"").bytes }, b"");- assert_eq!(- unsafe { &Wtf8::from_bytes_unchecked(b"a\xC3\xA9 \xF0\x9F\x92\xA9").bytes },- b"a\xC3\xA9 \xF0\x9F\x92\xA9"- );- assert_eq!(- unsafe { Wtf8::from_bytes_unchecked(b"a\xC3\xA9 \xF0\x9F\x92\xA9") },- Wtf8::from_str("aé 💩")- )- }-- #[test]- fn wtf8_cow() {- let s: Cow<Wtf8> = Cow::from(Wtf8::from_str("aé 💩"));- assert!(matches!(s, Cow::Borrowed(_)));- let owned: Wtf8Buf = s.into_owned();- assert_eq!(owned, Wtf8Buf::from_str("aé 💩"));- }-- #[test]- fn wtf8_len() {- assert_eq!(Wtf8::from_str("").len(), 0);- assert_eq!(Wtf8::from_str("aé 💩").len(), 8);- }-- #[test]- fn wtf8_slice() {- assert_eq!(&Wtf8::from_str("aé 💩").slice(1, 4).bytes, b"\xC3\xA9 ");- }-- #[test]- #[should_panic]- fn wtf8_slice_not_code_point_boundary() {- Wtf8::from_str("aé 💩").slice(2, 4);- }-- #[test]- fn wtf8_slice_from() {- assert_eq!(- &Wtf8::from_str("aé 💩").slice_from(1).bytes,- b"\xC3\xA9 \xF0\x9F\x92\xA9"- );- }-- #[test]- #[should_panic]- fn wtf8_slice_from_not_code_point_boundary() {- Wtf8::from_str("aé 💩").slice_from(2);- }-- #[test]- fn wtf8_slice_to() {- assert_eq!(&Wtf8::from_str("aé 💩").slice_to(4).bytes, b"a\xC3\xA9 ");- }-- #[test]- #[should_panic]- fn wtf8_slice_to_not_code_point_boundary() {- Wtf8::from_str("aé 💩").slice_from(5);- }-- #[test]- fn wtf8_ascii_byte_at() {- let slice = Wtf8::from_str("aé 💩");- assert_eq!(slice.ascii_byte_at(0), b'a');- assert_eq!(slice.ascii_byte_at(1), b'\xFF');- assert_eq!(slice.ascii_byte_at(2), b'\xFF');- assert_eq!(slice.ascii_byte_at(3), b' ');- assert_eq!(slice.ascii_byte_at(4), b'\xFF');- }-- #[test]- fn wtf8_code_points() {- fn c(value: u32) -> CodePoint {- CodePoint::from_u32(value).unwrap()- }- fn cp(string: &Wtf8Buf) -> Vec<Option<char>> {- string- .code_points()- .map(|c| c.to_char())- .collect::<Vec<_>>()- }- let mut string = Wtf8Buf::from_str("é ");- assert_eq!(cp(&string), vec![Some('é'), Some(' ')]);- string.push(c(0xd83d));- assert_eq!(cp(&string), vec![Some('é'), Some(' '), None]);- string.push(c(0xdca9));- assert_eq!(cp(&string), vec![Some('é'), Some(' '), Some('💩')]);- }-- #[test]- fn wtf8_as_str() {- assert_eq!(Wtf8::from_str("").as_str(), Some(""));- assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩"));- let mut string = Wtf8Buf::new();- string.push(CodePoint::from_u32(0xd800).unwrap());- assert_eq!(string.as_str(), None);- }-- #[test]- fn wtf8_to_string_lossy() {- assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed(""));- assert_eq!(- Wtf8::from_str("aé 💩").to_string_lossy(),- Cow::Borrowed("aé 💩")- );- let mut string = Wtf8Buf::from_str("aé 💩");- string.push(CodePoint::from_u32(0xd800).unwrap());- assert_eq!(string.to_string_lossy(), {- let o: Cow<str> = Cow::Owned(String::from("aé 💩�"));- o- });- }-- #[test]- fn wtf8_to_ill_formed_utf16() {- let mut string = Wtf8Buf::from_str("aé ");- string.push(CodePoint::from_u32(0xd83d).unwrap());- string.push_char('💩');- assert_eq!(- string.to_ill_formed_utf16().collect::<Vec<_>>(),- vec![0x61, 0xe9, 0x20, 0xd83d, 0xd83d, 0xdca9]- );- }-- #[test]- fn wtf8buf_wtf8_from_bytes_valid() {- // Valid UTF-8- assert!(Wtf8Buf::from_bytes(b"hello".to_vec()).is_ok());- assert!(Wtf8Buf::from_bytes(b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec()).is_ok());- assert!(Wtf8::from_bytes(b"hello").is_ok());- assert!(Wtf8::from_bytes(b"a\xC3\xA9 \xF0\x9F\x92\xA9").is_ok());-- // Valid WTF-8 with unpaired surrogates- assert!(Wtf8Buf::from_bytes(b"\xED\xA0\x80".to_vec()).is_ok()); // lead surrogate- assert!(Wtf8Buf::from_bytes(b"\xED\xB0\x80".to_vec()).is_ok()); // trail surrogate- assert!(Wtf8Buf::from_bytes(b"a\xED\xA0\xBD".to_vec()).is_ok()); // text + lead- assert!(Wtf8Buf::from_bytes(b"\xED\xB2\xA9z".to_vec()).is_ok()); // trail + text- assert!(Wtf8Buf::from_bytes(b"\xED\xB2\xA9\xED\xA0\xBD".to_vec()).is_ok());- // trail + lead- }-- #[test]- fn wtf8buf_wtf8_from_bytes_invalid() {- // Invalid: surrogate pair encoded as two 3-byte sequences- assert!(Wtf8Buf::from_bytes(b"\xED\xA0\x80\xED\xB0\x80".to_vec()).is_err());- assert!(Wtf8Buf::from_bytes(b"\xED\xA0\xBD\xED\xB2\xA9".to_vec()).is_err());- assert!(Wtf8::from_bytes(b"\xED\xA0\x80\xED\xB0\x80").is_err());- assert!(Wtf8::from_bytes(b"\xED\xA0\xBD\xED\xB2\xA9").is_err());-- // Invalid UTF-8- assert!(Wtf8Buf::from_bytes(vec![0xff]).is_err());- assert!(Wtf8Buf::from_bytes(vec![0xc0, 0x80]).is_err()); // overlong- assert!(Wtf8Buf::from_bytes(vec![0xed, 0xa0]).is_err()); // truncated lead surrogate- assert!(Wtf8Buf::from_bytes(vec![0xf4, 0x90, 0x80, 0x80]).is_err()); // > U+10FFFF-- // Verify we can recover the original bytes on failure- let original = vec![0xff, 0xfe];- let result = Wtf8Buf::from_bytes(original.clone());- assert_eq!(result.unwrap_err(), original);-- let result = Wtf8::from_bytes(&original);- assert_eq!(result.unwrap_err(), original);- }-}
deps/swc/crates/hstr/src/wtf8/not_quite_std.rs
@@ -1,367 +0,0 @@-// Copyright (c) 2014 Simon Sapin-// Licensed under the MIT License-// Original source: https://github.com/SimonSapin/rust-wtf8--//! The code in this module is copied from Rust standard library-//! (the `std` crate and crates it is a facade for)-//! at commit 16d80de231abb2b1756f3951ffd4776d681035eb,-//! with the signature changed to use `Wtf8Buf`, `Wtf8`, and `CodePoint`-//! instead of `String`, `&str`, and `char`.-//!-//! FIXME: if and when this is moved into the standard library,-//! try to avoid the code duplication.-//! Maybe by having private generic code that is monomorphized to UTF-8 and-//! WTF-8?--use core::{- char,- mem::{self, MaybeUninit},- slice,-};--use super::{CodePoint, IllFormedUtf16CodeUnits, Wtf8, Wtf8Buf};--// UTF-8 ranges and tags for encoding characters-// Copied from 48d5fe9ec560b53b1f5069219b0d62015e1de5ba^:src/libcore/char.rs-const TAG_CONT: u8 = 0b1000_0000;-const TAG_TWO_B: u8 = 0b1100_0000;-const TAG_THREE_B: u8 = 0b1110_0000;-const TAG_FOUR_B: u8 = 0b1111_0000;-const MAX_ONE_B: u32 = 0x80;-const MAX_TWO_B: u32 = 0x800;-const MAX_THREE_B: u32 = 0x10000;--/// Encode a code point into potentially uninitialized storage.-///-/// On success, exactly the first returned number of elements in `dst` are-/// initialized. Copied from-/// 48d5fe9ec560b53b1f5069219b0d62015e1de5ba^:src/libcore/char.rs.-#[inline]-fn encode_utf8_raw(code: u32, dst: &mut [MaybeUninit<u8>]) -> Option<usize> {- // Marked #[inline] to allow llvm optimizing it away- if code < MAX_ONE_B && !dst.is_empty() {- dst[0].write(code as u8);- Some(1)- } else if code < MAX_TWO_B && dst.len() >= 2 {- dst[0].write((code >> 6 & 0x1f) as u8 | TAG_TWO_B);- dst[1].write((code & 0x3f) as u8 | TAG_CONT);- Some(2)- } else if code < MAX_THREE_B && dst.len() >= 3 {- dst[0].write((code >> 12 & 0x0f) as u8 | TAG_THREE_B);- dst[1].write((code >> 6 & 0x3f) as u8 | TAG_CONT);- dst[2].write((code & 0x3f) as u8 | TAG_CONT);- Some(3)- } else if dst.len() >= 4 {- dst[0].write((code >> 18 & 0x07) as u8 | TAG_FOUR_B);- dst[1].write((code >> 12 & 0x3f) as u8 | TAG_CONT);- dst[2].write((code >> 6 & 0x3f) as u8 | TAG_CONT);- dst[3].write((code & 0x3f) as u8 | TAG_CONT);- Some(4)- } else {- None- }-}--/// Copied from 48d5fe9ec560b53b1f5069219b0d62015e1de5ba^:src/libcore/char.rs-#[inline]-fn encode_utf16_raw(mut ch: u32, dst: &mut [u16]) -> Option<usize> {- // Marked #[inline] to allow llvm optimizing it away- if (ch & 0xffff) == ch && !dst.is_empty() {- // The BMP falls through (assuming non-surrogate, as it should)- dst[0] = ch as u16;- Some(1)- } else if dst.len() >= 2 {- // Supplementary planes break into surrogates.- ch -= 0x1_0000;- dst[0] = 0xd800 | ((ch >> 10) as u16);- dst[1] = 0xdc00 | ((ch as u16) & 0x3ff);- Some(2)- } else {- None- }-}--/// Copied from core::str::next_code_point-#[inline]-pub fn next_code_point(bytes: &mut slice::Iter<u8>) -> Option<u32> {- // Decode UTF-8- let x = match bytes.next() {- None => return None,- Some(&next_byte) if next_byte < 128 => return Some(next_byte as u32),- Some(&next_byte) => next_byte,- };-- // Multibyte case follows- // Decode from a byte combination out of: [[[x y] z] w]- // NOTE: Performance is sensitive to the exact formulation here- let init = utf8_first_byte(x, 2);- let y = unwrap_or_0(bytes.next());- let mut ch = utf8_acc_cont_byte(init, y);- if x >= 0xe0 {- // [[x y z] w] case- // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid- let z = unwrap_or_0(bytes.next());- let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z);- ch = init << 12 | y_z;- if x >= 0xf0 {- // [x y z w] case- // use only the lower 3 bits of `init`- let w = unwrap_or_0(bytes.next());- ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w);- }- }-- Some(ch)-}--#[inline]-fn utf8_first_byte(byte: u8, width: u32) -> u32 {- (byte & (0x7f >> width)) as u32-}--/// Return the value of `ch` updated with continuation byte `byte`.-#[inline]-fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 {- (ch << 6) | (byte & CONT_MASK) as u32-}--#[inline]-fn unwrap_or_0(opt: Option<&u8>) -> u8 {- match opt {- Some(&byte) => byte,- None => 0,- }-}--/// Mask of the value bits of a continuation byte-const CONT_MASK: u8 = 0b0011_1111;--/// Copied from String::push-/// This does **not** include the WTF-8 concatenation check.-#[inline]-pub fn push_code_point(string: &mut Wtf8Buf, code_point: CodePoint) {- let cur_len = string.len();- // This may use up to 4 bytes.- string.reserve(4);-- let used = {- let spare = string.bytes.spare_capacity_mut();- encode_utf8_raw(code_point.to_u32(), &mut spare[..4])- .expect("four bytes are sufficient to encode any code point")- };-- // SAFETY: `reserve(4)` guarantees capacity for `cur_len + 4`, and- // `encode_utf8_raw` initialized exactly the first `used` spare bytes.- unsafe {- string.bytes.set_len(cur_len + used);- }-}--/// Copied from core::str::StrPrelude::is_char_boundary-#[inline]-pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool {- if index == slice.len() {- return true;- }- match slice.bytes.get(index) {- None => false,- Some(&b) => !(128u8..192u8).contains(&b),- }-}--/// Copied from core::str::raw::slice_unchecked-#[inline]-pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 {- mem::transmute(slice::from_raw_parts(- s.bytes.as_ptr().add(begin),- end - begin,- ))-}--/// Copied from core::str::raw::slice_error_fail-#[inline(never)]-pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! {- assert!(begin <= end);- panic!("index {begin} and/or {end} in {s:?} do not lie on character boundary");-}--/// Copied from core::str::Utf16CodeUnits::next-pub fn next_utf16_code_unit(iter: &mut IllFormedUtf16CodeUnits) -> Option<u16> {- if iter.extra != 0 {- let tmp = iter.extra;- iter.extra = 0;- return Some(tmp);- }-- let mut buf = [0u16; 2];- iter.code_points.next().map(|code_point| {- let n = encode_utf16_raw(code_point.to_u32(), &mut buf).unwrap_or(0);- if n == 2 {- iter.extra = buf[1];- }- buf[0]- })-}--/// Copied from src/librustc_unicode/char.rs-pub struct DecodeUtf16<I>-where- I: Iterator<Item = u16>,-{- iter: I,- buf: Option<u16>,-}--/// Copied from src/librustc_unicode/char.rs-#[inline]-pub fn decode_utf16<I: IntoIterator<Item = u16>>(iterable: I) -> DecodeUtf16<I::IntoIter> {- DecodeUtf16 {- iter: iterable.into_iter(),- buf: None,- }-}--/// Copied from src/librustc_unicode/char.rs-impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> {- type Item = Result<char, u16>;-- fn next(&mut self) -> Option<Result<char, u16>> {- let u = match self.buf.take() {- Some(buf) => buf,- None => self.iter.next()?,- };-- if !(0xd800..=0xdfff).contains(&u) {- // not a surrogate- Some(Ok(unsafe { char::from_u32_unchecked(u as u32) }))- } else if u >= 0xdc00 {- // a trailing surrogate- Some(Err(u))- } else {- let u2 = match self.iter.next() {- Some(u2) => u2,- // eof- None => return Some(Err(u)),- };- if !(0xdc00..=0xdfff).contains(&u2) {- // not a trailing surrogate so we're not a valid- // surrogate pair, so rewind to redecode u2 next time.- self.buf = Some(u2);- return Some(Err(u));- }-- // all ok, so lets decode it.- let c = (((u - 0xd800) as u32) << 10 | (u2 - 0xdc00) as u32) + 0x1_0000;- Some(Ok(unsafe { char::from_u32_unchecked(c) }))- }- }-- #[inline]- fn size_hint(&self) -> (usize, Option<usize>) {- let (low, high) = self.iter.size_hint();- // we could be entirely valid surrogates (2 elements per- // char), or entirely non-surrogates (1 element per char)- (low / 2, high)- }-}--/// Check if a byte is a valid UTF-8 continuation byte.-#[inline]-fn is_continuation_byte(byte: u8) -> bool {- byte & 0xc0 == 0x80-}--/// Check if bytes at position form a surrogate pair. A surrogate pair should be-/// encoded as 4-byte sequence in UTF-8 instead of two separate 3-byte-/// sequences.-#[inline]-fn is_surrogate_pair(bytes: &[u8], pos: usize) -> bool {- if pos + 5 >= bytes.len() {- return false;- }- bytes[pos] == 0xed- && (0xa0..0xb0).contains(&bytes[pos + 1])- && is_continuation_byte(bytes[pos + 2])- && bytes[pos + 3] == 0xed- && (0xb0..0xc0).contains(&bytes[pos + 4])- && is_continuation_byte(bytes[pos + 5])-}--/// Validate that bytes represent well-formed WTF-8.-///-/// This checks that:-/// - All bytes form valid UTF-8 sequences OR valid surrogate code point-/// encodings-/// - Surrogate pairs are not encoded as two separate 3-byte sequences-pub fn validate_wtf8(bytes: &[u8]) -> bool {- let mut i = 0;- while i < bytes.len() {- let byte = bytes[i];-- // ASCII range (1-byte sequence)- if byte < 0x80 {- i += 1;- continue;- }-- // 2-byte sequence- if byte < 0xe0 {- if i + 1 >= bytes.len() || !is_continuation_byte(bytes[i + 1]) || byte < 0xc2 {- return false; // Truncated, invalid continuation, or overlong- }- i += 2;- continue;- }-- // 3-byte sequence- if byte < 0xf0 {- if i + 2 >= bytes.len()- || !is_continuation_byte(bytes[i + 1])- || !is_continuation_byte(bytes[i + 2])- {- return false; // Truncated or invalid continuation bytes- }-- let b2 = bytes[i + 1];-- // Check for overlong encoding- if byte == 0xe0 && b2 < 0xa0 {- return false;- }-- // Check for surrogate pair (lead + trail) - invalid in WTF-8- if is_surrogate_pair(bytes, i) {- return false;- }-- i += 3;- continue;- }-- // 4-byte sequence- if byte < 0xf8 {- if i + 3 >= bytes.len()- || !is_continuation_byte(bytes[i + 1])- || !is_continuation_byte(bytes[i + 2])- || !is_continuation_byte(bytes[i + 3])- {- return false; // Truncated or invalid continuation bytes- }-- let b2 = bytes[i + 1];-- // Check for overlong encoding and valid range- if (byte == 0xf0 && b2 < 0x90) || (byte == 0xf4 && b2 >= 0x90) || byte > 0xf4 {- return false;- }-- i += 4;- continue;- }-- // Invalid byte (>= 0xF8)- return false;- }-- true-}
deps/swc/crates/hstr/src/wtf8_atom.rs
@@ -1,663 +0,0 @@-use std::{- fmt::Debug,- hash::Hash,- mem::{forget, transmute, ManuallyDrop},- ops::Deref,-};--use debug_unreachable::debug_unreachable;--use crate::{- macros::{get_hash, impl_from_alias},- tagged_value::TaggedValue,- wtf8::Wtf8,- Atom, DYNAMIC_TAG, INLINE_TAG, LEN_MASK, LEN_OFFSET, TAG_MASK,-};--/// A WTF-8 encoded atom. This is like [Atom], but can contain unpaired-/// surrogates.-///-/// [Atom]: crate::Atom-#[repr(transparent)]-pub struct Wtf8Atom {- pub(crate) unsafe_data: TaggedValue,-}--impl Wtf8Atom {- #[inline(always)]- pub fn new<S>(s: S) -> Self- where- Self: From<S>,- {- Self::from(s)- }-- /// Try to convert this to a UTF-8 [Atom].- ///- /// Returns [Atom] if the string is valid UTF-8, otherwise returns- /// the original [Wtf8Atom].- pub fn try_into_atom(self) -> Result<Atom, Wtf8Atom> {- if self.as_str().is_some() {- let atom = ManuallyDrop::new(self);- Ok(Atom {- unsafe_data: atom.unsafe_data,- })- } else {- Err(self)- }- }-- #[inline(always)]- fn tag(&self) -> u8 {- self.unsafe_data.tag() & TAG_MASK- }-- /// Return true if this is a dynamic Atom.- #[inline(always)]- fn is_dynamic(&self) -> bool {- self.tag() == DYNAMIC_TAG- }-}--impl Default for Wtf8Atom {- #[inline(never)]- fn default() -> Self {- Wtf8Atom::new("")- }-}--/// Immutable, so it's safe to be shared between threads-unsafe impl Send for Wtf8Atom {}--/// Immutable, so it's safe to be shared between threads-unsafe impl Sync for Wtf8Atom {}--impl Debug for Wtf8Atom {- #[inline]- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {- Debug::fmt(&**self, f)- }-}--#[cfg(feature = "serde")]-impl serde::ser::Serialize for Wtf8Atom {- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>- where- S: serde::ser::Serializer,- {- use crate::wtf8::Wtf8;- fn convert_wtf8_to_raw(s: &Wtf8) -> String {- let mut result = String::new();- let mut iter = s.code_points().peekable();-- while let Some(code_point) = iter.next() {- if let Some(c) = code_point.to_char() {- // Escape literal '\u' sequences to avoid ambiguity with surrogate encoding.- // Without this escaping, we couldn't distinguish between:- // - JavaScript's "\uD800" (actual unpaired surrogate)- // - JavaScript's "\\uD800" (literal text '\uD800')- //- // By escaping literal '\u' to '\\u', we ensure:- // - Unpaired surrogates serialize as '\uXXXX'- // - Literal '\u' text serializes as '\\uXXXX'- //- // However, we should only escape '\u' if it's followed by exactly 4 hex digits,- // which would indicate a Unicode escape sequence. Otherwise, '\u' followed by- // non-hex characters (like '\util') should not be escaped.- if c == '\\' && iter.peek().map(|cp| cp.to_u32()) == Some('u' as u32) {- // Look ahead to see if this is followed by exactly 4 hex digits- let mut lookahead = iter.clone();- lookahead.next(); // skip 'u'-- let mut hex_count = 0;- let mut all_hex = true;- for _ in 0..4 {- if let Some(next_cp) = lookahead.next() {- if let Some(next_c) = next_cp.to_char() {- if next_c.is_ascii_hexdigit() {- hex_count += 1;- } else {- all_hex = false;- break;- }- } else {- all_hex = false;- break;- }- } else {- all_hex = false;- break;- }- }-- // Only escape if we have exactly 4 hex digits after '\u'- if hex_count == 4 && all_hex {- iter.next(); // skip 'u'- result.push_str("\\\\u");- } else {- result.push(c);- }- } else {- result.push(c)- }- } else {- // Unpaired surrogates can't be represented in valid UTF-8,- // so encode them as '\uXXXX' for JavaScript compatibility- result.push_str(format!("\\u{:04X}", code_point.to_u32()).as_str());- }- }-- result- }-- serializer.serialize_str(&convert_wtf8_to_raw(self))- }-}--#[cfg(feature = "serde")]-impl<'de> serde::de::Deserialize<'de> for Wtf8Atom {- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>- where- D: serde::Deserializer<'de>,- {- use crate::wtf8::{CodePoint, Wtf8Buf};- fn convert_wtf8_string_to_wtf8(s: String) -> Wtf8Buf {- let mut iter = s.chars().peekable();- let mut result = Wtf8Buf::with_capacity(s.len());-- // This function reverses the encoding done in serialize.- // It handles two cases:- // 1. '\uXXXX' - Decode as an unpaired surrogate code point- // 2. '\\uXXXX' - Treat as literal text '\uXXXX'- while let Some(c) = iter.next() {- if c == '\\' {- if iter.peek() == Some(&'u') {- // Found '\u' - might be a surrogate encoding- let _ = iter.next(); // skip 'u'-- // Try to read 4 hex digits- let d1 = iter.next();- let d2 = iter.next();- let d3 = iter.next();- let d4 = iter.next();-- match (d1, d2, d3, d4) {- (Some(d1), Some(d2), Some(d3), Some(d4)) => {- let hex = format!("{d1}{d2}{d3}{d4}");- if let Ok(code_point) = u16::from_str_radix(&hex, 16) {- result.push(unsafe {- CodePoint::from_u32_unchecked(code_point as u32)- });- continue;- }-- result.push_char('\\');- result.push_char('u');- result.push_char(d1);- result.push_char(d2);- result.push_char(d3);- result.push_char(d4);- }- (d1, d2, d3, d4) => {- result.push_char('\\');- result.push_char('u');-- macro_rules! push_if_some {- ($expr:expr) => {- if let Some(c) = $expr {- result.push_char(c);- }- };- }-- push_if_some!(d1);- push_if_some!(d2);- push_if_some!(d3);- push_if_some!(d4);- }- }- } else if iter.peek() == Some(&'\\') {- // Found '\\' - this is an escaped backslash- // '\\u' should become literal '\u' text- let _ = iter.next(); // skip the second '\'- if iter.peek() == Some(&'u') {- let _ = iter.next(); // skip 'u'- result.push_char('\\');- result.push_char('u');- } else {- result.push_str("\\\\");- }- } else {- result.push_char(c);- }- } else {- result.push_char(c);- }- }- result- }-- String::deserialize(deserializer).map(|v| convert_wtf8_string_to_wtf8(v).into())- }-}--impl PartialEq for Wtf8Atom {- #[inline]- fn eq(&self, other: &Self) -> bool {- let unsafe_data = self.unsafe_data;- let other_unsafe_data = other.unsafe_data;-- if unsafe_data == other_unsafe_data {- return true;- }-- let tag = unsafe_data.tag() & TAG_MASK;-- if tag != (other_unsafe_data.tag() & TAG_MASK) {- return false;- }-- match tag {- // Inline atoms encode both their length and bytes in `unsafe_data`, so- // different raw values mean different strings.- INLINE_TAG => false,- DYNAMIC_TAG => {- let this = unsafe { crate::dynamic::deref_from(unsafe_data) };- let other = unsafe { crate::dynamic::deref_from(other_unsafe_data) };-- if this.header.header.hash != other.header.header.hash {- return false;- }-- this.slice == other.slice- }- _ => unsafe { debug_unreachable!() },- }- }-}--impl Eq for Wtf8Atom {}--impl Hash for Wtf8Atom {- #[inline(always)]- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {- state.write_u64(self.get_hash());- }-}--impl Drop for Wtf8Atom {- #[inline(always)]- fn drop(&mut self) {- if self.is_dynamic() {- unsafe { drop(crate::dynamic::restore_arc(self.unsafe_data)) }- }- }-}--impl Clone for Wtf8Atom {- #[inline(always)]- fn clone(&self) -> Self {- Self::from_alias(self.unsafe_data)- }-}--impl Deref for Wtf8Atom {- type Target = Wtf8;-- #[inline(always)]- fn deref(&self) -> &Self::Target {- self.as_wtf8()- }-}--impl AsRef<Wtf8> for Wtf8Atom {- #[inline(always)]- fn as_ref(&self) -> &Wtf8 {- self.as_wtf8()- }-}--impl PartialEq<Wtf8> for Wtf8Atom {- #[inline]- fn eq(&self, other: &Wtf8) -> bool {- self.as_wtf8() == other- }-}--impl PartialEq<crate::Atom> for Wtf8Atom {- #[inline]- fn eq(&self, other: &crate::Atom) -> bool {- self.as_str() == Some(other.as_str())- }-}--impl PartialEq<&'_ Wtf8> for Wtf8Atom {- #[inline]- fn eq(&self, other: &&Wtf8) -> bool {- self.as_wtf8() == *other- }-}--impl PartialEq<Wtf8Atom> for Wtf8 {- #[inline]- fn eq(&self, other: &Wtf8Atom) -> bool {- self == other.as_wtf8()- }-}--impl PartialEq<str> for Wtf8Atom {- #[inline]- fn eq(&self, other: &str) -> bool {- matches!(self.as_str(), Some(s) if s == other)- }-}--impl PartialEq<&str> for Wtf8Atom {- #[inline]- fn eq(&self, other: &&str) -> bool {- matches!(self.as_str(), Some(s) if s == *other)- }-}--impl Wtf8Atom {- pub(super) fn get_hash(&self) -> u64 {- get_hash!(self)- }-- fn as_wtf8(&self) -> &Wtf8 {- match self.tag() {- DYNAMIC_TAG => unsafe {- let item = crate::dynamic::deref_from(self.unsafe_data);- Wtf8::from_bytes_unchecked(transmute::<&[u8], &'static [u8]>(&item.slice))- },- INLINE_TAG => {- let len = (self.unsafe_data.tag() & LEN_MASK) >> LEN_OFFSET;- let src = self.unsafe_data.data();- unsafe { Wtf8::from_bytes_unchecked(&src[..(len as usize)]) }- }- _ => unsafe { debug_unreachable!() },- }- }-}--impl_from_alias!(Wtf8Atom);--#[cfg(test)]-impl Wtf8Atom {- pub(crate) fn ref_count(&self) -> usize {- match self.tag() {- DYNAMIC_TAG => {- let ptr = unsafe { crate::dynamic::deref_from(self.unsafe_data) };-- triomphe::ThinArc::strong_count(&ptr.0)- }- _ => 1,- }- }-}--#[cfg(test)]-mod tests {- use super::*;- use crate::wtf8::{CodePoint, Wtf8Buf};-- #[cfg(feature = "serde")]- #[test]- fn test_serialize_normal_utf8() {- let atom = Wtf8Atom::new("Hello, world!");- let serialized = serde_json::to_string(&atom).unwrap();- assert_eq!(serialized, "\"Hello, world!\"");- }-- #[cfg(feature = "serde")]- #[test]- fn test_deserialize_normal_utf8() {- let json = "\"Hello, world!\"";- let atom: Wtf8Atom = serde_json::from_str(json).unwrap();- assert_eq!(atom.as_str(), Some("Hello, world!"));- }-- #[cfg(feature = "serde")]- #[test]- fn test_serialize_unpaired_high_surrogate() {- // Create a WTF-8 string with an unpaired high surrogate (U+D800)- let mut wtf8 = Wtf8Buf::new();- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xd800) });- let atom = Wtf8Atom::from(wtf8);-- let serialized = serde_json::to_string(&atom).unwrap();- // The serialized output will have double escaping due to serde_json- assert_eq!(serialized, "\"\\\\uD800\"");- }-- #[cfg(feature = "serde")]- #[test]- fn test_serialize_unpaired_low_surrogate() {- // Create a WTF-8 string with an unpaired low surrogate (U+DC00)- let mut wtf8 = Wtf8Buf::new();- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xdc00) });- let atom = Wtf8Atom::from(wtf8);-- let serialized = serde_json::to_string(&atom).unwrap();- // The serialized output will have double escaping due to serde_json- assert_eq!(serialized, "\"\\\\uDC00\"");- }-- #[cfg(feature = "serde")]- #[test]- fn test_serialize_multiple_surrogates() {- // Create a WTF-8 string with multiple unpaired surrogates- let mut wtf8 = Wtf8Buf::new();- wtf8.push_str("Hello ");- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xd800) });- wtf8.push_str(" World ");- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xdc00) });- let atom = Wtf8Atom::from(wtf8);-- let serialized = serde_json::to_string(&atom).unwrap();- // The serialized output will have double escaping due to serde_json- assert_eq!(serialized, "\"Hello \\\\uD800 World \\\\uDC00\"");- }-- #[cfg(feature = "serde")]- #[test]- fn test_serialize_literal_backslash_u() {- // Test that literal "\u" in the string gets escaped properly- let atom = Wtf8Atom::new("\\u0041");- let serialized = serde_json::to_string(&atom).unwrap();- // serde_json escapes the backslash, resulting in 4 backslashes- assert_eq!(serialized, "\"\\\\\\\\u0041\"");- }-- #[cfg(feature = "serde")]- #[test]- fn test_deserialize_escaped_backslash_u() {- // Test deserializing the escaped format for unpaired surrogates- let json = "\"\\\\uD800\"";- let atom: Wtf8Atom = serde_json::from_str(json).unwrap();- // This should be parsed as an unpaired surrogate- assert_eq!(atom.as_str(), None);- assert_eq!(atom.to_string_lossy(), "\u{FFFD}");- }-- #[cfg(feature = "serde")]- #[test]- fn test_deserialize_unpaired_surrogates() {- let json = "\"\\\\uD800\""; // Use escaped format that matches serialization- let atom: Wtf8Atom = serde_json::from_str(json).unwrap();- // Should contain an unpaired surrogate, so as_str() returns None- assert_eq!(atom.as_str(), None);- // But to_string_lossy should work- assert_eq!(atom.to_string_lossy(), "\u{FFFD}");- }-- #[cfg(feature = "serde")]- #[test]- fn test_round_trip_normal_string() {- let original = Wtf8Atom::new("Hello, 世界! 🌍");- let serialized = serde_json::to_string(&original).unwrap();- let deserialized: Wtf8Atom = serde_json::from_str(&serialized).unwrap();- assert_eq!(original.as_str(), deserialized.as_str());- }-- #[cfg(feature = "serde")]- #[test]- fn test_round_trip_unpaired_surrogates() {- // Create a string with unpaired surrogates- let mut wtf8 = Wtf8Buf::new();- wtf8.push_str("Before ");- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xd800) });- wtf8.push_str(" Middle ");- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xdc00) });- wtf8.push_str(" After");- let original = Wtf8Atom::from(wtf8);-- let serialized = serde_json::to_string(&original).unwrap();- let deserialized: Wtf8Atom = serde_json::from_str(&serialized).unwrap();-- // Both should be equal when compared as WTF-8- assert_eq!(original, deserialized);-- // Both should produce the same lossy string- assert_eq!(original.to_string_lossy(), deserialized.to_string_lossy());- }-- #[cfg(feature = "serde")]- #[test]- fn test_round_trip_mixed_content() {- // Create a complex string with normal text, emojis, and unpaired surrogates- let mut wtf8 = Wtf8Buf::new();- wtf8.push_str("Hello 世界 🌍 ");- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xd83d) }); // Unpaired high- wtf8.push_str(" test ");- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xdca9) }); // Unpaired low- let original = Wtf8Atom::from(wtf8);-- let serialized = serde_json::to_string(&original).unwrap();- let deserialized: Wtf8Atom = serde_json::from_str(&serialized).unwrap();-- assert_eq!(original, deserialized);- }-- #[cfg(feature = "serde")]- #[test]- fn test_empty_string() {- let atom = Wtf8Atom::new("");- let serialized = serde_json::to_string(&atom).unwrap();- assert_eq!(serialized, "\"\"");-- let deserialized: Wtf8Atom = serde_json::from_str("\"\"").unwrap();- assert_eq!(deserialized.as_str(), Some(""));- }-- #[cfg(feature = "serde")]- #[test]- fn test_special_characters() {- let test_cases = vec![- ("\"", "\"\\\"\""),- ("\n\r\t", "\"\\n\\r\\t\""), // serde_json escapes control characters- ("\\", "\"\\\\\""),- ("/", "\"/\""),- ];-- for (input, expected) in test_cases {- let atom = Wtf8Atom::new(input);- let serialized = serde_json::to_string(&atom).unwrap();- assert_eq!(serialized, expected, "Failed for input: {input:?}");-- let deserialized: Wtf8Atom = serde_json::from_str(&serialized).unwrap();- assert_eq!(deserialized.as_str(), Some(input));- }- }-- #[cfg(feature = "serde")]- #[test]- fn test_consecutive_surrogates_not_paired() {- // Test that consecutive surrogates that don't form a valid pair- // are handled correctly- let mut wtf8 = Wtf8Buf::new();- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xd800) }); // High surrogate- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xd800) }); // Another high surrogate- let atom = Wtf8Atom::from(wtf8);-- let serialized = serde_json::to_string(&atom).unwrap();- // The serialized output will have double escaping due to serde_json- assert_eq!(serialized, "\"\\\\uD800\\\\uD800\"");-- let deserialized: Wtf8Atom = serde_json::from_str(&serialized).unwrap();- assert_eq!(atom, deserialized);- }-- #[cfg(feature = "serde")]- #[test]- fn test_deserialize_incomplete_escape() {- // Test handling of incomplete escape sequences from our custom format- let json = "\"\\\\\\\\u123\""; // Escaped backslash + incomplete sequence- let atom: Wtf8Atom = serde_json::from_str(json).unwrap();- // JSON decodes \\\\u123 to \\u123, then our deserializer sees \u123 and treats- // it as literal- assert_eq!(atom.as_str(), Some("\\u123"));- }-- #[cfg(feature = "serde")]- #[test]- fn test_deserialize_invalid_hex() {- // Test handling of invalid hex in escape sequences from our custom format- let json = "\"\\\\\\\\uGGGG\""; // Escaped backslash + invalid hex- let atom: Wtf8Atom = serde_json::from_str(json).unwrap();- // JSON decodes \\\\uGGGG to \\uGGGG, then our deserializer sees \uGGGG and- // treats it as literal- assert_eq!(atom.as_str(), Some("\\uGGGG"));- }-- #[test]- fn test_try_into_atom_valid_utf8() {- let wtf8_atom = Wtf8Atom::new("Valid UTF-8 string");- let result = wtf8_atom.try_into_atom();- assert!(result.is_ok());- assert_eq!(result.unwrap().as_str(), "Valid UTF-8 string");- }-- #[test]- fn test_try_into_atom_invalid_utf8() {- // Create an atom with unpaired surrogates- let mut wtf8 = Wtf8Buf::new();- wtf8.push(unsafe { CodePoint::from_u32_unchecked(0xd800) });- let wtf8_atom = Wtf8Atom::from(wtf8);-- let result = wtf8_atom.try_into_atom();- assert!(result.is_err());- // Should return the original Wtf8Atom- let err_atom = result.unwrap_err();- assert_eq!(err_atom.to_string_lossy(), "\u{FFFD}");- }-- #[cfg(feature = "serde")]- #[test]- fn test_backslash_util_issue_11214() {- let atom =- Wtf8Atom::from("C:\\github\\swc-plugin-coverage-instrument\\spec\\util\\verifier.ts");- let serialized = serde_json::to_string(&atom).unwrap();-- assert!(- !serialized.contains("spec\\\\\\\\util"),- "Found quadruple backslashes in spec segment! Serialized: {serialized}"- );-- assert!(- serialized.contains("spec\\\\util"),- "Expected double backslashes in spec segment not found! Serialized: {serialized}",- );-- // The expected serialized value should have consistent escaping- let expected = r#""C:\\github\\swc-plugin-coverage-instrument\\spec\\util\\verifier.ts""#;- assert_eq!(- serialized, expected,- "Serialized value should have consistent backslash escaping"- );-- // Test round-trip- let deserialized: Wtf8Atom = serde_json::from_str(&serialized).unwrap();- assert_eq!(atom, deserialized);- }-}
deps/swc/crates/jsdoc/AGENTS.md
@@ -1,5 +0,0 @@-### Fixture Test Addition Guide--- Preferred fixture roots in this crate: tests/fixtures.-- Update generated fixture outputs with: UPDATE=1 cargo test -p jsdoc.-- Verify without UPDATE before finishing: cargo test -p jsdoc.
deps/swc/crates/jsdoc/Cargo.toml
@@ -1,37 +0,0 @@-[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>"]-description = "JsDoc parser writen in rust"-documentation = "https://rustdoc.swc.rs/jsdoc/"-edition = { workspace = true }-include = ["Cargo.toml", "src/**/*.rs"]-license = { workspace = true }-name = "jsdoc"-repository = { workspace = true }-version = "26.0.0"--[lib]-bench = false--[features]-encoding-impl = [- "cbor4ii",- "swc_atoms/encoding-impl",- "swc_common/encoding-impl",-]-serde-impl = ["serde"]--[lints.rust]-unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] }--[dependencies]-cbor4ii = { workspace = true, features = ["use_std"], optional = true }-nom = { workspace = true }-serde = { workspace = true, features = ["derive"], optional = true }--swc_atoms = { version = "10.0.0", path = "../swc_atoms" }-swc_common = { version = "26.0.0", path = "../swc_common" }--[dev-dependencies]-dashmap = { workspace = true }-swc_ecma_parser = { version = "46.0.0", path = "../swc_ecma_parser" }-testing = { version = "27.0.0", path = "../testing" }
deps/swc/crates/jsdoc/src/ast.rs
@@ -1,826 +0,0 @@-#![allow(unexpected_cfgs)]--use swc_atoms::Atom;-use swc_common::{ast_node, Span};--/// Spanned text-#[ast_node]-#[derive(Eq)]-pub struct Text {- pub span: Span,- pub value: Atom,-}--#[ast_node]-pub struct JsDoc {- pub span: Span,-- pub description: Text,- pub tags: Vec<TagItem>,-}--/// tag with comments.-#[ast_node]-pub struct TagItem {- pub span: Span,- #[cfg_attr(feature = "serde-impl", serde(rename = "tagName"))]- pub tag_name: Text,- #[cfg_attr(feature = "serde-impl", serde(flatten))]- pub tag: Tag,-}--#[ast_node(no_unknown)]-pub enum Tag {- #[tag("Yield")]- Yield(YieldTag),- #[tag("TypeDef")]- TypeDef(TypeDefTag),- #[tag("Throw")]- Throw(ThrowTag),- #[tag("Todo")]- Todo(TodoTag),- #[tag("Tutorial")]- Tutorial(TutorialTag),- #[tag("Static")]- Static(StaticTag),- #[tag("Summary")]- Summary(SummaryTag),- #[tag("See")]- See(SeeTag),- #[tag("Since")]- Since(SinceTag),- #[tag("Requires")]- Requires(RequiresTag),- #[tag("Override")]- Override(OverrideTag),- #[tag("Package")]- Package(PackageTag),- #[tag("Module")]- Module(ModuleTag),- #[tag("Name")]- Name(NameTag),- #[tag("Namespace")]- Namespace(NamespaceTag),- #[tag("Variation")]- Variation(VariationTag),- #[tag("Version")]- Version(VersionTag),- #[tag("MemberOf")]- MemberOf(MemberOfTag),- #[tag("Mixes")]- Mixes(MixesTag),- #[tag("Mixin")]- Mixin(MixinTag),- #[tag("Member")]- Member(MemberTag),- #[tag("Listens")]- Listens(ListensTag),- #[tag("License")]- License(LicenseTag),- #[tag("Kind")]- Kind(KindTag),- #[tag("Lends")]- Lends(LendsTag),- #[tag("Instance")]- Instance(InstanceTag),- #[tag("Interface")]- Interface(InterfaceTag),- #[tag("Inner")]- Inner(InnerTag),- #[tag("InheritDoc")]- InheritDoc(InheritDocTag),- #[tag("IgnoreTag")]- Ignore(IgnoreTag),- #[tag("HideConstructorTag")]- HideConstructor(HideConstructorTag),- #[tag("GeneratorTag")]- Generator(GeneratorTag),- #[tag("FunctionTag")]- Function(FunctionTag),- #[tag("FileTag")]- File(FileTag),- #[tag("ConstructsTag")]- Constructs(ConstructsTag),- #[tag("CopyrightTag")]- Copyright(CopyrightTag),- #[tag("AbstractTag")]- Abstract(AbstractTag),- #[tag("AccessTag")]- Access(AccessTag),- #[tag("AliasTag")]- Alias(AliasTag),- #[tag("AsyncTag")]- Async(AsyncTag),- #[tag("UnknownTag")]- Unknown(UnknownTag),- #[tag("AugmentsTag")]- Augments(AugmentsTag),- #[tag("ImplementsTag")]- Implements(ImplementsTag),- #[tag("AuthorTag")]- Author(AuthorTag),- #[tag("BorrowsTag")]- Borrows(BorrowsTag),- #[tag("ClassTag")]- Class(ClassTag),- #[tag("JSDocClassDescTag")]- ClassDesc(JSDocClassDescTag),- #[tag("ConstTag")]- Const(ConstTag),- #[tag("PublicTag")]- Public(PublicTag),- #[tag("PrivateTag")]- Private(PrivateTag),- #[tag("ProtectedTag")]- Protected(ProtectedTag),- #[tag("ReadonlyTag")]- Readonly(ReadonlyTag),- #[tag("CallbackTag")]- Callback(CallbackTag),- #[tag("EnumTag")]- Enum(EnumTag),- #[tag("ParameterTag")]- Parameter(ParameterTag),- #[tag("ReturnTag")]- Return(ReturnTag),- #[tag("ThisTag")]- This(ThisTag),- #[tag("TypeTag")]- Type(TypeTag),- #[tag("TemplateTag")]- Template(TemplateTag),- #[tag("TypedefTag")]- Typedef(TypedefTag),- #[tag("PropertyTag")]- Property(PropertyTag),- #[tag("DescriptionTag")]- Description(DescriptionTag),- #[tag("ExampleTag")]- Example(ExampleTag),- #[tag("ExportsTag")]- Exports(ExportsTag),- #[tag("ExternalTag")]- External(ExternalTag),- #[tag("DefaultTag")]- Default(DefaultTag),- #[tag("DeprecatedTag")]- Deprecated(DeprecatedTag),-}--#[ast_node]-pub struct AbstractTag {- pub span: Span,-}--#[ast_node]-pub struct AccessTag {- pub span: Span,- pub access: Text,-}--#[ast_node]-pub struct AliasTag {- pub span: Span,- pub name_path: NamePath,-}--#[ast_node]-pub struct AsyncTag {- pub span: Span,-}--#[ast_node]-pub struct BorrowsTag {- pub span: Span,- pub from: NamePath,- pub to: NamePath,-}--#[ast_node]-pub struct JSDocClassDescTag {- pub span: Span,- pub desc: Text,-}--#[ast_node]-pub struct ConstTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub ty: Option<Text>,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub name: Option<Text>,-}--#[ast_node]-pub struct UnknownTag {- pub span: Span,- pub extras: Text,-}--/// `@extends`, `@augments`-#[ast_node]-pub struct AugmentsTag {- pub span: Span,- pub class: NamePath,-}--#[ast_node]-pub struct ImplementsTag {- pub span: Span,- pub class: Text,-}--#[ast_node]-pub struct ExprWithTypeArgs {- pub span: Span,-- // TODO parent: HeritageClause | JSDocAugmentsTag | JSDocImplementsTag;- pub expr: Box<Expr>,-}--#[ast_node]-pub enum Expr {- #[tag("Identifier")]- Text(Text),- #[tag("NamePath")]- Property(NamePath),-}--#[ast_node]-pub struct AuthorTag {- pub span: Span,- /// `<name> [<emailAddress>]`- pub author: Text,-}--#[ast_node]-#[derive(Eq)]-pub struct ClassTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub ty: Option<Text>,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub name: Option<Text>,-}--#[ast_node]-#[derive(Eq)]-pub struct PublicTag {- pub span: Span,-}--#[ast_node]-#[derive(Eq)]-pub struct PrivateTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub ty: Option<Text>,-}--#[ast_node]-#[derive(Eq)]-pub struct ProtectedTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub ty: Option<Text>,-}--#[ast_node]-#[derive(Eq)]-pub struct ReadonlyTag {- pub span: Span,-}--#[ast_node]-pub struct CallbackTag {- pub span: Span,- pub name_path: NamePath,-}--#[ast_node]-pub struct PropertyTag {- pub span: Span,-- pub name_path: NamePath,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub ty: Option<Text>,- pub desc: Text,-}--#[ast_node]-pub struct ParameterTag {- pub span: Span,-- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub name: Option<Text>,- #[cfg_attr(feature = "serde-impl", serde(rename = "typeExpression"))]- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub ty: Option<Text>,-- pub desc: Text,-}--#[ast_node]-#[derive(Eq)]-pub struct EnumTag {- pub span: Span,- pub ty: Text,-}--#[ast_node]-pub struct ReturnTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub ty: Option<Text>,- pub description: Text,-}--#[ast_node]-pub struct ThisTag {- pub span: Span,- pub name_path: NamePath,-}--#[ast_node]-pub struct TypeTag {- pub span: Span,- pub name: Text,-}--#[ast_node]-pub struct TemplateTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub constraint: Option<TypeExpr>,-}--#[ast_node]-pub struct TypedefTag {- pub span: Span,- #[cfg_attr(feature = "serde-impl", serde(rename = "full_name"))]- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub full_name: Option<NamespaceBody>,-- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub name: Option<Text>,- #[cfg_attr(feature = "serde-impl", serde(rename = "typeExpression"))]- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub type_expr: Option<TypeExprOrTypeLit>,-}--#[ast_node(no_unknown)]-pub enum Type {- /// `*`- #[tag("AllType")]- All(AllType),- /// `?`- #[tag("UnknownType")]- Unknown(UnknownType),- #[tag("NullableType")]- Nullable(NullableType),- #[tag("NonNullableType")]- NonNullable(NonNullableType),- #[tag("OptionalType")]- Optional(OptionalType),- #[tag("FunctionType")]- Function(FunctionType),- #[tag("VariadicType")]- Variadic(VariadicType),- // https://jsdoc.app/about-namepaths.html- #[tag("NamePathType")]- NamePath(NamePathType),- #[tag("UnionType")]- Union(UnionType),- #[tag("ParenType")]- Paren(ParenType),-}--#[ast_node]-pub struct UnionType {- pub span: Span,- pub types: Vec<Type>,-}--#[ast_node]-pub struct ParenType {- pub span: Span,- pub ty: Box<Type>,-}--#[ast_node]-#[derive(Eq)]-pub struct AllType {- pub span: Span,-}--#[ast_node]-#[derive(Eq)]-pub struct UnknownType {- pub span: Span,-}--#[ast_node]-pub struct NullableType {- pub span: Span,- pub ty: Box<Type>,-}--#[ast_node]-pub struct NonNullableType {- pub span: Span,- pub ty: Box<Type>,-}--#[ast_node]-pub struct OptionalType {- pub span: Span,- pub ty: Box<Type>,-}--/// TODO: Add fields-#[ast_node]-pub struct FunctionType {- pub span: Span,- pub ty: Box<Type>,-}--#[ast_node]-pub struct VariadicType {- pub span: Span,- pub ty: Box<Type>,-}--#[ast_node]-pub struct NamePathType {- pub span: Span,- pub ty: Box<Type>,-}--/// represents a top level: { type } expression in a JSDoc comment.-#[ast_node]-pub struct TypeExpr {- pub span: Span,- pub ty: Type,-}--#[ast_node]-pub struct NamespaceDecl {- pub span: Span,- pub name: Text,- pub body: Vec<NamespaceBody>,-}--#[ast_node]-pub enum NamespaceBody {- #[tag("Identifier")]- Text(Box<Text>),- #[tag("NamespaceDecl")]- Decl(Box<NamespaceDecl>),-}--#[ast_node]-pub enum TypeExprOrTypeLit {- #[tag("TypeExpr")]- Expr(Box<TypeExpr>),- #[tag("TypeLit")]- TypeLit(Box<TypeLit>),-}--#[ast_node]-pub struct TypeLit {- pub span: Span,- pub tags: Vec<PropOrParam>,- /// If true, then this type literal represents an *array* of its type.- pub is_array_type: bool,-}--#[ast_node]-pub enum PropOrParam {- #[tag("PropertyTag")]- Prop(PropertyTag),- #[tag("ParameterTag")]- Param(ParameterTag),-}--#[ast_node]-pub struct NamePath {- pub span: Span,- pub components: Vec<Text>,-}--#[ast_node]-pub struct CopyrightTag {- pub span: Span,- pub text: Text,-}--#[ast_node]-pub struct DescriptionTag {- pub span: Span,- pub text: Text,-}--#[ast_node]-pub struct ExampleTag {- pub span: Span,- pub text: Text,-}--#[ast_node]-pub struct ExportsTag {- pub span: Span,- pub module_name: Text,-}--#[ast_node]-pub struct ExternalTag {- pub span: Span,- pub name: Text,-}--#[ast_node]-pub struct ConstructsTag {- pub span: Span,- pub name: Text,-}--#[ast_node]-pub struct DefaultTag {- pub span: Span,- pub value: Text,-}--#[ast_node]-pub struct DeprecatedTag {- pub span: Span,- pub text: Text,-}--#[ast_node]-pub struct FileTag {- pub span: Span,- pub text: Text,-}--#[ast_node]-pub struct FunctionTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub name: Option<Text>,-}--#[ast_node]-pub struct GeneratorTag {- pub span: Span,-}-#[ast_node]-pub struct HideConstructorTag {- pub span: Span,-}--#[ast_node]-pub struct IgnoreTag {- pub span: Span,-}--#[ast_node]-pub struct InheritDocTag {- pub span: Span,-}--#[ast_node]-pub struct InnerTag {- pub span: Span,-}--#[ast_node]-pub struct InstanceTag {- pub span: Span,-}--#[ast_node]-pub struct InterfaceTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub name: Option<Text>,-}-#[ast_node]-pub struct KindTag {- pub span: Span,- pub name: Text,-}--#[ast_node]-pub struct LendsTag {- pub span: Span,- pub name: NamePath,-}--#[ast_node]-pub struct LicenseTag {- pub span: Span,- pub identifier: Text,-}--#[ast_node]-pub struct ListensTag {- pub span: Span,- pub event_name: Text,-}--#[ast_node]-pub struct MemberTag {- pub span: Span,- pub ty: Text,- pub name: Text,-}--#[ast_node]-pub struct MemberOfTag {- pub span: Span,- pub parent_name_path: NamePath,-}--#[ast_node]-pub struct TypeDefTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub ty: Option<Text>,- pub name_path: NamePath,-}--#[ast_node]-pub struct MixesTag {- pub span: Span,- pub name_path: NamePath,-}--#[ast_node]-pub struct MixinTag {- pub span: Span,- pub name: Text,-}--#[ast_node]-pub struct ModuleTag {- pub span: Span,- pub name: Text,- pub ty: Text,-}--#[ast_node]-pub struct NameTag {- pub span: Span,- pub name_path: NamePath,-}--#[ast_node]-pub struct NamespaceTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub ty: Option<Text>,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub name: Option<Text>,-}--#[ast_node]-pub struct OverrideTag {- pub span: Span,-}--#[ast_node]-pub struct PackageTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub ty: Option<Text>,-}--#[ast_node]-pub struct RequiresTag {- pub span: Span,- pub name_path: NamePath,-}--#[ast_node]-pub struct SeeTag {- pub span: Span,- pub text: Text,-}--#[ast_node]-pub struct SinceTag {- pub span: Span,- pub version: Text,-}--#[ast_node]-pub struct SummaryTag {- pub span: Span,- pub text: Text,-}--#[ast_node]-pub struct StaticTag {- pub span: Span,-}--#[ast_node]-pub struct ThrowTag {- pub span: Span,- pub text: Text,-}--#[ast_node]-pub struct TodoTag {- pub span: Span,- pub text: Text,-}--#[ast_node]-pub struct TutorialTag {- pub span: Span,- pub text: Text,-}--#[ast_node]-pub struct VariationTag {- pub span: Span,- pub number: Text,-}--#[ast_node]-pub struct VersionTag {- pub span: Span,- pub value: Text,-}--#[ast_node]-pub struct YieldTag {- pub span: Span,- #[cfg_attr(- feature = "encoding-impl",- encoding(with = "cbor4ii::core::types::Maybe")- )]- pub value: Option<Text>,- pub description: Text,-}
deps/swc/crates/jsdoc/src/input.rs
@@ -1,125 +0,0 @@-use std::{- ops::{Deref, Range, RangeFrom, RangeTo},- str::{CharIndices, Chars},-};--use nom::{- Compare, CompareResult, InputIter, InputLength, InputTake, Needed, Slice, UnspecializedInput,-};-use swc_common::{comments::Comment, BytePos, Span};--use crate::ast::Text;--#[derive(Debug, Clone, Copy)]-pub struct Input<'i> {- start: BytePos,- end: BytePos,- src: &'i str,-}--impl<'a> From<&'a Comment> for Input<'a> {- fn from(c: &'a Comment) -> Self {- Self::new(c.span.lo, c.span.hi, &c.text)- }-}--impl<'i> Input<'i> {- pub const fn empty() -> Self {- Self::new(BytePos::DUMMY, BytePos::DUMMY, "")- }-- pub const fn new(start: BytePos, end: BytePos, src: &'i str) -> Self {- Self { start, end, src }- }-- #[inline(always)]- pub fn span(self) -> Span {- Span::new(self.start, self.end)- }-}--macro_rules! impl_slice {- ($T:ident) => {- impl Slice<$T<usize>> for Input<'_> {- fn slice(&self, range: $T<usize>) -> Self {- let s = self.src.slice(range);-- Self::new(self.start, self.start + BytePos(s.as_bytes().len() as _), s)- }- }- };-}--impl_slice!(Range);-impl_slice!(RangeFrom);-impl_slice!(RangeTo);--impl From<Input<'_>> for Text {- fn from(i: Input) -> Self {- Self {- span: Span::new(i.start, i.end),- value: i.src.into(),- }- }-}--impl InputTake for Input<'_> {- fn take(&self, count: usize) -> Self {- self.slice(..count)- }-- fn take_split(&self, count: usize) -> (Self, Self) {- (self.slice(..count), self.slice(count..))- }-}--impl<'a> Compare<&'a str> for Input<'_> {- fn compare(&self, t: &'a str) -> CompareResult {- self.src.compare(t)- }-- fn compare_no_case(&self, t: &'a str) -> CompareResult {- self.src.compare_no_case(t)- }-}--impl InputLength for Input<'_> {- fn input_len(&self) -> usize {- self.src.len()- }-}--impl UnspecializedInput for Input<'_> {}--impl<'a> InputIter for Input<'a> {- type Item = char;- type Iter = CharIndices<'a>;- type IterElem = Chars<'a>;-- fn iter_indices(&self) -> Self::Iter {- self.src.iter_indices()- }-- fn iter_elements(&self) -> Self::IterElem {- self.src.iter_elements()- }-- fn position<P>(&self, predicate: P) -> Option<usize>- where- P: Fn(Self::Item) -> bool,- {- self.src.position(predicate)- }-- fn slice_index(&self, count: usize) -> Result<usize, Needed> {- self.src.slice_index(count)- }-}--impl Deref for Input<'_> {- type Target = str;-- fn deref(&self) -> &Self::Target {- self.src- }-}
deps/swc/crates/jsdoc/src/lib.rs
@@ -1,796 +0,0 @@-use nom::{- bytes::complete::{tag, take_while},- error::ErrorKind,- IResult, InputIter, Slice,-};-use swc_common::{Span, Spanned};--pub use self::input::Input;-use crate::ast::*;--pub mod ast;-mod input;--pub fn parse(i: Input) -> IResult<Input, JsDoc> {- let i = skip(i);-- let mut tags = Vec::new();- let lo = i.span().lo;- let (description, mut i) = take_while(|c| c != '@')(i)?;- let description = trim(description).into();-- i = skip(i);-- while i.starts_with('@') {- let (input, tag) = parse_tag_item(i)?;- i = input;- tags.push(tag);- i = skip(i);- }-- let hi = i.span().hi;- Ok((- i,- JsDoc {- span: Span::new(lo, hi),- tags,- description,- },- ))-}--pub fn parse_tag_item(i: Input) -> IResult<Input, TagItem> {- let i = skip(i);- let (_, i) = tag("@")(i)?;-- let (mut i, tag_name) = parse_word(i)?;- i = skip_ws(i);-- let span = tag_name.span();- let tag = match &*tag_name.value {- "abstract" | "virtual" => Tag::Abstract(AbstractTag { span }),-- "access" => {- let (input, access) = parse_one_of(i, &["private", "protected", "package", "public"])?;- i = input;- Tag::Access(AccessTag { span, access })- }-- "alias" => {- let (input, name_path) = parse_name_path(i)?;- i = input;- Tag::Alias(AliasTag { span, name_path })- }-- "async" => Tag::Async(AsyncTag { span }),-- "augments" | "extends" => {- let (input, name_path) = parse_name_path(i)?;- i = input;- Tag::Augments(AugmentsTag {- span,- class: name_path,- })- }-- "author" => {- let (input, author) = parse_line(i)?;- i = input;- Tag::Author(AuthorTag { span, author })- }-- "borrows" => {- let (input, from) = parse_name_path(i)?;- let (_, input) = tag("as")(input)?;- let (input, to) = parse_name_path(input)?;- i = input;- Tag::Borrows(BorrowsTag { span, from, to })- }-- "callback" => {- let (input, name_path) = parse_name_path(i)?;- i = input;- Tag::Callback(CallbackTag { span, name_path })- }-- "class" | "constructor" => {- // TODO: name is must if ty is some- let (input, ty) = parse_opt_str(i)?;- let (input, name) = parse_opt_str(input)?;- i = input;-- Tag::Class(ClassTag { span, ty, name })- }-- "classdesc" => {- let (input, desc) = parse_line(i)?;- i = input;-- Tag::ClassDesc(JSDocClassDescTag { span, desc })- }-- "constant" | "const" => {- // TODO: name is must if ty is some- let (input, ty) = parse_opt_str(i)?;- let (input, name) = parse_opt_str(input)?;- i = input;- Tag::Const(ConstTag { span, ty, name })- }-- "constructs" => {- let (input, name) = parse_line(i)?;- i = input;- Tag::Constructs(ConstructsTag { span, name })- }-- "copyright" => {- let (input, text) = parse_line(i)?;- i = input;- Tag::Copyright(CopyrightTag { span, text })- }-- "default" | "defaultvalue" => {- let (input, value) = parse_line(i)?;- i = input;- Tag::Default(DefaultTag { span, value })- }-- "deprecated" => {- let (input, text) = parse_line(i)?;- i = input;- Tag::Deprecated(DeprecatedTag { span, text })- }-- "description" | "desc" => {- let (input, text) = parse_line(i)?;- i = input;- Tag::Description(DescriptionTag { span, text })- }-- "enum" => {- let (input, ty) = parse_type(i)?;- i = input;- Tag::Enum(EnumTag { span, ty })- }-- "event" => {- // TODO: implement this- let (input, ty) = parse_line(i)?;- i = input;- Tag::Unknown(UnknownTag { span, extras: ty })- }-- "example" => {- let (text, input) = take_while(|c| c != '@')(i)?;- i = input;- Tag::Example(ExampleTag {- span,- text: text.into(),- })- }-- "exports" => {- let (input, text) = parse_line(i)?;- i = input;- Tag::Exports(ExportsTag {- span,- module_name: text,- })- }-- "external" | "host" => {- let (input, name) = parse_line(i)?;- i = input;- Tag::External(ExternalTag { span, name })- }-- "file" | "fileoverview" | "overview" => {- let (input, text) = parse_line(i)?;- i = input;- Tag::File(FileTag { span, text })- }-- "fires" | "emits" => {- // TODO: implement this- let (input, ty) = parse_line(i)?;- i = input;- Tag::Unknown(UnknownTag { span, extras: ty })- }-- "function" | "func" | "method" => {- let (input, name) = parse_opt_str(i)?;- i = input;- Tag::Function(FunctionTag { span, name })- }-- "generator" => Tag::Generator(GeneratorTag { span }),-- "hideconstructor" => Tag::HideConstructor(HideConstructorTag { span }),-- "ignore" => Tag::Ignore(IgnoreTag { span }),-- "implements" => {- let (input, class) = parse_type(i)?;- i = input;- Tag::Implements(ImplementsTag { span, class })- }-- "inheritdoc" => Tag::InheritDoc(InheritDocTag { span }),-- "inner" => Tag::Inner(InnerTag { span }),-- "instance" => Tag::Instance(InstanceTag { span }),-- "interface" => {- let (input, name) = parse_opt_str(i)?;- i = input;- Tag::Interface(InterfaceTag { span, name })- }-- "kind" => {- let (input, name) = parse_one_of(- i,- &[- "class",- "constant",- "event",- "external",- "file",- "function",- "member",- "mixin",- "module",- "namespace",- "typedef",- ],- )?;- i = input;- Tag::Kind(KindTag { span, name })- }-- "lends" => {- let (input, name) = parse_name_path(i)?;- i = input;- Tag::Lends(LendsTag { span, name })- }-- "license" => {- let (input, identifier) = parse_line(i)?;- i = input;- Tag::License(LicenseTag { span, identifier })- }-- "listens" => {- let (input, event_name) = parse_line(i)?;- i = input;- Tag::Listens(ListensTag { span, event_name })- }-- "member" | "var" => {- let (input, ty) = parse_word(i)?;- let (input, name) = parse_word(input)?;- i = input;- Tag::Member(MemberTag { span, ty, name })- }-- "memberof" | "memberof!" => {- let (input, parent_name_path) = parse_name_path(i)?;- i = input;- Tag::MemberOf(MemberOfTag {- span,- parent_name_path,- })- }-- "mixes" => {- let (input, name_path) = parse_name_path(i)?;- i = input;- Tag::Mixes(MixesTag { span, name_path })- }-- "mixin" => {- let (input, name) = parse_line(i)?;- i = input;- Tag::Mixin(MixinTag { span, name })- }-- "module" => {- let (input, ty) = parse_word(i)?;- let (input, name) = parse_line(input)?;- i = input;- Tag::Module(ModuleTag { span, ty, name })- }-- "name" => {- let (input, name_path) = parse_name_path(i)?;- i = input;- Tag::Name(NameTag { span, name_path })- }-- "namespace" => {- let (input, ty) = parse_opt_type(i)?;- let (input, name) = parse_opt_str(input)?;- i = input;- Tag::Namespace(NamespaceTag { span, ty, name })- }-- "override" => Tag::Override(OverrideTag { span }),-- "package" => {- let (input, ty) = parse_opt_type(i)?;- i = input;- Tag::Package(PackageTag { span, ty })- }-- "param" | "arg" | "argument" => {- let (input, ty) = parse_opt_type(i)?;- let (input, name) = parse_opt_word(input)?;- let (input, desc) = parse_line(input)?;- i = input;- Tag::Parameter(ParameterTag {- span,- ty,- name,- desc,- })- }-- "private" => {- let (input, ty) = parse_opt_type(i)?;- i = input;- Tag::Private(PrivateTag { span, ty })- }-- "property" | "prop" => {- let (input, ty) = parse_opt_type(i)?;- let (input, name_path) = parse_name_path(input)?;- let (input, desc) = parse_line(input)?;- i = input;- Tag::Property(PropertyTag {- span,- ty,- name_path,- desc,- })- }-- "protected" => {- let (input, ty) = parse_opt_type(i)?;- i = input;- Tag::Protected(ProtectedTag { span, ty })- }-- "public" => Tag::Public(PublicTag { span }),-- "readonly" => Tag::Readonly(ReadonlyTag { span }),-- "requires" => {- let (input, name_path) = parse_name_path(i)?;- i = input;- Tag::Requires(RequiresTag { span, name_path })- }-- "returns" | "return" => {- let (input, ty) = parse_opt_type(i)?;- let (input, description) = parse_line(input)?;- i = input;- Tag::Return(ReturnTag {- span,- ty,- description,- })- }-- "see" => {- let (input, text) = parse_line(i)?;- i = input;- Tag::See(SeeTag { span, text })- }-- "since" => {- let (input, version) = parse_line(i)?;- i = input;- Tag::Since(SinceTag { span, version })- }-- "static" => Tag::Static(StaticTag { span }),-- "summary" => {- let (input, text) = parse_line(i)?;- i = input;- Tag::Summary(SummaryTag { span, text })- }-- "this" => {- let (input, name_path) = parse_name_path(i)?;- i = input;- Tag::This(ThisTag { span, name_path })- }-- "throws" => {- let (input, text) = parse_line(i)?;- i = input;- Tag::Throw(ThrowTag { span, text })- }-- "todo" => {- let (input, text) = parse_line(i)?;- i = input;- Tag::Todo(TodoTag { span, text })- }-- "tutorial" => {- let (input, text) = parse_line(i)?;- i = input;- Tag::Tutorial(TutorialTag { span, text })- }-- "type" => {- let (input, name) = parse_line(i)?;- i = input;- Tag::Type(TypeTag { span, name })- }-- "typedef" => {- let (input, ty) = parse_opt_type(i)?;- let (input, name_path) = parse_name_path(input)?;- i = input;- Tag::TypeDef(TypeDefTag {- span,- ty,- name_path,- })- }-- "variation" => {- let (input, number) = parse_line(i)?;- i = input;- Tag::Variation(VariationTag { span, number })- }-- "version" => {- let (input, value) = parse_line(i)?;- i = input;- Tag::Version(VersionTag { span, value })- }-- "yields" | "yield" => {- let (input, value) = parse_opt_type(i)?;- let (input, description) = parse_line(input)?;- i = input;- Tag::Yield(YieldTag {- span,- value,- description,- })- }-- _ => {- let (input, extras) = parse_str(i)?;- i = input;- Tag::Unknown(UnknownTag { span, extras })- }- };-- Ok((- i,- TagItem {- span,- tag_name,- tag,- },- ))-}--fn parse_opt_str(i: Input) -> IResult<Input, Option<Text>> {- let (i, res) = parse_line(i)?;-- if res.value.is_empty() {- Ok((i, None))- } else {- Ok((i, Some(res)))- }-}--fn parse_str(i: Input) -> IResult<Input, Text> {- parse_line(i)-}--fn parse_type(i: Input) -> IResult<Input, Text> {- parse_line(i)-}--// ----- ----- Done ----- -------fn trim(i: Input) -> Input {- let prev_len = i.len();- let new_str = i.trim_start();-- let start = prev_len - new_str.len();-- let end = i.trim_end().len();-- if start >= end {- return i;- }-- i.slice(start..end)-}--fn parse_opt_type(i: Input) -> IResult<Input, Option<Text>> {- let i = skip_ws(i);- if i.starts_with('{') {- if let Some(pos) = i.find('}') {- let ret = i.slice(..pos + 1);- let i = i.slice(pos + 1..);- return Ok((i, Some(ret.into())));- }- }-- parse_opt_word(i)-}--fn parse_one_of<'i>(i: Input<'i>, list: &[&str]) -> IResult<Input<'i>, Text> {- for &item in list {- if i.starts_with(item) {- let res = tag::<&str, Input<'_>, (_, ErrorKind)>(item)(i);- match res {- Ok(v) => return Ok((v.1, v.0.into())),- Err(..) => continue,- }- }- }-- Err(nom::Err::Error(nom::error::Error::new(i, ErrorKind::Tag)))-}--fn parse_name_path(mut i: Input) -> IResult<Input, NamePath> {- let lo = i.span().lo;- let mut components = Vec::new();-- loop {- let (input, component) = parse_word(i)?;- components.push(component);- i = input;-- let (_, input) = match tag(".")(i) {- Ok(v) => v,- Err(err) => {- if components.is_empty() {- return Err(err);- }-- return Ok((- i,- NamePath {- span: Span::new(lo, i.span().hi),- components,- },- ));- }- };- i = input;- }-}--fn parse_opt_word(i: Input) -> IResult<Input, Option<Text>> {- let (i, v) = parse_word(i)?;- if v.value.is_empty() {- return Ok((i, None));- }-- Ok((i, Some(v)))-}--fn parse_word(i: Input) -> IResult<Input, Text> {- let res = i.iter_indices().find(|(_, c)| {- !(('a' <= *c && *c <= 'z') || ('A' <= *c && *c <= 'Z' || *c == '<' || *c == '>'))- });-- if let Some((idx, _)) = res {- let rest = i.slice(idx + 1..);- let ret = i.slice(..idx);-- Ok((rest, ret.into()))- } else {- // Everything was alphabet- Ok((Input::empty(), i.into()))- }-}--fn parse_line(i: Input) -> IResult<Input, Text> {- let i = skip_ws(i);- let res = i.iter_indices().find(|(_, c)| *c == '\n' || *c == '\r');-- if let Some((idx, _)) = res {- let rest = i.slice(idx + 1..);- let ret = i.slice(..idx);-- Ok((rest, ret.into()))- } else {- Ok((i, Input::empty().into()))- }-}--/// Skips whitespace-///-/// This function does not handle newline nor *.-fn skip_ws(i: Input) -> Input {- let mut index = 0;-- for (idx, c) in i.char_indices() {- if c == ' ' {- index = idx + 1;- continue;- }-- break;- }-- i.slice(index..)-}--/// Skips whitespace and * at line start-fn skip(i: Input) -> Input {- //-- let mut at_line_start = true;- let mut index = 0;-- for (idx, c) in i.char_indices() {- if at_line_start && c == '*' {- at_line_start = false;- index = idx + 1;- continue;- }-- if c == '\r' || c == '\n' {- at_line_start = true;- index = idx + 1;- continue;- }-- if c == ' ' {- index = idx + 1;- continue;- }-- break;- }-- i.slice(index..)-}--#[cfg(test)]-mod tests {- use swc_common::BytePos;-- use super::*;-- fn input(s: &str) -> Input<'_> {- Input::new(BytePos(0), BytePos(s.len() as _), s)- }-- #[test]- fn issue_1058() {- let (i, ret) = parse(input(- r#"- *- * @param list - LinkedList<T>- * @example <caption>Linkedlists.compareWith</caption>- * import { LinkedList } from './js_test/linkedlist.ts'- * const testArr = [1, 2, 3, 4, 5, 6, 78, 9, 0, 65];- * const firstList = new LinkedList<number>();- * const secondList = new LinkedList<number>();- * for (let data of testArr) {- * firstList.insertNode(data);- * secondList.insertNode(data);- * }- * const result = firstList.compareWith(secondList);- * assert(result);- * @returns boolean- "#,- ))- .unwrap();-- assert_eq!(&*skip(i), "");- assert_eq!(ret.tags.len(), 3);- }-- #[test]- fn access_tag() {- let (i, ret) = parse(input(- " Give x another name.- @alias myObject- @namespace- ",- ))- .unwrap();-- assert_eq!(&*ret.description.value, "Give x another name.");- assert_eq!(ret.tags.len(), 2);- assert_eq!(&*skip(i), "");- }-- #[test]- fn abstract_tag() {- let (i, ret) = parse_tag_item(input(- "- * @abstract ",- ))- .unwrap();-- match ret.tag {- Tag::Abstract(..) => {}- _ => panic!("Invalid tag: {:?}", ret.tag),- }-- assert_eq!(&*skip(i), "");- }-- #[test]- fn yield_tag_1() {- let (i, ret) = parse_tag_item(input(- "- *- * @yields {number} The next number in the Fibonacci sequence.- ",- ))- .unwrap();-- match ret.tag {- Tag::Yield(tag) => {- assert_eq!(tag.value.as_ref().map(|v| &*v.value), Some("{number}"));- assert_eq!(- &*tag.description.value,- "The next number in the Fibonacci sequence."- );- }- _ => panic!("Invalid tag: {:?}", ret.tag),- }-- assert_eq!(&*skip(i), "");- }-- #[test]- fn trim_1() {- assert_eq!(&*trim(input(" foo ")), "foo");- assert_eq!(&*trim(input("foo ")), "foo");- assert_eq!(&*trim(input(" foo")), "foo");- }-- #[test]- fn skip_1() {- let i = skip(input(- "- *- * @yields ",- ));-- assert_eq!(&*i, "@yields ");- }-- #[test]- fn one_of_1() {- let (rest, ret) = parse_one_of(input("foo bar\nbaz"), &["fo", "bar"]).unwrap();-- assert_eq!(&*ret.value, "fo");- assert_eq!(&*rest, "o bar\nbaz");- }-- #[test]- fn line_1() {- let (rest, ret) = parse_line(input("foo bar\nbaz")).unwrap();-- assert_eq!(&*ret.value, "foo bar");- assert_eq!(&*rest, "baz");- }-- #[test]- fn word_1() {- let (rest, ret) = parse_word(input("foo bar\nbaz")).unwrap();-- assert_eq!(&*ret.value, "foo");- assert_eq!(&*rest, "bar\nbaz");- }-}
deps/swc/crates/preset_env_base/Cargo.toml
@@ -1,25 +0,0 @@-[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>"]-description = "Common logic for targetting vairous browsers"-documentation = "https://rustdoc.swc.rs/preset_env_base/"-edition = { workspace = true }-license = { workspace = true }-name = "preset_env_base"-repository = { workspace = true }-version = "10.0.0"--[lib]-bench = false--[dependencies]-anyhow = { workspace = true }-browserslist-rs = { workspace = true }-dashmap = { workspace = true }-once_cell = { workspace = true }-rustc-hash = { workspace = true }-semver = { workspace = true, features = ["serde"] }-serde = { workspace = true, features = ["derive"] }-st-map = { workspace = true }-tracing = { workspace = true }--from_variant = { version = "3.0.0", path = "../from_variant" }
deps/swc/crates/preset_env_base/src/lib.rs
@@ -1,150 +0,0 @@-//! Base crate for `preset-env`-like crates.-//!-//! This crate provides an interface to convert `browserslist` query to-//! something usable.--use anyhow::Error;-use serde::{Deserialize, Serialize};-use st_map::StaticMap;--use self::version::Version;--pub mod query;-pub mod version;--/// A map without allocation.-#[derive(Debug, Default, Deserialize, Clone, Copy, Serialize, StaticMap, PartialEq, Eq)]-#[serde(deny_unknown_fields)]-pub struct BrowserData<T: Default> {- #[serde(default)]- pub chrome: T,- #[serde(default, rename = "chrome-android")]- pub chrome_android: T,- #[serde(default, rename = "firefox-android")]- pub firefox_android: T,- #[serde(default, rename = "opera-android")]- pub opera_android: T,-- #[serde(default)]- pub quest: T,- #[serde(default, rename = "react-native")]- pub react_native: T,-- #[serde(default)]- pub and_chr: T,- #[serde(default)]- pub and_ff: T,- #[serde(default)]- pub op_mob: T,- #[serde(default)]- pub ie: T,- #[serde(default)]- pub edge: T,- #[serde(default)]- pub firefox: T,- #[serde(default)]- pub safari: T,- #[serde(default)]- pub node: T,- #[serde(default)]- pub ios: T,- #[serde(default)]- pub samsung: T,- #[serde(default)]- pub opera: T,- #[serde(default)]- pub android: T,- #[serde(default)]- pub electron: T,- #[serde(default)]- pub phantom: T,- #[serde(default)]- pub opera_mobile: T,- #[serde(default)]- pub rhino: T,- #[serde(default)]- pub deno: T,- #[serde(default)]- pub hermes: T,- #[serde(default)]- pub oculus: T,- #[serde(default)]- pub bun: T,-}--impl<T> BrowserData<T>-where- T: Default,-{- pub fn insert(&mut self, k: &str, v: T) -> T {- for (key, value) in self.iter_mut() {- if k == key {- return std::mem::replace(value, v);- }- }-- panic!("unknown key: {k}")- }-}--/// A map of browser names to data for feature support in browser.-///-/// This type mainly stores `minimum version for each browsers with support for-/// a feature`.-pub type Versions = BrowserData<Option<Version>>;--impl BrowserData<Option<Version>> {- /// Returns true if all fields are [None].- pub fn is_any_target(&self) -> bool {- self.iter().all(|(_, v)| v.is_none())- }-- /// Parses the value returned from `browserslist` as [Versions].- pub fn parse_versions(distribs: Vec<browserslist::Distrib>) -> Result<Self, Error> {- fn remap(key: &str) -> &str {- match key {- "and_chr" => "chrome",- "and_ff" => "firefox",- "ie_mob" => "ie",- "ios_saf" => "ios",- "op_mob" => "opera",- _ => key,- }- }-- let mut data: Versions = BrowserData::default();- for dist in distribs {- let browser = dist.name();- let browser = remap(browser);- let version = dist.version();- match browser {- "and_qq" | "and_uc" | "baidu" | "bb" | "kaios" | "op_mini" => continue,-- _ => {}- }-- let version = version- .split_once('-')- .map(|(version, _)| version)- .unwrap_or(version)- .parse()- .ok();-- let version = match version {- Some(v) => v,- None => continue,- };-- // lowest version- if data[&browser].map(|v| v > version).unwrap_or(true) {- for (k, v) in data.iter_mut() {- if browser == k {- *v = Some(version);- }- }- }- }-- Ok(data)- }-}
deps/swc/crates/preset_env_base/src/query.rs
@@ -1,259 +0,0 @@-//! Module for `browserslist` queries.-#![deny(clippy::all)]--use std::{collections::HashMap, path::PathBuf, sync::Arc};--use anyhow::{anyhow, Context, Error};-use dashmap::DashMap;-use from_variant::FromVariant;-use once_cell::sync::Lazy;-use rustc_hash::FxBuildHasher;-use serde::Deserialize;--use crate::{version::Version, BrowserData, Versions};--/// Result of resolving browser targets.-#[derive(Debug, Clone)]-pub struct TargetInfo {- /// The resolved browser versions.- pub versions: Arc<Versions>,- /// True if the browserslist query returned an empty result (unknown browser- /// version). When this is true, we should assume the browser is a- /// recent version that supports all modern features (no transforms- /// needed), similar to Babel's behavior.- pub unknown_version: bool,-}--#[derive(Debug, Clone, Deserialize, FromVariant)]-#[serde(untagged)]-#[allow(clippy::large_enum_variant)]-pub enum Targets {- Query(Query),- EsModules(EsModules),- Versions(Versions),- HashMap(HashMap<String, QueryOrVersion, FxBuildHasher>),-}--#[derive(Debug, Clone, Copy, Deserialize)]-pub struct EsModules {- #[allow(dead_code)]- esmodules: bool,-}--#[derive(Debug, Clone, Deserialize, FromVariant)]-#[serde(untagged)]-pub enum QueryOrVersion {- Query(Query),- Version(Version),-}--#[derive(Debug, Clone, Deserialize, FromVariant, Eq, PartialEq, PartialOrd, Ord, Hash)]-#[serde(untagged)]-pub enum Query {- Single(String),- Multiple(Vec<String>),-}--/// Internal query result containing both versions and whether the query-/// returned empty.-type InternalQueryResult = Result<(Arc<Versions>, bool), Error>;--impl Query {- fn exec(&self) -> InternalQueryResult {- fn query<T>(s: &[T]) -> InternalQueryResult- where- T: AsRef<str>,- {- let distribs = browserslist::resolve(- s,- &browserslist::Opts {- mobile_to_desktop: true,- ignore_unknown_versions: true,- ..Default::default()- },- )- .with_context(|| {- format!(- "failed to resolve browserslist query: {:?}",- s.iter().map(|v| v.as_ref()).collect::<Vec<_>>()- )- })?;-- // Track if the browserslist query returned empty (unknown version).- // When this happens, we should treat it as a recent browser version- // that supports all features, not apply all transforms.- let unknown_version = distribs.is_empty();-- let versions =- BrowserData::parse_versions(distribs).expect("failed to parse browser version");-- Ok((Arc::new(versions), unknown_version))- }-- static CACHE: Lazy<DashMap<Query, (Arc<Versions>, bool), FxBuildHasher>> =- Lazy::new(Default::default);-- if let Some(v) = CACHE.get(self) {- return Ok(v.clone());- }-- let result = match *self {- Query::Single(ref s) => {- if s.is_empty() {- query(&["defaults"])- } else {- query(&[s])- }- }- Query::Multiple(ref s) => query(s),- }- .context("failed to execute query")?;-- CACHE.insert(self.clone(), result.clone());-- Ok(result)- }-}--pub fn targets_to_versions(v: Option<Targets>, path: Option<PathBuf>) -> Result<TargetInfo, Error> {- match v {- #[cfg(not(target_arch = "wasm32"))]- None => {- let mut browserslist_opts = browserslist::Opts {- mobile_to_desktop: true,- ignore_unknown_versions: true,- ..Default::default()- };- if let Some(path) = path {- browserslist_opts.path = path- .clone()- .into_os_string()- .into_string()- .map_err(|_| anyhow!("Invalid path \"{path:?}\""))?- .into();- }- let distribs = browserslist::execute(&browserslist_opts)- .with_context(|| "failed to resolve browserslist query from browserslist config")?;-- // When targets is None, it means the user didn't specify any targets.- // We use browserslist config or defaults, so we should NOT treat empty- // results as "unknown version". That case is for when a user explicitly- // specifies a query like "Chrome > 99999" that returns empty.- let versions = BrowserData::parse_versions(distribs)- .with_context(|| "failed to parse browser version")?;-- Ok(TargetInfo {- versions: Arc::new(versions),- unknown_version: false,- })- }- #[cfg(target_arch = "wasm32")]- None => Ok(TargetInfo {- versions: Default::default(),- unknown_version: false,- }),- Some(Targets::Versions(v)) => Ok(TargetInfo {- versions: Arc::new(v),- unknown_version: false,- }),- Some(Targets::Query(q)) => {- let (versions, unknown_version) = q- .exec()- .context("failed to convert target query to version data")?;- Ok(TargetInfo {- versions,- unknown_version,- })- }- Some(Targets::HashMap(mut map)) => {- let q = map.remove("browsers").map(|q| match q {- QueryOrVersion::Query(q) => q.exec().expect("failed to run query"),- _ => unreachable!(),- });-- let node = map.remove("node").map(|q| match q {- QueryOrVersion::Version(v) => v,- QueryOrVersion::Query(..) => unreachable!(),- });-- // Track if any query returned empty (unknown version)- let mut unknown_version = false;-- if map.is_empty() {- if let Some((versions, is_unknown)) = q {- let mut versions = *versions;- versions.node = node;- unknown_version = is_unknown;- return Ok(TargetInfo {- versions: Arc::new(versions),- unknown_version,- });- }- }-- let mut result = Versions::default();- for (k, v) in map.iter() {- match v {- QueryOrVersion::Query(q) => {- let (versions, is_unknown) = q.exec().context("failed to run query")?;- unknown_version = unknown_version || is_unknown;-- for (k, v) in versions.iter() {- result.insert(k, *v);- }- }- QueryOrVersion::Version(v) => {- result.insert(k, Some(*v));- }- }- }-- unimplemented!("Targets: {:?}", map)- }- _ => unimplemented!("Option<Targets>: {:?}", v),- }-}--#[cfg(test)]-mod tests {- use super::Query;-- #[test]- fn test_empty() {- let (res, unknown_version) = Query::Single("".into()).exec().unwrap();- assert!(- !res.is_any_target(),- "empty query should return non-empty result"- );- assert!(- !unknown_version,- "empty query should not be unknown version"- );- }-- #[test]- fn test_node_20_19() {- let (res, unknown_version) = Query::Single("node 20.19".into()).exec().unwrap();- let node_version = res.node.expect("node version should be resolved");- assert_eq!(node_version.major, 20, "major version should be 20");- assert_eq!(node_version.minor, 19, "minor version should be 19");- assert!(- !unknown_version,- "known node version should not be unknown version"- );- }-- #[test]- fn test_unknown_chrome_version() {- // Chrome 999 is an unknown version, browserslist should return empty- let (res, unknown_version) = Query::Single("Chrome > 9999999".into()).exec().unwrap();- assert!(- res.is_any_target(),- "unknown chrome version should return empty result"- );- assert!(- unknown_version,- "unknown chrome version should be marked as unknown"- );- }-}
deps/swc/crates/preset_env_base/src/version.rs
@@ -1,214 +0,0 @@-//! Module for browser versions--use std::{cmp, cmp::Ordering, fmt, str::FromStr};--use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize};-#[cfg(debug_assertions)]-use tracing::warn;--use crate::Versions;--/// A version of a browser.-///-/// This is similar to semver, but this assumes a production build. (No tag like-/// `alpha`)-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]-pub struct Version {- /// `a` in `a.b.c`- pub major: u32,- /// `b` in `a.b.c`- pub minor: u32,- /// `c` in `a.b.c`- pub patch: u32,-}--impl FromStr for Version {- type Err = ();-- fn from_str(v: &str) -> Result<Self, Self::Err> {- if !v.contains('.') {- return Ok(Version {- major: v.parse().map_err(|err| {- #[cfg(debug_assertions)]- warn!("failed to parse `{}` as a version: {}", v, err);- #[cfg(not(debug_assertions))]- let _ = err;- })?,- minor: 0,- patch: 0,- });- }-- if v.split('.').count() == 2 {- let mut s = v.split('.');- return Ok(Version {- major: s.next().unwrap().parse().unwrap(),- minor: s.next().unwrap().parse().unwrap(),- patch: 0,- });- }-- let v = v.parse::<semver::Version>().map_err(|err| {- #[cfg(debug_assertions)]- warn!("failed to parse `{}` as a version: {}", v, err);- #[cfg(not(debug_assertions))]- let _ = err;- })?;-- Ok(Version {- major: v.major as _,- minor: v.minor as _,- patch: v.patch as _,- })- }-}--impl cmp::PartialOrd for Version {- fn partial_cmp(&self, other: &Version) -> Option<Ordering> {- Some(self.cmp(other))- }-}--impl cmp::Ord for Version {- fn cmp(&self, other: &Version) -> Ordering {- match self.major.cmp(&other.major) {- Ordering::Equal => {}- r => return r,- }-- match self.minor.cmp(&other.minor) {- Ordering::Equal => {}- r => return r,- }-- match self.patch.cmp(&other.patch) {- Ordering::Equal => {}- r => return r,- }-- Ordering::Equal- }-}--struct SerdeVisitor;--impl<'de> Visitor<'de> for SerdeVisitor {- type Value = Version;-- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {- formatter.write_str("a browser version")- }-- fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>- where- E: de::Error,- {- Ok(Version {- major: v as _,- minor: 0,- patch: 0,- })- }-- fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>- where- E: de::Error,- {- Ok(Version {- major: v as _,- minor: 0,- patch: 0,- })- }-- fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>- where- E: de::Error,- {- Ok(Version {- major: v.floor() as _,- minor: v.fract() as _,- patch: 0,- })- }-- fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>- where- E: de::Error,- {- v.parse()- .map_err(|_| de::Error::invalid_type(de::Unexpected::Str(v), &self))- }-- #[inline]- fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>- where- E: de::Error,- {- self.visit_str(v)- }-- fn visit_string<E>(self, v: String) -> Result<Self::Value, E>- where- E: de::Error,- {- self.visit_str(&v)- }-}--impl<'de> Deserialize<'de> for Version {- fn deserialize<D>(deserializer: D) -> Result<Version, D::Error>- where- D: Deserializer<'de>,- {- deserializer.deserialize_any(SerdeVisitor)- }-}--pub fn should_enable(target: &Versions, feature: &Versions, default: bool) -> bool {- if target- .iter()- .zip(feature.iter())- .all(|((_, target_version), (_, f))| target_version.is_none() && f.is_none())- {- return default;- }-- target.iter().zip(feature.iter()).any(- |((target_name, maybe_target_version), (_, maybe_feature_version))| {- maybe_target_version.is_some_and(|target_version| {- let feature_or_fallback_version =- maybe_feature_version.or_else(|| match target_name {- // Fall back to Chrome versions if Android browser data- // is missing from the feature data. It appears the- // Android browser has aligned its versioning with Chrome.- "android" => feature.chrome,- _ => None,- });-- feature_or_fallback_version.map_or(true, |v| v > target_version)- })- },- )-}--#[cfg(test)]-mod tests {- use super::*;- use crate::BrowserData;-- #[test]- fn should_enable_android_falls_back_to_chrome() {- assert!(!should_enable(- &BrowserData {- android: Some("51.0.0".parse().unwrap()),- ..Default::default()- },- &BrowserData {- chrome: Some("51.0.0".parse().unwrap()),- ..Default::default()- },- false- ));- }-}
deps/swc/crates/string_enum/Cargo.toml
@@ -1,23 +0,0 @@-[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>"]-description = "String based enum."-documentation = "https://rustdoc.swc.rs/string_enum/"-edition = { workspace = true }-license = { workspace = true }-name = "string_enum"-repository = { workspace = true }-version = "1.0.2"--[lib]-bench = false-proc-macro = true--[dependencies]-quote = { workspace = true }-swc_macros_common = { version = "1.0.1", path = "../swc_macros_common" }-[dependencies.syn]-features = ["full", "parsing", "printing", "extra-traits"]-workspace = true--[dev-dependencies]-serde = { workspace = true }
deps/swc/crates/string_enum/src/lib.rs
@@ -1,369 +0,0 @@-#![recursion_limit = "1024"]--extern crate proc_macro;--use quote::quote_spanned;-use swc_macros_common::prelude::*;-use syn::{parse::Parse, *};--/// Creates `.as_str()` and then implements `Debug` and `Display` using it.-///-///# Input-/// Enum with \`str_value\`-style **doc** comment for each variant.-///-/// e.g.-///-///```no_run-/// pub enum BinOp {-/// /// `+`-/// Add,-/// /// `-`-/// Minus,-/// }-/// ```-///-/// Currently, \`str_value\` must be live in it's own line.-///-///# Output-///-/// - `pub fn as_str(&self) -> &'static str`-/// - `impl serde::Serialize` with `cfg(feature = "serde")`-/// - `impl serde::Deserialize` with `cfg(feature = "serde")`-/// - `impl FromStr`-/// - `impl Debug`-/// - `impl Display`-///-///# Example-///-///-///```-/// #[macro_use]-/// extern crate string_enum;-/// extern crate serde;-///-/// #[derive(StringEnum)]-/// pub enum Tokens {-/// /// `a`-/// A,-/// /// `bar`-/// B,-/// }-/// # fn main() {-///-/// assert_eq!(Tokens::A.as_str(), "a");-/// assert_eq!(Tokens::B.as_str(), "bar");-///-/// assert_eq!(Tokens::A.to_string(), "a");-/// assert_eq!(format!("{:?}", Tokens::A), format!("{:?}", "a"));-///-/// # }-/// ```-///-///-/// All formatting flags are handled correctly.-#[proc_macro_derive(StringEnum, attributes(string_enum))]-pub fn derive_string_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {- let input = syn::parse::<syn::DeriveInput>(input).expect("failed to parse derive input");- let mut tts = TokenStream::new();-- make_as_str(&input).to_tokens(&mut tts);- make_from_str(&input).to_tokens(&mut tts);-- make_serialize(&input).to_tokens(&mut tts);- make_deserialize(&input).to_tokens(&mut tts);-- derive_fmt(&input, quote_spanned!(Span::call_site() => std::fmt::Debug)).to_tokens(&mut tts);- derive_fmt(- &input,- quote_spanned!(Span::call_site() => std::fmt::Display),- )- .to_tokens(&mut tts);-- print("derive(StringEnum)", tts)-}--fn derive_fmt(i: &DeriveInput, trait_path: TokenStream) -> ItemImpl {- let ty = &i.ident;-- let item: ItemImpl = parse_quote!(- impl #trait_path for #ty {- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {- let s = self.as_str();- #trait_path::fmt(s, f)- }- }- );-- item.with_generics(i.generics.clone())-}--fn get_str_value(attrs: &[Attribute]) -> String {- // TODO: Accept multiline string- let docs: Vec<_> = attrs.iter().filter_map(doc_str).collect();- for raw_line in docs {- let line = raw_line.trim();- if line.starts_with('`') && line.ends_with('`') {- let mut s: String = line.split_at(1).1.into();- let new_len = s.len() - 1;- s.truncate(new_len);- return s;- }- }-- panic!("StringEnum: Cannot determine string value of this variant")-}--fn make_from_str(i: &DeriveInput) -> ItemImpl {- let arms = Binder::new_from(i)- .variants()- .into_iter()- .map(|v| {- // Qualified path of variant.- let qual_name = v.qual_path();-- let str_value = get_str_value(v.attrs());-- let mut pat: Pat = Pat::Lit(ExprLit {- attrs: Default::default(),- lit: Lit::Str(LitStr::new(&str_value, Span::call_site())),- });-- // Handle `string_enum(alias("foo"))`- for attr in v- .attrs()- .iter()- .filter(|attr| is_attr_name(attr, "string_enum"))- {- if let Meta::List(meta) = &attr.meta {- let mut cases = Punctuated::default();-- cases.push(pat);-- for item in parse2::<FieldAttr>(meta.tokens.clone())- .expect("failed to parse `#[string_enum]`")- .aliases- {- cases.push(Pat::Lit(PatLit {- attrs: Default::default(),- lit: Lit::Str(item.alias),- }));- }-- pat = Pat::Or(PatOr {- attrs: Default::default(),- leading_vert: None,- cases,- });- continue;- }-- panic!("Unsupported meta: {:#?}", attr.meta);- }-- let body = match *v.data() {- Fields::Unit => Box::new(parse_quote!(return Ok(#qual_name))),- _ => unreachable!("StringEnum requires all variants not to have fields"),- };-- Arm {- body,- attrs: v- .attrs()- .iter()- .filter(|attr| is_attr_name(attr, "cfg"))- .cloned()- .collect(),- pat,- guard: None,- fat_arrow_token: Default::default(),- comma: Some(Token)),- }- })- .chain(::std::iter::once(parse_quote!(_ => Err(()))))- .collect();-- let body = Expr::Match(ExprMatch {- attrs: Default::default(),- match_token: Default::default(),- brace_token: Default::default(),- expr: Box::new(parse_quote!(s)),- arms,- });-- let ty = &i.ident;- let item: ItemImpl = parse_quote!(- impl ::std::str::FromStr for #ty {- type Err = ();-- fn from_str(s: &str) -> Result<Self, ()> {- #body- }- }- );- item.with_generics(i.generics.clone())-}--fn make_as_str(i: &DeriveInput) -> ItemImpl {- let arms = Binder::new_from(i)- .variants()- .into_iter()- .map(|v| {- // Qualified path of variant.- let qual_name = v.qual_path();-- let str_value = get_str_value(v.attrs());-- let body = Box::new(parse_quote!(return #str_value));-- let pat = match *v.data() {- Fields::Unit => Box::new(Pat::Path(PatPath {- qself: None,- path: qual_name,- attrs: Default::default(),- })),- _ => Box::new(Pat::Struct(PatStruct {- attrs: Default::default(),- qself: None,- path: qual_name,- brace_token: Default::default(),- fields: Default::default(),- rest: Some(PatRest {- attrs: Default::default(),- dot2_token: Default::default(),- }),- })),- };-- Arm {- body,- attrs: v- .attrs()- .iter()- .filter(|attr| is_attr_name(attr, "cfg"))- .cloned()- .collect(),- pat: Pat::Reference(PatReference {- and_token: Default::default(),- mutability: None,- pat,- attrs: Default::default(),- }),- guard: None,- fat_arrow_token: Default::default(),- comma: Some(Token)),- }- })- .collect();-- let body = Expr::Match(ExprMatch {- attrs: Default::default(),- match_token: Default::default(),- brace_token: Default::default(),- expr: Box::new(parse_quote!(self)),- arms,- });-- let ty = &i.ident;- let as_str = make_as_str_ident();- let item: ItemImpl = parse_quote!(- impl #ty {- pub fn #as_str(&self) -> &'static str {- #body- }- }- );-- item.with_generics(i.generics.clone())-}--fn make_as_str_ident() -> Ident {- Ident::new("as_str", call_site())-}--fn make_serialize(i: &DeriveInput) -> ItemImpl {- let ty = &i.ident;- let item: ItemImpl = parse_quote!(- #[cfg(feature = "serde")]- impl ::serde::Serialize for #ty {- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>- where- S: ::serde::Serializer,- {- serializer.serialize_str(self.as_str())- }- }- );-- item.with_generics(i.generics.clone())-}--fn make_deserialize(i: &DeriveInput) -> ItemImpl {- let ty = &i.ident;- let item: ItemImpl = parse_quote!(- #[cfg(feature = "serde")]- impl<'de> ::serde::Deserialize<'de> for #ty {- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>- where- D: ::serde::Deserializer<'de>,- {- struct StrVisitor;-- impl<'de> ::serde::de::Visitor<'de> for StrVisitor {- type Value = #ty;-- fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {- // TODO: List strings- write!(f, "one of (TODO)")- }-- fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>- where- E: ::serde::de::Error,- {- // TODO- value.parse().map_err(|()| E::unknown_variant(value, &[]))- }- }-- deserializer.deserialize_str(StrVisitor)- }- }- );-- item.with_generics(i.generics.clone())-}--struct FieldAttr {- aliases: Punctuated<FieldAttrItem, Token![,]>,-}--impl Parse for FieldAttr {- fn parse(input: parse::ParseStream) -> Result<Self> {- Ok(Self {- aliases: input.call(Punctuated::parse_terminated)?,- })- }-}--/// `alias("text")` in `#[string_enum(alias("text"))]`.-struct FieldAttrItem {- alias: LitStr,-}--impl Parse for FieldAttrItem {- fn parse(input: parse::ParseStream) -> Result<Self> {- let name: Ident = input.parse()?;-- assert!(- name == "alias",- "#[derive(StringEnum) only supports `#[string_enum(alias(\"text\"))]]"- );-- let alias;- parenthesized!(alias in input);-- Ok(Self {- alias: alias.parse()?,- })- }-}
deps/swc/crates/swc-ast-explorer/Cargo.toml
@@ -1,27 +0,0 @@-[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>"]-description = "Small CLI for printing SWC EcmaScript ASTs"-edition = { workspace = true }-license = { workspace = true }-name = "swc-ast-explorer"-publish = false-repository = { workspace = true }-version = "0.1.0"--[[bin]]-bench = false-name = "swc-ast-explorer"-path = "src/main.rs"--[dependencies]-anyhow = { workspace = true }-clap = { version = "3", features = ["derive"] }-owo-colors = { workspace = true }-regex = { workspace = true }-swc_common = { version = "26.0.0", path = "../swc_common" }-swc_ecma_ast = { version = "29.0.2", path = "../swc_ecma_ast" }-swc_ecma_parser = { version = "46.0.0", path = "../swc_ecma_parser" }-swc_error_reporters = { version = "28.0.0", path = "../swc_error_reporters" }--[dev-dependencies]-assert_cmd = { workspace = true }
deps/swc/crates/swc-ast-explorer/README.md
@@ -1,9 +0,0 @@-# swc-ast-explorer--A small binary to print SWC EcmaScript and TypeScript abstract syntax trees.--```shell-echo "console.log('hello')" | cargo run -p swc-ast-explorer-```--Use `--spans` to keep span fields in the printed tree.
deps/swc/crates/swc-ast-explorer/src/args.rs
@@ -1,10 +0,0 @@-use clap::Parser;--/// Command line options for the SWC AST explorer.-#[derive(Debug, Parser)]-#[clap(author, version, about, long_about = None)]-pub struct Args {- /// Whether to keep Span (location) markers.- #[clap(long, value_parser, default_value_t = false)]- pub spans: bool,-}
deps/swc/crates/swc-ast-explorer/src/format.rs
@@ -1,56 +0,0 @@-use std::sync::OnceLock;--use owo_colors::OwoColorize;-use regex::{NoExpand, Regex};-use swc_ecma_ast::Program;--static STRUCT_SPAN_FIELD: OnceLock<Regex> = OnceLock::new();-static RANGE_SPAN_FIELD: OnceLock<Regex> = OnceLock::new();-static ALTERNATE_WS: OnceLock<Regex> = OnceLock::new();-static INDENT_WS: OnceLock<Regex> = OnceLock::new();--/// Formats an SWC program using the same tree-like debug output as the-/// original explorer.-pub fn format_program(program: &Program, keep_spans: bool) -> String {- let print = format!("{program:#?}");- let stripped = if keep_spans {- print- } else {- strip_spans(&print)- };-- colorize_indentation(&stripped)-}--fn strip_spans(print: &str) -> String {- let print = struct_span_field().replace_all(print, NoExpand(""));-- range_span_field()- .replace_all(&print, NoExpand(""))- .into_owned()-}--fn colorize_indentation(print: &str) -> String {- let alternate = format!("{}{}", " ".on_default_color(), " ".on_black());- let alternating = alternate_ws().replace_all(print, NoExpand(&alternate));-- indent_ws()- .replace_all(&alternating, NoExpand(" "))- .into_owned()-}--fn struct_span_field() -> &'static Regex {- STRUCT_SPAN_FIELD.get_or_init(|| Regex::new(r"(?m)^\s+\w*span\w*: Span \{[^}]*\},\n").unwrap())-}--fn range_span_field() -> &'static Regex {- RANGE_SPAN_FIELD.get_or_init(|| Regex::new(r"(?m)^\s+\w*span\w*: \d+\.\.\d+,\n").unwrap())-}--fn alternate_ws() -> &'static Regex {- ALTERNATE_WS.get_or_init(|| Regex::new(r" {8}").unwrap())-}--fn indent_ws() -> &'static Regex {- INDENT_WS.get_or_init(|| Regex::new(r" {4}").unwrap())-}
deps/swc/crates/swc-ast-explorer/src/main.rs
@@ -1,46 +0,0 @@-use std::io::{self, Read};--use anyhow::Result;-use clap::Parser;-use swc_common::{errors::ColorConfig, sync::Lrc, FileName, Globals, SourceMap, GLOBALS};-use swc_error_reporters::{- handler::{try_with_handler, HandlerOpts},- TWithDiagnosticArray,-};--use crate::{args::Args, format::format_program, parser::parse_source};--mod args;-mod format;-mod parser;--fn main() -> Result<()> {- let args = Args::parse();- let mut contents = String::new();- io::stdin().read_to_string(&mut contents)?;-- let cm = Lrc::new(SourceMap::default());- let program = parse_stdin(cm, contents).map_err(TWithDiagnosticArray::to_pretty_error)?;-- println!("{}", format_program(&program, args.spans));-- Ok(())-}--fn parse_stdin(- cm: Lrc<SourceMap>,- contents: String,-) -> Result<swc_ecma_ast::Program, TWithDiagnosticArray<anyhow::Error>> {- let file = cm.new_source_file(FileName::Anon.into(), contents);-- GLOBALS.set(&Globals::new(), || {- try_with_handler(- cm,- HandlerOpts {- color: ColorConfig::Always,- skip_filename: false,- },- |handler| parse_source(&file, handler),- )- })-}
deps/swc/crates/swc-ast-explorer/src/parser.rs
@@ -1,32 +0,0 @@-use anyhow::{anyhow, bail, Result};-use swc_common::{errors::Handler, SourceFile};-use swc_ecma_ast::{EsVersion, Program};-use swc_ecma_parser::{parse_file_as_program, Syntax, TsSyntax};--/// Parses a source file as JavaScript, TypeScript, or TSX and returns the SWC-/// program tree. Recovered parser errors are treated as fatal so the CLI does-/// not print partial ASTs for invalid input.-pub fn parse_source(file: &SourceFile, handler: &Handler) -> Result<Program> {- let syntax = Syntax::Typescript(TsSyntax {- tsx: true,- ..Default::default()- });- let mut errors = Vec::new();- let program = parse_file_as_program(file, syntax, EsVersion::latest(), None, &mut errors)- .map_err(|err| {- err.into_diagnostic(handler).emit();- anyhow!("Syntax Error")- })?;-- let mut has_recovered_error = false;- for err in errors {- err.into_diagnostic(handler).emit();- has_recovered_error = true;- }-- if has_recovered_error {- bail!("Syntax Error");- }-- Ok(program)-}
deps/swc/crates/swc/.browserslistrc
deps/swc/crates/swc/.gitignore
@@ -1,3 +0,0 @@-# I use this to try stuffs-/lab.js-/cur.js
deps/swc/crates/swc/AGENTS.md
@@ -1,5 +0,0 @@-### Fixture Test Addition Guide--- Preferred fixture roots in this crate: tests/fixture, tests/errors, tests/exec, tests/minify, tests/typescript, tests/vercel, tests/stacktrace, tests/babel-exec.-- Update generated fixture outputs with: UPDATE=1 cargo test -p swc.-- Verify without UPDATE before finishing: cargo test -p swc.
deps/swc/crates/swc/Cargo.toml
@@ -1,202 +0,0 @@---[package]-authors = ["강동윤 <kdy1997.dev@gmail.com>"]-description = "Speedy web compiler"-documentation = "https://rustdoc.swc.rs/swc/"-edition = { workspace = true }-include = ["Cargo.toml", "src/**/*.rs"]-license = { workspace = true }-name = "swc"-repository = { workspace = true }-version = "80.0.0"--[lib]-bench = false-name = "swc"--[features]-# TODO: This may need reorganization with swc_core - swc_core allows to optionally enable-# each features (minifier, transforms..) but swc includes all of them.-concurrent = [- "swc_ecma_transforms/concurrent",- "swc_common/concurrent",- "swc_ecma_minifier/concurrent",-]--debug = ["swc_ecma_visit/debug", "swc_ecma_minifier/debug"]-default = ["lint", "isolated-dts", "module"]-es3 = ["swc_ecma_transforms_compat/es3", "swc_ecma_preset_env/es3"]-flow = ["swc_ecma_parser/flow"]-isolated-dts = ["swc_typescript"]-# Enable module transforms (CommonJS, AMD, UMD, SystemJS).-# Bundlers typically don't need this as they handle module transforms themselves.-module = ["swc_ecma_transforms/module", "swc_ecma_transforms_module"]-node = ["napi", "napi-derive", "swc_compiler_base/node"]--# Enable React Compiler APIs.-react-compiler = ["dep:swc_ecma_react_compiler"]--plugin = [- "swc_plugin_runner/ecma",- "swc_plugin_runner/encoding-impl",- "swc_plugin_proxy/plugin-rt",- "tokio",-]-plugin_transform_schema_v1 = [- "swc_common/plugin_transform_schema_v1",- "swc_plugin_runner/plugin_transform_schema_v1",-]-plugin_transform_schema_vtest = [- "swc_common/plugin_transform_schema_vtest",- "swc_plugin_runner/plugin_transform_schema_vtest",-]--# Enable wasmer plugin runtime implement-plugin_backend_wasmer = ["swc_plugin_backend_wasmer"]--plugin_transform_host_js = [- "swc_plugin_backend_wasmer/plugin_transform_host_js",-]-plugin_transform_host_native = [- "swc_plugin_backend_wasmer/plugin_transform_host_native",-]-# Do not inject tokio runtime while running plugin transforms-manual-tokio-runtime = []--lint = ["swc_ecma_lints"]--[dependencies]-anyhow = { workspace = true }-base64 = { workspace = true }-bytes-str = { workspace = true }-dashmap = { workspace = true }-either = { workspace = true }-indexmap = { workspace = true, features = ["serde"] }-jsonc-parser = { workspace = true, features = ["serde"] }-once_cell = { workspace = true }-par-core = { workspace = true }-par-iter = { workspace = true }-parking_lot = { workspace = true }-regex = { workspace = true }-rustc-hash = { workspace = true }-serde = { workspace = true, features = ["derive"] }-serde_json = { workspace = true }-swc_sourcemap = { workspace = true }-tracing = { workspace = true }-url = { workspace = true }---swc_atoms = { version = "10.0.0", path = "../swc_atoms" }-swc_common = { version = "26.0.0", path = "../swc_common", features = [- "sourcemap",- "parking_lot",-] }-swc_compiler_base = { version = "66.0.0", path = "../swc_compiler_base" }-swc_config = { version = "6.0.1", path = "../swc_config" }-swc_ecma_ast = { version = "29.0.2", path = "../swc_ecma_ast" }-swc_ecma_codegen = { version = "32.0.3", path = "../swc_ecma_codegen" }-swc_ecma_ext_transforms = { version = "35.0.0", path = "../swc_ecma_ext_transforms" }-swc_ecma_lints = { version = "37.0.0", path = "../swc_ecma_lints", optional = true }-swc_ecma_loader = { version = "27.0.0", path = "../swc_ecma_loader", features = [- "cache",- "node",- "tsc",-] }-swc_ecma_minifier = { version = "63.0.1", path = "../swc_ecma_minifier" }-swc_ecma_parser = { version = "46.0.0", path = "../swc_ecma_parser", default-features = false, features = [- "typescript",-] }-swc_ecma_preset_env = { version = "66.0.0", path = "../swc_ecma_preset_env", default-features = false, features = [- "serde-impl",-] }-swc_ecma_react_compiler = { version = "26.0.0", path = "../swc_ecma_react_compiler", optional = true }-swc_ecma_transforms = { version = "64.0.0", path = "../swc_ecma_transforms", features = [- "compat",- "optimization",- "proposal",- "react",- "typescript",-] }-swc_ecma_transforms_base = { version = "50.0.0", path = "../swc_ecma_transforms_base" }-swc_ecma_transforms_compat = { version = "58.0.0", path = "../swc_ecma_transforms_compat", default-features = false }-swc_ecma_transforms_module = { version = "57.0.0", path = "../swc_ecma_transforms_module", optional = true }-swc_ecma_transforms_optimization = { version = "53.0.0", path = "../swc_ecma_transforms_optimization" }-swc_ecma_utils = { version = "35.0.3", path = "../swc_ecma_utils" }-swc_ecma_visit = { version = "29.0.0", path = "../swc_ecma_visit" }-swc_error_reporters = { version = "28.0.0", path = "../swc_error_reporters" }-swc_node_comments = { version = "27.0.0", path = "../swc_node_comments" }-swc_plugin_backend_wasmer = { version = "17.0.0", path = "../swc_plugin_backend_wasmer", optional = true, default-features = false }-swc_plugin_proxy = { version = "30.0.0", path = "../swc_plugin_proxy", optional = true }-swc_plugin_runner = { version = "34.0.0", path = "../swc_plugin_runner", optional = true, default-features = false }-swc_transform_common = { version = "20.0.0", path = "../swc_transform_common" }-swc_typescript = { version = "34.0.1", path = "../swc_typescript", optional = true }-swc_visit = { version = "2.0.2", path = "../swc_visit" }--[dependencies.tokio]-features = ["rt", "rt-multi-thread"]-optional = true-workspace = true--[dependencies.napi]-features = ["napi3"]-optional = true-workspace = true--[dependencies.napi-derive]-features = ["type-def"]-optional = true-workspace = true--[dev-dependencies]-ansi_term = { workspace = true }-codspeed-criterion-compat = { workspace = true }-criterion = { workspace = true }-par-core = { workspace = true, features = ["chili"] }-tempfile = { workspace = true }-walkdir = { workspace = true }--swc_ecma_ast = { version = "29.0.2", path = "../swc_ecma_ast", features = [- "serde-impl",-] }-swc_ecma_lints = { version = "37.0.0", path = "../swc_ecma_lints", features = [- "non_critical_lints",-] }-swc_ecma_preset_env = { version = "66.0.0", path = "../swc_ecma_preset_env", features = [- "es3",-] }-swc_ecma_testing = { version = "27.0.1", path = "../swc_ecma_testing" }-swc_ecma_transforms_base = { version = "50.0.0", path = "../swc_ecma_transforms_base", features = [- "inline-helpers",-] }-swc_ecma_transforms_compat = { version = "58.0.0", path = "../swc_ecma_transforms_compat", features = [- "es3",-] }-swc_malloc = { version = "1.2.5", path = "../swc_malloc" }-testing = { version = "27.0.0", path = "../testing" }--[[example]]-name = "transform"--[[bench]]-harness = false-name = "bugs"--[[bench]]-harness = false-name = "minify"---[[bench]]-harness = false-name = "oxc"---[[bench]]-harness = false-name = "typescript"---[[bench]]-harness = false-name = "isolated_declarations"
deps/swc/crates/swc/README.md
@@ -1,7 +0,0 @@-## Testing--### `tests/exec`--All files named `exec.js` or `exec.ts` will be executed, and the test system will ensure that original source code and transpiled source code print the same output to the console.--You can use `./scripts/check-issues.sh` to automatically unignore fixed tests.
deps/swc/crates/swc/benches/.gitignore
@@ -1 +0,0 @@-assets/huge.ts
deps/swc/crates/swc/benches/assets/Observable.ts
@@ -1,543 +0,0 @@-/**- * @prettier- */-import { Operator } from './Operator';-import { SafeSubscriber, Subscriber } from './Subscriber';-import { isSubscription, Subscription } from './Subscription';-import { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';-import { observable as Symbol_observable } from './symbol/observable';-import { pipeFromArray } from './util/pipe';-import { config } from './config';-import { isFunction } from './util/isFunction';--/**- * A representation of any set of values over any amount of time. This is the most basic building block- * of RxJS.- *- * @class Observable<T>- */-export class Observable<T> implements Subscribable<T> {- /**- * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.- */- source: Observable<any> | undefined;-- /**- * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.- */- operator: Operator<any, T> | undefined;-- /**- * @constructor- * @param {Function} subscribe the function that is called when the Observable is- * initially subscribed to. This function is given a Subscriber, to which new values- * can be `next`ed, or an `error` method can be called to raise an error, or- * `complete` can be called to notify of a successful completion.- */- constructor(subscribe?: (this: Observable<T>, subscriber: Subscriber<T>) => TeardownLogic) {- if (subscribe) {- this._subscribe = subscribe;- }- }-- // HACK: Since TypeScript inherits static properties too, we have to- // fight against TypeScript here so Subject can have a different static create signature- /**- * Creates a new Observable by calling the Observable constructor- * @owner Observable- * @method create- * @param {Function} subscribe? the subscriber function to be passed to the Observable constructor- * @return {Observable} a new observable- * @nocollapse- * @deprecated Use `new Observable()` instead. Will be removed in v8.- */- static create: (...args: any[]) => any = <T>(subscribe?: (subscriber: Subscriber<T>) => TeardownLogic) => {- return new Observable<T>(subscribe);- };-- /**- * Creates a new Observable, with this Observable instance as the source, and the passed- * operator defined as the new observable's operator.- * @method lift- * @param operator the operator defining the operation to take on the observable- * @return a new observable with the Operator applied- * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.- * If you have implemented an operator using `lift`, it is recommended that you create an- * operator by simply returning `new Observable()` directly. See "Creating new operators from- * scratch" section here: https://rxjs.dev/guide/operators- */- lift<R>(operator?: Operator<T, R>): Observable<R> {- const observable = new Observable<R>();- observable.source = this;- observable.operator = operator;- return observable;- }-- subscribe(observer?: Partial<Observer<T>>): Subscription;- subscribe(next: (value: T) => void): Subscription;- /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */- subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;- /**- * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.- *- * <span class="informal">Use it when you have all these Observables, but still nothing is happening.</span>- *- * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It- * might be for example a function that you passed to Observable's constructor, but most of the time it is- * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means- * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often- * the thought.- *- * Apart from starting the execution of an Observable, this method allows you to listen for values- * that an Observable emits, as well as for when it completes or errors. You can achieve this in two- * of the following ways.- *- * The first way is creating an object that implements {@link Observer} interface. It should have methods- * defined by that interface, but note that it should be just a regular JavaScript object, which you can create- * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do- * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also- * that your object does not have to implement all methods. If you find yourself creating a method that doesn't- * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,- * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,- * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or- * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide- * an `error` method to avoid missing thrown errors.- *- * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.- * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent- * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,- * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,- * since `subscribe` recognizes these functions by where they were placed in function call. When it comes- * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.- *- * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events- * and you also handled emissions internally by using operators (e.g. using `tap`).- *- * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.- * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean- * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback- * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.- *- * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.- * It is an Observable itself that decides when these functions will be called. For example {@link of}- * by default emits all its values synchronously. Always check documentation for how given Observable- * will behave when subscribed and if its default behavior can be modified with a `scheduler`.- *- * ## Example- * ### Subscribe with an Observer- * ```ts- * import { of } from 'rxjs';- *- * const sumObserver = {- * sum: 0,- * next(value) {- * console.log('Adding: ' + value);- * this.sum = this.sum + value;- * },- * error() {- * // We actually could just remove this method,- * // since we do not really care about errors right now.- * },- * complete() {- * console.log('Sum equals: ' + this.sum);- * }- * };- *- * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.- * .subscribe(sumObserver);- *- * // Logs:- * // "Adding: 1"- * // "Adding: 2"- * // "Adding: 3"- * // "Sum equals: 6"- * ```- *- * ### Subscribe with functions- * ```ts- * import { of } from 'rxjs'- *- * let sum = 0;- *- * of(1, 2, 3).subscribe(- * value => {- * console.log('Adding: ' + value);- * sum = sum + value;- * },- * undefined,- * () => console.log('Sum equals: ' + sum)- * );- *- * // Logs:- * // "Adding: 1"- * // "Adding: 2"- * // "Adding: 3"- * // "Sum equals: 6"- * ```- *- * ### Cancel a subscription- * ```ts- * import { interval } from 'rxjs';- *- * const subscription = interval(1000).subscribe({- * next(num) {- * console.log(num)- * },- * complete() {- * // Will not be called, even when cancelling subscription.- * console.log('completed!');- * }- * });- *- * setTimeout(() => {- * subscription.unsubscribe();- * console.log('unsubscribed!');- * }, 2500);- *- * // Logs:- * // 0 after 1s- * // 1 after 2s- * // "unsubscribed!" after 2.5s- * ```- *- * @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,- * or the first of three possible handlers, which is the handler for each value emitted from the subscribed- * Observable.- * @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,- * the error will be thrown asynchronously as unhandled.- * @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.- * @return {Subscription} a subscription reference to the registered handlers- * @method subscribe- */- subscribe(- observerOrNext?: Partial<Observer<T>> | ((value: T) => void) | null,- error?: ((error: any) => void) | null,- complete?: (() => void) | null- ): Subscription {- const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);-- if (config.useDeprecatedSynchronousErrorHandling) {- this._deprecatedSyncErrorSubscribe(subscriber);- } else {- const { operator, source } = this;- subscriber.add(- operator- ? // We're dealing with a subscription in the- // operator chain to one of our lifted operators.- operator.call(subscriber, source)- : source- ? // If `source` has a value, but `operator` does not, something that- // had intimate knowledge of our API, like our `Subject`, must have- // set it. We're going to just call `_subscribe` directly.- this._subscribe(subscriber)- : // In all other cases, we're likely wrapping a user-provided initializer- // function, so we need to catch errors and handle them appropriately.- this._trySubscribe(subscriber)- );- }- return subscriber;- }-- /**- * REMOVE THIS ENTIRE METHOD IN VERSION 8.- */- private _deprecatedSyncErrorSubscribe(subscriber: Subscriber<unknown>) {- const localSubscriber: any = subscriber;- localSubscriber._syncErrorHack_isSubscribing = true;- const { operator } = this;- if (operator) {- // We don't need to try/catch on operators, as they- // are doing their own try/catching, and will- // properly decorate the subscriber with `__syncError`.- subscriber.add(operator.call(subscriber, this.source));- } else {- try {- subscriber.add(this._subscribe(subscriber));- } catch (err) {- localSubscriber.__syncError = err;- }- }-- // In the case of the deprecated sync error handling,- // we need to crawl forward through our subscriber chain and- // look to see if there's any synchronously thrown errors.- // Does this suck for perf? Yes. So stop using the deprecated sync- // error handling already. We're removing this in v8.- let dest = localSubscriber;- while (dest) {- // Technically, someone could throw something falsy, like 0, or "",- // so we need to check to see if anything was thrown, and we know- // that by the mere existence of `__syncError`.- if ('__syncError' in dest) {- try {- throw dest.__syncError;- } finally {- subscriber.unsubscribe();- }- }- dest = dest.destination;- }-- localSubscriber._syncErrorHack_isSubscribing = false;- }-- /** @internal */- protected _trySubscribe(sink: Subscriber<T>): TeardownLogic {- try {- return this._subscribe(sink);- } catch (err) {- // We don't need to return anything in this case,- // because it's just going to try to `add()` to a subscription- // above.- sink.error(err);- }- }-- /**- * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with- * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.- *- * **WARNING**: Only use this with observables you *know* will complete. If the source- * observable does not complete, you will end up with a promise that is hung up, and- * potentially all of the state of an async function hanging out in memory. To avoid- * this situation, look into adding something like {@link timeout}, {@link take},- * {@link takeWhile}, or {@link takeUntil} amongst others.- *- * ### Example:- *- * ```ts- * import { interval } from 'rxjs';- * import { take } from 'rxjs/operators';- *- * const source$ = interval(1000).pipe(take(4));- *- * async function getTotal() {- * let total = 0;- *- * await source$.forEach(value => {- * total += value;- * console.log('observable -> ', value);- * });- *- * return total;- * }- *- * getTotal().then(- * total => console.log('Total:', total)- * )- *- * // Expected:- * // "observable -> 0"- * // "observable -> 1"- * // "observable -> 2"- * // "observable -> 3"- * // "Total: 6"- * ```- * @param next a handler for each value emitted by the observable- * @return a promise that either resolves on observable completion or- * rejects with the handled error- */- forEach(next: (value: T) => void): Promise<void>;-- /**- * @param next a handler for each value emitted by the observable- * @param promiseCtor a constructor function used to instantiate the Promise- * @return a promise that either resolves on observable completion or- * rejects with the handled error- * @deprecated Passing a Promise constructor will no longer be available- * in upcoming versions of RxJS. This is because it adds weight to the library, for very- * little benefit. If you need this functionality, it is recommended that you either- * polyfill Promise, or you create an adapter to convert the returned native promise- * to whatever promise implementation you wanted. Will be removed in v8.- */- forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise<void>;-- forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise<void> {- promiseCtor = getPromiseCtor(promiseCtor);-- return new promiseCtor<void>((resolve, reject) => {- // Must be declared in a separate statement to avoid a ReferenceError when- // accessing subscription below in the closure due to Temporal Dead Zone.- let subscription: Subscription;- subscription = this.subscribe(- (value) => {- try {- next(value);- } catch (err) {- reject(err);- subscription?.unsubscribe();- }- },- reject,- resolve- );- }) as Promise<void>;- }-- /** @internal */- protected _subscribe(subscriber: Subscriber<any>): TeardownLogic {- return this.source?.subscribe(subscriber);- }-- /**- * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable- * @method Symbol.observable- * @return {Observable} this instance of the observable- */- [Symbol_observable]() {- return this;- }-- /* tslint:disable:max-line-length */- pipe(): Observable<T>;- pipe<A>(op1: OperatorFunction<T, A>): Observable<A>;- pipe<A, B>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>): Observable<B>;- pipe<A, B, C>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>): Observable<C>;- pipe<A, B, C, D>(- op1: OperatorFunction<T, A>,- op2: OperatorFunction<A, B>,- op3: OperatorFunction<B, C>,- op4: OperatorFunction<C, D>- ): Observable<D>;- pipe<A, B, C, D, E>(- op1: OperatorFunction<T, A>,- op2: OperatorFunction<A, B>,- op3: OperatorFunction<B, C>,- op4: OperatorFunction<C, D>,- op5: OperatorFunction<D, E>- ): Observable<E>;- pipe<A, B, C, D, E, F>(- op1: OperatorFunction<T, A>,- op2: OperatorFunction<A, B>,- op3: OperatorFunction<B, C>,- op4: OperatorFunction<C, D>,- op5: OperatorFunction<D, E>,- op6: OperatorFunction<E, F>- ): Observable<F>;- pipe<A, B, C, D, E, F, G>(- op1: OperatorFunction<T, A>,- op2: OperatorFunction<A, B>,- op3: OperatorFunction<B, C>,- op4: OperatorFunction<C, D>,- op5: OperatorFunction<D, E>,- op6: OperatorFunction<E, F>,- op7: OperatorFunction<F, G>- ): Observable<G>;- pipe<A, B, C, D, E, F, G, H>(- op1: OperatorFunction<T, A>,- op2: OperatorFunction<A, B>,- op3: OperatorFunction<B, C>,- op4: OperatorFunction<C, D>,- op5: OperatorFunction<D, E>,- op6: OperatorFunction<E, F>,- op7: OperatorFunction<F, G>,- op8: OperatorFunction<G, H>- ): Observable<H>;- pipe<A, B, C, D, E, F, G, H, I>(- op1: OperatorFunction<T, A>,- op2: OperatorFunction<A, B>,- op3: OperatorFunction<B, C>,- op4: OperatorFunction<C, D>,- op5: OperatorFunction<D, E>,- op6: OperatorFunction<E, F>,- op7: OperatorFunction<F, G>,- op8: OperatorFunction<G, H>,- op9: OperatorFunction<H, I>- ): Observable<I>;- pipe<A, B, C, D, E, F, G, H, I>(- op1: OperatorFunction<T, A>,- op2: OperatorFunction<A, B>,- op3: OperatorFunction<B, C>,- op4: OperatorFunction<C, D>,- op5: OperatorFunction<D, E>,- op6: OperatorFunction<E, F>,- op7: OperatorFunction<F, G>,- op8: OperatorFunction<G, H>,- op9: OperatorFunction<H, I>,- ...operations: OperatorFunction<any, any>[]- ): Observable<unknown>;- /* tslint:enable:max-line-length */-- /**- * Used to stitch together functional operators into a chain.- * @method pipe- * @return {Observable} the Observable result of all of the operators having- * been called in the order they were passed in.- *- * ### Example- * ```ts- * import { interval } from 'rxjs';- * import { map, filter, scan } from 'rxjs/operators';- *- * interval(1000)- * .pipe(- * filter(x => x % 2 === 0),- * map(x => x + x),- * scan((acc, x) => acc + x)- * )- * .subscribe(x => console.log(x))- * ```- */- pipe(...operations: OperatorFunction<any, any>[]): Observable<any> {- return operations.length ? pipeFromArray(operations)(this) : this;- }-- /* tslint:disable:max-line-length */- /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */- toPromise(): Promise<T | undefined>;- /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */- toPromise(PromiseCtor: typeof Promise): Promise<T | undefined>;- /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */- toPromise(PromiseCtor: PromiseConstructorLike): Promise<T | undefined>;- /* tslint:enable:max-line-length */-- /**- * Subscribe to this Observable and get a Promise resolving on- * `complete` with the last emission (if any).- *- * **WARNING**: Only use this with observables you *know* will complete. If the source- * observable does not complete, you will end up with a promise that is hung up, and- * potentially all of the state of an async function hanging out in memory. To avoid- * this situation, look into adding something like {@link timeout}, {@link take},- * {@link takeWhile}, or {@link takeUntil} amongst others.- *- * @method toPromise- * @param [promiseCtor] a constructor function used to instantiate- * the Promise- * @return A Promise that resolves with the last value emit, or- * rejects on an error. If there were no emissions, Promise- * resolves with undefined.- * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise- */- toPromise(promiseCtor?: PromiseConstructorLike): Promise<T | undefined> {- promiseCtor = getPromiseCtor(promiseCtor);-- return new promiseCtor((resolve, reject) => {- let value: T | undefined;- this.subscribe(- (x: T) => (value = x),- (err: any) => reject(err),- () => resolve(value)- );- }) as Promise<T | undefined>;- }-}--/**- * Decides between a passed promise constructor from consuming code,- * A default configured promise constructor, and the native promise- * constructor and returns it. If nothing can be found, it will throw- * an error.- * @param promiseCtor The optional promise constructor to passed by consuming code- */-function getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {- return promiseCtor ?? config.Promise ?? Promise;-}--function isObserver<T>(value: any): value is Observer<T> {- return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);-}--function isSubscriber<T>(value: any): value is Subscriber<T> {- return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));-}
deps/swc/crates/swc/benches/assets/UserSettings.tsx
@@ -1,124 +0,0 @@-import { zodResolver } from "@hookform/resolvers/zod";-import { useEffect } from "react";-import { useForm } from "react-hook-form";-import { z } from "zod";--import dayjs from "@calcom/dayjs";-import { useTimePreferences } from "@calcom/features/bookings/lib";-import { FULL_NAME_LENGTH_MAX_LIMIT } from "@calcom/lib/constants";-import { useLocale } from "@calcom/lib/hooks/useLocale";-import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";-import { trpc } from "@calcom/trpc/react";-import { Button, TimezoneSelect, Icon, Input } from "@calcom/ui";--import { UsernameAvailabilityField } from "@components/ui/UsernameAvailability";--interface IUserSettingsProps {- nextStep: () => void;- hideUsername?: boolean;-}--const UserSettings = (props: IUserSettingsProps) => {- const { nextStep } = props;- const [user] = trpc.viewer.me.useSuspenseQuery();- const { t } = useLocale();- const { setTimezone: setSelectedTimeZone, timezone: selectedTimeZone } = useTimePreferences();- const telemetry = useTelemetry();- const userSettingsSchema = z.object({- name: z- .string()- .min(1)- .max(FULL_NAME_LENGTH_MAX_LIMIT, {- message: t("max_limit_allowed_hint", { limit: FULL_NAME_LENGTH_MAX_LIMIT }),- }),- });- const {- register,- handleSubmit,- formState: { errors },- } = useForm<z.infer<typeof userSettingsSchema>>({- defaultValues: {- name: user?.name || "",- },- reValidateMode: "onChange",- resolver: zodResolver(userSettingsSchema),- });-- useEffect(() => {- telemetry.event(telemetryEventTypes.onboardingStarted);- }, [telemetry]);-- const utils = trpc.useUtils();- const onSuccess = async () => {- await utils.viewer.me.invalidate();- nextStep();- };- const mutation = trpc.viewer.updateProfile.useMutation({- onSuccess: onSuccess,- });-- const onSubmit = handleSubmit((data) => {- mutation.mutate({- name: data.name,- timeZone: selectedTimeZone,- });- });-- return (- <form onSubmit={onSubmit}>- <div className="space-y-6">- {/* Username textfield: when not coming from signup */}- {!props.hideUsername && <UsernameAvailabilityField />}-- {/* Full name textfield */}- <div className="w-full">- <label htmlFor="name" className="text-default mb-2 block text-sm font-medium">- {t("full_name")}- </label>- <Input- {...register("name", {- required: true,- })}- id="name"- name="name"- type="text"- autoComplete="off"- autoCorrect="off"- />- {errors.name && (- <p data-testid="required" className="py-2 text-xs text-red-500">- {errors.name.message}- </p>- )}- </div>- {/* Timezone select field */}- <div className="w-full">- <label htmlFor="timeZone" className="text-default block text-sm font-medium">- {t("timezone")}- </label>-- <TimezoneSelect- id="timeZone"- value={selectedTimeZone}- onChange={({ value }) => setSelectedTimeZone(value)}- className="mt-2 w-full rounded-md text-sm"- />-- <p className="text-subtle mt-3 flex flex-row font-sans text-xs leading-tight">- {t("current_time")} {dayjs().tz(selectedTimeZone).format("LT").toString().toLowerCase()}- </p>- </div>- </div>- <Button- type="submit"- className="mt-8 flex w-full flex-row justify-center"- loading={mutation.isPending}- disabled={mutation.isPending}>- {t("next_step_text")}- <Icon name="arrow-right" className="ml-2 h-4 w-4 self-center" aria-hidden="true" />- </Button>- </form>- );-};--export { UserSettings };
deps/swc/crates/swc/benches/assets/parser.ts
@@ -1,10777 +0,0 @@-import {- AccessorDeclaration,- addRange,- addRelatedInfo,- append,- ArrayBindingElement,- ArrayBindingPattern,- ArrayLiteralExpression,- ArrayTypeNode,- ArrowFunction,- AsExpression,- AssertionLevel,- AsteriskToken,- attachFileToDiagnostics,- AwaitExpression,- BaseNodeFactory,- BigIntLiteral,- BinaryExpression,- BinaryOperatorToken,- BindingElement,- BindingName,- BindingPattern,- Block,- BooleanLiteral,- BreakOrContinueStatement,- BreakStatement,- CallExpression,- CallSignatureDeclaration,- canHaveJSDoc,- canHaveModifiers,- CaseBlock,- CaseClause,- CaseOrDefaultClause,- CatchClause,- CharacterCodes,- ClassDeclaration,- ClassElement,- ClassExpression,- ClassLikeDeclaration,- ClassStaticBlockDeclaration,- CommaListExpression,- CommentDirective,- commentPragmas,- CommentRange,- ComputedPropertyName,- concatenate,- ConditionalExpression,- ConditionalTypeNode,- ConstructorDeclaration,- ConstructorTypeNode,- ConstructSignatureDeclaration,- containsParseError,- ContinueStatement,- convertToJson,- createDetachedDiagnostic,- createNodeFactory,- createScanner,- createTextChangeRange,- createTextSpanFromBounds,- Debug,- Decorator,- DefaultClause,- DeleteExpression,- Diagnostic,- DiagnosticArguments,- DiagnosticMessage,- Diagnostics,- DiagnosticWithDetachedLocation,- DoStatement,- DotDotDotToken,- ElementAccessExpression,- emptyArray,- emptyMap,- EndOfFileToken,- ensureScriptKind,- EntityName,- EnumDeclaration,- EnumMember,- ExclamationToken,- ExportAssignment,- ExportDeclaration,- ExportSpecifier,- Expression,- ExpressionStatement,- ExpressionWithTypeArguments,- Extension,- ExternalModuleReference,- fileExtensionIs,- findIndex,- firstOrUndefined,- forEach,- ForEachChildNodes,- ForInOrOfStatement,- ForInStatement,- ForOfStatement,- ForStatement,- FunctionDeclaration,- FunctionExpression,- FunctionOrConstructorTypeNode,- FunctionTypeNode,- GetAccessorDeclaration,- getAnyExtensionFromPath,- getBaseFileName,- getBinaryOperatorPrecedence,- getFullWidth,- getJSDocCommentRanges,- getLanguageVariant,- getLastChild,- getLeadingCommentRanges,- getSpellingSuggestion,- getTextOfNodeFromSourceText,- HasJSDoc,- hasJSDocNodes,- HasModifiers,- HeritageClause,- Identifier,- identity,- idText,- IfStatement,- ImportAttribute,- ImportAttributes,- ImportClause,- ImportDeclaration,- ImportEqualsDeclaration,- ImportOrExportSpecifier,- ImportSpecifier,- ImportTypeAssertionContainer,- ImportTypeNode,- IndexedAccessTypeNode,- IndexSignatureDeclaration,- InferTypeNode,- InterfaceDeclaration,- IntersectionTypeNode,- isArray,- isAssignmentOperator,- isAsyncModifier,- isClassMemberModifier,- isExportAssignment,- isExportDeclaration,- isExportModifier,- isExpressionWithTypeArguments,- isExternalModuleReference,- isFunctionTypeNode,- isIdentifier as isIdentifierNode,- isIdentifierText,- isImportDeclaration,- isImportEqualsDeclaration,- isJSDocFunctionType,- isJSDocNullableType,- isJSDocReturnTag,- isJSDocTypeTag,- isJsxNamespacedName,- isJsxOpeningElement,- isJsxOpeningFragment,- isKeyword,- isKeywordOrPunctuation,- isLeftHandSideExpression,- isLiteralKind,- isMetaProperty,- isModifierKind,- isNonNullExpression,- isPrivateIdentifier,- isSetAccessorDeclaration,- isStringOrNumericLiteralLike,- isTaggedTemplateExpression,- isTemplateLiteralKind,- isTypeReferenceNode,- IterationStatement,- JSDoc,- JSDocAllType,- JSDocAugmentsTag,- JSDocAuthorTag,- JSDocCallbackTag,- JSDocClassTag,- JSDocComment,- JSDocDeprecatedTag,- JSDocEnumTag,- JSDocFunctionType,- JSDocImplementsTag,- JSDocImportTag,- JSDocLink,- JSDocLinkCode,- JSDocLinkPlain,- JSDocMemberName,- JSDocNameReference,- JSDocNamespaceDeclaration,- JSDocNonNullableType,- JSDocNullableType,- JSDocOptionalType,- JSDocOverloadTag,- JSDocOverrideTag,- JSDocParameterTag,- JSDocParsingMode,- JSDocPrivateTag,- JSDocPropertyLikeTag,- JSDocPropertyTag,- JSDocProtectedTag,- JSDocPublicTag,- JSDocReadonlyTag,- JSDocReturnTag,- JSDocSatisfiesTag,- JSDocSeeTag,- JSDocSignature,- JSDocSyntaxKind,- JSDocTag,- JSDocTemplateTag,- JSDocText,- JSDocThisTag,- JSDocThrowsTag,- JSDocTypedefTag,- JSDocTypeExpression,- JSDocTypeLiteral,- JSDocTypeTag,- JSDocUnknownTag,- JSDocUnknownType,- JSDocVariadicType,- JsonMinusNumericLiteral,- JsonObjectExpressionStatement,- JsonSourceFile,- JsxAttribute,- JsxAttributes,- JsxAttributeValue,- JsxChild,- JsxClosingElement,- JsxClosingFragment,- JsxElement,- JsxExpression,- JsxFragment,- JsxNamespacedName,- JsxOpeningElement,- JsxOpeningFragment,- JsxOpeningLikeElement,- JsxSelfClosingElement,- JsxSpreadAttribute,- JsxTagNameExpression,- JsxText,- JsxTokenSyntaxKind,- LabeledStatement,- LanguageVariant,- lastOrUndefined,- LeftHandSideExpression,- LiteralExpression,- LiteralLikeNode,- LiteralTypeNode,- map,- mapDefined,- MappedTypeNode,- MemberExpression,- MetaProperty,- MethodDeclaration,- MethodSignature,- MinusToken,- MissingDeclaration,- Modifier,- ModifierFlags,- ModifierLike,- modifiersToFlags,- ModuleBlock,- ModuleDeclaration,- ModuleExportName,- ModuleKind,- Mutable,- NamedExportBindings,- NamedExports,- NamedImports,- NamedImportsOrExports,- NamedTupleMember,- NamespaceDeclaration,- NamespaceExport,- NamespaceExportDeclaration,- NamespaceImport,- NewExpression,- Node,- NodeArray,- NodeFactory,- NodeFactoryFlags,- NodeFlags,- nodeIsMissing,- nodeIsPresent,- NonNullExpression,- noop,- normalizePath,- NoSubstitutionTemplateLiteral,- NullLiteral,- NumericLiteral,- objectAllocator,- ObjectBindingPattern,- ObjectLiteralElementLike,- ObjectLiteralExpression,- OperatorPrecedence,- OptionalTypeNode,- PackageJsonInfo,- ParameterDeclaration,- ParenthesizedExpression,- ParenthesizedTypeNode,- PartiallyEmittedExpression,- PlusToken,- PostfixUnaryExpression,- PostfixUnaryOperator,- PragmaContext,- PragmaDefinition,- PragmaKindFlags,- PragmaMap,- PragmaPseudoMap,- PragmaPseudoMapEntry,- PrefixUnaryExpression,- PrefixUnaryOperator,- PrimaryExpression,- PrivateIdentifier,- PropertyAccessEntityNameExpression,- PropertyAccessExpression,- PropertyAssignment,- PropertyDeclaration,- PropertyName,- PropertySignature,- PunctuationOrKeywordSyntaxKind,- PunctuationSyntaxKind,- QualifiedName,- QuestionDotToken,- QuestionToken,- ReadonlyKeyword,- ReadonlyPragmaMap,- ResolutionMode,- RestTypeNode,- ReturnStatement,- SatisfiesExpression,- ScriptKind,- ScriptTarget,- SetAccessorDeclaration,- setParent,- setParentRecursive,- setTextRange,- setTextRangePos,- setTextRangePosEnd,- setTextRangePosWidth,- ShorthandPropertyAssignment,- skipTrivia,- some,- SourceFile,- SpreadAssignment,- SpreadElement,- startsWith,- Statement,- StringLiteral,- supportedDeclarationExtensions,- SwitchStatement,- SyntaxKind,- TaggedTemplateExpression,- TemplateExpression,- TemplateHead,- TemplateLiteralToken,- TemplateLiteralTypeNode,- TemplateLiteralTypeSpan,- TemplateMiddle,- TemplateSpan,- TemplateTail,- TextChangeRange,- textChangeRangeIsUnchanged,- textChangeRangeNewSpan,- TextRange,- textSpanEnd,- textToKeywordObj,- ThisExpression,- ThisTypeNode,- ThrowStatement,- toArray,- Token,- TokenFlags,- tokenIsIdentifierOrKeyword,- tokenIsIdentifierOrKeywordOrGreaterThan,- tokenToString,- tracing,- transferSourceFileChildren,- TransformFlags,- TryStatement,- TupleTypeNode,- TypeAliasDeclaration,- TypeAssertion,- TypeElement,- TypeLiteralNode,- TypeNode,- TypeOfExpression,- TypeOperatorNode,- TypeParameterDeclaration,- TypePredicateNode,- TypeQueryNode,- TypeReferenceNode,- UnaryExpression,- unescapeLeadingUnderscores,- UnionOrIntersectionTypeNode,- UnionTypeNode,- unsetNodeChildren,- UpdateExpression,- VariableDeclaration,- VariableDeclarationList,- VariableStatement,- VoidExpression,- WhileStatement,- WithStatement,- YieldExpression,-} from "./_namespaces/ts.js";-import * as performance from "./_namespaces/ts.performance.js";--const enum SignatureFlags {- None = 0,- Yield = 1 << 0,- Await = 1 << 1,- Type = 1 << 2,- IgnoreMissingOpenBrace = 1 << 4,- JSDoc = 1 << 5,-}--const enum SpeculationKind {- TryParse,- Lookahead,- Reparse,-}--let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;-let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;-let IdentifierConstructor: new (kind: SyntaxKind.Identifier, pos: number, end: number) => Node;-let PrivateIdentifierConstructor: new (kind: SyntaxKind.PrivateIdentifier, pos: number, end: number) => Node;-let SourceFileConstructor: new (kind: SyntaxKind.SourceFile, pos: number, end: number) => Node;--/**- * NOTE: You should not use this, it is only exported to support `createNode` in `~/src/deprecatedCompat/deprecations.ts`.- *- * @internal- * @knipignore- */-export const parseBaseNodeFactory: BaseNodeFactory = {- createBaseSourceFileNode: kind => new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, -1, -1),- createBaseIdentifierNode: kind => new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, -1, -1),- createBasePrivateIdentifierNode: kind => new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, -1, -1),- createBaseTokenNode: kind => new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1),- createBaseNode: kind => new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1),-};--/** @internal */-export const parseNodeFactory: NodeFactory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules, parseBaseNodeFactory);--function visitNode<T>(cbNode: (node: Node) => T, node: Node | undefined): T | undefined {- return node && cbNode(node);-}--function visitNodes<T>(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray<Node>) => T | undefined) | undefined, nodes: NodeArray<Node> | undefined): T | undefined {- if (nodes) {- if (cbNodes) {- return cbNodes(nodes);- }- for (const node of nodes) {- const result = cbNode(node);- if (result) {- return result;- }- }- }-}--/** @internal */-export function isJSDocLikeText(text: string, start: number): boolean {- return text.charCodeAt(start + 1) === CharacterCodes.asterisk &&- text.charCodeAt(start + 2) === CharacterCodes.asterisk &&- text.charCodeAt(start + 3) !== CharacterCodes.slash;-}--/** @internal */-export function isFileProbablyExternalModule(sourceFile: SourceFile): Node | undefined {- // Try to use the first top-level import/export when available, then- // fall back to looking for an 'import.meta' somewhere in the tree if necessary.- return forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) ||- getImportMetaIfNecessary(sourceFile);-}--function isAnExternalModuleIndicatorNode(node: Node) {- return canHaveModifiers(node) && hasModifierOfKind(node, SyntaxKind.ExportKeyword)- || isImportEqualsDeclaration(node) && isExternalModuleReference(node.moduleReference)- || isImportDeclaration(node)- || isExportAssignment(node)- || isExportDeclaration(node) ? node : undefined;-}--function getImportMetaIfNecessary(sourceFile: SourceFile) {- return sourceFile.flags & NodeFlags.PossiblyContainsImportMeta ?- walkTreeForImportMeta(sourceFile) :- undefined;-}--function walkTreeForImportMeta(node: Node): Node | undefined {- return isImportMeta(node) ? node : forEachChild(node, walkTreeForImportMeta);-}--/** Do not use hasModifier inside the parser; it relies on parent pointers. Use this instead. */-function hasModifierOfKind(node: HasModifiers, kind: SyntaxKind) {- return some(node.modifiers, m => m.kind === kind);-}--function isImportMeta(node: Node): boolean {- return isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta";-}--type ForEachChildFunction<TNode> = <T>(node: TNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined) => T | undefined;-type ForEachChildTable = { [TNode in ForEachChildNodes as TNode["kind"]]: ForEachChildFunction<TNode>; };-const forEachChildTable: ForEachChildTable = {- [SyntaxKind.QualifiedName]: function forEachChildInQualifiedName<T>(node: QualifiedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.left) ||- visitNode(cbNode, node.right);- },- [SyntaxKind.TypeParameter]: function forEachChildInTypeParameter<T>(node: TypeParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.constraint) ||- visitNode(cbNode, node.default) ||- visitNode(cbNode, node.expression);- },- [SyntaxKind.ShorthandPropertyAssignment]: function forEachChildInShorthandPropertyAssignment<T>(node: ShorthandPropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.questionToken) ||- visitNode(cbNode, node.exclamationToken) ||- visitNode(cbNode, node.equalsToken) ||- visitNode(cbNode, node.objectAssignmentInitializer);- },- [SyntaxKind.SpreadAssignment]: function forEachChildInSpreadAssignment<T>(node: SpreadAssignment, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.Parameter]: function forEachChildInParameter<T>(node: ParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.dotDotDotToken) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.questionToken) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.initializer);- },- [SyntaxKind.PropertyDeclaration]: function forEachChildInPropertyDeclaration<T>(node: PropertyDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.questionToken) ||- visitNode(cbNode, node.exclamationToken) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.initializer);- },- [SyntaxKind.PropertySignature]: function forEachChildInPropertySignature<T>(node: PropertySignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.questionToken) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.initializer);- },- [SyntaxKind.PropertyAssignment]: function forEachChildInPropertyAssignment<T>(node: PropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.questionToken) ||- visitNode(cbNode, node.exclamationToken) ||- visitNode(cbNode, node.initializer);- },- [SyntaxKind.VariableDeclaration]: function forEachChildInVariableDeclaration<T>(node: VariableDeclaration, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.name) ||- visitNode(cbNode, node.exclamationToken) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.initializer);- },- [SyntaxKind.BindingElement]: function forEachChildInBindingElement<T>(node: BindingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.dotDotDotToken) ||- visitNode(cbNode, node.propertyName) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.initializer);- },- [SyntaxKind.IndexSignature]: function forEachChildInIndexSignature<T>(node: IndexSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type);- },- [SyntaxKind.ConstructorType]: function forEachChildInConstructorType<T>(node: ConstructorTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type);- },- [SyntaxKind.FunctionType]: function forEachChildInFunctionType<T>(node: FunctionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type);- },- [SyntaxKind.CallSignature]: forEachChildInCallOrConstructSignature,- [SyntaxKind.ConstructSignature]: forEachChildInCallOrConstructSignature,- [SyntaxKind.MethodDeclaration]: function forEachChildInMethodDeclaration<T>(node: MethodDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.asteriskToken) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.questionToken) ||- visitNode(cbNode, node.exclamationToken) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.body);- },- [SyntaxKind.MethodSignature]: function forEachChildInMethodSignature<T>(node: MethodSignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.questionToken) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type);- },- [SyntaxKind.Constructor]: function forEachChildInConstructor<T>(node: ConstructorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.body);- },- [SyntaxKind.GetAccessor]: function forEachChildInGetAccessor<T>(node: GetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.body);- },- [SyntaxKind.SetAccessor]: function forEachChildInSetAccessor<T>(node: SetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.body);- },- [SyntaxKind.FunctionDeclaration]: function forEachChildInFunctionDeclaration<T>(node: FunctionDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.asteriskToken) ||- visitNode(cbNode, node.name) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.body);- },- [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression<T>(node: FunctionExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.asteriskToken) ||- visitNode(cbNode, node.name) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.body);- },- [SyntaxKind.ArrowFunction]: function forEachChildInArrowFunction<T>(node: ArrowFunction, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type) ||- visitNode(cbNode, node.equalsGreaterThanToken) ||- visitNode(cbNode, node.body);- },- [SyntaxKind.ClassStaticBlockDeclaration]: function forEachChildInClassStaticBlockDeclaration<T>(node: ClassStaticBlockDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.body);- },- [SyntaxKind.TypeReference]: function forEachChildInTypeReference<T>(node: TypeReferenceNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.typeName) ||- visitNodes(cbNode, cbNodes, node.typeArguments);- },- [SyntaxKind.TypePredicate]: function forEachChildInTypePredicate<T>(node: TypePredicateNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.assertsModifier) ||- visitNode(cbNode, node.parameterName) ||- visitNode(cbNode, node.type);- },- [SyntaxKind.TypeQuery]: function forEachChildInTypeQuery<T>(node: TypeQueryNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.exprName) ||- visitNodes(cbNode, cbNodes, node.typeArguments);- },- [SyntaxKind.TypeLiteral]: function forEachChildInTypeLiteral<T>(node: TypeLiteralNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.members);- },- [SyntaxKind.ArrayType]: function forEachChildInArrayType<T>(node: ArrayTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.elementType);- },- [SyntaxKind.TupleType]: function forEachChildInTupleType<T>(node: TupleTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.elements);- },- [SyntaxKind.UnionType]: forEachChildInUnionOrIntersectionType,- [SyntaxKind.IntersectionType]: forEachChildInUnionOrIntersectionType,- [SyntaxKind.ConditionalType]: function forEachChildInConditionalType<T>(node: ConditionalTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.checkType) ||- visitNode(cbNode, node.extendsType) ||- visitNode(cbNode, node.trueType) ||- visitNode(cbNode, node.falseType);- },- [SyntaxKind.InferType]: function forEachChildInInferType<T>(node: InferTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.typeParameter);- },- [SyntaxKind.ImportType]: function forEachChildInImportType<T>(node: ImportTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.argument) ||- visitNode(cbNode, node.attributes) ||- visitNode(cbNode, node.qualifier) ||- visitNodes(cbNode, cbNodes, node.typeArguments);- },- [SyntaxKind.ImportTypeAssertionContainer]: function forEachChildInImportTypeAssertionContainer<T>(node: ImportTypeAssertionContainer, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.assertClause);- },- [SyntaxKind.ParenthesizedType]: forEachChildInParenthesizedTypeOrTypeOperator,- [SyntaxKind.TypeOperator]: forEachChildInParenthesizedTypeOrTypeOperator,- [SyntaxKind.IndexedAccessType]: function forEachChildInIndexedAccessType<T>(node: IndexedAccessTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.objectType) ||- visitNode(cbNode, node.indexType);- },- [SyntaxKind.MappedType]: function forEachChildInMappedType<T>(node: MappedTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.readonlyToken) ||- visitNode(cbNode, node.typeParameter) ||- visitNode(cbNode, node.nameType) ||- visitNode(cbNode, node.questionToken) ||- visitNode(cbNode, node.type) ||- visitNodes(cbNode, cbNodes, node.members);- },- [SyntaxKind.LiteralType]: function forEachChildInLiteralType<T>(node: LiteralTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.literal);- },- [SyntaxKind.NamedTupleMember]: function forEachChildInNamedTupleMember<T>(node: NamedTupleMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.dotDotDotToken) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.questionToken) ||- visitNode(cbNode, node.type);- },- [SyntaxKind.ObjectBindingPattern]: forEachChildInObjectOrArrayBindingPattern,- [SyntaxKind.ArrayBindingPattern]: forEachChildInObjectOrArrayBindingPattern,- [SyntaxKind.ArrayLiteralExpression]: function forEachChildInArrayLiteralExpression<T>(node: ArrayLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.elements);- },- [SyntaxKind.ObjectLiteralExpression]: function forEachChildInObjectLiteralExpression<T>(node: ObjectLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.properties);- },- [SyntaxKind.PropertyAccessExpression]: function forEachChildInPropertyAccessExpression<T>(node: PropertyAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- visitNode(cbNode, node.questionDotToken) ||- visitNode(cbNode, node.name);- },- [SyntaxKind.ElementAccessExpression]: function forEachChildInElementAccessExpression<T>(node: ElementAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- visitNode(cbNode, node.questionDotToken) ||- visitNode(cbNode, node.argumentExpression);- },- [SyntaxKind.CallExpression]: forEachChildInCallOrNewExpression,- [SyntaxKind.NewExpression]: forEachChildInCallOrNewExpression,- [SyntaxKind.TaggedTemplateExpression]: function forEachChildInTaggedTemplateExpression<T>(node: TaggedTemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tag) ||- visitNode(cbNode, node.questionDotToken) ||- visitNodes(cbNode, cbNodes, node.typeArguments) ||- visitNode(cbNode, node.template);- },- [SyntaxKind.TypeAssertionExpression]: function forEachChildInTypeAssertionExpression<T>(node: TypeAssertion, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.type) ||- visitNode(cbNode, node.expression);- },- [SyntaxKind.ParenthesizedExpression]: function forEachChildInParenthesizedExpression<T>(node: ParenthesizedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.DeleteExpression]: function forEachChildInDeleteExpression<T>(node: DeleteExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.TypeOfExpression]: function forEachChildInTypeOfExpression<T>(node: TypeOfExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.VoidExpression]: function forEachChildInVoidExpression<T>(node: VoidExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.PrefixUnaryExpression]: function forEachChildInPrefixUnaryExpression<T>(node: PrefixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.operand);- },- [SyntaxKind.YieldExpression]: function forEachChildInYieldExpression<T>(node: YieldExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.asteriskToken) ||- visitNode(cbNode, node.expression);- },- [SyntaxKind.AwaitExpression]: function forEachChildInAwaitExpression<T>(node: AwaitExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.PostfixUnaryExpression]: function forEachChildInPostfixUnaryExpression<T>(node: PostfixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.operand);- },- [SyntaxKind.BinaryExpression]: function forEachChildInBinaryExpression<T>(node: BinaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.left) ||- visitNode(cbNode, node.operatorToken) ||- visitNode(cbNode, node.right);- },- [SyntaxKind.AsExpression]: function forEachChildInAsExpression<T>(node: AsExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- visitNode(cbNode, node.type);- },- [SyntaxKind.NonNullExpression]: function forEachChildInNonNullExpression<T>(node: NonNullExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.SatisfiesExpression]: function forEachChildInSatisfiesExpression<T>(node: SatisfiesExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) || visitNode(cbNode, node.type);- },- [SyntaxKind.MetaProperty]: function forEachChildInMetaProperty<T>(node: MetaProperty, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.name);- },- [SyntaxKind.ConditionalExpression]: function forEachChildInConditionalExpression<T>(node: ConditionalExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.condition) ||- visitNode(cbNode, node.questionToken) ||- visitNode(cbNode, node.whenTrue) ||- visitNode(cbNode, node.colonToken) ||- visitNode(cbNode, node.whenFalse);- },- [SyntaxKind.SpreadElement]: function forEachChildInSpreadElement<T>(node: SpreadElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.Block]: forEachChildInBlock,- [SyntaxKind.ModuleBlock]: forEachChildInBlock,- [SyntaxKind.SourceFile]: function forEachChildInSourceFile<T>(node: SourceFile, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.statements) ||- visitNode(cbNode, node.endOfFileToken);- },- [SyntaxKind.VariableStatement]: function forEachChildInVariableStatement<T>(node: VariableStatement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.declarationList);- },- [SyntaxKind.VariableDeclarationList]: function forEachChildInVariableDeclarationList<T>(node: VariableDeclarationList, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.declarations);- },- [SyntaxKind.ExpressionStatement]: function forEachChildInExpressionStatement<T>(node: ExpressionStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.IfStatement]: function forEachChildInIfStatement<T>(node: IfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- visitNode(cbNode, node.thenStatement) ||- visitNode(cbNode, node.elseStatement);- },- [SyntaxKind.DoStatement]: function forEachChildInDoStatement<T>(node: DoStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.statement) ||- visitNode(cbNode, node.expression);- },- [SyntaxKind.WhileStatement]: function forEachChildInWhileStatement<T>(node: WhileStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- visitNode(cbNode, node.statement);- },- [SyntaxKind.ForStatement]: function forEachChildInForStatement<T>(node: ForStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.initializer) ||- visitNode(cbNode, node.condition) ||- visitNode(cbNode, node.incrementor) ||- visitNode(cbNode, node.statement);- },- [SyntaxKind.ForInStatement]: function forEachChildInForInStatement<T>(node: ForInStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.initializer) ||- visitNode(cbNode, node.expression) ||- visitNode(cbNode, node.statement);- },- [SyntaxKind.ForOfStatement]: function forEachChildInForOfStatement<T>(node: ForOfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.awaitModifier) ||- visitNode(cbNode, node.initializer) ||- visitNode(cbNode, node.expression) ||- visitNode(cbNode, node.statement);- },- [SyntaxKind.ContinueStatement]: forEachChildInContinueOrBreakStatement,- [SyntaxKind.BreakStatement]: forEachChildInContinueOrBreakStatement,- [SyntaxKind.ReturnStatement]: function forEachChildInReturnStatement<T>(node: ReturnStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.WithStatement]: function forEachChildInWithStatement<T>(node: WithStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- visitNode(cbNode, node.statement);- },- [SyntaxKind.SwitchStatement]: function forEachChildInSwitchStatement<T>(node: SwitchStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- visitNode(cbNode, node.caseBlock);- },- [SyntaxKind.CaseBlock]: function forEachChildInCaseBlock<T>(node: CaseBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.clauses);- },- [SyntaxKind.CaseClause]: function forEachChildInCaseClause<T>(node: CaseClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- visitNodes(cbNode, cbNodes, node.statements);- },- [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause<T>(node: DefaultClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.statements);- },- [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement<T>(node: LabeledStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.label) ||- visitNode(cbNode, node.statement);- },- [SyntaxKind.ThrowStatement]: function forEachChildInThrowStatement<T>(node: ThrowStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.TryStatement]: function forEachChildInTryStatement<T>(node: TryStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tryBlock) ||- visitNode(cbNode, node.catchClause) ||- visitNode(cbNode, node.finallyBlock);- },- [SyntaxKind.CatchClause]: function forEachChildInCatchClause<T>(node: CatchClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.variableDeclaration) ||- visitNode(cbNode, node.block);- },- [SyntaxKind.Decorator]: function forEachChildInDecorator<T>(node: Decorator, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.ClassDeclaration]: forEachChildInClassDeclarationOrExpression,- [SyntaxKind.ClassExpression]: forEachChildInClassDeclarationOrExpression,- [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration<T>(node: InterfaceDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.heritageClauses) ||- visitNodes(cbNode, cbNodes, node.members);- },- [SyntaxKind.TypeAliasDeclaration]: function forEachChildInTypeAliasDeclaration<T>(node: TypeAliasDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNode(cbNode, node.type);- },- [SyntaxKind.EnumDeclaration]: function forEachChildInEnumDeclaration<T>(node: EnumDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNodes(cbNode, cbNodes, node.members);- },- [SyntaxKind.EnumMember]: function forEachChildInEnumMember<T>(node: EnumMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.name) ||- visitNode(cbNode, node.initializer);- },- [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration<T>(node: ModuleDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.body);- },- [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration<T>(node: ImportEqualsDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNode(cbNode, node.moduleReference);- },- [SyntaxKind.ImportDeclaration]: function forEachChildInImportDeclaration<T>(node: ImportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.importClause) ||- visitNode(cbNode, node.moduleSpecifier) ||- visitNode(cbNode, node.attributes);- },- [SyntaxKind.ImportClause]: function forEachChildInImportClause<T>(node: ImportClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.name) ||- visitNode(cbNode, node.namedBindings);- },- [SyntaxKind.ImportAttributes]: function forEachChildInImportAttributes<T>(node: ImportAttributes, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.elements);- },- [SyntaxKind.ImportAttribute]: function forEachChildInImportAttribute<T>(node: ImportAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.name) ||- visitNode(cbNode, node.value);- },- [SyntaxKind.NamespaceExportDeclaration]: function forEachChildInNamespaceExportDeclaration<T>(node: NamespaceExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name);- },- [SyntaxKind.NamespaceImport]: function forEachChildInNamespaceImport<T>(node: NamespaceImport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.name);- },- [SyntaxKind.NamespaceExport]: function forEachChildInNamespaceExport<T>(node: NamespaceExport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.name);- },- [SyntaxKind.NamedImports]: forEachChildInNamedImportsOrExports,- [SyntaxKind.NamedExports]: forEachChildInNamedImportsOrExports,- [SyntaxKind.ExportDeclaration]: function forEachChildInExportDeclaration<T>(node: ExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.exportClause) ||- visitNode(cbNode, node.moduleSpecifier) ||- visitNode(cbNode, node.attributes);- },- [SyntaxKind.ImportSpecifier]: forEachChildInImportOrExportSpecifier,- [SyntaxKind.ExportSpecifier]: forEachChildInImportOrExportSpecifier,- [SyntaxKind.ExportAssignment]: function forEachChildInExportAssignment<T>(node: ExportAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.expression);- },- [SyntaxKind.TemplateExpression]: function forEachChildInTemplateExpression<T>(node: TemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.head) ||- visitNodes(cbNode, cbNodes, node.templateSpans);- },- [SyntaxKind.TemplateSpan]: function forEachChildInTemplateSpan<T>(node: TemplateSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- visitNode(cbNode, node.literal);- },- [SyntaxKind.TemplateLiteralType]: function forEachChildInTemplateLiteralType<T>(node: TemplateLiteralTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.head) ||- visitNodes(cbNode, cbNodes, node.templateSpans);- },- [SyntaxKind.TemplateLiteralTypeSpan]: function forEachChildInTemplateLiteralTypeSpan<T>(node: TemplateLiteralTypeSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.type) ||- visitNode(cbNode, node.literal);- },- [SyntaxKind.ComputedPropertyName]: function forEachChildInComputedPropertyName<T>(node: ComputedPropertyName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.HeritageClause]: function forEachChildInHeritageClause<T>(node: HeritageClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.types);- },- [SyntaxKind.ExpressionWithTypeArguments]: function forEachChildInExpressionWithTypeArguments<T>(node: ExpressionWithTypeArguments, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- visitNodes(cbNode, cbNodes, node.typeArguments);- },- [SyntaxKind.ExternalModuleReference]: function forEachChildInExternalModuleReference<T>(node: ExternalModuleReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.MissingDeclaration]: function forEachChildInMissingDeclaration<T>(node: MissingDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers);- },- [SyntaxKind.CommaListExpression]: function forEachChildInCommaListExpression<T>(node: CommaListExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.elements);- },- [SyntaxKind.JsxElement]: function forEachChildInJsxElement<T>(node: JsxElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.openingElement) ||- visitNodes(cbNode, cbNodes, node.children) ||- visitNode(cbNode, node.closingElement);- },- [SyntaxKind.JsxFragment]: function forEachChildInJsxFragment<T>(node: JsxFragment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.openingFragment) ||- visitNodes(cbNode, cbNodes, node.children) ||- visitNode(cbNode, node.closingFragment);- },- [SyntaxKind.JsxSelfClosingElement]: forEachChildInJsxOpeningOrSelfClosingElement,- [SyntaxKind.JsxOpeningElement]: forEachChildInJsxOpeningOrSelfClosingElement,- [SyntaxKind.JsxAttributes]: function forEachChildInJsxAttributes<T>(node: JsxAttributes, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.properties);- },- [SyntaxKind.JsxAttribute]: function forEachChildInJsxAttribute<T>(node: JsxAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.name) ||- visitNode(cbNode, node.initializer);- },- [SyntaxKind.JsxSpreadAttribute]: function forEachChildInJsxSpreadAttribute<T>(node: JsxSpreadAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);- },- [SyntaxKind.JsxExpression]: function forEachChildInJsxExpression<T>(node: JsxExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.dotDotDotToken) ||- visitNode(cbNode, node.expression);- },- [SyntaxKind.JsxClosingElement]: function forEachChildInJsxClosingElement<T>(node: JsxClosingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName);- },- [SyntaxKind.JsxNamespacedName]: function forEachChildInJsxNamespacedName<T>(node: JsxNamespacedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.namespace) ||- visitNode(cbNode, node.name);- },- [SyntaxKind.OptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier,- [SyntaxKind.RestType]: forEachChildInOptionalRestOrJSDocParameterModifier,- [SyntaxKind.JSDocTypeExpression]: forEachChildInOptionalRestOrJSDocParameterModifier,- [SyntaxKind.JSDocNonNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier,- [SyntaxKind.JSDocNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier,- [SyntaxKind.JSDocOptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier,- [SyntaxKind.JSDocVariadicType]: forEachChildInOptionalRestOrJSDocParameterModifier,- [SyntaxKind.JSDocFunctionType]: function forEachChildInJSDocFunctionType<T>(node: JSDocFunctionType, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type);- },- [SyntaxKind.JSDoc]: function forEachChildInJSDoc<T>(node: JSDoc, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))- || visitNodes(cbNode, cbNodes, node.tags);- },- [SyntaxKind.JSDocSeeTag]: function forEachChildInJSDocSeeTag<T>(node: JSDocSeeTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName) ||- visitNode(cbNode, node.name) ||- (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));- },- [SyntaxKind.JSDocNameReference]: function forEachChildInJSDocNameReference<T>(node: JSDocNameReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.name);- },- [SyntaxKind.JSDocMemberName]: function forEachChildInJSDocMemberName<T>(node: JSDocMemberName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.left) ||- visitNode(cbNode, node.right);- },- [SyntaxKind.JSDocParameterTag]: forEachChildInJSDocParameterOrPropertyTag,- [SyntaxKind.JSDocPropertyTag]: forEachChildInJSDocParameterOrPropertyTag,- [SyntaxKind.JSDocAuthorTag]: function forEachChildInJSDocAuthorTag<T>(node: JSDocAuthorTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName) ||- (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));- },- [SyntaxKind.JSDocImplementsTag]: function forEachChildInJSDocImplementsTag<T>(node: JSDocImplementsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName) ||- visitNode(cbNode, node.class) ||- (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));- },- [SyntaxKind.JSDocAugmentsTag]: function forEachChildInJSDocAugmentsTag<T>(node: JSDocAugmentsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName) ||- visitNode(cbNode, node.class) ||- (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));- },- [SyntaxKind.JSDocTemplateTag]: function forEachChildInJSDocTemplateTag<T>(node: JSDocTemplateTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName) ||- visitNode(cbNode, node.constraint) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));- },- [SyntaxKind.JSDocTypedefTag]: function forEachChildInJSDocTypedefTag<T>(node: JSDocTypedefTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName) ||- (node.typeExpression &&- node.typeExpression.kind === SyntaxKind.JSDocTypeExpression- ? visitNode(cbNode, node.typeExpression) ||- visitNode(cbNode, node.fullName) ||- (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))- : visitNode(cbNode, node.fullName) ||- visitNode(cbNode, node.typeExpression) ||- (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)));- },- [SyntaxKind.JSDocCallbackTag]: function forEachChildInJSDocCallbackTag<T>(node: JSDocCallbackTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName) ||- visitNode(cbNode, node.fullName) ||- visitNode(cbNode, node.typeExpression) ||- (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));- },- [SyntaxKind.JSDocReturnTag]: forEachChildInJSDocTypeLikeTag,- [SyntaxKind.JSDocTypeTag]: forEachChildInJSDocTypeLikeTag,- [SyntaxKind.JSDocThisTag]: forEachChildInJSDocTypeLikeTag,- [SyntaxKind.JSDocEnumTag]: forEachChildInJSDocTypeLikeTag,- [SyntaxKind.JSDocSatisfiesTag]: forEachChildInJSDocTypeLikeTag,- [SyntaxKind.JSDocThrowsTag]: forEachChildInJSDocTypeLikeTag,- [SyntaxKind.JSDocOverloadTag]: forEachChildInJSDocTypeLikeTag,- [SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature<T>(node: JSDocSignature, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return forEach(node.typeParameters, cbNode) ||- forEach(node.parameters, cbNode) ||- visitNode(cbNode, node.type);- },- [SyntaxKind.JSDocLink]: forEachChildInJSDocLinkCodeOrPlain,- [SyntaxKind.JSDocLinkCode]: forEachChildInJSDocLinkCodeOrPlain,- [SyntaxKind.JSDocLinkPlain]: forEachChildInJSDocLinkCodeOrPlain,- [SyntaxKind.JSDocTypeLiteral]: function forEachChildInJSDocTypeLiteral<T>(node: JSDocTypeLiteral, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return forEach(node.jsDocPropertyTags, cbNode);- },- [SyntaxKind.JSDocTag]: forEachChildInJSDocTag,- [SyntaxKind.JSDocClassTag]: forEachChildInJSDocTag,- [SyntaxKind.JSDocPublicTag]: forEachChildInJSDocTag,- [SyntaxKind.JSDocPrivateTag]: forEachChildInJSDocTag,- [SyntaxKind.JSDocProtectedTag]: forEachChildInJSDocTag,- [SyntaxKind.JSDocReadonlyTag]: forEachChildInJSDocTag,- [SyntaxKind.JSDocDeprecatedTag]: forEachChildInJSDocTag,- [SyntaxKind.JSDocOverrideTag]: forEachChildInJSDocTag,- [SyntaxKind.JSDocImportTag]: forEachChildInJSDocImportTag,- [SyntaxKind.PartiallyEmittedExpression]: forEachChildInPartiallyEmittedExpression,-};--// shared--function forEachChildInCallOrConstructSignature<T>(node: CallSignatureDeclaration | ConstructSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.parameters) ||- visitNode(cbNode, node.type);-}--function forEachChildInUnionOrIntersectionType<T>(node: UnionTypeNode | IntersectionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.types);-}--function forEachChildInParenthesizedTypeOrTypeOperator<T>(node: ParenthesizedTypeNode | TypeOperatorNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.type);-}--function forEachChildInObjectOrArrayBindingPattern<T>(node: BindingPattern, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.elements);-}--function forEachChildInCallOrNewExpression<T>(node: CallExpression | NewExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression) ||- // TODO: should we separate these branches out?- visitNode(cbNode, (node as CallExpression).questionDotToken) ||- visitNodes(cbNode, cbNodes, node.typeArguments) ||- visitNodes(cbNode, cbNodes, node.arguments);-}--function forEachChildInBlock<T>(node: Block | ModuleBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.statements);-}--function forEachChildInContinueOrBreakStatement<T>(node: ContinueStatement | BreakStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.label);-}--function forEachChildInClassDeclarationOrExpression<T>(node: ClassDeclaration | ClassExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.modifiers) ||- visitNode(cbNode, node.name) ||- visitNodes(cbNode, cbNodes, node.typeParameters) ||- visitNodes(cbNode, cbNodes, node.heritageClauses) ||- visitNodes(cbNode, cbNodes, node.members);-}--function forEachChildInNamedImportsOrExports<T>(node: NamedImports | NamedExports, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNodes(cbNode, cbNodes, node.elements);-}--function forEachChildInImportOrExportSpecifier<T>(node: ImportSpecifier | ExportSpecifier, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.propertyName) ||- visitNode(cbNode, node.name);-}--function forEachChildInJsxOpeningOrSelfClosingElement<T>(node: JsxOpeningLikeElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName) ||- visitNodes(cbNode, cbNodes, node.typeArguments) ||- visitNode(cbNode, node.attributes);-}--function forEachChildInOptionalRestOrJSDocParameterModifier<T>(node: OptionalTypeNode | RestTypeNode | JSDocTypeExpression | JSDocNullableType | JSDocNonNullableType | JSDocOptionalType | JSDocVariadicType, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.type);-}--function forEachChildInJSDocParameterOrPropertyTag<T>(node: JSDocParameterTag | JSDocPropertyTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName) ||- (node.isNameFirst- ? visitNode(cbNode, node.name) || visitNode(cbNode, node.typeExpression)- : visitNode(cbNode, node.typeExpression) || visitNode(cbNode, node.name)) ||- (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));-}--function forEachChildInJSDocTypeLikeTag<T>(node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag | JSDocThrowsTag | JSDocOverloadTag | JSDocSatisfiesTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName) ||- visitNode(cbNode, node.typeExpression) ||- (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));-}--function forEachChildInJSDocLinkCodeOrPlain<T>(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.name);-}--function forEachChildInJSDocTag<T>(node: JSDocUnknownTag | JSDocClassTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag | JSDocOverrideTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName)- || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));-}--function forEachChildInJSDocImportTag<T>(node: JSDocImportTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.tagName)- || visitNode(cbNode, node.importClause)- || visitNode(cbNode, node.moduleSpecifier)- || visitNode(cbNode, node.attributes)- || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));-}--function forEachChildInPartiallyEmittedExpression<T>(node: PartiallyEmittedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- return visitNode(cbNode, node.expression);-}--/**- * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes- * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,- * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns- * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.- *- * @param node a given node to visit its children- * @param cbNode a callback to be invoked for all child nodes- * @param cbNodes a callback to be invoked for embedded array- *- * @remarks `forEachChild` must visit the children of a node in the order- * that they appear in the source code. The language service depends on this property to locate nodes by position.- */-export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {- if (node === undefined || node.kind <= SyntaxKind.LastToken) {- return;- }- const fn = (forEachChildTable as Record<SyntaxKind, ForEachChildFunction<any>>)[node.kind];- return fn === undefined ? undefined : fn(node, cbNode, cbNodes);-}--/**- * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes- * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; additionally,- * unlike `forEachChild`, embedded arrays are flattened and the 'cbNode' callback is invoked for each element.- * If a callback returns a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.- *- * @param node a given node to visit its children- * @param cbNode a callback to be invoked for all child nodes- * @param cbNodes a callback to be invoked for embedded array- *- * @remarks Unlike `forEachChild`, `forEachChildRecursively` handles recursively invoking the traversal on each child node found,- * and while doing so, handles traversing the structure without relying on the callstack to encode the tree structure.- *- * @internal- */-export function forEachChildRecursively<T>(rootNode: Node, cbNode: (node: Node, parent: Node) => T | "skip" | undefined, cbNodes?: (nodes: NodeArray<Node>, parent: Node) => T | "skip" | undefined): T | undefined {- const queue: (Node | NodeArray<Node>)[] = gatherPossibleChildren(rootNode);- const parents: Node[] = []; // tracks parent references for elements in queue- while (parents.length < queue.length) {- parents.push(rootNode);- }- while (queue.length !== 0) {- const current = queue.pop()!;- const parent = parents.pop()!;- if (isArray(current)) {- if (cbNodes) {- const res = cbNodes(current, parent);- if (res) {- if (res === "skip") continue;- return res;- }- }- for (let i = current.length - 1; i >= 0; --i) {- queue.push(current[i]);- parents.push(parent);- }- }- else {- const res = cbNode(current, parent);- if (res) {- if (res === "skip") continue;- return res;- }- if (current.kind >= SyntaxKind.FirstNode) {- // add children in reverse order to the queue, so popping gives the first child- for (const child of gatherPossibleChildren(current)) {- queue.push(child);- parents.push(current);- }- }- }- }-}--function gatherPossibleChildren(node: Node) {- const children: (Node | NodeArray<Node>)[] = [];- forEachChild(node, addWorkItem, addWorkItem); // By using a stack above and `unshift` here, we emulate a depth-first preorder traversal- return children;-- function addWorkItem(n: Node | NodeArray<Node>) {- children.unshift(n);- }-}--export interface CreateSourceFileOptions {- languageVersion: ScriptTarget;- /**- * Controls the format the file is detected as - this can be derived from only the path- * and files on disk, but needs to be done with a module resolution cache in scope to be performant.- * This is usually `undefined` for compilations that do not have `moduleResolution` values of `node16` or `nodenext`.- */- impliedNodeFormat?: ResolutionMode;- /**- * Controls how module-y-ness is set for the given file. Usually the result of calling- * `getSetExternalModuleIndicator` on a valid `CompilerOptions` object. If not present, the default- * check specified by `isFileProbablyExternalModule` will be used to set the field.- */- setExternalModuleIndicator?: (file: SourceFile) => void;- /** @internal */ packageJsonLocations?: readonly string[];- /** @internal */ packageJsonScope?: PackageJsonInfo;- jsDocParsingMode?: JSDocParsingMode;-}--function setExternalModuleIndicator(sourceFile: SourceFile) {- sourceFile.externalModuleIndicator = isFileProbablyExternalModule(sourceFile);-}--export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {- tracing?.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true);- performance.mark("beforeParse");- let result: SourceFile;-- const {- languageVersion,- setExternalModuleIndicator: overrideSetExternalModuleIndicator,- impliedNodeFormat: format,- jsDocParsingMode,- } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions);- if (languageVersion === ScriptTarget.JSON) {- result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop, jsDocParsingMode);- }- else {- const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => {- file.impliedNodeFormat = format;- return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file);- };- result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator, jsDocParsingMode);- }-- performance.mark("afterParse");- performance.measure("Parse", "beforeParse", "afterParse");- tracing?.pop();- return result;-}--export function parseIsolatedEntityName(text: string, languageVersion: ScriptTarget): EntityName | undefined {- return Parser.parseIsolatedEntityName(text, languageVersion);-}--/**- * Parse json text into SyntaxTree and return node and parse errors if any- * @param fileName- * @param sourceText- */-export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile {- return Parser.parseJsonText(fileName, sourceText);-}--// See also `isExternalOrCommonJsModule` in utilities.ts-export function isExternalModule(file: SourceFile): boolean {- return file.externalModuleIndicator !== undefined;-}--// Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter-// indicates what changed between the 'text' that this SourceFile has and the 'newText'.-// The SourceFile will be created with the compiler attempting to reuse as many nodes from-// this file as possible.-//-// Note: this function mutates nodes from this SourceFile. That means any existing nodes-// from this SourceFile that are being held onto may change as a result (including-// becoming detached from any SourceFile). It is recommended that this SourceFile not-// be used once 'update' is called on it.-export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks = false): SourceFile {- const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks);- // Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import.- // We will manually port the flag to the new source file.- (newSourceFile as Mutable<SourceFile>).flags |= sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags;- return newSourceFile;-}--/** @internal */-export interface JsDocWithDiagnostics {- jsDoc: JSDoc;- diagnostics: Diagnostic[];-}--/** @internal */-export function parseIsolatedJSDocComment(content: string, start?: number, length?: number): JsDocWithDiagnostics | undefined {- const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length);- if (result && result.jsDoc) {- // because the jsDocComment was parsed out of the source file, it might- // not be covered by the fixupParentReferences.- Parser.fixupParentReferences(result.jsDoc);- }-- return result;-}--/** @internal */-// Exposed only for testing.-export function parseJSDocTypeExpressionForTests(content: string, start?: number, length?: number): {- jsDocTypeExpression: JSDocTypeExpression;- diagnostics: Diagnostic[];-} | undefined {- return Parser.JSDocParser.parseJSDocTypeExpressionForTests(content, start, length);-}--// Implement the parser as a singleton module. We do this for perf reasons because creating-// parser instances can actually be expensive enough to impact us on projects with many source-// files.-namespace Parser {- // Why var? It avoids TDZ checks in the runtime which can be costly.- // See: https://github.com/microsoft/TypeScript/issues/52924- /* eslint-disable no-var */-- // Share a single scanner across all calls to parse a source file. This helps speed things- // up by avoiding the cost of creating/compiling scanners over and over again.- var scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true);-- var disallowInAndDecoratorContext = NodeFlags.DisallowInContext | NodeFlags.DecoratorContext;-- // capture constructors in 'initializeState' to avoid null checks- var NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;- var TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;- var IdentifierConstructor: new (kind: SyntaxKind.Identifier, pos: number, end: number) => Identifier;- var PrivateIdentifierConstructor: new (kind: SyntaxKind.PrivateIdentifier, pos: number, end: number) => PrivateIdentifier;- var SourceFileConstructor: new (kind: SyntaxKind.SourceFile, pos: number, end: number) => SourceFile;-- function countNode(node: Node) {- nodeCount++;- return node;- }-- // Rather than using `createBaseNodeFactory` here, we establish a `BaseNodeFactory` that closes over the- // constructors above, which are reset each time `initializeState` is called.- var baseNodeFactory: BaseNodeFactory = {- createBaseSourceFileNode: kind => countNode(new SourceFileConstructor(kind, /*pos*/ 0, /*end*/ 0)),- createBaseIdentifierNode: kind => countNode(new IdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)),- createBasePrivateIdentifierNode: kind => countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)),- createBaseTokenNode: kind => countNode(new TokenConstructor(kind, /*pos*/ 0, /*end*/ 0)),- createBaseNode: kind => countNode(new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0)),- };-- var factory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters | NodeFactoryFlags.NoOriginalNode, baseNodeFactory);-- var {- createNodeArray: factoryCreateNodeArray,- createNumericLiteral: factoryCreateNumericLiteral,- createStringLiteral: factoryCreateStringLiteral,- createLiteralLikeNode: factoryCreateLiteralLikeNode,- createIdentifier: factoryCreateIdentifier,- createPrivateIdentifier: factoryCreatePrivateIdentifier,- createToken: factoryCreateToken,- createArrayLiteralExpression: factoryCreateArrayLiteralExpression,- createObjectLiteralExpression: factoryCreateObjectLiteralExpression,- createPropertyAccessExpression: factoryCreatePropertyAccessExpression,- createPropertyAccessChain: factoryCreatePropertyAccessChain,- createElementAccessExpression: factoryCreateElementAccessExpression,- createElementAccessChain: factoryCreateElementAccessChain,- createCallExpression: factoryCreateCallExpression,- createCallChain: factoryCreateCallChain,- createNewExpression: factoryCreateNewExpression,- createParenthesizedExpression: factoryCreateParenthesizedExpression,- createBlock: factoryCreateBlock,- createVariableStatement: factoryCreateVariableStatement,- createExpressionStatement: factoryCreateExpressionStatement,- createIfStatement: factoryCreateIfStatement,- createWhileStatement: factoryCreateWhileStatement,- createForStatement: factoryCreateForStatement,- createForOfStatement: factoryCreateForOfStatement,- createVariableDeclaration: factoryCreateVariableDeclaration,- createVariableDeclarationList: factoryCreateVariableDeclarationList,- } = factory;-- var fileName: string;- var sourceFlags: NodeFlags;- var sourceText: string;- var languageVersion: ScriptTarget;- var scriptKind: ScriptKind;- var languageVariant: LanguageVariant;- var parseDiagnostics: DiagnosticWithDetachedLocation[];- var jsDocDiagnostics: DiagnosticWithDetachedLocation[];- var syntaxCursor: IncrementalParser.SyntaxCursor | undefined;-- var currentToken: SyntaxKind;- var nodeCount: number;- var identifiers: Map<string, string>;- var identifierCount: number;-- // TODO(jakebailey): This type is a lie; this value actually contains the result- // of ORing a bunch of `1 << ParsingContext.XYZ`.- var parsingContext: ParsingContext;-- var notParenthesizedArrow: Set<number> | undefined;-- // Flags that dictate what parsing context we're in. For example:- // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is- // that some tokens that would be considered identifiers may be considered keywords.- //- // When adding more parser context flags, consider which is the more common case that the- // flag will be in. This should be the 'false' state for that flag. The reason for this is- // that we don't store data in our nodes unless the value is in the *non-default* state. So,- // for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for- // 'disallow-in' set to 'false'. Otherwise, if we had 'allowsIn' set to 'true', then almost- // all nodes would need extra state on them to store this info.- //- // Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6- // grammar specification.- //- // An important thing about these context concepts. By default they are effectively inherited- // while parsing through every grammar production. i.e. if you don't change them, then when- // you parse a sub-production, it will have the same context values as the parent production.- // This is great most of the time. After all, consider all the 'expression' grammar productions- // and how nearly all of them pass along the 'in' and 'yield' context values:- //- // EqualityExpression[In, Yield] :- // RelationalExpression[?In, ?Yield]- // EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield]- // EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield]- // EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield]- // EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield]- //- // Where you have to be careful is then understanding what the points are in the grammar- // where the values are *not* passed along. For example:- //- // SingleNameBinding[Yield,GeneratorParameter]- // [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt- // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt- //- // Here this is saying that if the GeneratorParameter context flag is set, that we should- // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier- // and we should explicitly unset the 'yield' context flag before calling into the Initializer.- // production. Conversely, if the GeneratorParameter context flag is not set, then we- // should leave the 'yield' context flag alone.- //- // Getting this all correct is tricky and requires careful reading of the grammar to- // understand when these values should be changed versus when they should be inherited.- //- // Note: it should not be necessary to save/restore these flags during speculative/lookahead- // parsing. These context flags are naturally stored and restored through normal recursive- // descent parsing and unwinding.- var contextFlags: NodeFlags;-- // Indicates whether we are currently parsing top-level statements.- var topLevel = true;-- // Whether or not we've had a parse error since creating the last AST node. If we have- // encountered an error, it will be stored on the next AST node we create. Parse errors- // can be broken down into three categories:- //- // 1) An error that occurred during scanning. For example, an unterminated literal, or a- // character that was completely not understood.- //- // 2) A token was expected, but was not present. This type of error is commonly produced- // by the 'parseExpected' function.- //- // 3) A token was present that no parsing function was able to consume. This type of error- // only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser- // decides to skip the token.- //- // In all of these cases, we want to mark the next node as having had an error before it.- // With this mark, we can know in incremental settings if this node can be reused, or if- // we have to reparse it. If we don't keep this information around, we may just reuse the- // node. in that event we would then not produce the same errors as we did before, causing- // significant confusion problems.- //- // Note: it is necessary that this value be saved/restored during speculative/lookahead- // parsing. During lookahead parsing, we will often create a node. That node will have- // this value attached, and then this value will be set back to 'false'. If we decide to- // rewind, we must get back to the same value we had prior to the lookahead.- //- // Note: any errors at the end of the file that do not precede a regular node, should get- // attached to the EOF token.- var parseErrorBeforeNextFinishedNode = false;- /* eslint-enable no-var */-- export function parseSourceFile(- fileName: string,- sourceText: string,- languageVersion: ScriptTarget,- syntaxCursor: IncrementalParser.SyntaxCursor | undefined,- setParentNodes = false,- scriptKind?: ScriptKind,- setExternalModuleIndicatorOverride?: (file: SourceFile) => void,- jsDocParsingMode = JSDocParsingMode.ParseAll,- ): SourceFile {- scriptKind = ensureScriptKind(fileName, scriptKind);- if (scriptKind === ScriptKind.JSON) {- const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes);- convertToJson(result, result.statements[0]?.expression, result.parseDiagnostics, /*returnValue*/ false, /*jsonConversionNotifier*/ undefined);- result.referencedFiles = emptyArray;- result.typeReferenceDirectives = emptyArray;- result.libReferenceDirectives = emptyArray;- result.amdDependencies = emptyArray;- result.hasNoDefaultLib = false;- result.pragmas = emptyMap as ReadonlyPragmaMap;- return result;- }-- initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind, jsDocParsingMode);-- const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator, jsDocParsingMode);-- clearState();-- return result;- }-- export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName | undefined {- // Choice of `isDeclarationFile` should be arbitrary- initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS, JSDocParsingMode.ParseAll);- // Prime the scanner.- nextToken();- const entityName = parseEntityName(/*allowReservedWords*/ true);- const isValid = token() === SyntaxKind.EndOfFileToken && !parseDiagnostics.length;- clearState();- return isValid ? entityName : undefined;- }-- export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes = false): JsonSourceFile {- initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON, JSDocParsingMode.ParseAll);- sourceFlags = contextFlags;-- // Prime the scanner.- nextToken();- const pos = getNodePos();- let statements, endOfFileToken;- if (token() === SyntaxKind.EndOfFileToken) {- statements = createNodeArray([], pos, pos);- endOfFileToken = parseTokenNode<EndOfFileToken>();- }- else {- // Loop and synthesize an ArrayLiteralExpression if there are more than- // one top-level expressions to ensure all input text is consumed.- let expressions: Expression[] | Expression | undefined;- while (token() !== SyntaxKind.EndOfFileToken) {- let expression;- switch (token()) {- case SyntaxKind.OpenBracketToken:- expression = parseArrayLiteralExpression();- break;- case SyntaxKind.TrueKeyword:- case SyntaxKind.FalseKeyword:- case SyntaxKind.NullKeyword:- expression = parseTokenNode<BooleanLiteral | NullLiteral>();- break;- case SyntaxKind.MinusToken:- if (lookAhead(() => nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken)) {- expression = parsePrefixUnaryExpression() as JsonMinusNumericLiteral;- }- else {- expression = parseObjectLiteralExpression();- }- break;- case SyntaxKind.NumericLiteral:- case SyntaxKind.StringLiteral:- if (lookAhead(() => nextToken() !== SyntaxKind.ColonToken)) {- expression = parseLiteralNode() as StringLiteral | NumericLiteral;- break;- }- // falls through- default:- expression = parseObjectLiteralExpression();- break;- }-- // Error recovery: collect multiple top-level expressions- if (expressions && isArray(expressions)) {- expressions.push(expression);- }- else if (expressions) {- expressions = [expressions, expression];- }- else {- expressions = expression;- if (token() !== SyntaxKind.EndOfFileToken) {- parseErrorAtCurrentToken(Diagnostics.Unexpected_token);- }- }- }-- const expression = isArray(expressions) ? finishNode(factoryCreateArrayLiteralExpression(expressions), pos) : Debug.checkDefined(expressions);- const statement = factoryCreateExpressionStatement(expression) as JsonObjectExpressionStatement;- finishNode(statement, pos);- statements = createNodeArray([statement], pos);- endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token) as EndOfFileToken;- }-- // Set source file so that errors will be reported with this file name- const sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclarationFile*/ false, statements, endOfFileToken, sourceFlags, noop);-- if (setParentNodes) {- fixupParentReferences(sourceFile);- }-- sourceFile.nodeCount = nodeCount;- sourceFile.identifierCount = identifierCount;- sourceFile.identifiers = identifiers;- sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);- if (jsDocDiagnostics) {- sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile);- }-- const result = sourceFile as JsonSourceFile;- clearState();- return result;- }-- function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind, _jsDocParsingMode: JSDocParsingMode) {- NodeConstructor = objectAllocator.getNodeConstructor();- TokenConstructor = objectAllocator.getTokenConstructor();- IdentifierConstructor = objectAllocator.getIdentifierConstructor();- PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor();- SourceFileConstructor = objectAllocator.getSourceFileConstructor();-- fileName = normalizePath(_fileName);- sourceText = _sourceText;- languageVersion = _languageVersion;- syntaxCursor = _syntaxCursor;- scriptKind = _scriptKind;- languageVariant = getLanguageVariant(_scriptKind);-- parseDiagnostics = [];- parsingContext = 0;- identifiers = new Map<string, string>();- identifierCount = 0;- nodeCount = 0;- sourceFlags = 0;- topLevel = true;-- switch (scriptKind) {- case ScriptKind.JS:- case ScriptKind.JSX:- contextFlags = NodeFlags.JavaScriptFile;- break;- case ScriptKind.JSON:- contextFlags = NodeFlags.JavaScriptFile | NodeFlags.JsonFile;- break;- default:- contextFlags = NodeFlags.None;- break;- }- parseErrorBeforeNextFinishedNode = false;-- // Initialize and prime the scanner before parsing the source elements.- scanner.setText(sourceText);- scanner.setOnError(scanError);- scanner.setScriptTarget(languageVersion);- scanner.setLanguageVariant(languageVariant);- scanner.setScriptKind(scriptKind);- scanner.setJSDocParsingMode(_jsDocParsingMode);- }-- function clearState() {- // Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily.- scanner.clearCommentDirectives();- scanner.setText("");- scanner.setOnError(undefined);- scanner.setScriptKind(ScriptKind.Unknown);- scanner.setJSDocParsingMode(JSDocParsingMode.ParseAll);-- // Clear any data. We don't want to accidentally hold onto it for too long.- sourceText = undefined!;- languageVersion = undefined!;- syntaxCursor = undefined;- scriptKind = undefined!;- languageVariant = undefined!;- sourceFlags = 0;- parseDiagnostics = undefined!;- jsDocDiagnostics = undefined!;- parsingContext = 0;- identifiers = undefined!;- notParenthesizedArrow = undefined;- topLevel = true;- }-- function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void, jsDocParsingMode: JSDocParsingMode): SourceFile {- const isDeclarationFile = isDeclarationFileName(fileName);- if (isDeclarationFile) {- contextFlags |= NodeFlags.Ambient;- }-- sourceFlags = contextFlags;-- // Prime the scanner.- nextToken();-- const statements = parseList(ParsingContext.SourceElements, parseStatement);- Debug.assert(token() === SyntaxKind.EndOfFileToken);- const endHasJSDoc = hasPrecedingJSDocComment();- const endOfFileToken = withJSDoc(parseTokenNode<EndOfFileToken>(), endHasJSDoc);-- const sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile, statements, endOfFileToken, sourceFlags, setExternalModuleIndicator);-- // A member of ReadonlyArray<T> isn't assignable to a member of T[] (and prevents a direct cast) - but this is where we set up those members so they can be readonly in the future- processCommentPragmas(sourceFile as {} as PragmaContext, sourceText);- processPragmasIntoFields(sourceFile as {} as PragmaContext, reportPragmaDiagnostic);-- sourceFile.commentDirectives = scanner.getCommentDirectives();- sourceFile.nodeCount = nodeCount;- sourceFile.identifierCount = identifierCount;- sourceFile.identifiers = identifiers;- sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);- sourceFile.jsDocParsingMode = jsDocParsingMode;- if (jsDocDiagnostics) {- sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile);- }-- if (setParentNodes) {- fixupParentReferences(sourceFile);- }-- return sourceFile;-- function reportPragmaDiagnostic(pos: number, end: number, diagnostic: DiagnosticMessage) {- parseDiagnostics.push(createDetachedDiagnostic(fileName, sourceText, pos, end, diagnostic));- }- }-- let hasDeprecatedTag = false;- function withJSDoc<T extends HasJSDoc>(node: T, hasJSDoc: boolean): T {- if (!hasJSDoc) {- return node;- }-- Debug.assert(!node.jsDoc); // Should only be called once per node- const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceText), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos));- if (jsDoc.length) node.jsDoc = jsDoc;- if (hasDeprecatedTag) {- hasDeprecatedTag = false;- (node as Mutable<T>).flags |= NodeFlags.Deprecated;- }- return node;- }-- function reparseTopLevelAwait(sourceFile: SourceFile) {- const savedSyntaxCursor = syntaxCursor;- const baseSyntaxCursor = IncrementalParser.createSyntaxCursor(sourceFile);- syntaxCursor = { currentNode };-- const statements: Statement[] = [];- const savedParseDiagnostics = parseDiagnostics;-- parseDiagnostics = [];-- let pos = 0;- let start = findNextStatementWithAwait(sourceFile.statements, 0);- while (start !== -1) {- // append all statements between pos and start- const prevStatement = sourceFile.statements[pos];- const nextStatement = sourceFile.statements[start];- addRange(statements, sourceFile.statements, pos, start);- pos = findNextStatementWithoutAwait(sourceFile.statements, start);-- // append all diagnostics associated with the copied range- const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos);- const diagnosticEnd = diagnosticStart >= 0 ? findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= nextStatement.pos, diagnosticStart) : -1;- if (diagnosticStart >= 0) {- addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart, diagnosticEnd >= 0 ? diagnosticEnd : undefined);- }-- // reparse all statements between start and pos. We skip existing diagnostics for the same range and allow the parser to generate new ones.- speculationHelper(() => {- const savedContextFlags = contextFlags;- contextFlags |= NodeFlags.AwaitContext;- scanner.resetTokenState(nextStatement.pos);- nextToken();-- while (token() !== SyntaxKind.EndOfFileToken) {- const startPos = scanner.getTokenFullStart();- const statement = parseListElement(ParsingContext.SourceElements, parseStatement);- statements.push(statement);- if (startPos === scanner.getTokenFullStart()) {- nextToken();- }-- if (pos >= 0) {- const nonAwaitStatement = sourceFile.statements[pos];- if (statement.end === nonAwaitStatement.pos) {- // done reparsing this section- break;- }- if (statement.end > nonAwaitStatement.pos) {- // we ate into the next statement, so we must reparse it.- pos = findNextStatementWithoutAwait(sourceFile.statements, pos + 1);- }- }- }-- contextFlags = savedContextFlags;- }, SpeculationKind.Reparse);-- // find the next statement containing an `await`- start = pos >= 0 ? findNextStatementWithAwait(sourceFile.statements, pos) : -1;- }-- // append all statements between pos and the end of the list- if (pos >= 0) {- const prevStatement = sourceFile.statements[pos];- addRange(statements, sourceFile.statements, pos);-- // append all diagnostics associated with the copied range- const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos);- if (diagnosticStart >= 0) {- addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart);- }- }-- syntaxCursor = savedSyntaxCursor;- return factory.updateSourceFile(sourceFile, setTextRange(factoryCreateNodeArray(statements), sourceFile.statements));-- function containsPossibleTopLevelAwait(node: Node) {- return !(node.flags & NodeFlags.AwaitContext)- && !!(node.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait);- }-- function findNextStatementWithAwait(statements: NodeArray<Statement>, start: number) {- for (let i = start; i < statements.length; i++) {- if (containsPossibleTopLevelAwait(statements[i])) {- return i;- }- }- return -1;- }-- function findNextStatementWithoutAwait(statements: NodeArray<Statement>, start: number) {- for (let i = start; i < statements.length; i++) {- if (!containsPossibleTopLevelAwait(statements[i])) {- return i;- }- }- return -1;- }-- function currentNode(position: number) {- const node = baseSyntaxCursor.currentNode(position);- if (topLevel && node && containsPossibleTopLevelAwait(node)) {- markAsIntersectingIncrementalChange(node);- }- return node;- }- }-- export function fixupParentReferences(rootNode: Node) {- // normally parent references are set during binding. However, for clients that only need- // a syntax tree, and no semantic features, then the binding process is an unnecessary- // overhead. This functions allows us to set all the parents, without all the expense of- // binding.- setParentRecursive(rootNode, /*incremental*/ true);- }-- function createSourceFile(- fileName: string,- languageVersion: ScriptTarget,- scriptKind: ScriptKind,- isDeclarationFile: boolean,- statements: readonly Statement[],- endOfFileToken: EndOfFileToken,- flags: NodeFlags,- setExternalModuleIndicator: (sourceFile: SourceFile) => void,- ): SourceFile {- // code from createNode is inlined here so createNode won't have to deal with special case of creating source files- // this is quite rare comparing to other nodes and createNode should be as fast as possible- let sourceFile = factory.createSourceFile(statements, endOfFileToken, flags);- setTextRangePosWidth(sourceFile, 0, sourceText.length);- setFields(sourceFile);-- // If we parsed this as an external module, it may contain top-level await- if (!isDeclarationFile && isExternalModule(sourceFile) && sourceFile.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait) {- const oldSourceFile = sourceFile;- sourceFile = reparseTopLevelAwait(sourceFile);- if (oldSourceFile !== sourceFile) setFields(sourceFile);- }-- return sourceFile;-- function setFields(sourceFile: SourceFile) {- sourceFile.text = sourceText;- sourceFile.bindDiagnostics = [];- sourceFile.bindSuggestionDiagnostics = undefined;- sourceFile.languageVersion = languageVersion;- sourceFile.fileName = fileName;- sourceFile.languageVariant = getLanguageVariant(scriptKind);- sourceFile.isDeclarationFile = isDeclarationFile;- sourceFile.scriptKind = scriptKind;-- setExternalModuleIndicator(sourceFile);- sourceFile.setExternalModuleIndicator = setExternalModuleIndicator;- }- }-- function setContextFlag(val: boolean, flag: NodeFlags) {- if (val) {- contextFlags |= flag;- }- else {- contextFlags &= ~flag;- }- }-- function setDisallowInContext(val: boolean) {- setContextFlag(val, NodeFlags.DisallowInContext);- }-- function setYieldContext(val: boolean) {- setContextFlag(val, NodeFlags.YieldContext);- }-- function setDecoratorContext(val: boolean) {- setContextFlag(val, NodeFlags.DecoratorContext);- }-- function setAwaitContext(val: boolean) {- setContextFlag(val, NodeFlags.AwaitContext);- }-- function doOutsideOfContext<T>(context: NodeFlags, func: () => T): T {- // contextFlagsToClear will contain only the context flags that are- // currently set that we need to temporarily clear- // We don't just blindly reset to the previous flags to ensure- // that we do not mutate cached flags for the incremental- // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and- // HasAggregatedChildData).- const contextFlagsToClear = context & contextFlags;- if (contextFlagsToClear) {- // clear the requested context flags- setContextFlag(/*val*/ false, contextFlagsToClear);- const result = func();- // restore the context flags we just cleared- setContextFlag(/*val*/ true, contextFlagsToClear);- return result;- }-- // no need to do anything special as we are not in any of the requested contexts- return func();- }-- function doInsideOfContext<T>(context: NodeFlags, func: () => T): T {- // contextFlagsToSet will contain only the context flags that- // are not currently set that we need to temporarily enable.- // We don't just blindly reset to the previous flags to ensure- // that we do not mutate cached flags for the incremental- // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and- // HasAggregatedChildData).- const contextFlagsToSet = context & ~contextFlags;- if (contextFlagsToSet) {- // set the requested context flags- setContextFlag(/*val*/ true, contextFlagsToSet);- const result = func();- // reset the context flags we just set- setContextFlag(/*val*/ false, contextFlagsToSet);- return result;- }-- // no need to do anything special as we are already in all of the requested contexts- return func();- }-- function allowInAnd<T>(func: () => T): T {- return doOutsideOfContext(NodeFlags.DisallowInContext, func);- }-- function disallowInAnd<T>(func: () => T): T {- return doInsideOfContext(NodeFlags.DisallowInContext, func);- }-- function allowConditionalTypesAnd<T>(func: () => T): T {- return doOutsideOfContext(NodeFlags.DisallowConditionalTypesContext, func);- }-- function disallowConditionalTypesAnd<T>(func: () => T): T {- return doInsideOfContext(NodeFlags.DisallowConditionalTypesContext, func);- }-- function doInYieldContext<T>(func: () => T): T {- return doInsideOfContext(NodeFlags.YieldContext, func);- }-- function doInDecoratorContext<T>(func: () => T): T {- return doInsideOfContext(NodeFlags.DecoratorContext, func);- }-- function doInAwaitContext<T>(func: () => T): T {- return doInsideOfContext(NodeFlags.AwaitContext, func);- }-- function doOutsideOfAwaitContext<T>(func: () => T): T {- return doOutsideOfContext(NodeFlags.AwaitContext, func);- }-- function doInYieldAndAwaitContext<T>(func: () => T): T {- return doInsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func);- }-- function doOutsideOfYieldAndAwaitContext<T>(func: () => T): T {- return doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func);- }-- function inContext(flags: NodeFlags) {- return (contextFlags & flags) !== 0;- }-- function inYieldContext() {- return inContext(NodeFlags.YieldContext);- }-- function inDisallowInContext() {- return inContext(NodeFlags.DisallowInContext);- }-- function inDisallowConditionalTypesContext() {- return inContext(NodeFlags.DisallowConditionalTypesContext);- }-- function inDecoratorContext() {- return inContext(NodeFlags.DecoratorContext);- }-- function inAwaitContext() {- return inContext(NodeFlags.AwaitContext);- }-- function parseErrorAtCurrentToken(message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation | undefined {- return parseErrorAt(scanner.getTokenStart(), scanner.getTokenEnd(), message, ...args);- }-- function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation | undefined {- // Don't report another error if it would just be at the same position as the last error.- const lastError = lastOrUndefined(parseDiagnostics);- let result: DiagnosticWithDetachedLocation | undefined;- if (!lastError || start !== lastError.start) {- result = createDetachedDiagnostic(fileName, sourceText, start, length, message, ...args);- parseDiagnostics.push(result);- }-- // Mark that we've encountered an error. We'll set an appropriate bit on the next- // node we finish so that it can't be reused incrementally.- parseErrorBeforeNextFinishedNode = true;- return result;- }-- function parseErrorAt(start: number, end: number, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation | undefined {- return parseErrorAtPosition(start, end - start, message, ...args);- }-- function parseErrorAtRange(range: TextRange, message: DiagnosticMessage, ...args: DiagnosticArguments): void {- parseErrorAt(range.pos, range.end, message, ...args);- }-- function scanError(message: DiagnosticMessage, length: number, arg0?: any): void {- parseErrorAtPosition(scanner.getTokenEnd(), length, message, arg0);- }-- function getNodePos(): number {- return scanner.getTokenFullStart();- }-- function hasPrecedingJSDocComment() {- return scanner.hasPrecedingJSDocComment();- }-- // Use this function to access the current token instead of reading the currentToken- // variable. Since function results aren't narrowed in control flow analysis, this ensures- // that the type checker doesn't make wrong assumptions about the type of the current- // token (e.g. a call to nextToken() changes the current token but the checker doesn't- // reason about this side effect). Mainstream VMs inline simple functions like this, so- // there is no performance penalty.- function token(): SyntaxKind {- return currentToken;- }-- function nextTokenWithoutCheck() {- return currentToken = scanner.scan();- }-- function nextTokenAnd<T>(func: () => T): T {- nextToken();- return func();- }-- function nextToken(): SyntaxKind {- // if the keyword had an escape- if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) {- // issue a parse error for the escape- parseErrorAt(scanner.getTokenStart(), scanner.getTokenEnd(), Diagnostics.Keywords_cannot_contain_escape_characters);- }- return nextTokenWithoutCheck();- }-- function nextTokenJSDoc(): JSDocSyntaxKind {- return currentToken = scanner.scanJsDocToken();- }-- function nextJSDocCommentTextToken(inBackticks: boolean): JSDocSyntaxKind | SyntaxKind.JSDocCommentTextToken {- return currentToken = scanner.scanJSDocCommentTextToken(inBackticks);- }-- function reScanGreaterToken(): SyntaxKind {- return currentToken = scanner.reScanGreaterToken();- }-- function reScanSlashToken(): SyntaxKind {- return currentToken = scanner.reScanSlashToken();- }-- function reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind {- return currentToken = scanner.reScanTemplateToken(isTaggedTemplate);- }-- function reScanLessThanToken(): SyntaxKind {- return currentToken = scanner.reScanLessThanToken();- }-- function reScanHashToken(): SyntaxKind {- return currentToken = scanner.reScanHashToken();- }-- function scanJsxIdentifier(): SyntaxKind {- return currentToken = scanner.scanJsxIdentifier();- }-- function scanJsxText(): SyntaxKind {- return currentToken = scanner.scanJsxToken();- }-- function scanJsxAttributeValue(): SyntaxKind {- return currentToken = scanner.scanJsxAttributeValue();- }-- function speculationHelper<T>(callback: () => T, speculationKind: SpeculationKind): T {- // Keep track of the state we'll need to rollback to if lookahead fails (or if the- // caller asked us to always reset our state).- const saveToken = currentToken;- const saveParseDiagnosticsLength = parseDiagnostics.length;- const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;-- // Note: it is not actually necessary to save/restore the context flags here. That's- // because the saving/restoring of these flags happens naturally through the recursive- // descent nature of our parser. However, we still store this here just so we can- // assert that invariant holds.- const saveContextFlags = contextFlags;-- // If we're only looking ahead, then tell the scanner to only lookahead as well.- // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the- // same.- const result = speculationKind !== SpeculationKind.TryParse- ? scanner.lookAhead(callback)- : scanner.tryScan(callback);-- Debug.assert(saveContextFlags === contextFlags);-- // If our callback returned something 'falsy' or we're just looking ahead,- // then unconditionally restore us to where we were.- if (!result || speculationKind !== SpeculationKind.TryParse) {- currentToken = saveToken;- if (speculationKind !== SpeculationKind.Reparse) {- parseDiagnostics.length = saveParseDiagnosticsLength;- }- parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode;- }-- return result;- }-- /** Invokes the provided callback then unconditionally restores the parser to the state it- * was in immediately prior to invoking the callback. The result of invoking the callback- * is returned from this function.- */- function lookAhead<T>(callback: () => T): T {- return speculationHelper(callback, SpeculationKind.Lookahead);- }-- /** Invokes the provided callback. If the callback returns something falsy, then it restores- * the parser to the state it was in immediately prior to invoking the callback. If the- * callback returns something truthy, then the parser state is not rolled back. The result- * of invoking the callback is returned from this function.- */- function tryParse<T>(callback: () => T): T {- return speculationHelper(callback, SpeculationKind.TryParse);- }-- function isBindingIdentifier(): boolean {- if (token() === SyntaxKind.Identifier) {- return true;- }-- // `let await`/`let yield` in [Yield] or [Await] are allowed here and disallowed in the binder.- return token() > SyntaxKind.LastReservedWord;- }-- // Ignore strict mode flag because we will report an error in type checker instead.- function isIdentifier(): boolean {- if (token() === SyntaxKind.Identifier) {- return true;- }-- // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is- // considered a keyword and is not an identifier.- if (token() === SyntaxKind.YieldKeyword && inYieldContext()) {- return false;- }-- // If we have a 'await' keyword, and we're in the [Await] context, then 'await' is- // considered a keyword and is not an identifier.- if (token() === SyntaxKind.AwaitKeyword && inAwaitContext()) {- return false;- }-- return token() > SyntaxKind.LastReservedWord;- }-- function parseExpected(kind: PunctuationOrKeywordSyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean {- if (token() === kind) {- if (shouldAdvance) {- nextToken();- }- return true;- }-- // Report specific message if provided with one. Otherwise, report generic fallback message.- if (diagnosticMessage) {- parseErrorAtCurrentToken(diagnosticMessage);- }- else {- parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind));- }- return false;- }-- const viableKeywordSuggestions = Object.keys(textToKeywordObj).filter(keyword => keyword.length > 2);-- /**- * Provides a better error message than the generic "';' expected" if possible for- * known common variants of a missing semicolon, such as from a mispelled names.- *- * @param node Node preceding the expected semicolon location.- */- function parseErrorForMissingSemicolonAfter(node: Expression | PropertyName): void {- // Tagged template literals are sometimes used in places where only simple strings are allowed, i.e.:- // module `M1` {- // ^^^^^^^^^^^ This block is parsed as a template literal like module`M1`.- if (isTaggedTemplateExpression(node)) {- parseErrorAt(skipTrivia(sourceText, node.template.pos), node.template.end, Diagnostics.Module_declaration_names_may_only_use_or_quoted_strings);- return;- }-- // Otherwise, if this isn't a well-known keyword-like identifier, give the generic fallback message.- const expressionText = isIdentifierNode(node) ? idText(node) : undefined;- if (!expressionText || !isIdentifierText(expressionText, languageVersion)) {- parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken));- return;- }-- const pos = skipTrivia(sourceText, node.pos);-- // Some known keywords are likely signs of syntax being used improperly.- switch (expressionText) {- case "const":- case "let":- case "var":- parseErrorAt(pos, node.end, Diagnostics.Variable_declaration_not_allowed_at_this_location);- return;-- case "declare":- // If a declared node failed to parse, it would have emitted a diagnostic already.- return;-- case "interface":- parseErrorForInvalidName(Diagnostics.Interface_name_cannot_be_0, Diagnostics.Interface_must_be_given_a_name, SyntaxKind.OpenBraceToken);- return;-- case "is":- parseErrorAt(pos, scanner.getTokenStart(), Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods);- return;-- case "module":- case "namespace":- parseErrorForInvalidName(Diagnostics.Namespace_name_cannot_be_0, Diagnostics.Namespace_must_be_given_a_name, SyntaxKind.OpenBraceToken);- return;-- case "type":- parseErrorForInvalidName(Diagnostics.Type_alias_name_cannot_be_0, Diagnostics.Type_alias_must_be_given_a_name, SyntaxKind.EqualsToken);- return;- }-- // The user alternatively might have misspelled or forgotten to add a space after a common keyword.- const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, identity) ?? getSpaceSuggestion(expressionText);- if (suggestion) {- parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion);- return;- }-- // Unknown tokens are handled with their own errors in the scanner- if (token() === SyntaxKind.Unknown) {- return;- }-- // Otherwise, we know this some kind of unknown word, not just a missing expected semicolon.- parseErrorAt(pos, node.end, Diagnostics.Unexpected_keyword_or_identifier);- }-- /**- * Reports a diagnostic error for the current token being an invalid name.- *- * @param blankDiagnostic Diagnostic to report for the case of the name being blank (matched tokenIfBlankName).- * @param nameDiagnostic Diagnostic to report for all other cases.- * @param tokenIfBlankName Current token if the name was invalid for being blank (not provided / skipped).- */- function parseErrorForInvalidName(nameDiagnostic: DiagnosticMessage, blankDiagnostic: DiagnosticMessage, tokenIfBlankName: SyntaxKind) {- if (token() === tokenIfBlankName) {- parseErrorAtCurrentToken(blankDiagnostic);- }- else {- parseErrorAtCurrentToken(nameDiagnostic, scanner.getTokenValue());- }- }-- function getSpaceSuggestion(expressionText: string) {- for (const keyword of viableKeywordSuggestions) {- if (expressionText.length > keyword.length + 2 && startsWith(expressionText, keyword)) {- return `${keyword} ${expressionText.slice(keyword.length)}`;- }- }-- return undefined;- }-- function parseSemicolonAfterPropertyName(name: PropertyName, type: TypeNode | undefined, initializer: Expression | undefined) {- if (token() === SyntaxKind.AtToken && !scanner.hasPrecedingLineBreak()) {- parseErrorAtCurrentToken(Diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations);- return;- }-- if (token() === SyntaxKind.OpenParenToken) {- parseErrorAtCurrentToken(Diagnostics.Cannot_start_a_function_call_in_a_type_annotation);- nextToken();- return;- }-- if (type && !canParseSemicolon()) {- if (initializer) {- parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken));- }- else {- parseErrorAtCurrentToken(Diagnostics.Expected_for_property_initializer);- }- return;- }-- if (tryParseSemicolon()) {- return;- }-- if (initializer) {- parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken));- return;- }-- parseErrorForMissingSemicolonAfter(name);- }-- function parseExpectedJSDoc(kind: JSDocSyntaxKind) {- if (token() === kind) {- nextTokenJSDoc();- return true;- }- Debug.assert(isKeywordOrPunctuation(kind));- parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind));- return false;- }-- function parseExpectedMatchingBrackets(openKind: PunctuationSyntaxKind, closeKind: PunctuationSyntaxKind, openParsed: boolean, openPosition: number) {- if (token() === closeKind) {- nextToken();- return;- }- const lastError = parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(closeKind));- if (!openParsed) {- return;- }- if (lastError) {- addRelatedInfo(- lastError,- createDetachedDiagnostic(fileName, sourceText, openPosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, tokenToString(openKind), tokenToString(closeKind)),- );- }- }-- function parseOptional(t: SyntaxKind): boolean {- if (token() === t) {- nextToken();- return true;- }- return false;- }-- function parseOptionalToken<TKind extends SyntaxKind>(t: TKind): Token<TKind>;- function parseOptionalToken(t: SyntaxKind): Node | undefined {- if (token() === t) {- return parseTokenNode();- }- return undefined;- }-- function parseOptionalTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>;- function parseOptionalTokenJSDoc(t: JSDocSyntaxKind): Node | undefined {- if (token() === t) {- return parseTokenNodeJSDoc();- }- return undefined;- }-- function parseExpectedToken<TKind extends SyntaxKind>(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: string): Token<TKind>;- function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: string): Node {- return parseOptionalToken(t) ||- createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t)!);- }-- function parseExpectedTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>;- function parseExpectedTokenJSDoc(t: JSDocSyntaxKind): Node {- const optional = parseOptionalTokenJSDoc(t);- if (optional) return optional;- Debug.assert(isKeywordOrPunctuation(t));- return createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t));- }-- function parseTokenNode<T extends Node>(): T {- const pos = getNodePos();- const kind = token();- nextToken();- return finishNode(factoryCreateToken(kind), pos) as T;- }-- function parseTokenNodeJSDoc<T extends Node>(): T {- const pos = getNodePos();- const kind = token();- nextTokenJSDoc();- return finishNode(factoryCreateToken(kind), pos) as T;- }-- function canParseSemicolon() {- // If there's a real semicolon, then we can always parse it out.- if (token() === SyntaxKind.SemicolonToken) {- return true;- }-- // We can parse out an optional semicolon in ASI cases in the following cases.- return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak();- }-- function tryParseSemicolon() {- if (!canParseSemicolon()) {- return false;- }-- if (token() === SyntaxKind.SemicolonToken) {- // consume the semicolon if it was explicitly provided.- nextToken();- }-- return true;- }-- function parseSemicolon(): boolean {- return tryParseSemicolon() || parseExpected(SyntaxKind.SemicolonToken);- }-- function createNodeArray<T extends Node>(elements: T[], pos: number, end?: number, hasTrailingComma?: boolean): NodeArray<T> {- const array = factoryCreateNodeArray(elements, hasTrailingComma);- setTextRangePosEnd(array, pos, end ?? scanner.getTokenFullStart());- return array;- }-- function finishNode<T extends Node>(node: T, pos: number, end?: number): T {- setTextRangePosEnd(node, pos, end ?? scanner.getTokenFullStart());- if (contextFlags) {- (node as Mutable<T>).flags |= contextFlags;- }-- // Keep track on the node if we encountered an error while parsing it. If we did, then- // we cannot reuse the node incrementally. Once we've marked this node, clear out the- // flag so that we don't mark any subsequent nodes.- if (parseErrorBeforeNextFinishedNode) {- parseErrorBeforeNextFinishedNode = false;- (node as Mutable<T>).flags |= NodeFlags.ThisNodeHasError;- }-- return node;- }-- function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): T;- function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, ...args: DiagnosticArguments): T;- function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): T {- if (reportAtCurrentPosition) {- parseErrorAtPosition(scanner.getTokenFullStart(), 0, diagnosticMessage!, ...args);- }- else if (diagnosticMessage) {- parseErrorAtCurrentToken(diagnosticMessage, ...args);- }-- const pos = getNodePos();- const result = kind === SyntaxKind.Identifier ? factoryCreateIdentifier("", /*originalKeywordKind*/ undefined) :- isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) :- kind === SyntaxKind.NumericLiteral ? factoryCreateNumericLiteral("", /*numericLiteralFlags*/ undefined) :- kind === SyntaxKind.StringLiteral ? factoryCreateStringLiteral("", /*isSingleQuote*/ undefined) :- kind === SyntaxKind.MissingDeclaration ? factory.createMissingDeclaration() :- factoryCreateToken(kind);- return finishNode(result, pos) as T;- }-- function internIdentifier(text: string): string {- let identifier = identifiers.get(text);- if (identifier === undefined) {- identifiers.set(text, identifier = text);- }- return identifier;- }-- // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues- // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for- // each identifier in order to reduce memory consumption.- function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier {- if (isIdentifier) {- identifierCount++;- const pos = scanner.hasPrecedingJSDocLeadingAsterisks() ? scanner.getTokenStart() : getNodePos();- // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker- const originalKeywordKind = token();- const text = internIdentifier(scanner.getTokenValue());- const hasExtendedUnicodeEscape = scanner.hasExtendedUnicodeEscape();- nextTokenWithoutCheck();- return finishNode(factoryCreateIdentifier(text, originalKeywordKind, hasExtendedUnicodeEscape), pos);- }-- if (token() === SyntaxKind.PrivateIdentifier) {- parseErrorAtCurrentToken(privateIdentifierDiagnosticMessage || Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies);- return createIdentifier(/*isIdentifier*/ true);- }-- if (token() === SyntaxKind.Unknown && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.Identifier)) {- // Scanner has already recorded an 'Invalid character' error, so no need to add another from the parser.- return createIdentifier(/*isIdentifier*/ true);- }-- identifierCount++;- // Only for end of file because the error gets reported incorrectly on embedded script tags.- const reportAtCurrentPosition = token() === SyntaxKind.EndOfFileToken;-- const isReservedWord = scanner.isReservedWord();- const msgArg = scanner.getTokenText();-- const defaultMessage = isReservedWord ?- Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here :- Diagnostics.Identifier_expected;-- return createMissingNode<Identifier>(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || defaultMessage, msgArg);- }-- function parseBindingIdentifier(privateIdentifierDiagnosticMessage?: DiagnosticMessage) {- return createIdentifier(isBindingIdentifier(), /*diagnosticMessage*/ undefined, privateIdentifierDiagnosticMessage);- }-- function parseIdentifier(diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier {- return createIdentifier(isIdentifier(), diagnosticMessage, privateIdentifierDiagnosticMessage);- }-- function parseIdentifierName(diagnosticMessage?: DiagnosticMessage): Identifier {- return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage);- }-- function parseIdentifierNameErrorOnUnicodeEscapeSequence(): Identifier {- if (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape()) {- parseErrorAtCurrentToken(Diagnostics.Unicode_escape_sequence_cannot_appear_here);- }- return createIdentifier(tokenIsIdentifierOrKeyword(token()));- }-- function isLiteralPropertyName(): boolean {- return tokenIsIdentifierOrKeyword(token()) ||- token() === SyntaxKind.StringLiteral ||- token() === SyntaxKind.NumericLiteral ||- token() === SyntaxKind.BigIntLiteral;- }-- function isImportAttributeName(): boolean {- return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.StringLiteral;- }-- function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName {- if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral) {- const node = parseLiteralNode() as StringLiteral | NumericLiteral | BigIntLiteral;- node.text = internIdentifier(node.text);- return node;- }- if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) {- return parseComputedPropertyName();- }- if (token() === SyntaxKind.PrivateIdentifier) {- return parsePrivateIdentifier();- }- return parseIdentifierName();- }-- function parsePropertyName(): PropertyName {- return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true);- }-- function parseComputedPropertyName(): ComputedPropertyName {- // PropertyName [Yield]:- // LiteralPropertyName- // ComputedPropertyName[?Yield]- const pos = getNodePos();- parseExpected(SyntaxKind.OpenBracketToken);- // We parse any expression (including a comma expression). But the grammar- // says that only an assignment expression is allowed, so the grammar checker- // will error if it sees a comma expression.- const expression = allowInAnd(parseExpression);- parseExpected(SyntaxKind.CloseBracketToken);- return finishNode(factory.createComputedPropertyName(expression), pos);- }-- function parsePrivateIdentifier(): PrivateIdentifier {- const pos = getNodePos();- const node = factoryCreatePrivateIdentifier(internIdentifier(scanner.getTokenValue()));- nextToken();- return finishNode(node, pos);- }-- function parseContextualModifier(t: SyntaxKind): boolean {- return token() === t && tryParse(nextTokenCanFollowModifier);- }-- function nextTokenIsOnSameLineAndCanFollowModifier() {- nextToken();- if (scanner.hasPrecedingLineBreak()) {- return false;- }- return canFollowModifier();- }-- function nextTokenCanFollowModifier() {- switch (token()) {- case SyntaxKind.ConstKeyword:- // 'const' is only a modifier if followed by 'enum'.- return nextToken() === SyntaxKind.EnumKeyword;- case SyntaxKind.ExportKeyword:- nextToken();- if (token() === SyntaxKind.DefaultKeyword) {- return lookAhead(nextTokenCanFollowDefaultKeyword);- }- if (token() === SyntaxKind.TypeKeyword) {- return lookAhead(nextTokenCanFollowExportModifier);- }- return canFollowExportModifier();- case SyntaxKind.DefaultKeyword:- return nextTokenCanFollowDefaultKeyword();- case SyntaxKind.StaticKeyword:- case SyntaxKind.GetKeyword:- case SyntaxKind.SetKeyword:- nextToken();- return canFollowModifier();- default:- return nextTokenIsOnSameLineAndCanFollowModifier();- }- }-- function canFollowExportModifier(): boolean {- return token() === SyntaxKind.AtToken- || token() !== SyntaxKind.AsteriskToken- && token() !== SyntaxKind.AsKeyword- && token() !== SyntaxKind.OpenBraceToken- && canFollowModifier();- }-- function nextTokenCanFollowExportModifier(): boolean {- nextToken();- return canFollowExportModifier();- }-- function parseAnyContextualModifier(): boolean {- return isModifierKind(token()) && tryParse(nextTokenCanFollowModifier);- }-- function canFollowModifier(): boolean {- return token() === SyntaxKind.OpenBracketToken- || token() === SyntaxKind.OpenBraceToken- || token() === SyntaxKind.AsteriskToken- || token() === SyntaxKind.DotDotDotToken- || isLiteralPropertyName();- }-- function nextTokenCanFollowDefaultKeyword(): boolean {- nextToken();- return token() === SyntaxKind.ClassKeyword- || token() === SyntaxKind.FunctionKeyword- || token() === SyntaxKind.InterfaceKeyword- || token() === SyntaxKind.AtToken- || (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine))- || (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine));- }-- // True if positioned at the start of a list element- function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean {- const node = currentNode(parsingContext);- if (node) {- return true;- }-- switch (parsingContext) {- case ParsingContext.SourceElements:- case ParsingContext.BlockStatements:- case ParsingContext.SwitchClauseStatements:- // If we're in error recovery, then we don't want to treat ';' as an empty statement.- // The problem is that ';' can show up in far too many contexts, and if we see one- // and assume it's a statement, then we may bail out inappropriately from whatever- // we're parsing. For example, if we have a semicolon in the middle of a class, then- // we really don't want to assume the class is over and we're on a statement in the- // outer module. We just want to consume and move on.- return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement();- case ParsingContext.SwitchClauses:- return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;- case ParsingContext.TypeMembers:- return lookAhead(isTypeMemberStart);- case ParsingContext.ClassMembers:- // We allow semicolons as class elements (as specified by ES6) as long as we're- // not in error recovery. If we're in error recovery, we don't want an errant- // semicolon to be treated as a class member (since they're almost always used- // for statements.- return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery);- case ParsingContext.EnumMembers:- // Include open bracket computed properties. This technically also lets in indexers,- // which would be a candidate for improved error reporting.- return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName();- case ParsingContext.ObjectLiteralMembers:- switch (token()) {- case SyntaxKind.OpenBracketToken:- case SyntaxKind.AsteriskToken:- case SyntaxKind.DotDotDotToken:- case SyntaxKind.DotToken: // Not an object literal member, but don't want to close the object (see `tests/cases/fourslash/completionsDotInObjectLiteral.ts`)- return true;- default:- return isLiteralPropertyName();- }- case ParsingContext.RestProperties:- return isLiteralPropertyName();- case ParsingContext.ObjectBindingElements:- return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();- case ParsingContext.ImportAttributes:- return isImportAttributeName();- case ParsingContext.HeritageClauseElement:- // If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{`- // That way we won't consume the body of a class in its heritage clause.- if (token() === SyntaxKind.OpenBraceToken) {- return lookAhead(isValidHeritageClauseObjectLiteral);- }-- if (!inErrorRecovery) {- return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword();- }- else {- // If we're in error recovery we tighten up what we're willing to match.- // That way we don't treat something like "this" as a valid heritage clause- // element during recovery.- return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword();- }- case ParsingContext.VariableDeclarations:- return isBindingIdentifierOrPrivateIdentifierOrPattern();- case ParsingContext.ArrayBindingElements:- return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern();- case ParsingContext.TypeParameters:- return token() === SyntaxKind.InKeyword || token() === SyntaxKind.ConstKeyword || isIdentifier();- case ParsingContext.ArrayLiteralMembers:- switch (token()) {- case SyntaxKind.CommaToken:- case SyntaxKind.DotToken: // Not an array literal member, but don't want to close the array (see `tests/cases/fourslash/completionsDotInArrayLiteralInObjectLiteral.ts`)- return true;- }- // falls through- case ParsingContext.ArgumentExpressions:- return token() === SyntaxKind.DotDotDotToken || isStartOfExpression();- case ParsingContext.Parameters:- return isStartOfParameter(/*isJSDocParameter*/ false);- case ParsingContext.JSDocParameters:- return isStartOfParameter(/*isJSDocParameter*/ true);- case ParsingContext.TypeArguments:- case ParsingContext.TupleElementTypes:- return token() === SyntaxKind.CommaToken || isStartOfType();- case ParsingContext.HeritageClauses:- return isHeritageClause();- case ParsingContext.ImportOrExportSpecifiers:- // bail out if the next token is [FromKeyword StringLiteral].- // That means we're in something like `import { from "mod"`. Stop here can give better error message.- if (token() === SyntaxKind.FromKeyword && lookAhead(nextTokenIsStringLiteral)) {- return false;- }- if (token() === SyntaxKind.StringLiteral) {- return true; // For "arbitrary module namespace identifiers"- }- return tokenIsIdentifierOrKeyword(token());- case ParsingContext.JsxAttributes:- return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.OpenBraceToken;- case ParsingContext.JsxChildren:- return true;- case ParsingContext.JSDocComment:- return true;- case ParsingContext.Count:- return Debug.fail("ParsingContext.Count used as a context"); // Not a real context, only a marker.- default:- Debug.assertNever(parsingContext, "Non-exhaustive case in 'isListElement'.");- }- }-- function isValidHeritageClauseObjectLiteral() {- Debug.assert(token() === SyntaxKind.OpenBraceToken);- if (nextToken() === SyntaxKind.CloseBraceToken) {- // if we see "extends {}" then only treat the {} as what we're extending (and not- // the class body) if we have:- //- // extends {} {- // extends {},- // extends {} extends- // extends {} implements-- const next = nextToken();- return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword;- }-- return true;- }-- function nextTokenIsIdentifier() {- nextToken();- return isIdentifier();- }-- function nextTokenIsIdentifierOrKeyword() {- nextToken();- return tokenIsIdentifierOrKeyword(token());- }-- function nextTokenIsIdentifierOrKeywordOrGreaterThan() {- nextToken();- return tokenIsIdentifierOrKeywordOrGreaterThan(token());- }-- function isHeritageClauseExtendsOrImplementsKeyword(): boolean {- if (- token() === SyntaxKind.ImplementsKeyword ||- token() === SyntaxKind.ExtendsKeyword- ) {- return lookAhead(nextTokenIsStartOfExpression);- }-- return false;- }-- function nextTokenIsStartOfExpression() {- nextToken();- return isStartOfExpression();- }-- function nextTokenIsStartOfType() {- nextToken();- return isStartOfType();- }-- // True if positioned at a list terminator- function isListTerminator(kind: ParsingContext): boolean {- if (token() === SyntaxKind.EndOfFileToken) {- // Being at the end of the file ends all lists.- return true;- }-- switch (kind) {- case ParsingContext.BlockStatements:- case ParsingContext.SwitchClauses:- case ParsingContext.TypeMembers:- case ParsingContext.ClassMembers:- case ParsingContext.EnumMembers:- case ParsingContext.ObjectLiteralMembers:- case ParsingContext.ObjectBindingElements:- case ParsingContext.ImportOrExportSpecifiers:- case ParsingContext.ImportAttributes:- return token() === SyntaxKind.CloseBraceToken;- case ParsingContext.SwitchClauseStatements:- return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;- case ParsingContext.HeritageClauseElement:- return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;- case ParsingContext.VariableDeclarations:- return isVariableDeclaratorListTerminator();- case ParsingContext.TypeParameters:- // Tokens other than '>' are here for better error recovery- return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;- case ParsingContext.ArgumentExpressions:- // Tokens other than ')' are here for better error recovery- return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken;- case ParsingContext.ArrayLiteralMembers:- case ParsingContext.TupleElementTypes:- case ParsingContext.ArrayBindingElements:- return token() === SyntaxKind.CloseBracketToken;- case ParsingContext.JSDocParameters:- case ParsingContext.Parameters:- case ParsingContext.RestProperties:- // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery- return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/;- case ParsingContext.TypeArguments:- // All other tokens should cause the type-argument to terminate except comma token- return token() !== SyntaxKind.CommaToken;- case ParsingContext.HeritageClauses:- return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.CloseBraceToken;- case ParsingContext.JsxAttributes:- return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.SlashToken;- case ParsingContext.JsxChildren:- return token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsSlash);- default:- return false;- }- }-- function isVariableDeclaratorListTerminator(): boolean {- // If we can consume a semicolon (either explicitly, or with ASI), then consider us done- // with parsing the list of variable declarators.- if (canParseSemicolon()) {- return true;- }-- // in the case where we're parsing the variable declarator of a 'for-in' statement, we- // are done if we see an 'in' keyword in front of us. Same with for-of- if (isInOrOfKeyword(token())) {- return true;- }-- // ERROR RECOVERY TWEAK:- // For better error recovery, if we see an '=>' then we just stop immediately. We've got an- // arrow function here and it's going to be very unlikely that we'll resynchronize and get- // another variable declaration.- if (token() === SyntaxKind.EqualsGreaterThanToken) {- return true;- }-- // Keep trying to parse out variable declarators.- return false;- }-- // True if positioned at element or terminator of the current list or any enclosing list- function isInSomeParsingContext(): boolean {- // We should be in at least one parsing context, be it SourceElements while parsing- // a SourceFile, or JSDocComment when lazily parsing JSDoc.- Debug.assert(parsingContext, "Missing parsing context");- for (let kind = 0; kind < ParsingContext.Count; kind++) {- if (parsingContext & (1 << kind)) {- if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) {- return true;- }- }- }-- return false;- }-- // Parses a list of elements- function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> {- const saveParsingContext = parsingContext;- parsingContext |= 1 << kind;- const list = [];- const listPos = getNodePos();-- while (!isListTerminator(kind)) {- if (isListElement(kind, /*inErrorRecovery*/ false)) {- list.push(parseListElement(kind, parseElement));-- continue;- }-- if (abortParsingListOrMoveToNextToken(kind)) {- break;- }- }-- parsingContext = saveParsingContext;- return createNodeArray(list, listPos);- }-- function parseListElement<T extends Node | undefined>(parsingContext: ParsingContext, parseElement: () => T): T {- const node = currentNode(parsingContext);- if (node) {- return consumeNode(node) as T;- }-- return parseElement();- }-- function currentNode(parsingContext: ParsingContext, pos?: number): Node | undefined {- // If we don't have a cursor or the parsing context isn't reusable, there's nothing to reuse.- //- // If there is an outstanding parse error that we've encountered, but not attached to- // some node, then we cannot get a node from the old source tree. This is because we- // want to mark the next node we encounter as being unusable.- //- // Note: This may be too conservative. Perhaps we could reuse the node and set the bit- // on it (or its leftmost child) as having the error. For now though, being conservative- // is nice and likely won't ever affect perf.- if (!syntaxCursor || !isReusableParsingContext(parsingContext) || parseErrorBeforeNextFinishedNode) {- return undefined;- }-- const node = syntaxCursor.currentNode(pos ?? scanner.getTokenFullStart());-- // Can't reuse a missing node.- // Can't reuse a node that intersected the change range.- // Can't reuse a node that contains a parse error. This is necessary so that we- // produce the same set of errors again.- if (nodeIsMissing(node) || intersectsIncrementalChange(node) || containsParseError(node)) {- return undefined;- }-- // We can only reuse a node if it was parsed under the same strict mode that we're- // currently in. i.e. if we originally parsed a node in non-strict mode, but then- // the user added 'using strict' at the top of the file, then we can't use that node- // again as the presence of strict mode may cause us to parse the tokens in the file- // differently.- //- // Note: we *can* reuse tokens when the strict mode changes. That's because tokens- // are unaffected by strict mode. It's just the parser will decide what to do with it- // differently depending on what mode it is in.- //- // This also applies to all our other context flags as well.- const nodeContextFlags = node.flags & NodeFlags.ContextFlags;- if (nodeContextFlags !== contextFlags) {- return undefined;- }-- // Ok, we have a node that looks like it could be reused. Now verify that it is valid- // in the current list parsing context that we're currently at.- if (!canReuseNode(node, parsingContext)) {- return undefined;- }-- if (canHaveJSDoc(node) && node.jsDoc?.jsDocCache) {- // jsDocCache may include tags from parent nodes, which might have been modified.- node.jsDoc.jsDocCache = undefined;- }-- return node;- }-- function consumeNode(node: Node) {- // Move the scanner so it is after the node we just consumed.- scanner.resetTokenState(node.end);- nextToken();- return node;- }-- function isReusableParsingContext(parsingContext: ParsingContext): boolean {- switch (parsingContext) {- case ParsingContext.ClassMembers:- case ParsingContext.SwitchClauses:- case ParsingContext.SourceElements:- case ParsingContext.BlockStatements:- case ParsingContext.SwitchClauseStatements:- case ParsingContext.EnumMembers:- case ParsingContext.TypeMembers:- case ParsingContext.VariableDeclarations:- case ParsingContext.JSDocParameters:- case ParsingContext.Parameters:- return true;- }- return false;- }-- function canReuseNode(node: Node, parsingContext: ParsingContext): boolean {- switch (parsingContext) {- case ParsingContext.ClassMembers:- return isReusableClassMember(node);-- case ParsingContext.SwitchClauses:- return isReusableSwitchClause(node);-- case ParsingContext.SourceElements:- case ParsingContext.BlockStatements:- case ParsingContext.SwitchClauseStatements:- return isReusableStatement(node);-- case ParsingContext.EnumMembers:- return isReusableEnumMember(node);-- case ParsingContext.TypeMembers:- return isReusableTypeMember(node);-- case ParsingContext.VariableDeclarations:- return isReusableVariableDeclaration(node);-- case ParsingContext.JSDocParameters:- case ParsingContext.Parameters:- return isReusableParameter(node);-- // Any other lists we do not care about reusing nodes in. But feel free to add if- // you can do so safely. Danger areas involve nodes that may involve speculative- // parsing. If speculative parsing is involved with the node, then the range the- // parser reached while looking ahead might be in the edited range (see the example- // in canReuseVariableDeclaratorNode for a good case of this).-- // case ParsingContext.HeritageClauses:- // This would probably be safe to reuse. There is no speculative parsing with- // heritage clauses.-- // case ParsingContext.TypeParameters:- // This would probably be safe to reuse. There is no speculative parsing with- // type parameters. Note that that's because type *parameters* only occur in- // unambiguous *type* contexts. While type *arguments* occur in very ambiguous- // *expression* contexts.-- // case ParsingContext.TupleElementTypes:- // This would probably be safe to reuse. There is no speculative parsing with- // tuple types.-- // Technically, type argument list types are probably safe to reuse. While- // speculative parsing is involved with them (since type argument lists are only- // produced from speculative parsing a < as a type argument list), we only have- // the types because speculative parsing succeeded. Thus, the lookahead never- // went past the end of the list and rewound.- // case ParsingContext.TypeArguments:-- // Note: these are almost certainly not safe to ever reuse. Expressions commonly- // need a large amount of lookahead, and we should not reuse them as they may- // have actually intersected the edit.- // case ParsingContext.ArgumentExpressions:-- // This is not safe to reuse for the same reason as the 'AssignmentExpression'- // cases. i.e. a property assignment may end with an expression, and thus might- // have lookahead far beyond it's old node.- // case ParsingContext.ObjectLiteralMembers:-- // This is probably not safe to reuse. There can be speculative parsing with- // type names in a heritage clause. There can be generic names in the type- // name list, and there can be left hand side expressions (which can have type- // arguments.)- // case ParsingContext.HeritageClauseElement:-- // Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes- // on any given element. Same for children.- // case ParsingContext.JsxAttributes:- // case ParsingContext.JsxChildren:- }-- return false;- }-- function isReusableClassMember(node: Node) {- if (node) {- switch (node.kind) {- case SyntaxKind.Constructor:- case SyntaxKind.IndexSignature:- case SyntaxKind.GetAccessor:- case SyntaxKind.SetAccessor:- case SyntaxKind.PropertyDeclaration:- case SyntaxKind.SemicolonClassElement:- return true;- case SyntaxKind.MethodDeclaration:- // Method declarations are not necessarily reusable. An object-literal- // may have a method calls "constructor(...)" and we must reparse that- // into an actual .ConstructorDeclaration.- const methodDeclaration = node as MethodDeclaration;- const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier &&- methodDeclaration.name.escapedText === "constructor";-- return !nameIsConstructor;- }- }-- return false;- }-- function isReusableSwitchClause(node: Node) {- if (node) {- switch (node.kind) {- case SyntaxKind.CaseClause:- case SyntaxKind.DefaultClause:- return true;- }- }-- return false;- }-- function isReusableStatement(node: Node) {- if (node) {- switch (node.kind) {- case SyntaxKind.FunctionDeclaration:- case SyntaxKind.VariableStatement:- case SyntaxKind.Block:- case SyntaxKind.IfStatement:- case SyntaxKind.ExpressionStatement:- case SyntaxKind.ThrowStatement:- case SyntaxKind.ReturnStatement:- case SyntaxKind.SwitchStatement:- case SyntaxKind.BreakStatement:- case SyntaxKind.ContinueStatement:- case SyntaxKind.ForInStatement:- case SyntaxKind.ForOfStatement:- case SyntaxKind.ForStatement:- case SyntaxKind.WhileStatement:- case SyntaxKind.WithStatement:- case SyntaxKind.EmptyStatement:- case SyntaxKind.TryStatement:- case SyntaxKind.LabeledStatement:- case SyntaxKind.DoStatement:- case SyntaxKind.DebuggerStatement:- case SyntaxKind.ImportDeclaration:- case SyntaxKind.ImportEqualsDeclaration:- case SyntaxKind.ExportDeclaration:- case SyntaxKind.ExportAssignment:- case SyntaxKind.ModuleDeclaration:- case SyntaxKind.ClassDeclaration:- case SyntaxKind.InterfaceDeclaration:- case SyntaxKind.EnumDeclaration:- case SyntaxKind.TypeAliasDeclaration:- return true;- }- }-- return false;- }-- function isReusableEnumMember(node: Node) {- return node.kind === SyntaxKind.EnumMember;- }-- function isReusableTypeMember(node: Node) {- if (node) {- switch (node.kind) {- case SyntaxKind.ConstructSignature:- case SyntaxKind.MethodSignature:- case SyntaxKind.IndexSignature:- case SyntaxKind.PropertySignature:- case SyntaxKind.CallSignature:- return true;- }- }-- return false;- }-- function isReusableVariableDeclaration(node: Node) {- if (node.kind !== SyntaxKind.VariableDeclaration) {- return false;- }-- // Very subtle incremental parsing bug. Consider the following code:- //- // let v = new List < A, B- //- // This is actually legal code. It's a list of variable declarators "v = new List<A"- // on one side and "B" on the other. If you then change that to:- //- // let v = new List < A, B >()- //- // then we have a problem. "v = new List<A" doesn't intersect the change range, so we- // start reparsing at "B" and we completely fail to handle this properly.- //- // In order to prevent this, we do not allow a variable declarator to be reused if it- // has an initializer.- const variableDeclarator = node as VariableDeclaration;- return variableDeclarator.initializer === undefined;- }-- function isReusableParameter(node: Node) {- if (node.kind !== SyntaxKind.Parameter) {- return false;- }-- // See the comment in isReusableVariableDeclaration for why we do this.- const parameter = node as ParameterDeclaration;- return parameter.initializer === undefined;- }-- // Returns true if we should abort parsing.- function abortParsingListOrMoveToNextToken(kind: ParsingContext) {- parsingContextErrors(kind);- if (isInSomeParsingContext()) {- return true;- }-- nextToken();- return false;- }-- function parsingContextErrors(context: ParsingContext) {- switch (context) {- case ParsingContext.SourceElements:- return token() === SyntaxKind.DefaultKeyword- ? parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ExportKeyword))- : parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected);- case ParsingContext.BlockStatements:- return parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected);- case ParsingContext.SwitchClauses:- return parseErrorAtCurrentToken(Diagnostics.case_or_default_expected);- case ParsingContext.SwitchClauseStatements:- return parseErrorAtCurrentToken(Diagnostics.Statement_expected);- case ParsingContext.RestProperties: // fallthrough- case ParsingContext.TypeMembers:- return parseErrorAtCurrentToken(Diagnostics.Property_or_signature_expected);- case ParsingContext.ClassMembers:- return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected);- case ParsingContext.EnumMembers:- return parseErrorAtCurrentToken(Diagnostics.Enum_member_expected);- case ParsingContext.HeritageClauseElement:- return parseErrorAtCurrentToken(Diagnostics.Expression_expected);- case ParsingContext.VariableDeclarations:- return isKeyword(token())- ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, tokenToString(token())!)- : parseErrorAtCurrentToken(Diagnostics.Variable_declaration_expected);- case ParsingContext.ObjectBindingElements:- return parseErrorAtCurrentToken(Diagnostics.Property_destructuring_pattern_expected);- case ParsingContext.ArrayBindingElements:- return parseErrorAtCurrentToken(Diagnostics.Array_element_destructuring_pattern_expected);- case ParsingContext.ArgumentExpressions:- return parseErrorAtCurrentToken(Diagnostics.Argument_expression_expected);- case ParsingContext.ObjectLiteralMembers:- return parseErrorAtCurrentToken(Diagnostics.Property_assignment_expected);- case ParsingContext.ArrayLiteralMembers:- return parseErrorAtCurrentToken(Diagnostics.Expression_or_comma_expected);- case ParsingContext.JSDocParameters:- return parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected);- case ParsingContext.Parameters:- return isKeyword(token())- ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_parameter_name, tokenToString(token())!)- : parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected);- case ParsingContext.TypeParameters:- return parseErrorAtCurrentToken(Diagnostics.Type_parameter_declaration_expected);- case ParsingContext.TypeArguments:- return parseErrorAtCurrentToken(Diagnostics.Type_argument_expected);- case ParsingContext.TupleElementTypes:- return parseErrorAtCurrentToken(Diagnostics.Type_expected);- case ParsingContext.HeritageClauses:- return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_expected);- case ParsingContext.ImportOrExportSpecifiers:- if (token() === SyntaxKind.FromKeyword) {- return parseErrorAtCurrentToken(Diagnostics._0_expected, "}");- }- return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);- case ParsingContext.JsxAttributes:- return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);- case ParsingContext.JsxChildren:- return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);- case ParsingContext.ImportAttributes:- return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected);- case ParsingContext.JSDocComment:- return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);- case ParsingContext.Count:- return Debug.fail("ParsingContext.Count used as a context"); // Not a real context, only a marker.- default:- Debug.assertNever(context);- }- }-- // Parses a comma-delimited list of elements- function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<T>;- function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined;- function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined {- const saveParsingContext = parsingContext;- parsingContext |= 1 << kind;- const list: NonNullable<T>[] = [];- const listPos = getNodePos();-- let commaStart = -1; // Meaning the previous token was not a comma- while (true) {- if (isListElement(kind, /*inErrorRecovery*/ false)) {- const startPos = scanner.getTokenFullStart();- const result = parseListElement(kind, parseElement);- if (!result) {- parsingContext = saveParsingContext;- return undefined;- }- list.push(result);- commaStart = scanner.getTokenStart();-- if (parseOptional(SyntaxKind.CommaToken)) {- // No need to check for a zero length node since we know we parsed a comma- continue;- }-- commaStart = -1; // Back to the state where the last token was not a comma- if (isListTerminator(kind)) {- break;- }-- // We didn't get a comma, and the list wasn't terminated, explicitly parse- // out a comma so we give a good error message.- parseExpected(SyntaxKind.CommaToken, getExpectedCommaDiagnostic(kind));-- // If the token was a semicolon, and the caller allows that, then skip it and- // continue. This ensures we get back on track and don't result in tons of- // parse errors. For example, this can happen when people do things like use- // a semicolon to delimit object literal members. Note: we'll have already- // reported an error when we called parseExpected above.- if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) {- nextToken();- }- if (startPos === scanner.getTokenFullStart()) {- // What we're parsing isn't actually remotely recognizable as a element and we've consumed no tokens whatsoever- // Consume a token to advance the parser in some way and avoid an infinite loop- // This can happen when we're speculatively parsing parenthesized expressions which we think may be arrow functions,- // or when a modifier keyword which is disallowed as a parameter name (ie, `static` in strict mode) is supplied- nextToken();- }- continue;- }-- if (isListTerminator(kind)) {- break;- }-- if (abortParsingListOrMoveToNextToken(kind)) {- break;- }- }-- parsingContext = saveParsingContext;- // Recording the trailing comma is deliberately done after the previous- // loop, and not just if we see a list terminator. This is because the list- // may have ended incorrectly, but it is still important to know if there- // was a trailing comma.- // Check if the last token was a comma.- // Always preserve a trailing comma by marking it on the NodeArray- return createNodeArray(list, listPos, /*end*/ undefined, commaStart >= 0);- }-- function getExpectedCommaDiagnostic(kind: ParsingContext) {- return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or : undefined;- }-- interface MissingList<T extends Node> extends NodeArray<T> {- isMissingList: true;- }-- function createMissingList<T extends Node>(): MissingList<T> {- const list = createNodeArray<T>([], getNodePos()) as MissingList<T>;- list.isMissingList = true;- return list;- }-- function isMissingList(arr: NodeArray<Node>): boolean {- return !!(arr as MissingList<Node>).isMissingList;- }-- function parseBracketedList<T extends Node>(kind: ParsingContext, parseElement: () => T, open: PunctuationSyntaxKind, close: PunctuationSyntaxKind): NodeArray<T> {- if (parseExpected(open)) {- const result = parseDelimitedList(kind, parseElement);- parseExpected(close);- return result;- }-- return createMissingList<T>();- }-- function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName {- const pos = getNodePos();- let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage);- while (parseOptional(SyntaxKind.DotToken)) {- if (token() === SyntaxKind.LessThanToken) {- // The entity is part of a JSDoc-style generic. We will use the gap between `typeName` and- // `typeArguments` to report it as a grammar error in the checker.- break;- }- entity = finishNode(- factory.createQualifiedName(- entity,- parseRightSideOfDot(allowReservedWords, /*allowPrivateIdentifiers*/ false, /*allowUnicodeEscapeSequenceInIdentifierName*/ true) as Identifier,- ),- pos,- );- }- return entity;- }-- function createQualifiedName(entity: EntityName, name: Identifier): QualifiedName {- return finishNode(factory.createQualifiedName(entity, name), entity.pos);- }-- function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean, allowUnicodeEscapeSequenceInIdentifierName: boolean): Identifier | PrivateIdentifier {- // Technically a keyword is valid here as all identifiers and keywords are identifier names.- // However, often we'll encounter this in error situations when the identifier or keyword- // is actually starting another valid construct.- //- // So, we check for the following specific case:- //- // name.- // identifierOrKeyword identifierNameOrKeyword- //- // Note: the newlines are important here. For example, if that above code- // were rewritten into:- //- // name.identifierOrKeyword- // identifierNameOrKeyword- //- // Then we would consider it valid. That's because ASI would take effect and- // the code would be implicitly: "name.identifierOrKeyword; identifierNameOrKeyword".- // In the first case though, ASI will not take effect because there is not a- // line terminator after the identifier or keyword.- if (scanner.hasPrecedingLineBreak() && tokenIsIdentifierOrKeyword(token())) {- const matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine);-- if (matchesPattern) {- // Report that we need an identifier. However, report it right after the dot,- // and not on the next token. This is because the next token might actually- // be an identifier and the error would be quite confusing.- return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);- }- }-- if (token() === SyntaxKind.PrivateIdentifier) {- const node = parsePrivateIdentifier();- return allowPrivateIdentifiers ? node : createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);- }-- if (allowIdentifierNames) {- return allowUnicodeEscapeSequenceInIdentifierName ? parseIdentifierName() : parseIdentifierNameErrorOnUnicodeEscapeSequence();- }-- return parseIdentifier();- }-- function parseTemplateSpans(isTaggedTemplate: boolean) {- const pos = getNodePos();- const list = [];- let node: TemplateSpan;- do {- node = parseTemplateSpan(isTaggedTemplate);- list.push(node);- }- while (node.literal.kind === SyntaxKind.TemplateMiddle);- return createNodeArray(list, pos);- }-- function parseTemplateExpression(isTaggedTemplate: boolean): TemplateExpression {- const pos = getNodePos();- return finishNode(- factory.createTemplateExpression(- parseTemplateHead(isTaggedTemplate),- parseTemplateSpans(isTaggedTemplate),- ),- pos,- );- }-- function parseTemplateType(): TemplateLiteralTypeNode {- const pos = getNodePos();- return finishNode(- factory.createTemplateLiteralType(- parseTemplateHead(/*isTaggedTemplate*/ false),- parseTemplateTypeSpans(),- ),- pos,- );- }-- function parseTemplateTypeSpans() {- const pos = getNodePos();- const list = [];- let node: TemplateLiteralTypeSpan;- do {- node = parseTemplateTypeSpan();- list.push(node);- }- while (node.literal.kind === SyntaxKind.TemplateMiddle);- return createNodeArray(list, pos);- }-- function parseTemplateTypeSpan(): TemplateLiteralTypeSpan {- const pos = getNodePos();- return finishNode(- factory.createTemplateLiteralTypeSpan(- parseType(),- parseLiteralOfTemplateSpan(/*isTaggedTemplate*/ false),- ),- pos,- );- }-- function parseLiteralOfTemplateSpan(isTaggedTemplate: boolean) {- if (token() === SyntaxKind.CloseBraceToken) {- reScanTemplateToken(isTaggedTemplate);- return parseTemplateMiddleOrTemplateTail();- }- else {- // TODO(rbuckton): Do we need to call `parseExpectedToken` or can we just call `createMissingNode` directly?- return parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)) as TemplateTail;- }- }-- function parseTemplateSpan(isTaggedTemplate: boolean): TemplateSpan {- const pos = getNodePos();- return finishNode(- factory.createTemplateSpan(- allowInAnd(parseExpression),- parseLiteralOfTemplateSpan(isTaggedTemplate),- ),- pos,- );- }-- function parseLiteralNode(): LiteralExpression {- return parseLiteralLikeNode(token()) as LiteralExpression;- }-- function parseTemplateHead(isTaggedTemplate: boolean): TemplateHead {- if (!isTaggedTemplate && scanner.getTokenFlags() & TokenFlags.IsInvalid) {- reScanTemplateToken(/*isTaggedTemplate*/ false);- }- const fragment = parseLiteralLikeNode(token());- Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind");- return fragment as TemplateHead;- }-- function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail {- const fragment = parseLiteralLikeNode(token());- Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind");- return fragment as TemplateMiddle | TemplateTail;- }-- function getTemplateLiteralRawText(kind: TemplateLiteralToken["kind"]) {- const isLast = kind === SyntaxKind.NoSubstitutionTemplateLiteral || kind === SyntaxKind.TemplateTail;- const tokenText = scanner.getTokenText();- return tokenText.substring(1, tokenText.length - (scanner.isUnterminated() ? 0 : isLast ? 1 : 2));- }-- function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode {- const pos = getNodePos();- const node = isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, scanner.getTokenValue(), getTemplateLiteralRawText(kind), scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags) :- // Note that theoretically the following condition would hold true literals like 009,- // which is not octal. But because of how the scanner separates the tokens, we would- // never get a token like this. Instead, we would get 00 and 9 as two separate tokens.- // We also do not need to check for negatives because any prefix operator would be part of a- // parent unary expression.- kind === SyntaxKind.NumericLiteral ? factoryCreateNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) :- kind === SyntaxKind.StringLiteral ? factoryCreateStringLiteral(scanner.getTokenValue(), /*isSingleQuote*/ undefined, scanner.hasExtendedUnicodeEscape()) :- isLiteralKind(kind) ? factoryCreateLiteralLikeNode(kind, scanner.getTokenValue()) :- Debug.fail();-- if (scanner.hasExtendedUnicodeEscape()) {- node.hasExtendedUnicodeEscape = true;- }-- if (scanner.isUnterminated()) {- node.isUnterminated = true;- }-- nextToken();- return finishNode(node, pos);- }-- // TYPES-- function parseEntityNameOfTypeReference() {- return parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected);- }-- function parseTypeArgumentsOfTypeReference() {- if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) {- return parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);- }- }-- function parseTypeReference(): TypeReferenceNode {- const pos = getNodePos();- return finishNode(- factory.createTypeReferenceNode(- parseEntityNameOfTypeReference(),- parseTypeArgumentsOfTypeReference(),- ),- pos,- );- }-- // If true, we should abort parsing an error function.- function typeHasArrowFunctionBlockingParseError(node: TypeNode): boolean {- switch (node.kind) {- case SyntaxKind.TypeReference:- return nodeIsMissing((node as TypeReferenceNode).typeName);- case SyntaxKind.FunctionType:- case SyntaxKind.ConstructorType: {- const { parameters, type } = node as FunctionOrConstructorTypeNode;- return isMissingList(parameters) || typeHasArrowFunctionBlockingParseError(type);- }- case SyntaxKind.ParenthesizedType:- return typeHasArrowFunctionBlockingParseError((node as ParenthesizedTypeNode).type);- default:- return false;- }- }-- function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode {- nextToken();- return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, lhs, parseType()), lhs.pos);- }-- function parseThisTypeNode(): ThisTypeNode {- const pos = getNodePos();- nextToken();- return finishNode(factory.createThisTypeNode(), pos);- }-- function parseJSDocAllType(): JSDocAllType | JSDocOptionalType {- const pos = getNodePos();- nextToken();- return finishNode(factory.createJSDocAllType(), pos);- }-- function parseJSDocNonNullableType(): TypeNode {- const pos = getNodePos();- nextToken();- return finishNode(factory.createJSDocNonNullableType(parseNonArrayType(), /*postfix*/ false), pos);- }-- function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType {- const pos = getNodePos();- // skip the ?- nextToken();-- // Need to lookahead to decide if this is a nullable or unknown type.-- // Here are cases where we'll pick the unknown type:- //- // Foo(?,- // { a: ? }- // Foo(?)- // Foo<?>- // Foo(?=- // (?|- if (- token() === SyntaxKind.CommaToken ||- token() === SyntaxKind.CloseBraceToken ||- token() === SyntaxKind.CloseParenToken ||- token() === SyntaxKind.GreaterThanToken ||- token() === SyntaxKind.EqualsToken ||- token() === SyntaxKind.BarToken- ) {- return finishNode(factory.createJSDocUnknownType(), pos);- }- else {- return finishNode(factory.createJSDocNullableType(parseType(), /*postfix*/ false), pos);- }- }-- function parseJSDocFunctionType(): JSDocFunctionType | TypeReferenceNode {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- if (tryParse(nextTokenIsOpenParen)) {- const parameters = parseParameters(SignatureFlags.Type | SignatureFlags.JSDoc);- const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);- return withJSDoc(finishNode(factory.createJSDocFunctionType(parameters, type), pos), hasJSDoc);- }- return finishNode(factory.createTypeReferenceNode(parseIdentifierName(), /*typeArguments*/ undefined), pos);- }-- function parseJSDocParameter(): ParameterDeclaration {- const pos = getNodePos();- let name: Identifier | undefined;- if (token() === SyntaxKind.ThisKeyword || token() === SyntaxKind.NewKeyword) {- name = parseIdentifierName();- parseExpected(SyntaxKind.ColonToken);- }- return finishNode(- factory.createParameterDeclaration(- /*modifiers*/ undefined,- /*dotDotDotToken*/ undefined,- // TODO(rbuckton): JSDoc parameters don't have names (except `this`/`new`), should we manufacture an empty identifier?- name!,- /*questionToken*/ undefined,- parseJSDocType(),- /*initializer*/ undefined,- ),- pos,- );- }-- function parseJSDocType(): TypeNode {- scanner.setSkipJsDocLeadingAsterisks(true);- const pos = getNodePos();- if (parseOptional(SyntaxKind.ModuleKeyword)) {- // TODO(rbuckton): We never set the type for a JSDocNamepathType. What should we put here?- const moduleTag = factory.createJSDocNamepathType(/*type*/ undefined!);- terminate:- while (true) {- switch (token()) {- case SyntaxKind.CloseBraceToken:- case SyntaxKind.EndOfFileToken:- case SyntaxKind.CommaToken:- case SyntaxKind.WhitespaceTrivia:- break terminate;- default:- nextTokenJSDoc();- }- }-- scanner.setSkipJsDocLeadingAsterisks(false);- return finishNode(moduleTag, pos);- }-- const hasDotDotDot = parseOptional(SyntaxKind.DotDotDotToken);- let type = parseTypeOrTypePredicate();- scanner.setSkipJsDocLeadingAsterisks(false);- if (hasDotDotDot) {- type = finishNode(factory.createJSDocVariadicType(type), pos);- }- if (token() === SyntaxKind.EqualsToken) {- nextToken();- return finishNode(factory.createJSDocOptionalType(type), pos);- }- return type;- }-- function parseTypeQuery(): TypeQueryNode {- const pos = getNodePos();- parseExpected(SyntaxKind.TypeOfKeyword);- const entityName = parseEntityName(/*allowReservedWords*/ true);- // Make sure we perform ASI to prevent parsing the next line's type arguments as part of an instantiation expression.- const typeArguments = !scanner.hasPrecedingLineBreak() ? tryParseTypeArguments() : undefined;- return finishNode(factory.createTypeQueryNode(entityName, typeArguments), pos);- }-- function parseTypeParameter(): TypeParameterDeclaration {- const pos = getNodePos();- const modifiers = parseModifiers(/*allowDecorators*/ false, /*permitConstAsModifier*/ true);- const name = parseIdentifier();- let constraint: TypeNode | undefined;- let expression: Expression | undefined;- if (parseOptional(SyntaxKind.ExtendsKeyword)) {- // It's not uncommon for people to write improper constraints to a generic. If the- // user writes a constraint that is an expression and not an actual type, then parse- // it out as an expression (so we can recover well), but report that a type is needed- // instead.- if (isStartOfType() || !isStartOfExpression()) {- constraint = parseType();- }- else {- // It was not a type, and it looked like an expression. Parse out an expression- // here so we recover well. Note: it is important that we call parseUnaryExpression- // and not parseExpression here. If the user has:- //- // <T extends "">- //- // We do *not* want to consume the `>` as we're consuming the expression for "".- expression = parseUnaryExpressionOrHigher();- }- }-- const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined;- const node = factory.createTypeParameterDeclaration(modifiers, name, constraint, defaultType);- node.expression = expression;- return finishNode(node, pos);- }-- function parseTypeParameters(): NodeArray<TypeParameterDeclaration> | undefined {- if (token() === SyntaxKind.LessThanToken) {- return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);- }- }-- function isStartOfParameter(isJSDocParameter: boolean): boolean {- return token() === SyntaxKind.DotDotDotToken ||- isBindingIdentifierOrPrivateIdentifierOrPattern() ||- isModifierKind(token()) ||- token() === SyntaxKind.AtToken ||- isStartOfType(/*inStartOfParameter*/ !isJSDocParameter);- }-- function parseNameOfParameter(modifiers: NodeArray<ModifierLike> | undefined) {- // FormalParameter [Yield,Await]:- // BindingElement[?Yield,?Await]- const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_cannot_be_used_as_parameters);- if (getFullWidth(name) === 0 && !some(modifiers) && isModifierKind(token())) {- // in cases like- // 'use strict'- // function foo(static)- // isParameter('static') === true, because of isModifier('static')- // however 'static' is not a legal identifier in a strict mode.- // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined)- // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM)- // to avoid this we'll advance cursor to the next token.- nextToken();- }- return name;- }-- function isParameterNameStart() {- // Be permissive about await and yield by calling isBindingIdentifier instead of isIdentifier; disallowing- // them during a speculative parse leads to many more follow-on errors than allowing the function to parse then later- // complaining about the use of the keywords.- return isBindingIdentifier() || token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken;- }-- function parseParameter(inOuterAwaitContext: boolean): ParameterDeclaration {- return parseParameterWorker(inOuterAwaitContext);- }-- function parseParameterForSpeculation(inOuterAwaitContext: boolean): ParameterDeclaration | undefined {- return parseParameterWorker(inOuterAwaitContext, /*allowAmbiguity*/ false);- }-- function parseParameterWorker(inOuterAwaitContext: boolean): ParameterDeclaration;- function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity: false): ParameterDeclaration | undefined;- function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity = true): ParameterDeclaration | undefined {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();-- // FormalParameter [Yield,Await]:- // BindingElement[?Yield,?Await]-- // Decorators are parsed in the outer [Await] context, the rest of the parameter is parsed in the function's [Await] context.- const modifiers = inOuterAwaitContext ?- doInAwaitContext(() => parseModifiers(/*allowDecorators*/ true)) :- doOutsideOfAwaitContext(() => parseModifiers(/*allowDecorators*/ true));-- if (token() === SyntaxKind.ThisKeyword) {- const node = factory.createParameterDeclaration(- modifiers,- /*dotDotDotToken*/ undefined,- createIdentifier(/*isIdentifier*/ true),- /*questionToken*/ undefined,- parseTypeAnnotation(),- /*initializer*/ undefined,- );-- const modifier = firstOrUndefined(modifiers);- if (modifier) {- parseErrorAtRange(modifier, Diagnostics.Neither_decorators_nor_modifiers_may_be_applied_to_this_parameters);- }-- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- const savedTopLevel = topLevel;- topLevel = false;-- const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);-- if (!allowAmbiguity && !isParameterNameStart()) {- return undefined;- }-- const node = withJSDoc(- finishNode(- factory.createParameterDeclaration(- modifiers,- dotDotDotToken,- parseNameOfParameter(modifiers),- parseOptionalToken(SyntaxKind.QuestionToken),- parseTypeAnnotation(),- parseInitializer(),- ),- pos,- ),- hasJSDoc,- );- topLevel = savedTopLevel;- return node;- }-- function parseReturnType(returnToken: SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode;- function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined;- function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) {- if (shouldParseReturnType(returnToken, isType)) {- return allowConditionalTypesAnd(parseTypeOrTypePredicate);- }- }-- function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean {- if (returnToken === SyntaxKind.EqualsGreaterThanToken) {- parseExpected(returnToken);- return true;- }- else if (parseOptional(SyntaxKind.ColonToken)) {- return true;- }- else if (isType && token() === SyntaxKind.EqualsGreaterThanToken) {- // This is easy to get backward, especially in type contexts, so parse the type anyway- parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken));- nextToken();- return true;- }- return false;- }-- function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: true): NodeArray<ParameterDeclaration>;- function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: false): NodeArray<ParameterDeclaration> | undefined;- function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: boolean): NodeArray<ParameterDeclaration> | undefined {- // FormalParameters [Yield,Await]: (modified)- // [empty]- // FormalParameterList[?Yield,Await]- //- // FormalParameter[Yield,Await]: (modified)- // BindingElement[?Yield,Await]- //- // BindingElement [Yield,Await]: (modified)- // SingleNameBinding[?Yield,?Await]- // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt- //- // SingleNameBinding [Yield,Await]:- // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt- const savedYieldContext = inYieldContext();- const savedAwaitContext = inAwaitContext();-- setYieldContext(!!(flags & SignatureFlags.Yield));- setAwaitContext(!!(flags & SignatureFlags.Await));-- const parameters = flags & SignatureFlags.JSDoc ?- parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) :- parseDelimitedList(ParsingContext.Parameters, () => allowAmbiguity ? parseParameter(savedAwaitContext) : parseParameterForSpeculation(savedAwaitContext));-- setYieldContext(savedYieldContext);- setAwaitContext(savedAwaitContext);-- return parameters;- }-- function parseParameters(flags: SignatureFlags): NodeArray<ParameterDeclaration> {- // FormalParameters [Yield,Await]: (modified)- // [empty]- // FormalParameterList[?Yield,Await]- //- // FormalParameter[Yield,Await]: (modified)- // BindingElement[?Yield,Await]- //- // BindingElement [Yield,Await]: (modified)- // SingleNameBinding[?Yield,?Await]- // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt- //- // SingleNameBinding [Yield,Await]:- // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt- if (!parseExpected(SyntaxKind.OpenParenToken)) {- return createMissingList<ParameterDeclaration>();- }-- const parameters = parseParametersWorker(flags, /*allowAmbiguity*/ true);- parseExpected(SyntaxKind.CloseParenToken);- return parameters;- }-- function parseTypeMemberSemicolon() {- // We allow type members to be separated by commas or (possibly ASI) semicolons.- // First check if it was a comma. If so, we're done with the member.- if (parseOptional(SyntaxKind.CommaToken)) {- return;- }-- // Didn't have a comma. We must have a (possible ASI) semicolon.- parseSemicolon();- }-- function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- if (kind === SyntaxKind.ConstructSignature) {- parseExpected(SyntaxKind.NewKeyword);- }-- const typeParameters = parseTypeParameters();- const parameters = parseParameters(SignatureFlags.Type);- const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true);- parseTypeMemberSemicolon();- const node = kind === SyntaxKind.CallSignature- ? factory.createCallSignature(typeParameters, parameters, type)- : factory.createConstructSignature(typeParameters, parameters, type);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function isIndexSignature(): boolean {- return token() === SyntaxKind.OpenBracketToken && lookAhead(isUnambiguouslyIndexSignature);- }-- function isUnambiguouslyIndexSignature() {- // The only allowed sequence is:- //- // [id:- //- // However, for error recovery, we also check the following cases:- //- // [...- // [id,- // [id?,- // [id?:- // [id?]- // [public id- // [private id- // [protected id- // []- //- nextToken();- if (token() === SyntaxKind.DotDotDotToken || token() === SyntaxKind.CloseBracketToken) {- return true;- }-- if (isModifierKind(token())) {- nextToken();- if (isIdentifier()) {- return true;- }- }- else if (!isIdentifier()) {- return false;- }- else {- // Skip the identifier- nextToken();- }-- // A colon signifies a well formed indexer- // A comma should be a badly formed indexer because comma expressions are not allowed- // in computed properties.- if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken) {- return true;- }-- // Question mark could be an indexer with an optional property,- // or it could be a conditional expression in a computed property.- if (token() !== SyntaxKind.QuestionToken) {- return false;- }-- // If any of the following tokens are after the question mark, it cannot- // be a conditional expression, so treat it as an indexer.- nextToken();- return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBracketToken;- }-- function parseIndexSignatureDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): IndexSignatureDeclaration {- const parameters = parseBracketedList<ParameterDeclaration>(ParsingContext.Parameters, () => parseParameter(/*inOuterAwaitContext*/ false), SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);- const type = parseTypeAnnotation();- parseTypeMemberSemicolon();- const node = factory.createIndexSignature(modifiers, parameters, type);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parsePropertyOrMethodSignature(pos: number, hasJSDoc: boolean, modifiers: NodeArray<Modifier> | undefined): PropertySignature | MethodSignature {- const name = parsePropertyName();- const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);- let node: PropertySignature | MethodSignature;- if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {- // Method signatures don't exist in expression contexts. So they have neither- // [Yield] nor [Await]- const typeParameters = parseTypeParameters();- const parameters = parseParameters(SignatureFlags.Type);- const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true);- node = factory.createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type);- }- else {- const type = parseTypeAnnotation();- node = factory.createPropertySignature(modifiers, name, questionToken, type);- // Although type literal properties cannot not have initializers, we attempt- // to parse an initializer so we can report in the checker that an interface- // property or type literal property cannot have an initializer.- if (token() === SyntaxKind.EqualsToken) (node as Mutable<PropertySignature>).initializer = parseInitializer();- }- parseTypeMemberSemicolon();- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function isTypeMemberStart(): boolean {- // Return true if we have the start of a signature member- if (- token() === SyntaxKind.OpenParenToken ||- token() === SyntaxKind.LessThanToken ||- token() === SyntaxKind.GetKeyword ||- token() === SyntaxKind.SetKeyword- ) {- return true;- }- let idToken = false;- // Eat up all modifiers, but hold on to the last one in case it is actually an identifier- while (isModifierKind(token())) {- idToken = true;- nextToken();- }- // Index signatures and computed property names are type members- if (token() === SyntaxKind.OpenBracketToken) {- return true;- }- // Try to get the first property-like token following all modifiers- if (isLiteralPropertyName()) {- idToken = true;- nextToken();- }- // If we were able to get any potential identifier, check that it is- // the start of a member declaration- if (idToken) {- return token() === SyntaxKind.OpenParenToken ||- token() === SyntaxKind.LessThanToken ||- token() === SyntaxKind.QuestionToken ||- token() === SyntaxKind.ColonToken ||- token() === SyntaxKind.CommaToken ||- canParseSemicolon();- }- return false;- }-- function parseTypeMember(): TypeElement {- if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {- return parseSignatureMember(SyntaxKind.CallSignature);- }- if (token() === SyntaxKind.NewKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) {- return parseSignatureMember(SyntaxKind.ConstructSignature);- }- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const modifiers = parseModifiers(/*allowDecorators*/ false);- if (parseContextualModifier(SyntaxKind.GetKeyword)) {- return parseAccessorDeclaration(pos, hasJSDoc, modifiers, SyntaxKind.GetAccessor, SignatureFlags.Type);- }-- if (parseContextualModifier(SyntaxKind.SetKeyword)) {- return parseAccessorDeclaration(pos, hasJSDoc, modifiers, SyntaxKind.SetAccessor, SignatureFlags.Type);- }-- if (isIndexSignature()) {- return parseIndexSignatureDeclaration(pos, hasJSDoc, modifiers);- }- return parsePropertyOrMethodSignature(pos, hasJSDoc, modifiers);- }-- function nextTokenIsOpenParenOrLessThan() {- nextToken();- return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken;- }-- function nextTokenIsDot() {- return nextToken() === SyntaxKind.DotToken;- }-- function nextTokenIsOpenParenOrLessThanOrDot() {- switch (nextToken()) {- case SyntaxKind.OpenParenToken:- case SyntaxKind.LessThanToken:- case SyntaxKind.DotToken:- return true;- }- return false;- }-- function parseTypeLiteral(): TypeLiteralNode {- const pos = getNodePos();- return finishNode(factory.createTypeLiteralNode(parseObjectTypeMembers()), pos);- }-- function parseObjectTypeMembers(): NodeArray<TypeElement> {- let members: NodeArray<TypeElement>;- if (parseExpected(SyntaxKind.OpenBraceToken)) {- members = parseList(ParsingContext.TypeMembers, parseTypeMember);- parseExpected(SyntaxKind.CloseBraceToken);- }- else {- members = createMissingList<TypeElement>();- }-- return members;- }-- function isStartOfMappedType() {- nextToken();- if (token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {- return nextToken() === SyntaxKind.ReadonlyKeyword;- }- if (token() === SyntaxKind.ReadonlyKeyword) {- nextToken();- }- return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() && nextToken() === SyntaxKind.InKeyword;- }-- function parseMappedTypeParameter() {- const pos = getNodePos();- const name = parseIdentifierName();- parseExpected(SyntaxKind.InKeyword);- const type = parseType();- return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), pos);- }-- function parseMappedType() {- const pos = getNodePos();- parseExpected(SyntaxKind.OpenBraceToken);- let readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined;- if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {- readonlyToken = parseTokenNode<ReadonlyKeyword | PlusToken | MinusToken>();- if (readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) {- parseExpected(SyntaxKind.ReadonlyKeyword);- }- }- parseExpected(SyntaxKind.OpenBracketToken);- const typeParameter = parseMappedTypeParameter();- const nameType = parseOptional(SyntaxKind.AsKeyword) ? parseType() : undefined;- parseExpected(SyntaxKind.CloseBracketToken);- let questionToken: QuestionToken | PlusToken | MinusToken | undefined;- if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {- questionToken = parseTokenNode<QuestionToken | PlusToken | MinusToken>();- if (questionToken.kind !== SyntaxKind.QuestionToken) {- parseExpected(SyntaxKind.QuestionToken);- }- }- const type = parseTypeAnnotation();- parseSemicolon();- const members = parseList(ParsingContext.TypeMembers, parseTypeMember);- parseExpected(SyntaxKind.CloseBraceToken);- return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), pos);- }-- function parseTupleElementType() {- const pos = getNodePos();- if (parseOptional(SyntaxKind.DotDotDotToken)) {- return finishNode(factory.createRestTypeNode(parseType()), pos);- }- const type = parseType();- if (isJSDocNullableType(type) && type.pos === type.type.pos) {- const node = factory.createOptionalTypeNode(type.type);- setTextRange(node, type);- (node as Mutable<Node>).flags = type.flags;- return node;- }- return type;- }-- function isNextTokenColonOrQuestionColon() {- return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken);- }-- function isTupleElementName() {- if (token() === SyntaxKind.DotDotDotToken) {- return tokenIsIdentifierOrKeyword(nextToken()) && isNextTokenColonOrQuestionColon();- }- return tokenIsIdentifierOrKeyword(token()) && isNextTokenColonOrQuestionColon();- }-- function parseTupleElementNameOrTupleElementType() {- if (lookAhead(isTupleElementName)) {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);- const name = parseIdentifierName();- const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);- parseExpected(SyntaxKind.ColonToken);- const type = parseTupleElementType();- const node = factory.createNamedTupleMember(dotDotDotToken, name, questionToken, type);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }- return parseTupleElementType();- }-- function parseTupleType(): TupleTypeNode {- const pos = getNodePos();- return finishNode(- factory.createTupleTypeNode(- parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementNameOrTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken),- ),- pos,- );- }-- function parseParenthesizedType(): TypeNode {- const pos = getNodePos();- parseExpected(SyntaxKind.OpenParenToken);- const type = parseType();- parseExpected(SyntaxKind.CloseParenToken);- return finishNode(factory.createParenthesizedType(type), pos);- }-- function parseModifiersForConstructorType(): NodeArray<Modifier> | undefined {- let modifiers: NodeArray<Modifier> | undefined;- if (token() === SyntaxKind.AbstractKeyword) {- const pos = getNodePos();- nextToken();- const modifier = finishNode(factoryCreateToken(SyntaxKind.AbstractKeyword), pos);- modifiers = createNodeArray<Modifier>([modifier], pos);- }- return modifiers;- }-- function parseFunctionOrConstructorType(): TypeNode {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const modifiers = parseModifiersForConstructorType();- const isConstructorType = parseOptional(SyntaxKind.NewKeyword);- Debug.assert(!modifiers || isConstructorType, "Per isStartOfFunctionOrConstructorType, a function type cannot have modifiers.");- const typeParameters = parseTypeParameters();- const parameters = parseParameters(SignatureFlags.Type);- const type = parseReturnType(SyntaxKind.EqualsGreaterThanToken, /*isType*/ false);- const node = isConstructorType- ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, type)- : factory.createFunctionTypeNode(typeParameters, parameters, type);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseKeywordAndNoDot(): TypeNode | undefined {- const node = parseTokenNode<TypeNode>();- return token() === SyntaxKind.DotToken ? undefined : node;- }-- function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode {- const pos = getNodePos();- if (negative) {- nextToken();- }- let expression: BooleanLiteral | NullLiteral | LiteralExpression | PrefixUnaryExpression = token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword || token() === SyntaxKind.NullKeyword ?- parseTokenNode<BooleanLiteral | NullLiteral>() :- parseLiteralLikeNode(token()) as LiteralExpression;- if (negative) {- expression = finishNode(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, expression), pos);- }- return finishNode(factory.createLiteralTypeNode(expression), pos);- }-- function isStartOfTypeOfImportType() {- nextToken();- return token() === SyntaxKind.ImportKeyword;- }-- function parseImportType(): ImportTypeNode {- sourceFlags |= NodeFlags.PossiblyContainsDynamicImport;- const pos = getNodePos();- const isTypeOf = parseOptional(SyntaxKind.TypeOfKeyword);- parseExpected(SyntaxKind.ImportKeyword);- parseExpected(SyntaxKind.OpenParenToken);- const type = parseType();- let attributes: ImportAttributes | undefined;- if (parseOptional(SyntaxKind.CommaToken)) {- const openBracePosition = scanner.getTokenStart();- parseExpected(SyntaxKind.OpenBraceToken);- const currentToken = token();- if (currentToken === SyntaxKind.WithKeyword || currentToken === SyntaxKind.AssertKeyword) {- nextToken();- }- else {- parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.WithKeyword));- }- parseExpected(SyntaxKind.ColonToken);- attributes = parseImportAttributes(currentToken as SyntaxKind.WithKeyword | SyntaxKind.AssertKeyword, /*skipKeyword*/ true);- if (!parseExpected(SyntaxKind.CloseBraceToken)) {- const lastError = lastOrUndefined(parseDiagnostics);- if (lastError && lastError.code === Diagnostics._0_expected.code) {- addRelatedInfo(- lastError,- createDetachedDiagnostic(fileName, sourceText, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}"),- );- }- }- }- parseExpected(SyntaxKind.CloseParenToken);- const qualifier = parseOptional(SyntaxKind.DotToken) ? parseEntityNameOfTypeReference() : undefined;- const typeArguments = parseTypeArgumentsOfTypeReference();- return finishNode(factory.createImportTypeNode(type, attributes, qualifier, typeArguments, isTypeOf), pos);- }-- function nextTokenIsNumericOrBigIntLiteral() {- nextToken();- return token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral;- }-- function parseNonArrayType(): TypeNode {- switch (token()) {- case SyntaxKind.AnyKeyword:- case SyntaxKind.UnknownKeyword:- case SyntaxKind.StringKeyword:- case SyntaxKind.NumberKeyword:- case SyntaxKind.BigIntKeyword:- case SyntaxKind.SymbolKeyword:- case SyntaxKind.BooleanKeyword:- case SyntaxKind.UndefinedKeyword:- case SyntaxKind.NeverKeyword:- case SyntaxKind.ObjectKeyword:- // If these are followed by a dot, then parse these out as a dotted type reference instead.- return tryParse(parseKeywordAndNoDot) || parseTypeReference();- case SyntaxKind.AsteriskEqualsToken:- // If there is '*=', treat it as * followed by postfix =- scanner.reScanAsteriskEqualsToken();- // falls through- case SyntaxKind.AsteriskToken:- return parseJSDocAllType();- case SyntaxKind.QuestionQuestionToken:- // If there is '??', treat it as prefix-'?' in JSDoc type.- scanner.reScanQuestionToken();- // falls through- case SyntaxKind.QuestionToken:- return parseJSDocUnknownOrNullableType();- case SyntaxKind.FunctionKeyword:- return parseJSDocFunctionType();- case SyntaxKind.ExclamationToken:- return parseJSDocNonNullableType();- case SyntaxKind.NoSubstitutionTemplateLiteral:- case SyntaxKind.StringLiteral:- case SyntaxKind.NumericLiteral:- case SyntaxKind.BigIntLiteral:- case SyntaxKind.TrueKeyword:- case SyntaxKind.FalseKeyword:- case SyntaxKind.NullKeyword:- return parseLiteralTypeNode();- case SyntaxKind.MinusToken:- return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();- case SyntaxKind.VoidKeyword:- return parseTokenNode<TypeNode>();- case SyntaxKind.ThisKeyword: {- const thisKeyword = parseThisTypeNode();- if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) {- return parseThisTypePredicate(thisKeyword);- }- else {- return thisKeyword;- }- }- case SyntaxKind.TypeOfKeyword:- return lookAhead(isStartOfTypeOfImportType) ? parseImportType() : parseTypeQuery();- case SyntaxKind.OpenBraceToken:- return lookAhead(isStartOfMappedType) ? parseMappedType() : parseTypeLiteral();- case SyntaxKind.OpenBracketToken:- return parseTupleType();- case SyntaxKind.OpenParenToken:- return parseParenthesizedType();- case SyntaxKind.ImportKeyword:- return parseImportType();- case SyntaxKind.AssertsKeyword:- return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference();- case SyntaxKind.TemplateHead:- return parseTemplateType();- default:- return parseTypeReference();- }- }-- function isStartOfType(inStartOfParameter?: boolean): boolean {- switch (token()) {- case SyntaxKind.AnyKeyword:- case SyntaxKind.UnknownKeyword:- case SyntaxKind.StringKeyword:- case SyntaxKind.NumberKeyword:- case SyntaxKind.BigIntKeyword:- case SyntaxKind.BooleanKeyword:- case SyntaxKind.ReadonlyKeyword:- case SyntaxKind.SymbolKeyword:- case SyntaxKind.UniqueKeyword:- case SyntaxKind.VoidKeyword:- case SyntaxKind.UndefinedKeyword:- case SyntaxKind.NullKeyword:- case SyntaxKind.ThisKeyword:- case SyntaxKind.TypeOfKeyword:- case SyntaxKind.NeverKeyword:- case SyntaxKind.OpenBraceToken:- case SyntaxKind.OpenBracketToken:- case SyntaxKind.LessThanToken:- case SyntaxKind.BarToken:- case SyntaxKind.AmpersandToken:- case SyntaxKind.NewKeyword:- case SyntaxKind.StringLiteral:- case SyntaxKind.NumericLiteral:- case SyntaxKind.BigIntLiteral:- case SyntaxKind.TrueKeyword:- case SyntaxKind.FalseKeyword:- case SyntaxKind.ObjectKeyword:- case SyntaxKind.AsteriskToken:- case SyntaxKind.QuestionToken:- case SyntaxKind.ExclamationToken:- case SyntaxKind.DotDotDotToken:- case SyntaxKind.InferKeyword:- case SyntaxKind.ImportKeyword:- case SyntaxKind.AssertsKeyword:- case SyntaxKind.NoSubstitutionTemplateLiteral:- case SyntaxKind.TemplateHead:- return true;- case SyntaxKind.FunctionKeyword:- return !inStartOfParameter;- case SyntaxKind.MinusToken:- return !inStartOfParameter && lookAhead(nextTokenIsNumericOrBigIntLiteral);- case SyntaxKind.OpenParenToken:- // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier,- // or something that starts a type. We don't want to consider things like '(1)' a type.- return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType);- default:- return isIdentifier();- }- }-- function isStartOfParenthesizedOrFunctionType() {- nextToken();- return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) || isStartOfType();- }-- function parsePostfixTypeOrHigher(): TypeNode {- const pos = getNodePos();- let type = parseNonArrayType();- while (!scanner.hasPrecedingLineBreak()) {- switch (token()) {- case SyntaxKind.ExclamationToken:- nextToken();- type = finishNode(factory.createJSDocNonNullableType(type, /*postfix*/ true), pos);- break;- case SyntaxKind.QuestionToken:- // If next token is start of a type we have a conditional type- if (lookAhead(nextTokenIsStartOfType)) {- return type;- }- nextToken();- type = finishNode(factory.createJSDocNullableType(type, /*postfix*/ true), pos);- break;- case SyntaxKind.OpenBracketToken:- parseExpected(SyntaxKind.OpenBracketToken);- if (isStartOfType()) {- const indexType = parseType();- parseExpected(SyntaxKind.CloseBracketToken);- type = finishNode(factory.createIndexedAccessTypeNode(type, indexType), pos);- }- else {- parseExpected(SyntaxKind.CloseBracketToken);- type = finishNode(factory.createArrayTypeNode(type), pos);- }- break;- default:- return type;- }- }- return type;- }-- function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) {- const pos = getNodePos();- parseExpected(operator);- return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos);- }-- function tryParseConstraintOfInferType() {- if (parseOptional(SyntaxKind.ExtendsKeyword)) {- const constraint = disallowConditionalTypesAnd(parseType);- if (inDisallowConditionalTypesContext() || token() !== SyntaxKind.QuestionToken) {- return constraint;- }- }- }-- function parseTypeParameterOfInferType(): TypeParameterDeclaration {- const pos = getNodePos();- const name = parseIdentifier();- const constraint = tryParse(tryParseConstraintOfInferType);- const node = factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, constraint);- return finishNode(node, pos);- }-- function parseInferType(): InferTypeNode {- const pos = getNodePos();- parseExpected(SyntaxKind.InferKeyword);- return finishNode(factory.createInferTypeNode(parseTypeParameterOfInferType()), pos);- }-- function parseTypeOperatorOrHigher(): TypeNode {- const operator = token();- switch (operator) {- case SyntaxKind.KeyOfKeyword:- case SyntaxKind.UniqueKeyword:- case SyntaxKind.ReadonlyKeyword:- return parseTypeOperator(operator);- case SyntaxKind.InferKeyword:- return parseInferType();- }- return allowConditionalTypesAnd(parsePostfixTypeOrHigher);- }-- function parseFunctionOrConstructorTypeToError(- isInUnionType: boolean,- ): TypeNode | undefined {- // the function type and constructor type shorthand notation- // are not allowed directly in unions and intersections, but we'll- // try to parse them gracefully and issue a helpful message.- if (isStartOfFunctionTypeOrConstructorType()) {- const type = parseFunctionOrConstructorType();- let diagnostic: DiagnosticMessage;- if (isFunctionTypeNode(type)) {- diagnostic = isInUnionType- ? Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_a_union_type- : Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_an_intersection_type;- }- else {- diagnostic = isInUnionType- ? Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_a_union_type- : Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_an_intersection_type;- }- parseErrorAtRange(type, diagnostic);- return type;- }- return undefined;- }-- function parseUnionOrIntersectionType(- operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken,- parseConstituentType: () => TypeNode,- createTypeNode: (types: NodeArray<TypeNode>) => UnionOrIntersectionTypeNode,- ): TypeNode {- const pos = getNodePos();- const isUnionType = operator === SyntaxKind.BarToken;- const hasLeadingOperator = parseOptional(operator);- let type = hasLeadingOperator && parseFunctionOrConstructorTypeToError(isUnionType)- || parseConstituentType();- if (token() === operator || hasLeadingOperator) {- const types = [type];- while (parseOptional(operator)) {- types.push(parseFunctionOrConstructorTypeToError(isUnionType) || parseConstituentType());- }- type = finishNode(createTypeNode(createNodeArray(types, pos)), pos);- }- return type;- }-- function parseIntersectionTypeOrHigher(): TypeNode {- return parseUnionOrIntersectionType(SyntaxKind.AmpersandToken, parseTypeOperatorOrHigher, factory.createIntersectionTypeNode);- }-- function parseUnionTypeOrHigher(): TypeNode {- return parseUnionOrIntersectionType(SyntaxKind.BarToken, parseIntersectionTypeOrHigher, factory.createUnionTypeNode);- }-- function nextTokenIsNewKeyword(): boolean {- nextToken();- return token() === SyntaxKind.NewKeyword;- }-- function isStartOfFunctionTypeOrConstructorType(): boolean {- if (token() === SyntaxKind.LessThanToken) {- return true;- }- if (token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType)) {- return true;- }- return token() === SyntaxKind.NewKeyword ||- token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsNewKeyword);- }-- function skipParameterStart(): boolean {- if (isModifierKind(token())) {- // Skip modifiers- parseModifiers(/*allowDecorators*/ false);- }- if (isIdentifier() || token() === SyntaxKind.ThisKeyword) {- nextToken();- return true;- }- if (token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken) {- // Return true if we can parse an array or object binding pattern with no errors- const previousErrorCount = parseDiagnostics.length;- parseIdentifierOrPattern();- return previousErrorCount === parseDiagnostics.length;- }- return false;- }-- function isUnambiguouslyStartOfFunctionType() {- nextToken();- if (token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.DotDotDotToken) {- // ( )- // ( ...- return true;- }- if (skipParameterStart()) {- // We successfully skipped modifiers (if any) and an identifier or binding pattern,- // now see if we have something that indicates a parameter declaration- if (- token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken ||- token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken- ) {- // ( xxx :- // ( xxx ,- // ( xxx ?- // ( xxx =- return true;- }- if (token() === SyntaxKind.CloseParenToken) {- nextToken();- if (token() === SyntaxKind.EqualsGreaterThanToken) {- // ( xxx ) =>- return true;- }- }- }- return false;- }-- function parseTypeOrTypePredicate(): TypeNode {- const pos = getNodePos();- const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix);- const type = parseType();- if (typePredicateVariable) {- return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, typePredicateVariable, type), pos);- }- else {- return type;- }- }-- function parseTypePredicatePrefix() {- const id = parseIdentifier();- if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) {- nextToken();- return id;- }- }-- function parseAssertsTypePredicate(): TypeNode {- const pos = getNodePos();- const assertsModifier = parseExpectedToken(SyntaxKind.AssertsKeyword);- const parameterName = token() === SyntaxKind.ThisKeyword ? parseThisTypeNode() : parseIdentifier();- const type = parseOptional(SyntaxKind.IsKeyword) ? parseType() : undefined;- return finishNode(factory.createTypePredicateNode(assertsModifier, parameterName, type), pos);- }-- function parseType(): TypeNode {- if (contextFlags & NodeFlags.TypeExcludesFlags) {- return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseType);- }- if (isStartOfFunctionTypeOrConstructorType()) {- return parseFunctionOrConstructorType();- }- const pos = getNodePos();- const type = parseUnionTypeOrHigher();- if (!inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) {- // The type following 'extends' is not permitted to be another conditional type- const extendsType = disallowConditionalTypesAnd(parseType);- parseExpected(SyntaxKind.QuestionToken);- const trueType = allowConditionalTypesAnd(parseType);- parseExpected(SyntaxKind.ColonToken);- const falseType = allowConditionalTypesAnd(parseType);- return finishNode(factory.createConditionalTypeNode(type, extendsType, trueType, falseType), pos);- }- return type;- }-- function parseTypeAnnotation(): TypeNode | undefined {- return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined;- }-- // EXPRESSIONS- function isStartOfLeftHandSideExpression(): boolean {- switch (token()) {- case SyntaxKind.ThisKeyword:- case SyntaxKind.SuperKeyword:- case SyntaxKind.NullKeyword:- case SyntaxKind.TrueKeyword:- case SyntaxKind.FalseKeyword:- case SyntaxKind.NumericLiteral:- case SyntaxKind.BigIntLiteral:- case SyntaxKind.StringLiteral:- case SyntaxKind.NoSubstitutionTemplateLiteral:- case SyntaxKind.TemplateHead:- case SyntaxKind.OpenParenToken:- case SyntaxKind.OpenBracketToken:- case SyntaxKind.OpenBraceToken:- case SyntaxKind.FunctionKeyword:- case SyntaxKind.ClassKeyword:- case SyntaxKind.NewKeyword:- case SyntaxKind.SlashToken:- case SyntaxKind.SlashEqualsToken:- case SyntaxKind.Identifier:- return true;- case SyntaxKind.ImportKeyword:- return lookAhead(nextTokenIsOpenParenOrLessThanOrDot);- default:- return isIdentifier();- }- }-- function isStartOfExpression(): boolean {- if (isStartOfLeftHandSideExpression()) {- return true;- }-- switch (token()) {- case SyntaxKind.PlusToken:- case SyntaxKind.MinusToken:- case SyntaxKind.TildeToken:- case SyntaxKind.ExclamationToken:- case SyntaxKind.DeleteKeyword:- case SyntaxKind.TypeOfKeyword:- case SyntaxKind.VoidKeyword:- case SyntaxKind.PlusPlusToken:- case SyntaxKind.MinusMinusToken:- case SyntaxKind.LessThanToken:- case SyntaxKind.AwaitKeyword:- case SyntaxKind.YieldKeyword:- case SyntaxKind.PrivateIdentifier:- case SyntaxKind.AtToken:- // Yield/await always starts an expression. Either it is an identifier (in which case- // it is definitely an expression). Or it's a keyword (either because we're in- // a generator or async function, or in strict mode (or both)) and it started a yield or await expression.- return true;- default:- // Error tolerance. If we see the start of some binary operator, we consider- // that the start of an expression. That way we'll parse out a missing identifier,- // give a good message about an identifier being missing, and then consume the- // rest of the binary expression.- if (isBinaryOperator()) {- return true;- }-- return isIdentifier();- }- }-- function isStartOfExpressionStatement(): boolean {- // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement.- return token() !== SyntaxKind.OpenBraceToken &&- token() !== SyntaxKind.FunctionKeyword &&- token() !== SyntaxKind.ClassKeyword &&- token() !== SyntaxKind.AtToken &&- isStartOfExpression();- }-- function parseExpression(): Expression {- // Expression[in]:- // AssignmentExpression[in]- // Expression[in] , AssignmentExpression[in]-- // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator- const saveDecoratorContext = inDecoratorContext();- if (saveDecoratorContext) {- setDecoratorContext(/*val*/ false);- }-- const pos = getNodePos();- let expr = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);- let operatorToken: BinaryOperatorToken;- while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) {- expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), pos);- }-- if (saveDecoratorContext) {- setDecoratorContext(/*val*/ true);- }- return expr;- }-- function parseInitializer(): Expression | undefined {- return parseOptional(SyntaxKind.EqualsToken) ? parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) : undefined;- }-- function parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction: boolean): Expression {- // AssignmentExpression[in,yield]:- // 1) ConditionalExpression[?in,?yield]- // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield]- // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield]- // 4) ArrowFunctionExpression[?in,?yield]- // 5) AsyncArrowFunctionExpression[in,yield,await]- // 6) [+Yield] YieldExpression[?In]- //- // Note: for ease of implementation we treat productions '2' and '3' as the same thing.- // (i.e. they're both BinaryExpressions with an assignment operator in it).-- // First, do the simple check if we have a YieldExpression (production '6').- if (isYieldExpression()) {- return parseYieldExpression();- }-- // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized- // parameter list or is an async arrow function.- // AsyncArrowFunctionExpression:- // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]- // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]- // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression".- // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression".- //- // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is- // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done- // with AssignmentExpression if we see one.- const arrowExpression = tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) || tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction);- if (arrowExpression) {- return arrowExpression;- }-- // Now try to see if we're in production '1', '2' or '3'. A conditional expression can- // start with a LogicalOrExpression, while the assignment productions can only start with- // LeftHandSideExpressions.- //- // So, first, we try to just parse out a BinaryExpression. If we get something that is a- // LeftHandSide or higher, then we can try to parse out the assignment expression part.- // Otherwise, we try to parse out the conditional expression bit. We want to allow any- // binary expression here, so we pass in the 'lowest' precedence here so that it matches- // and consumes anything.- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest);-- // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized- // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single- // identifier and the current token is an arrow.- if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) {- return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, hasJSDoc, /*asyncModifier*/ undefined);- }-- // Now see if we might be in cases '2' or '3'.- // If the expression was a LHS expression, and we have an assignment operator, then- // we're in '2' or '3'. Consume the assignment and return.- //- // Note: we call reScanGreaterToken so that we get an appropriately merged token- // for cases like `> > =` becoming `>>=`- if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) {- return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction), pos);- }-- // It wasn't an assignment or a lambda. This is a conditional expression:- return parseConditionalExpressionRest(expr, pos, allowReturnTypeInArrowFunction);- }-- function isYieldExpression(): boolean {- if (token() === SyntaxKind.YieldKeyword) {- // If we have a 'yield' keyword, and this is a context where yield expressions are- // allowed, then definitely parse out a yield expression.- if (inYieldContext()) {- return true;- }-- // We're in a context where 'yield expr' is not allowed. However, if we can- // definitely tell that the user was trying to parse a 'yield expr' and not- // just a normal expr that start with a 'yield' identifier, then parse out- // a 'yield expr'. We can then report an error later that they are only- // allowed in generator expressions.- //- // for example, if we see 'yield(foo)', then we'll have to treat that as an- // invocation expression of something called 'yield'. However, if we have- // 'yield foo' then that is not legal as a normal expression, so we can- // definitely recognize this as a yield expression.- //- // for now we just check if the next token is an identifier. More heuristics- // can be added here later as necessary. We just need to make sure that we- // don't accidentally consume something legal.- return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine);- }-- return false;- }-- function nextTokenIsIdentifierOnSameLine() {- nextToken();- return !scanner.hasPrecedingLineBreak() && isIdentifier();- }-- function parseYieldExpression(): YieldExpression {- const pos = getNodePos();-- // YieldExpression[In] :- // yield- // yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield]- // yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield]- nextToken();-- if (- !scanner.hasPrecedingLineBreak() &&- (token() === SyntaxKind.AsteriskToken || isStartOfExpression())- ) {- return finishNode(- factory.createYieldExpression(- parseOptionalToken(SyntaxKind.AsteriskToken),- parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true),- ),- pos,- );- }- else {- // if the next token is not on the same line as yield. or we don't have an '*' or- // the start of an expression, then this is just a simple "yield" expression.- return finishNode(factory.createYieldExpression(/*asteriskToken*/ undefined, /*expression*/ undefined), pos);- }- }-- function parseSimpleArrowFunctionExpression(pos: number, identifier: Identifier, allowReturnTypeInArrowFunction: boolean, hasJSDoc: boolean, asyncModifier?: NodeArray<Modifier> | undefined): ArrowFunction {- Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>");- const parameter = factory.createParameterDeclaration(- /*modifiers*/ undefined,- /*dotDotDotToken*/ undefined,- identifier,- /*questionToken*/ undefined,- /*type*/ undefined,- /*initializer*/ undefined,- );- finishNode(parameter, identifier.pos);-- const parameters = createNodeArray<ParameterDeclaration>([parameter], parameter.pos, parameter.end);- const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);- const body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier, allowReturnTypeInArrowFunction);- const node = factory.createArrowFunction(asyncModifier, /*typeParameters*/ undefined, parameters, /*type*/ undefined, equalsGreaterThanToken, body);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): Expression | undefined {- const triState = isParenthesizedArrowFunctionExpression();- if (triState === Tristate.False) {- // It's definitely not a parenthesized arrow function expression.- return undefined;- }-- // If we definitely have an arrow function, then we can just parse one, not requiring a- // following => or { token. Otherwise, we *might* have an arrow function. Try to parse- // it out, but don't allow any ambiguity, and return 'undefined' if this could be an- // expression instead.- return triState === Tristate.True ?- parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true, /*allowReturnTypeInArrowFunction*/ true) :- tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction));- }-- // True -> We definitely expect a parenthesized arrow function here.- // False -> There *cannot* be a parenthesized arrow function here.- // Unknown -> There *might* be a parenthesized arrow function here.- // Speculatively look ahead to be sure, and rollback if not.- function isParenthesizedArrowFunctionExpression(): Tristate {- if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) {- return lookAhead(isParenthesizedArrowFunctionExpressionWorker);- }-- if (token() === SyntaxKind.EqualsGreaterThanToken) {- // ERROR RECOVERY TWEAK:- // If we see a standalone => try to parse it as an arrow function expression as that's- // likely what the user intended to write.- return Tristate.True;- }- // Definitely not a parenthesized arrow function.- return Tristate.False;- }-- function isParenthesizedArrowFunctionExpressionWorker() {- if (token() === SyntaxKind.AsyncKeyword) {- nextToken();- if (scanner.hasPrecedingLineBreak()) {- return Tristate.False;- }- if (token() !== SyntaxKind.OpenParenToken && token() !== SyntaxKind.LessThanToken) {- return Tristate.False;- }- }-- const first = token();- const second = nextToken();-- if (first === SyntaxKind.OpenParenToken) {- if (second === SyntaxKind.CloseParenToken) {- // Simple cases: "() =>", "(): ", and "() {".- // This is an arrow function with no parameters.- // The last one is not actually an arrow function,- // but this is probably what the user intended.- const third = nextToken();- switch (third) {- case SyntaxKind.EqualsGreaterThanToken:- case SyntaxKind.ColonToken:- case SyntaxKind.OpenBraceToken:- return Tristate.True;- default:- return Tristate.False;- }- }-- // If encounter "([" or "({", this could be the start of a binding pattern.- // Examples:- // ([ x ]) => { }- // ({ x }) => { }- // ([ x ])- // ({ x })- if (second === SyntaxKind.OpenBracketToken || second === SyntaxKind.OpenBraceToken) {- return Tristate.Unknown;- }-- // Simple case: "(..."- // This is an arrow function with a rest parameter.- if (second === SyntaxKind.DotDotDotToken) {- return Tristate.True;- }-- // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This- // isn't actually allowed, but we want to treat it as a lambda so we can provide- // a good error message.- if (isModifierKind(second) && second !== SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsIdentifier)) {- if (nextToken() === SyntaxKind.AsKeyword) {- // https://github.com/microsoft/TypeScript/issues/44466- return Tristate.False;- }- return Tristate.True;- }-- // If we had "(" followed by something that's not an identifier,- // then this definitely doesn't look like a lambda. "this" is not- // valid, but we want to parse it and then give a semantic error.- if (!isIdentifier() && second !== SyntaxKind.ThisKeyword) {- return Tristate.False;- }-- switch (nextToken()) {- case SyntaxKind.ColonToken:- // If we have something like "(a:", then we must have a- // type-annotated parameter in an arrow function expression.- return Tristate.True;- case SyntaxKind.QuestionToken:- nextToken();- // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda.- if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) {- return Tristate.True;- }- // Otherwise it is definitely not a lambda.- return Tristate.False;- case SyntaxKind.CommaToken:- case SyntaxKind.EqualsToken:- case SyntaxKind.CloseParenToken:- // If we have "(a," or "(a=" or "(a)" this *could* be an arrow function- return Tristate.Unknown;- }- // It is definitely not an arrow function- return Tristate.False;- }- else {- Debug.assert(first === SyntaxKind.LessThanToken);-- // If we have "<" not followed by an identifier,- // then this definitely is not an arrow function.- if (!isIdentifier() && token() !== SyntaxKind.ConstKeyword) {- return Tristate.False;- }-- // JSX overrides- if (languageVariant === LanguageVariant.JSX) {- const isArrowFunctionInJsx = lookAhead(() => {- parseOptional(SyntaxKind.ConstKeyword);- const third = nextToken();- if (third === SyntaxKind.ExtendsKeyword) {- const fourth = nextToken();- switch (fourth) {- case SyntaxKind.EqualsToken:- case SyntaxKind.GreaterThanToken:- case SyntaxKind.SlashToken:- return false;- default:- return true;- }- }- else if (third === SyntaxKind.CommaToken || third === SyntaxKind.EqualsToken) {- return true;- }- return false;- });-- if (isArrowFunctionInJsx) {- return Tristate.True;- }-- return Tristate.False;- }-- // This *could* be a parenthesized arrow function.- return Tristate.Unknown;- }- }-- function parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined {- const tokenPos = scanner.getTokenStart();- if (notParenthesizedArrow?.has(tokenPos)) {- return undefined;- }-- const result = parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ false, allowReturnTypeInArrowFunction);- if (!result) {- (notParenthesizedArrow || (notParenthesizedArrow = new Set())).add(tokenPos);- }-- return result;- }-- function tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined {- // We do a check here so that we won't be doing unnecessarily call to "lookAhead"- if (token() === SyntaxKind.AsyncKeyword) {- if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const asyncModifier = parseModifiersForArrowFunction();- const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest);- return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, hasJSDoc, asyncModifier);- }- }- return undefined;- }-- function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate {- // AsyncArrowFunctionExpression:- // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]- // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]- if (token() === SyntaxKind.AsyncKeyword) {- nextToken();- // If the "async" is followed by "=>" token then it is not a beginning of an async arrow-function- // but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher"- if (scanner.hasPrecedingLineBreak() || token() === SyntaxKind.EqualsGreaterThanToken) {- return Tristate.False;- }- // Check for un-parenthesized AsyncArrowFunction- const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest);- if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) {- return Tristate.True;- }- }-- return Tristate.False;- }-- function parseParenthesizedArrowFunctionExpression(allowAmbiguity: boolean, allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const modifiers = parseModifiersForArrowFunction();- const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None;- // Arrow functions are never generators.- //- // If we're speculatively parsing a signature for a parenthesized arrow function, then- // we have to have a complete parameter list. Otherwise we might see something like- // a => (b => c)- // And think that "(b =>" was actually a parenthesized arrow function with a missing- // close paren.- const typeParameters = parseTypeParameters();-- let parameters: NodeArray<ParameterDeclaration>;- if (!parseExpected(SyntaxKind.OpenParenToken)) {- if (!allowAmbiguity) {- return undefined;- }- parameters = createMissingList<ParameterDeclaration>();- }- else {- if (!allowAmbiguity) {- const maybeParameters = parseParametersWorker(isAsync, allowAmbiguity);- if (!maybeParameters) {- return undefined;- }- parameters = maybeParameters;- }- else {- parameters = parseParametersWorker(isAsync, allowAmbiguity);- }- if (!parseExpected(SyntaxKind.CloseParenToken) && !allowAmbiguity) {- return undefined;- }- }-- const hasReturnColon = token() === SyntaxKind.ColonToken;- const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);- if (type && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(type)) {- return undefined;- }-- // Parsing a signature isn't enough.- // Parenthesized arrow signatures often look like other valid expressions.- // For instance:- // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value.- // - "(x,y)" is a comma expression parsed as a signature with two parameters.- // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation.- // - "a ? (b): function() {}" will too, since function() is a valid JSDoc function type.- // - "a ? (b): (function() {})" as well, but inside of a parenthesized type with an arbitrary amount of nesting.- //- // So we need just a bit of lookahead to ensure that it can only be a signature.-- let unwrappedType = type;- while (unwrappedType?.kind === SyntaxKind.ParenthesizedType) {- unwrappedType = (unwrappedType as ParenthesizedTypeNode).type; // Skip parens if need be- }-- const hasJSDocFunctionType = unwrappedType && isJSDocFunctionType(unwrappedType);- if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) {- // Returning undefined here will cause our caller to rewind to where we started from.- return undefined;- }-- // If we have an arrow, then try to parse the body. Even if not, try to parse if we- // have an opening brace, just in case we're in an error state.- const lastToken = token();- const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);- const body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken)- ? parseArrowFunctionExpressionBody(some(modifiers, isAsyncModifier), allowReturnTypeInArrowFunction)- : parseIdentifier();-- // Given:- // x ? y => ({ y }) : z => ({ z })- // We try to parse the body of the first arrow function by looking at:- // ({ y }) : z => ({ z })- // This is a valid arrow function with "z" as the return type.- //- // But, if we're in the true side of a conditional expression, this colon- // terminates the expression, so we cannot allow a return type if we aren't- // certain whether or not the preceding text was parsed as a parameter list.- //- // For example,- // a() ? (b: number, c?: string): void => d() : e- // is determined by isParenthesizedArrowFunctionExpression to unambiguously- // be an arrow expression, so we allow a return type.- if (!allowReturnTypeInArrowFunction && hasReturnColon) {- // However, if the arrow function we were able to parse is followed by another colon- // as in:- // a ? (x): string => x : null- // Then allow the arrow function, and treat the second colon as terminating- // the conditional expression. It's okay to do this because this code would- // be a syntax error in JavaScript (as the second colon shouldn't be there).- if (token() !== SyntaxKind.ColonToken) {- return undefined;- }- }-- const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseArrowFunctionExpressionBody(isAsync: boolean, allowReturnTypeInArrowFunction: boolean): Block | Expression {- if (token() === SyntaxKind.OpenBraceToken) {- return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None);- }-- if (- token() !== SyntaxKind.SemicolonToken &&- token() !== SyntaxKind.FunctionKeyword &&- token() !== SyntaxKind.ClassKeyword &&- isStartOfStatement() &&- !isStartOfExpressionStatement()- ) {- // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations)- //- // Here we try to recover from a potential error situation in the case where the- // user meant to supply a block. For example, if the user wrote:- //- // a =>- // let v = 0;- // }- //- // they may be missing an open brace. Check to see if that's the case so we can- // try to recover better. If we don't do this, then the next close curly we see may end- // up preemptively closing the containing construct.- //- // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error.- return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None));- }-- const savedTopLevel = topLevel;- topLevel = false;- const node = isAsync- ? doInAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction))- : doOutsideOfAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction));- topLevel = savedTopLevel;- return node;- }-- function parseConditionalExpressionRest(leftOperand: Expression, pos: number, allowReturnTypeInArrowFunction: boolean): Expression {- // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher.- const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);- if (!questionToken) {- return leftOperand;- }-- // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and- // we do not that for the 'whenFalse' part.- let colonToken;- return finishNode(- factory.createConditionalExpression(- leftOperand,- questionToken,- doOutsideOfContext(disallowInAndDecoratorContext, () => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ false)),- colonToken = parseExpectedToken(SyntaxKind.ColonToken),- nodeIsPresent(colonToken)- ? parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction)- : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)),- ),- pos,- );- }-- function parseBinaryExpressionOrHigher(precedence: OperatorPrecedence): Expression {- const pos = getNodePos();- const leftOperand = parseUnaryExpressionOrHigher();- return parseBinaryExpressionRest(precedence, leftOperand, pos);- }-- function isInOrOfKeyword(t: SyntaxKind) {- return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword;- }-- function parseBinaryExpressionRest(precedence: OperatorPrecedence, leftOperand: Expression, pos: number): Expression {- while (true) {- // We either have a binary operator here, or we're finished. We call- // reScanGreaterToken so that we merge token sequences like > and = into >=-- reScanGreaterToken();- const newPrecedence = getBinaryOperatorPrecedence(token());-- // Check the precedence to see if we should "take" this operator- // - For left associative operator (all operator but **), consume the operator,- // recursively call the function below, and parse binaryExpression as a rightOperand- // of the caller if the new precedence of the operator is greater then or equal to the current precedence.- // For example:- // a - b - c;- // ^token; leftOperand = b. Return b to the caller as a rightOperand- // a * b - c- // ^token; leftOperand = b. Return b to the caller as a rightOperand- // a - b * c;- // ^token; leftOperand = b. Return b * c to the caller as a rightOperand- // - For right associative operator (**), consume the operator, recursively call the function- // and parse binaryExpression as a rightOperand of the caller if the new precedence of- // the operator is strictly grater than the current precedence- // For example:- // a ** b ** c;- // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand- // a - b ** c;- // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand- // a ** b - c- // ^token; leftOperand = b. Return b to the caller as a rightOperand- const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken ?- newPrecedence >= precedence :- newPrecedence > precedence;-- if (!consumeCurrentOperator) {- break;- }-- if (token() === SyntaxKind.InKeyword && inDisallowInContext()) {- break;- }-- if (token() === SyntaxKind.AsKeyword || token() === SyntaxKind.SatisfiesKeyword) {- // Make sure we *do* perform ASI for constructs like this:- // var x = foo- // as (Bar)- // This should be parsed as an initialized variable, followed- // by a function call to 'as' with the argument 'Bar'- if (scanner.hasPrecedingLineBreak()) {- break;- }- else {- const keywordKind = token();- nextToken();- leftOperand = keywordKind === SyntaxKind.SatisfiesKeyword ? makeSatisfiesExpression(leftOperand, parseType()) :- makeAsExpression(leftOperand, parseType());- }- }- else {- leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence), pos);- }- }-- return leftOperand;- }-- function isBinaryOperator() {- if (inDisallowInContext() && token() === SyntaxKind.InKeyword) {- return false;- }-- return getBinaryOperatorPrecedence(token()) > 0;- }-- function makeSatisfiesExpression(left: Expression, right: TypeNode): SatisfiesExpression {- return finishNode(factory.createSatisfiesExpression(left, right), left.pos);- }-- function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, pos: number): BinaryExpression {- return finishNode(factory.createBinaryExpression(left, operatorToken, right), pos);- }-- function makeAsExpression(left: Expression, right: TypeNode): AsExpression {- return finishNode(factory.createAsExpression(left, right), left.pos);- }-- function parsePrefixUnaryExpression() {- const pos = getNodePos();- return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseSimpleUnaryExpression)), pos);- }-- function parseDeleteExpression() {- const pos = getNodePos();- return finishNode(factory.createDeleteExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);- }-- function parseTypeOfExpression() {- const pos = getNodePos();- return finishNode(factory.createTypeOfExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);- }-- function parseVoidExpression() {- const pos = getNodePos();- return finishNode(factory.createVoidExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);- }-- function isAwaitExpression(): boolean {- if (token() === SyntaxKind.AwaitKeyword) {- if (inAwaitContext()) {- return true;- }-- // here we are using similar heuristics as 'isYieldExpression'- return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine);- }-- return false;- }-- function parseAwaitExpression() {- const pos = getNodePos();- return finishNode(factory.createAwaitExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);- }-- /**- * Parse ES7 exponential expression and await expression- *- * ES7 ExponentiationExpression:- * 1) UnaryExpression[?Yield]- * 2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield]- */- function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression {- /**- * ES7 UpdateExpression:- * 1) LeftHandSideExpression[?Yield]- * 2) LeftHandSideExpression[?Yield][no LineTerminator here]++- * 3) LeftHandSideExpression[?Yield][no LineTerminator here]--- * 4) ++UnaryExpression[?Yield]- * 5) --UnaryExpression[?Yield]- */- if (isUpdateExpression()) {- const pos = getNodePos();- const updateExpression = parseUpdateExpression();- return token() === SyntaxKind.AsteriskAsteriskToken ?- parseBinaryExpressionRest(getBinaryOperatorPrecedence(token()), updateExpression, pos) as BinaryExpression :- updateExpression;- }-- /**- * ES7 UnaryExpression:- * 1) UpdateExpression[?yield]- * 2) delete UpdateExpression[?yield]- * 3) void UpdateExpression[?yield]- * 4) typeof UpdateExpression[?yield]- * 5) + UpdateExpression[?yield]- * 6) - UpdateExpression[?yield]- * 7) ~ UpdateExpression[?yield]- * 8) ! UpdateExpression[?yield]- */- const unaryOperator = token();- const simpleUnaryExpression = parseSimpleUnaryExpression();- if (token() === SyntaxKind.AsteriskAsteriskToken) {- const pos = skipTrivia(sourceText, simpleUnaryExpression.pos);- const { end } = simpleUnaryExpression;- if (simpleUnaryExpression.kind === SyntaxKind.TypeAssertionExpression) {- parseErrorAt(pos, end, Diagnostics.A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses);- }- else {- Debug.assert(isKeywordOrPunctuation(unaryOperator));- parseErrorAt(pos, end, Diagnostics.An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, tokenToString(unaryOperator));- }- }- return simpleUnaryExpression;- }-- /**- * Parse ES7 simple-unary expression or higher:- *- * ES7 UnaryExpression:- * 1) UpdateExpression[?yield]- * 2) delete UnaryExpression[?yield]- * 3) void UnaryExpression[?yield]- * 4) typeof UnaryExpression[?yield]- * 5) + UnaryExpression[?yield]- * 6) - UnaryExpression[?yield]- * 7) ~ UnaryExpression[?yield]- * 8) ! UnaryExpression[?yield]- * 9) [+Await] await UnaryExpression[?yield]- */- function parseSimpleUnaryExpression(): UnaryExpression {- switch (token()) {- case SyntaxKind.PlusToken:- case SyntaxKind.MinusToken:- case SyntaxKind.TildeToken:- case SyntaxKind.ExclamationToken:- return parsePrefixUnaryExpression();- case SyntaxKind.DeleteKeyword:- return parseDeleteExpression();- case SyntaxKind.TypeOfKeyword:- return parseTypeOfExpression();- case SyntaxKind.VoidKeyword:- return parseVoidExpression();- case SyntaxKind.LessThanToken:- // Just like in parseUpdateExpression, we need to avoid parsing type assertions when- // in JSX and we see an expression like "+ <foo> bar".- if (languageVariant === LanguageVariant.JSX) {- return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, /*topInvalidNodePosition*/ undefined, /*openingTag*/ undefined, /*mustBeUnary*/ true);- }- // This is modified UnaryExpression grammar in TypeScript- // UnaryExpression (modified):- // < type > UnaryExpression- return parseTypeAssertion();- case SyntaxKind.AwaitKeyword:- if (isAwaitExpression()) {- return parseAwaitExpression();- }- // falls through- default:- return parseUpdateExpression();- }- }-- /**- * Check if the current token can possibly be an ES7 increment expression.- *- * ES7 UpdateExpression:- * LeftHandSideExpression[?Yield]- * LeftHandSideExpression[?Yield][no LineTerminator here]++- * LeftHandSideExpression[?Yield][no LineTerminator here]--- * ++LeftHandSideExpression[?Yield]- * --LeftHandSideExpression[?Yield]- */- function isUpdateExpression(): boolean {- // This function is called inside parseUnaryExpression to decide- // whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly- switch (token()) {- case SyntaxKind.PlusToken:- case SyntaxKind.MinusToken:- case SyntaxKind.TildeToken:- case SyntaxKind.ExclamationToken:- case SyntaxKind.DeleteKeyword:- case SyntaxKind.TypeOfKeyword:- case SyntaxKind.VoidKeyword:- case SyntaxKind.AwaitKeyword:- return false;- case SyntaxKind.LessThanToken:- // If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression- if (languageVariant !== LanguageVariant.JSX) {- return false;- }- // We are in JSX context and the token is part of JSXElement.- // falls through- default:- return true;- }- }-- /**- * Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression.- *- * ES7 UpdateExpression[yield]:- * 1) LeftHandSideExpression[?yield]- * 2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++- * 3) LeftHandSideExpression[?yield] [[no LineTerminator here]]--- * 4) ++LeftHandSideExpression[?yield]- * 5) --LeftHandSideExpression[?yield]- * In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression- */- function parseUpdateExpression(): UpdateExpression {- if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) {- const pos = getNodePos();- return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseLeftHandSideExpressionOrHigher)), pos);- }- else if (languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) {- // JSXElement is part of primaryExpression- return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true);- }-- const expression = parseLeftHandSideExpressionOrHigher();-- Debug.assert(isLeftHandSideExpression(expression));- if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) {- const operator = token() as PostfixUnaryOperator;- nextToken();- return finishNode(factory.createPostfixUnaryExpression(expression, operator), expression.pos);- }-- return expression;- }-- function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression {- // Original Ecma:- // LeftHandSideExpression: See 11.2- // NewExpression- // CallExpression- //- // Our simplification:- //- // LeftHandSideExpression: See 11.2- // MemberExpression- // CallExpression- //- // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with- // MemberExpression to make our lives easier.- //- // to best understand the below code, it's important to see how CallExpression expands- // out into its own productions:- //- // CallExpression:- // MemberExpression Arguments- // CallExpression Arguments- // CallExpression[Expression]- // CallExpression.IdentifierName- // import (AssignmentExpression)- // super Arguments- // super.IdentifierName- //- // Because of the recursion in these calls, we need to bottom out first. There are three- // bottom out states we can run into: 1) We see 'super' which must start either of- // the last two CallExpression productions. 2) We see 'import' which must start import call.- // 3)we have a MemberExpression which either completes the LeftHandSideExpression,- // or starts the beginning of the first four CallExpression productions.- const pos = getNodePos();- let expression: MemberExpression;- if (token() === SyntaxKind.ImportKeyword) {- if (lookAhead(nextTokenIsOpenParenOrLessThan)) {- // We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "("- // For example:- // var foo3 = require("subfolder- // import * as foo1 from "module-from-node- // We want this import to be a statement rather than import call expression- sourceFlags |= NodeFlags.PossiblyContainsDynamicImport;- expression = parseTokenNode<PrimaryExpression>();- }- else if (lookAhead(nextTokenIsDot)) {- // This is an 'import.*' metaproperty (i.e. 'import.meta')- nextToken(); // advance past the 'import'- nextToken(); // advance past the dot- expression = finishNode(factory.createMetaProperty(SyntaxKind.ImportKeyword, parseIdentifierName()), pos);- sourceFlags |= NodeFlags.PossiblyContainsImportMeta;- }- else {- expression = parseMemberExpressionOrHigher();- }- }- else {- expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher();- }-- // Now, we *may* be complete. However, we might have consumed the start of a- // CallExpression or OptionalExpression. As such, we need to consume the rest- // of it here to be complete.- return parseCallExpressionRest(pos, expression);- }-- function parseMemberExpressionOrHigher(): MemberExpression {- // Note: to make our lives simpler, we decompose the NewExpression productions and- // place ObjectCreationExpression and FunctionExpression into PrimaryExpression.- // like so:- //- // PrimaryExpression : See 11.1- // this- // Identifier- // Literal- // ArrayLiteral- // ObjectLiteral- // (Expression)- // FunctionExpression- // new MemberExpression Arguments?- //- // MemberExpression : See 11.2- // PrimaryExpression- // MemberExpression[Expression]- // MemberExpression.IdentifierName- //- // CallExpression : See 11.2- // MemberExpression- // CallExpression Arguments- // CallExpression[Expression]- // CallExpression.IdentifierName- //- // Technically this is ambiguous. i.e. CallExpression defines:- //- // CallExpression:- // CallExpression Arguments- //- // If you see: "new Foo()"- //- // Then that could be treated as a single ObjectCreationExpression, or it could be- // treated as the invocation of "new Foo". We disambiguate that in code (to match- // the original grammar) by making sure that if we see an ObjectCreationExpression- // we always consume arguments if they are there. So we treat "new Foo()" as an- // object creation only, and not at all as an invocation. Another way to think- // about this is that for every "new" that we see, we will consume an argument list if- // it is there as part of the *associated* object creation node. Any additional- // argument lists we see, will become invocation expressions.- //- // Because there are no other places in the grammar now that refer to FunctionExpression- // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression- // production.- //- // Because CallExpression and MemberExpression are left recursive, we need to bottom out- // of the recursion immediately. So we parse out a primary expression to start with.- const pos = getNodePos();- const expression = parsePrimaryExpression();- return parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true);- }-- function parseSuperExpression(): MemberExpression {- const pos = getNodePos();- let expression = parseTokenNode<MemberExpression>();- if (token() === SyntaxKind.LessThanToken) {- const startPos = getNodePos();- const typeArguments = tryParse(parseTypeArgumentsInExpression);- if (typeArguments !== undefined) {- parseErrorAt(startPos, getNodePos(), Diagnostics.super_may_not_use_type_arguments);- if (!isTemplateStartOfTaggedTemplate()) {- expression = factory.createExpressionWithTypeArguments(expression, typeArguments);- }- }- }-- if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) {- return expression;- }-- // If we have seen "super" it must be followed by '(' or '.'.- // If it wasn't then just try to parse out a '.' and report an error.- parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);- // private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic- return finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true, /*allowUnicodeEscapeSequenceInIdentifierName*/ true)), pos);- }-- function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment, mustBeUnary = false): JsxElement | JsxSelfClosingElement | JsxFragment {- const pos = getNodePos();- const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext);- let result: JsxElement | JsxSelfClosingElement | JsxFragment;- if (opening.kind === SyntaxKind.JsxOpeningElement) {- let children = parseJsxChildren(opening);- let closingElement: JsxClosingElement;-- const lastChild: JsxChild | undefined = children[children.length - 1];- if (- lastChild?.kind === SyntaxKind.JsxElement- && !tagNamesAreEquivalent(lastChild.openingElement.tagName, lastChild.closingElement.tagName)- && tagNamesAreEquivalent(opening.tagName, lastChild.closingElement.tagName)- ) {- // when an unclosed JsxOpeningElement incorrectly parses its parent's JsxClosingElement,- // restructure (<div>(...<span>...</div>)) --> (<div>(...<span>...</>)</div>)- // (no need to error; the parent will error)- const end = lastChild.children.end;- const newLast = finishNode(- factory.createJsxElement(- lastChild.openingElement,- lastChild.children,- finishNode(factory.createJsxClosingElement(finishNode(factoryCreateIdentifier(""), end, end)), end, end),- ),- lastChild.openingElement.pos,- end,- );-- children = createNodeArray([...children.slice(0, children.length - 1), newLast], children.pos, end);- closingElement = lastChild.closingElement;- }- else {- closingElement = parseJsxClosingElement(opening, inExpressionContext);- if (!tagNamesAreEquivalent(opening.tagName, closingElement.tagName)) {- if (openingTag && isJsxOpeningElement(openingTag) && tagNamesAreEquivalent(closingElement.tagName, openingTag.tagName)) {- // opening incorrectly matched with its parent's closing -- put error on opening- parseErrorAtRange(opening.tagName, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, opening.tagName));- }- else {- // other opening/closing mismatches -- put error on closing- parseErrorAtRange(closingElement.tagName, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, opening.tagName));- }- }- }- result = finishNode(factory.createJsxElement(opening, children, closingElement), pos);- }- else if (opening.kind === SyntaxKind.JsxOpeningFragment) {- result = finishNode(factory.createJsxFragment(opening, parseJsxChildren(opening), parseJsxClosingFragment(inExpressionContext)), pos);- }- else {- Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement);- // Nothing else to do for self-closing elements- result = opening;- }-- // If the user writes the invalid code '<div></div><div></div>' in an expression context (i.e. not wrapped in- // an enclosing tag), we'll naively try to parse ^ this as a 'less than' operator and the remainder of the tag- // as garbage, which will cause the formatter to badly mangle the JSX. Perform a speculative parse of a JSX- // element if we see a < token so that we can wrap it in a synthetic binary expression so the formatter- // does less damage and we can report a better error.- // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios- // of one sort or another.- // If we are in a unary context, we can't do this recovery; the binary expression we return here is not- // a valid UnaryExpression and will cause problems later.- if (!mustBeUnary && inExpressionContext && token() === SyntaxKind.LessThanToken) {- const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition;- const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos));- if (invalidElement) {- const operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false);- setTextRangePosWidth(operatorToken, invalidElement.pos, 0);- parseErrorAt(skipTrivia(sourceText, topBadPos), invalidElement.end, Diagnostics.JSX_expressions_must_have_one_parent_element);- return finishNode(factory.createBinaryExpression(result, operatorToken as Token<SyntaxKind.CommaToken>, invalidElement), pos) as Node as JsxElement;- }- }-- return result;- }-- function parseJsxText(): JsxText {- const pos = getNodePos();- const node = factory.createJsxText(scanner.getTokenValue(), currentToken === SyntaxKind.JsxTextAllWhiteSpaces);- currentToken = scanner.scanJsxToken();- return finishNode(node, pos);- }-- function parseJsxChild(openingTag: JsxOpeningElement | JsxOpeningFragment, token: JsxTokenSyntaxKind): JsxChild | undefined {- switch (token) {- case SyntaxKind.EndOfFileToken:- // If we hit EOF, issue the error at the tag that lacks the closing element- // rather than at the end of the file (which is useless)- if (isJsxOpeningFragment(openingTag)) {- parseErrorAtRange(openingTag, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag);- }- else {- // We want the error span to cover only 'Foo.Bar' in < Foo.Bar >- // or to cover only 'Foo' in < Foo >- const tag = openingTag.tagName;- const start = Math.min(skipTrivia(sourceText, tag.pos), tag.end);- parseErrorAt(start, tag.end, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName));- }- return undefined;- case SyntaxKind.LessThanSlashToken:- case SyntaxKind.ConflictMarkerTrivia:- return undefined;- case SyntaxKind.JsxText:- case SyntaxKind.JsxTextAllWhiteSpaces:- return parseJsxText();- case SyntaxKind.OpenBraceToken:- return parseJsxExpression(/*inExpressionContext*/ false);- case SyntaxKind.LessThanToken:- return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false, /*topInvalidNodePosition*/ undefined, openingTag);- default:- return Debug.assertNever(token);- }- }-- function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray<JsxChild> {- const list = [];- const listPos = getNodePos();- const saveParsingContext = parsingContext;- parsingContext |= 1 << ParsingContext.JsxChildren;-- while (true) {- const child = parseJsxChild(openingTag, currentToken = scanner.reScanJsxToken());- if (!child) break;- list.push(child);- if (- isJsxOpeningElement(openingTag)- && child?.kind === SyntaxKind.JsxElement- && !tagNamesAreEquivalent(child.openingElement.tagName, child.closingElement.tagName)- && tagNamesAreEquivalent(openingTag.tagName, child.closingElement.tagName)- ) {- // stop after parsing a mismatched child like <div>...(<span></div>) in order to reattach the </div> higher- break;- }- }-- parsingContext = saveParsingContext;- return createNodeArray(list, listPos);- }-- function parseJsxAttributes(): JsxAttributes {- const pos = getNodePos();- return finishNode(factory.createJsxAttributes(parseList(ParsingContext.JsxAttributes, parseJsxAttribute)), pos);- }-- function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment {- const pos = getNodePos();-- parseExpected(SyntaxKind.LessThanToken);-- if (token() === SyntaxKind.GreaterThanToken) {- // See below for explanation of scanJsxText- scanJsxText();- return finishNode(factory.createJsxOpeningFragment(), pos);- }- const tagName = parseJsxElementName();- const typeArguments = (contextFlags & NodeFlags.JavaScriptFile) === 0 ? tryParseTypeArguments() : undefined;- const attributes = parseJsxAttributes();-- let node: JsxOpeningLikeElement;-- if (token() === SyntaxKind.GreaterThanToken) {- // Closing tag, so scan the immediately-following text with the JSX scanning instead- // of regular scanning to avoid treating illegal characters (e.g. '#') as immediate- // scanning errors- scanJsxText();- node = factory.createJsxOpeningElement(tagName, typeArguments, attributes);- }- else {- parseExpected(SyntaxKind.SlashToken);- if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnosticMessage*/ undefined, /*shouldAdvance*/ false)) {- // manually advance the scanner in order to look for jsx text inside jsx- if (inExpressionContext) {- nextToken();- }- else {- scanJsxText();- }- }- node = factory.createJsxSelfClosingElement(tagName, typeArguments, attributes);- }-- return finishNode(node, pos);- }-- function parseJsxElementName(): JsxTagNameExpression {- const pos = getNodePos();- // JsxElement can have name in the form of- // propertyAccessExpression- // primaryExpression in the form of an identifier and "this" keyword- // We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword- // We only want to consider "this" as a primaryExpression- const initialExpression = parseJsxTagName();- if (isJsxNamespacedName(initialExpression)) {- return initialExpression; // `a:b.c` is invalid syntax, don't even look for the `.` if we parse `a:b`, and let `parseAttribute` report "unexpected :" instead.- }- let expression: PropertyAccessExpression | Identifier | ThisExpression = initialExpression;- while (parseOptional(SyntaxKind.DotToken)) {- expression = finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false, /*allowUnicodeEscapeSequenceInIdentifierName*/ false)), pos);- }- return expression as JsxTagNameExpression;- }-- function parseJsxTagName(): Identifier | JsxNamespacedName | ThisExpression {- const pos = getNodePos();- scanJsxIdentifier();-- const isThis = token() === SyntaxKind.ThisKeyword;- const tagName = parseIdentifierNameErrorOnUnicodeEscapeSequence();- if (parseOptional(SyntaxKind.ColonToken)) {- scanJsxIdentifier();- return finishNode(factory.createJsxNamespacedName(tagName, parseIdentifierNameErrorOnUnicodeEscapeSequence()), pos);- }- return isThis ? finishNode(factory.createToken(SyntaxKind.ThisKeyword), pos) : tagName;- }-- function parseJsxExpression(inExpressionContext: boolean): JsxExpression | undefined {- const pos = getNodePos();- if (!parseExpected(SyntaxKind.OpenBraceToken)) {- return undefined;- }-- let dotDotDotToken: DotDotDotToken | undefined;- let expression: Expression | undefined;- if (token() !== SyntaxKind.CloseBraceToken) {- if (!inExpressionContext) {- dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);- }- // Only an AssignmentExpression is valid here per the JSX spec,- // but we can unambiguously parse a comma sequence and provide- // a better error message in grammar checking.- expression = parseExpression();- }- if (inExpressionContext) {- parseExpected(SyntaxKind.CloseBraceToken);- }- else {- if (parseExpected(SyntaxKind.CloseBraceToken, /*diagnosticMessage*/ undefined, /*shouldAdvance*/ false)) {- scanJsxText();- }- }-- return finishNode(factory.createJsxExpression(dotDotDotToken, expression), pos);- }-- function parseJsxAttribute(): JsxAttribute | JsxSpreadAttribute {- if (token() === SyntaxKind.OpenBraceToken) {- return parseJsxSpreadAttribute();- }-- const pos = getNodePos();- return finishNode(factory.createJsxAttribute(parseJsxAttributeName(), parseJsxAttributeValue()), pos);- }-- function parseJsxAttributeValue(): JsxAttributeValue | undefined {- if (token() === SyntaxKind.EqualsToken) {- if (scanJsxAttributeValue() === SyntaxKind.StringLiteral) {- return parseLiteralNode() as StringLiteral;- }- if (token() === SyntaxKind.OpenBraceToken) {- return parseJsxExpression(/*inExpressionContext*/ true);- }- if (token() === SyntaxKind.LessThanToken) {- return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true);- }- parseErrorAtCurrentToken(Diagnostics.or_JSX_element_expected);- }- return undefined;- }-- function parseJsxAttributeName() {- const pos = getNodePos();- scanJsxIdentifier();-- const attrName = parseIdentifierNameErrorOnUnicodeEscapeSequence();- if (parseOptional(SyntaxKind.ColonToken)) {- scanJsxIdentifier();- return finishNode(factory.createJsxNamespacedName(attrName, parseIdentifierNameErrorOnUnicodeEscapeSequence()), pos);- }- return attrName;- }-- function parseJsxSpreadAttribute(): JsxSpreadAttribute {- const pos = getNodePos();- parseExpected(SyntaxKind.OpenBraceToken);- parseExpected(SyntaxKind.DotDotDotToken);- const expression = parseExpression();- parseExpected(SyntaxKind.CloseBraceToken);- return finishNode(factory.createJsxSpreadAttribute(expression), pos);- }-- function parseJsxClosingElement(open: JsxOpeningElement, inExpressionContext: boolean): JsxClosingElement {- const pos = getNodePos();- parseExpected(SyntaxKind.LessThanSlashToken);- const tagName = parseJsxElementName();- if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnosticMessage*/ undefined, /*shouldAdvance*/ false)) {- // manually advance the scanner in order to look for jsx text inside jsx- if (inExpressionContext || !tagNamesAreEquivalent(open.tagName, tagName)) {- nextToken();- }- else {- scanJsxText();- }- }- return finishNode(factory.createJsxClosingElement(tagName), pos);- }-- function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment {- const pos = getNodePos();- parseExpected(SyntaxKind.LessThanSlashToken);- if (parseExpected(SyntaxKind.GreaterThanToken, Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment, /*shouldAdvance*/ false)) {- // manually advance the scanner in order to look for jsx text inside jsx- if (inExpressionContext) {- nextToken();- }- else {- scanJsxText();- }- }- return finishNode(factory.createJsxJsxClosingFragment(), pos);- }-- function parseTypeAssertion(): TypeAssertion {- Debug.assert(languageVariant !== LanguageVariant.JSX, "Type assertions should never be parsed in JSX; they should be parsed as comparisons or JSX elements/fragments.");- const pos = getNodePos();- parseExpected(SyntaxKind.LessThanToken);- const type = parseType();- parseExpected(SyntaxKind.GreaterThanToken);- const expression = parseSimpleUnaryExpression();- return finishNode(factory.createTypeAssertion(type, expression), pos);- }-- function nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate() {- nextToken();- return tokenIsIdentifierOrKeyword(token())- || token() === SyntaxKind.OpenBracketToken- || isTemplateStartOfTaggedTemplate();- }-- function isStartOfOptionalPropertyOrElementAccessChain() {- return token() === SyntaxKind.QuestionDotToken- && lookAhead(nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate);- }-- function tryReparseOptionalChain(node: Expression) {- if (node.flags & NodeFlags.OptionalChain) {- return true;- }- // check for an optional chain in a non-null expression- if (isNonNullExpression(node)) {- let expr = node.expression;- while (isNonNullExpression(expr) && !(expr.flags & NodeFlags.OptionalChain)) {- expr = expr.expression;- }- if (expr.flags & NodeFlags.OptionalChain) {- // this is part of an optional chain. Walk down from `node` to `expression` and set the flag.- while (isNonNullExpression(node)) {- (node as Mutable<NonNullExpression>).flags |= NodeFlags.OptionalChain;- node = node.expression;- }- return true;- }- }- return false;- }-- function parsePropertyAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {- const name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true, /*allowUnicodeEscapeSequenceInIdentifierName*/ true);- const isOptionalChain = questionDotToken || tryReparseOptionalChain(expression);- const propertyAccess = isOptionalChain ?- factoryCreatePropertyAccessChain(expression, questionDotToken, name) :- factoryCreatePropertyAccessExpression(expression, name);- if (isOptionalChain && isPrivateIdentifier(propertyAccess.name)) {- parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers);- }- if (isExpressionWithTypeArguments(expression) && expression.typeArguments) {- const pos = expression.typeArguments.pos - 1;- const end = skipTrivia(sourceText, expression.typeArguments.end) + 1;- parseErrorAt(pos, end, Diagnostics.An_instantiation_expression_cannot_be_followed_by_a_property_access);- }- return finishNode(propertyAccess, pos);- }-- function parseElementAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {- let argumentExpression: Expression;- if (token() === SyntaxKind.CloseBracketToken) {- argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument);- }- else {- const argument = allowInAnd(parseExpression);- if (isStringOrNumericLiteralLike(argument)) {- argument.text = internIdentifier(argument.text);- }- argumentExpression = argument;- }-- parseExpected(SyntaxKind.CloseBracketToken);-- const indexedAccess = questionDotToken || tryReparseOptionalChain(expression) ?- factoryCreateElementAccessChain(expression, questionDotToken, argumentExpression) :- factoryCreateElementAccessExpression(expression, argumentExpression);- return finishNode(indexedAccess, pos);- }-- function parseMemberExpressionRest(pos: number, expression: LeftHandSideExpression, allowOptionalChain: boolean): MemberExpression {- while (true) {- let questionDotToken: QuestionDotToken | undefined;- let isPropertyAccess = false;- if (allowOptionalChain && isStartOfOptionalPropertyOrElementAccessChain()) {- questionDotToken = parseExpectedToken(SyntaxKind.QuestionDotToken);- isPropertyAccess = tokenIsIdentifierOrKeyword(token());- }- else {- isPropertyAccess = parseOptional(SyntaxKind.DotToken);- }-- if (isPropertyAccess) {- expression = parsePropertyAccessExpressionRest(pos, expression, questionDotToken);- continue;- }-- // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName- if ((questionDotToken || !inDecoratorContext()) && parseOptional(SyntaxKind.OpenBracketToken)) {- expression = parseElementAccessExpressionRest(pos, expression, questionDotToken);- continue;- }-- if (isTemplateStartOfTaggedTemplate()) {- // Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments- expression = !questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments ?- parseTaggedTemplateRest(pos, (expression as ExpressionWithTypeArguments).expression, questionDotToken, (expression as ExpressionWithTypeArguments).typeArguments) :- parseTaggedTemplateRest(pos, expression, questionDotToken, /*typeArguments*/ undefined);- continue;- }-- if (!questionDotToken) {- if (token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {- nextToken();- expression = finishNode(factory.createNonNullExpression(expression), pos);- continue;- }- const typeArguments = tryParse(parseTypeArgumentsInExpression);- if (typeArguments) {- expression = finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos);- continue;- }- }-- return expression as MemberExpression;- }- }-- function isTemplateStartOfTaggedTemplate() {- return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead;- }-- function parseTaggedTemplateRest(pos: number, tag: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, typeArguments: NodeArray<TypeNode> | undefined) {- const tagExpression = factory.createTaggedTemplateExpression(- tag,- typeArguments,- token() === SyntaxKind.NoSubstitutionTemplateLiteral ?- (reScanTemplateToken(/*isTaggedTemplate*/ true), parseLiteralNode() as NoSubstitutionTemplateLiteral) :- parseTemplateExpression(/*isTaggedTemplate*/ true),- );- if (questionDotToken || tag.flags & NodeFlags.OptionalChain) {- (tagExpression as Mutable<Node>).flags |= NodeFlags.OptionalChain;- }- tagExpression.questionDotToken = questionDotToken;- return finishNode(tagExpression, pos);- }-- function parseCallExpressionRest(pos: number, expression: LeftHandSideExpression): LeftHandSideExpression {- while (true) {- expression = parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true);- let typeArguments: NodeArray<TypeNode> | undefined;- const questionDotToken = parseOptionalToken(SyntaxKind.QuestionDotToken);- if (questionDotToken) {- typeArguments = tryParse(parseTypeArgumentsInExpression);- if (isTemplateStartOfTaggedTemplate()) {- expression = parseTaggedTemplateRest(pos, expression, questionDotToken, typeArguments);- continue;- }- }- if (typeArguments || token() === SyntaxKind.OpenParenToken) {- // Absorb type arguments into CallExpression when preceding expression is ExpressionWithTypeArguments- if (!questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments) {- typeArguments = (expression as ExpressionWithTypeArguments).typeArguments;- expression = (expression as ExpressionWithTypeArguments).expression;- }- const argumentList = parseArgumentList();- const callExpr = questionDotToken || tryReparseOptionalChain(expression) ?- factoryCreateCallChain(expression, questionDotToken, typeArguments, argumentList) :- factoryCreateCallExpression(expression, typeArguments, argumentList);- expression = finishNode(callExpr, pos);- continue;- }- if (questionDotToken) {- // We parsed `?.` but then failed to parse anything, so report a missing identifier here.- const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Identifier_expected);- expression = finishNode(factoryCreatePropertyAccessChain(expression, questionDotToken, name), pos);- }- break;- }- return expression;- }-- function parseArgumentList() {- parseExpected(SyntaxKind.OpenParenToken);- const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression);- parseExpected(SyntaxKind.CloseParenToken);- return result;- }-- function parseTypeArgumentsInExpression() {- if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) {- // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators.- return undefined;- }-- if (reScanLessThanToken() !== SyntaxKind.LessThanToken) {- return undefined;- }- nextToken();-- const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType);- if (reScanGreaterToken() !== SyntaxKind.GreaterThanToken) {- // If it doesn't have the closing `>` then it's definitely not an type argument list.- return undefined;- }- nextToken();-- // We successfully parsed a type argument list. The next token determines whether we want to- // treat it as such. If the type argument list is followed by `(` or a template literal, as in- // `f<number>(42)`, we favor the type argument interpretation even though JavaScript would view- // it as a relational expression.- return typeArguments && canFollowTypeArgumentsInExpression() ? typeArguments : undefined;- }-- function canFollowTypeArgumentsInExpression(): boolean {- switch (token()) {- // These tokens can follow a type argument list in a call expression.- case SyntaxKind.OpenParenToken: // foo<x>(- case SyntaxKind.NoSubstitutionTemplateLiteral: // foo<T> `...`- case SyntaxKind.TemplateHead: // foo<T> `...${100}...`- return true;- // A type argument list followed by `<` never makes sense, and a type argument list followed- // by `>` is ambiguous with a (re-scanned) `>>` operator, so we disqualify both. Also, in- // this context, `+` and `-` are unary operators, not binary operators.- case SyntaxKind.LessThanToken:- case SyntaxKind.GreaterThanToken:- case SyntaxKind.PlusToken:- case SyntaxKind.MinusToken:- return false;- }- // We favor the type argument list interpretation when it is immediately followed by- // a line break, a binary operator, or something that can't start an expression.- return scanner.hasPrecedingLineBreak() || isBinaryOperator() || !isStartOfExpression();- }-- function parsePrimaryExpression(): PrimaryExpression {- switch (token()) {- case SyntaxKind.NoSubstitutionTemplateLiteral:- if (scanner.getTokenFlags() & TokenFlags.IsInvalid) {- reScanTemplateToken(/*isTaggedTemplate*/ false);- }- // falls through- case SyntaxKind.NumericLiteral:- case SyntaxKind.BigIntLiteral:- case SyntaxKind.StringLiteral:- return parseLiteralNode();- case SyntaxKind.ThisKeyword:- case SyntaxKind.SuperKeyword:- case SyntaxKind.NullKeyword:- case SyntaxKind.TrueKeyword:- case SyntaxKind.FalseKeyword:- return parseTokenNode<PrimaryExpression>();- case SyntaxKind.OpenParenToken:- return parseParenthesizedExpression();- case SyntaxKind.OpenBracketToken:- return parseArrayLiteralExpression();- case SyntaxKind.OpenBraceToken:- return parseObjectLiteralExpression();- case SyntaxKind.AsyncKeyword:- // Async arrow functions are parsed earlier in parseAssignmentExpressionOrHigher.- // If we encounter `async [no LineTerminator here] function` then this is an async- // function; otherwise, its an identifier.- if (!lookAhead(nextTokenIsFunctionKeywordOnSameLine)) {- break;- }-- return parseFunctionExpression();- case SyntaxKind.AtToken:- return parseDecoratedExpression();- case SyntaxKind.ClassKeyword:- return parseClassExpression();- case SyntaxKind.FunctionKeyword:- return parseFunctionExpression();- case SyntaxKind.NewKeyword:- return parseNewExpressionOrNewDotTarget();- case SyntaxKind.SlashToken:- case SyntaxKind.SlashEqualsToken:- if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) {- return parseLiteralNode();- }- break;- case SyntaxKind.TemplateHead:- return parseTemplateExpression(/*isTaggedTemplate*/ false);- case SyntaxKind.PrivateIdentifier:- return parsePrivateIdentifier();- }-- return parseIdentifier(Diagnostics.Expression_expected);- }-- function parseParenthesizedExpression(): ParenthesizedExpression {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.OpenParenToken);- const expression = allowInAnd(parseExpression);- parseExpected(SyntaxKind.CloseParenToken);- return withJSDoc(finishNode(factoryCreateParenthesizedExpression(expression), pos), hasJSDoc);- }-- function parseSpreadElement(): Expression {- const pos = getNodePos();- parseExpected(SyntaxKind.DotDotDotToken);- const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);- return finishNode(factory.createSpreadElement(expression), pos);- }-- function parseArgumentOrArrayLiteralElement(): Expression {- return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() :- token() === SyntaxKind.CommaToken ? finishNode(factory.createOmittedExpression(), getNodePos()) :- parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);- }-- function parseArgumentExpression(): Expression {- return doOutsideOfContext(disallowInAndDecoratorContext, parseArgumentOrArrayLiteralElement);- }-- function parseArrayLiteralExpression(): ArrayLiteralExpression {- const pos = getNodePos();- const openBracketPosition = scanner.getTokenStart();- const openBracketParsed = parseExpected(SyntaxKind.OpenBracketToken);- const multiLine = scanner.hasPrecedingLineBreak();- const elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement);- parseExpectedMatchingBrackets(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, openBracketParsed, openBracketPosition);- return finishNode(factoryCreateArrayLiteralExpression(elements, multiLine), pos);- }-- function parseObjectLiteralElement(): ObjectLiteralElementLike {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();-- if (parseOptionalToken(SyntaxKind.DotDotDotToken)) {- const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);- return withJSDoc(finishNode(factory.createSpreadAssignment(expression), pos), hasJSDoc);- }-- const modifiers = parseModifiers(/*allowDecorators*/ true);- if (parseContextualModifier(SyntaxKind.GetKeyword)) {- return parseAccessorDeclaration(pos, hasJSDoc, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None);- }- if (parseContextualModifier(SyntaxKind.SetKeyword)) {- return parseAccessorDeclaration(pos, hasJSDoc, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None);- }-- const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);- const tokenIsIdentifier = isIdentifier();- const name = parsePropertyName();-- // Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker.- const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);- const exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken);-- if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {- return parseMethodDeclaration(pos, hasJSDoc, modifiers, asteriskToken, name, questionToken, exclamationToken);- }-- // check if it is short-hand property assignment or normal property assignment- // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production- // CoverInitializedName[Yield] :- // IdentifierReference[?Yield] Initializer[In, ?Yield]- // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern- let node: Mutable<ShorthandPropertyAssignment | PropertyAssignment>;- const isShorthandPropertyAssignment = tokenIsIdentifier && (token() !== SyntaxKind.ColonToken);- if (isShorthandPropertyAssignment) {- const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken);- const objectAssignmentInitializer = equalsToken ? allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)) : undefined;- node = factory.createShorthandPropertyAssignment(name as Identifier, objectAssignmentInitializer);- // Save equals token for error reporting.- // TODO(rbuckton): Consider manufacturing this when we need to report an error as it is otherwise not useful.- node.equalsToken = equalsToken;- }- else {- parseExpected(SyntaxKind.ColonToken);- const initializer = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true));- node = factory.createPropertyAssignment(name, initializer);- }- // Decorators, Modifiers, questionToken, and exclamationToken are not supported by property assignments and are reported in the grammar checker- node.modifiers = modifiers;- node.questionToken = questionToken;- node.exclamationToken = exclamationToken;- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseObjectLiteralExpression(): ObjectLiteralExpression {- const pos = getNodePos();- const openBracePosition = scanner.getTokenStart();- const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken);- const multiLine = scanner.hasPrecedingLineBreak();- const properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true);- parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition);- return finishNode(factoryCreateObjectLiteralExpression(properties, multiLine), pos);- }-- function parseFunctionExpression(): FunctionExpression {- // GeneratorExpression:- // function* BindingIdentifier [Yield][opt](FormalParameters[Yield]){ GeneratorBody }- //- // FunctionExpression:- // function BindingIdentifier[opt](FormalParameters){ FunctionBody }- const savedDecoratorContext = inDecoratorContext();- setDecoratorContext(/*val*/ false);-- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const modifiers = parseModifiers(/*allowDecorators*/ false);- parseExpected(SyntaxKind.FunctionKeyword);- const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);- const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;- const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None;- const name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalBindingIdentifier) :- isGenerator ? doInYieldContext(parseOptionalBindingIdentifier) :- isAsync ? doInAwaitContext(parseOptionalBindingIdentifier) :- parseOptionalBindingIdentifier();-- const typeParameters = parseTypeParameters();- const parameters = parseParameters(isGenerator | isAsync);- const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);- const body = parseFunctionBlock(isGenerator | isAsync);-- setDecoratorContext(savedDecoratorContext);-- const node = factory.createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseOptionalBindingIdentifier(): Identifier | undefined {- return isBindingIdentifier() ? parseBindingIdentifier() : undefined;- }-- function parseNewExpressionOrNewDotTarget(): NewExpression | MetaProperty {- const pos = getNodePos();- parseExpected(SyntaxKind.NewKeyword);- if (parseOptional(SyntaxKind.DotToken)) {- const name = parseIdentifierName();- return finishNode(factory.createMetaProperty(SyntaxKind.NewKeyword, name), pos);- }- const expressionPos = getNodePos();- let expression: LeftHandSideExpression = parseMemberExpressionRest(expressionPos, parsePrimaryExpression(), /*allowOptionalChain*/ false);- let typeArguments: NodeArray<TypeNode> | undefined;- // Absorb type arguments into NewExpression when preceding expression is ExpressionWithTypeArguments- if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) {- typeArguments = (expression as ExpressionWithTypeArguments).typeArguments;- expression = (expression as ExpressionWithTypeArguments).expression;- }- if (token() === SyntaxKind.QuestionDotToken) {- parseErrorAtCurrentToken(Diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, getTextOfNodeFromSourceText(sourceText, expression));- }- const argumentList = token() === SyntaxKind.OpenParenToken ? parseArgumentList() : undefined;- return finishNode(factoryCreateNewExpression(expression, typeArguments, argumentList), pos);- }-- // STATEMENTS- function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const openBracePosition = scanner.getTokenStart();- const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage);- if (openBraceParsed || ignoreMissingOpenBrace) {- const multiLine = scanner.hasPrecedingLineBreak();- const statements = parseList(ParsingContext.BlockStatements, parseStatement);- parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition);- const result = withJSDoc(finishNode(factoryCreateBlock(statements, multiLine), pos), hasJSDoc);- if (token() === SyntaxKind.EqualsToken) {- parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected_This_follows_a_block_of_statements_so_if_you_intended_to_write_a_destructuring_assignment_you_might_need_to_wrap_the_whole_assignment_in_parentheses);- nextToken();- }-- return result;- }- else {- const statements = createMissingList<Statement>();- return withJSDoc(finishNode(factoryCreateBlock(statements, /*multiLine*/ undefined), pos), hasJSDoc);- }- }-- function parseFunctionBlock(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block {- const savedYieldContext = inYieldContext();- setYieldContext(!!(flags & SignatureFlags.Yield));-- const savedAwaitContext = inAwaitContext();- setAwaitContext(!!(flags & SignatureFlags.Await));-- const savedTopLevel = topLevel;- topLevel = false;-- // We may be in a [Decorator] context when parsing a function expression or- // arrow function. The body of the function is not in [Decorator] context.- const saveDecoratorContext = inDecoratorContext();- if (saveDecoratorContext) {- setDecoratorContext(/*val*/ false);- }-- const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage);-- if (saveDecoratorContext) {- setDecoratorContext(/*val*/ true);- }-- topLevel = savedTopLevel;- setYieldContext(savedYieldContext);- setAwaitContext(savedAwaitContext);-- return block;- }-- function parseEmptyStatement(): Statement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.SemicolonToken);- return withJSDoc(finishNode(factory.createEmptyStatement(), pos), hasJSDoc);- }-- function parseIfStatement(): IfStatement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.IfKeyword);- const openParenPosition = scanner.getTokenStart();- const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);- const expression = allowInAnd(parseExpression);- parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);- const thenStatement = parseStatement();- const elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined;- return withJSDoc(finishNode(factoryCreateIfStatement(expression, thenStatement, elseStatement), pos), hasJSDoc);- }-- function parseDoStatement(): DoStatement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.DoKeyword);- const statement = parseStatement();- parseExpected(SyntaxKind.WhileKeyword);- const openParenPosition = scanner.getTokenStart();- const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);- const expression = allowInAnd(parseExpression);- parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);-- // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html- // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in- // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby- // do;while(0)x will have a semicolon inserted before x.- parseOptional(SyntaxKind.SemicolonToken);- return withJSDoc(finishNode(factory.createDoStatement(statement, expression), pos), hasJSDoc);- }-- function parseWhileStatement(): WhileStatement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.WhileKeyword);- const openParenPosition = scanner.getTokenStart();- const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);- const expression = allowInAnd(parseExpression);- parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);- const statement = parseStatement();- return withJSDoc(finishNode(factoryCreateWhileStatement(expression, statement), pos), hasJSDoc);- }-- function parseForOrForInOrForOfStatement(): Statement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.ForKeyword);- const awaitToken = parseOptionalToken(SyntaxKind.AwaitKeyword);- parseExpected(SyntaxKind.OpenParenToken);-- let initializer!: VariableDeclarationList | Expression;- if (token() !== SyntaxKind.SemicolonToken) {- if (- token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword ||- token() === SyntaxKind.UsingKeyword && lookAhead(nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLineDisallowOf) ||- // this one is meant to allow of- token() === SyntaxKind.AwaitKeyword && lookAhead(nextTokenIsUsingKeywordThenBindingIdentifierOrStartOfObjectDestructuringOnSameLine)- ) {- initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true);- }- else {- initializer = disallowInAnd(parseExpression);- }- }-- let node: IterationStatement;- if (awaitToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) {- const expression = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true));- parseExpected(SyntaxKind.CloseParenToken);- node = factoryCreateForOfStatement(awaitToken, initializer, expression, parseStatement());- }- else if (parseOptional(SyntaxKind.InKeyword)) {- const expression = allowInAnd(parseExpression);- parseExpected(SyntaxKind.CloseParenToken);- node = factory.createForInStatement(initializer, expression, parseStatement());- }- else {- parseExpected(SyntaxKind.SemicolonToken);- const condition = token() !== SyntaxKind.SemicolonToken && token() !== SyntaxKind.CloseParenToken- ? allowInAnd(parseExpression)- : undefined;- parseExpected(SyntaxKind.SemicolonToken);- const incrementor = token() !== SyntaxKind.CloseParenToken- ? allowInAnd(parseExpression)- : undefined;- parseExpected(SyntaxKind.CloseParenToken);- node = factoryCreateForStatement(initializer, condition, incrementor, parseStatement());- }-- return withJSDoc(finishNode(node, pos) as ForStatement | ForInOrOfStatement, hasJSDoc);- }-- function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();-- parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword);- const label = canParseSemicolon() ? undefined : parseIdentifier();-- parseSemicolon();- const node = kind === SyntaxKind.BreakStatement- ? factory.createBreakStatement(label)- : factory.createContinueStatement(label);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseReturnStatement(): ReturnStatement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.ReturnKeyword);- const expression = canParseSemicolon() ? undefined : allowInAnd(parseExpression);- parseSemicolon();- return withJSDoc(finishNode(factory.createReturnStatement(expression), pos), hasJSDoc);- }-- function parseWithStatement(): WithStatement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.WithKeyword);- const openParenPosition = scanner.getTokenStart();- const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);- const expression = allowInAnd(parseExpression);- parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);- const statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement);- return withJSDoc(finishNode(factory.createWithStatement(expression, statement), pos), hasJSDoc);- }-- function parseCaseClause(): CaseClause {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.CaseKeyword);- const expression = allowInAnd(parseExpression);- parseExpected(SyntaxKind.ColonToken);- const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement);- return withJSDoc(finishNode(factory.createCaseClause(expression, statements), pos), hasJSDoc);- }-- function parseDefaultClause(): DefaultClause {- const pos = getNodePos();- parseExpected(SyntaxKind.DefaultKeyword);- parseExpected(SyntaxKind.ColonToken);- const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement);- return finishNode(factory.createDefaultClause(statements), pos);- }-- function parseCaseOrDefaultClause(): CaseOrDefaultClause {- return token() === SyntaxKind.CaseKeyword ? parseCaseClause() : parseDefaultClause();- }-- function parseCaseBlock(): CaseBlock {- const pos = getNodePos();- parseExpected(SyntaxKind.OpenBraceToken);- const clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause);- parseExpected(SyntaxKind.CloseBraceToken);- return finishNode(factory.createCaseBlock(clauses), pos);- }-- function parseSwitchStatement(): SwitchStatement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.SwitchKeyword);- parseExpected(SyntaxKind.OpenParenToken);- const expression = allowInAnd(parseExpression);- parseExpected(SyntaxKind.CloseParenToken);- const caseBlock = parseCaseBlock();- return withJSDoc(finishNode(factory.createSwitchStatement(expression, caseBlock), pos), hasJSDoc);- }-- function parseThrowStatement(): ThrowStatement {- // ThrowStatement[Yield] :- // throw [no LineTerminator here]Expression[In, ?Yield];-- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.ThrowKeyword);-- // Because of automatic semicolon insertion, we need to report error if this- // throw could be terminated with a semicolon. Note: we can't call 'parseExpression'- // directly as that might consume an expression on the following line.- // Instead, we create a "missing" identifier, but don't report an error. The actual error- // will be reported in the grammar walker.- let expression = scanner.hasPrecedingLineBreak() ? undefined : allowInAnd(parseExpression);- if (expression === undefined) {- identifierCount++;- expression = finishNode(factoryCreateIdentifier(""), getNodePos());- }- if (!tryParseSemicolon()) {- parseErrorForMissingSemicolonAfter(expression);- }- return withJSDoc(finishNode(factory.createThrowStatement(expression), pos), hasJSDoc);- }-- // TODO: Review for error recovery- function parseTryStatement(): TryStatement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();-- parseExpected(SyntaxKind.TryKeyword);- const tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);- const catchClause = token() === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined;-- // If we don't have a catch clause, then we must have a finally clause. Try to parse- // one out no matter what.- let finallyBlock: Block | undefined;- if (!catchClause || token() === SyntaxKind.FinallyKeyword) {- parseExpected(SyntaxKind.FinallyKeyword, Diagnostics.catch_or_finally_expected);- finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);- }-- return withJSDoc(finishNode(factory.createTryStatement(tryBlock, catchClause, finallyBlock), pos), hasJSDoc);- }-- function parseCatchClause(): CatchClause {- const pos = getNodePos();- parseExpected(SyntaxKind.CatchKeyword);-- let variableDeclaration;- if (parseOptional(SyntaxKind.OpenParenToken)) {- variableDeclaration = parseVariableDeclaration();- parseExpected(SyntaxKind.CloseParenToken);- }- else {- // Keep shape of node to avoid degrading performance.- variableDeclaration = undefined;- }-- const block = parseBlock(/*ignoreMissingOpenBrace*/ false);- return finishNode(factory.createCatchClause(variableDeclaration, block), pos);- }-- function parseDebuggerStatement(): Statement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- parseExpected(SyntaxKind.DebuggerKeyword);- parseSemicolon();- return withJSDoc(finishNode(factory.createDebuggerStatement(), pos), hasJSDoc);- }-- function parseExpressionOrLabeledStatement(): ExpressionStatement | LabeledStatement {- // Avoiding having to do the lookahead for a labeled statement by just trying to parse- // out an expression, seeing if it is identifier and then seeing if it is followed by- // a colon.- const pos = getNodePos();- let hasJSDoc = hasPrecedingJSDocComment();- let node: ExpressionStatement | LabeledStatement;- const hasParen = token() === SyntaxKind.OpenParenToken;- const expression = allowInAnd(parseExpression);- if (isIdentifierNode(expression) && parseOptional(SyntaxKind.ColonToken)) {- node = factory.createLabeledStatement(expression, parseStatement());- }- else {- if (!tryParseSemicolon()) {- parseErrorForMissingSemicolonAfter(expression);- }- node = factoryCreateExpressionStatement(expression);- if (hasParen) {- // do not parse the same jsdoc twice- hasJSDoc = false;- }- }- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function nextTokenIsIdentifierOrKeywordOnSameLine() {- nextToken();- return tokenIsIdentifierOrKeyword(token()) && !scanner.hasPrecedingLineBreak();- }-- function nextTokenIsClassKeywordOnSameLine() {- nextToken();- return token() === SyntaxKind.ClassKeyword && !scanner.hasPrecedingLineBreak();- }-- function nextTokenIsFunctionKeywordOnSameLine() {- nextToken();- return token() === SyntaxKind.FunctionKeyword && !scanner.hasPrecedingLineBreak();- }-- function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() {- nextToken();- return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak();- }-- function isDeclaration(): boolean {- while (true) {- switch (token()) {- case SyntaxKind.VarKeyword:- case SyntaxKind.LetKeyword:- case SyntaxKind.ConstKeyword:- case SyntaxKind.FunctionKeyword:- case SyntaxKind.ClassKeyword:- case SyntaxKind.EnumKeyword:- return true;- case SyntaxKind.UsingKeyword:- return isUsingDeclaration();- case SyntaxKind.AwaitKeyword:- return isAwaitUsingDeclaration();-- // 'declare', 'module', 'namespace', 'interface'* and 'type' are all legal JavaScript identifiers;- // however, an identifier cannot be followed by another identifier on the same line. This is what we- // count on to parse out the respective declarations. For instance, we exploit this to say that- //- // namespace n- //- // can be none other than the beginning of a namespace declaration, but need to respect that JavaScript sees- //- // namespace- // n- //- // as the identifier 'namespace' on one line followed by the identifier 'n' on another.- // We need to look one token ahead to see if it permissible to try parsing a declaration.- //- // *Note*: 'interface' is actually a strict mode reserved word. So while- //- // "use strict"- // interface- // I {}- //- // could be legal, it would add complexity for very little gain.- case SyntaxKind.InterfaceKeyword:- case SyntaxKind.TypeKeyword:- return nextTokenIsIdentifierOnSameLine();- case SyntaxKind.ModuleKeyword:- case SyntaxKind.NamespaceKeyword:- return nextTokenIsIdentifierOrStringLiteralOnSameLine();- case SyntaxKind.AbstractKeyword:- case SyntaxKind.AccessorKeyword:- case SyntaxKind.AsyncKeyword:- case SyntaxKind.DeclareKeyword:- case SyntaxKind.PrivateKeyword:- case SyntaxKind.ProtectedKeyword:- case SyntaxKind.PublicKeyword:- case SyntaxKind.ReadonlyKeyword:- const previousToken = token();- nextToken();- // ASI takes effect for this modifier.- if (scanner.hasPrecedingLineBreak()) {- return false;- }- if (previousToken === SyntaxKind.DeclareKeyword && token() === SyntaxKind.TypeKeyword) {- // If we see 'declare type', then commit to parsing a type alias. parseTypeAliasDeclaration will- // report Line_break_not_permitted_here if needed.- return true;- }- continue;-- case SyntaxKind.GlobalKeyword:- nextToken();- return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier || token() === SyntaxKind.ExportKeyword;-- case SyntaxKind.ImportKeyword:- nextToken();- return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken ||- token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token());- case SyntaxKind.ExportKeyword:- let currentToken = nextToken();- if (currentToken === SyntaxKind.TypeKeyword) {- currentToken = lookAhead(nextToken);- }- if (- currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken ||- currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword ||- currentToken === SyntaxKind.AsKeyword || currentToken === SyntaxKind.AtToken- ) {- return true;- }- continue;-- case SyntaxKind.StaticKeyword:- nextToken();- continue;-- default:- return false;- }- }- }-- function isStartOfDeclaration(): boolean {- return lookAhead(isDeclaration);- }-- function isStartOfStatement(): boolean {- switch (token()) {- case SyntaxKind.AtToken:- case SyntaxKind.SemicolonToken:- case SyntaxKind.OpenBraceToken:- case SyntaxKind.VarKeyword:- case SyntaxKind.LetKeyword:- case SyntaxKind.UsingKeyword:- case SyntaxKind.FunctionKeyword:- case SyntaxKind.ClassKeyword:- case SyntaxKind.EnumKeyword:- case SyntaxKind.IfKeyword:- case SyntaxKind.DoKeyword:- case SyntaxKind.WhileKeyword:- case SyntaxKind.ForKeyword:- case SyntaxKind.ContinueKeyword:- case SyntaxKind.BreakKeyword:- case SyntaxKind.ReturnKeyword:- case SyntaxKind.WithKeyword:- case SyntaxKind.SwitchKeyword:- case SyntaxKind.ThrowKeyword:- case SyntaxKind.TryKeyword:- case SyntaxKind.DebuggerKeyword:- // 'catch' and 'finally' do not actually indicate that the code is part of a statement,- // however, we say they are here so that we may gracefully parse them and error later.- // falls through- case SyntaxKind.CatchKeyword:- case SyntaxKind.FinallyKeyword:- return true;-- case SyntaxKind.ImportKeyword:- return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThanOrDot);-- case SyntaxKind.ConstKeyword:- case SyntaxKind.ExportKeyword:- return isStartOfDeclaration();-- case SyntaxKind.AsyncKeyword:- case SyntaxKind.DeclareKeyword:- case SyntaxKind.InterfaceKeyword:- case SyntaxKind.ModuleKeyword:- case SyntaxKind.NamespaceKeyword:- case SyntaxKind.TypeKeyword:- case SyntaxKind.GlobalKeyword:- // When these don't start a declaration, they're an identifier in an expression statement- return true;-- case SyntaxKind.AccessorKeyword:- case SyntaxKind.PublicKeyword:- case SyntaxKind.PrivateKeyword:- case SyntaxKind.ProtectedKeyword:- case SyntaxKind.StaticKeyword:- case SyntaxKind.ReadonlyKeyword:- // When these don't start a declaration, they may be the start of a class member if an identifier- // immediately follows. Otherwise they're an identifier in an expression statement.- return isStartOfDeclaration() || !lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine);-- default:- return isStartOfExpression();- }- }-- function nextTokenIsBindingIdentifierOrStartOfDestructuring() {- nextToken();- return isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken;- }-- function isLetDeclaration() {- // In ES6 'let' always starts a lexical declaration if followed by an identifier or {- // or [.- return lookAhead(nextTokenIsBindingIdentifierOrStartOfDestructuring);- }-- function nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLineDisallowOf() {- return nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLine(/*disallowOf*/ true);- }-- function nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLine(disallowOf?: boolean) {- nextToken();- if (disallowOf && token() === SyntaxKind.OfKeyword) return false;- return (isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken) && !scanner.hasPrecedingLineBreak();- }-- function isUsingDeclaration() {- // 'using' always starts a lexical declaration if followed by an identifier. We also eagerly parse- // |ObjectBindingPattern| so that we can report a grammar error during check. We don't parse out- // |ArrayBindingPattern| since it potentially conflicts with element access (i.e., `using[x]`).- return lookAhead(nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLine);- }-- function nextTokenIsUsingKeywordThenBindingIdentifierOrStartOfObjectDestructuringOnSameLine(disallowOf?: boolean) {- if (nextToken() === SyntaxKind.UsingKeyword) {- return nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLine(disallowOf);- }- return false;- }-- function isAwaitUsingDeclaration() {- // 'await using' always starts a lexical declaration if followed by an identifier. We also eagerly parse- // |ObjectBindingPattern| so that we can report a grammar error during check. We don't parse out- // |ArrayBindingPattern| since it potentially conflicts with element access (i.e., `await using[x]`).- return lookAhead(nextTokenIsUsingKeywordThenBindingIdentifierOrStartOfObjectDestructuringOnSameLine);- }-- function parseStatement(): Statement {- switch (token()) {- case SyntaxKind.SemicolonToken:- return parseEmptyStatement();- case SyntaxKind.OpenBraceToken:- return parseBlock(/*ignoreMissingOpenBrace*/ false);- case SyntaxKind.VarKeyword:- return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*modifiers*/ undefined);- case SyntaxKind.LetKeyword:- if (isLetDeclaration()) {- return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*modifiers*/ undefined);- }- break;- case SyntaxKind.AwaitKeyword:- if (isAwaitUsingDeclaration()) {- return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*modifiers*/ undefined);- }- break;- case SyntaxKind.UsingKeyword:- if (isUsingDeclaration()) {- return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*modifiers*/ undefined);- }- break;- case SyntaxKind.FunctionKeyword:- return parseFunctionDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*modifiers*/ undefined);- case SyntaxKind.ClassKeyword:- return parseClassDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*modifiers*/ undefined);- case SyntaxKind.IfKeyword:- return parseIfStatement();- case SyntaxKind.DoKeyword:- return parseDoStatement();- case SyntaxKind.WhileKeyword:- return parseWhileStatement();- case SyntaxKind.ForKeyword:- return parseForOrForInOrForOfStatement();- case SyntaxKind.ContinueKeyword:- return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement);- case SyntaxKind.BreakKeyword:- return parseBreakOrContinueStatement(SyntaxKind.BreakStatement);- case SyntaxKind.ReturnKeyword:- return parseReturnStatement();- case SyntaxKind.WithKeyword:- return parseWithStatement();- case SyntaxKind.SwitchKeyword:- return parseSwitchStatement();- case SyntaxKind.ThrowKeyword:- return parseThrowStatement();- case SyntaxKind.TryKeyword:- // Include 'catch' and 'finally' for error recovery.- // falls through- case SyntaxKind.CatchKeyword:- case SyntaxKind.FinallyKeyword:- return parseTryStatement();- case SyntaxKind.DebuggerKeyword:- return parseDebuggerStatement();- case SyntaxKind.AtToken:- return parseDeclaration();- case SyntaxKind.AsyncKeyword:- case SyntaxKind.InterfaceKeyword:- case SyntaxKind.TypeKeyword:- case SyntaxKind.ModuleKeyword:- case SyntaxKind.NamespaceKeyword:- case SyntaxKind.DeclareKeyword:- case SyntaxKind.ConstKeyword:- case SyntaxKind.EnumKeyword:- case SyntaxKind.ExportKeyword:- case SyntaxKind.ImportKeyword:- case SyntaxKind.PrivateKeyword:- case SyntaxKind.ProtectedKeyword:- case SyntaxKind.PublicKeyword:- case SyntaxKind.AbstractKeyword:- case SyntaxKind.AccessorKeyword:- case SyntaxKind.StaticKeyword:- case SyntaxKind.ReadonlyKeyword:- case SyntaxKind.GlobalKeyword:- if (isStartOfDeclaration()) {- return parseDeclaration();- }- break;- }- return parseExpressionOrLabeledStatement();- }-- function isDeclareModifier(modifier: ModifierLike) {- return modifier.kind === SyntaxKind.DeclareKeyword;- }-- function parseDeclaration(): Statement {- // `parseListElement` attempted to get the reused node at this position,- // but the ambient context flag was not yet set, so the node appeared- // not reusable in that context.- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const modifiers = parseModifiers(/*allowDecorators*/ true);- const isAmbient = some(modifiers, isDeclareModifier);- if (isAmbient) {- const node = tryReuseAmbientDeclaration(pos);- if (node) {- return node;- }-- for (const m of modifiers!) {- (m as Mutable<Node>).flags |= NodeFlags.Ambient;- }- return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(pos, hasJSDoc, modifiers));- }- else {- return parseDeclarationWorker(pos, hasJSDoc, modifiers);- }- }-- function tryReuseAmbientDeclaration(pos: number): Statement | undefined {- return doInsideOfContext(NodeFlags.Ambient, () => {- // TODO(jakebailey): this is totally wrong; `parsingContext` is the result of ORing a bunch of `1 << ParsingContext.XYZ`.- // The enum should really be a bunch of flags.- const node = currentNode(parsingContext, pos);- if (node) {- return consumeNode(node) as Statement;- }- });- }-- function parseDeclarationWorker(pos: number, hasJSDoc: boolean, modifiersIn: NodeArray<ModifierLike> | undefined): Statement {- switch (token()) {- case SyntaxKind.VarKeyword:- case SyntaxKind.LetKeyword:- case SyntaxKind.ConstKeyword:- case SyntaxKind.UsingKeyword:- case SyntaxKind.AwaitKeyword:- return parseVariableStatement(pos, hasJSDoc, modifiersIn);- case SyntaxKind.FunctionKeyword:- return parseFunctionDeclaration(pos, hasJSDoc, modifiersIn);- case SyntaxKind.ClassKeyword:- return parseClassDeclaration(pos, hasJSDoc, modifiersIn);- case SyntaxKind.InterfaceKeyword:- return parseInterfaceDeclaration(pos, hasJSDoc, modifiersIn);- case SyntaxKind.TypeKeyword:- return parseTypeAliasDeclaration(pos, hasJSDoc, modifiersIn);- case SyntaxKind.EnumKeyword:- return parseEnumDeclaration(pos, hasJSDoc, modifiersIn);- case SyntaxKind.GlobalKeyword:- case SyntaxKind.ModuleKeyword:- case SyntaxKind.NamespaceKeyword:- return parseModuleDeclaration(pos, hasJSDoc, modifiersIn);- case SyntaxKind.ImportKeyword:- return parseImportDeclarationOrImportEqualsDeclaration(pos, hasJSDoc, modifiersIn);- case SyntaxKind.ExportKeyword:- nextToken();- switch (token()) {- case SyntaxKind.DefaultKeyword:- case SyntaxKind.EqualsToken:- return parseExportAssignment(pos, hasJSDoc, modifiersIn);- case SyntaxKind.AsKeyword:- return parseNamespaceExportDeclaration(pos, hasJSDoc, modifiersIn);- default:- return parseExportDeclaration(pos, hasJSDoc, modifiersIn);- }- default:- if (modifiersIn) {- // We reached this point because we encountered decorators and/or modifiers and assumed a declaration- // would follow. For recovery and error reporting purposes, return an incomplete declaration.- const missing = createMissingNode<MissingDeclaration>(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected);- setTextRangePos(missing, pos);- (missing as Mutable<MissingDeclaration>).modifiers = modifiersIn;- return missing;- }- return undefined!; // TODO: GH#18217- }- }-- function nextTokenIsStringLiteral() {- return nextToken() === SyntaxKind.StringLiteral;- }-- function nextTokenIsFromKeywordOrEqualsToken() {- nextToken();- return token() === SyntaxKind.FromKeyword || token() === SyntaxKind.EqualsToken;- }-- function nextTokenIsIdentifierOrStringLiteralOnSameLine() {- nextToken();- return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral);- }-- function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block | undefined {- if (token() !== SyntaxKind.OpenBraceToken) {- if (flags & SignatureFlags.Type) {- parseTypeMemberSemicolon();- return;- }- if (canParseSemicolon()) {- parseSemicolon();- return;- }- }- return parseFunctionBlock(flags, diagnosticMessage);- }-- // DECLARATIONS-- function parseArrayBindingElement(): ArrayBindingElement {- const pos = getNodePos();- if (token() === SyntaxKind.CommaToken) {- return finishNode(factory.createOmittedExpression(), pos);- }- const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);- const name = parseIdentifierOrPattern();- const initializer = parseInitializer();- return finishNode(factory.createBindingElement(dotDotDotToken, /*propertyName*/ undefined, name, initializer), pos);- }-- function parseObjectBindingElement(): BindingElement {- const pos = getNodePos();- const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);- const tokenIsIdentifier = isBindingIdentifier();- let propertyName: PropertyName | undefined = parsePropertyName();- let name: BindingName;- if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) {- name = propertyName as Identifier;- propertyName = undefined;- }- else {- parseExpected(SyntaxKind.ColonToken);- name = parseIdentifierOrPattern();- }- const initializer = parseInitializer();- return finishNode(factory.createBindingElement(dotDotDotToken, propertyName, name, initializer), pos);- }-- function parseObjectBindingPattern(): ObjectBindingPattern {- const pos = getNodePos();- parseExpected(SyntaxKind.OpenBraceToken);- const elements = allowInAnd(() => parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement));- parseExpected(SyntaxKind.CloseBraceToken);- return finishNode(factory.createObjectBindingPattern(elements), pos);- }-- function parseArrayBindingPattern(): ArrayBindingPattern {- const pos = getNodePos();- parseExpected(SyntaxKind.OpenBracketToken);- const elements = allowInAnd(() => parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement));- parseExpected(SyntaxKind.CloseBracketToken);- return finishNode(factory.createArrayBindingPattern(elements), pos);- }-- function isBindingIdentifierOrPrivateIdentifierOrPattern() {- return token() === SyntaxKind.OpenBraceToken- || token() === SyntaxKind.OpenBracketToken- || token() === SyntaxKind.PrivateIdentifier- || isBindingIdentifier();- }-- function parseIdentifierOrPattern(privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier | BindingPattern {- if (token() === SyntaxKind.OpenBracketToken) {- return parseArrayBindingPattern();- }- if (token() === SyntaxKind.OpenBraceToken) {- return parseObjectBindingPattern();- }- return parseBindingIdentifier(privateIdentifierDiagnosticMessage);- }-- function parseVariableDeclarationAllowExclamation() {- return parseVariableDeclaration(/*allowExclamation*/ true);- }-- function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations);- let exclamationToken: ExclamationToken | undefined;- if (- allowExclamation && name.kind === SyntaxKind.Identifier &&- token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()- ) {- exclamationToken = parseTokenNode<Token<SyntaxKind.ExclamationToken>>();- }- const type = parseTypeAnnotation();- const initializer = isInOrOfKeyword(token()) ? undefined : parseInitializer();- const node = factoryCreateVariableDeclaration(name, exclamationToken, type, initializer);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList {- const pos = getNodePos();-- let flags: NodeFlags = 0;- switch (token()) {- case SyntaxKind.VarKeyword:- break;- case SyntaxKind.LetKeyword:- flags |= NodeFlags.Let;- break;- case SyntaxKind.ConstKeyword:- flags |= NodeFlags.Const;- break;- case SyntaxKind.UsingKeyword:- flags |= NodeFlags.Using;- break;- case SyntaxKind.AwaitKeyword:- Debug.assert(isAwaitUsingDeclaration());- flags |= NodeFlags.AwaitUsing;- nextToken();- break;- default:- Debug.fail();- }-- nextToken();-- // The user may have written the following:- //- // for (let of X) { }- //- // In this case, we want to parse an empty declaration list, and then parse 'of'- // as a keyword. The reason this is not automatic is that 'of' is a valid identifier.- // So we need to look ahead to determine if 'of' should be treated as a keyword in- // this context.- // The checker will then give an error that there is an empty declaration list.- let declarations: readonly VariableDeclaration[];- if (token() === SyntaxKind.OfKeyword && lookAhead(canFollowContextualOfKeyword)) {- declarations = createMissingList<VariableDeclaration>();- }- else {- const savedDisallowIn = inDisallowInContext();- setDisallowInContext(inForStatementInitializer);-- declarations = parseDelimitedList(- ParsingContext.VariableDeclarations,- inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation,- );-- setDisallowInContext(savedDisallowIn);- }-- return finishNode(factoryCreateVariableDeclarationList(declarations, flags), pos);- }-- function canFollowContextualOfKeyword(): boolean {- return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken;- }-- function parseVariableStatement(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): VariableStatement {- const declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false);- parseSemicolon();- const node = factoryCreateVariableStatement(modifiers, declarationList);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseFunctionDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): FunctionDeclaration {- const savedAwaitContext = inAwaitContext();- const modifierFlags = modifiersToFlags(modifiers);- parseExpected(SyntaxKind.FunctionKeyword);- const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);- // We don't parse the name here in await context, instead we will report a grammar error in the checker.- const name = modifierFlags & ModifierFlags.Default ? parseOptionalBindingIdentifier() : parseBindingIdentifier();- const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;- const isAsync = modifierFlags & ModifierFlags.Async ? SignatureFlags.Await : SignatureFlags.None;- const typeParameters = parseTypeParameters();- if (modifierFlags & ModifierFlags.Export) setAwaitContext(/*value*/ true);- const parameters = parseParameters(isGenerator | isAsync);- const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);- const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected);- setAwaitContext(savedAwaitContext);- const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseConstructorName() {- if (token() === SyntaxKind.ConstructorKeyword) {- return parseExpected(SyntaxKind.ConstructorKeyword);- }- if (token() === SyntaxKind.StringLiteral && lookAhead(nextToken) === SyntaxKind.OpenParenToken) {- return tryParse(() => {- const literalNode = parseLiteralNode();- return literalNode.text === "constructor" ? literalNode : undefined;- });- }- }-- function tryParseConstructorDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): ConstructorDeclaration | undefined {- return tryParse(() => {- if (parseConstructorName()) {- const typeParameters = parseTypeParameters();- const parameters = parseParameters(SignatureFlags.None);- const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);- const body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected);- const node = factory.createConstructorDeclaration(modifiers, parameters, body);-- // Attach invalid nodes if they exist so that we can report them in the grammar checker.- (node as Mutable<ConstructorDeclaration>).typeParameters = typeParameters;- (node as Mutable<ConstructorDeclaration>).type = type;- return withJSDoc(finishNode(node, pos), hasJSDoc);- }- });- }-- function parseMethodDeclaration(- pos: number,- hasJSDoc: boolean,- modifiers: NodeArray<ModifierLike> | undefined,- asteriskToken: AsteriskToken | undefined,- name: PropertyName,- questionToken: QuestionToken | undefined,- exclamationToken: ExclamationToken | undefined,- diagnosticMessage?: DiagnosticMessage,- ): MethodDeclaration {- const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;- const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None;- const typeParameters = parseTypeParameters();- const parameters = parseParameters(isGenerator | isAsync);- const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);- const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, diagnosticMessage);- const node = factory.createMethodDeclaration(- modifiers,- asteriskToken,- name,- questionToken,- typeParameters,- parameters,- type,- body,- );-- // An exclamation token on a method is invalid syntax and will be handled by the grammar checker- (node as Mutable<MethodDeclaration>).exclamationToken = exclamationToken;- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parsePropertyDeclaration(- pos: number,- hasJSDoc: boolean,- modifiers: NodeArray<ModifierLike> | undefined,- name: PropertyName,- questionToken: QuestionToken | undefined,- ): PropertyDeclaration {- const exclamationToken = !questionToken && !scanner.hasPrecedingLineBreak() ? parseOptionalToken(SyntaxKind.ExclamationToken) : undefined;- const type = parseTypeAnnotation();- const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer);- parseSemicolonAfterPropertyName(name, type, initializer);- const node = factory.createPropertyDeclaration(- modifiers,- name,- questionToken || exclamationToken,- type,- initializer,- );- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parsePropertyOrMethodDeclaration(- pos: number,- hasJSDoc: boolean,- modifiers: NodeArray<ModifierLike> | undefined,- ): PropertyDeclaration | MethodDeclaration {- const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);- const name = parsePropertyName();- // Note: this is not legal as per the grammar. But we allow it in the parser and- // report an error in the grammar checker.- const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);- if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {- return parseMethodDeclaration(pos, hasJSDoc, modifiers, asteriskToken, name, questionToken, /*exclamationToken*/ undefined, Diagnostics.or_expected);- }- return parsePropertyDeclaration(pos, hasJSDoc, modifiers, name, questionToken);- }-- function parseAccessorDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined, kind: AccessorDeclaration["kind"], flags: SignatureFlags): AccessorDeclaration {- const name = parsePropertyName();- const typeParameters = parseTypeParameters();- const parameters = parseParameters(SignatureFlags.None);- const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);- const body = parseFunctionBlockOrSemicolon(flags);- const node = kind === SyntaxKind.GetAccessor- ? factory.createGetAccessorDeclaration(modifiers, name, parameters, type, body)- : factory.createSetAccessorDeclaration(modifiers, name, parameters, body);- // Keep track of `typeParameters` (for both) and `type` (for setters) if they were parsed those indicate grammar errors- (node as Mutable<AccessorDeclaration>).typeParameters = typeParameters;- if (isSetAccessorDeclaration(node)) (node as Mutable<SetAccessorDeclaration>).type = type;- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function isClassMemberStart(): boolean {- let idToken: SyntaxKind | undefined;-- if (token() === SyntaxKind.AtToken) {- return true;- }-- // Eat up all modifiers, but hold on to the last one in case it is actually an identifier.- while (isModifierKind(token())) {- idToken = token();- // If the idToken is a class modifier (protected, private, public, and static), it is- // certain that we are starting to parse class member. This allows better error recovery- // Example:- // public foo() ... // true- // public @dec blah ... // true; we will then report an error later- // export public ... // true; we will then report an error later- if (isClassMemberModifier(idToken)) {- return true;- }-- nextToken();- }-- if (token() === SyntaxKind.AsteriskToken) {- return true;- }-- // Try to get the first property-like token following all modifiers.- // This can either be an identifier or the 'get' or 'set' keywords.- if (isLiteralPropertyName()) {- idToken = token();- nextToken();- }-- // Index signatures and computed properties are class members; we can parse.- if (token() === SyntaxKind.OpenBracketToken) {- return true;- }-- // If we were able to get any potential identifier...- if (idToken !== undefined) {- // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse.- if (!isKeyword(idToken) || idToken === SyntaxKind.SetKeyword || idToken === SyntaxKind.GetKeyword) {- return true;- }-- // If it *is* a keyword, but not an accessor, check a little farther along- // to see if it should actually be parsed as a class member.- switch (token()) {- case SyntaxKind.OpenParenToken: // Method declaration- case SyntaxKind.LessThanToken: // Generic Method declaration- case SyntaxKind.ExclamationToken: // Non-null assertion on property name- case SyntaxKind.ColonToken: // Type Annotation for declaration- case SyntaxKind.EqualsToken: // Initializer for declaration- case SyntaxKind.QuestionToken: // Not valid, but permitted so that it gets caught later on.- return true;- default:- // Covers- // - Semicolons (declaration termination)- // - Closing braces (end-of-class, must be declaration)- // - End-of-files (not valid, but permitted so that it gets caught later on)- // - Line-breaks (enabling *automatic semicolon insertion*)- return canParseSemicolon();- }- }-- return false;- }-- function parseClassStaticBlockDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): ClassStaticBlockDeclaration {- parseExpectedToken(SyntaxKind.StaticKeyword);- const body = parseClassStaticBlockBody();- const node = withJSDoc(finishNode(factory.createClassStaticBlockDeclaration(body), pos), hasJSDoc);- (node as Mutable<ClassStaticBlockDeclaration>).modifiers = modifiers;- return node;- }-- function parseClassStaticBlockBody() {- const savedYieldContext = inYieldContext();- const savedAwaitContext = inAwaitContext();-- setYieldContext(false);- setAwaitContext(true);-- const body = parseBlock(/*ignoreMissingOpenBrace*/ false);-- setYieldContext(savedYieldContext);- setAwaitContext(savedAwaitContext);-- return body;- }-- function parseDecoratorExpression() {- if (inAwaitContext() && token() === SyntaxKind.AwaitKeyword) {- // `@await` is is disallowed in an [Await] context, but can cause parsing to go off the rails- // This simply parses the missing identifier and moves on.- const pos = getNodePos();- const awaitExpression = parseIdentifier(Diagnostics.Expression_expected);- nextToken();- const memberExpression = parseMemberExpressionRest(pos, awaitExpression, /*allowOptionalChain*/ true);- return parseCallExpressionRest(pos, memberExpression);- }- return parseLeftHandSideExpressionOrHigher();- }-- function tryParseDecorator(): Decorator | undefined {- const pos = getNodePos();- if (!parseOptional(SyntaxKind.AtToken)) {- return undefined;- }- const expression = doInDecoratorContext(parseDecoratorExpression);- return finishNode(factory.createDecorator(expression), pos);- }-- function tryParseModifier(hasSeenStaticModifier: boolean, permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): Modifier | undefined {- const pos = getNodePos();- const kind = token();-- if (token() === SyntaxKind.ConstKeyword && permitConstAsModifier) {- // We need to ensure that any subsequent modifiers appear on the same line- // so that when 'const' is a standalone declaration, we don't issue an error.- if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) {- return undefined;- }- }- else if (stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) {- return undefined;- }- else if (hasSeenStaticModifier && token() === SyntaxKind.StaticKeyword) {- return undefined;- }- else {- if (!parseAnyContextualModifier()) {- return undefined;- }- }-- return finishNode(factoryCreateToken(kind as Modifier["kind"]), pos);- }-- /*- * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member.- * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect- * and turns it into a standalone declaration), then it is better to parse it and report an error later.- *- * In such situations, 'permitConstAsModifier' should be set to true.- */- function parseModifiers(allowDecorators: false, permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray<Modifier> | undefined;- function parseModifiers(allowDecorators: true, permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray<ModifierLike> | undefined;- function parseModifiers(allowDecorators: boolean, permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray<ModifierLike> | undefined {- const pos = getNodePos();- let list: ModifierLike[] | undefined;- let decorator, modifier, hasSeenStaticModifier = false, hasLeadingModifier = false, hasTrailingDecorator = false;-- // Decorators should be contiguous in a list of modifiers but can potentially appear in two places (i.e., `[...leadingDecorators, ...leadingModifiers, ...trailingDecorators, ...trailingModifiers]`).- // The leading modifiers *should* only contain `export` and `default` when trailingDecorators are present, but we'll handle errors for any other leading modifiers in the checker.- // It is illegal to have both leadingDecorators and trailingDecorators, but we will report that as a grammar check in the checker.-- // parse leading decorators- if (allowDecorators && token() === SyntaxKind.AtToken) {- while (decorator = tryParseDecorator()) {- list = append(list, decorator);- }- }-- // parse leading modifiers- while (modifier = tryParseModifier(hasSeenStaticModifier, permitConstAsModifier, stopOnStartOfClassStaticBlock)) {- if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStaticModifier = true;- list = append(list, modifier);- hasLeadingModifier = true;- }-- // parse trailing decorators, but only if we parsed any leading modifiers- if (hasLeadingModifier && allowDecorators && token() === SyntaxKind.AtToken) {- while (decorator = tryParseDecorator()) {- list = append(list, decorator);- hasTrailingDecorator = true;- }- }-- // parse trailing modifiers, but only if we parsed any trailing decorators- if (hasTrailingDecorator) {- while (modifier = tryParseModifier(hasSeenStaticModifier, permitConstAsModifier, stopOnStartOfClassStaticBlock)) {- if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStaticModifier = true;- list = append(list, modifier);- }- }-- return list && createNodeArray(list, pos);- }-- function parseModifiersForArrowFunction(): NodeArray<Modifier> | undefined {- let modifiers: NodeArray<Modifier> | undefined;- if (token() === SyntaxKind.AsyncKeyword) {- const pos = getNodePos();- nextToken();- const modifier = finishNode(factoryCreateToken(SyntaxKind.AsyncKeyword), pos);- modifiers = createNodeArray<Modifier>([modifier], pos);- }- return modifiers;- }-- function parseClassElement(): ClassElement {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- if (token() === SyntaxKind.SemicolonToken) {- nextToken();- return withJSDoc(finishNode(factory.createSemicolonClassElement(), pos), hasJSDoc);- }-- const modifiers = parseModifiers(/*allowDecorators*/ true, /*permitConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true);- if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) {- return parseClassStaticBlockDeclaration(pos, hasJSDoc, modifiers);- }-- if (parseContextualModifier(SyntaxKind.GetKeyword)) {- return parseAccessorDeclaration(pos, hasJSDoc, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None);- }-- if (parseContextualModifier(SyntaxKind.SetKeyword)) {- return parseAccessorDeclaration(pos, hasJSDoc, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None);- }-- if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) {- const constructorDeclaration = tryParseConstructorDeclaration(pos, hasJSDoc, modifiers);- if (constructorDeclaration) {- return constructorDeclaration;- }- }-- if (isIndexSignature()) {- return parseIndexSignatureDeclaration(pos, hasJSDoc, modifiers);- }-- // It is very important that we check this *after* checking indexers because- // the [ token can start an index signature or a computed property name- if (- tokenIsIdentifierOrKeyword(token()) ||- token() === SyntaxKind.StringLiteral ||- token() === SyntaxKind.NumericLiteral ||- token() === SyntaxKind.BigIntLiteral ||- token() === SyntaxKind.AsteriskToken ||- token() === SyntaxKind.OpenBracketToken- ) {- const isAmbient = some(modifiers, isDeclareModifier);- if (isAmbient) {- for (const m of modifiers!) {- (m as Mutable<Node>).flags |= NodeFlags.Ambient;- }- return doInsideOfContext(NodeFlags.Ambient, () => parsePropertyOrMethodDeclaration(pos, hasJSDoc, modifiers));- }- else {- return parsePropertyOrMethodDeclaration(pos, hasJSDoc, modifiers);- }- }-- if (modifiers) {- // treat this as a property declaration with a missing name.- const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected);- return parsePropertyDeclaration(pos, hasJSDoc, modifiers, name, /*questionToken*/ undefined);- }-- // 'isClassMemberStart' should have hinted not to attempt parsing.- return Debug.fail("Should not have attempted to parse class member declaration.");- }-- function parseDecoratedExpression(): PrimaryExpression {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const modifiers = parseModifiers(/*allowDecorators*/ true);- if (token() === SyntaxKind.ClassKeyword) {- return parseClassDeclarationOrExpression(pos, hasJSDoc, modifiers, SyntaxKind.ClassExpression) as ClassExpression;- }-- const missing = createMissingNode<MissingDeclaration>(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Expression_expected);- setTextRangePos(missing, pos);- (missing as Mutable<MissingDeclaration>).modifiers = modifiers;- return missing;- }-- function parseClassExpression(): ClassExpression {- return parseClassDeclarationOrExpression(getNodePos(), hasPrecedingJSDocComment(), /*modifiers*/ undefined, SyntaxKind.ClassExpression) as ClassExpression;- }-- function parseClassDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): ClassDeclaration {- return parseClassDeclarationOrExpression(pos, hasJSDoc, modifiers, SyntaxKind.ClassDeclaration) as ClassDeclaration;- }-- function parseClassDeclarationOrExpression(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined, kind: ClassLikeDeclaration["kind"]): ClassLikeDeclaration {- const savedAwaitContext = inAwaitContext();- parseExpected(SyntaxKind.ClassKeyword);-- // We don't parse the name here in await context, instead we will report a grammar error in the checker.- const name = parseNameOfClassDeclarationOrExpression();- const typeParameters = parseTypeParameters();- if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true);- const heritageClauses = parseHeritageClauses();-- let members;- if (parseExpected(SyntaxKind.OpenBraceToken)) {- // ClassTail[Yield,Await] : (Modified) See 14.5- // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }- members = parseClassMembers();- parseExpected(SyntaxKind.CloseBraceToken);- }- else {- members = createMissingList<ClassElement>();- }- setAwaitContext(savedAwaitContext);- const node = kind === SyntaxKind.ClassDeclaration- ? factory.createClassDeclaration(modifiers, name, typeParameters, heritageClauses, members)- : factory.createClassExpression(modifiers, name, typeParameters, heritageClauses, members);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseNameOfClassDeclarationOrExpression(): Identifier | undefined {- // implements is a future reserved word so- // 'class implements' might mean either- // - class expression with omitted name, 'implements' starts heritage clause- // - class with name 'implements'- // 'isImplementsClause' helps to disambiguate between these two cases- return isBindingIdentifier() && !isImplementsClause()- ? createIdentifier(isBindingIdentifier())- : undefined;- }-- function isImplementsClause() {- return token() === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword);- }-- function parseHeritageClauses(): NodeArray<HeritageClause> | undefined {- // ClassTail[Yield,Await] : (Modified) See 14.5- // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }-- if (isHeritageClause()) {- return parseList(ParsingContext.HeritageClauses, parseHeritageClause);- }-- return undefined;- }-- function parseHeritageClause(): HeritageClause {- const pos = getNodePos();- const tok = token();- Debug.assert(tok === SyntaxKind.ExtendsKeyword || tok === SyntaxKind.ImplementsKeyword); // isListElement() should ensure this.- nextToken();- const types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseExpressionWithTypeArguments);- return finishNode(factory.createHeritageClause(tok, types), pos);- }-- function parseExpressionWithTypeArguments(): ExpressionWithTypeArguments {- const pos = getNodePos();- const expression = parseLeftHandSideExpressionOrHigher();- if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) {- return expression as ExpressionWithTypeArguments;- }- const typeArguments = tryParseTypeArguments();- return finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos);- }-- function tryParseTypeArguments(): NodeArray<TypeNode> | undefined {- return token() === SyntaxKind.LessThanToken ?- parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) : undefined;- }-- function isHeritageClause(): boolean {- return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;- }-- function parseClassMembers(): NodeArray<ClassElement> {- return parseList(ParsingContext.ClassMembers, parseClassElement);- }-- function parseInterfaceDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): InterfaceDeclaration {- parseExpected(SyntaxKind.InterfaceKeyword);- const name = parseIdentifier();- const typeParameters = parseTypeParameters();- const heritageClauses = parseHeritageClauses();- const members = parseObjectTypeMembers();- const node = factory.createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseTypeAliasDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): TypeAliasDeclaration {- parseExpected(SyntaxKind.TypeKeyword);- if (scanner.hasPrecedingLineBreak()) {- parseErrorAtCurrentToken(Diagnostics.Line_break_not_permitted_here);- }- const name = parseIdentifier();- const typeParameters = parseTypeParameters();- parseExpected(SyntaxKind.EqualsToken);- const type = token() === SyntaxKind.IntrinsicKeyword && tryParse(parseKeywordAndNoDot) || parseType();- parseSemicolon();- const node = factory.createTypeAliasDeclaration(modifiers, name, typeParameters, type);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- // In an ambient declaration, the grammar only allows integer literals as initializers.- // In a non-ambient declaration, the grammar allows uninitialized members only in a- // ConstantEnumMemberSection, which starts at the beginning of an enum declaration- // or any time an integer literal initializer is encountered.- function parseEnumMember(): EnumMember {- const pos = getNodePos();- const hasJSDoc = hasPrecedingJSDocComment();- const name = parsePropertyName();- const initializer = allowInAnd(parseInitializer);- return withJSDoc(finishNode(factory.createEnumMember(name, initializer), pos), hasJSDoc);- }-- function parseEnumDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): EnumDeclaration {- parseExpected(SyntaxKind.EnumKeyword);- const name = parseIdentifier();- let members;- if (parseExpected(SyntaxKind.OpenBraceToken)) {- members = doOutsideOfYieldAndAwaitContext(() => parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember));- parseExpected(SyntaxKind.CloseBraceToken);- }- else {- members = createMissingList<EnumMember>();- }- const node = factory.createEnumDeclaration(modifiers, name, members);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseModuleBlock(): ModuleBlock {- const pos = getNodePos();- let statements;- if (parseExpected(SyntaxKind.OpenBraceToken)) {- statements = parseList(ParsingContext.BlockStatements, parseStatement);- parseExpected(SyntaxKind.CloseBraceToken);- }- else {- statements = createMissingList<Statement>();- }- return finishNode(factory.createModuleBlock(statements), pos);- }-- function parseModuleOrNamespaceDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined, flags: NodeFlags): ModuleDeclaration {- // If we are parsing a dotted namespace name, we want to- // propagate the 'Namespace' flag across the names if set.- const namespaceFlag = flags & NodeFlags.Namespace;- const name = flags & NodeFlags.NestedNamespace ? parseIdentifierName() : parseIdentifier();- const body = parseOptional(SyntaxKind.DotToken)- ? parseModuleOrNamespaceDeclaration(getNodePos(), /*hasJSDoc*/ false, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag) as NamespaceDeclaration- : parseModuleBlock();- const node = factory.createModuleDeclaration(modifiers, name, body, flags);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseAmbientExternalModuleDeclaration(pos: number, hasJSDoc: boolean, modifiersIn: NodeArray<ModifierLike> | undefined): ModuleDeclaration {- let flags: NodeFlags = 0;- let name;- if (token() === SyntaxKind.GlobalKeyword) {- // parse 'global' as name of global scope augmentation- name = parseIdentifier();- flags |= NodeFlags.GlobalAugmentation;- }- else {- name = parseLiteralNode() as StringLiteral;- name.text = internIdentifier(name.text);- }- let body: ModuleBlock | undefined;- if (token() === SyntaxKind.OpenBraceToken) {- body = parseModuleBlock();- }- else {- parseSemicolon();- }- const node = factory.createModuleDeclaration(modifiersIn, name, body, flags);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseModuleDeclaration(pos: number, hasJSDoc: boolean, modifiersIn: NodeArray<ModifierLike> | undefined): ModuleDeclaration {- let flags: NodeFlags = 0;- if (token() === SyntaxKind.GlobalKeyword) {- // global augmentation- return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, modifiersIn);- }- else if (parseOptional(SyntaxKind.NamespaceKeyword)) {- flags |= NodeFlags.Namespace;- }- else {- parseExpected(SyntaxKind.ModuleKeyword);- if (token() === SyntaxKind.StringLiteral) {- return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, modifiersIn);- }- }- return parseModuleOrNamespaceDeclaration(pos, hasJSDoc, modifiersIn, flags);- }-- function isExternalModuleReference() {- return token() === SyntaxKind.RequireKeyword &&- lookAhead(nextTokenIsOpenParen);- }-- function nextTokenIsOpenParen() {- return nextToken() === SyntaxKind.OpenParenToken;- }-- function nextTokenIsOpenBrace() {- return nextToken() === SyntaxKind.OpenBraceToken;- }-- function nextTokenIsSlash() {- return nextToken() === SyntaxKind.SlashToken;- }-- function parseNamespaceExportDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): NamespaceExportDeclaration {- parseExpected(SyntaxKind.AsKeyword);- parseExpected(SyntaxKind.NamespaceKeyword);- const name = parseIdentifier();- parseSemicolon();- const node = factory.createNamespaceExportDeclaration(name);- // NamespaceExportDeclaration nodes cannot have decorators or modifiers, so we attach them here so we can report them in the grammar checker- (node as Mutable<NamespaceExportDeclaration>).modifiers = modifiers;- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseImportDeclarationOrImportEqualsDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): ImportEqualsDeclaration | ImportDeclaration {- parseExpected(SyntaxKind.ImportKeyword);-- const afterImportPos = scanner.getTokenFullStart();-- // We don't parse the identifier here in await context, instead we will report a grammar error in the checker.- let identifier: Identifier | undefined;- if (isIdentifier()) {- identifier = parseIdentifier();- }-- let isTypeOnly = false;- if (- identifier?.escapedText === "type" &&- (token() !== SyntaxKind.FromKeyword || isIdentifier() && lookAhead(nextTokenIsFromKeywordOrEqualsToken)) &&- (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration())- ) {- isTypeOnly = true;- identifier = isIdentifier() ? parseIdentifier() : undefined;- }-- if (identifier && !tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration()) {- return parseImportEqualsDeclaration(pos, hasJSDoc, modifiers, identifier, isTypeOnly);- }-- const importClause = tryParseImportClause(identifier, afterImportPos, isTypeOnly);- const moduleSpecifier = parseModuleSpecifier();- const attributes = tryParseImportAttributes();-- parseSemicolon();- const node = factory.createImportDeclaration(modifiers, importClause, moduleSpecifier, attributes);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function tryParseImportClause(identifier: Identifier | undefined, pos: number, isTypeOnly: boolean, skipJsDocLeadingAsterisks = false) {- // ImportDeclaration:- // import ImportClause from ModuleSpecifier ;- // import ModuleSpecifier;- let importClause: ImportClause | undefined;- if (- identifier || // import id- token() === SyntaxKind.AsteriskToken || // import *- token() === SyntaxKind.OpenBraceToken // import {- ) {- importClause = parseImportClause(identifier, pos, isTypeOnly, skipJsDocLeadingAsterisks);- parseExpected(SyntaxKind.FromKeyword);- }- return importClause;- }-- function tryParseImportAttributes() {- const currentToken = token();- if ((currentToken === SyntaxKind.WithKeyword || currentToken === SyntaxKind.AssertKeyword) && !scanner.hasPrecedingLineBreak()) {- return parseImportAttributes(currentToken);- }- }-- function parseImportAttribute() {- const pos = getNodePos();- const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral;- parseExpected(SyntaxKind.ColonToken);- const value = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);- return finishNode(factory.createImportAttribute(name, value), pos);- }-- function parseImportAttributes(token: SyntaxKind.AssertKeyword | SyntaxKind.WithKeyword, skipKeyword?: true) {- const pos = getNodePos();- if (!skipKeyword) {- parseExpected(token);- }- const openBracePosition = scanner.getTokenStart();- if (parseExpected(SyntaxKind.OpenBraceToken)) {- const multiLine = scanner.hasPrecedingLineBreak();- const elements = parseDelimitedList(ParsingContext.ImportAttributes, parseImportAttribute, /*considerSemicolonAsDelimiter*/ true);- if (!parseExpected(SyntaxKind.CloseBraceToken)) {- const lastError = lastOrUndefined(parseDiagnostics);- if (lastError && lastError.code === Diagnostics._0_expected.code) {- addRelatedInfo(- lastError,- createDetachedDiagnostic(fileName, sourceText, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}"),- );- }- }- return finishNode(factory.createImportAttributes(elements, multiLine, token), pos);- }- else {- const elements = createNodeArray([], getNodePos(), /*end*/ undefined, /*hasTrailingComma*/ false);- return finishNode(factory.createImportAttributes(elements, /*multiLine*/ false, token), pos);- }- }-- function tokenAfterImportDefinitelyProducesImportDeclaration() {- return token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.OpenBraceToken;- }-- function tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() {- // In `import id ___`, the current token decides whether to produce- // an ImportDeclaration or ImportEqualsDeclaration.- return token() === SyntaxKind.CommaToken || token() === SyntaxKind.FromKeyword;- }-- function parseImportEqualsDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined, identifier: Identifier, isTypeOnly: boolean): ImportEqualsDeclaration {- parseExpected(SyntaxKind.EqualsToken);- const moduleReference = parseModuleReference();- parseSemicolon();- const node = factory.createImportEqualsDeclaration(modifiers, isTypeOnly, identifier, moduleReference);- const finished = withJSDoc(finishNode(node, pos), hasJSDoc);- return finished;- }-- function parseImportClause(identifier: Identifier | undefined, pos: number, isTypeOnly: boolean, skipJsDocLeadingAsterisks: boolean) {- // ImportClause:- // ImportedDefaultBinding- // NameSpaceImport- // NamedImports- // ImportedDefaultBinding, NameSpaceImport- // ImportedDefaultBinding, NamedImports-- // If there was no default import or if there is comma token after default import- // parse namespace or named imports- let namedBindings: NamespaceImport | NamedImports | undefined;- if (- !identifier ||- parseOptional(SyntaxKind.CommaToken)- ) {- if (skipJsDocLeadingAsterisks) scanner.setSkipJsDocLeadingAsterisks(true);- namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports);- if (skipJsDocLeadingAsterisks) scanner.setSkipJsDocLeadingAsterisks(false);- }-- return finishNode(factory.createImportClause(isTypeOnly, identifier, namedBindings), pos);- }-- function parseModuleReference() {- return isExternalModuleReference()- ? parseExternalModuleReference()- : parseEntityName(/*allowReservedWords*/ false);- }-- function parseExternalModuleReference() {- const pos = getNodePos();- parseExpected(SyntaxKind.RequireKeyword);- parseExpected(SyntaxKind.OpenParenToken);- const expression = parseModuleSpecifier();- parseExpected(SyntaxKind.CloseParenToken);- return finishNode(factory.createExternalModuleReference(expression), pos);- }-- function parseModuleSpecifier(): Expression {- if (token() === SyntaxKind.StringLiteral) {- const result = parseLiteralNode();- result.text = internIdentifier(result.text);- return result;- }- else {- // We allow arbitrary expressions here, even though the grammar only allows string- // literals. We check to ensure that it is only a string literal later in the grammar- // check pass.- return parseExpression();- }- }-- function parseNamespaceImport(): NamespaceImport {- // NameSpaceImport:- // * as ImportedBinding- const pos = getNodePos();- parseExpected(SyntaxKind.AsteriskToken);- parseExpected(SyntaxKind.AsKeyword);- const name = parseIdentifier();- return finishNode(factory.createNamespaceImport(name), pos);- }-- function canParseModuleExportName(): boolean {- return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.StringLiteral;- }-- function parseModuleExportName(parseName: () => Identifier): ModuleExportName {- return token() === SyntaxKind.StringLiteral ? parseLiteralNode() as StringLiteral : parseName();- }-- function parseNamedImportsOrExports(kind: SyntaxKind.NamedImports): NamedImports;- function parseNamedImportsOrExports(kind: SyntaxKind.NamedExports): NamedExports;- function parseNamedImportsOrExports(kind: SyntaxKind): NamedImportsOrExports {- const pos = getNodePos();-- // NamedImports:- // { }- // { ImportsList }- // { ImportsList, }-- // ImportsList:- // ImportSpecifier- // ImportsList, ImportSpecifier- const node = kind === SyntaxKind.NamedImports- ? factory.createNamedImports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseImportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken))- : factory.createNamedExports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseExportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken));- return finishNode(node, pos);- }-- function parseExportSpecifier() {- const hasJSDoc = hasPrecedingJSDocComment();- return withJSDoc(parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier) as ExportSpecifier, hasJSDoc);- }-- function parseImportSpecifier() {- return parseImportOrExportSpecifier(SyntaxKind.ImportSpecifier) as ImportSpecifier;- }-- function parseImportOrExportSpecifier(kind: SyntaxKind): ImportOrExportSpecifier {- const pos = getNodePos();- // ImportSpecifier:- // BindingIdentifier- // ModuleExportName as BindingIdentifier- // ExportSpecifier:- // ModuleExportName- // ModuleExportName as ModuleExportName- let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();- let checkIdentifierStart = scanner.getTokenStart();- let checkIdentifierEnd = scanner.getTokenEnd();- let isTypeOnly = false;- let propertyName: ModuleExportName | undefined;- let canParseAsKeyword = true;- let name = parseModuleExportName(parseIdentifierName);- if (name.kind === SyntaxKind.Identifier && name.escapedText === "type") {- // If the first token of an import specifier is 'type', there are a lot of possibilities,- // especially if we see 'as' afterwards:- //- // import { type } from "mod"; - isTypeOnly: false, name: type- // import { type as } from "mod"; - isTypeOnly: true, name: as- // import { type as as } from "mod"; - isTypeOnly: false, name: as, propertyName: type- // import { type as as as } from "mod"; - isTypeOnly: true, name: as, propertyName: as- if (token() === SyntaxKind.AsKeyword) {- // { type as ...? }- const firstAs = parseIdentifierName();- if (token() === SyntaxKind.AsKeyword) {- // { type as as ...? }- const secondAs = parseIdentifierName();- if (canParseModuleExportName()) {- // { type as as something }- // { type as as "something" }- isTypeOnly = true;- propertyName = firstAs;- name = parseModuleExportName(parseNameWithKeywordCheck);- canParseAsKeyword = false;- }- else {- // { type as as }- propertyName = name;- name = secondAs;- canParseAsKeyword = false;- }- }- else if (canParseModuleExportName()) {- // { type as something }- // { type as "something" }- propertyName = name;- canParseAsKeyword = false;- name = parseModuleExportName(parseNameWithKeywordCheck);- }- else {- // { type as }- isTypeOnly = true;- name = firstAs;- }- }- else if (canParseModuleExportName()) {- // { type something ...? }- // { type "something" ...? }- isTypeOnly = true;- name = parseModuleExportName(parseNameWithKeywordCheck);- }- }-- if (canParseAsKeyword && token() === SyntaxKind.AsKeyword) {- propertyName = name;- parseExpected(SyntaxKind.AsKeyword);- name = parseModuleExportName(parseNameWithKeywordCheck);- }- if (kind === SyntaxKind.ImportSpecifier) {- if (name.kind !== SyntaxKind.Identifier) {- // ImportSpecifier casts "name" to Identifier below, so make sure it's an identifier- parseErrorAt(skipTrivia(sourceText, name.pos), name.end, Diagnostics.Identifier_expected);- name = setTextRangePosEnd(createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false), name.pos, name.pos);- }- else if (checkIdentifierIsKeyword) {- parseErrorAt(checkIdentifierStart, checkIdentifierEnd, Diagnostics.Identifier_expected);- }- }- const node = kind === SyntaxKind.ImportSpecifier- ? factory.createImportSpecifier(isTypeOnly, propertyName, name as Identifier)- : factory.createExportSpecifier(isTypeOnly, propertyName, name);- return finishNode(node, pos);-- function parseNameWithKeywordCheck() {- checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();- checkIdentifierStart = scanner.getTokenStart();- checkIdentifierEnd = scanner.getTokenEnd();- return parseIdentifierName();- }- }-- function parseNamespaceExport(pos: number): NamespaceExport {- return finishNode(factory.createNamespaceExport(parseModuleExportName(parseIdentifierName)), pos);- }-- function parseExportDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): ExportDeclaration {- const savedAwaitContext = inAwaitContext();- setAwaitContext(/*value*/ true);- let exportClause: NamedExportBindings | undefined;- let moduleSpecifier: Expression | undefined;- let attributes: ImportAttributes | undefined;- const isTypeOnly = parseOptional(SyntaxKind.TypeKeyword);- const namespaceExportPos = getNodePos();- if (parseOptional(SyntaxKind.AsteriskToken)) {- if (parseOptional(SyntaxKind.AsKeyword)) {- exportClause = parseNamespaceExport(namespaceExportPos);- }- parseExpected(SyntaxKind.FromKeyword);- moduleSpecifier = parseModuleSpecifier();- }- else {- exportClause = parseNamedImportsOrExports(SyntaxKind.NamedExports);- // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios,- // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`)- // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect.- if (token() === SyntaxKind.FromKeyword || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) {- parseExpected(SyntaxKind.FromKeyword);- moduleSpecifier = parseModuleSpecifier();- }- }- const currentToken = token();- if (moduleSpecifier && (currentToken === SyntaxKind.WithKeyword || currentToken === SyntaxKind.AssertKeyword) && !scanner.hasPrecedingLineBreak()) {- attributes = parseImportAttributes(currentToken);- }- parseSemicolon();- setAwaitContext(savedAwaitContext);- const node = factory.createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, attributes);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- function parseExportAssignment(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): ExportAssignment {- const savedAwaitContext = inAwaitContext();- setAwaitContext(/*value*/ true);- let isExportEquals: boolean | undefined;- if (parseOptional(SyntaxKind.EqualsToken)) {- isExportEquals = true;- }- else {- parseExpected(SyntaxKind.DefaultKeyword);- }- const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);- parseSemicolon();- setAwaitContext(savedAwaitContext);- const node = factory.createExportAssignment(modifiers, isExportEquals, expression);- return withJSDoc(finishNode(node, pos), hasJSDoc);- }-- // dprint-ignore- const enum ParsingContext {- SourceElements, // Elements in source file- BlockStatements, // Statements in block- SwitchClauses, // Clauses in switch statement- SwitchClauseStatements, // Statements in switch clause- TypeMembers, // Members in interface or type literal- ClassMembers, // Members in class declaration- EnumMembers, // Members in enum declaration- HeritageClauseElement, // Elements in a heritage clause- VariableDeclarations, // Variable declarations in variable statement- ObjectBindingElements, // Binding elements in object binding list- ArrayBindingElements, // Binding elements in array binding list- ArgumentExpressions, // Expressions in argument list- ObjectLiteralMembers, // Members in object literal- JsxAttributes, // Attributes in jsx element- JsxChildren, // Things between opening and closing JSX tags- ArrayLiteralMembers, // Members in array literal- Parameters, // Parameters in parameter list- JSDocParameters, // JSDoc parameters in parameter list of JSDoc function type- RestProperties, // Property names in a rest type list- TypeParameters, // Type parameters in type parameter list- TypeArguments, // Type arguments in type argument list- TupleElementTypes, // Element types in tuple element type list- HeritageClauses, // Heritage clauses for a class or interface declaration.- ImportOrExportSpecifiers, // Named import clause's import specifier list,- ImportAttributes, // Import attributes- JSDocComment, // Parsing via JSDocParser- Count, // Number of parsing contexts- }-- const enum Tristate {- False,- True,- Unknown,- }-- export namespace JSDocParser {- export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression; diagnostics: Diagnostic[]; } | undefined {- initializeState("file.js", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS, JSDocParsingMode.ParseAll);- scanner.setText(content, start, length);- currentToken = scanner.scan();- const jsDocTypeExpression = parseJSDocTypeExpression();-- const sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false, [], factoryCreateToken(SyntaxKind.EndOfFileToken), NodeFlags.None, noop);- const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);- if (jsDocDiagnostics) {- sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile);- }-- clearState();-- return jsDocTypeExpression ? { jsDocTypeExpression, diagnostics } : undefined;- }-- // Parses out a JSDoc type expression.- export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression {- const pos = getNodePos();- const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken);- const type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);- if (!mayOmitBraces || hasBrace) {- parseExpectedJSDoc(SyntaxKind.CloseBraceToken);- }-- const result = factory.createJSDocTypeExpression(type);- fixupParentReferences(result);- return finishNode(result, pos);- }-- export function parseJSDocNameReference(): JSDocNameReference {- const pos = getNodePos();- const hasBrace = parseOptional(SyntaxKind.OpenBraceToken);- const p2 = getNodePos();- let entityName: EntityName | JSDocMemberName = parseEntityName(/*allowReservedWords*/ false);- while (token() === SyntaxKind.PrivateIdentifier) {- reScanHashToken(); // rescan #id as # id- nextTokenJSDoc(); // then skip the #- entityName = finishNode(factory.createJSDocMemberName(entityName, parseIdentifier()), p2);- }- if (hasBrace) {- parseExpectedJSDoc(SyntaxKind.CloseBraceToken);- }-- const result = factory.createJSDocNameReference(entityName);- fixupParentReferences(result);- return finishNode(result, pos);- }-- export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc; diagnostics: Diagnostic[]; } | undefined {- initializeState("", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS, JSDocParsingMode.ParseAll);- const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));-- const sourceFile = { languageVariant: LanguageVariant.Standard, text: content } as SourceFile;- const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);- clearState();-- return jsDoc ? { jsDoc, diagnostics } : undefined;- }-- export function parseJSDocComment(parent: HasJSDoc, start: number, length: number): JSDoc | undefined {- const saveToken = currentToken;- const saveParseDiagnosticsLength = parseDiagnostics.length;- const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;-- const comment = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));- setParent(comment, parent);-- if (contextFlags & NodeFlags.JavaScriptFile) {- if (!jsDocDiagnostics) {- jsDocDiagnostics = [];- }- addRange(jsDocDiagnostics, parseDiagnostics, saveParseDiagnosticsLength);- }- currentToken = saveToken;- parseDiagnostics.length = saveParseDiagnosticsLength;- parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode;- return comment;- }-- const enum JSDocState {- BeginningOfLine,- SawAsterisk,- SavingComments,- SavingBackticks, // NOTE: Only used when parsing tag comments- }-- const enum PropertyLikeParse {- Property = 1 << 0,- Parameter = 1 << 1,- CallbackParameter = 1 << 2,- }-- function parseJSDocCommentWorker(start = 0, length: number | undefined): JSDoc | undefined {- const content = sourceText;- const end = length === undefined ? content.length : start + length;- length = end - start;-- Debug.assert(start >= 0);- Debug.assert(start <= end);- Debug.assert(end <= content.length);-- // Check for /** (JSDoc opening part)- if (!isJSDocLikeText(content, start)) {- return undefined;- }-- let tags: JSDocTag[];- let tagsPos: number;- let tagsEnd: number;- let linkEnd: number;- let commentsPos: number | undefined;- let comments: string[] = [];- const parts: JSDocComment[] = [];-- const saveParsingContext = parsingContext;- parsingContext |= 1 << ParsingContext.JSDocComment;-- // + 3 for leading /**, - 5 in total for /** */- const result = scanner.scanRange(start + 3, length - 5, doJSDocScan);- parsingContext = saveParsingContext;- return result;-- function doJSDocScan() {- // Initially we can parse out a tag. We also have seen a starting asterisk.- // This is so that /** * @type */ doesn't parse.- let state = JSDocState.SawAsterisk;- let margin: number | undefined;- // + 4 for leading '/** '- // + 1 because the last index of \n is always one index before the first character in the line and coincidentally, if there is no \n before start, it is -1, which is also one index before the first character- let indent = start - (content.lastIndexOf("\n", start) + 1) + 4;- function pushComment(text: string) {- if (!margin) {- margin = indent;- }- comments.push(text);- indent += text.length;- }-- nextTokenJSDoc();- while (parseOptionalJsdoc(SyntaxKind.WhitespaceTrivia));- if (parseOptionalJsdoc(SyntaxKind.NewLineTrivia)) {- state = JSDocState.BeginningOfLine;- indent = 0;- }- loop:- while (true) {- switch (token()) {- case SyntaxKind.AtToken:- removeTrailingWhitespace(comments);- if (!commentsPos) commentsPos = getNodePos();- addTag(parseTag(indent));- // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag.- // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning- // for malformed examples like `/** @param {string} x @returns {number} the length */`- state = JSDocState.BeginningOfLine;- margin = undefined;- break;- case SyntaxKind.NewLineTrivia:- comments.push(scanner.getTokenText());- state = JSDocState.BeginningOfLine;- indent = 0;- break;- case SyntaxKind.AsteriskToken:- const asterisk = scanner.getTokenText();- if (state === JSDocState.SawAsterisk) {- // If we've already seen an asterisk, then we can no longer parse a tag on this line- state = JSDocState.SavingComments;- pushComment(asterisk);- }- else {- Debug.assert(state === JSDocState.BeginningOfLine);- // Ignore the first asterisk on a line- state = JSDocState.SawAsterisk;- indent += asterisk.length;- }- break;- case SyntaxKind.WhitespaceTrivia:- Debug.assert(state !== JSDocState.SavingComments, "whitespace shouldn't come from the scanner while saving top-level comment text");- // only collect whitespace if we're already saving comments or have just crossed the comment indent margin- const whitespace = scanner.getTokenText();- if (margin !== undefined && indent + whitespace.length > margin) {- comments.push(whitespace.slice(margin - indent));- }- indent += whitespace.length;- break;- case SyntaxKind.EndOfFileToken:- break loop;- case SyntaxKind.JSDocCommentTextToken:- state = JSDocState.SavingComments;- pushComment(scanner.getTokenValue());- break;- case SyntaxKind.OpenBraceToken:- state = JSDocState.SavingComments;- const commentEnd = scanner.getTokenFullStart();- const linkStart = scanner.getTokenEnd() - 1;- const link = parseJSDocLink(linkStart);- if (link) {- if (!linkEnd) {- removeLeadingNewlines(comments);- }- parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentEnd));- parts.push(link);- comments = [];- linkEnd = scanner.getTokenEnd();- break;- }- // fallthrough if it's not a {@link sequence- default:- // Anything else is doc comment text. We just save it. Because it- // wasn't a tag, we can no longer parse a tag on this line until we hit the next- // line break.- state = JSDocState.SavingComments;- pushComment(scanner.getTokenText());- break;- }- if (state === JSDocState.SavingComments) {- nextJSDocCommentTextToken(/*inBackticks*/ false);- }- else {- nextTokenJSDoc();- }- }- const trimmedComments = comments.join("").trimEnd();- if (parts.length && trimmedComments.length) {- parts.push(finishNode(factory.createJSDocText(trimmedComments), linkEnd ?? start, commentsPos));- }- if (parts.length && tags) Debug.assertIsDefined(commentsPos, "having parsed tags implies that the end of the comment span should be set");- const tagsArray = tags && createNodeArray(tags, tagsPos, tagsEnd);- return finishNode(factory.createJSDocComment(parts.length ? createNodeArray(parts, start, commentsPos) : trimmedComments.length ? trimmedComments : undefined, tagsArray), start, end);- }-- function removeLeadingNewlines(comments: string[]) {- while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) {- comments.shift();- }- }-- function removeTrailingWhitespace(comments: string[]) {- while (comments.length) {- const trimmed = comments[comments.length - 1].trimEnd();- if (trimmed === "") {- comments.pop();- }- else if (trimmed.length < comments[comments.length - 1].length) {- comments[comments.length - 1] = trimmed;- break;- }- else {- break;- }- }- }-- function isNextNonwhitespaceTokenEndOfFile(): boolean {- // We must use infinite lookahead, as there could be any number of newlines :(- while (true) {- nextTokenJSDoc();- if (token() === SyntaxKind.EndOfFileToken) {- return true;- }- if (!(token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia)) {- return false;- }- }- }-- function skipWhitespace(): void {- if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {- if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {- return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range- }- }- while (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {- nextTokenJSDoc();- }- }-- function skipWhitespaceOrAsterisk(): string {- if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {- if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {- return ""; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range- }- }-- let precedingLineBreak = scanner.hasPrecedingLineBreak();- let seenLineBreak = false;- let indentText = "";- while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {- indentText += scanner.getTokenText();- if (token() === SyntaxKind.NewLineTrivia) {- precedingLineBreak = true;- seenLineBreak = true;- indentText = "";- }- else if (token() === SyntaxKind.AsteriskToken) {- precedingLineBreak = false;- }- nextTokenJSDoc();- }- return seenLineBreak ? indentText : "";- }-- function parseTag(margin: number) {- Debug.assert(token() === SyntaxKind.AtToken);- const start = scanner.getTokenStart();- nextTokenJSDoc();-- const tagName = parseJSDocIdentifierName(/*message*/ undefined);- const indentText = skipWhitespaceOrAsterisk();-- let tag: JSDocTag | undefined;- switch (tagName.escapedText) {- case "author":- tag = parseAuthorTag(start, tagName, margin, indentText);- break;- case "implements":- tag = parseImplementsTag(start, tagName, margin, indentText);- break;- case "augments":- case "extends":- tag = parseAugmentsTag(start, tagName, margin, indentText);- break;- case "class":- case "constructor":- tag = parseSimpleTag(start, factory.createJSDocClassTag, tagName, margin, indentText);- break;- case "public":- tag = parseSimpleTag(start, factory.createJSDocPublicTag, tagName, margin, indentText);- break;- case "private":- tag = parseSimpleTag(start, factory.createJSDocPrivateTag, tagName, margin, indentText);- break;- case "protected":- tag = parseSimpleTag(start, factory.createJSDocProtectedTag, tagName, margin, indentText);- break;- case "readonly":- tag = parseSimpleTag(start, factory.createJSDocReadonlyTag, tagName, margin, indentText);- break;- case "override":- tag = parseSimpleTag(start, factory.createJSDocOverrideTag, tagName, margin, indentText);- break;- case "deprecated":- hasDeprecatedTag = true;- tag = parseSimpleTag(start, factory.createJSDocDeprecatedTag, tagName, margin, indentText);- break;- case "this":- tag = parseThisTag(start, tagName, margin, indentText);- break;- case "enum":- tag = parseEnumTag(start, tagName, margin, indentText);- break;- case "arg":- case "argument":- case "param":- return parseParameterOrPropertyTag(start, tagName, PropertyLikeParse.Parameter, margin);- case "return":- case "returns":- tag = parseReturnTag(start, tagName, margin, indentText);- break;- case "template":- tag = parseTemplateTag(start, tagName, margin, indentText);- break;- case "type":- tag = parseTypeTag(start, tagName, margin, indentText);- break;- case "typedef":- tag = parseTypedefTag(start, tagName, margin, indentText);- break;- case "callback":- tag = parseCallbackTag(start, tagName, margin, indentText);- break;- case "overload":- tag = parseOverloadTag(start, tagName, margin, indentText);- break;- case "satisfies":- tag = parseSatisfiesTag(start, tagName, margin, indentText);- break;- case "see":- tag = parseSeeTag(start, tagName, margin, indentText);- break;- case "exception":- case "throws":- tag = parseThrowsTag(start, tagName, margin, indentText);- break;- case "import":- tag = parseImportTag(start, tagName, margin, indentText);- break;- default:- tag = parseUnknownTag(start, tagName, margin, indentText);- break;- }- return tag;- }-- function parseTrailingTagComments(pos: number, end: number, margin: number, indentText: string) {- // some tags, like typedef and callback, have already parsed their comments earlier- if (!indentText) {- margin += end - pos;- }- return parseTagComments(margin, indentText.slice(margin));- }-- function parseTagComments(indent: number, initialMargin?: string): string | NodeArray<JSDocComment> | undefined {- const commentsPos = getNodePos();- let comments: string[] = [];- const parts: JSDocComment[] = [];- let linkEnd;- let state = JSDocState.BeginningOfLine;- let margin: number | undefined;- function pushComment(text: string) {- if (!margin) {- margin = indent;- }- comments.push(text);- indent += text.length;- }- if (initialMargin !== undefined) {- // jump straight to saving comments if there is some initial indentation- if (initialMargin !== "") {- pushComment(initialMargin);- }- state = JSDocState.SawAsterisk;- }- let tok = token() as JSDocSyntaxKind | SyntaxKind.JSDocCommentTextToken;- loop:- while (true) {- switch (tok) {- case SyntaxKind.NewLineTrivia:- state = JSDocState.BeginningOfLine;- // don't use pushComment here because we want to keep the margin unchanged- comments.push(scanner.getTokenText());- indent = 0;- break;- case SyntaxKind.AtToken:- scanner.resetTokenState(scanner.getTokenEnd() - 1);- break loop;- case SyntaxKind.EndOfFileToken:- // Done- break loop;- case SyntaxKind.WhitespaceTrivia:- Debug.assert(state !== JSDocState.SavingComments && state !== JSDocState.SavingBackticks, "whitespace shouldn't come from the scanner while saving comment text");- const whitespace = scanner.getTokenText();- // if the whitespace crosses the margin, take only the whitespace that passes the margin- if (margin !== undefined && indent + whitespace.length > margin) {- comments.push(whitespace.slice(margin - indent));- state = JSDocState.SavingComments;- }- indent += whitespace.length;- break;- case SyntaxKind.OpenBraceToken:- state = JSDocState.SavingComments;- const commentEnd = scanner.getTokenFullStart();- const linkStart = scanner.getTokenEnd() - 1;- const link = parseJSDocLink(linkStart);- if (link) {- parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos, commentEnd));- parts.push(link);- comments = [];- linkEnd = scanner.getTokenEnd();- }- else {- pushComment(scanner.getTokenText());- }- break;- case SyntaxKind.BacktickToken:- if (state === JSDocState.SavingBackticks) {- state = JSDocState.SavingComments;- }- else {- state = JSDocState.SavingBackticks;- }- pushComment(scanner.getTokenText());- break;- case SyntaxKind.JSDocCommentTextToken:- if (state !== JSDocState.SavingBackticks) {- state = JSDocState.SavingComments; // leading identifiers start recording as well- }- pushComment(scanner.getTokenValue());- break;- case SyntaxKind.AsteriskToken:- if (state === JSDocState.BeginningOfLine) {- // leading asterisks start recording on the *next* (non-whitespace) token- state = JSDocState.SawAsterisk;- indent += 1;- break;- }- // record the * as a comment- // falls through- default:- if (state !== JSDocState.SavingBackticks) {- state = JSDocState.SavingComments; // leading identifiers start recording as well- }- pushComment(scanner.getTokenText());- break;- }- if (state === JSDocState.SavingComments || state === JSDocState.SavingBackticks) {- tok = nextJSDocCommentTextToken(state === JSDocState.SavingBackticks);- }- else {- tok = nextTokenJSDoc();- }- }-- removeLeadingNewlines(comments);- const trimmedComments = comments.join("").trimEnd();- if (parts.length) {- if (trimmedComments.length) {- parts.push(finishNode(factory.createJSDocText(trimmedComments), linkEnd ?? commentsPos));- }- return createNodeArray(parts, commentsPos, scanner.getTokenEnd());- }- else if (trimmedComments.length) {- return trimmedComments;- }- }-- function parseJSDocLink(start: number) {- const linkType = tryParse(parseJSDocLinkPrefix);- if (!linkType) {- return undefined;- }- nextTokenJSDoc(); // start at token after link, then skip any whitespace- skipWhitespace();- const name = parseJSDocLinkName();- const text = [];- while (token() !== SyntaxKind.CloseBraceToken && token() !== SyntaxKind.NewLineTrivia && token() !== SyntaxKind.EndOfFileToken) {- text.push(scanner.getTokenText());- nextTokenJSDoc();- }- const create = linkType === "link" ? factory.createJSDocLink- : linkType === "linkcode" ? factory.createJSDocLinkCode- : factory.createJSDocLinkPlain;- return finishNode(create(name, text.join("")), start, scanner.getTokenEnd());- }-- function parseJSDocLinkName() {- if (tokenIsIdentifierOrKeyword(token())) {- const pos = getNodePos();-- let name: EntityName | JSDocMemberName = parseIdentifierName();- while (parseOptional(SyntaxKind.DotToken)) {- name = finishNode(factory.createQualifiedName(name, token() === SyntaxKind.PrivateIdentifier ? createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false) : parseIdentifierName()), pos);- }- while (token() === SyntaxKind.PrivateIdentifier) {- reScanHashToken();- nextTokenJSDoc();- name = finishNode(factory.createJSDocMemberName(name, parseIdentifier()), pos);- }- return name;- }- return undefined;- }-- function parseJSDocLinkPrefix() {- skipWhitespaceOrAsterisk();- if (- token() === SyntaxKind.OpenBraceToken- && nextTokenJSDoc() === SyntaxKind.AtToken- && tokenIsIdentifierOrKeyword(nextTokenJSDoc())- ) {- const kind = scanner.getTokenValue();- if (isJSDocLinkTag(kind)) return kind;- }- }-- function isJSDocLinkTag(kind: string) {- return kind === "link" || kind === "linkcode" || kind === "linkplain";- }-- function parseUnknownTag(start: number, tagName: Identifier, indent: number, indentText: string) {- return finishNode(factory.createJSDocUnknownTag(tagName, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start);- }-- function addTag(tag: JSDocTag | undefined): void {- if (!tag) {- return;- }- if (!tags) {- tags = [tag];- tagsPos = tag.pos;- }- else {- tags.push(tag);- }- tagsEnd = tag.end;- }-- function tryParseTypeExpression(): JSDocTypeExpression | undefined {- skipWhitespaceOrAsterisk();- return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;- }-- function parseBracketNameInPropertyAndParamTag(): { name: EntityName; isBracketed: boolean; } {- // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar'- const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);- if (isBracketed) {- skipWhitespace();- }- // a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild- const isBackquoted = parseOptionalJsdoc(SyntaxKind.BacktickToken);- const name = parseJSDocEntityName();- if (isBackquoted) {- parseExpectedTokenJSDoc(SyntaxKind.BacktickToken);- }- if (isBracketed) {- skipWhitespace();- // May have an optional default, e.g. '[foo = 42]'- if (parseOptionalToken(SyntaxKind.EqualsToken)) {- parseExpression();- }-- parseExpected(SyntaxKind.CloseBracketToken);- }-- return { name, isBracketed };- }-- function isObjectOrObjectArrayTypeReference(node: TypeNode): boolean {- switch (node.kind) {- case SyntaxKind.ObjectKeyword:- return true;- case SyntaxKind.ArrayType:- return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType);- default:- return isTypeReferenceNode(node) && isIdentifierNode(node.typeName) && node.typeName.escapedText === "Object" && !node.typeArguments;- }- }-- function parseParameterOrPropertyTag(start: number, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag {- let typeExpression = tryParseTypeExpression();- let isNameFirst = !typeExpression;- skipWhitespaceOrAsterisk();-- const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();- const indentText = skipWhitespaceOrAsterisk();-- if (isNameFirst && !lookAhead(parseJSDocLinkPrefix)) {- typeExpression = tryParseTypeExpression();- }-- const comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);-- const nestedTypeLiteral = parseNestedTypeLiteral(typeExpression, name, target, indent);- if (nestedTypeLiteral) {- typeExpression = nestedTypeLiteral;- isNameFirst = true;- }- const result = target === PropertyLikeParse.Property- ? factory.createJSDocPropertyTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment)- : factory.createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment);- return finishNode(result, start);- }-- function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) {- if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) {- const pos = getNodePos();- let child: JSDocPropertyLikeTag | JSDocTypeTag | JSDocTemplateTag | JSDocThisTag | false;- let children: JSDocPropertyLikeTag[] | undefined;- while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) {- if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) {- children = append(children, child);- }- else if (child.kind === SyntaxKind.JSDocTemplateTag) {- parseErrorAtRange(child.tagName, Diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag);- }- }- if (children) {- const literal = finishNode(factory.createJSDocTypeLiteral(children, typeExpression.type.kind === SyntaxKind.ArrayType), pos);- return finishNode(factory.createJSDocTypeExpression(literal), pos);- }- }- }-- function parseReturnTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocReturnTag {- if (some(tags, isJSDocReturnTag)) {- parseErrorAt(tagName.pos, scanner.getTokenStart(), Diagnostics._0_tag_already_specified, unescapeLeadingUnderscores(tagName.escapedText));- }-- const typeExpression = tryParseTypeExpression();- return finishNode(factory.createJSDocReturnTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start);- }-- function parseTypeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocTypeTag {- if (some(tags, isJSDocTypeTag)) {- parseErrorAt(tagName.pos, scanner.getTokenStart(), Diagnostics._0_tag_already_specified, unescapeLeadingUnderscores(tagName.escapedText));- }-- const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);- const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined;- return finishNode(factory.createJSDocTypeTag(tagName, typeExpression, comments), start);- }-- function parseSeeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocSeeTag {- const isMarkdownOrJSDocLink = token() === SyntaxKind.OpenBracketToken- || lookAhead(() => nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) && isJSDocLinkTag(scanner.getTokenValue()));- const nameExpression = isMarkdownOrJSDocLink ? undefined : parseJSDocNameReference();- const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined;- return finishNode(factory.createJSDocSeeTag(tagName, nameExpression, comments), start);- }-- function parseThrowsTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocThrowsTag {- const typeExpression = tryParseTypeExpression();- const comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);- return finishNode(factory.createJSDocThrowsTag(tagName, typeExpression, comment), start);- }-- function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag {- const commentStart = getNodePos();- const textOnly = parseAuthorNameAndEmail();- let commentEnd = scanner.getTokenFullStart();- const comments = parseTrailingTagComments(start, commentEnd, indent, indentText);- if (!comments) {- commentEnd = scanner.getTokenFullStart();- }- const allParts = typeof comments !== "string"- ? createNodeArray(concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as JSDocComment[], commentStart) // cast away readonly- : textOnly.text + comments;- return finishNode(factory.createJSDocAuthorTag(tagName, allParts), start);- }-- function parseAuthorNameAndEmail(): JSDocText {- const comments: string[] = [];- let inEmail = false;- let token = scanner.getToken();- while (token !== SyntaxKind.EndOfFileToken && token !== SyntaxKind.NewLineTrivia) {- if (token === SyntaxKind.LessThanToken) {- inEmail = true;- }- else if (token === SyntaxKind.AtToken && !inEmail) {- break;- }- else if (token === SyntaxKind.GreaterThanToken && inEmail) {- comments.push(scanner.getTokenText());- scanner.resetTokenState(scanner.getTokenEnd());- break;- }- comments.push(scanner.getTokenText());- token = nextTokenJSDoc();- }-- return factory.createJSDocText(comments.join(""));- }-- function parseImplementsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImplementsTag {- const className = parseExpressionWithTypeArgumentsForAugments();- return finishNode(factory.createJSDocImplementsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);- }-- function parseAugmentsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocAugmentsTag {- const className = parseExpressionWithTypeArgumentsForAugments();- return finishNode(factory.createJSDocAugmentsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);- }-- function parseSatisfiesTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocSatisfiesTag {- const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ false);- const comments = margin !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), margin, indentText) : undefined;- return finishNode(factory.createJSDocSatisfiesTag(tagName, typeExpression, comments), start);- }-- function parseImportTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImportTag {- const afterImportTagPos = scanner.getTokenFullStart();-- let identifier: Identifier | undefined;- if (isIdentifier()) {- identifier = parseIdentifier();- }-- const importClause = tryParseImportClause(identifier, afterImportTagPos, /*isTypeOnly*/ true, /*skipJsDocLeadingAsterisks*/ true);- const moduleSpecifier = parseModuleSpecifier();- const attributes = tryParseImportAttributes();-- const comments = margin !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), margin, indentText) : undefined;- return finishNode(factory.createJSDocImportTag(tagName, importClause, moduleSpecifier, attributes, comments), start);- }-- function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression; } {- const usedBrace = parseOptional(SyntaxKind.OpenBraceToken);- const pos = getNodePos();- const expression = parsePropertyAccessEntityNameExpression();- scanner.setSkipJsDocLeadingAsterisks(true);- const typeArguments = tryParseTypeArguments();- scanner.setSkipJsDocLeadingAsterisks(false);- const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression; };- const res = finishNode(node, pos);- if (usedBrace) {- parseExpected(SyntaxKind.CloseBraceToken);- }- return res;- }-- function parsePropertyAccessEntityNameExpression() {- const pos = getNodePos();- let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName();- while (parseOptional(SyntaxKind.DotToken)) {- const name = parseJSDocIdentifierName();- node = finishNode(factoryCreatePropertyAccessExpression(node, name), pos) as PropertyAccessEntityNameExpression;- }- return node;- }-- function parseSimpleTag(start: number, createTag: (tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>) => JSDocTag, tagName: Identifier, margin: number, indentText: string): JSDocTag {- return finishNode(createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);- }-- function parseThisTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocThisTag {- const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);- skipWhitespace();- return finishNode(factory.createJSDocThisTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);- }-- function parseEnumTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocEnumTag {- const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);- skipWhitespace();- return finishNode(factory.createJSDocEnumTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);- }-- function parseTypedefTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTypedefTag {- let typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined = tryParseTypeExpression();- skipWhitespaceOrAsterisk();-- const fullName = parseJSDocTypeNameWithNamespace();- skipWhitespace();- let comment = parseTagComments(indent);-- let end: number | undefined;- if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) {- let child: JSDocTypeTag | JSDocPropertyTag | JSDocTemplateTag | false;- let childTypeTag: JSDocTypeTag | undefined;- let jsDocPropertyTags: JSDocPropertyTag[] | undefined;- let hasChildren = false;- while (child = tryParse(() => parseChildPropertyTag(indent))) {- if (child.kind === SyntaxKind.JSDocTemplateTag) {- break;- }- hasChildren = true;- if (child.kind === SyntaxKind.JSDocTypeTag) {- if (childTypeTag) {- const lastError = parseErrorAtCurrentToken(Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags);- if (lastError) {- addRelatedInfo(lastError, createDetachedDiagnostic(fileName, sourceText, 0, 0, Diagnostics.The_tag_was_first_specified_here));- }- break;- }- else {- childTypeTag = child;- }- }- else {- jsDocPropertyTags = append(jsDocPropertyTags, child);- }- }- if (hasChildren) {- const isArrayType = typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType;- const jsdocTypeLiteral = factory.createJSDocTypeLiteral(jsDocPropertyTags, isArrayType);- typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ?- childTypeTag.typeExpression :- finishNode(jsdocTypeLiteral, start);- end = typeExpression.end;- }- }-- // Only include the characters between the name end and the next token if a comment was actually parsed out - otherwise it's just whitespace- end = end || comment !== undefined ?- getNodePos() :- (fullName ?? typeExpression ?? tagName).end;-- if (!comment) {- comment = parseTrailingTagComments(start, end, indent, indentText);- }-- const typedefTag = factory.createJSDocTypedefTag(tagName, typeExpression, fullName, comment);- return finishNode(typedefTag, start, end);- }-- function parseJSDocTypeNameWithNamespace(nested?: boolean) {- const start = scanner.getTokenStart();- if (!tokenIsIdentifierOrKeyword(token())) {- return undefined;- }- const typeNameOrNamespaceName = parseJSDocIdentifierName();- if (parseOptional(SyntaxKind.DotToken)) {- const body = parseJSDocTypeNameWithNamespace(/*nested*/ true);- const jsDocNamespaceNode = factory.createModuleDeclaration(- /*modifiers*/ undefined,- typeNameOrNamespaceName,- body,- nested ? NodeFlags.NestedNamespace : undefined,- ) as JSDocNamespaceDeclaration;- return finishNode(jsDocNamespaceNode, start);- }-- if (nested) {- (typeNameOrNamespaceName as Mutable<Identifier>).flags |= NodeFlags.IdentifierIsInJSDocNamespace;- }- return typeNameOrNamespaceName;- }-- function parseCallbackTagParameters(indent: number) {- const pos = getNodePos();- let child: JSDocParameterTag | JSDocTemplateTag | false;- let parameters;- while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag | JSDocTemplateTag)) {- if (child.kind === SyntaxKind.JSDocTemplateTag) {- parseErrorAtRange(child.tagName, Diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag);- break;- }- parameters = append(parameters, child);- }- return createNodeArray(parameters || [], pos);- }-- function parseJSDocSignature(start: number, indent: number): JSDocSignature {- const parameters = parseCallbackTagParameters(indent);- const returnTag = tryParse(() => {- if (parseOptionalJsdoc(SyntaxKind.AtToken)) {- const tag = parseTag(indent);- if (tag && tag.kind === SyntaxKind.JSDocReturnTag) {- return tag as JSDocReturnTag;- }- }- });- return finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start);- }-- function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag {- const fullName = parseJSDocTypeNameWithNamespace();- skipWhitespace();- let comment = parseTagComments(indent);- const typeExpression = parseJSDocSignature(start, indent);- if (!comment) {- comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);- }- const end = comment !== undefined ? getNodePos() : typeExpression.end;- return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end);- }-- function parseOverloadTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocOverloadTag {- skipWhitespace();- let comment = parseTagComments(indent);- const typeExpression = parseJSDocSignature(start, indent);- if (!comment) {- comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);- }- const end = comment !== undefined ? getNodePos() : typeExpression.end;- return finishNode(factory.createJSDocOverloadTag(tagName, typeExpression, comment), start, end);- }-- function escapedTextsEqual(a: EntityName, b: EntityName): boolean {- while (!isIdentifierNode(a) || !isIdentifierNode(b)) {- if (!isIdentifierNode(a) && !isIdentifierNode(b) && a.right.escapedText === b.right.escapedText) {- a = a.left;- b = b.left;- }- else {- return false;- }- }- return a.escapedText === b.escapedText;- }-- function parseChildPropertyTag(indent: number) {- return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | JSDocTemplateTag | false;- }-- function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | JSDocThisTag | false {- let canParseTag = true;- let seenAsterisk = false;- while (true) {- switch (nextTokenJSDoc()) {- case SyntaxKind.AtToken:- if (canParseTag) {- const child = tryParseChildTag(target, indent);- if (- child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) &&- name && (isIdentifierNode(child.name) || !escapedTextsEqual(name, child.name.left))- ) {- return false;- }- return child;- }- seenAsterisk = false;- break;- case SyntaxKind.NewLineTrivia:- canParseTag = true;- seenAsterisk = false;- break;- case SyntaxKind.AsteriskToken:- if (seenAsterisk) {- canParseTag = false;- }- seenAsterisk = true;- break;- case SyntaxKind.Identifier:- canParseTag = false;- break;- case SyntaxKind.EndOfFileToken:- return false;- }- }- }-- function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | JSDocThisTag | false {- Debug.assert(token() === SyntaxKind.AtToken);- const start = scanner.getTokenFullStart();- nextTokenJSDoc();-- const tagName = parseJSDocIdentifierName();- const indentText = skipWhitespaceOrAsterisk();- let t: PropertyLikeParse;- switch (tagName.escapedText) {- case "type":- return target === PropertyLikeParse.Property && parseTypeTag(start, tagName);- case "prop":- case "property":- t = PropertyLikeParse.Property;- break;- case "arg":- case "argument":- case "param":- t = PropertyLikeParse.Parameter | PropertyLikeParse.CallbackParameter;- break;- case "template":- return parseTemplateTag(start, tagName, indent, indentText);- case "this":- return parseThisTag(start, tagName, indent, indentText);- default:- return false;- }- if (!(target & t)) {- return false;- }- return parseParameterOrPropertyTag(start, tagName, target, indent);- }-- function parseTemplateTagTypeParameter() {- const typeParameterPos = getNodePos();- const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);- if (isBracketed) {- skipWhitespace();- }-- const modifiers = parseModifiers(/*allowDecorators*/ false, /*permitConstAsModifier*/ true);- const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);- let defaultType: TypeNode | undefined;- if (isBracketed) {- skipWhitespace();- parseExpected(SyntaxKind.EqualsToken);- defaultType = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);- parseExpected(SyntaxKind.CloseBracketToken);- }-- if (nodeIsMissing(name)) {- return undefined;- }- return finishNode(factory.createTypeParameterDeclaration(modifiers, name, /*constraint*/ undefined, defaultType), typeParameterPos);- }-- function parseTemplateTagTypeParameters() {- const pos = getNodePos();- const typeParameters = [];- do {- skipWhitespace();- const node = parseTemplateTagTypeParameter();- if (node !== undefined) {- typeParameters.push(node);- }- skipWhitespaceOrAsterisk();- }- while (parseOptionalJsdoc(SyntaxKind.CommaToken));- return createNodeArray(typeParameters, pos);- }-- function parseTemplateTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTemplateTag {- // The template tag looks like one of the following:- // @template T,U,V- // @template {Constraint} T- //- // According to the [closure docs](https://github.com/google/closure-compiler/wiki/Generic-Types#multiple-bounded-template-types):- // > Multiple bounded generics cannot be declared on the same line. For the sake of clarity, if multiple templates share the same- // > type bound they must be declared on separate lines.- //- // TODO: Determine whether we should enforce this in the checker.- // TODO: Consider moving the `constraint` to the first type parameter as we could then remove `getEffectiveConstraintOfTypeParameter`.- // TODO: Consider only parsing a single type parameter if there is a constraint.- const constraint = token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;- const typeParameters = parseTemplateTagTypeParameters();- return finishNode(factory.createJSDocTemplateTag(tagName, constraint, typeParameters, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start);- }-- function parseOptionalJsdoc(t: JSDocSyntaxKind): boolean {- if (token() === t) {- nextTokenJSDoc();- return true;- }- return false;- }-- function parseJSDocEntityName(): EntityName {- let entity: EntityName = parseJSDocIdentifierName();- if (parseOptional(SyntaxKind.OpenBracketToken)) {- parseExpected(SyntaxKind.CloseBracketToken);- // Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking.- // Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}>- // but it's not worth it to enforce that restriction.- }- while (parseOptional(SyntaxKind.DotToken)) {- const name = parseJSDocIdentifierName();- if (parseOptional(SyntaxKind.OpenBracketToken)) {- parseExpected(SyntaxKind.CloseBracketToken);- }- entity = createQualifiedName(entity, name);- }- return entity;- }-- function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier {- if (!tokenIsIdentifierOrKeyword(token())) {- return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected);- }-- identifierCount++;- const start = scanner.getTokenStart();- const end = scanner.getTokenEnd();- const originalKeywordKind = token();- const text = internIdentifier(scanner.getTokenValue());- const result = finishNode(factoryCreateIdentifier(text, originalKeywordKind), start, end);- nextTokenJSDoc();- return result;- }- }- }-}--const incrementallyParsedFiles = new WeakSet<SourceFile>();--function markAsIncrementallyParsed(sourceFile: SourceFile) {- if (incrementallyParsedFiles.has(sourceFile)) {- Debug.fail("Source file has already been incrementally parsed");- }- incrementallyParsedFiles.add(sourceFile);-}--const intersectingChangeSet = new WeakSet<Node | NodeArray<Node>>();--function intersectsIncrementalChange(node: Node | NodeArray<Node>): boolean {- return intersectingChangeSet.has(node);-}--function markAsIntersectingIncrementalChange(node: Node | NodeArray<Node>) {- intersectingChangeSet.add(node);-}--namespace IncrementalParser {- export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile {- aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive);-- checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks);- if (textChangeRangeIsUnchanged(textChangeRange)) {- // if the text didn't change, then we can just return our current source file as-is.- return sourceFile;- }-- if (sourceFile.statements.length === 0) {- // If we don't have any statements in the current source file, then there's no real- // way to incrementally parse. So just do a full parse instead.- return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator, sourceFile.jsDocParsingMode);- }-- // Make sure we're not trying to incrementally update a source file more than once. Once- // we do an update the original source file is considered unusable from that point onwards.- //- // This is because we do incremental parsing in-place. i.e. we take nodes from the old- // tree and give them new positions and parents. From that point on, trusting the old- // tree at all is not possible as far too much of it may violate invariants.- markAsIncrementallyParsed(sourceFile);- Parser.fixupParentReferences(sourceFile);- const oldText = sourceFile.text;- const syntaxCursor = createSyntaxCursor(sourceFile);-- // Make the actual change larger so that we know to reparse anything whose lookahead- // might have intersected the change.- const changeRange = extendToAffectedRange(sourceFile, textChangeRange);- checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks);-- // Ensure that extending the affected range only moved the start of the change range- // earlier in the file.- Debug.assert(changeRange.span.start <= textChangeRange.span.start);- Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span));- Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange)));-- // The is the amount the nodes after the edit range need to be adjusted. It can be- // positive (if the edit added characters), negative (if the edit deleted characters)- // or zero (if this was a pure overwrite with nothing added/removed).- const delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length;-- // If we added or removed characters during the edit, then we need to go and adjust all- // the nodes after the edit. Those nodes may move forward (if we inserted chars) or they- // may move backward (if we deleted chars).- //- // Doing this helps us out in two ways. First, it means that any nodes/tokens we want- // to reuse are already at the appropriate position in the new text. That way when we- // reuse them, we don't have to figure out if they need to be adjusted. Second, it makes- // it very easy to determine if we can reuse a node. If the node's position is at where- // we are in the text, then we can reuse it. Otherwise we can't. If the node's position- // is ahead of us, then we'll need to rescan tokens. If the node's position is behind- // us, then we'll need to skip it or crumble it as appropriate- //- // We will also adjust the positions of nodes that intersect the change range as well.- // By doing this, we ensure that all the positions in the old tree are consistent, not- // just the positions of nodes entirely before/after the change range. By being- // consistent, we can then easily map from positions to nodes in the old tree easily.- //- // Also, mark any syntax elements that intersect the changed span. We know, up front,- // that we cannot reuse these elements.- updateTokenPositionsAndMarkElements(sourceFile, changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks);-- // Now that we've set up our internal incremental state just proceed and parse the- // source file in the normal fashion. When possible the parser will retrieve and- // reuse nodes from the old tree.- //- // Note: passing in 'true' for setNodeParents is very important. When incrementally- // parsing, we will be reusing nodes from the old tree, and placing it into new- // parents. If we don't set the parents now, we'll end up with an observably- // inconsistent tree. Setting the parents on the new tree should be very fast. We- // will immediately bail out of walking any subtrees when we can see that their parents- // are already correct.- const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator, sourceFile.jsDocParsingMode);- result.commentDirectives = getNewCommentDirectives(- sourceFile.commentDirectives,- result.commentDirectives,- changeRange.span.start,- textSpanEnd(changeRange.span),- delta,- oldText,- newText,- aggressiveChecks,- );- result.impliedNodeFormat = sourceFile.impliedNodeFormat;- transferSourceFileChildren(sourceFile, result);- return result;- }-- function getNewCommentDirectives(- oldDirectives: CommentDirective[] | undefined,- newDirectives: CommentDirective[] | undefined,- changeStart: number,- changeRangeOldEnd: number,- delta: number,- oldText: string,- newText: string,- aggressiveChecks: boolean,- ): CommentDirective[] | undefined {- if (!oldDirectives) return newDirectives;- let commentDirectives: CommentDirective[] | undefined;- let addedNewlyScannedDirectives = false;- for (const directive of oldDirectives) {- const { range, type } = directive;- // Range before the change- if (range.end < changeStart) {- commentDirectives = append(commentDirectives, directive);- }- else if (range.pos > changeRangeOldEnd) {- addNewlyScannedDirectives();- // Node is entirely past the change range. We need to move both its pos and- // end, forward or backward appropriately.- const updatedDirective: CommentDirective = {- range: { pos: range.pos + delta, end: range.end + delta },- type,- };- commentDirectives = append(commentDirectives, updatedDirective);- if (aggressiveChecks) {- Debug.assert(oldText.substring(range.pos, range.end) === newText.substring(updatedDirective.range.pos, updatedDirective.range.end));- }- }- // Ignore ranges that fall in change range- }- addNewlyScannedDirectives();- return commentDirectives;-- function addNewlyScannedDirectives() {- if (addedNewlyScannedDirectives) return;- addedNewlyScannedDirectives = true;- if (!commentDirectives) {- commentDirectives = newDirectives;- }- else if (newDirectives) {- commentDirectives.push(...newDirectives);- }- }- }-- function moveElementEntirelyPastChangeRange(element: Node, origSourceFile: SourceFile, isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;- function moveElementEntirelyPastChangeRange(element: NodeArray<Node>, origSourceFile: SourceFile, isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;- function moveElementEntirelyPastChangeRange(element: Node | NodeArray<Node>, origSourceFile: SourceFile, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {- if (isArray) {- visitArray(element as NodeArray<Node>);- }- else {- visitNode(element as Node);- }- return;-- function visitNode(node: Node) {- let text = "";- if (aggressiveChecks && shouldCheckNode(node)) {- text = oldText.substring(node.pos, node.end);- }-- // Ditch any existing LS children we may have created. This way we can avoid- // moving them forward.- unsetNodeChildren(node, origSourceFile);-- setTextRangePosEnd(node, node.pos + delta, node.end + delta);-- if (aggressiveChecks && shouldCheckNode(node)) {- Debug.assert(text === newText.substring(node.pos, node.end));- }-- forEachChild(node, visitNode as (node: Node) => void, visitArray as (nodes: NodeArray<Node>) => void);- if (hasJSDocNodes(node)) {- for (const jsDocComment of node.jsDoc!) {- visitNode(jsDocComment);- }- }- checkNodePositions(node, aggressiveChecks);- }-- function visitArray(array: NodeArray<Node>) {- setTextRangePosEnd(array, array.pos + delta, array.end + delta);-- for (const node of array) {- visitNode(node);- }- }- }-- function shouldCheckNode(node: Node) {- switch (node.kind) {- case SyntaxKind.StringLiteral:- case SyntaxKind.NumericLiteral:- case SyntaxKind.Identifier:- return true;- }-- return false;- }-- function adjustIntersectingElement(element: Node | NodeArray<Node>, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) {- Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range");- Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range");- Debug.assert(element.pos <= element.end);-- // We have an element that intersects the change range in some way. It may have its- // start, or its end (or both) in the changed range. We want to adjust any part- // that intersects such that the final tree is in a consistent state. i.e. all- // children have spans within the span of their parent, and all siblings are ordered- // properly.-- // We may need to update both the 'pos' and the 'end' of the element.-- // If the 'pos' is before the start of the change, then we don't need to touch it.- // If it isn't, then the 'pos' must be inside the change. How we update it will- // depend if delta is positive or negative. If delta is positive then we have- // something like:- //- // -------------------AAA------------------ // -------------------BBBCCCCCCC------------------ //- // In this case, we consider any node that started in the change range to still be- // starting at the same position.- //- // however, if the delta is negative, then we instead have something like this:- //- // -------------------XXXYYYYYYY------------------ // -------------------ZZZ------------------ //- // In this case, any element that started in the 'X' range will keep its position.- // However any element that started after that will have their pos adjusted to be- // at the end of the new range. i.e. any node that started in the 'Y' range will- // be adjusted to have their start at the end of the 'Z' range.- //- // The element will keep its position if possible. Or Move backward to the new-end- // if it's in the 'Y' range.- const pos = Math.min(element.pos, changeRangeNewEnd);-- // If the 'end' is after the change range, then we always adjust it by the delta- // amount. However, if the end is in the change range, then how we adjust it- // will depend on if delta is positive or negative. If delta is positive then we- // have something like:- //- // -------------------AAA------------------ // -------------------BBBCCCCCCC------------------ //- // In this case, we consider any node that ended inside the change range to keep its- // end position.- //- // however, if the delta is negative, then we instead have something like this:- //- // -------------------XXXYYYYYYY------------------ // -------------------ZZZ------------------ //- // In this case, any element that ended in the 'X' range will keep its position.- // However any element that ended after that will have their pos adjusted to be- // at the end of the new range. i.e. any node that ended in the 'Y' range will- // be adjusted to have their end at the end of the 'Z' range.- const end = element.end >= changeRangeOldEnd ?- // Element ends after the change range. Always adjust the end pos.- element.end + delta :- // Element ends in the change range. The element will keep its position if- // possible. Or Move backward to the new-end if it's in the 'Y' range.- Math.min(element.end, changeRangeNewEnd);-- Debug.assert(pos <= end);- if ((element as any).parent) {- const parent = (element as any).parent as Node;- Debug.assertGreaterThanOrEqual(pos, parent.pos);- Debug.assertLessThanOrEqual(end, parent.end);- }-- setTextRangePosEnd(element, pos, end);- }-- function checkNodePositions(node: Node, aggressiveChecks: boolean) {- if (aggressiveChecks) {- let pos = node.pos;- const visitNode = (child: Node) => {- Debug.assert(child.pos >= pos);- pos = child.end;- };- if (hasJSDocNodes(node)) {- for (const jsDocComment of node.jsDoc!) {- visitNode(jsDocComment);- }- }- forEachChild(node, visitNode);- Debug.assert(pos <= node.end);- }- }-- function updateTokenPositionsAndMarkElements(- sourceFile: SourceFile,- changeStart: number,- changeRangeOldEnd: number,- changeRangeNewEnd: number,- delta: number,- oldText: string,- newText: string,- aggressiveChecks: boolean,- ): void {- visitNode(sourceFile);- return;-- function visitNode(child: Node) {- Debug.assert(child.pos <= child.end);- if (child.pos > changeRangeOldEnd) {- // Node is entirely past the change range. We need to move both its pos and- // end, forward or backward appropriately.- moveElementEntirelyPastChangeRange(child, sourceFile, /*isArray*/ false, delta, oldText, newText, aggressiveChecks);- return;- }-- // Check if the element intersects the change range. If it does, then it is not- // reusable. Also, we'll need to recurse to see what constituent portions we may- // be able to use.- const fullEnd = child.end;- if (fullEnd >= changeStart) {- markAsIntersectingIncrementalChange(child);- unsetNodeChildren(child, sourceFile);-- // Adjust the pos or end (or both) of the intersecting element accordingly.- adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);- forEachChild(child, visitNode as (node: Node) => void, visitArray as (nodes: NodeArray<Node>) => void);- if (hasJSDocNodes(child)) {- for (const jsDocComment of child.jsDoc!) {- visitNode(jsDocComment);- }- }- checkNodePositions(child, aggressiveChecks);- return;- }-- // Otherwise, the node is entirely before the change range. No need to do anything with it.- Debug.assert(fullEnd < changeStart);- }-- function visitArray(array: NodeArray<Node>) {- Debug.assert(array.pos <= array.end);- if (array.pos > changeRangeOldEnd) {- // Array is entirely after the change range. We need to move it, and move any of- // its children.- moveElementEntirelyPastChangeRange(array, sourceFile, /*isArray*/ true, delta, oldText, newText, aggressiveChecks);- return;- }-- // Check if the element intersects the change range. If it does, then it is not- // reusable. Also, we'll need to recurse to see what constituent portions we may- // be able to use.- const fullEnd = array.end;- if (fullEnd >= changeStart) {- markAsIntersectingIncrementalChange(array);-- // Adjust the pos or end (or both) of the intersecting array accordingly.- adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);- for (const node of array) {- visitNode(node);- }- return;- }-- // Otherwise, the array is entirely before the change range. No need to do anything with it.- Debug.assert(fullEnd < changeStart);- }- }-- function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange {- // Consider the following code:- // void foo() { /; }- //- // If the text changes with an insertion of / just before the semicolon then we end up with:- // void foo() { //; }- //- // If we were to just use the changeRange a is, then we would not rescan the { token- // (as it does not intersect the actual original change range). Because an edit may- // change the token touching it, we actually need to look back *at least* one token so- // that the prior token sees that change.- const maxLookahead = 1;-- let start = changeRange.span.start;-- // the first iteration aligns us with the change start. subsequent iteration move us to- // the left by maxLookahead tokens. We only need to do this as long as we're not at the- // start of the tree.- for (let i = 0; start > 0 && i <= maxLookahead; i++) {- const nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start);- Debug.assert(nearestNode.pos <= start);- const position = nearestNode.pos;-- start = Math.max(0, position - 1);- }-- const finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span));- const finalLength = changeRange.newLength + (changeRange.span.start - start);-- return createTextChangeRange(finalSpan, finalLength);- }-- function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node {- let bestResult: Node = sourceFile;- let lastNodeEntirelyBeforePosition: Node | undefined;-- forEachChild(sourceFile, visit);-- if (lastNodeEntirelyBeforePosition) {- const lastChildOfLastEntireNodeBeforePosition = getLastDescendant(lastNodeEntirelyBeforePosition);- if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) {- bestResult = lastChildOfLastEntireNodeBeforePosition;- }- }-- return bestResult;-- function getLastDescendant(node: Node): Node {- while (true) {- const lastChild = getLastChild(node);- if (lastChild) {- node = lastChild;- }- else {- return node;- }- }- }-- function visit(child: Node) {- if (nodeIsMissing(child)) {- // Missing nodes are effectively invisible to us. We never even consider them- // When trying to find the nearest node before us.- return;- }-- // If the child intersects this position, then this node is currently the nearest- // node that starts before the position.- if (child.pos <= position) {- if (child.pos >= bestResult.pos) {- // This node starts before the position, and is closer to the position than- // the previous best node we found. It is now the new best node.- bestResult = child;- }-- // Now, the node may overlap the position, or it may end entirely before the- // position. If it overlaps with the position, then either it, or one of its- // children must be the nearest node before the position. So we can just- // recurse into this child to see if we can find something better.- if (position < child.end) {- // The nearest node is either this child, or one of the children inside- // of it. We've already marked this child as the best so far. Recurse- // in case one of the children is better.- forEachChild(child, visit);-- // Once we look at the children of this node, then there's no need to- // continue any further.- return true;- }- else {- Debug.assert(child.end <= position);- // The child ends entirely before this position. Say you have the following- // (where $ is the position)- //- // <complex expr 1> ? <complex expr 2> $ : <...> <...>- //- // We would want to find the nearest preceding node in "complex expr 2".- // To support that, we keep track of this node, and once we're done searching- // for a best node, we recurse down this node to see if we can find a good- // result in it.- //- // This approach allows us to quickly skip over nodes that are entirely- // before the position, while still allowing us to find any nodes in the- // last one that might be what we want.- lastNodeEntirelyBeforePosition = child;- }- }- else {- Debug.assert(child.pos > position);- // We're now at a node that is entirely past the position we're searching for.- // This node (and all following nodes) could never contribute to the result,- // so just skip them by returning 'true' here.- return true;- }- }- }-- function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) {- const oldText = sourceFile.text;- if (textChangeRange) {- Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length);-- if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) {- const oldTextPrefix = oldText.substr(0, textChangeRange.span.start);- const newTextPrefix = newText.substr(0, textChangeRange.span.start);- Debug.assert(oldTextPrefix === newTextPrefix);-- const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length);- const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length);- Debug.assert(oldTextSuffix === newTextSuffix);- }- }- }-- // Allows finding nodes in the source file at a certain position in an efficient manner.- // The implementation takes advantage of the calling pattern it knows the parser will- // make in order to optimize finding nodes as quickly as possible.- export interface SyntaxCursor {- currentNode(position: number): Node;- }-- export function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor {- let currentArray: NodeArray<Node> = sourceFile.statements;- let currentArrayIndex = 0;-- Debug.assert(currentArrayIndex < currentArray.length);- let current = currentArray[currentArrayIndex];- let lastQueriedPosition = InvalidPosition.Value;-- return {- currentNode(position: number) {- // Only compute the current node if the position is different than the last time- // we were asked. The parser commonly asks for the node at the same position- // twice. Once to know if can read an appropriate list element at a certain point,- // and then to actually read and consume the node.- if (position !== lastQueriedPosition) {- // Much of the time the parser will need the very next node in the array that- // we just returned a node from.So just simply check for that case and move- // forward in the array instead of searching for the node again.- if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) {- currentArrayIndex++;- current = currentArray[currentArrayIndex];- }-- // If we don't have a node, or the node we have isn't in the right position,- // then try to find a viable node at the position requested.- if (!current || current.pos !== position) {- findHighestListElementThatStartsAtPosition(position);- }- }-- // Cache this query so that we don't do any extra work if the parser calls back- // into us. Note: this is very common as the parser will make pairs of calls like- // 'isListElement -> parseListElement'. If we were unable to find a node when- // called with 'isListElement', we don't want to redo the work when parseListElement- // is called immediately after.- lastQueriedPosition = position;-- // Either we don'd have a node, or we have a node at the position being asked for.- Debug.assert(!current || current.pos === position);- return current;- },- };-- // Finds the highest element in the tree we can find that starts at the provided position.- // The element must be a direct child of some node list in the tree. This way after we- // return it, we can easily return its next sibling in the list.- function findHighestListElementThatStartsAtPosition(position: number) {- // Clear out any cached state about the last node we found.- currentArray = undefined!;- currentArrayIndex = InvalidPosition.Value;- current = undefined!;-- // Recurse into the source file to find the highest node at this position.- forEachChild(sourceFile, visitNode, visitArray);- return;-- function visitNode(node: Node) {- if (position >= node.pos && position < node.end) {- // Position was within this node. Keep searching deeper to find the node.- forEachChild(node, visitNode, visitArray);-- // don't proceed any further in the search.- return true;- }-- // position wasn't in this node, have to keep searching.- return false;- }-- function visitArray(array: NodeArray<Node>) {- if (position >= array.pos && position < array.end) {- // position was in this array. Search through this array to see if we find a- // viable element.- for (let i = 0; i < array.length; i++) {- const child = array[i];- if (child) {- if (child.pos === position) {- // Found the right node. We're done.- currentArray = array;- currentArrayIndex = i;- current = child;- return true;- }- else {- if (child.pos < position && position < child.end) {- // Position in somewhere within this child. Search in it and- // stop searching in this array.- forEachChild(child, visitNode, visitArray);- return true;- }- }- }- }- }-- // position wasn't in this array, have to keep searching.- return false;- }- }- }-- const enum InvalidPosition {- Value = -1,- }-}--/** @internal */-export function isDeclarationFileName(fileName: string): boolean {- return getDeclarationFileExtension(fileName) !== undefined;-}--/** @internal */-export function getDeclarationFileExtension(fileName: string): string | undefined {- const standardExtension = getAnyExtensionFromPath(fileName, supportedDeclarationExtensions, /*ignoreCase*/ false);- if (standardExtension) {- return standardExtension;- }- if (fileExtensionIs(fileName, Extension.Ts)) {- const baseName = getBaseFileName(fileName);- const index = baseName.lastIndexOf(".d.");- if (index >= 0) {- return baseName.substring(index);- }- }- return undefined;-}--function parseResolutionMode(mode: string | undefined, pos: number, end: number, reportDiagnostic: PragmaDiagnosticReporter): ResolutionMode {- if (!mode) {- return undefined;- }- if (mode === "import") {- return ModuleKind.ESNext;- }- if (mode === "require") {- return ModuleKind.CommonJS;- }- reportDiagnostic(pos, end - pos, Diagnostics.resolution_mode_should_be_either_require_or_import);- return undefined;-}--/** @internal */-export function processCommentPragmas(context: PragmaContext, sourceText: string): void {- const pragmas: PragmaPseudoMapEntry[] = [];-- for (const range of getLeadingCommentRanges(sourceText, 0) || emptyArray) {- const comment = sourceText.substring(range.pos, range.end);- extractPragmas(pragmas, range, comment);- }-- context.pragmas = new Map() as PragmaMap;- for (const pragma of pragmas) {- if (context.pragmas.has(pragma.name)) {- const currentValue = context.pragmas.get(pragma.name);- if (currentValue instanceof Array) {- currentValue.push(pragma.args);- }- else {- context.pragmas.set(pragma.name, [currentValue, pragma.args]);- }- continue;- }- context.pragmas.set(pragma.name, pragma.args);- }-}--/** @internal */-export type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void;--/** @internal */-export function processPragmasIntoFields(context: PragmaContext, reportDiagnostic: PragmaDiagnosticReporter): void {- context.checkJsDirective = undefined;- context.referencedFiles = [];- context.typeReferenceDirectives = [];- context.libReferenceDirectives = [];- context.amdDependencies = [];- context.hasNoDefaultLib = false;- context.pragmas!.forEach((entryOrList, key) => { // TODO: GH#18217- // TODO: The below should be strongly type-guarded and not need casts/explicit annotations, since entryOrList is related to- // key and key is constrained to a union; but it's not (see GH#21483 for at least partial fix) :(- switch (key) {- case "reference": {- const referencedFiles = context.referencedFiles;- const typeReferenceDirectives = context.typeReferenceDirectives;- const libReferenceDirectives = context.libReferenceDirectives;- forEach(toArray(entryOrList) as PragmaPseudoMap["reference"][], arg => {- const { types, lib, path, ["resolution-mode"]: res, preserve: _preserve } = arg.arguments;- const preserve = _preserve === "true" ? true : undefined;- if (arg.arguments["no-default-lib"] === "true") {- context.hasNoDefaultLib = true;- }- else if (types) {- const parsed = parseResolutionMode(res, types.pos, types.end, reportDiagnostic);- typeReferenceDirectives.push({ pos: types.pos, end: types.end, fileName: types.value, ...(parsed ? { resolutionMode: parsed } : {}), ...(preserve ? { preserve } : {}) });- }- else if (lib) {- libReferenceDirectives.push({ pos: lib.pos, end: lib.end, fileName: lib.value, ...(preserve ? { preserve } : {}) });- }- else if (path) {- referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value, ...(preserve ? { preserve } : {}) });- }- else {- reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax);- }- });- break;- }- case "amd-dependency": {- context.amdDependencies = map(- toArray(entryOrList) as PragmaPseudoMap["amd-dependency"][],- x => ({ name: x.arguments.name, path: x.arguments.path }),- );- break;- }- case "amd-module": {- if (entryOrList instanceof Array) {- for (const entry of entryOrList) {- if (context.moduleName) {- // TODO: It's probably fine to issue this diagnostic on all instances of the pragma- reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments);- }- context.moduleName = (entry as PragmaPseudoMap["amd-module"]).arguments.name;- }- }- else {- context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"]).arguments.name;- }- break;- }- case "ts-nocheck":- case "ts-check": {- // _last_ of either nocheck or check in a file is the "winner"- forEach(toArray(entryOrList), entry => {- if (!context.checkJsDirective || entry.range.pos > context.checkJsDirective.pos) {- context.checkJsDirective = {- enabled: key === "ts-check",- end: entry.range.end,- pos: entry.range.pos,- };- }- });- break;- }- case "jsx":- case "jsxfrag":- case "jsximportsource":- case "jsxruntime":- return; // Accessed directly- default:- Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future?- }- });-}--const namedArgRegExCache = new Map<string, RegExp>();-function getNamedArgRegEx(name: string): RegExp {- if (namedArgRegExCache.has(name)) {- return namedArgRegExCache.get(name)!;- }- const result = new RegExp(`(\\s${name}\\s*=\\s*)(?:(?:'([^']*)')|(?:"([^"]*)"))`, "im");- namedArgRegExCache.set(name, result);- return result;-}--const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/m;-const singleLinePragmaRegEx = /^\/\/\/?\s*@([^\s:]+)((?:[^\S\r\n]|:).*)?$/m;-function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, text: string) {- const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia && tripleSlashXMLCommentStartRegEx.exec(text);- if (tripleSlash) {- const name = tripleSlash[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks- const pragma = commentPragmas[name] as PragmaDefinition;- if (!pragma || !(pragma.kind! & PragmaKindFlags.TripleSlashXML)) {- return;- }- if (pragma.args) {- const argument: { [index: string]: string | { value: string; pos: number; end: number; }; } = {};- for (const arg of pragma.args) {- const matcher = getNamedArgRegEx(arg.name);- const matchResult = matcher.exec(text);- if (!matchResult && !arg.optional) {- return; // Missing required argument, don't parse- }- else if (matchResult) {- const value = matchResult[2] || matchResult[3];- if (arg.captureSpan) {- const startPos = range.pos + matchResult.index + matchResult[1].length + 1;- argument[arg.name] = {- value,- pos: startPos,- end: startPos + value.length,- };- }- else {- argument[arg.name] = value;- }- }- }- pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry);- }- else {- pragmas.push({ name, args: { arguments: {}, range } } as PragmaPseudoMapEntry);- }- return;- }-- const singleLine = range.kind === SyntaxKind.SingleLineCommentTrivia && singleLinePragmaRegEx.exec(text);- if (singleLine) {- return addPragmaForMatch(pragmas, range, PragmaKindFlags.SingleLine, singleLine);- }-- if (range.kind === SyntaxKind.MultiLineCommentTrivia) {- const multiLinePragmaRegEx = /@(\S+)(\s+(?:\S.*)?)?$/gm; // Defined inline since it uses the "g" flag, which keeps a persistent index (for iterating)- let multiLineMatch: RegExpExecArray | null; // eslint-disable-line no-restricted-syntax- while (multiLineMatch = multiLinePragmaRegEx.exec(text)) {- addPragmaForMatch(pragmas, range, PragmaKindFlags.MultiLine, multiLineMatch);- }- }-}--function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) {- if (!match) return;- const name = match[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks- const pragma = commentPragmas[name] as PragmaDefinition;- if (!pragma || !(pragma.kind! & kind)) {- return;- }- const args = match[2]; // Split on spaces and match up positionally with definition- const argument = getNamedPragmaArguments(pragma, args);- if (argument === "fail") return; // Missing required argument, fail to parse it- pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry);- return;-}--function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): { [index: string]: string; } | "fail" {- if (!text) return {};- if (!pragma.args) return {};- const args = text.trim().split(/\s+/);- const argMap: { [index: string]: string; } = {};- for (let i = 0; i < pragma.args.length; i++) {- const argument = pragma.args[i];- if (!args[i] && !argument.optional) {- return "fail";- }- if (argument.captureSpan) {- return Debug.fail("Capture spans not yet implemented for non-xml pragmas");- }- argMap[argument.name] = args[i];- }- return argMap;-}--/** @internal */-export function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean {- if (lhs.kind !== rhs.kind) {- return false;- }-- if (lhs.kind === SyntaxKind.Identifier) {- return lhs.escapedText === (rhs as Identifier).escapedText;- }-- if (lhs.kind === SyntaxKind.ThisKeyword) {- return true;- }-- if (lhs.kind === SyntaxKind.JsxNamespacedName) {- return lhs.namespace.escapedText === (rhs as JsxNamespacedName).namespace.escapedText &&- lhs.name.escapedText === (rhs as JsxNamespacedName).name.escapedText;- }-- // If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only- // take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression- // it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element- return (lhs as PropertyAccessExpression).name.escapedText === (rhs as PropertyAccessExpression).name.escapedText &&- tagNamesAreEquivalent((lhs as PropertyAccessExpression).expression as JsxTagNameExpression, (rhs as PropertyAccessExpression).expression as JsxTagNameExpression);-}
deps/swc/crates/swc/benches/assets/renderer.ts
@@ -1,2550 +0,0 @@-import {- Comment,- Fragment,- Static,- Text,- type VNode,- type VNodeArrayChildren,- type VNodeHook,- type VNodeProps,- cloneIfMounted,- createVNode,- invokeVNodeHook,- isSameVNodeType,- normalizeVNode,-} from './vnode'-import {- type ComponentInternalInstance,- type ComponentOptions,- type Data,- type LifecycleHook,- createComponentInstance,- setupComponent,-} from './component'-import {- filterSingleRoot,- renderComponentRoot,- shouldUpdateComponent,- updateHOCHostEl,-} from './componentRenderUtils'-import {- EMPTY_ARR,- EMPTY_OBJ,- NOOP,- PatchFlags,- ShapeFlags,- def,- getGlobalThis,- invokeArrayFns,- isArray,- isReservedProp,-} from '@vue/shared'-import {- type SchedulerJob,- SchedulerJobFlags,- type SchedulerJobs,- flushPostFlushCbs,- flushPreFlushCbs,- queueJob,- queuePostFlushCb,-} from './scheduler'-import {- EffectFlags,- ReactiveEffect,- pauseTracking,- resetTracking,-} from '@vue/reactivity'-import { updateProps } from './componentProps'-import { updateSlots } from './componentSlots'-import { popWarningContext, pushWarningContext, warn } from './warning'-import { type CreateAppFunction, createAppAPI } from './apiCreateApp'-import { setRef } from './rendererTemplateRef'-import {- type SuspenseBoundary,- type SuspenseImpl,- isSuspense,- queueEffectWithSuspense,-} from './components/Suspense'-import {- TeleportEndKey,- type TeleportImpl,- type TeleportVNode,-} from './components/Teleport'-import { type KeepAliveContext, isKeepAlive } from './components/KeepAlive'-import { isHmrUpdating, registerHMR, unregisterHMR } from './hmr'-import { type RootHydrateFunction, createHydrationFunctions } from './hydration'-import { invokeDirectiveHook } from './directives'-import { endMeasure, startMeasure } from './profiling'-import {- devtoolsComponentAdded,- devtoolsComponentRemoved,- devtoolsComponentUpdated,- setDevtoolsHook,-} from './devtools'-import { initFeatureFlags } from './featureFlags'-import { isAsyncWrapper } from './apiAsyncComponent'-import { isCompatEnabled } from './compat/compatConfig'-import { DeprecationTypes } from './compat/compatConfig'-import type { TransitionHooks } from './components/BaseTransition'--export interface Renderer<HostElement = RendererElement> {- render: RootRenderFunction<HostElement>- createApp: CreateAppFunction<HostElement>-}--export interface HydrationRenderer extends Renderer<Element | ShadowRoot> {- hydrate: RootHydrateFunction-}--export type ElementNamespace = 'svg' | 'mathml' | undefined--export type RootRenderFunction<HostElement = RendererElement> = (- vnode: VNode | null,- container: HostElement,- namespace?: ElementNamespace,-) => void--export interface RendererOptions<- HostNode = RendererNode,- HostElement = RendererElement,-> {- patchProp(- el: HostElement,- key: string,- prevValue: any,- nextValue: any,- namespace?: ElementNamespace,- parentComponent?: ComponentInternalInstance | null,- ): void- insert(el: HostNode, parent: HostElement, anchor?: HostNode | null): void- remove(el: HostNode): void- createElement(- type: string,- namespace?: ElementNamespace,- isCustomizedBuiltIn?: string,- vnodeProps?: (VNodeProps & { [key: string]: any }) | null,- ): HostElement- createText(text: string): HostNode- createComment(text: string): HostNode- setText(node: HostNode, text: string): void- setElementText(node: HostElement, text: string): void- parentNode(node: HostNode): HostElement | null- nextSibling(node: HostNode): HostNode | null- querySelector?(selector: string): HostElement | null- setScopeId?(el: HostElement, id: string): void- cloneNode?(node: HostNode): HostNode- insertStaticContent?(- content: string,- parent: HostElement,- anchor: HostNode | null,- namespace: ElementNamespace,- start?: HostNode | null,- end?: HostNode | null,- ): [HostNode, HostNode]-}--// Renderer Node can technically be any object in the context of core renderer-// logic - they are never directly operated on and always passed to the node op-// functions provided via options, so the internal constraint is really just-// a generic object.-export interface RendererNode {- [key: string | symbol]: any-}--export interface RendererElement extends RendererNode {}--// An object exposing the internals of a renderer, passed to tree-shakeable-// features so that they can be decoupled from this file. Keys are shortened-// to optimize bundle size.-export interface RendererInternals<- HostNode = RendererNode,- HostElement = RendererElement,-> {- p: PatchFn- um: UnmountFn- r: RemoveFn- m: MoveFn- mt: MountComponentFn- mc: MountChildrenFn- pc: PatchChildrenFn- pbc: PatchBlockChildrenFn- n: NextFn- o: RendererOptions<HostNode, HostElement>-}--// These functions are created inside a closure and therefore their types cannot-// be directly exported. In order to avoid maintaining function signatures in-// two places, we declare them once here and use them inside the closure.-type PatchFn = (- n1: VNode | null, // null means this is a mount- n2: VNode,- container: RendererElement,- anchor?: RendererNode | null,- parentComponent?: ComponentInternalInstance | null,- parentSuspense?: SuspenseBoundary | null,- namespace?: ElementNamespace,- slotScopeIds?: string[] | null,- optimized?: boolean,-) => void--type MountChildrenFn = (- children: VNodeArrayChildren,- container: RendererElement,- anchor: RendererNode | null,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- slotScopeIds: string[] | null,- optimized: boolean,- start?: number,-) => void--type PatchChildrenFn = (- n1: VNode | null,- n2: VNode,- container: RendererElement,- anchor: RendererNode | null,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- slotScopeIds: string[] | null,- optimized: boolean,-) => void--type PatchBlockChildrenFn = (- oldChildren: VNode[],- newChildren: VNode[],- fallbackContainer: RendererElement,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- slotScopeIds: string[] | null,-) => void--type MoveFn = (- vnode: VNode,- container: RendererElement,- anchor: RendererNode | null,- type: MoveType,- parentSuspense?: SuspenseBoundary | null,-) => void--type NextFn = (vnode: VNode) => RendererNode | null--type UnmountFn = (- vnode: VNode,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- doRemove?: boolean,- optimized?: boolean,-) => void--type RemoveFn = (vnode: VNode) => void--type UnmountChildrenFn = (- children: VNode[],- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- doRemove?: boolean,- optimized?: boolean,- start?: number,-) => void--export type MountComponentFn = (- initialVNode: VNode,- container: RendererElement,- anchor: RendererNode | null,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- optimized: boolean,-) => void--type ProcessTextOrCommentFn = (- n1: VNode | null,- n2: VNode,- container: RendererElement,- anchor: RendererNode | null,-) => void--export type SetupRenderEffectFn = (- instance: ComponentInternalInstance,- initialVNode: VNode,- container: RendererElement,- anchor: RendererNode | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- optimized: boolean,-) => void--export enum MoveType {- ENTER,- LEAVE,- REORDER,-}--export const queuePostRenderEffect: (- fn: SchedulerJobs,- suspense: SuspenseBoundary | null,-) => void = __FEATURE_SUSPENSE__- ? __TEST__- ? // vitest can't seem to handle eager circular dependency- (fn: Function | Function[], suspense: SuspenseBoundary | null) =>- queueEffectWithSuspense(fn, suspense)- : queueEffectWithSuspense- : queuePostFlushCb--/**- * The createRenderer function accepts two generic arguments:- * HostNode and HostElement, corresponding to Node and Element types in the- * host environment. For example, for runtime-dom, HostNode would be the DOM- * `Node` interface and HostElement would be the DOM `Element` interface.- *- * Custom renderers can pass in the platform specific types like this:- *- * ``` js- * const { render, createApp } = createRenderer<Node, Element>({- * patchProp,- * ...nodeOps- * })- * ```- */-export function createRenderer<- HostNode = RendererNode,- HostElement = RendererElement,->(options: RendererOptions<HostNode, HostElement>): Renderer<HostElement> {- return baseCreateRenderer<HostNode, HostElement>(options)-}--// Separate API for creating hydration-enabled renderer.-// Hydration logic is only used when calling this function, making it-// tree-shakable.-export function createHydrationRenderer(- options: RendererOptions<Node, Element>,-): HydrationRenderer {- return baseCreateRenderer(options, createHydrationFunctions)-}--// overload 1: no hydration-function baseCreateRenderer<- HostNode = RendererNode,- HostElement = RendererElement,->(options: RendererOptions<HostNode, HostElement>): Renderer<HostElement>--// overload 2: with hydration-function baseCreateRenderer(- options: RendererOptions<Node, Element>,- createHydrationFns: typeof createHydrationFunctions,-): HydrationRenderer--// implementation-function baseCreateRenderer(- options: RendererOptions,- createHydrationFns?: typeof createHydrationFunctions,-): any {- // compile-time feature flags check- if (__ESM_BUNDLER__ && !__TEST__) {- initFeatureFlags()- }-- const target = getGlobalThis()- target.__VUE__ = true- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {- setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__, target)- }-- const {- insert: hostInsert,- remove: hostRemove,- patchProp: hostPatchProp,- createElement: hostCreateElement,- createText: hostCreateText,- createComment: hostCreateComment,- setText: hostSetText,- setElementText: hostSetElementText,- parentNode: hostParentNode,- nextSibling: hostNextSibling,- setScopeId: hostSetScopeId = NOOP,- insertStaticContent: hostInsertStaticContent,- } = options-- // Note: functions inside this closure should use `const xxx = () => {}`- // style in order to prevent being inlined by minifiers.- const patch: PatchFn = (- n1,- n2,- container,- anchor = null,- parentComponent = null,- parentSuspense = null,- namespace = undefined,- slotScopeIds = null,- optimized = __DEV__ && isHmrUpdating ? false : !!n2.dynamicChildren,- ) => {- if (n1 === n2) {- return- }-- // patching & not same type, unmount old tree- if (n1 && !isSameVNodeType(n1, n2)) {- anchor = getNextHostNode(n1)- unmount(n1, parentComponent, parentSuspense, true)- n1 = null- }-- if (n2.patchFlag === PatchFlags.BAIL) {- optimized = false- n2.dynamicChildren = null- }-- const { type, ref, shapeFlag } = n2- switch (type) {- case Text:- processText(n1, n2, container, anchor)- break- case Comment:- processCommentNode(n1, n2, container, anchor)- break- case Static:- if (n1 == null) {- mountStaticNode(n2, container, anchor, namespace)- } else if (__DEV__) {- patchStaticNode(n1, n2, container, namespace)- }- break- case Fragment:- processFragment(- n1,- n2,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- break- default:- if (shapeFlag & ShapeFlags.ELEMENT) {- processElement(- n1,- n2,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- } else if (shapeFlag & ShapeFlags.COMPONENT) {- processComponent(- n1,- n2,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- } else if (shapeFlag & ShapeFlags.TELEPORT) {- ;(type as typeof TeleportImpl).process(- n1 as TeleportVNode,- n2 as TeleportVNode,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- internals,- )- } else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {- ;(type as typeof SuspenseImpl).process(- n1,- n2,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- internals,- )- } else if (__DEV__) {- warn('Invalid VNode type:', type, `(${typeof type})`)- }- }-- // set ref- if (ref != null && parentComponent) {- setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2)- }- }-- const processText: ProcessTextOrCommentFn = (n1, n2, container, anchor) => {- if (n1 == null) {- hostInsert(- (n2.el = hostCreateText(n2.children as string)),- container,- anchor,- )- } else {- const el = (n2.el = n1.el!)- if (n2.children !== n1.children) {- hostSetText(el, n2.children as string)- }- }- }-- const processCommentNode: ProcessTextOrCommentFn = (- n1,- n2,- container,- anchor,- ) => {- if (n1 == null) {- hostInsert(- (n2.el = hostCreateComment((n2.children as string) || '')),- container,- anchor,- )- } else {- // there's no support for dynamic comments- n2.el = n1.el- }- }-- const mountStaticNode = (- n2: VNode,- container: RendererElement,- anchor: RendererNode | null,- namespace: ElementNamespace,- ) => {- // static nodes are only present when used with compiler-dom/runtime-dom- // which guarantees presence of hostInsertStaticContent.- ;[n2.el, n2.anchor] = hostInsertStaticContent!(- n2.children as string,- container,- anchor,- namespace,- n2.el,- n2.anchor,- )- }-- /**- * Dev / HMR only- */- const patchStaticNode = (- n1: VNode,- n2: VNode,- container: RendererElement,- namespace: ElementNamespace,- ) => {- // static nodes are only patched during dev for HMR- if (n2.children !== n1.children) {- const anchor = hostNextSibling(n1.anchor!)- // remove existing- removeStaticNode(n1)- // insert new- ;[n2.el, n2.anchor] = hostInsertStaticContent!(- n2.children as string,- container,- anchor,- namespace,- )- } else {- n2.el = n1.el- n2.anchor = n1.anchor- }- }-- const moveStaticNode = (- { el, anchor }: VNode,- container: RendererElement,- nextSibling: RendererNode | null,- ) => {- let next- while (el && el !== anchor) {- next = hostNextSibling(el)- hostInsert(el, container, nextSibling)- el = next- }- hostInsert(anchor!, container, nextSibling)- }-- const removeStaticNode = ({ el, anchor }: VNode) => {- let next- while (el && el !== anchor) {- next = hostNextSibling(el)- hostRemove(el)- el = next- }- hostRemove(anchor!)- }-- const processElement = (- n1: VNode | null,- n2: VNode,- container: RendererElement,- anchor: RendererNode | null,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- slotScopeIds: string[] | null,- optimized: boolean,- ) => {- if (n2.type === 'svg') {- namespace = 'svg'- } else if (n2.type === 'math') {- namespace = 'mathml'- }-- if (n1 == null) {- mountElement(- n2,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- } else {- patchElement(- n1,- n2,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- }- }-- const mountElement = (- vnode: VNode,- container: RendererElement,- anchor: RendererNode | null,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- slotScopeIds: string[] | null,- optimized: boolean,- ) => {- let el: RendererElement- let vnodeHook: VNodeHook | undefined | null- const { props, shapeFlag, transition, dirs } = vnode-- el = vnode.el = hostCreateElement(- vnode.type as string,- namespace,- props && props.is,- props,- )-- // mount children first, since some props may rely on child content- // being already rendered, e.g. `<select value>`- if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {- hostSetElementText(el, vnode.children as string)- } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {- mountChildren(- vnode.children as VNodeArrayChildren,- el,- null,- parentComponent,- parentSuspense,- resolveChildrenNamespace(vnode, namespace),- slotScopeIds,- optimized,- )- }-- if (dirs) {- invokeDirectiveHook(vnode, null, parentComponent, 'created')- }- // scopeId- setScopeId(el, vnode, vnode.scopeId, slotScopeIds, parentComponent)- // props- if (props) {- for (const key in props) {- if (key !== 'value' && !isReservedProp(key)) {- hostPatchProp(el, key, null, props[key], namespace, parentComponent)- }- }- /**- * Special case for setting value on DOM elements:- * - it can be order-sensitive (e.g. should be set *after* min/max, #2325, #4024)- * - it needs to be forced (#1471)- * #2353 proposes adding another renderer option to configure this, but- * the properties affects are so finite it is worth special casing it- * here to reduce the complexity. (Special casing it also should not- * affect non-DOM renderers)- */- if ('value' in props) {- hostPatchProp(el, 'value', null, props.value, namespace)- }- if ((vnodeHook = props.onVnodeBeforeMount)) {- invokeVNodeHook(vnodeHook, parentComponent, vnode)- }- }-- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {- def(el, '__vnode', vnode, true)- def(el, '__vueParentComponent', parentComponent, true)- }-- if (dirs) {- invokeDirectiveHook(vnode, null, parentComponent, 'beforeMount')- }- // #1583 For inside suspense + suspense not resolved case, enter hook should call when suspense resolved- // #1689 For inside suspense + suspense resolved case, just call it- const needCallTransitionHooks = needTransition(parentSuspense, transition)- if (needCallTransitionHooks) {- transition!.beforeEnter(el)- }- hostInsert(el, container, anchor)- if (- (vnodeHook = props && props.onVnodeMounted) ||- needCallTransitionHooks ||- dirs- ) {- queuePostRenderEffect(() => {- vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)- needCallTransitionHooks && transition!.enter(el)- dirs && invokeDirectiveHook(vnode, null, parentComponent, 'mounted')- }, parentSuspense)- }- }-- const setScopeId = (- el: RendererElement,- vnode: VNode,- scopeId: string | null,- slotScopeIds: string[] | null,- parentComponent: ComponentInternalInstance | null,- ) => {- if (scopeId) {- hostSetScopeId(el, scopeId)- }- if (slotScopeIds) {- for (let i = 0; i < slotScopeIds.length; i++) {- hostSetScopeId(el, slotScopeIds[i])- }- }- if (parentComponent) {- let subTree = parentComponent.subTree- if (- __DEV__ &&- subTree.patchFlag > 0 &&- subTree.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT- ) {- subTree =- filterSingleRoot(subTree.children as VNodeArrayChildren) || subTree- }- if (- vnode === subTree ||- (isSuspense(subTree.type) &&- (subTree.ssContent === vnode || subTree.ssFallback === vnode))- ) {- const parentVNode = parentComponent.vnode- setScopeId(- el,- parentVNode,- parentVNode.scopeId,- parentVNode.slotScopeIds,- parentComponent.parent,- )- }- }- }-- const mountChildren: MountChildrenFn = (- children,- container,- anchor,- parentComponent,- parentSuspense,- namespace: ElementNamespace,- slotScopeIds,- optimized,- start = 0,- ) => {- for (let i = start; i < children.length; i++) {- const child = (children[i] = optimized- ? cloneIfMounted(children[i] as VNode)- : normalizeVNode(children[i]))- patch(- null,- child,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- }- }-- const patchElement = (- n1: VNode,- n2: VNode,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- slotScopeIds: string[] | null,- optimized: boolean,- ) => {- const el = (n2.el = n1.el!)- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {- el.__vnode = n2- }- let { patchFlag, dynamicChildren, dirs } = n2- // #1426 take the old vnode's patch flag into account since user may clone a- // compiler-generated vnode, which de-opts to FULL_PROPS- patchFlag |= n1.patchFlag & PatchFlags.FULL_PROPS- const oldProps = n1.props || EMPTY_OBJ- const newProps = n2.props || EMPTY_OBJ- let vnodeHook: VNodeHook | undefined | null-- // disable recurse in beforeUpdate hooks- parentComponent && toggleRecurse(parentComponent, false)- if ((vnodeHook = newProps.onVnodeBeforeUpdate)) {- invokeVNodeHook(vnodeHook, parentComponent, n2, n1)- }- if (dirs) {- invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate')- }- parentComponent && toggleRecurse(parentComponent, true)-- if (__DEV__ && isHmrUpdating) {- // HMR updated, force full diff- patchFlag = 0- optimized = false- dynamicChildren = null- }-- // #9135 innerHTML / textContent unset needs to happen before possible- // new children mount- if (- (oldProps.innerHTML && newProps.innerHTML == null) ||- (oldProps.textContent && newProps.textContent == null)- ) {- hostSetElementText(el, '')- }-- if (dynamicChildren) {- patchBlockChildren(- n1.dynamicChildren!,- dynamicChildren,- el,- parentComponent,- parentSuspense,- resolveChildrenNamespace(n2, namespace),- slotScopeIds,- )- if (__DEV__) {- // necessary for HMR- traverseStaticChildren(n1, n2)- }- } else if (!optimized) {- // full diff- patchChildren(- n1,- n2,- el,- null,- parentComponent,- parentSuspense,- resolveChildrenNamespace(n2, namespace),- slotScopeIds,- false,- )- }-- if (patchFlag > 0) {- // the presence of a patchFlag means this element's render code was- // generated by the compiler and can take the fast path.- // in this path old node and new node are guaranteed to have the same shape- // (i.e. at the exact same position in the source template)- if (patchFlag & PatchFlags.FULL_PROPS) {- // element props contain dynamic keys, full diff needed- patchProps(el, oldProps, newProps, parentComponent, namespace)- } else {- // class- // this flag is matched when the element has dynamic class bindings.- if (patchFlag & PatchFlags.CLASS) {- if (oldProps.class !== newProps.class) {- hostPatchProp(el, 'class', null, newProps.class, namespace)- }- }-- // style- // this flag is matched when the element has dynamic style bindings- if (patchFlag & PatchFlags.STYLE) {- hostPatchProp(el, 'style', oldProps.style, newProps.style, namespace)- }-- // props- // This flag is matched when the element has dynamic prop/attr bindings- // other than class and style. The keys of dynamic prop/attrs are saved for- // faster iteration.- // Note dynamic keys like :[foo]="bar" will cause this optimization to- // bail out and go through a full diff because we need to unset the old key- if (patchFlag & PatchFlags.PROPS) {- // if the flag is present then dynamicProps must be non-null- const propsToUpdate = n2.dynamicProps!- for (let i = 0; i < propsToUpdate.length; i++) {- const key = propsToUpdate[i]- const prev = oldProps[key]- const next = newProps[key]- // #1471 force patch value- if (next !== prev || key === 'value') {- hostPatchProp(el, key, prev, next, namespace, parentComponent)- }- }- }- }-- // text- // This flag is matched when the element has only dynamic text children.- if (patchFlag & PatchFlags.TEXT) {- if (n1.children !== n2.children) {- hostSetElementText(el, n2.children as string)- }- }- } else if (!optimized && dynamicChildren == null) {- // unoptimized, full diff- patchProps(el, oldProps, newProps, parentComponent, namespace)- }-- if ((vnodeHook = newProps.onVnodeUpdated) || dirs) {- queuePostRenderEffect(() => {- vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, n2, n1)- dirs && invokeDirectiveHook(n2, n1, parentComponent, 'updated')- }, parentSuspense)- }- }-- // The fast path for blocks.- const patchBlockChildren: PatchBlockChildrenFn = (- oldChildren,- newChildren,- fallbackContainer,- parentComponent,- parentSuspense,- namespace: ElementNamespace,- slotScopeIds,- ) => {- for (let i = 0; i < newChildren.length; i++) {- const oldVNode = oldChildren[i]- const newVNode = newChildren[i]- // Determine the container (parent element) for the patch.- const container =- // oldVNode may be an errored async setup() component inside Suspense- // which will not have a mounted element- oldVNode.el &&- // - In the case of a Fragment, we need to provide the actual parent- // of the Fragment itself so it can move its children.- (oldVNode.type === Fragment ||- // - In the case of different nodes, there is going to be a replacement- // which also requires the correct parent container- !isSameVNodeType(oldVNode, newVNode) ||- // - In the case of a component, it could contain anything.- oldVNode.shapeFlag & (ShapeFlags.COMPONENT | ShapeFlags.TELEPORT))- ? hostParentNode(oldVNode.el)!- : // In other cases, the parent container is not actually used so we- // just pass the block element here to avoid a DOM parentNode call.- fallbackContainer- patch(- oldVNode,- newVNode,- container,- null,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- true,- )- }- }-- const patchProps = (- el: RendererElement,- oldProps: Data,- newProps: Data,- parentComponent: ComponentInternalInstance | null,- namespace: ElementNamespace,- ) => {- if (oldProps !== newProps) {- if (oldProps !== EMPTY_OBJ) {- for (const key in oldProps) {- if (!isReservedProp(key) && !(key in newProps)) {- hostPatchProp(- el,- key,- oldProps[key],- null,- namespace,- parentComponent,- )- }- }- }- for (const key in newProps) {- // empty string is not valid prop- if (isReservedProp(key)) continue- const next = newProps[key]- const prev = oldProps[key]- // defer patching value- if (next !== prev && key !== 'value') {- hostPatchProp(el, key, prev, next, namespace, parentComponent)- }- }- if ('value' in newProps) {- hostPatchProp(el, 'value', oldProps.value, newProps.value, namespace)- }- }- }-- const processFragment = (- n1: VNode | null,- n2: VNode,- container: RendererElement,- anchor: RendererNode | null,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- slotScopeIds: string[] | null,- optimized: boolean,- ) => {- const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateText(''))!- const fragmentEndAnchor = (n2.anchor = n1 ? n1.anchor : hostCreateText(''))!-- let { patchFlag, dynamicChildren, slotScopeIds: fragmentSlotScopeIds } = n2-- if (- __DEV__ &&- // #5523 dev root fragment may inherit directives- (isHmrUpdating || patchFlag & PatchFlags.DEV_ROOT_FRAGMENT)- ) {- // HMR updated / Dev root fragment (w/ comments), force full diff- patchFlag = 0- optimized = false- dynamicChildren = null- }-- // check if this is a slot fragment with :slotted scope ids- if (fragmentSlotScopeIds) {- slotScopeIds = slotScopeIds- ? slotScopeIds.concat(fragmentSlotScopeIds)- : fragmentSlotScopeIds- }-- if (n1 == null) {- hostInsert(fragmentStartAnchor, container, anchor)- hostInsert(fragmentEndAnchor, container, anchor)- // a fragment can only have array children- // since they are either generated by the compiler, or implicitly created- // from arrays.- mountChildren(- // #10007- // such fragment like `<></>` will be compiled into- // a fragment which doesn't have a children.- // In this case fallback to an empty array- (n2.children || []) as VNodeArrayChildren,- container,- fragmentEndAnchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- } else {- if (- patchFlag > 0 &&- patchFlag & PatchFlags.STABLE_FRAGMENT &&- dynamicChildren &&- // #2715 the previous fragment could've been a BAILed one as a result- // of renderSlot() with no valid children- n1.dynamicChildren- ) {- // a stable fragment (template root or <template v-for>) doesn't need to- // patch children order, but it may contain dynamicChildren.- patchBlockChildren(- n1.dynamicChildren,- dynamicChildren,- container,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- )- if (__DEV__) {- // necessary for HMR- traverseStaticChildren(n1, n2)- } else if (- // #2080 if the stable fragment has a key, it's a <template v-for> that may- // get moved around. Make sure all root level vnodes inherit el.- // #2134 or if it's a component root, it may also get moved around- // as the component is being moved.- n2.key != null ||- (parentComponent && n2 === parentComponent.subTree)- ) {- traverseStaticChildren(n1, n2, true /* shallow */)- }- } else {- // keyed / unkeyed, or manual fragments.- // for keyed & unkeyed, since they are compiler generated from v-for,- // each child is guaranteed to be a block so the fragment will never- // have dynamicChildren.- patchChildren(- n1,- n2,- container,- fragmentEndAnchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- }- }- }-- const processComponent = (- n1: VNode | null,- n2: VNode,- container: RendererElement,- anchor: RendererNode | null,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- slotScopeIds: string[] | null,- optimized: boolean,- ) => {- n2.slotScopeIds = slotScopeIds- if (n1 == null) {- if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {- ;(parentComponent!.ctx as KeepAliveContext).activate(- n2,- container,- anchor,- namespace,- optimized,- )- } else {- mountComponent(- n2,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- optimized,- )- }- } else {- updateComponent(n1, n2, optimized)- }- }-- const mountComponent: MountComponentFn = (- initialVNode,- container,- anchor,- parentComponent,- parentSuspense,- namespace: ElementNamespace,- optimized,- ) => {- // 2.x compat may pre-create the component instance before actually- // mounting- const compatMountInstance =- __COMPAT__ && initialVNode.isCompatRoot && initialVNode.component- const instance: ComponentInternalInstance =- compatMountInstance ||- (initialVNode.component = createComponentInstance(- initialVNode,- parentComponent,- parentSuspense,- ))-- if (__DEV__ && instance.type.__hmrId) {- registerHMR(instance)- }-- if (__DEV__) {- pushWarningContext(initialVNode)- startMeasure(instance, `mount`)- }-- // inject renderer internals for keepAlive- if (isKeepAlive(initialVNode)) {- ;(instance.ctx as KeepAliveContext).renderer = internals- }-- // resolve props and slots for setup context- if (!(__COMPAT__ && compatMountInstance)) {- if (__DEV__) {- startMeasure(instance, `init`)- }- setupComponent(instance, false, optimized)- if (__DEV__) {- endMeasure(instance, `init`)- }- }-- // setup() is async. This component relies on async logic to be resolved- // before proceeding- if (__FEATURE_SUSPENSE__ && instance.asyncDep) {- // avoid hydration for hmr updating- if (__DEV__ && isHmrUpdating) initialVNode.el = null-- parentSuspense &&- parentSuspense.registerDep(instance, setupRenderEffect, optimized)-- // Give it a placeholder if this is not hydration- // TODO handle self-defined fallback- if (!initialVNode.el) {- const placeholder = (instance.subTree = createVNode(Comment))- processCommentNode(null, placeholder, container!, anchor)- }- } else {- setupRenderEffect(- instance,- initialVNode,- container,- anchor,- parentSuspense,- namespace,- optimized,- )- }-- if (__DEV__) {- popWarningContext()- endMeasure(instance, `mount`)- }- }-- const updateComponent = (n1: VNode, n2: VNode, optimized: boolean) => {- const instance = (n2.component = n1.component)!- if (shouldUpdateComponent(n1, n2, optimized)) {- if (- __FEATURE_SUSPENSE__ &&- instance.asyncDep &&- !instance.asyncResolved- ) {- // async & still pending - just update props and slots- // since the component's reactive effect for render isn't set-up yet- if (__DEV__) {- pushWarningContext(n2)- }- updateComponentPreRender(instance, n2, optimized)- if (__DEV__) {- popWarningContext()- }- return- } else {- // normal update- instance.next = n2- // instance.update is the reactive effect.- instance.update()- }- } else {- // no update needed. just copy over properties- n2.el = n1.el- instance.vnode = n2- }- }-- const setupRenderEffect: SetupRenderEffectFn = (- instance,- initialVNode,- container,- anchor,- parentSuspense,- namespace: ElementNamespace,- optimized,- ) => {- const componentUpdateFn = () => {- if (!instance.isMounted) {- let vnodeHook: VNodeHook | null | undefined- const { el, props } = initialVNode- const { bm, m, parent, root, type } = instance- const isAsyncWrapperVNode = isAsyncWrapper(initialVNode)-- toggleRecurse(instance, false)- // beforeMount hook- if (bm) {- invokeArrayFns(bm)- }- // onVnodeBeforeMount- if (- !isAsyncWrapperVNode &&- (vnodeHook = props && props.onVnodeBeforeMount)- ) {- invokeVNodeHook(vnodeHook, parent, initialVNode)- }- if (- __COMPAT__ &&- isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)- ) {- instance.emit('hook:beforeMount')- }- toggleRecurse(instance, true)-- if (el && hydrateNode) {- // vnode has adopted host node - perform hydration instead of mount.- const hydrateSubTree = () => {- if (__DEV__) {- startMeasure(instance, `render`)- }- instance.subTree = renderComponentRoot(instance)- if (__DEV__) {- endMeasure(instance, `render`)- }- if (__DEV__) {- startMeasure(instance, `hydrate`)- }- hydrateNode!(- el as Node,- instance.subTree,- instance,- parentSuspense,- null,- )- if (__DEV__) {- endMeasure(instance, `hydrate`)- }- }-- if (- isAsyncWrapperVNode &&- (type as ComponentOptions).__asyncHydrate- ) {- ;(type as ComponentOptions).__asyncHydrate!(- el as Element,- instance,- hydrateSubTree,- )- } else {- hydrateSubTree()- }- } else {- // custom element style injection- if (root.ce) {- root.ce._injectChildStyle(type)- }-- if (__DEV__) {- startMeasure(instance, `render`)- }- const subTree = (instance.subTree = renderComponentRoot(instance))- if (__DEV__) {- endMeasure(instance, `render`)- }- if (__DEV__) {- startMeasure(instance, `patch`)- }- patch(- null,- subTree,- container,- anchor,- instance,- parentSuspense,- namespace,- )- if (__DEV__) {- endMeasure(instance, `patch`)- }- initialVNode.el = subTree.el- }- // mounted hook- if (m) {- queuePostRenderEffect(m, parentSuspense)- }- // onVnodeMounted- if (- !isAsyncWrapperVNode &&- (vnodeHook = props && props.onVnodeMounted)- ) {- const scopedInitialVNode = initialVNode- queuePostRenderEffect(- () => invokeVNodeHook(vnodeHook!, parent, scopedInitialVNode),- parentSuspense,- )- }- if (- __COMPAT__ &&- isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)- ) {- queuePostRenderEffect(- () => instance.emit('hook:mounted'),- parentSuspense,- )- }-- // activated hook for keep-alive roots.- // #1742 activated hook must be accessed after first render- // since the hook may be injected by a child keep-alive- if (- initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE ||- (parent &&- isAsyncWrapper(parent.vnode) &&- parent.vnode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE)- ) {- instance.a && queuePostRenderEffect(instance.a, parentSuspense)- if (- __COMPAT__ &&- isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)- ) {- queuePostRenderEffect(- () => instance.emit('hook:activated'),- parentSuspense,- )- }- }- instance.isMounted = true-- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {- devtoolsComponentAdded(instance)- }-- // #2458: deference mount-only object parameters to prevent memleaks- initialVNode = container = anchor = null as any- } else {- let { next, bu, u, parent, vnode } = instance-- if (__FEATURE_SUSPENSE__) {- const nonHydratedAsyncRoot = locateNonHydratedAsyncRoot(instance)- // we are trying to update some async comp before hydration- // this will cause crash because we don't know the root node yet- if (nonHydratedAsyncRoot) {- // only sync the properties and abort the rest of operations- if (next) {- next.el = vnode.el- updateComponentPreRender(instance, next, optimized)- }- // and continue the rest of operations once the deps are resolved- nonHydratedAsyncRoot.asyncDep!.then(() => {- // the instance may be destroyed during the time period- if (!instance.isUnmounted) {- componentUpdateFn()- }- })- return- }- }-- // updateComponent- // This is triggered by mutation of component's own state (next: null)- // OR parent calling processComponent (next: VNode)- let originNext = next- let vnodeHook: VNodeHook | null | undefined- if (__DEV__) {- pushWarningContext(next || instance.vnode)- }-- // Disallow component effect recursion during pre-lifecycle hooks.- toggleRecurse(instance, false)- if (next) {- next.el = vnode.el- updateComponentPreRender(instance, next, optimized)- } else {- next = vnode- }-- // beforeUpdate hook- if (bu) {- invokeArrayFns(bu)- }- // onVnodeBeforeUpdate- if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) {- invokeVNodeHook(vnodeHook, parent, next, vnode)- }- if (- __COMPAT__ &&- isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)- ) {- instance.emit('hook:beforeUpdate')- }- toggleRecurse(instance, true)-- // render- if (__DEV__) {- startMeasure(instance, `render`)- }- const nextTree = renderComponentRoot(instance)- if (__DEV__) {- endMeasure(instance, `render`)- }- const prevTree = instance.subTree- instance.subTree = nextTree-- if (__DEV__) {- startMeasure(instance, `patch`)- }- patch(- prevTree,- nextTree,- // parent may have changed if it's in a teleport- hostParentNode(prevTree.el!)!,- // anchor may have changed if it's in a fragment- getNextHostNode(prevTree),- instance,- parentSuspense,- namespace,- )- if (__DEV__) {- endMeasure(instance, `patch`)- }- next.el = nextTree.el- if (originNext === null) {- // self-triggered update. In case of HOC, update parent component- // vnode el. HOC is indicated by parent instance's subTree pointing- // to child component's vnode- updateHOCHostEl(instance, nextTree.el)- }- // updated hook- if (u) {- queuePostRenderEffect(u, parentSuspense)- }- // onVnodeUpdated- if ((vnodeHook = next.props && next.props.onVnodeUpdated)) {- queuePostRenderEffect(- () => invokeVNodeHook(vnodeHook!, parent, next!, vnode),- parentSuspense,- )- }- if (- __COMPAT__ &&- isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)- ) {- queuePostRenderEffect(- () => instance.emit('hook:updated'),- parentSuspense,- )- }-- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {- devtoolsComponentUpdated(instance)- }-- if (__DEV__) {- popWarningContext()- }- }- }-- // create reactive effect for rendering- instance.scope.on()- const effect = (instance.effect = new ReactiveEffect(componentUpdateFn))- instance.scope.off()-- const update = (instance.update = effect.run.bind(effect))- const job: SchedulerJob = (instance.job = effect.runIfDirty.bind(effect))- job.i = instance- job.id = instance.uid- effect.scheduler = () => queueJob(job)-- // allowRecurse- // #1801, #2043 component render effects should allow recursive updates- toggleRecurse(instance, true)-- if (__DEV__) {- effect.onTrack = instance.rtc- ? e => invokeArrayFns(instance.rtc!, e)- : void 0- effect.onTrigger = instance.rtg- ? e => invokeArrayFns(instance.rtg!, e)- : void 0- }-- update()- }-- const updateComponentPreRender = (- instance: ComponentInternalInstance,- nextVNode: VNode,- optimized: boolean,- ) => {- nextVNode.component = instance- const prevProps = instance.vnode.props- instance.vnode = nextVNode- instance.next = null- updateProps(instance, nextVNode.props, prevProps, optimized)- updateSlots(instance, nextVNode.children, optimized)-- pauseTracking()- // props update may have triggered pre-flush watchers.- // flush them before the render update.- flushPreFlushCbs(instance)- resetTracking()- }-- const patchChildren: PatchChildrenFn = (- n1,- n2,- container,- anchor,- parentComponent,- parentSuspense,- namespace: ElementNamespace,- slotScopeIds,- optimized = false,- ) => {- const c1 = n1 && n1.children- const prevShapeFlag = n1 ? n1.shapeFlag : 0- const c2 = n2.children-- const { patchFlag, shapeFlag } = n2- // fast path- if (patchFlag > 0) {- if (patchFlag & PatchFlags.KEYED_FRAGMENT) {- // this could be either fully-keyed or mixed (some keyed some not)- // presence of patchFlag means children are guaranteed to be arrays- patchKeyedChildren(- c1 as VNode[],- c2 as VNodeArrayChildren,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- return- } else if (patchFlag & PatchFlags.UNKEYED_FRAGMENT) {- // unkeyed- patchUnkeyedChildren(- c1 as VNode[],- c2 as VNodeArrayChildren,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- return- }- }-- // children has 3 possibilities: text, array or no children.- if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {- // text children fast path- if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {- unmountChildren(c1 as VNode[], parentComponent, parentSuspense)- }- if (c2 !== c1) {- hostSetElementText(container, c2 as string)- }- } else {- if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {- // prev children was array- if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {- // two arrays, cannot assume anything, do full diff- patchKeyedChildren(- c1 as VNode[],- c2 as VNodeArrayChildren,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- } else {- // no new children, just unmount old- unmountChildren(c1 as VNode[], parentComponent, parentSuspense, true)- }- } else {- // prev children was text OR null- // new children is array OR null- if (prevShapeFlag & ShapeFlags.TEXT_CHILDREN) {- hostSetElementText(container, '')- }- // mount new if array- if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {- mountChildren(- c2 as VNodeArrayChildren,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- }- }- }- }-- const patchUnkeyedChildren = (- c1: VNode[],- c2: VNodeArrayChildren,- container: RendererElement,- anchor: RendererNode | null,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- slotScopeIds: string[] | null,- optimized: boolean,- ) => {- c1 = c1 || EMPTY_ARR- c2 = c2 || EMPTY_ARR- const oldLength = c1.length- const newLength = c2.length- const commonLength = Math.min(oldLength, newLength)- let i- for (i = 0; i < commonLength; i++) {- const nextChild = (c2[i] = optimized- ? cloneIfMounted(c2[i] as VNode)- : normalizeVNode(c2[i]))- patch(- c1[i],- nextChild,- container,- null,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- }- if (oldLength > newLength) {- // remove old- unmountChildren(- c1,- parentComponent,- parentSuspense,- true,- false,- commonLength,- )- } else {- // mount new- mountChildren(- c2,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- commonLength,- )- }- }-- // can be all-keyed or mixed- const patchKeyedChildren = (- c1: VNode[],- c2: VNodeArrayChildren,- container: RendererElement,- parentAnchor: RendererNode | null,- parentComponent: ComponentInternalInstance | null,- parentSuspense: SuspenseBoundary | null,- namespace: ElementNamespace,- slotScopeIds: string[] | null,- optimized: boolean,- ) => {- let i = 0- const l2 = c2.length- let e1 = c1.length - 1 // prev ending index- let e2 = l2 - 1 // next ending index-- // 1. sync from start- // (a b) c- // (a b) d e- while (i <= e1 && i <= e2) {- const n1 = c1[i]- const n2 = (c2[i] = optimized- ? cloneIfMounted(c2[i] as VNode)- : normalizeVNode(c2[i]))- if (isSameVNodeType(n1, n2)) {- patch(- n1,- n2,- container,- null,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- } else {- break- }- i++- }-- // 2. sync from end- // a (b c)- // d e (b c)- while (i <= e1 && i <= e2) {- const n1 = c1[e1]- const n2 = (c2[e2] = optimized- ? cloneIfMounted(c2[e2] as VNode)- : normalizeVNode(c2[e2]))- if (isSameVNodeType(n1, n2)) {- patch(- n1,- n2,- container,- null,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- } else {- break- }- e1--- e2--- }-- // 3. common sequence + mount- // (a b)- // (a b) c- // i = 2, e1 = 1, e2 = 2- // (a b)- // c (a b)- // i = 0, e1 = -1, e2 = 0- if (i > e1) {- if (i <= e2) {- const nextPos = e2 + 1- const anchor = nextPos < l2 ? (c2[nextPos] as VNode).el : parentAnchor- while (i <= e2) {- patch(- null,- (c2[i] = optimized- ? cloneIfMounted(c2[i] as VNode)- : normalizeVNode(c2[i])),- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- i++- }- }- }-- // 4. common sequence + unmount- // (a b) c- // (a b)- // i = 2, e1 = 2, e2 = 1- // a (b c)- // (b c)- // i = 0, e1 = 0, e2 = -1- else if (i > e2) {- while (i <= e1) {- unmount(c1[i], parentComponent, parentSuspense, true)- i++- }- }-- // 5. unknown sequence- // [i ... e1 + 1]: a b [c d e] f g- // [i ... e2 + 1]: a b [e d c h] f g- // i = 2, e1 = 4, e2 = 5- else {- const s1 = i // prev starting index- const s2 = i // next starting index-- // 5.1 build key:index map for newChildren- const keyToNewIndexMap: Map<PropertyKey, number> = new Map()- for (i = s2; i <= e2; i++) {- const nextChild = (c2[i] = optimized- ? cloneIfMounted(c2[i] as VNode)- : normalizeVNode(c2[i]))- if (nextChild.key != null) {- if (__DEV__ && keyToNewIndexMap.has(nextChild.key)) {- warn(- `Duplicate keys found during update:`,- JSON.stringify(nextChild.key),- `Make sure keys are unique.`,- )- }- keyToNewIndexMap.set(nextChild.key, i)- }- }-- // 5.2 loop through old children left to be patched and try to patch- // matching nodes & remove nodes that are no longer present- let j- let patched = 0- const toBePatched = e2 - s2 + 1- let moved = false- // used to track whether any node has moved- let maxNewIndexSoFar = 0- // works as Map<newIndex, oldIndex>- // Note that oldIndex is offset by +1- // and oldIndex = 0 is a special value indicating the new node has- // no corresponding old node.- // used for determining longest stable subsequence- const newIndexToOldIndexMap = new Array(toBePatched)- for (i = 0; i < toBePatched; i++) newIndexToOldIndexMap[i] = 0-- for (i = s1; i <= e1; i++) {- const prevChild = c1[i]- if (patched >= toBePatched) {- // all new children have been patched so this can only be a removal- unmount(prevChild, parentComponent, parentSuspense, true)- continue- }- let newIndex- if (prevChild.key != null) {- newIndex = keyToNewIndexMap.get(prevChild.key)- } else {- // key-less node, try to locate a key-less node of the same type- for (j = s2; j <= e2; j++) {- if (- newIndexToOldIndexMap[j - s2] === 0 &&- isSameVNodeType(prevChild, c2[j] as VNode)- ) {- newIndex = j- break- }- }- }- if (newIndex === undefined) {- unmount(prevChild, parentComponent, parentSuspense, true)- } else {- newIndexToOldIndexMap[newIndex - s2] = i + 1- if (newIndex >= maxNewIndexSoFar) {- maxNewIndexSoFar = newIndex- } else {- moved = true- }- patch(- prevChild,- c2[newIndex] as VNode,- container,- null,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- patched++- }- }-- // 5.3 move and mount- // generate longest stable subsequence only when nodes have moved- const increasingNewIndexSequence = moved- ? getSequence(newIndexToOldIndexMap)- : EMPTY_ARR- j = increasingNewIndexSequence.length - 1- // looping backwards so that we can use last patched node as anchor- for (i = toBePatched - 1; i >= 0; i--) {- const nextIndex = s2 + i- const nextChild = c2[nextIndex] as VNode- const anchor =- nextIndex + 1 < l2 ? (c2[nextIndex + 1] as VNode).el : parentAnchor- if (newIndexToOldIndexMap[i] === 0) {- // mount new- patch(- null,- nextChild,- container,- anchor,- parentComponent,- parentSuspense,- namespace,- slotScopeIds,- optimized,- )- } else if (moved) {- // move if:- // There is no stable subsequence (e.g. a reverse)- // OR current node is not among the stable sequence- if (j < 0 || i !== increasingNewIndexSequence[j]) {- move(nextChild, container, anchor, MoveType.REORDER)- } else {- j--- }- }- }- }- }-- const move: MoveFn = (- vnode,- container,- anchor,- moveType,- parentSuspense = null,- ) => {- const { el, type, transition, children, shapeFlag } = vnode- if (shapeFlag & ShapeFlags.COMPONENT) {- move(vnode.component!.subTree, container, anchor, moveType)- return- }-- if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {- vnode.suspense!.move(container, anchor, moveType)- return- }-- if (shapeFlag & ShapeFlags.TELEPORT) {- ;(type as typeof TeleportImpl).move(vnode, container, anchor, internals)- return- }-- if (type === Fragment) {- hostInsert(el!, container, anchor)- for (let i = 0; i < (children as VNode[]).length; i++) {- move((children as VNode[])[i], container, anchor, moveType)- }- hostInsert(vnode.anchor!, container, anchor)- return- }-- if (type === Static) {- moveStaticNode(vnode, container, anchor)- return- }-- // single nodes- const needTransition =- moveType !== MoveType.REORDER &&- shapeFlag & ShapeFlags.ELEMENT &&- transition- if (needTransition) {- if (moveType === MoveType.ENTER) {- transition!.beforeEnter(el!)- hostInsert(el!, container, anchor)- queuePostRenderEffect(() => transition!.enter(el!), parentSuspense)- } else {- const { leave, delayLeave, afterLeave } = transition!- const remove = () => hostInsert(el!, container, anchor)- const performLeave = () => {- leave(el!, () => {- remove()- afterLeave && afterLeave()- })- }- if (delayLeave) {- delayLeave(el!, remove, performLeave)- } else {- performLeave()- }- }- } else {- hostInsert(el!, container, anchor)- }- }-- const unmount: UnmountFn = (- vnode,- parentComponent,- parentSuspense,- doRemove = false,- optimized = false,- ) => {- const {- type,- props,- ref,- children,- dynamicChildren,- shapeFlag,- patchFlag,- dirs,- cacheIndex,- } = vnode-- if (patchFlag === PatchFlags.BAIL) {- optimized = false- }-- // unset ref- if (ref != null) {- setRef(ref, null, parentSuspense, vnode, true)- }-- // #6593 should clean memo cache when unmount- if (cacheIndex != null) {- parentComponent!.renderCache[cacheIndex] = undefined- }-- if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {- ;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)- return- }-- const shouldInvokeDirs = shapeFlag & ShapeFlags.ELEMENT && dirs- const shouldInvokeVnodeHook = !isAsyncWrapper(vnode)-- let vnodeHook: VNodeHook | undefined | null- if (- shouldInvokeVnodeHook &&- (vnodeHook = props && props.onVnodeBeforeUnmount)- ) {- invokeVNodeHook(vnodeHook, parentComponent, vnode)- }-- if (shapeFlag & ShapeFlags.COMPONENT) {- unmountComponent(vnode.component!, parentSuspense, doRemove)- } else {- if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {- vnode.suspense!.unmount(parentSuspense, doRemove)- return- }-- if (shouldInvokeDirs) {- invokeDirectiveHook(vnode, null, parentComponent, 'beforeUnmount')- }-- if (shapeFlag & ShapeFlags.TELEPORT) {- ;(vnode.type as typeof TeleportImpl).remove(- vnode,- parentComponent,- parentSuspense,- internals,- doRemove,- )- } else if (- dynamicChildren &&- // #5154- // when v-once is used inside a block, setBlockTracking(-1) marks the- // parent block with hasOnce: true- // so that it doesn't take the fast path during unmount - otherwise- // components nested in v-once are never unmounted.- !dynamicChildren.hasOnce &&- // #1153: fast path should not be taken for non-stable (v-for) fragments- (type !== Fragment ||- (patchFlag > 0 && patchFlag & PatchFlags.STABLE_FRAGMENT))- ) {- // fast path for block nodes: only need to unmount dynamic children.- unmountChildren(- dynamicChildren,- parentComponent,- parentSuspense,- false,- true,- )- } else if (- (type === Fragment &&- patchFlag &- (PatchFlags.KEYED_FRAGMENT | PatchFlags.UNKEYED_FRAGMENT)) ||- (!optimized && shapeFlag & ShapeFlags.ARRAY_CHILDREN)- ) {- unmountChildren(children as VNode[], parentComponent, parentSuspense)- }-- if (doRemove) {- remove(vnode)- }- }-- if (- (shouldInvokeVnodeHook &&- (vnodeHook = props && props.onVnodeUnmounted)) ||- shouldInvokeDirs- ) {- queuePostRenderEffect(() => {- vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)- shouldInvokeDirs &&- invokeDirectiveHook(vnode, null, parentComponent, 'unmounted')- }, parentSuspense)- }- }-- const remove: RemoveFn = vnode => {- const { type, el, anchor, transition } = vnode- if (type === Fragment) {- if (- __DEV__ &&- vnode.patchFlag > 0 &&- vnode.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT &&- transition &&- !transition.persisted- ) {- ;(vnode.children as VNode[]).forEach(child => {- if (child.type === Comment) {- hostRemove(child.el!)- } else {- remove(child)- }- })- } else {- removeFragment(el!, anchor!)- }- return- }-- if (type === Static) {- removeStaticNode(vnode)- return- }-- const performRemove = () => {- hostRemove(el!)- if (transition && !transition.persisted && transition.afterLeave) {- transition.afterLeave()- }- }-- if (- vnode.shapeFlag & ShapeFlags.ELEMENT &&- transition &&- !transition.persisted- ) {- const { leave, delayLeave } = transition- const performLeave = () => leave(el!, performRemove)- if (delayLeave) {- delayLeave(vnode.el!, performRemove, performLeave)- } else {- performLeave()- }- } else {- performRemove()- }- }-- const removeFragment = (cur: RendererNode, end: RendererNode) => {- // For fragments, directly remove all contained DOM nodes.- // (fragment child nodes cannot have transition)- let next- while (cur !== end) {- next = hostNextSibling(cur)!- hostRemove(cur)- cur = next- }- hostRemove(end)- }-- const unmountComponent = (- instance: ComponentInternalInstance,- parentSuspense: SuspenseBoundary | null,- doRemove?: boolean,- ) => {- if (__DEV__ && instance.type.__hmrId) {- unregisterHMR(instance)- }-- const { bum, scope, job, subTree, um, m, a } = instance- invalidateMount(m)- invalidateMount(a)-- // beforeUnmount hook- if (bum) {- invokeArrayFns(bum)- }-- if (- __COMPAT__ &&- isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)- ) {- instance.emit('hook:beforeDestroy')- }-- // stop effects in component scope- scope.stop()-- // job may be null if a component is unmounted before its async- // setup has resolved.- if (job) {- // so that scheduler will no longer invoke it- job.flags! |= SchedulerJobFlags.DISPOSED- unmount(subTree, instance, parentSuspense, doRemove)- }- // unmounted hook- if (um) {- queuePostRenderEffect(um, parentSuspense)- }- if (- __COMPAT__ &&- isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)- ) {- queuePostRenderEffect(- () => instance.emit('hook:destroyed'),- parentSuspense,- )- }- queuePostRenderEffect(() => {- instance.isUnmounted = true- }, parentSuspense)-- // A component with async dep inside a pending suspense is unmounted before- // its async dep resolves. This should remove the dep from the suspense, and- // cause the suspense to resolve immediately if that was the last dep.- if (- __FEATURE_SUSPENSE__ &&- parentSuspense &&- parentSuspense.pendingBranch &&- !parentSuspense.isUnmounted &&- instance.asyncDep &&- !instance.asyncResolved &&- instance.suspenseId === parentSuspense.pendingId- ) {- parentSuspense.deps--- if (parentSuspense.deps === 0) {- parentSuspense.resolve()- }- }-- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {- devtoolsComponentRemoved(instance)- }- }-- const unmountChildren: UnmountChildrenFn = (- children,- parentComponent,- parentSuspense,- doRemove = false,- optimized = false,- start = 0,- ) => {- for (let i = start; i < children.length; i++) {- unmount(children[i], parentComponent, parentSuspense, doRemove, optimized)- }- }-- const getNextHostNode: NextFn = vnode => {- if (vnode.shapeFlag & ShapeFlags.COMPONENT) {- return getNextHostNode(vnode.component!.subTree)- }- if (__FEATURE_SUSPENSE__ && vnode.shapeFlag & ShapeFlags.SUSPENSE) {- return vnode.suspense!.next()- }- const el = hostNextSibling((vnode.anchor || vnode.el)!)- // #9071, #9313- // teleported content can mess up nextSibling searches during patch so- // we need to skip them during nextSibling search- const teleportEnd = el && el[TeleportEndKey]- return teleportEnd ? hostNextSibling(teleportEnd) : el- }-- let isFlushing = false- const render: RootRenderFunction = (vnode, container, namespace) => {- if (vnode == null) {- if (container._vnode) {- unmount(container._vnode, null, null, true)- }- } else {- patch(- container._vnode || null,- vnode,- container,- null,- null,- null,- namespace,- )- }- container._vnode = vnode- if (!isFlushing) {- isFlushing = true- flushPreFlushCbs()- flushPostFlushCbs()- isFlushing = false- }- }-- const internals: RendererInternals = {- p: patch,- um: unmount,- m: move,- r: remove,- mt: mountComponent,- mc: mountChildren,- pc: patchChildren,- pbc: patchBlockChildren,- n: getNextHostNode,- o: options,- }-- let hydrate: ReturnType<typeof createHydrationFunctions>[0] | undefined- let hydrateNode: ReturnType<typeof createHydrationFunctions>[1] | undefined- if (createHydrationFns) {- ;[hydrate, hydrateNode] = createHydrationFns(- internals as RendererInternals<Node, Element>,- )- }-- return {- render,- hydrate,- createApp: createAppAPI(render, hydrate),- }-}--function resolveChildrenNamespace(- { type, props }: VNode,- currentNamespace: ElementNamespace,-): ElementNamespace {- return (currentNamespace === 'svg' && type === 'foreignObject') ||- (currentNamespace === 'mathml' &&- type === 'annotation-xml' &&- props &&- props.encoding &&- props.encoding.includes('html'))- ? undefined- : currentNamespace-}--function toggleRecurse(- { effect, job }: ComponentInternalInstance,- allowed: boolean,-) {- if (allowed) {- effect.flags |= EffectFlags.ALLOW_RECURSE- job.flags! |= SchedulerJobFlags.ALLOW_RECURSE- } else {- effect.flags &= ~EffectFlags.ALLOW_RECURSE- job.flags! &= ~SchedulerJobFlags.ALLOW_RECURSE- }-}--export function needTransition(- parentSuspense: SuspenseBoundary | null,- transition: TransitionHooks | null,-): boolean | null {- return (- (!parentSuspense || (parentSuspense && !parentSuspense.pendingBranch)) &&- transition &&- !transition.persisted- )-}--/**- * #1156- * When a component is HMR-enabled, we need to make sure that all static nodes- * inside a block also inherit the DOM element from the previous tree so that- * HMR updates (which are full updates) can retrieve the element for patching.- *- * #2080- * Inside keyed `template` fragment static children, if a fragment is moved,- * the children will always be moved. Therefore, in order to ensure correct move- * position, el should be inherited from previous nodes.- */-export function traverseStaticChildren(- n1: VNode,- n2: VNode,- shallow = false,-): void {- const ch1 = n1.children- const ch2 = n2.children- if (isArray(ch1) && isArray(ch2)) {- for (let i = 0; i < ch1.length; i++) {- // this is only called in the optimized path so array children are- // guaranteed to be vnodes- const c1 = ch1[i] as VNode- let c2 = ch2[i] as VNode- if (c2.shapeFlag & ShapeFlags.ELEMENT && !c2.dynamicChildren) {- if (c2.patchFlag <= 0 || c2.patchFlag === PatchFlags.NEED_HYDRATION) {- c2 = ch2[i] = cloneIfMounted(ch2[i] as VNode)- c2.el = c1.el- }- if (!shallow && c2.patchFlag !== PatchFlags.BAIL)- traverseStaticChildren(c1, c2)- }- // #6852 also inherit for text nodes- if (c2.type === Text) {- c2.el = c1.el- }- // also inherit for comment nodes, but not placeholders (e.g. v-if which- // would have received .el during block patch)- if (__DEV__ && c2.type === Comment && !c2.el) {- c2.el = c1.el- }- }- }-}--// https://en.wikipedia.org/wiki/Longest_increasing_subsequence-function getSequence(arr: number[]): number[] {- const p = arr.slice()- const result = [0]- let i, j, u, v, c- const len = arr.length- for (i = 0; i < len; i++) {- const arrI = arr[i]- if (arrI !== 0) {- j = result[result.length - 1]- if (arr[j] < arrI) {- p[i] = j- result.push(i)- continue- }- u = 0- v = result.length - 1- while (u < v) {- c = (u + v) >> 1- if (arr[result[c]] < arrI) {- u = c + 1- } else {- v = c- }- }- if (arrI < arr[result[u]]) {- if (u > 0) {- p[i] = result[u - 1]- }- result[u] = i- }- }- }- u = result.length- v = result[u - 1]- while (u-- > 0) {- result[u] = v- v = p[v]- }- return result-}--function locateNonHydratedAsyncRoot(- instance: ComponentInternalInstance,-): ComponentInternalInstance | undefined {- const subComponent = instance.subTree.component- if (subComponent) {- if (subComponent.asyncDep && !subComponent.asyncResolved) {- return subComponent- } else {- return locateNonHydratedAsyncRoot(subComponent)- }- }-}--export function invalidateMount(hooks: LifecycleHook): void {- if (hooks) {- for (let i = 0; i < hooks.length; i++)- hooks[i].flags! |= SchedulerJobFlags.DISPOSED- }-}
deps/swc/crates/swc/benches/assets/table.tsx
@@ -1,1117 +0,0 @@-import type { MenuProps } from '@affine/component';-import { Button, IconButton, Menu, MenuItem, Tooltip } from '@affine/component';-import { useCurrentWorkspacePropertiesAdapter } from '@affine/core/components/hooks/use-affine-adapter';-import { DocLinksService } from '@affine/core/modules/doc-link';-import { EditorSettingService } from '@affine/core/modules/editor-settting';-import type {- PageInfoCustomProperty,- PageInfoCustomPropertyMeta,- PagePropertyType,-} from '@affine/core/modules/properties/services/schema';-import { i18nTime, useI18n } from '@affine/i18n';-import { track } from '@affine/track';-import { assertExists } from '@blocksuite/affine/global/utils';-import {- ArrowDownSmallIcon,- DeleteIcon,- InvisibleIcon,- MoreHorizontalIcon,- PlusIcon,- TagsIcon,- ToggleExpandIcon,- ViewIcon,-} from '@blocksuite/icons/rc';-import type { DragEndEvent, DraggableAttributes } from '@dnd-kit/core';-import {- DndContext,- PointerSensor,- useSensor,- useSensors,-} from '@dnd-kit/core';-import {- restrictToParentElement,- restrictToVerticalAxis,-} from '@dnd-kit/modifiers';-import { SortableContext, useSortable } from '@dnd-kit/sortable';-import * as Collapsible from '@radix-ui/react-collapsible';-import {- DocService,- useLiveData,- useServices,- WorkspaceService,-} from '@toeverything/infra';-import clsx from 'clsx';-import { use } from 'foxact/use';-import { useDebouncedValue } from 'foxact/use-debounced-value';-import { atom, useAtomValue, useSetAtom } from 'jotai';-import type React from 'react';-import type {- CSSProperties,- MouseEvent,- MouseEventHandler,- PropsWithChildren,-} from 'react';-import {- Suspense,- useCallback,- useContext,- useEffect,- useMemo,- useState,-} from 'react';--import { AffinePageReference } from '../reference-link';-import { managerContext } from './common';-import { ConfirmDeletePropertyModal } from './confirm-delete-property-modal';-import type { PagePropertyIcon } from './icons-mapping';-import { getDefaultIconName, nameToIcon } from './icons-mapping';-import type { MenuItemOption } from './menu-items';-import {- EditPropertyNameMenuItem,- PropertyTypeMenuItem,- renderMenuItemOptions,-} from './menu-items';-import type { PagePropertiesMetaManager } from './page-properties-manager';-import {- newPropertyTypes,- PagePropertiesManager,-} from './page-properties-manager';-import {- propertyValueRenderers,- TagsValue,-} from './property-row-value-renderer';-import * as styles from './styles.css';--type PagePropertiesSettingsPopupProps = PropsWithChildren<{- className?: string;- style?: React.CSSProperties;-}>;--const Divider = () => <div className={styles.tableHeaderDivider} />;--type PropertyVisibility = PageInfoCustomProperty['visibility'];--const editingPropertyAtom = atom<string | null>(null);--const modifiers = [restrictToParentElement, restrictToVerticalAxis];--interface SortablePropertiesProps {- children: (properties: PageInfoCustomProperty[]) => React.ReactNode;-}--export const SortableProperties = ({ children }: SortablePropertiesProps) => {- const manager = useContext(managerContext);- const properties = useMemo(() => manager.sorter.getOrderedItems(), [manager]);- const editingItem = useAtomValue(editingPropertyAtom);- const draggable = !manager.readonly && !editingItem;- const sensors = useSensors(- useSensor(PointerSensor, {- activationConstraint: {- distance: 8,- },- })- );- // use localProperties since changes applied to upstream may be delayed- // if we use that one, there will be weird behavior after reordering- const [localProperties, setLocalProperties] = useState(properties);-- useEffect(() => {- setLocalProperties(properties);- }, [properties]);-- const onDragEnd = useCallback(- (event: DragEndEvent) => {- if (!draggable) {- return;- }- const { active, over } = event;- if (over) {- manager.sorter.move(active.id, over.id);- }- setLocalProperties(manager.sorter.getOrderedItems());- },- [manager, draggable]- );-- const filteredProperties = useMemo(- () => localProperties.filter(p => manager.getCustomPropertyMeta(p.id)),- [localProperties, manager]- );-- return (- <DndContext sensors={sensors} onDragEnd={onDragEnd} modifiers={modifiers}>- <SortableContext disabled={!draggable} items={properties}>- {children(filteredProperties)}- </SortableContext>- </DndContext>- );-};--type SyntheticListenerMap = ReturnType<typeof useSortable>['listeners'];--const SortablePropertyRow = ({- property,- className,- children,- ...props-}: {- property: PageInfoCustomProperty;- className?: string;- children?:- | React.ReactNode- | ((props: {- attributes: DraggableAttributes;- listeners?: SyntheticListenerMap;- }) => React.ReactNode);-}) => {- const manager = useContext(managerContext);- const {- setNodeRef,- attributes,- listeners,- transform,- transition,- active,- isDragging,- isSorting,- } = useSortable({- id: property.id,- });- const style: CSSProperties = useMemo(- () => ({- transform: transform- ? `translate3d(${transform.x}px, ${transform.y}px, 0)`- : undefined,- transition: isSorting ? transition : undefined,- pointerEvents: manager.readonly ? 'none' : undefined,- }),- [isSorting, manager.readonly, transform, transition]- );-- return (- <div- style={style}- ref={setNodeRef}- className={clsx(styles.propertyRow, className)}- data-property={property.id}- data-draggable={!manager.readonly}- data-dragging={isDragging}- data-other-dragging={active ? active.id !== property.id : false}- {...props}- {...attributes}- {...listeners}- >- {typeof children === 'function'- ? children({ attributes, listeners })- : children}- </div>- );-};--const visibilities: PropertyVisibility[] = ['visible', 'hide', 'hide-if-empty'];-const rotateVisibility = (- visibility: PropertyVisibility-): PropertyVisibility => {- const index = visibilities.indexOf(visibility);- return visibilities[(index + 1) % visibilities.length];-};--const visibilityMenuText = (visibility: PropertyVisibility = 'visible') => {- switch (visibility) {- case 'hide':- return 'com.affine.page-properties.property.hide-in-view';- case 'hide-if-empty':- return 'com.affine.page-properties.property.hide-in-view-when-empty';- case 'visible':- return 'com.affine.page-properties.property.show-in-view';- default:- throw new Error(`unknown visibility: ${visibility}`);- }-};--const visibilitySelectorText = (visibility: PropertyVisibility = 'visible') => {- switch (visibility) {- case 'hide':- return 'com.affine.page-properties.property.always-hide';- case 'hide-if-empty':- return 'com.affine.page-properties.property.hide-when-empty';- case 'visible':- return 'com.affine.page-properties.property.always-show';- default:- throw new Error(`unknown visibility: ${visibility}`);- }-};--const VisibilityModeSelector = ({- property,-}: {- property: PageInfoCustomProperty;-}) => {- const manager = useContext(managerContext);- const t = useI18n();- const meta = manager.getCustomPropertyMeta(property.id);- const visibility = property.visibility || 'visible';-- const menuItems = useMemo(() => {- const options: MenuItemOption[] = [];- options.push(- visibilities.map(v => {- const text = visibilityMenuText(v);- return {- text: t[text](),- selected: visibility === v,- onClick: () => {- manager.updateCustomProperty(property.id, {- visibility: v,- });- },- };- })- );- return renderMenuItemOptions(options);- }, [manager, property.id, t, visibility]);-- if (!meta) {- return null;- }-- const required = meta.required;-- return (- <Menu- items={menuItems}- rootOptions={{- open: required ? false : undefined,- }}- contentOptions={{- onClick(e) {- e.stopPropagation();- },- }}- >- <div- role="button"- data-required={required}- className={styles.selectorButton}- >- {required ? (- t['com.affine.page-properties.property.required']()- ) : (- <>- {t[visibilitySelectorText(visibility)]()}- <ArrowDownSmallIcon width={16} height={16} />- </>- )}- </div>- </Menu>- );-};--export const PagePropertiesSettingsPopup = ({- children,-}: PagePropertiesSettingsPopupProps) => {- const manager = useContext(managerContext);- const t = useI18n();-- const menuItems = useMemo(() => {- const options: MenuItemOption[] = [];- options.push(- <div- role="heading"- className={styles.menuHeader}- style={{ minWidth: 320 }}- >- {t['com.affine.page-properties.settings.title']()}- </div>- );- options.push('-');- options.push([- <SortableProperties key="sortable-settings">- {properties =>- properties.map(property => {- const meta = manager.getCustomPropertyMeta(property.id);- assertExists(meta, 'meta should exist for property');- const Icon = nameToIcon(meta.icon, meta.type);- const name = meta.name;- return (- <SortablePropertyRow- key={meta.id}- property={property}- className={styles.propertySettingRow}- data-testid="page-properties-settings-menu-item"- >- <Icon />- <div- data-testid="page-property-setting-row-name"- className={styles.propertyRowName}- >- {name}- </div>- <VisibilityModeSelector property={property} />- </SortablePropertyRow>- );- })- }- </SortableProperties>,- ]);- return renderMenuItemOptions(options);- }, [manager, t]);-- return (- <Menu- contentOptions={{- onClick(e) {- e.stopPropagation();- },- }}- items={menuItems}- >- {children}- </Menu>- );-};--type PageBacklinksPopupProps = PropsWithChildren<{- backlinks: { docId: string; blockId: string; title: string }[];-}>;--export const PageBacklinksPopup = ({- backlinks,- children,-}: PageBacklinksPopupProps) => {- return (- <Menu- contentOptions={{- onClick(e) {- e.stopPropagation();- },- }}- items={- <div className={styles.backlinksList}>- {backlinks.map(link => (- <AffinePageReference- key={link.docId + ':' + link.blockId}- wrapper={MenuItem}- pageId={link.docId}- />- ))}- </div>- }- >- {children}- </Menu>- );-};--interface PagePropertyRowNameProps {- property: PageInfoCustomProperty;- meta: PageInfoCustomPropertyMeta;- editing: boolean;- onFinishEditing: () => void;-}--export const PagePropertyRowNameMenu = ({- editing,- meta,- property,- onFinishEditing,- children,-}: PropsWithChildren<PagePropertyRowNameProps>) => {- const manager = useContext(managerContext);- const [localPropertyMeta, setLocalPropertyMeta] = useState(() => ({- ...meta,- }));- const [localProperty, setLocalProperty] = useState(() => ({ ...property }));- const nextVisibility = rotateVisibility(localProperty.visibility);-- const [showDeleteModal, setShowDeleteModal] = useState(false);-- useEffect(() => {- setLocalPropertyMeta(meta);- }, [meta]);-- useEffect(() => {- setLocalProperty(property);- }, [property]);-- const handleFinishEditing = useCallback(() => {- onFinishEditing();- manager.updateCustomPropertyMeta(meta.id, localPropertyMeta);- manager.updateCustomProperty(property.id, localProperty);- }, [- localProperty,- localPropertyMeta,- manager,- meta.id,- onFinishEditing,- property.id,- ]);- const t = useI18n();- const handleNameBlur = useCallback(- (v: string) => {- manager.updateCustomPropertyMeta(meta.id, {- name: v,- });- },- [manager, meta.id]- );- const handleNameChange: (name: string) => void = useCallback(name => {- setLocalPropertyMeta(prev => ({- ...prev,- name: name,- }));- }, []);- const toggleHide = useCallback(- (e: MouseEvent) => {- e.stopPropagation();- e.preventDefault();- setLocalProperty(prev => ({- ...prev,- visibility: nextVisibility,- }));- },- [nextVisibility]- );- const handleDelete = useCallback(() => {- manager.removeCustomProperty(property.id);- }, [manager, property.id]);-- const handleIconChange = useCallback(- (icon: PagePropertyIcon) => {- setLocalPropertyMeta(prev => ({- ...prev,- icon,- }));- manager.updateCustomPropertyMeta(meta.id, {- icon: icon,- });- },- [manager, meta.id]- );-- const menuItems = useMemo(() => {- const options: MenuItemOption[] = [];- options.push(- <EditPropertyNameMenuItem- property={localPropertyMeta}- onIconChange={handleIconChange}- onNameBlur={handleNameBlur}- onNameChange={handleNameChange}- />- );- options.push(<PropertyTypeMenuItem property={localPropertyMeta} />);- if (!localPropertyMeta.required) {- options.push('-');- options.push({- icon:- nextVisibility === 'hide' || nextVisibility === 'hide-if-empty' ? (- <InvisibleIcon />- ) : (- <ViewIcon />- ),- text: t[- visibilityMenuText(rotateVisibility(localProperty.visibility))- ](),- onClick: toggleHide,- });- options.push({- type: 'danger',- icon: <DeleteIcon />,- text: t['com.affine.page-properties.property.remove-property'](),- onClick: () => setShowDeleteModal(true),- });- }- return renderMenuItemOptions(options);- }, [- handleIconChange,- handleNameBlur,- handleNameChange,- localProperty.visibility,- localPropertyMeta,- nextVisibility,- t,- toggleHide,- ]);-- return (- <>- <Menu- rootOptions={{- open: editing,- }}- contentOptions={{- onInteractOutside: handleFinishEditing,- onClick(e) {- e.stopPropagation();- },- onKeyDown(e) {- if (e.key === 'Escape') {- handleFinishEditing();- }- },- }}- items={menuItems}- >- {children}- </Menu>- <ConfirmDeletePropertyModal- onConfirm={() => {- setShowDeleteModal(false);- handleDelete();- }}- onCancel={() => setShowDeleteModal(false)}- show={showDeleteModal}- property={meta}- />- </>- );-};--interface PagePropertiesTableHeaderProps {- className?: string;- style?: React.CSSProperties;- open: boolean;- onOpenChange: (open: boolean) => void;-}--// backlinks - #no Updated yyyy-mm-dd-// ─────────────────────────────────────────────────-// Page Info ...-export const PagePropertiesTableHeader = ({- className,- style,- open,- onOpenChange,-}: PagePropertiesTableHeaderProps) => {- const manager = useContext(managerContext);-- const t = useI18n();- const {- docLinksServices,- docService,- workspaceService,- editorSettingService,- } = useServices({- DocLinksServices: DocLinksService,- DocService,- WorkspaceService,- EditorSettingService,- });- const docBacklinks = docLinksServices.backlinks;- const backlinks = useLiveData(docBacklinks.backlinks$);-- const displayDocInfo = useLiveData(- editorSettingService.editorSetting.settings$.selector(s => s.displayDocInfo)- );-- const { syncing, retrying, serverClock } = useLiveData(- workspaceService.workspace.engine.doc.docState$(docService.doc.id)- );-- const timestampElement = useMemo(() => {- const localizedCreateTime = manager.createDate- ? i18nTime(manager.createDate)- : null;-- const createTimeElement = (- <div className={styles.tableHeaderTimestamp}>- {t['Created']()} {localizedCreateTime}- </div>- );-- return serverClock ? (- <Tooltip- side="right"- content={- <>- <div className={styles.tableHeaderTimestamp}>- {t['Updated']()} {i18nTime(serverClock)}- </div>- {manager.createDate && (- <div className={styles.tableHeaderTimestamp}>- {t['Created']()} {i18nTime(manager.createDate)}- </div>- )}- </>- }- >- <div className={styles.tableHeaderTimestamp}>- {!syncing && !retrying ? (- <>- {t['Updated']()}{' '}- {i18nTime(serverClock, {- relative: {- max: [1, 'day'],- accuracy: 'minute',- },- absolute: {- accuracy: 'day',- },- })}- </>- ) : (- <>{t['com.affine.syncing']()}</>- )}- </div>- </Tooltip>- ) : manager.updatedDate ? (- <Tooltip side="right" content={createTimeElement}>- <div className={styles.tableHeaderTimestamp}>- {t['Updated']()} {i18nTime(manager.updatedDate)}- </div>- </Tooltip>- ) : (- createTimeElement- );- }, [- manager.createDate,- manager.updatedDate,- retrying,- serverClock,- syncing,- t,- ]);-- const dTimestampElement = useDebouncedValue(timestampElement, 500);-- const handleCollapse = useCallback(() => {- track.doc.inlineDocInfo.$.toggle();- onOpenChange(!open);- }, [onOpenChange, open]);-- const properties = manager.sorter.getOrderedItems();-- return (- <div className={clsx(styles.tableHeader, className)} style={style}>- {/* TODO(@Peng): add click handler to backlinks */}- <div className={styles.tableHeaderInfoRow}>- {backlinks.length > 0 ? (- <PageBacklinksPopup backlinks={backlinks}>- <div className={styles.tableHeaderBacklinksHint}>- {t['com.affine.page-properties.backlinks']()} · {backlinks.length}- </div>- </PageBacklinksPopup>- ) : null}- {dTimestampElement}- </div>- <Divider />- {displayDocInfo ? (- <div className={styles.tableHeaderSecondaryRow}>- <div className={clsx(!open ? styles.pageInfoDimmed : null)}>- {t['com.affine.page-properties.page-info']()}- </div>- {properties.length === 0 || manager.readonly ? null : (- <PagePropertiesSettingsPopup>- <IconButton data-testid="page-info-show-more" size="20">- <MoreHorizontalIcon />- </IconButton>- </PagePropertiesSettingsPopup>- )}- <Collapsible.Trigger asChild role="button" onClick={handleCollapse}>- <div- className={styles.tableHeaderCollapseButtonWrapper}- data-testid="page-info-collapse"- >- <IconButton size="20">- <ToggleExpandIcon- className={styles.collapsedIcon}- data-collapsed={!open}- />- </IconButton>- </div>- </Collapsible.Trigger>- </div>- ) : null}- </div>- );-};--interface PagePropertyRowProps {- property: PageInfoCustomProperty;- style?: React.CSSProperties;- rowNameClassName?: string;-}--export const PagePropertyRow = ({- property,- rowNameClassName,-}: PagePropertyRowProps) => {- const manager = useContext(managerContext);- const meta = manager.getCustomPropertyMeta(property.id);-- assertExists(meta, 'meta should exist for property');-- const Icon = nameToIcon(meta.icon, meta.type);- const name = meta.name;- const ValueRenderer = propertyValueRenderers[meta.type];- const [editingMeta, setEditingMeta] = useState(false);- const setEditingItem = useSetAtom(editingPropertyAtom);- const handleEditMeta = useCallback(() => {- if (!manager.readonly) {- setEditingMeta(true);- }- setEditingItem(property.id);- }, [manager.readonly, property.id, setEditingItem]);- const handleFinishEditingMeta = useCallback(() => {- setEditingMeta(false);- setEditingItem(null);- }, [setEditingItem]);-- // NOTE: if we define a new property type, the value render may not exists in old client- // skip rendering if value render is not define yet- if (!ValueRenderer || typeof ValueRenderer !== 'function') return null;-- return (- <SortablePropertyRow property={property} data-testid="page-property-row">- {({ attributes, listeners }) => (- <>- <PagePropertyRowNameMenu- editing={editingMeta}- meta={meta}- property={property}- onFinishEditing={handleFinishEditingMeta}- >- <div- {...attributes}- {...listeners}- data-testid="page-property-row-name"- className={clsx(- styles.sortablePropertyRowNameCell,- rowNameClassName- )}- onClick={handleEditMeta}- >- <div className={styles.propertyRowNameContainer}>- <div className={styles.propertyRowIconContainer}>- <Icon />- </div>- <div className={styles.propertyRowName}>{name}</div>- </div>- </div>- </PagePropertyRowNameMenu>- <ValueRenderer meta={meta} property={property} />- </>- )}- </SortablePropertyRow>- );-};--export const PageTagsRow = ({- rowNameClassName,-}: {- rowNameClassName?: string;-}) => {- const t = useI18n();- return (- <div- className={styles.tagsPropertyRow}- data-testid="page-property-row"- data-property="tags"- >- <div- className={clsx(styles.propertyRowNameCell, rowNameClassName)}- data-testid="page-property-row-name"- >- <div className={styles.propertyRowNameContainer}>- <div className={styles.propertyRowIconContainer}>- <TagsIcon />- </div>- <div className={styles.propertyRowName}>{t['Tags']()}</div>- </div>- </div>- <TagsValue />- </div>- );-};--interface PagePropertiesTableBodyProps {- className?: string;- style?: React.CSSProperties;-}--// 🏷️ Tags (⋅ xxx) (⋅ yyy)-// #️⃣ Number 123456-// + Add a property-export const PagePropertiesTableBody = ({- className,- style,-}: PagePropertiesTableBodyProps) => {- const manager = useContext(managerContext);- return (- <Collapsible.Content- className={clsx(styles.tableBodyRoot, className)}- style={style}- >- <PageTagsRow />- <SortableProperties>- {properties =>- properties.length ? (- <div className={styles.tableBodySortable}>- {properties- .filter(- property =>- manager.isPropertyRequired(property.id) ||- (property.visibility !== 'hide' &&- !(- property.visibility === 'hide-if-empty' &&- !property.value- ))- )- .map(property => (- <PagePropertyRow key={property.id} property={property} />- ))}- </div>- ) : null- }- </SortableProperties>- {manager.readonly ? null : <PagePropertiesAddProperty />}- <Divider />- </Collapsible.Content>- );-};--interface PagePropertiesCreatePropertyMenuItemsProps {- onCreated?: (e: React.MouseEvent, id: string) => void;- metaManager: PagePropertiesMetaManager;-}--const findNextDefaultName = (name: string, allNames: string[]): string => {- const nameExists = allNames.includes(name);- if (nameExists) {- const match = name.match(/(\d+)$/);- if (match) {- const num = parseInt(match[1], 10);- const nextName = name.replace(/(\d+)$/, `${num + 1}`);- return findNextDefaultName(nextName, allNames);- } else {
The diff stops at 1024 KiB. git show 1d7e0126 shows the rest.