-
Notifications
You must be signed in to change notification settings - Fork 1
Labels
enhancementNew feature or requestNew feature or request
Description
Context
Part of #110 (EPIC: Support regex syntax /pattern/ in search queries) — step 1 of 2.
The GitHub REST API does not support regex queries. This issue implements the pure-function core that makes regex work:
- detect regex syntax
- derive a meaningful API query algorithmically
- filter API results locally with the original regex
Scope
New module: src/regex.ts
Pure functions only — no I/O.
/** Returns true if the query contains a /pattern/ or /pattern/flags token. */
export function isRegexQuery(q: string): boolean
/**
* Given a raw query string (possibly mixing GitHub qualifiers and a /regex/ token),
* returns:
* - apiQuery: the query safe to send to the GitHub REST API
* - regexFilter: the compiled RegExp to apply locally on text_matches.fragment
* - warn: set when no exploitable literal term could be extracted (user should use --regex-hint)
*/
export function buildApiQuery(q: string): {
apiQuery: string;
regexFilter: RegExp | null;
warn?: string;
}buildApiQuery() algorithm:
- Tokenize the raw query: separate
qualifier:valuetokens (e.g.filename:,language:,path:) from the/pattern/flagstoken - Preserve all qualifier tokens unchanged
- On the regex pattern:
- Top-level alternation
A|B|C(not nested inside[...]or(...)) →A OR B OR C - Otherwise → extract all unescaped literal sequences (ignoring
.*,\s,\d,[...], quantifiers+?*{n}, anchors^$) → pick the longest one - If the result is fewer than 3 characters → set
warn, return empty term
- Top-level alternation
- Reconstruct:
"<qualifiers> <apiTerm>".trim() - Compile the original pattern into a
RegExp(with extracted flags, excludingg)
Extend src/aggregate.ts
Add an optional regexFilter?: RegExp parameter to aggregate(). When provided, a CodeMatch is kept only if at least one of its text_matches fragments matches the regex.
Update src/types.ts if needed
If the new regexFilter parameter requires a shared type, add it to src/types.ts first (type-first approach per AGENTS.md).
Acceptance criteria
src/regex.test.ts — all cases must pass
| Input query | apiQuery |
regexFilter |
warn? |
|---|---|---|---|
/from.*['"]axios/ |
axios |
/from.*['"]axios/ |
— |
/TODO|FIXME|HACK/ |
TODO OR FIXME OR HACK |
/TODO|FIXME|HACK/ |
— |
/require\(['"]old-lib['"]\)/ |
old-lib |
/require\(['"]old-lib['"]\)/ |
— |
filename:package.json /["']axios["']:\s*"/ |
filename:package.json axios |
✓ | — |
/[~^]?[0-9]+\.[0-9]+/ |
"" |
✓ | |
/useState/ |
useState |
/useState/ |
— |
/(import|require).*someLongLib/ |
someLongLib (alternation partial → fallback to longest) |
✓ | — |
/pattern/i |
pattern |
/pattern/i |
— |
/pattern/gi |
pattern |
/pattern/i (g stripped) |
— |
/[/ (invalid regex) |
"" |
null |
|
plain text query |
plain text query (no-op) |
null |
— |
src/aggregate.test.ts — new cases
aggregate()withregexFilter=/axios/keeps only matches where at least one fragment matchesaggregate()withregexFilterset but no fragment matches → repo excluded from resultsaggregate()withoutregexFilter(undefined) → existing behaviour unchanged
Checklist
-
src/regex.tscreated withisRegexQueryandbuildApiQuery -
src/regex.test.tscreated, all table cases above pass -
src/aggregate.tsextended withregexFilter?: RegExp -
src/aggregate.test.tsextended with regex filter cases -
src/types.tsupdated if new shared types are introduced -
bun test— full suite green -
bun run lint— zero errors -
bun run format:check— no diff -
bun run knip— no unused exports
Note: C4 diagrams and
AGENTS.mdare updated in #112 once the full module surface is known.
Branch
feat/regex-core
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request