@tishlang/tish 1.7.0 → 1.9.0

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.
Files changed (99) hide show
  1. package/Cargo.toml +2 -0
  2. package/README.md +2 -0
  3. package/bin/tish +0 -0
  4. package/crates/js_to_tish/src/transform/expr.rs +28 -8
  5. package/crates/js_to_tish/src/transform/stmt.rs +49 -22
  6. package/crates/tish/Cargo.toml +14 -5
  7. package/crates/tish/src/cargo_native_registry.rs +29 -0
  8. package/crates/tish/src/cli_help.rs +16 -10
  9. package/crates/tish/src/main.rs +87 -32
  10. package/crates/tish/src/repl_completion.rs +3 -3
  11. package/crates/tish/tests/cargo_example_compile.rs +1 -1
  12. package/crates/tish/tests/integration_test.rs +19 -7
  13. package/crates/tish/tests/shortcircuit.rs +1 -1
  14. package/crates/tish_ast/src/ast.rs +80 -9
  15. package/crates/tish_build_utils/Cargo.toml +4 -0
  16. package/crates/tish_build_utils/src/lib.rs +105 -2
  17. package/crates/tish_builtins/Cargo.toml +5 -1
  18. package/crates/tish_builtins/src/array.rs +13 -12
  19. package/crates/tish_builtins/src/construct.rs +34 -33
  20. package/crates/tish_builtins/src/globals.rs +12 -11
  21. package/crates/tish_builtins/src/helpers.rs +2 -1
  22. package/crates/tish_builtins/src/object.rs +3 -2
  23. package/crates/tish_builtins/src/string.rs +73 -3
  24. package/crates/tish_bytecode/src/compiler.rs +12 -14
  25. package/crates/tish_bytecode/src/opcode.rs +12 -3
  26. package/crates/tish_compile/Cargo.toml +1 -0
  27. package/crates/tish_compile/src/codegen.rs +745 -199
  28. package/crates/tish_compile/src/infer.rs +6 -0
  29. package/crates/tish_compile/src/lib.rs +4 -3
  30. package/crates/tish_compile/src/resolve.rs +180 -82
  31. package/crates/tish_compile/src/types.rs +175 -11
  32. package/crates/tish_compile_js/Cargo.toml +1 -0
  33. package/crates/tish_compile_js/src/codegen.rs +152 -29
  34. package/crates/tish_compile_js/src/lib.rs +3 -1
  35. package/crates/tish_compiler_wasm/src/resolve_virtual.rs +31 -12
  36. package/crates/tish_core/Cargo.toml +8 -0
  37. package/crates/tish_core/src/json.rs +102 -53
  38. package/crates/tish_core/src/lib.rs +3 -1
  39. package/crates/tish_core/src/macros.rs +5 -5
  40. package/crates/tish_core/src/value.rs +53 -15
  41. package/crates/tish_core/src/vmref.rs +178 -0
  42. package/crates/tish_eval/Cargo.toml +17 -2
  43. package/crates/tish_eval/src/eval.rs +90 -28
  44. package/crates/tish_eval/src/http.rs +61 -0
  45. package/crates/tish_eval/src/lib.rs +3 -3
  46. package/crates/tish_eval/src/natives.rs +41 -0
  47. package/crates/tish_eval/src/value.rs +7 -3
  48. package/crates/tish_eval/src/value_convert.rs +13 -5
  49. package/crates/tish_fmt/src/lib.rs +120 -30
  50. package/crates/tish_lexer/src/lib.rs +20 -5
  51. package/crates/tish_lexer/src/token.rs +4 -0
  52. package/crates/tish_llvm/src/lib.rs +3 -1
  53. package/crates/tish_lsp/Cargo.toml +4 -1
  54. package/crates/tish_lsp/README.md +1 -1
  55. package/crates/tish_lsp/src/builtin_goto.rs +261 -0
  56. package/crates/tish_lsp/src/import_goto.rs +549 -0
  57. package/crates/tish_lsp/src/main.rs +502 -102
  58. package/crates/tish_native/src/build.rs +3 -2
  59. package/crates/tish_native/src/lib.rs +6 -2
  60. package/crates/tish_opt/src/lib.rs +17 -2
  61. package/crates/tish_parser/src/lib.rs +10 -3
  62. package/crates/tish_parser/src/parser.rs +346 -56
  63. package/crates/tish_pg/Cargo.toml +34 -0
  64. package/crates/tish_pg/README.md +38 -0
  65. package/crates/tish_pg/src/error.rs +52 -0
  66. package/crates/tish_pg/src/lib.rs +967 -0
  67. package/crates/tish_resolve/Cargo.toml +13 -0
  68. package/crates/tish_resolve/src/lib.rs +3436 -0
  69. package/crates/tish_resolve/src/pos.rs +133 -0
  70. package/crates/tish_runtime/Cargo.toml +68 -3
  71. package/crates/tish_runtime/src/http.rs +1123 -141
  72. package/crates/tish_runtime/src/http_fetch.rs +15 -14
  73. package/crates/tish_runtime/src/http_hyper.rs +418 -0
  74. package/crates/tish_runtime/src/http_prefork.rs +189 -0
  75. package/crates/tish_runtime/src/lib.rs +159 -29
  76. package/crates/tish_runtime/src/promise.rs +199 -36
  77. package/crates/tish_runtime/src/promise_io.rs +2 -1
  78. package/crates/tish_runtime/src/timers.rs +37 -1
  79. package/crates/tish_runtime/src/ws.rs +26 -28
  80. package/crates/tish_ui/src/jsx.rs +279 -8
  81. package/crates/tish_ui/src/lib.rs +5 -2
  82. package/crates/tish_ui/src/runtime/hooks.rs +406 -45
  83. package/crates/tish_ui/src/runtime/mod.rs +36 -9
  84. package/crates/tish_vm/Cargo.toml +15 -5
  85. package/crates/tish_vm/src/vm.rs +506 -259
  86. package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +3 -1
  87. package/crates/tish_wasm/src/lib.rs +17 -14
  88. package/crates/tish_wasm_runtime/Cargo.toml +2 -1
  89. package/crates/tish_wasm_runtime/src/lib.rs +1 -1
  90. package/crates/tishlang_cargo_bindgen/Cargo.toml +1 -0
  91. package/crates/tishlang_cargo_bindgen/src/discover.rs +68 -0
  92. package/crates/tishlang_cargo_bindgen/src/lib.rs +5 -4
  93. package/justfile +8 -0
  94. package/package.json +1 -1
  95. package/platform/darwin-arm64/tish +0 -0
  96. package/platform/darwin-x64/tish +0 -0
  97. package/platform/linux-arm64/tish +0 -0
  98. package/platform/linux-x64/tish +0 -0
  99. package/platform/win32-x64/tish.exe +0 -0
@@ -135,6 +135,7 @@ fn infer_statement(stmt: &Statement, ctx: &mut InferCtx) -> Statement {
135
135
  match stmt {
136
136
  Statement::VarDecl {
137
137
  name,
138
+ name_span,
138
139
  mutable,
139
140
  type_ann,
140
141
  init,
@@ -152,6 +153,7 @@ fn infer_statement(stmt: &Statement, ctx: &mut InferCtx) -> Statement {
152
153
  }
153
154
  Statement::VarDecl {
154
155
  name: name.clone(),
156
+ name_span: *name_span,
155
157
  mutable: *mutable,
156
158
  type_ann: inferred,
157
159
  init: init.clone(),
@@ -189,6 +191,7 @@ fn infer_statement(stmt: &Statement, ctx: &mut InferCtx) -> Statement {
189
191
  }
190
192
  Statement::ForOf {
191
193
  name,
194
+ name_span,
192
195
  iterable,
193
196
  body,
194
197
  span,
@@ -198,6 +201,7 @@ fn infer_statement(stmt: &Statement, ctx: &mut InferCtx) -> Statement {
198
201
  ctx.pop_scope();
199
202
  Statement::ForOf {
200
203
  name: name.clone(),
204
+ name_span: *name_span,
201
205
  iterable: iterable.clone(),
202
206
  body: new_body,
203
207
  span: *span,
@@ -243,6 +247,7 @@ fn infer_statement(stmt: &Statement, ctx: &mut InferCtx) -> Statement {
243
247
  Statement::FunDecl {
244
248
  async_,
245
249
  name,
250
+ name_span,
246
251
  params,
247
252
  rest_param,
248
253
  return_type,
@@ -267,6 +272,7 @@ fn infer_statement(stmt: &Statement, ctx: &mut InferCtx) -> Statement {
267
272
  Statement::FunDecl {
268
273
  async_: *async_,
269
274
  name: name.clone(),
275
+ name_span: *name_span,
270
276
  params: params.clone(),
271
277
  rest_param: rest_param.clone(),
272
278
  return_type: return_type.clone(),
@@ -16,9 +16,10 @@ pub use resolve::{
16
16
  cargo_export_fn_name, compute_native_build_artifacts, detect_cycles, export_name_to_rust_ident,
17
17
  extract_native_import_features, format_rust_dependencies_toml, generate_native_wrapper_rs,
18
18
  has_external_native_imports, has_native_imports, infer_native_module_exports,
19
- is_builtin_native_spec, is_cargo_native_spec, merge_modules, read_project_tish_config,
20
- resolve_native_modules, resolve_project, resolve_project_from_stdin, NativeBuildArtifacts,
21
- NativeModuleInit, ResolvedNativeModule,
19
+ is_builtin_native_spec, is_cargo_native_spec, is_native_import, merge_modules,
20
+ normalize_builtin_spec, read_project_tish_config,
21
+ resolve_bare_spec, resolve_native_modules, resolve_project, resolve_project_from_stdin,
22
+ MergedProgram, NativeBuildArtifacts, NativeModuleInit, ResolvedNativeModule,
22
23
  };
23
24
  pub use types::{RustType, TypeContext};
24
25
 
@@ -49,6 +49,7 @@ pub struct NativeBuildArtifacts {
49
49
  const BUILTIN_ALIASES: &[(&str, &str)] = &[
50
50
  ("fs", "tish:fs"),
51
51
  ("http", "tish:http"),
52
+ ("timers", "tish:timers"),
52
53
  ("process", "tish:process"),
53
54
  ("ws", "tish:ws"),
54
55
  ];
@@ -66,8 +67,8 @@ pub fn normalize_builtin_spec(spec: &str) -> Option<String> {
66
67
 
67
68
  /// Built-in modules that come from tishlang_runtime, not from package.json.
68
69
  pub fn is_builtin_native_spec(spec: &str) -> bool {
69
- matches!(spec, "tish:fs" | "tish:http" | "tish:process" | "tish:ws")
70
- || matches!(spec, "fs" | "http" | "process" | "ws")
70
+ matches!(spec, "tish:fs" | "tish:http" | "tish:timers" | "tish:process" | "tish:ws")
71
+ || matches!(spec, "fs" | "http" | "timers" | "process" | "ws")
71
72
  }
72
73
 
73
74
  /// Resolve all native imports in a merged program via package.json lookup.
@@ -388,7 +389,7 @@ pub fn generate_native_wrapper_rs(
388
389
  use std::cell::RefCell;\n\
389
390
  use std::rc::Rc;\n\
390
391
  use std::sync::Arc;\n\
391
- use tishlang_runtime::{ObjectMap, Value};\n\n",
392
+ use tishlang_runtime::{ObjectMap, Value, VmRef};\n\n",
392
393
  );
393
394
  let mut any = false;
394
395
  for m in modules {
@@ -414,11 +415,11 @@ pub fn generate_native_wrapper_rs(
414
415
  let rust_fn = export_name_to_rust_ident(&export_name);
415
416
  let key_lit = format!("{:?}", export_name);
416
417
  file.push_str(&format!(
417
- " m.insert(Arc::from({}), Value::Function(Rc::new(|args: &[Value]| {{\n {}::{}(args)\n }})));\n",
418
+ " m.insert(Arc::from({}), Value::native(|args: &[Value]| {{\n {}::{}(args)\n }}));\n",
418
419
  key_lit, shim_crate, rust_fn
419
420
  ));
420
421
  }
421
- file.push_str(" Value::Object(Rc::new(RefCell::new(m)))\n}\n\n");
422
+ file.push_str(" Value::Object(VmRef::new(m))\n}\n\n");
422
423
  }
423
424
  if !any {
424
425
  return String::new();
@@ -719,7 +720,7 @@ fn load_module_recursive(
719
720
  }
720
721
 
721
722
  /// Returns true for native module imports that don't resolve to files.
722
- /// - fs, http, process, ws (Node-compatible aliases for tish:fs, tish:http, tish:process, tish:ws)
723
+ /// - fs, http, timers, process, ws (Node-compatible aliases for tish:*)
723
724
  /// - tish:egui, tish:polars, etc.
724
725
  /// - cargo:… (Cargo `rustDependencies` + generated wrapper; Rust native backend)
725
726
  /// - @scope/package (npm-style)
@@ -727,7 +728,7 @@ pub fn is_native_import(spec: &str) -> bool {
727
728
  spec.starts_with("tish:")
728
729
  || spec.starts_with("cargo:")
729
730
  || spec.starts_with('@')
730
- || matches!(spec, "fs" | "http" | "process" | "ws")
731
+ || matches!(spec, "fs" | "http" | "timers" | "process" | "ws")
731
732
  }
732
733
 
733
734
  /// Map native spec to Cargo feature name for built-in tish:* modules.
@@ -736,30 +737,52 @@ pub fn native_spec_to_feature(spec: &str) -> Option<String> {
736
737
  canonical.strip_prefix("tish:").map(|s| s.to_string())
737
738
  }
738
739
 
739
- /// Resolve a bare specifier (e.g. "lattish") to a path via node_modules.
740
- fn resolve_bare_spec(spec: &str, from_dir: &Path, _project_root: &Path) -> Option<PathBuf> {
740
+ /// Resolve `package.json` at `pkg_root` to the package's main `.tish` entry, if `name` matches `spec`.
741
+ fn resolve_package_root_to_entry(pkg_root: &Path, spec: &str) -> Option<PathBuf> {
742
+ let pkg_json = pkg_root.join("package.json");
743
+ if !pkg_json.exists() {
744
+ return None;
745
+ }
746
+ if read_package_name(&pkg_json).as_deref() != Some(spec) {
747
+ return None;
748
+ }
749
+ let content = std::fs::read_to_string(&pkg_json).ok()?;
750
+ let json: serde_json::Value = serde_json::from_str(&content).ok()?;
751
+ let entry = json
752
+ .get("tish")
753
+ .and_then(|t| t.get("module"))
754
+ .and_then(|m| m.as_str())
755
+ .or_else(|| json.get("main").and_then(|m| m.as_str()))
756
+ .unwrap_or("index.tish");
757
+ let entry_clean = entry.trim_start_matches("./");
758
+ let resolved = pkg_root.join(entry_clean);
759
+ if !resolved.exists() {
760
+ return None;
761
+ }
762
+ match resolved.canonicalize() {
763
+ Ok(p) => Some(p),
764
+ Err(_) => Some(resolved),
765
+ }
766
+ }
767
+
768
+ /// Resolve a bare specifier (e.g. "lattish") to the package entry `.tish` file.
769
+ ///
770
+ /// Walks upward from `from_dir` and, at each level, checks (same order as native [`find_package_dir`]):
771
+ /// - `node_modules/<spec>/`
772
+ /// - `<spec>/` as a sibling directory (monorepo: `…/tish/tish-candle` next to `…/tish/tish-hub`)
773
+ /// - the search directory itself if its `package.json` name matches `spec`
774
+ pub fn resolve_bare_spec(spec: &str, from_dir: &Path, _project_root: &Path) -> Option<PathBuf> {
741
775
  let mut search = from_dir.to_path_buf();
742
776
  loop {
743
- let node_mod = search.join("node_modules").join(spec);
744
- let pkg_json = node_mod.join("package.json");
745
- if pkg_json.exists() {
746
- if let Some(name) = read_package_name(&pkg_json) {
747
- if name == spec {
748
- let content = std::fs::read_to_string(&pkg_json).ok()?;
749
- let json: serde_json::Value = serde_json::from_str(&content).ok()?;
750
- let entry = json
751
- .get("tish")
752
- .and_then(|t| t.get("module"))
753
- .and_then(|m| m.as_str())
754
- .or_else(|| json.get("main").and_then(|m| m.as_str()));
755
- let entry = entry.unwrap_or("index.tish");
756
- let entry_clean = entry.trim_start_matches("./");
757
- let resolved = node_mod.join(entry_clean);
758
- if resolved.exists() {
759
- return resolved.canonicalize().ok();
760
- }
761
- }
762
- }
777
+ if let Some(p) = resolve_package_root_to_entry(&search.join("node_modules").join(spec), spec)
778
+ {
779
+ return Some(p);
780
+ }
781
+ if let Some(p) = resolve_package_root_to_entry(&search.join(spec), spec) {
782
+ return Some(p);
783
+ }
784
+ if let Some(p) = resolve_package_root_to_entry(&search, spec) {
785
+ return Some(p);
763
786
  }
764
787
  if let Some(parent) = search.parent() {
765
788
  if parent == search {
@@ -790,7 +813,7 @@ fn resolve_import_path(
790
813
  return Ok(path);
791
814
  }
792
815
  return Err(format!(
793
- "Package '{}' not found in node_modules. Install it with: npm install {}",
816
+ "Package '{}' not found. Install with `npm install {}`, or place the package under node_modules/ or as a sibling directory (same layout as native `find_package_dir`).",
794
817
  spec, spec
795
818
  ));
796
819
  }
@@ -885,10 +908,27 @@ fn has_cycle_from(
885
908
  Ok(false)
886
909
  }
887
910
 
911
+ /// Result of [`merge_modules`]: merged AST plus, per top-level statement, the originating `.tish` file.
912
+ #[derive(Debug)]
913
+ pub struct MergedProgram {
914
+ pub program: Program,
915
+ pub statement_sources: Vec<PathBuf>,
916
+ }
917
+
918
+ fn merge_push(
919
+ statements: &mut Vec<Statement>,
920
+ statement_sources: &mut Vec<PathBuf>,
921
+ stmt: Statement,
922
+ source: PathBuf,
923
+ ) {
924
+ statements.push(stmt);
925
+ statement_sources.push(source);
926
+ }
927
+
888
928
  /// Merge all resolved modules into a single program. Dependencies are emitted first.
889
929
  /// Import statements are rewritten as bindings from already-emitted dep exports.
890
930
  /// Export statements are unwrapped (the inner declaration is emitted).
891
- pub fn merge_modules(modules: Vec<ResolvedModule>) -> Result<Program, String> {
931
+ pub fn merge_modules(modules: Vec<ResolvedModule>) -> Result<MergedProgram, String> {
892
932
  let path_to_idx: HashMap<PathBuf, usize> = modules
893
933
  .iter()
894
934
  .enumerate()
@@ -919,7 +959,9 @@ pub fn merge_modules(modules: Vec<ResolvedModule>) -> Result<Program, String> {
919
959
  }
920
960
 
921
961
  let mut statements = Vec::new();
962
+ let mut statement_sources = Vec::new();
922
963
  for (idx, module) in modules.iter().enumerate() {
964
+ let src_path = module.path.clone();
923
965
  let dir = module.path.parent().unwrap_or(Path::new("."));
924
966
  for stmt in &module.program.statements {
925
967
  match stmt {
@@ -935,32 +977,44 @@ pub fn merge_modules(modules: Vec<ResolvedModule>) -> Result<Program, String> {
935
977
  // Emit VarDecl with NativeModuleLoad for each specifier
936
978
  for spec in specifiers {
937
979
  match spec {
938
- ImportSpecifier::Named { name, alias } => {
980
+ ImportSpecifier::Named {
981
+ name,
982
+ name_span,
983
+ alias,
984
+ alias_span,
985
+ } => {
939
986
  let bind = alias.as_deref().unwrap_or(name.as_ref());
987
+ let decl_name_span = alias_span.as_ref().unwrap_or(name_span);
940
988
  let init = Expr::NativeModuleLoad {
941
989
  spec: Arc::from(canonical_spec.clone()),
942
990
  export_name: name.clone(),
943
991
  span: *span,
944
992
  };
945
- statements.push(Statement::VarDecl {
946
- name: Arc::from(bind),
947
- mutable: false,
948
- type_ann: None,
949
- init: Some(init),
950
- span: *span,
951
- });
993
+ merge_push(
994
+ &mut statements,
995
+ &mut statement_sources,
996
+ Statement::VarDecl {
997
+ name: Arc::from(bind),
998
+ name_span: *decl_name_span,
999
+ mutable: false,
1000
+ type_ann: None,
1001
+ init: Some(init),
1002
+ span: *span,
1003
+ },
1004
+ src_path.clone(),
1005
+ );
952
1006
  }
953
- ImportSpecifier::Namespace(ns) => {
1007
+ ImportSpecifier::Namespace { name, .. } => {
954
1008
  return Err(format!(
955
1009
  "Namespace import (* as {}) not supported for native module '{}'",
956
- ns.as_ref(),
1010
+ name.as_ref(),
957
1011
  from.as_ref()
958
1012
  ));
959
1013
  }
960
- ImportSpecifier::Default(bind) => {
1014
+ ImportSpecifier::Default { name, .. } => {
961
1015
  return Err(format!(
962
1016
  "Default import '{}' not supported for native module '{}'. Use named import, e.g. import {{ egui }} from '{}'",
963
- bind.as_ref(),
1017
+ name.as_ref(),
964
1018
  from.as_ref(),
965
1019
  from.as_ref()
966
1020
  ));
@@ -977,26 +1031,38 @@ pub fn merge_modules(modules: Vec<ResolvedModule>) -> Result<Program, String> {
977
1031
  let dep_exports = &module_exports[dep_idx];
978
1032
  for spec in specifiers {
979
1033
  match spec {
980
- ImportSpecifier::Named { name, alias } => {
1034
+ ImportSpecifier::Named {
1035
+ name,
1036
+ name_span,
1037
+ alias,
1038
+ alias_span,
1039
+ } => {
981
1040
  let source = dep_exports
982
1041
  .get(name.as_ref())
983
1042
  .cloned()
984
1043
  .unwrap_or_else(|| name.to_string());
985
1044
  let bind = alias.as_deref().unwrap_or(name.as_ref());
986
1045
  if bind != source {
987
- statements.push(Statement::VarDecl {
988
- name: Arc::from(bind),
989
- mutable: false,
990
- type_ann: None,
991
- init: Some(Expr::Ident {
992
- name: Arc::from(source),
1046
+ let decl_name_span = alias_span.as_ref().unwrap_or(name_span);
1047
+ merge_push(
1048
+ &mut statements,
1049
+ &mut statement_sources,
1050
+ Statement::VarDecl {
1051
+ name: Arc::from(bind),
1052
+ name_span: *decl_name_span,
1053
+ mutable: false,
1054
+ type_ann: None,
1055
+ init: Some(Expr::Ident {
1056
+ name: Arc::from(source),
1057
+ span: *span,
1058
+ }),
993
1059
  span: *span,
994
- }),
995
- span: *span,
996
- });
1060
+ },
1061
+ src_path.clone(),
1062
+ );
997
1063
  }
998
1064
  }
999
- ImportSpecifier::Namespace(ns) => {
1065
+ ImportSpecifier::Namespace { name, name_span } => {
1000
1066
  let mut props = Vec::new();
1001
1067
  for (k, v) in dep_exports {
1002
1068
  props.push(tishlang_ast::ObjectProp::KeyValue(
@@ -1007,51 +1073,83 @@ pub fn merge_modules(modules: Vec<ResolvedModule>) -> Result<Program, String> {
1007
1073
  },
1008
1074
  ));
1009
1075
  }
1010
- statements.push(Statement::VarDecl {
1011
- name: ns.clone(),
1012
- mutable: false,
1013
- type_ann: None,
1014
- init: Some(Expr::Object { props, span: *span }),
1015
- span: *span,
1016
- });
1076
+ merge_push(
1077
+ &mut statements,
1078
+ &mut statement_sources,
1079
+ Statement::VarDecl {
1080
+ name: name.clone(),
1081
+ name_span: *name_span,
1082
+ mutable: false,
1083
+ type_ann: None,
1084
+ init: Some(Expr::Object { props, span: *span }),
1085
+ span: *span,
1086
+ },
1087
+ src_path.clone(),
1088
+ );
1017
1089
  }
1018
- ImportSpecifier::Default(bind) => {
1090
+ ImportSpecifier::Default { name, name_span } => {
1019
1091
  let source =
1020
1092
  dep_exports.get("default").cloned().ok_or_else(|| {
1021
1093
  format!("Module '{}' has no default export", from)
1022
1094
  })?;
1023
- statements.push(Statement::VarDecl {
1024
- name: bind.clone(),
1025
- mutable: false,
1026
- type_ann: None,
1027
- init: Some(Expr::Ident {
1028
- name: Arc::from(source),
1095
+ merge_push(
1096
+ &mut statements,
1097
+ &mut statement_sources,
1098
+ Statement::VarDecl {
1099
+ name: name.clone(),
1100
+ name_span: *name_span,
1101
+ mutable: false,
1102
+ type_ann: None,
1103
+ init: Some(Expr::Ident {
1104
+ name: Arc::from(source),
1105
+ span: *span,
1106
+ }),
1029
1107
  span: *span,
1030
- }),
1031
- span: *span,
1032
- });
1108
+ },
1109
+ src_path.clone(),
1110
+ );
1033
1111
  }
1034
1112
  }
1035
1113
  }
1036
1114
  }
1037
1115
  Statement::Export { declaration, .. } => match declaration.as_ref() {
1038
- ExportDeclaration::Named(s) => statements.push(*s.clone()),
1116
+ ExportDeclaration::Named(s) => merge_push(
1117
+ &mut statements,
1118
+ &mut statement_sources,
1119
+ *s.clone(),
1120
+ src_path.clone(),
1121
+ ),
1039
1122
  ExportDeclaration::Default(e) => {
1040
1123
  let default_name = format!("__default_{}", idx);
1041
- statements.push(Statement::VarDecl {
1042
- name: Arc::from(default_name),
1043
- mutable: false,
1044
- type_ann: None,
1045
- init: Some((*e).clone()),
1046
- span: e.span(),
1047
- });
1124
+ let espan = e.span();
1125
+ merge_push(
1126
+ &mut statements,
1127
+ &mut statement_sources,
1128
+ Statement::VarDecl {
1129
+ name: Arc::from(default_name),
1130
+ name_span: espan,
1131
+ mutable: false,
1132
+ type_ann: None,
1133
+ init: Some((*e).clone()),
1134
+ span: espan,
1135
+ },
1136
+ src_path.clone(),
1137
+ );
1048
1138
  }
1049
1139
  },
1050
- _ => statements.push(stmt.clone()),
1140
+ _ => merge_push(
1141
+ &mut statements,
1142
+ &mut statement_sources,
1143
+ stmt.clone(),
1144
+ src_path.clone(),
1145
+ ),
1051
1146
  }
1052
1147
  }
1053
1148
  }
1054
- Ok(Program { statements })
1149
+ Ok(MergedProgram {
1150
+ program: Program { statements },
1151
+ statement_sources,
1152
+ })
1055
1153
  }
1056
1154
 
1057
1155
  #[cfg(test)]
@@ -1088,7 +1186,7 @@ mod cargo_spec_tests {
1088
1186
  std::fs::write(&p, src).unwrap();
1089
1187
  let root = dir.path();
1090
1188
  let modules = resolve_project(&p, Some(root)).unwrap();
1091
- merge_modules(modules).unwrap();
1189
+ let _ = merge_modules(modules).unwrap();
1092
1190
  }
1093
1191
 
1094
1192
  #[test]