Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/.vitepress/theme/UseCaseTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const USE_CASES: UseCase[] = [
label: "Semver / version audit",
headline: "Which repos are pinned to a vulnerable minor version?",
description:
"Use regex syntax to target a precise version rangesomething a plain keyword search cannot do. Find every repo still locked to axios 1.x, react 17.x, or any other outdated pin, then export the list to a migration issue.",
"Use regex syntax to target a precise version range, something a plain keyword search cannot do. Find every repo still locked to axios 1.x, react 17.x, or any other outdated pin, then export the list to a migration issue. The CLI automatically escapes the double quotes in the pattern so the search stays precise instead of matching every unrelated mention of axios or react.",
command: `github-code-search query '/"axios": "1\\./' --org my-org`,
},
];
Expand Down
48 changes: 44 additions & 4 deletions docs/usage/search-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,14 @@ github-code-search "password= language:TypeScript NOT filename:test" --org fulll

`github-code-search` supports regex syntax using the `/pattern/flags` notation, just like the GitHub web UI.

Because the GitHub Code Search API does not natively support regex, the CLI automatically extracts a representative literal term from the regex to send to the API, then filters the returned results locally with the full pattern. In most cases this is fully transparent.
Because the GitHub Code Search API does not natively support regex, the CLI automatically extracts a representative literal term from the regex to send to the API, then filters the returned results locally with the full pattern. In most cases this is fully transparent, including patterns that contain literal `"` characters, which the CLI escapes automatically using GitHub's own quote-escaping syntax (see [Searching for a literal quote character](#searching-for-a-literal-quote-character) below).

```bash
# Imports using the axios module (any quote style)
github-code-search "/from.*['\"\`]axios/" --org fulll

# Axios dependency in package.json (any semver prefix)
# Axios dependency in package.json (any semver prefix) — the double quotes in
# the pattern are preserved and escaped automatically for the GitHub API
github-code-search '/"axios": "[~^]?[0-9]"/ filename:package.json' --org fulll

# Old library require() calls
Expand All @@ -110,20 +111,59 @@ If the extracted term is very short (fewer than 3 characters), the CLI will exit
⚠ Regex mode — No meaningful search term could be extracted from the regex pattern. Use --regex-hint <term> to specify the term to send to the GitHub API.
```

This happens when the pattern has no literal characters at all, for example a pure version-number match:

```bash
github-code-search '/[0-9]+\.[0-9]+\.[0-9]+/' --org fulll
```

Use `--regex-hint` to override the API search term while still applying the full regex filter locally:

```bash
github-code-search '/"axios":\s*"[~^]?[0-9]/ filename:package.json' \
github-code-search '/[0-9]+\.[0-9]+\.[0-9]+/ filename:package.json' \
--org fulll \
--regex-hint '"axios"'
--regex-hint version
```

::: tip Quoting a single word has no filtering effect
Wrapping a single word in double quotes (e.g. `--regex-hint '"axios"'`) does **not** narrow the
GitHub search — GitHub treats a one-word quoted phrase exactly like the bare word. Quotes only
matter for multi-word phrases (`"feature flag"`) or when you need to search for the literal `"`
character itself, see below.
:::

::: warning API coverage
The GitHub Code Search API returns **at most 1,000 results** per query. The regex filter
is applied to those results; results beyond the API cap can never be seen. Refine the
query with qualifiers (`language:`, `path:`, `filename:`) to keep the result set small.
:::

## Searching for a literal quote character

GitHub's query syntax treats `"` as a phrase delimiter, not a literal character. To search for an actual quote character (for example to match a `package.json` dependency key/value prefix like `"react": "`), escape it for **both** your shell and GitHub:

```bash
github-code-search '"\"react\": \""' --org myorg
```

- The outer single quotes protect the whole argument from your shell.
- The `\"` sequences are GitHub's own escape syntax for a literal quote character inside an exact phrase.

If you instead pass raw, unescaped quotes, two things can happen:

- **An even number of quotes** (e.g. `"react": `) is valid GitHub syntax, but GitHub silently strips the quotes and treats the query as separate terms, so you get broader results than expected, not an error.
- **An odd number of quotes** (e.g. `"react": "`) is rejected by GitHub with an opaque `422 ERROR_TYPE_QUERY_PARSING_FATAL` error. `github-code-search` detects this locally and fails fast with an actionable message before ever calling the API:

```text
Error: Unbalanced double quotes in query: "\"react\": \"". GitHub rejects this with a query
parsing error. To search for a literal quote character, escape it for both your shell and
GitHub, e.g.: github-code-search '"\"react\": \""' --org myorg
```

::: warning Shell escaping consumes backslashes too
Typing `"\"react\": \""` directly (double-quoted at the shell level) does **not** work: your shell resolves `\"` to a literal `"` _before_ the CLI ever sees it, so the program receives the same unbalanced `"react": "` string as if you had typed no backslashes at all. Always wrap the whole argument in **single** quotes so the backslashes reach GitHub unchanged, as in the example above.
:::

## API limits

The GitHub Code Search API returns at most **1,000 results** per query. If your query returns more, refine it with qualifiers (especially `language:` or `path:`) to stay below the limit.
Expand Down
Loading