@tishlang/tish 2.10.1 → 2.16.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +3 -0
- package/bin/tish +0 -0
- package/crates/tish/Cargo.toml +1 -1
- package/crates/tish/src/cli_help.rs +16 -0
- package/crates/tish/src/main.rs +24 -4
- package/crates/tish/tests/integration_test.rs +149 -0
- package/crates/tish_ast/src/ast.rs +10 -0
- package/crates/tish_builtins/src/array.rs +529 -56
- package/crates/tish_builtins/src/collections.rs +114 -40
- package/crates/tish_builtins/src/string.rs +95 -8
- package/crates/tish_bytecode/src/chunk.rs +7 -0
- package/crates/tish_bytecode/src/compiler.rs +560 -64
- package/crates/tish_bytecode/src/lib.rs +1 -1
- package/crates/tish_bytecode/src/opcode.rs +154 -2
- package/crates/tish_bytecode/src/serialize.rs +2 -0
- package/crates/tish_bytecode/tests/append_local_string_builder.rs +63 -0
- package/crates/tish_bytecode/tests/math_unary_intrinsic.rs +47 -0
- package/crates/tish_compile/src/codegen.rs +17736 -5269
- package/crates/tish_compile/src/infer.rs +1707 -190
- package/crates/tish_compile/src/lib.rs +29 -4
- package/crates/tish_compile/src/resolve.rs +66 -5
- package/crates/tish_compile/src/types.rs +224 -28
- package/crates/tish_compile/tests/dump_codegen.rs +21 -0
- package/crates/tish_compile/tests/perf_codegen_169_173.rs +8 -17
- package/crates/tish_compile/tests/perf_codegen_173_part3.rs +61 -0
- package/crates/tish_compile/tests/perf_codegen_174.rs +160 -0
- package/crates/tish_compile/tests/perf_codegen_175.rs +190 -0
- package/crates/tish_compile/tests/perf_codegen_176.rs +60 -0
- package/crates/tish_compile/tests/perf_codegen_177.rs +167 -0
- package/crates/tish_compile/tests/perf_codegen_178.rs +114 -0
- package/crates/tish_compile/tests/perf_codegen_178_rec.rs +124 -0
- package/crates/tish_compile/tests/perf_codegen_181.rs +36 -0
- package/crates/tish_compile/tests/perf_codegen_320.rs +211 -0
- package/crates/tish_compile/tests/perf_codegen_module_const_forof.rs +40 -0
- package/crates/tish_compile_js/src/codegen.rs +91 -4
- package/crates/tish_compile_js/src/lib.rs +5 -2
- package/crates/tish_compile_js/src/tests_jsx.rs +175 -7
- package/crates/tish_compiler_wasm/src/resolve_virtual.rs +100 -2
- package/crates/tish_core/Cargo.toml +4 -0
- package/crates/tish_core/src/json.rs +104 -5
- package/crates/tish_core/src/lib.rs +174 -0
- package/crates/tish_core/src/shape.rs +4 -2
- package/crates/tish_core/src/value.rs +565 -35
- package/crates/tish_core/src/vmref.rs +14 -0
- package/crates/tish_eval/src/eval.rs +675 -76
- package/crates/tish_eval/src/natives.rs +19 -0
- package/crates/tish_eval/src/value.rs +76 -21
- package/crates/tish_ffi/src/lib.rs +11 -1
- package/crates/tish_ffi/tests/double_free.rs +35 -0
- package/crates/tish_fmt/src/lib.rs +75 -1
- package/crates/tish_lexer/src/lib.rs +76 -0
- package/crates/tish_lexer/src/token.rs +4 -0
- package/crates/tish_lint/src/lib.rs +126 -0
- package/crates/tish_lsp/README.md +2 -1
- package/crates/tish_lsp/src/main.rs +378 -28
- package/crates/tish_native/src/build.rs +41 -0
- package/crates/tish_parser/Cargo.toml +4 -0
- package/crates/tish_parser/src/lib.rs +27 -0
- package/crates/tish_parser/src/parser.rs +302 -20
- package/crates/tish_resolve/src/lib.rs +9 -0
- package/crates/tish_runtime/Cargo.toml +5 -0
- package/crates/tish_runtime/src/http.rs +28 -10
- package/crates/tish_runtime/src/http_fetch.rs +150 -1
- package/crates/tish_runtime/src/http_prefork.rs +72 -11
- package/crates/tish_runtime/src/lib.rs +523 -42
- package/crates/tish_runtime/src/timers.rs +49 -2
- package/crates/tish_ui/src/jsx.rs +253 -0
- package/crates/tish_vm/src/jit.rs +2514 -117
- package/crates/tish_vm/src/vm.rs +1227 -182
- package/package.json +1 -1
- package/platform/darwin-arm64/tish +0 -0
- package/platform/darwin-x64/tish +0 -0
- package/platform/linux-arm64/tish +0 -0
- package/platform/linux-x64/tish +0 -0
- package/platform/win32-x64/tish.exe +0 -0
|
@@ -14,6 +14,26 @@ fn next_id() -> u64 {
|
|
|
14
14
|
NEXT_ID.fetch_add(1, Ordering::SeqCst)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/// Maximum number of LIVE (registered, not-yet-fired) timers per worker thread. A program that keeps
|
|
18
|
+
/// scheduling `setTimeout`/`setInterval` without them draining would otherwise grow the registry (and
|
|
19
|
+
/// its retained callbacks + closed-over data) without bound (#384). Past the cap a new timer is
|
|
20
|
+
/// dropped rather than registered. Override with `TISH_MAX_TIMERS`; default 100k — far above any real
|
|
21
|
+
/// timer workload, low enough to bound memory.
|
|
22
|
+
fn max_live_timers() -> usize {
|
|
23
|
+
// Read per call (timer registration is not a hot path, and the cap exists precisely to bound the
|
|
24
|
+
// pathological caller): keeps the limit overridable per test without a process-global cache.
|
|
25
|
+
std::env::var("TISH_MAX_TIMERS")
|
|
26
|
+
.ok()
|
|
27
|
+
.and_then(|v| v.parse().ok())
|
|
28
|
+
.filter(|&n| n > 0)
|
|
29
|
+
.unwrap_or(100_000)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#[cfg(test)]
|
|
33
|
+
fn registry_len() -> usize {
|
|
34
|
+
REGISTRY.with(|r| r.borrow().len())
|
|
35
|
+
}
|
|
36
|
+
|
|
17
37
|
struct TimerEntry {
|
|
18
38
|
due: Instant,
|
|
19
39
|
callback: Value,
|
|
@@ -114,7 +134,12 @@ pub fn set_timeout(args: &[Value]) -> Value {
|
|
|
114
134
|
let id = next_id();
|
|
115
135
|
let due = Instant::now() + Duration::from_millis(delay_ms);
|
|
116
136
|
REGISTRY.with(|r| {
|
|
117
|
-
r.borrow_mut()
|
|
137
|
+
let mut reg = r.borrow_mut();
|
|
138
|
+
// #384: bound the live-timer count so a runaway scheduler can't grow the registry unbounded.
|
|
139
|
+
if reg.len() >= max_live_timers() {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
reg.insert(
|
|
118
143
|
id,
|
|
119
144
|
TimerEntry {
|
|
120
145
|
due,
|
|
@@ -138,7 +163,12 @@ pub fn set_interval(args: &[Value]) -> Value {
|
|
|
138
163
|
let id = next_id();
|
|
139
164
|
let due = Instant::now() + Duration::from_millis(interval_ms);
|
|
140
165
|
REGISTRY.with(|r| {
|
|
141
|
-
r.borrow_mut()
|
|
166
|
+
let mut reg = r.borrow_mut();
|
|
167
|
+
// #384: bound the live-timer count (see set_timeout).
|
|
168
|
+
if reg.len() >= max_live_timers() {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
reg.insert(
|
|
142
172
|
id,
|
|
143
173
|
TimerEntry {
|
|
144
174
|
due,
|
|
@@ -170,3 +200,20 @@ pub fn clear_timeout(args: &[Value]) -> Value {
|
|
|
170
200
|
pub fn clear_interval(args: &[Value]) -> Value {
|
|
171
201
|
clear_timeout(args)
|
|
172
202
|
}
|
|
203
|
+
|
|
204
|
+
#[cfg(test)]
|
|
205
|
+
mod timer_cap_tests_384 {
|
|
206
|
+
use super::*;
|
|
207
|
+
|
|
208
|
+
#[test]
|
|
209
|
+
fn set_timeout_is_bounded_by_max_timers() {
|
|
210
|
+
// Each `#[test]` runs on its own thread, so REGISTRY (thread_local) starts empty here.
|
|
211
|
+
std::env::set_var("TISH_MAX_TIMERS", "5");
|
|
212
|
+
let cb = tishlang_core::native_fn(|_| Value::Null);
|
|
213
|
+
for _ in 0..20 {
|
|
214
|
+
let _ = set_timeout(&[Value::Function(cb.clone()), Value::Number(10_000.0)]);
|
|
215
|
+
}
|
|
216
|
+
assert_eq!(registry_len(), 5, "live timers must be capped at TISH_MAX_TIMERS");
|
|
217
|
+
std::env::remove_var("TISH_MAX_TIMERS");
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -240,6 +240,7 @@ fn collect_fun_decl_names_stmt(stmt: &Statement, names: &mut HashSet<String>) {
|
|
|
240
240
|
Statement::Export { declaration, .. } => match declaration.as_ref() {
|
|
241
241
|
ExportDeclaration::Named(inner) => collect_fun_decl_names_stmt(inner, names),
|
|
242
242
|
ExportDeclaration::Default(e) => collect_fun_decl_names_expr(e, names),
|
|
243
|
+
ExportDeclaration::ReExport { .. } => {}
|
|
243
244
|
},
|
|
244
245
|
Statement::Import { .. }
|
|
245
246
|
| Statement::Break { .. }
|
|
@@ -541,6 +542,257 @@ pub fn program_contains_jsx(program: &tishlang_ast::Program) -> bool {
|
|
|
541
542
|
program.statements.iter().any(stmt_contains_jsx)
|
|
542
543
|
}
|
|
543
544
|
|
|
545
|
+
/// Whether the program contains any JSX **fragment** (`<>…</>`). Fragments lower to
|
|
546
|
+
/// `h(Fragment, null, …)`, so they require the `Fragment` runtime binding in addition to `h`.
|
|
547
|
+
pub fn program_contains_jsx_fragment(program: &tishlang_ast::Program) -> bool {
|
|
548
|
+
program.statements.iter().any(stmt_contains_jsx_fragment)
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/// Which JSX runtime bindings (`h`, `Fragment`) a module needs auto-imported, given which names are
|
|
552
|
+
/// already in module scope. Any JSX needs `h`; fragments additionally need `Fragment`. A binding is
|
|
553
|
+
/// omitted if it's already provided by a top-level import/declaration (see
|
|
554
|
+
/// [`collect_jsx_runtime_bindings_in_scope`]).
|
|
555
|
+
///
|
|
556
|
+
/// Returns a subset of `["h", "Fragment"]` (in that order), or `[]` when the module has no JSX.
|
|
557
|
+
pub fn jsx_runtime_imports_needed(program: &tishlang_ast::Program) -> Vec<&'static str> {
|
|
558
|
+
if !program_contains_jsx(program) {
|
|
559
|
+
return Vec::new();
|
|
560
|
+
}
|
|
561
|
+
let in_scope = collect_jsx_runtime_bindings_in_scope(program);
|
|
562
|
+
let mut needed = Vec::new();
|
|
563
|
+
if !in_scope.contains("h") {
|
|
564
|
+
needed.push("h");
|
|
565
|
+
}
|
|
566
|
+
if program_contains_jsx_fragment(program) && !in_scope.contains("Fragment") {
|
|
567
|
+
needed.push("Fragment");
|
|
568
|
+
}
|
|
569
|
+
needed
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/// Top-level names that already bind the JSX runtime symbols `h` / `Fragment`, so the auto-import
|
|
573
|
+
/// must not shadow or duplicate them. Covers named imports (local alias), top-level `const`/`let`,
|
|
574
|
+
/// and `fn` declarations, including those wrapped in `export`.
|
|
575
|
+
pub fn collect_jsx_runtime_bindings_in_scope(program: &tishlang_ast::Program) -> HashSet<String> {
|
|
576
|
+
use tishlang_ast::{ExportDeclaration, ImportSpecifier, Statement};
|
|
577
|
+
let mut names = HashSet::new();
|
|
578
|
+
let note = |n: &str, names: &mut HashSet<String>| {
|
|
579
|
+
if n == "h" || n == "Fragment" {
|
|
580
|
+
names.insert(n.to_string());
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
for stmt in &program.statements {
|
|
584
|
+
match stmt {
|
|
585
|
+
Statement::Import { specifiers, .. } => {
|
|
586
|
+
for s in specifiers {
|
|
587
|
+
if let ImportSpecifier::Named { name, alias, .. } = s {
|
|
588
|
+
let local = alias.as_deref().unwrap_or(name.as_ref());
|
|
589
|
+
note(local, &mut names);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
Statement::VarDecl { name, .. } | Statement::FunDecl { name, .. } => {
|
|
594
|
+
note(name.as_ref(), &mut names)
|
|
595
|
+
}
|
|
596
|
+
Statement::Export { declaration, .. } => {
|
|
597
|
+
if let ExportDeclaration::Named(inner) = declaration.as_ref() {
|
|
598
|
+
match inner.as_ref() {
|
|
599
|
+
Statement::VarDecl { name, .. } | Statement::FunDecl { name, .. } => {
|
|
600
|
+
note(name.as_ref(), &mut names)
|
|
601
|
+
}
|
|
602
|
+
_ => {}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
_ => {}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
names
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
fn stmt_contains_jsx_fragment(stmt: &tishlang_ast::Statement) -> bool {
|
|
613
|
+
use tishlang_ast::{ExportDeclaration, Statement};
|
|
614
|
+
match stmt {
|
|
615
|
+
Statement::Block { statements, .. } | Statement::Multi { statements, .. } => {
|
|
616
|
+
statements.iter().any(stmt_contains_jsx_fragment)
|
|
617
|
+
}
|
|
618
|
+
Statement::VarDecl { init, .. } => init.as_ref().is_some_and(expr_contains_jsx_fragment),
|
|
619
|
+
Statement::VarDeclDestructure { init, .. } => expr_contains_jsx_fragment(init),
|
|
620
|
+
Statement::ExprStmt { expr, .. } => expr_contains_jsx_fragment(expr),
|
|
621
|
+
Statement::Return { value, .. } => value.as_ref().is_some_and(expr_contains_jsx_fragment),
|
|
622
|
+
Statement::If {
|
|
623
|
+
cond,
|
|
624
|
+
then_branch,
|
|
625
|
+
else_branch,
|
|
626
|
+
..
|
|
627
|
+
} => {
|
|
628
|
+
expr_contains_jsx_fragment(cond)
|
|
629
|
+
|| stmt_contains_jsx_fragment(then_branch)
|
|
630
|
+
|| else_branch
|
|
631
|
+
.as_ref()
|
|
632
|
+
.is_some_and(|s| stmt_contains_jsx_fragment(s))
|
|
633
|
+
}
|
|
634
|
+
Statement::While { cond, body, .. } | Statement::DoWhile { body, cond, .. } => {
|
|
635
|
+
expr_contains_jsx_fragment(cond) || stmt_contains_jsx_fragment(body)
|
|
636
|
+
}
|
|
637
|
+
Statement::For {
|
|
638
|
+
init,
|
|
639
|
+
cond,
|
|
640
|
+
update,
|
|
641
|
+
body,
|
|
642
|
+
..
|
|
643
|
+
} => {
|
|
644
|
+
init.as_ref().is_some_and(|s| stmt_contains_jsx_fragment(s))
|
|
645
|
+
|| cond.as_ref().is_some_and(expr_contains_jsx_fragment)
|
|
646
|
+
|| update.as_ref().is_some_and(expr_contains_jsx_fragment)
|
|
647
|
+
|| stmt_contains_jsx_fragment(body)
|
|
648
|
+
}
|
|
649
|
+
Statement::ForOf { iterable, body, .. } => {
|
|
650
|
+
expr_contains_jsx_fragment(iterable) || stmt_contains_jsx_fragment(body)
|
|
651
|
+
}
|
|
652
|
+
Statement::Switch {
|
|
653
|
+
expr,
|
|
654
|
+
cases,
|
|
655
|
+
default_body,
|
|
656
|
+
..
|
|
657
|
+
} => {
|
|
658
|
+
expr_contains_jsx_fragment(expr)
|
|
659
|
+
|| cases.iter().any(|(e, ss)| {
|
|
660
|
+
e.as_ref().is_some_and(expr_contains_jsx_fragment)
|
|
661
|
+
|| ss.iter().any(stmt_contains_jsx_fragment)
|
|
662
|
+
})
|
|
663
|
+
|| default_body
|
|
664
|
+
.as_ref()
|
|
665
|
+
.is_some_and(|ss| ss.iter().any(stmt_contains_jsx_fragment))
|
|
666
|
+
}
|
|
667
|
+
Statement::Try {
|
|
668
|
+
body,
|
|
669
|
+
catch_body,
|
|
670
|
+
finally_body,
|
|
671
|
+
..
|
|
672
|
+
} => {
|
|
673
|
+
stmt_contains_jsx_fragment(body)
|
|
674
|
+
|| catch_body
|
|
675
|
+
.as_ref()
|
|
676
|
+
.is_some_and(|s| stmt_contains_jsx_fragment(s))
|
|
677
|
+
|| finally_body
|
|
678
|
+
.as_ref()
|
|
679
|
+
.is_some_and(|s| stmt_contains_jsx_fragment(s))
|
|
680
|
+
}
|
|
681
|
+
Statement::FunDecl { body, .. } => stmt_contains_jsx_fragment(body),
|
|
682
|
+
Statement::Throw { value, .. } => expr_contains_jsx_fragment(value),
|
|
683
|
+
Statement::Export { declaration, .. } => match declaration.as_ref() {
|
|
684
|
+
ExportDeclaration::Named(inner) => stmt_contains_jsx_fragment(inner),
|
|
685
|
+
ExportDeclaration::Default(e) => expr_contains_jsx_fragment(e),
|
|
686
|
+
ExportDeclaration::ReExport { .. } => false,
|
|
687
|
+
},
|
|
688
|
+
Statement::Import { .. }
|
|
689
|
+
| Statement::Break { .. }
|
|
690
|
+
| Statement::Continue { .. }
|
|
691
|
+
| Statement::TypeAlias { .. }
|
|
692
|
+
| Statement::DeclareVar { .. }
|
|
693
|
+
| Statement::DeclareFun { .. } => false,
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
fn expr_contains_jsx_fragment(expr: &Expr) -> bool {
|
|
698
|
+
match expr {
|
|
699
|
+
Expr::JsxFragment { .. } => true,
|
|
700
|
+
Expr::JsxElement {
|
|
701
|
+
props, children, ..
|
|
702
|
+
} => {
|
|
703
|
+
props.iter().any(|p| match p {
|
|
704
|
+
JsxProp::Attr {
|
|
705
|
+
value: JsxAttrValue::Expr(e),
|
|
706
|
+
..
|
|
707
|
+
}
|
|
708
|
+
| JsxProp::Spread(e) => expr_contains_jsx_fragment(e),
|
|
709
|
+
_ => false,
|
|
710
|
+
}) || children.iter().any(|c| match c {
|
|
711
|
+
JsxChild::Expr(e) => expr_contains_jsx_fragment(e),
|
|
712
|
+
JsxChild::Text(_) => false,
|
|
713
|
+
})
|
|
714
|
+
}
|
|
715
|
+
Expr::Binary { left, right, .. } => {
|
|
716
|
+
expr_contains_jsx_fragment(left) || expr_contains_jsx_fragment(right)
|
|
717
|
+
}
|
|
718
|
+
Expr::Unary { operand, .. } => expr_contains_jsx_fragment(operand),
|
|
719
|
+
Expr::Assign { value, .. } => expr_contains_jsx_fragment(value),
|
|
720
|
+
Expr::Call { callee, args, .. } => {
|
|
721
|
+
expr_contains_jsx_fragment(callee)
|
|
722
|
+
|| args.iter().any(|a| match a {
|
|
723
|
+
tishlang_ast::CallArg::Expr(e) | tishlang_ast::CallArg::Spread(e) => {
|
|
724
|
+
expr_contains_jsx_fragment(e)
|
|
725
|
+
}
|
|
726
|
+
})
|
|
727
|
+
}
|
|
728
|
+
Expr::Member { object, prop, .. } => {
|
|
729
|
+
expr_contains_jsx_fragment(object)
|
|
730
|
+
|| matches!(prop, tishlang_ast::MemberProp::Expr(e) if expr_contains_jsx_fragment(e))
|
|
731
|
+
}
|
|
732
|
+
Expr::Index { object, index, .. } => {
|
|
733
|
+
expr_contains_jsx_fragment(object) || expr_contains_jsx_fragment(index)
|
|
734
|
+
}
|
|
735
|
+
Expr::Conditional {
|
|
736
|
+
cond,
|
|
737
|
+
then_branch,
|
|
738
|
+
else_branch,
|
|
739
|
+
..
|
|
740
|
+
} => {
|
|
741
|
+
expr_contains_jsx_fragment(cond)
|
|
742
|
+
|| expr_contains_jsx_fragment(then_branch)
|
|
743
|
+
|| expr_contains_jsx_fragment(else_branch)
|
|
744
|
+
}
|
|
745
|
+
Expr::Array { elements, .. } => elements.iter().any(|el| match el {
|
|
746
|
+
ArrayElement::Expr(e) | ArrayElement::Spread(e) => expr_contains_jsx_fragment(e),
|
|
747
|
+
}),
|
|
748
|
+
Expr::Object { props, .. } => props.iter().any(|p| match p {
|
|
749
|
+
ObjectProp::KeyValue(_, e, _) | ObjectProp::Spread(e) => expr_contains_jsx_fragment(e),
|
|
750
|
+
}),
|
|
751
|
+
Expr::ArrowFunction { body, .. } => match body {
|
|
752
|
+
tishlang_ast::ArrowBody::Expr(e) => expr_contains_jsx_fragment(e),
|
|
753
|
+
tishlang_ast::ArrowBody::Block(s) => stmt_contains_jsx_fragment(s),
|
|
754
|
+
},
|
|
755
|
+
Expr::NullishCoalesce { left, right, .. } => {
|
|
756
|
+
expr_contains_jsx_fragment(left) || expr_contains_jsx_fragment(right)
|
|
757
|
+
}
|
|
758
|
+
Expr::TemplateLiteral { exprs, .. } => exprs.iter().any(expr_contains_jsx_fragment),
|
|
759
|
+
Expr::Await { operand, .. } => expr_contains_jsx_fragment(operand),
|
|
760
|
+
Expr::TypeOf { operand, .. } => expr_contains_jsx_fragment(operand),
|
|
761
|
+
Expr::Delete { target, .. } => expr_contains_jsx_fragment(target),
|
|
762
|
+
Expr::CompoundAssign { value, .. } | Expr::LogicalAssign { value, .. } => {
|
|
763
|
+
expr_contains_jsx_fragment(value)
|
|
764
|
+
}
|
|
765
|
+
Expr::MemberAssign { object, value, .. } => {
|
|
766
|
+
expr_contains_jsx_fragment(object) || expr_contains_jsx_fragment(value)
|
|
767
|
+
}
|
|
768
|
+
Expr::IndexAssign {
|
|
769
|
+
object,
|
|
770
|
+
index,
|
|
771
|
+
value,
|
|
772
|
+
..
|
|
773
|
+
} => {
|
|
774
|
+
expr_contains_jsx_fragment(object)
|
|
775
|
+
|| expr_contains_jsx_fragment(index)
|
|
776
|
+
|| expr_contains_jsx_fragment(value)
|
|
777
|
+
}
|
|
778
|
+
Expr::New { callee, args, .. } => {
|
|
779
|
+
expr_contains_jsx_fragment(callee)
|
|
780
|
+
|| args.iter().any(|a| match a {
|
|
781
|
+
tishlang_ast::CallArg::Expr(e) | tishlang_ast::CallArg::Spread(e) => {
|
|
782
|
+
expr_contains_jsx_fragment(e)
|
|
783
|
+
}
|
|
784
|
+
})
|
|
785
|
+
}
|
|
786
|
+
Expr::PostfixInc { .. }
|
|
787
|
+
| Expr::PrefixInc { .. }
|
|
788
|
+
| Expr::PostfixDec { .. }
|
|
789
|
+
| Expr::PrefixDec { .. }
|
|
790
|
+
| Expr::Literal { .. }
|
|
791
|
+
| Expr::Ident { .. }
|
|
792
|
+
| Expr::NativeModuleLoad { .. } => false,
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
544
796
|
fn stmt_contains_jsx(stmt: &tishlang_ast::Statement) -> bool {
|
|
545
797
|
use tishlang_ast::{ExportDeclaration, Statement};
|
|
546
798
|
match stmt {
|
|
@@ -607,6 +859,7 @@ fn stmt_contains_jsx(stmt: &tishlang_ast::Statement) -> bool {
|
|
|
607
859
|
Statement::Export { declaration, .. } => match declaration.as_ref() {
|
|
608
860
|
ExportDeclaration::Named(inner) => stmt_contains_jsx(inner),
|
|
609
861
|
ExportDeclaration::Default(e) => expr_contains_jsx(e),
|
|
862
|
+
ExportDeclaration::ReExport { .. } => false,
|
|
610
863
|
},
|
|
611
864
|
Statement::Import { .. }
|
|
612
865
|
| Statement::Break { .. }
|