/**
* Searchfox query URL construction utilities
*/
import type { QueryComponents, SearchfoxUrlOptions } from "../types.js";
/**
* Parse query string to extract advanced syntax components
* Supports: symbol:, id:, path:, pathre:, text:, re:
*/
export function parseQuerySyntax(query: string): QueryComponents {
const components: QueryComponents = {};
// Parse symbol: prefix
const symbolMatch = query.match(/\bsymbol:(\S+)/);
if (symbolMatch) {
components.symbol = symbolMatch[1];
}
// Parse id: prefix (exact identifier)
const idMatch = query.match(/\bid:(\S+)/);
if (idMatch) {
components.identifier = idMatch[1];
}
// Parse path: prefix
const pathMatch = query.match(/\bpath:(\S+)/);
if (pathMatch) {
components.path = pathMatch[1];
}
// Parse pathre: prefix (path regex)
const pathreMatch = query.match(/\bpathre:(\S+)/);
if (pathreMatch) {
components.pathRegex = pathreMatch[1];
}
// Parse text: prefix (exact text)
const textMatch = query.match(/\btext:(.+)/);
if (textMatch) {
components.text = textMatch[1].trim();
}
// Parse re: prefix (regex)
const reMatch = query.match(/\bre:(.+)/);
if (reMatch) {
components.regex = reMatch[1].trim();
}
// If no special syntax found, treat as plain text
if (Object.keys(components).length === 0) {
components.text = query;
}
return components;
}
/**
* Build Searchfox query string from components
*/
export function buildQueryString(components: QueryComponents): string {
const parts: string[] = [];
if (components.symbol) {
parts.push(`symbol:${components.symbol}`);
}
if (components.identifier) {
parts.push(`id:${components.identifier}`);
}
if (components.path) {
parts.push(`path:${components.path}`);
}
if (components.pathRegex) {
parts.push(`pathre:${components.pathRegex}`);
}
if (components.text) {
parts.push(components.text);
}
if (components.regex) {
parts.push(`re:${components.regex}`);
}
return parts.join(" ");
}
/**
* Build Searchfox search URL with advanced query syntax
*/
export function buildSearchfoxUrl(options: SearchfoxUrlOptions): string {
const { repo, components, case_sensitive } = options;
const queryString = buildQueryString(components);
const params = new URLSearchParams({
q: queryString,
});
if (case_sensitive) {
params.append("case", "true");
}
// Add path filter if provided separately
if (components.path) {
params.append("path", components.path);
}
return `https://searchfox.org/${repo}/search?${params}`;
}
/**
* Check if query uses advanced syntax
*/
export function hasAdvancedSyntax(query: string): boolean {
return /\b(symbol|id|path|pathre|text|re):/.test(query);
}
/**
* Extract plain text from query (remove all prefixes)
*/
export function extractPlainText(query: string): string {
// Remove all prefix syntax
return query.replace(/\b(symbol|id|path|pathre|text|re):\S+/g, "").trim();
}