async fn references(&self, params: ReferenceParams) -> LspResult<Option<Vec<Location>>> {
        self.client
            .log_message(MessageType::INFO, "references!")
            .await;

        let Some(referenced_task) = ({
            let rope = {
                let map = self.files.lock().expect("only fails if poisoned");
                match map.get(&params.text_document_position.text_document.uri) {
                    Some(files) => files,
                    None => return Ok(None),
                }
                .to_owned() // cloning is cheap
            };

            let text = rope.chunks().join("");
            let parse = jsonc_parser::parse_to_ast(
                &text,
                &CollectOptions {
                    comments: true,
                    tokens: true,
                },
                &Default::default(),
            );

            // iterate pipeline items, and see if any of their ranges intersect
            // with the reference request's position
            let parse = match parse {
                Ok(parse) => parse,
                Err(_err) => {
                    // if it is not a valid json, then there are no references
                    return Ok(None);
                }
            };

            parse
                .value
                .as_ref()
                .and_then(|v| v.as_object())
                .and_then(|o| o.get_object("tasks"))
                .map(|p| p.properties.iter())
                .into_iter()
                .flatten()
                .find_map(|task| {
                    let mut range = task.range;
                    range.start += 1; // account for quote
                    let key_range = range.start + task.name.as_str().len();
                    range.end = key_range;

                    // convert ast range to lsp range
                    let lsp_range = convert_ranges(&rope, range);

                    if lsp_range.start < params.text_document_position.position
                        && lsp_range.end > params.text_document_position.position
                    {
                        Some(task.name.as_str().to_string())
                    } else {
                        None
                    }
                })
        }) else {
            // no overlap with any task definitions, exit
            return Ok(None);
        };

        self.client
            .log_message(
                MessageType::INFO,
                format!("finding references for {:?}", referenced_task),
            )
            .await;

        let repo_root = self
            .repo_root
            .lock()
            .expect("only fails if poisoned")
            .clone();

        let repo_root = match repo_root {
            Some(repo_root) => repo_root,
            None => {
                self.client
                    .log_message(MessageType::INFO, "received request before initialization")
                    .await;
                return Ok(None);
            }
        };

        let packages = match self.package_discovery().await {
            Ok(packages) => packages,
            Err(e) => {
                self.client
                    .log_message(MessageType::WARNING, e.to_string())
                    .await;

                // there aren't really any other errors we can return here, other than
                // an internal error
                let mut error = Error::internal_error();
                error.message = "failed to get package list from the daemon".into();
                return Err(error);
            }
        };

        let mut locations = vec![];
        for wd in packages.workspaces {
            let data = match std::fs::read_to_string(&wd.package_json) {
                Ok(data) => data,
                // if we can't read a package.json, then we can't set up references to it
                // so we just skip it and do a best effort
                Err(_) => continue,
            };
            let package_json = match PackageJson::load_from_str(&data, wd.package_json.as_str()) {
                Ok(package_json) => package_json,
                // if we can't parse a package.json, then we can't set up references to it
                // so we just skip it and do a best effort
                Err(_) => continue,
            };
            let scripts = package_json.scripts.into_keys().collect::<HashSet<_>>();

            // if in the root, the name should be '//'
            let package_json_name = if repo_root.contains(&wd.package_json) {
                Some("//")
            } else {
                package_json.name.as_ref().map(|name| name.as_str())
            };

            // todo: use jsonc_ast instead of text search
            let rope = crop::Rope::from(data.clone());

            let (package, task) = referenced_task
                .rsplit_once('#')
                .map(|(p, t)| (Some(p), t))
                .unwrap_or((None, &referenced_task));

            if let (Some(package), Some(package_name)) = (package, package_json_name) {
                if package_name != package {
                    continue;
                }
            };

            let Some(start) = data.find(&format!("\"{}\"", task)) else {
                continue;
            };
            let end = start + task.len() + 2;

            let start_line = rope.line_of_byte(start);
            let end_line = rope.line_of_byte(end);

            let range = Range {
                start: Position {
                    line: start_line as u32,
                    character: (start - rope.byte_of_line(start_line)) as u32,
                },
                end: Position {
                    line: end_line as u32,
                    character: (end - rope.byte_of_line(end_line)) as u32,
                },
            };

            if scripts.contains(task) {
                let location = Location::new(
                    Url::from_file_path(&wd.package_json).expect("only fails if path is relative"),
                    range,
                );
                locations.push(location);
            }
        }

        Ok(Some(locations))
    }
Find which projects / scripts are affected by a given pipeline item
crates/turborepo-lsp/src/lib.rs