@tishlang/tish 1.0.10 → 1.0.12

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,8 +1,10 @@
1
1
  #[cfg(test)]
2
2
  mod tests {
3
+ use std::io::Write;
4
+
3
5
  use tish_parser::parse;
4
6
 
5
- use crate::{compile_with_jsx, JsxMode};
7
+ use crate::{compile_project_with_jsx, compile_with_jsx, JsxMode};
6
8
 
7
9
  #[test]
8
10
  fn lattish_jsx_emits_h_with_children_array() {
@@ -21,6 +23,54 @@ mod tests {
21
23
  assert!(js.contains("h(Fragment, null, ["));
22
24
  }
23
25
 
26
+ #[test]
27
+ fn jsx_text_whitespace_coalesced() {
28
+ let src = r#"fn X() { return <p>First paragraph</p> }"#;
29
+ let program = parse(src).unwrap();
30
+ let js = compile_with_jsx(&program, false, JsxMode::LattishH).unwrap();
31
+ assert!(
32
+ js.contains("\"First paragraph\""),
33
+ "expected \"First paragraph\" in output, got: {}",
34
+ &js[..400.min(js.len())]
35
+ );
36
+ assert!(
37
+ !js.contains("\"First\", \"paragraph\""),
38
+ "text should be coalesced, not split"
39
+ );
40
+ }
41
+
42
+ #[test]
43
+ fn jsx_text_whitespace_coalesced_multiline() {
44
+ let src = "fn App() {\n return <p>First paragraph</p>\n}";
45
+ let program = parse(src).unwrap();
46
+ let js = compile_with_jsx(&program, false, JsxMode::LattishH).unwrap();
47
+ assert!(
48
+ js.contains("\"First paragraph\""),
49
+ "multiline: expected \"First paragraph\", got: {}",
50
+ &js[..400.min(js.len())]
51
+ );
52
+ }
53
+
54
+ #[test]
55
+ fn jsx_text_whitespace_via_compile_project() {
56
+ let dir = std::env::temp_dir().join("tish_compile_project_test");
57
+ let _ = std::fs::create_dir_all(&dir);
58
+ let path = dir.join("test.tish");
59
+ let src = "fn App() {\n return <p>First paragraph</p>\n}";
60
+ let mut f = std::fs::File::create(&path).unwrap();
61
+ f.write_all(src.as_bytes()).unwrap();
62
+ f.sync_all().unwrap();
63
+ drop(f);
64
+ let js = compile_project_with_jsx(&path, Some(&dir), false, JsxMode::LattishH)
65
+ .expect("compile_project_with_jsx failed");
66
+ assert!(
67
+ js.contains("\"First paragraph\""),
68
+ "compile_project: expected \"First paragraph\", got: {}",
69
+ &js[..500.min(js.len())]
70
+ );
71
+ let _ = std::fs::remove_file(&path);
72
+ }
73
+
24
74
  #[test]
25
75
  fn vdom_emits_vdom_h() {
26
76
  let src = r#"fn X() { return <p/> }"#;
@@ -27,6 +27,21 @@ export fn h(tag, props, children) {
27
27
  if (children === undefined || children === null) {
28
28
  children = []
29
29
  }
30
+ if (typeof tag === "function") {
31
+ let p = props && props !== null ? props : {}
32
+ if (children.length > 0) {
33
+ let newProps = {}
34
+ let keys = Object.keys(p)
35
+ let i = 0
36
+ while (i < keys.length) {
37
+ newProps[keys[i]] = p[keys[i]]
38
+ i = i + 1
39
+ }
40
+ newProps.children = children
41
+ p = newProps
42
+ }
43
+ return tag(p)
44
+ }
30
45
  if (tag === Fragment) {
31
46
  let f = document.createDocumentFragment()
32
47
  let i = 0
@@ -1561,6 +1561,17 @@ impl<'a> Parser<'a> {
1561
1561
  })
1562
1562
  }
1563
1563
 
1564
+ /// Push text child, merging with previous Text if any (preserves spaces between tokens).
1565
+ fn push_or_merge_text(&self, children: &mut Vec<JsxChild>, s: Arc<str>) {
1566
+ if let Some(JsxChild::Text(prev)) = children.last() {
1567
+ let merged = format!("{} {}", prev.as_ref(), s.as_ref());
1568
+ let last = children.len() - 1;
1569
+ children[last] = JsxChild::Text(Arc::from(merged.as_str()));
1570
+ } else {
1571
+ children.push(JsxChild::Text(s));
1572
+ }
1573
+ }
1574
+
1564
1575
  /// Parse JSX children until </Tag> or </>
1565
1576
  fn parse_jsx_children(&mut self, close_tag: &str) -> Result<Vec<JsxChild>, String> {
1566
1577
  let mut children = Vec::new();
@@ -1601,7 +1612,7 @@ impl<'a> Parser<'a> {
1601
1612
  let t = self.advance().unwrap();
1602
1613
  let s = t.literal.clone().unwrap_or_default();
1603
1614
  if !s.is_empty() {
1604
- children.push(JsxChild::Text(s));
1615
+ self.push_or_merge_text(&mut children, s);
1605
1616
  }
1606
1617
  }
1607
1618
  Some(TokenKind::Ident) => {
@@ -1609,7 +1620,7 @@ impl<'a> Parser<'a> {
1609
1620
  let t = self.advance().unwrap();
1610
1621
  let s = t.literal.clone().unwrap_or_default();
1611
1622
  if !s.is_empty() {
1612
- children.push(JsxChild::Text(s));
1623
+ self.push_or_merge_text(&mut children, s);
1613
1624
  }
1614
1625
  }
1615
1626
  _ => {
@@ -1659,7 +1670,14 @@ impl<'a> Parser<'a> {
1659
1670
  let t = self.advance().unwrap();
1660
1671
  let s = t.literal.clone().unwrap_or_default();
1661
1672
  if !s.is_empty() {
1662
- children.push(JsxChild::Text(s));
1673
+ self.push_or_merge_text(&mut children, s);
1674
+ }
1675
+ }
1676
+ Some(TokenKind::Ident) => {
1677
+ let t = self.advance().unwrap();
1678
+ let s = t.literal.clone().unwrap_or_default();
1679
+ if !s.is_empty() {
1680
+ self.push_or_merge_text(&mut children, s);
1663
1681
  }
1664
1682
  }
1665
1683
  _ => return Err(format!("Unexpected token in JSX fragment: {:?}", self.peek_kind())),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tishlang/tish",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Tish - minimal TS/JS-compatible language. Run, REPL, compile to native.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {
Binary file
Binary file
Binary file
Binary file
Binary file