@@ -1110,7 +1110,7 @@ mod tests {
let text = r#"
function a() {
- // local variables are omitted
+ // local variables are included
let a1 = 1;
// all functions are included
async function a2() {}
@@ -1133,6 +1133,7 @@ mod tests {
.collect::<Vec<_>>(),
&[
("function a()", 0),
+ ("let a1", 1),
("async function a2()", 1),
("let b", 0),
("function getB()", 0),
@@ -1141,6 +1142,223 @@ mod tests {
);
}
+ #[gpui::test]
+ async fn test_outline_with_destructuring(cx: &mut TestAppContext) {
+ let language = crate::language(
+ "typescript",
+ tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(),
+ );
+
+ let text = r#"
+ // Top-level destructuring
+ const { a1, a2 } = a;
+ const [b1, b2] = b;
+
+ // Defaults and rest
+ const [c1 = 1, , c2, ...rest1] = c;
+ const { d1, d2: e1, f1 = 2, g1: h1 = 3, ...rest2 } = d;
+
+ function processData() {
+ // Nested object destructuring
+ const { c1, c2 } = c;
+ // Nested array destructuring
+ const [d1, d2, d3] = d;
+ // Destructuring with renaming
+ const { f1: g1 } = f;
+ // With defaults
+ const [x = 10, y] = xy;
+ }
+
+ class DataHandler {
+ method() {
+ // Destructuring in class method
+ const { a1, a2 } = a;
+ const [b1, ...b2] = b;
+ }
+ }
+ "#
+ .unindent();
+
+ let buffer = cx.new(|cx| language::Buffer::local(text, cx).with_language(language, cx));
+ let outline = buffer.read_with(cx, |buffer, _| buffer.snapshot().outline(None));
+ assert_eq!(
+ outline
+ .items
+ .iter()
+ .map(|item| (item.text.as_str(), item.depth))
+ .collect::<Vec<_>>(),
+ &[
+ ("const a1", 0),
+ ("const a2", 0),
+ ("const b1", 0),
+ ("const b2", 0),
+ ("const c1", 0),
+ ("const c2", 0),
+ ("const rest1", 0),
+ ("const d1", 0),
+ ("const e1", 0),
+ ("const h1", 0),
+ ("const rest2", 0),
+ ("function processData()", 0),
+ ("const c1", 1),
+ ("const c2", 1),
+ ("const d1", 1),
+ ("const d2", 1),
+ ("const d3", 1),
+ ("const g1", 1),
+ ("const x", 1),
+ ("const y", 1),
+ ("class DataHandler", 0),
+ ("method()", 1),
+ ("const a1", 2),
+ ("const a2", 2),
+ ("const b1", 2),
+ ("const b2", 2),
+ ]
+ );
+ }
+
+ #[gpui::test]
+ async fn test_outline_with_object_properties(cx: &mut TestAppContext) {
+ let language = crate::language(
+ "typescript",
+ tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(),
+ );
+
+ let text = r#"
+ // Object with function properties
+ const o = { m() {}, async n() {}, g: function* () {}, h: () => {}, k: function () {} };
+
+ // Object with primitive properties
+ const p = { p1: 1, p2: "hello", p3: true };
+
+ // Nested objects
+ const q = {
+ r: {
+ // won't be included due to one-level depth limit
+ s: 1
+ },
+ t: 2
+ };
+
+ function getData() {
+ const local = { x: 1, y: 2 };
+ return local;
+ }
+ "#
+ .unindent();
+
+ let buffer = cx.new(|cx| language::Buffer::local(text, cx).with_language(language, cx));
+ let outline = buffer.read_with(cx, |buffer, _| buffer.snapshot().outline(None));
+ assert_eq!(
+ outline
+ .items
+ .iter()
+ .map(|item| (item.text.as_str(), item.depth))
+ .collect::<Vec<_>>(),
+ &[
+ ("const o", 0),
+ ("m()", 1),
+ ("async n()", 1),
+ ("g", 1),
+ ("h", 1),
+ ("k", 1),
+ ("const p", 0),
+ ("p1", 1),
+ ("p2", 1),
+ ("p3", 1),
+ ("const q", 0),
+ ("r", 1),
+ ("s", 2),
+ ("t", 1),
+ ("function getData()", 0),
+ ("const local", 1),
+ ("x", 2),
+ ("y", 2),
+ ]
+ );
+ }
+
+ #[gpui::test]
+ async fn test_outline_with_computed_property_names(cx: &mut TestAppContext) {
+ let language = crate::language(
+ "typescript",
+ tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(),
+ );
+
+ let text = r#"
+ // Symbols as object keys
+ const sym = Symbol("test");
+ const obj1 = {
+ [sym]: 1,
+ [Symbol("inline")]: 2,
+ normalKey: 3
+ };
+
+ // Enums as object keys
+ enum Color { Red, Blue, Green }
+
+ const obj2 = {
+ [Color.Red]: "red value",
+ [Color.Blue]: "blue value",
+ regularProp: "normal"
+ };
+
+ // Mixed computed properties
+ const key = "dynamic";
+ const obj3 = {
+ [key]: 1,
+ ["string" + "concat"]: 2,
+ [1 + 1]: 3,
+ static: 4
+ };
+
+ // Nested objects with computed properties
+ const obj4 = {
+ [sym]: {
+ nested: 1
+ },
+ regular: {
+ [key]: 2
+ }
+ };
+ "#
+ .unindent();
+
+ let buffer = cx.new(|cx| language::Buffer::local(text, cx).with_language(language, cx));
+ let outline = buffer.read_with(cx, |buffer, _| buffer.snapshot().outline(None));
+ assert_eq!(
+ outline
+ .items
+ .iter()
+ .map(|item| (item.text.as_str(), item.depth))
+ .collect::<Vec<_>>(),
+ &[
+ ("const sym", 0),
+ ("const obj1", 0),
+ ("[sym]", 1),
+ ("[Symbol(\"inline\")]", 1),
+ ("normalKey", 1),
+ ("enum Color", 0),
+ ("const obj2", 0),
+ ("[Color.Red]", 1),
+ ("[Color.Blue]", 1),
+ ("regularProp", 1),
+ ("const key", 0),
+ ("const obj3", 0),
+ ("[key]", 1),
+ ("[\"string\" + \"concat\"]", 1),
+ ("[1 + 1]", 1),
+ ("static", 1),
+ ("const obj4", 0),
+ ("[sym]", 1),
+ ("nested", 2),
+ ("regular", 1),
+ ("[key]", 2),
+ ]
+ );
+ }
+
#[gpui::test]
async fn test_generator_function_outline(cx: &mut TestAppContext) {
let language = crate::language("javascript", tree_sitter_typescript::LANGUAGE_TSX.into());