mirror of
https://github.com/swc-project/swc.git
synced 2024-12-26 07:02:28 +03:00
feat(es/typescript): Improve fast TS strip (#9154)
**Description:** It's almost done, but it need some more adjustment for arrow functions.
This commit is contained in:
parent
2daee6fa7e
commit
05c721030a
@ -1 +1 @@
|
||||
Subproject commit a03c69227413dfcac8a1e9f89d93554fa3b8b7fe
|
||||
Subproject commit 8e9c0b0fb3d548f378420aabbd351087efb5d5e5
|
@ -7,9 +7,12 @@ use swc_common::{
|
||||
BytePos, FileName, SourceMap, Span, Spanned,
|
||||
};
|
||||
use swc_ecma_ast::{
|
||||
BindingIdent, Decorator, EsVersion, Ident, ImportDecl, ImportSpecifier, Param, Pat, Program,
|
||||
TsAsExpr, TsConstAssertion, TsEnumDecl, TsInstantiation, TsModuleDecl, TsModuleName,
|
||||
TsNamespaceDecl, TsNonNullExpr, TsParamPropParam, TsSatisfiesExpr, TsTypeAliasDecl, TsTypeAnn,
|
||||
ArrowExpr, BindingIdent, Class, ClassMethod, ClassProp, Decorator, EsVersion, ExportAll,
|
||||
ExportDecl, ExportSpecifier, FnDecl, Ident, ImportDecl, ImportSpecifier, MethodKind,
|
||||
NamedExport, Param, Pat, Program, TsAsExpr, TsConstAssertion, TsEnumDecl, TsInstantiation,
|
||||
TsInterfaceDecl, TsModuleDecl, TsModuleName, TsNamespaceDecl, TsNonNullExpr, TsParamPropParam,
|
||||
TsSatisfiesExpr, TsTypeAliasDecl, TsTypeAnn, TsTypeAssertion, TsTypeParamDecl,
|
||||
TsTypeParamInstantiation, VarDecl,
|
||||
};
|
||||
use swc_ecma_parser::{
|
||||
parse_file_as_module, parse_file_as_program, parse_file_as_script, Syntax, TsSyntax,
|
||||
@ -83,7 +86,7 @@ pub fn operate(
|
||||
}
|
||||
|
||||
// Strip typescript types
|
||||
let mut ts_strip = TsStrip::new(fm.src.clone());
|
||||
let mut ts_strip = TsStrip::new(cm.clone(), fm.src.clone());
|
||||
program.visit_with(&mut ts_strip);
|
||||
|
||||
let replacements = ts_strip.replacements;
|
||||
@ -98,19 +101,48 @@ pub fn operate(
|
||||
code[(r.0 .0 - 1) as usize..(r.1 .0 - 1) as usize].fill(b' ');
|
||||
}
|
||||
|
||||
// Assert that removal does not overlap with each other
|
||||
|
||||
for removal in ts_strip.removals.iter() {
|
||||
for r in &ts_strip.removals {
|
||||
if removal == r {
|
||||
continue;
|
||||
}
|
||||
|
||||
assert!(
|
||||
r.0 < removal.0 || r.1 < removal.0 || r.0 > removal.1 || r.1 > removal.1,
|
||||
"removal {:?} overlaps with replacement {:?}",
|
||||
removal,
|
||||
r
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for removal in ts_strip.removals.iter().copied().rev() {
|
||||
code.drain((removal.0 .0 - 1) as usize..(removal.1 .0 - 1) as usize);
|
||||
}
|
||||
|
||||
String::from_utf8(code).map_err(|_| anyhow::anyhow!("failed to convert to utf-8"))
|
||||
}
|
||||
|
||||
struct TsStrip {
|
||||
cm: Lrc<SourceMap>,
|
||||
src: Lrc<String>,
|
||||
|
||||
/// Replaced with whitespace
|
||||
replacements: Vec<(BytePos, BytePos)>,
|
||||
|
||||
/// Applied after replacements. Used for arrow functions.
|
||||
removals: Vec<(BytePos, BytePos)>,
|
||||
}
|
||||
|
||||
impl TsStrip {
|
||||
fn new(src: Lrc<String>) -> Self {
|
||||
fn new(cm: Lrc<SourceMap>, src: Lrc<String>) -> Self {
|
||||
TsStrip {
|
||||
cm,
|
||||
src,
|
||||
replacements: Default::default(),
|
||||
removals: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -119,15 +151,208 @@ impl TsStrip {
|
||||
fn add_replacement(&mut self, span: Span) {
|
||||
self.replacements.push((span.lo, span.hi));
|
||||
}
|
||||
|
||||
fn add_removal(&mut self, span: Span) {
|
||||
self.removals.push((span.lo, span.hi));
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for TsStrip {
|
||||
fn visit_arrow_expr(&mut self, n: &ArrowExpr) {
|
||||
if let Some(ret) = &n.return_type {
|
||||
let mut sp = self.cm.span_extend_to_prev_char(ret.span, ')');
|
||||
|
||||
let pos = self.src[(sp.hi.0 as usize - 1)..].find("=>").unwrap();
|
||||
|
||||
sp.hi.0 += pos as u32;
|
||||
|
||||
self.add_removal(sp);
|
||||
}
|
||||
|
||||
n.type_params.visit_with(self);
|
||||
n.params.visit_with(self);
|
||||
n.body.visit_with(self);
|
||||
}
|
||||
|
||||
fn visit_binding_ident(&mut self, n: &BindingIdent) {
|
||||
n.visit_children_with(self);
|
||||
|
||||
if n.optional {
|
||||
self.add_replacement(span(n.id.span.hi, n.id.span.hi + BytePos(1)));
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_class(&mut self, n: &Class) {
|
||||
n.visit_children_with(self);
|
||||
|
||||
let lo = match &n.super_class {
|
||||
Some(v) => v.span().hi,
|
||||
None => n.span.lo,
|
||||
};
|
||||
let hi = skip_until(self.src.as_bytes(), lo.0, b'{');
|
||||
self.add_replacement(span(lo, BytePos(hi)));
|
||||
}
|
||||
|
||||
fn visit_class_method(&mut self, n: &ClassMethod) {
|
||||
if n.function.body.is_none() {
|
||||
self.add_replacement(n.span);
|
||||
return;
|
||||
}
|
||||
|
||||
let hi = match n.kind {
|
||||
MethodKind::Method => {
|
||||
if n.is_static {
|
||||
self.cm
|
||||
.span_extend_to_next_str(span(n.span.lo, n.span.lo), "static", false)
|
||||
.hi
|
||||
} else {
|
||||
n.key.span().lo
|
||||
}
|
||||
}
|
||||
MethodKind::Getter => {
|
||||
self.cm
|
||||
.span_extend_to_next_str(span(n.span.lo, n.span.lo), "get", false)
|
||||
.hi
|
||||
}
|
||||
MethodKind::Setter => {
|
||||
self.cm
|
||||
.span_extend_to_next_str(span(n.span.lo, n.span.lo), "set", false)
|
||||
.hi
|
||||
}
|
||||
};
|
||||
|
||||
self.add_replacement(span(n.span.lo, hi));
|
||||
|
||||
n.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_class_prop(&mut self, n: &ClassProp) {
|
||||
if n.declare {
|
||||
self.add_replacement(n.span);
|
||||
return;
|
||||
}
|
||||
|
||||
let hi = if n.is_static {
|
||||
self.cm
|
||||
.span_extend_to_next_str(span(n.span.lo, n.span.lo), "static", false)
|
||||
.hi
|
||||
} else {
|
||||
n.key.span().lo
|
||||
};
|
||||
|
||||
self.add_replacement(span(n.span.lo, hi));
|
||||
|
||||
n.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_decorator(&mut self, n: &Decorator) {
|
||||
HANDLER.with(|handler| {
|
||||
handler.span_err(n.span, "Decorators are not supported");
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_export_all(&mut self, n: &ExportAll) {
|
||||
if n.type_only {
|
||||
self.add_replacement(n.span);
|
||||
return;
|
||||
}
|
||||
|
||||
n.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_export_decl(&mut self, n: &ExportDecl) {
|
||||
match n.decl {
|
||||
swc_ecma_ast::Decl::TsInterface(_)
|
||||
| swc_ecma_ast::Decl::TsTypeAlias(_)
|
||||
| swc_ecma_ast::Decl::TsEnum(_)
|
||||
| swc_ecma_ast::Decl::TsModule(_) => {
|
||||
self.add_replacement(n.span);
|
||||
}
|
||||
|
||||
_ => {
|
||||
n.visit_children_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn_decl(&mut self, n: &FnDecl) {
|
||||
if n.function.body.is_none() {
|
||||
self.add_replacement(n.function.span);
|
||||
return;
|
||||
}
|
||||
n.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_import_decl(&mut self, n: &ImportDecl) {
|
||||
if n.type_only {
|
||||
self.add_replacement(n.span);
|
||||
return;
|
||||
}
|
||||
|
||||
n.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_import_specifiers(&mut self, n: &[ImportSpecifier]) {
|
||||
for (i, import) in n.iter().enumerate() {
|
||||
let ImportSpecifier::Named(import) = import else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if import.is_type_only {
|
||||
let mut span = import.span;
|
||||
span.hi.0 = n.get(i + 1).map(|x| x.span_lo().0).unwrap_or_else(|| {
|
||||
let bytes = self.src.as_bytes();
|
||||
skip_until(bytes, span.hi.0, b'}')
|
||||
});
|
||||
self.add_replacement(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_named_export(&mut self, n: &NamedExport) {
|
||||
if n.type_only {
|
||||
self.add_replacement(n.span);
|
||||
return;
|
||||
}
|
||||
|
||||
for export in n.specifiers.iter() {
|
||||
if let ExportSpecifier::Named(e) = export {
|
||||
if e.is_type_only {
|
||||
let sp = self.cm.span_extend_to_next_char(e.span, ',');
|
||||
self.add_replacement(span(sp.lo, sp.hi + BytePos(1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_params(&mut self, n: &[Param]) {
|
||||
if let Some(p) = n.first().filter(|param| {
|
||||
matches!(
|
||||
¶m.pat,
|
||||
Pat::Ident(BindingIdent {
|
||||
id: Ident { sym, .. },
|
||||
..
|
||||
}) if &**sym == "this"
|
||||
)
|
||||
}) {
|
||||
let mut span = p.span;
|
||||
|
||||
if n.len() == 1 {
|
||||
let bytes = self.src.as_bytes();
|
||||
span.hi.0 = skip_until(bytes, span.hi.0, b')');
|
||||
} else {
|
||||
span.hi = n[1].span.lo;
|
||||
n[1..].visit_children_with(self);
|
||||
}
|
||||
|
||||
self.add_replacement(span);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
n.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_ts_as_expr(&mut self, n: &TsAsExpr) {
|
||||
self.add_replacement(span(n.expr.span().hi, n.span.hi));
|
||||
|
||||
@ -160,6 +385,10 @@ impl Visit for TsStrip {
|
||||
n.expr.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_ts_interface_decl(&mut self, n: &TsInterfaceDecl) {
|
||||
self.add_replacement(n.span);
|
||||
}
|
||||
|
||||
fn visit_ts_module_decl(&mut self, n: &TsModuleDecl) {
|
||||
if n.declare || matches!(n.id, TsModuleName::Str(..)) {
|
||||
self.add_replacement(n.span);
|
||||
@ -217,67 +446,28 @@ impl Visit for TsStrip {
|
||||
self.add_replacement(n.span);
|
||||
}
|
||||
|
||||
fn visit_binding_ident(&mut self, n: &BindingIdent) {
|
||||
n.visit_children_with(self);
|
||||
fn visit_ts_type_assertion(&mut self, n: &TsTypeAssertion) {
|
||||
self.add_replacement(span(n.span.lo, n.expr.span().lo));
|
||||
|
||||
if n.optional {
|
||||
self.add_replacement(span(n.id.span.hi, n.id.span.hi + BytePos(1)));
|
||||
}
|
||||
n.expr.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_params(&mut self, n: &[Param]) {
|
||||
if let Some(p) = n.first().filter(|param| {
|
||||
matches!(
|
||||
¶m.pat,
|
||||
Pat::Ident(BindingIdent {
|
||||
id: Ident { sym, .. },
|
||||
..
|
||||
}) if &**sym == "this"
|
||||
)
|
||||
}) {
|
||||
let mut span = p.span;
|
||||
|
||||
if n.len() == 1 {
|
||||
let bytes = self.src.as_bytes();
|
||||
span.hi.0 = skip_until(bytes, span.hi.0, b')');
|
||||
} else {
|
||||
span.hi = n[1].span.lo;
|
||||
n[1..].visit_children_with(self);
|
||||
fn visit_ts_type_param_decl(&mut self, n: &TsTypeParamDecl) {
|
||||
self.add_replacement(n.span);
|
||||
}
|
||||
|
||||
self.add_replacement(span);
|
||||
|
||||
return;
|
||||
fn visit_ts_type_param_instantiation(&mut self, n: &TsTypeParamInstantiation) {
|
||||
self.add_replacement(span(n.span.lo, n.span.hi));
|
||||
}
|
||||
|
||||
n.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_import_decl(&mut self, n: &ImportDecl) {
|
||||
if n.type_only {
|
||||
fn visit_var_decl(&mut self, n: &VarDecl) {
|
||||
if n.declare {
|
||||
self.add_replacement(n.span);
|
||||
return;
|
||||
}
|
||||
|
||||
n.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_import_specifiers(&mut self, n: &[ImportSpecifier]) {
|
||||
for (i, import) in n.iter().enumerate() {
|
||||
let ImportSpecifier::Named(import) = import else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if import.is_type_only {
|
||||
let mut span = import.span;
|
||||
span.hi.0 = n.get(i + 1).map(|x| x.span_lo().0).unwrap_or_else(|| {
|
||||
let bytes = self.src.as_bytes();
|
||||
skip_until(bytes, span.hi.0, b'}')
|
||||
});
|
||||
self.add_replacement(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn span(lo: BytePos, hi: BytePos) -> Span {
|
||||
|
171
crates/swc_fast_ts_strip/tests/fixture/test-case-1.js
Normal file
171
crates/swc_fast_ts_strip/tests/fixture/test-case-1.js
Normal file
@ -0,0 +1,171 @@
|
||||
let x /**/ /**/ = 1 ;
|
||||
// ^^^^^^^^ ^
|
||||
|
||||
[] ;
|
||||
// ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
( "test");
|
||||
//^^^^^^^^
|
||||
|
||||
class C /**/ /*︎*/ extends Array {
|
||||
// ^^^^^ ^^^ ^^^^^^^^^^^^^^
|
||||
field/**/ /**/ = "";
|
||||
// ^^^^^^^^ ^^^^^^^^
|
||||
static accessor f1;
|
||||
f2/**/!/**/ /*︎*/;
|
||||
// ^^^^^^^ ^ ^^^^^^^^
|
||||
|
||||
// ^^^^^^^^^^^^^^^^ declared property
|
||||
|
||||
method/**/ /*︎*/(/*︎*/ a /*︎*/ /**/)/*︎*/ /*︎*/ {
|
||||
// ^^^^^^ ^^^ ^^^^^^^^ ^ ^^^^^^^^ ^^^^^^
|
||||
}
|
||||
|
||||
[key ] ;
|
||||
// ^^^^^^^^^^^^^^^^^^^ index signature
|
||||
|
||||
get g() { return 1 };
|
||||
// ^^^^^
|
||||
set g(v ) { };
|
||||
// ^^^^^
|
||||
}
|
||||
|
||||
class D extends C {
|
||||
// ^^^^^
|
||||
method(...args) { }
|
||||
// ^^^^^^^^ ^^^^^
|
||||
}
|
||||
|
||||
{
|
||||
// ^^^^^^^^
|
||||
a;
|
||||
// ^^^^^^^^^^^ abstract property
|
||||
b;
|
||||
|
||||
// ^^^^^^^^^^^^^^^^^^ abstract method
|
||||
}
|
||||
|
||||
{
|
||||
let m = new (Map ) ([] );
|
||||
// ^ ^^^^^^^^^^^^^^^^ ^
|
||||
}
|
||||
|
||||
{
|
||||
let a = (foo ) ;
|
||||
// ^ ^^^^^
|
||||
}
|
||||
|
||||
{
|
||||
let a = (foo ) ([] );
|
||||
// ^ ^^^^^ ^
|
||||
}
|
||||
|
||||
{
|
||||
let f = function (p ) { }
|
||||
// ^^^^^
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overload
|
||||
function overload() { }
|
||||
// ^^^^^
|
||||
}
|
||||
|
||||
/** @doc */
|
||||
|
||||
// ^^^^^^^^^^^ interface
|
||||
|
||||
void 0;
|
||||
|
||||
/** @doc */
|
||||
|
||||
// ^^^^^^^^ type alias
|
||||
|
||||
/**/
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `import type`
|
||||
|
||||
/**/
|
||||
// ^^^^^^^^^^^^^^^^^^ `export type`
|
||||
|
||||
/**/
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `export type *`
|
||||
|
||||
import { deepEqual } from "node:assert";
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
export {
|
||||
C,
|
||||
|
||||
// ^^^^^^
|
||||
}
|
||||
|
||||
/**/
|
||||
// ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
function foo (p = ()=> 1) {
|
||||
// ^^^ ^^^^^ ^^^^^ ^^^^^
|
||||
return p ;
|
||||
// ^^^^^^
|
||||
}
|
||||
|
||||
/**/
|
||||
// ^^^^^^^^^^^^^^^^^^ `declare enum`
|
||||
|
||||
void 0;
|
||||
|
||||
/**/
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^ `declare namespace`
|
||||
|
||||
void 0;
|
||||
|
||||
/**/
|
||||
// ^^^^^^^^^^^^^^^^^^^ `declare module`
|
||||
|
||||
void 0;
|
||||
|
||||
/**/
|
||||
// ^^^^^^^^^^^^^^ `declare let`
|
||||
|
||||
void 0;
|
||||
|
||||
/**/ { }
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `declare class`
|
||||
|
||||
void 0;
|
||||
|
||||
/**/
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `declare function`
|
||||
|
||||
void 0;
|
||||
|
||||
// `=>` spanning line cases:
|
||||
{
|
||||
()
|
||||
=>
|
||||
1
|
||||
};
|
||||
{
|
||||
()=>
|
||||
1
|
||||
};
|
||||
{
|
||||
(
|
||||
)
|
||||
=>
|
||||
1
|
||||
};
|
||||
{
|
||||
(
|
||||
)=>
|
||||
1
|
||||
};
|
||||
{
|
||||
(
|
||||
)=>
|
||||
1
|
||||
};
|
||||
{
|
||||
(a, b, c = [] /*comment-1*/)=>
|
||||
1
|
||||
};
|
177
crates/swc_fast_ts_strip/tests/fixture/test-case-1.ts
Normal file
177
crates/swc_fast_ts_strip/tests/fixture/test-case-1.ts
Normal file
@ -0,0 +1,177 @@
|
||||
let x /**/: number/**/ = 1!;
|
||||
// ^^^^^^^^ ^
|
||||
|
||||
[] as [] satisfies [];
|
||||
// ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
(<string>"test");
|
||||
//^^^^^^^^
|
||||
|
||||
class C /**/<T>/*︎*/ extends Array/**/<T> /*︎*/ implements I, J/*︎*/ {
|
||||
// ^^^^^ ^^^ ^^^^^^^^^^^^^^
|
||||
readonly field/**/: string/**/ = "";
|
||||
// ^^^^^^^^ ^^^^^^^^
|
||||
static accessor f1;
|
||||
private f2/**/!/**/: string/*︎*/;
|
||||
// ^^^^^^^ ^ ^^^^^^^^
|
||||
declare f3: any;
|
||||
// ^^^^^^^^^^^^^^^^ declared property
|
||||
|
||||
public method/**/<T>/*︎*/(/*︎*/this: T,/**/ a? /*︎*/: string/**/)/*︎*/: void/*︎*/ {
|
||||
// ^^^^^^ ^^^ ^^^^^^^^ ^ ^^^^^^^^ ^^^^^^
|
||||
}
|
||||
|
||||
[key: string]: any;
|
||||
// ^^^^^^^^^^^^^^^^^^^ index signature
|
||||
|
||||
get g(): any { return 1 };
|
||||
// ^^^^^
|
||||
set g(v: any) { };
|
||||
// ^^^^^
|
||||
}
|
||||
|
||||
class D extends C<any> {
|
||||
// ^^^^^
|
||||
override method(...args): any { }
|
||||
// ^^^^^^^^ ^^^^^
|
||||
}
|
||||
|
||||
abstract class A {
|
||||
// ^^^^^^^^
|
||||
abstract a;
|
||||
// ^^^^^^^^^^^ abstract property
|
||||
b;
|
||||
abstract method();
|
||||
// ^^^^^^^^^^^^^^^^^^ abstract method
|
||||
}
|
||||
|
||||
{
|
||||
let m = new (Map!)<string, number>([]!);
|
||||
// ^ ^^^^^^^^^^^^^^^^ ^
|
||||
}
|
||||
|
||||
{
|
||||
let a = (foo!)<any>;
|
||||
// ^ ^^^^^
|
||||
}
|
||||
|
||||
{
|
||||
let a = (foo!)<any>([]!);
|
||||
// ^ ^^^^^ ^
|
||||
}
|
||||
|
||||
{
|
||||
let f = function (p: any) { }
|
||||
// ^^^^^
|
||||
}
|
||||
|
||||
{
|
||||
function overload(): number;
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overload
|
||||
function overload(): any { }
|
||||
// ^^^^^
|
||||
}
|
||||
|
||||
/** @doc */
|
||||
interface I { }
|
||||
// ^^^^^^^^^^^ interface
|
||||
|
||||
void 0;
|
||||
|
||||
/** @doc */
|
||||
type J = I;
|
||||
// ^^^^^^^^ type alias
|
||||
|
||||
/**/import type T from "node:assert";
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `import type`
|
||||
|
||||
/**/export type { I };
|
||||
// ^^^^^^^^^^^^^^^^^^ `export type`
|
||||
|
||||
/**/export type * from "node:buffer";
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `export type *`
|
||||
|
||||
import { type AssertPredicate/**/, deepEqual } from "node:assert";
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
export {
|
||||
C,
|
||||
type T,
|
||||
// ^^^^^^
|
||||
}
|
||||
|
||||
/**/export type T2 = 1;
|
||||
// ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
function foo<T>(p: any = (): any => 1): any {
|
||||
// ^^^ ^^^^^ ^^^^^ ^^^^^
|
||||
return p as any;
|
||||
// ^^^^^^
|
||||
}
|
||||
|
||||
/**/declare enum E1 { }
|
||||
// ^^^^^^^^^^^^^^^^^^ `declare enum`
|
||||
|
||||
void 0;
|
||||
|
||||
/**/declare namespace N { }
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^ `declare namespace`
|
||||
|
||||
void 0;
|
||||
|
||||
/**/declare module M { }
|
||||
// ^^^^^^^^^^^^^^^^^^^ `declare module`
|
||||
|
||||
void 0;
|
||||
|
||||
/**/declare let a;
|
||||
// ^^^^^^^^^^^^^^ `declare let`
|
||||
|
||||
void 0;
|
||||
|
||||
/**/declare class DeclaredClass { }
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `declare class`
|
||||
|
||||
void 0;
|
||||
|
||||
/**/declare function DeclaredFunction(): void;
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `declare function`
|
||||
|
||||
void 0;
|
||||
|
||||
// `=>` spanning line cases:
|
||||
{
|
||||
()
|
||||
: any =>
|
||||
1
|
||||
};
|
||||
{
|
||||
():
|
||||
any =>
|
||||
1
|
||||
};
|
||||
{
|
||||
(
|
||||
)
|
||||
: any =>
|
||||
1
|
||||
};
|
||||
{
|
||||
(
|
||||
): (
|
||||
| any
|
||||
) =>
|
||||
1
|
||||
};
|
||||
{
|
||||
(
|
||||
):
|
||||
NonNullable<any
|
||||
> =>
|
||||
1
|
||||
};
|
||||
{
|
||||
(a, b, c: D = [] as any/*comment-1*/)/*comment-2*/:
|
||||
any =>
|
||||
1
|
||||
};
|
Loading…
Reference in New Issue
Block a user