@tishlang/tish-lint 3.11.0 → 3.12.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.
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "tishlang_lint"
3
- version = "3.11.0"
3
+ version = "3.12.0"
4
4
  edition = "2021"
5
5
  description = "AST-based linter for Tish"
6
6
  license-file = { workspace = true }
@@ -45,6 +45,13 @@ fn runtime_features_for_cargo(features: &[String]) -> Vec<String> {
45
45
  }
46
46
 
47
47
  /// `[profile.release]` for nested `cargo build` of generated crates.
48
+ ///
49
+ /// - default: fat LTO, one codegen unit — smallest and fastest binary, slowest to produce (the
50
+ /// final link is single-threaded and dominates a warm build of a large app).
51
+ /// - `TISH_FAST_NATIVE_BUILD=1`: iteration profile, no LTO, opt-level 1.
52
+ /// - `TISH_NATIVE_THIN_LTO=1`: thin LTO over 8 codegen units — keeps most of fat's size/speed win
53
+ /// while letting rustc parallelise the link. Same trade the GBA path offers via
54
+ /// `TISH_GBA_THIN_LTO`; for desktop apps this is the CI-friendly shipping profile.
48
55
  fn nested_release_profile_toml() -> &'static str {
49
56
  if std::env::var("TISH_FAST_NATIVE_BUILD").as_deref() == Ok("1") {
50
57
  r#"[profile.release]
@@ -55,6 +62,13 @@ incremental = true
55
62
  strip = false
56
63
  debug = 0
57
64
  panic = "abort"
65
+ "#
66
+ } else if std::env::var("TISH_NATIVE_THIN_LTO").as_deref() == Ok("1") {
67
+ r#"[profile.release]
68
+ strip = true
69
+ panic = "abort"
70
+ codegen-units = 8
71
+ lto = "thin"
58
72
  "#
59
73
  } else {
60
74
  r#"[profile.release]
@@ -1179,6 +1193,7 @@ edition = "2021"
1179
1193
 
1180
1194
  #[cfg(test)]
1181
1195
  mod tests {
1196
+ use super::nested_release_profile_toml;
1182
1197
  use super::runtime_features_for_cargo;
1183
1198
 
1184
1199
  /// The generated ROM crate must inherit the project's pin, or GBA builds float against whatever
@@ -1219,6 +1234,27 @@ mod tests {
1219
1234
  let _ = fs::remove_dir_all(&base);
1220
1235
  }
1221
1236
 
1237
+ /// `TISH_NATIVE_THIN_LTO=1` selects thin LTO for native release builds; fast wins over it.
1238
+ #[test]
1239
+ fn native_release_profile_follows_env() {
1240
+ use std::sync::Mutex;
1241
+ static ENV_LOCK: Mutex<()> = Mutex::new(());
1242
+ let _g = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
1243
+ std::env::remove_var("TISH_FAST_NATIVE_BUILD");
1244
+ std::env::remove_var("TISH_NATIVE_THIN_LTO");
1245
+ assert!(nested_release_profile_toml().contains("lto = \"fat\""));
1246
+ std::env::set_var("TISH_NATIVE_THIN_LTO", "1");
1247
+ let thin = nested_release_profile_toml();
1248
+ assert!(thin.contains("lto = \"thin\"") && thin.contains("codegen-units = 8"));
1249
+ std::env::set_var("TISH_FAST_NATIVE_BUILD", "1");
1250
+ assert!(
1251
+ nested_release_profile_toml().contains("lto = false"),
1252
+ "fast wins over thin"
1253
+ );
1254
+ std::env::remove_var("TISH_FAST_NATIVE_BUILD");
1255
+ std::env::remove_var("TISH_NATIVE_THIN_LTO");
1256
+ }
1257
+
1222
1258
  /// `TISH_NATIVE_TARGET_DIR`: unset/empty → None (temp-dir build); set → that dir, created.
1223
1259
  #[test]
1224
1260
  fn shared_native_target_dir_follows_env() {
@@ -218,9 +218,25 @@ pub fn copy_file_core(args: &[Value]) -> Result<Value, Value> {
218
218
  }
219
219
  pub fn realpath_core(args: &[Value]) -> Result<Value, Value> {
220
220
  std::fs::canonicalize(path_arg(args, 0))
221
- .map(|p| Value::String(p.to_string_lossy().into()))
221
+ .map(|p| Value::String(strip_verbatim_prefix(&p.to_string_lossy()).into()))
222
222
  .map_err(io_err)
223
223
  }
224
+
225
+ /// `std::fs::canonicalize` on Windows returns the verbatim form — `\\?\C:\Users\…` for a drive
226
+ /// path, `\\?\UNC\server\share\…` for a network one. Node's `fs.realpath` never does: it hands
227
+ /// back `C:\Users\…` / `\\server\share\…`, and programs treat the result as a display / URL /
228
+ /// comparison string, not just an OS handle (Dune showed `\\?\C:\…` as its workspace title, and a
229
+ /// `?` inside a URL path starts the query string). Match Node. No-op on POSIX and for paths
230
+ /// that carry no prefix.
231
+ pub(crate) fn strip_verbatim_prefix(p: &str) -> String {
232
+ if let Some(rest) = p.strip_prefix("\\\\?\\UNC\\") {
233
+ format!("\\\\{rest}")
234
+ } else if let Some(rest) = p.strip_prefix("\\\\?\\") {
235
+ rest.to_string()
236
+ } else {
237
+ p.to_string()
238
+ }
239
+ }
224
240
  pub fn readlink_core(args: &[Value]) -> Result<Value, Value> {
225
241
  std::fs::read_link(path_arg(args, 0))
226
242
  .map(|p| Value::String(p.to_string_lossy().into()))
@@ -393,3 +409,16 @@ pub fn constants() -> Value {
393
409
  m.insert("X_OK".into(), Value::Number(1.0));
394
410
  Value::object(m)
395
411
  }
412
+
413
+ #[cfg(test)]
414
+ mod verbatim_prefix_tests {
415
+ use super::strip_verbatim_prefix;
416
+
417
+ #[test]
418
+ fn strips_windows_verbatim_prefixes_like_node() {
419
+ assert_eq!(strip_verbatim_prefix("\\\\?\\C:\\Users\\x\\ui"), "C:\\Users\\x\\ui");
420
+ assert_eq!(strip_verbatim_prefix("\\\\?\\UNC\\srv\\share\\d"), "\\\\srv\\share\\d");
421
+ assert_eq!(strip_verbatim_prefix("C:\\Users\\x"), "C:\\Users\\x");
422
+ assert_eq!(strip_verbatim_prefix("/Users/x/ui"), "/Users/x/ui");
423
+ }
424
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tishlang/tish-lint",
3
- "version": "3.11.0",
3
+ "version": "3.12.0",
4
4
  "description": "Tish code linter",
5
5
  "license": "PIF",
6
6
  "repository": {
Binary file