> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/clyrisai/gitresolve/llms.txt
> Use this file to discover all available pages before exploring further.

# Classifier Functions — classifyInput, parseRepoUrl & More

> Reference for all five GitResolve classifier exports: classifyInput, parseRepoUrl, parseGitLink, extractGitUrlsFromText, and isGitProviderUrl.

The classifier module is the entry point for every string that flows into GitResolve. It answers two questions: *what kind of thing is this input?* and *what structured data can be extracted from it?* All five functions are pure and synchronous — they never perform network requests, making them safe to call in hot paths or batch loops without any async overhead.

## `classifyInput`

Examines a raw string and returns an `InputType` indicating what kind of candidate input it represents. This is the quickest way to route an unknown string before deciding which heavier pipeline function to invoke.

```typescript theme={null}
function classifyInput(input: string): InputType
```

### Parameters

<ParamField path="input" type="string" required>
  Any string — a URL, file path, or arbitrary text. The value is trimmed before classification.
</ParamField>

### Returns

An `InputType` string literal. The classification logic runs in this order:

| Returned value  | Condition                                                                           |
| --------------- | ----------------------------------------------------------------------------------- |
| `"resume_file"` | Input ends with `.pdf`, `.doc`, `.docx`, or `.rtf` (case-insensitive)               |
| `"linkedin"`    | Parsed hostname contains `linkedin.com`                                             |
| `"repo_url"`    | `parseRepoUrl` returns `valid: true` for the input                                  |
| `"git_profile"` | Host is a known git provider but `parseRepoUrl` is invalid (e.g. profile-only path) |
| `"portfolio"`   | Any other syntactically valid URL                                                   |
| `"unknown"`     | Not a valid URL and not a recognised file extension                                 |

<Note>
  `"resume_url"` is a valid `InputType` value but `classifyInput` never returns it — the classifier has no way to distinguish a remote PDF URL from any other portfolio URL without fetching the content. Downstream logic may promote `"portfolio"` to `"resume_url"` after inspecting `Content-Type`.
</Note>

### Examples

```typescript theme={null}
import { classifyInput } from '@clyrisai/gitresolve';

classifyInput('https://github.com/torvalds/linux');    // 'repo_url'
classifyInput('https://github.com/torvalds');          // 'git_profile'
classifyInput('https://janedoe.dev');                  // 'portfolio'
classifyInput('./resumes/janedoe.pdf');                // 'resume_file'
classifyInput('janedoe.docx');                         // 'resume_file'
classifyInput('https://linkedin.com/in/janedoe');      // 'linkedin'
classifyInput('not a url at all');                     // 'unknown'
```

***

## `parseRepoUrl`

Fully parses a GitHub, GitLab, or Bitbucket repository URL into structured fields. Strips `.git` suffixes and trailing slashes, handles GitLab sub-group paths, and detects pull request / issue contribution links.

```typescript theme={null}
function parseRepoUrl(repoUrl: string): {
  valid: boolean;
  data?: ParsedRepo;
  error?: string;
}
```

### Parameters

<ParamField path="repoUrl" type="string" required>
  An absolute URL. Must be parseable by the WHATWG `URL` constructor and hosted on `github.com`, `gitlab.com`, or `bitbucket.org`. The `www.` subdomain variant is **not** accepted by `parseRepoUrl` (use `parseGitLink` for that).
</ParamField>

### Returns

<ResponseField name="valid" type="boolean">
  `true` when parsing succeeded and `data` is populated; `false` otherwise.
</ResponseField>

<ResponseField name="data" type="ParsedRepo">
  Present only when `valid` is `true`.

  <Expandable title="ParsedRepo fields">
    <ResponseField name="provider" type="'github' | 'gitlab' | 'bitbucket'">
      Which git hosting service the URL belongs to.
    </ResponseField>

    <ResponseField name="host" type="string">
      Lowercase hostname, e.g. `"github.com"`.
    </ResponseField>

    <ResponseField name="owner" type="string">
      Repository owner username or organisation.
    </ResponseField>

    <ResponseField name="repo" type="string">
      Repository name (last meaningful path segment after group resolution).
    </ResponseField>

    <ResponseField name="fullPath" type="string">
      `owner/repo` for GitHub and Bitbucket. For GitLab this is the full group path, e.g. `"myorg/backend/api-service"`.
    </ResponseField>

    <ResponseField name="normalized" type="string">
      Canonical URL reconstructed as `https://{host}/{fullPath}` — `.git` suffixes and trailing slashes removed.
    </ResponseField>

    <ResponseField name="contribution" type="object | undefined">
      Present when the URL points to a specific PR or issue.

      <Expandable title="contribution fields">
        <ResponseField name="type" type="'pull_request' | 'issue'">
          Whether this is a pull request (GitLab: merge request) or an issue.
        </ResponseField>

        <ResponseField name="number" type="string">
          The numeric identifier as a string, e.g. `"42"`.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="error" type="string">
  Present only when `valid` is `false`. Possible values:

  | Error string                 | Cause                                                                                |
  | ---------------------------- | ------------------------------------------------------------------------------------ |
  | `"Unsupported provider"`     | Hostname is not `github.com`, `gitlab.com`, or `bitbucket.org`                       |
  | `"Invalid repo path"`        | Fewer than two path segments after stripping `.git` and slashes                      |
  | `"Reserved path"`            | First path segment is a provider-specific reserved word (e.g. `explore`, `settings`) |
  | `"Invalid GitLab repo path"` | GitLab path found a stop marker (`-`, `tree`, `blob`) before reaching `owner/repo`   |
  | `"Invalid URL"`              | Input is not a valid URL at all                                                      |
</ResponseField>

### Behavior notes

* **`.git` stripping** — `https://github.com/owner/repo.git` is treated identically to `https://github.com/owner/repo`.
* **GitLab sub-groups** — The parser walks path segments until it hits a stop marker (`-`, `tree`, or `blob`), so `https://gitlab.com/myorg/backend/api-service` correctly produces `owner: "myorg"`, `repo: "api-service"`, `fullPath: "myorg/backend/api-service"`.
* **Contribution detection** differs by provider:
  * GitHub: `/pull/{n}` → `pull_request`; `/issues/{n}` → `issue`
  * GitLab: `/-/merge_requests/{n}` → `pull_request`; `/-/issues/{n}` → `issue`
  * Bitbucket: `/pull-requests/{n}` → `pull_request`; `/issues/{n}` → `issue`

### Examples

<CodeGroup>
  ```typescript GitHub theme={null}
  import { parseRepoUrl } from '@clyrisai/gitresolve';

  const result = parseRepoUrl('https://github.com/owner/my-repo.git');
  // {
  //   valid: true,
  //   data: {
  //     provider: 'github',
  //     host: 'github.com',
  //     owner: 'owner',
  //     repo: 'my-repo',
  //     fullPath: 'owner/my-repo',
  //     normalized: 'https://github.com/owner/my-repo',
  //   }
  // }
  ```

  ```typescript GitLab sub-group theme={null}
  import { parseRepoUrl } from '@clyrisai/gitresolve';

  const result = parseRepoUrl('https://gitlab.com/myorg/backend/api-service');
  // {
  //   valid: true,
  //   data: {
  //     provider: 'gitlab',
  //     host: 'gitlab.com',
  //     owner: 'myorg',
  //     repo: 'api-service',
  //     fullPath: 'myorg/backend/api-service',
  //     normalized: 'https://gitlab.com/myorg/backend/api-service',
  //   }
  // }
  ```

  ```typescript Pull request theme={null}
  import { parseRepoUrl } from '@clyrisai/gitresolve';

  const result = parseRepoUrl('https://github.com/facebook/react/pull/28987');
  // {
  //   valid: true,
  //   data: {
  //     provider: 'github',
  //     owner: 'facebook',
  //     repo: 'react',
  //     fullPath: 'facebook/react',
  //     normalized: 'https://github.com/facebook/react',
  //     contribution: { type: 'pull_request', number: '28987' },
  //   }
  // }
  ```

  ```typescript Invalid theme={null}
  import { parseRepoUrl } from '@clyrisai/gitresolve';

  parseRepoUrl('https://github.com/settings/profile');
  // { valid: false, error: 'Reserved path' }

  parseRepoUrl('https://example.com/owner/repo');
  // { valid: false, error: 'Unsupported provider' }
  ```
</CodeGroup>

***

## `parseGitLink`

Classifies a raw URL from any of the six recognised git provider hostnames into a typed `ExtractedGitLink`. Unlike `parseRepoUrl`, this function also handles profile pages, PRs, issues, and the `www.` subdomain variants. Note that `gist.github.com` is not in `GIT_HOSTS`, so gist subdomain URLs return `null`.

```typescript theme={null}
function parseGitLink(rawUrl: string): ExtractedGitLink | null
```

### Parameters

<ParamField path="rawUrl" type="string" required>
  An absolute URL string. Must be parseable by the WHATWG `URL` constructor. Relative URLs return `null`.
</ParamField>

### Returns

An `ExtractedGitLink` object, or `null` when the URL should be discarded.

<ResponseField name="url" type="string">
  For repo links this is the `normalized` canonical URL from `parseRepoUrl`. For PR/issue links this is the original `rawUrl` to preserve the exact contribution reference. For profile links this is `rawUrl` as-is.
</ResponseField>

<ResponseField name="provider" type="'github' | 'gitlab' | 'bitbucket'">
  Resolved from the hostname via `GIT_HOSTS`.
</ResponseField>

<ResponseField name="type" type="GitLinkType">
  The classification result. See the table below.
</ResponseField>

<ResponseField name="username" type="string">
  The extracted owner username. For most link types this is the first path segment. For `"gist"` type links (matched when the first path segment is literally `gist` on `github.com`), the second path segment is used.
</ResponseField>

<ResponseField name="repo" type="string | undefined">
  Present when `type` is `'repo'`, `'pull_request'`, or `'issue'`.
</ResponseField>

<ResponseField name="number" type="string | undefined">
  Present when `type` is `'pull_request'` or `'issue'`.
</ResponseField>

### Classification logic

| `type` result    | Condition                                                                                                                                                               |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `"gist"`         | First path segment is literally `gist` (note: `gist.github.com` is **not** in `GIT_HOSTS` — URLs on that subdomain fail the `isGitProviderUrl` check and return `null`) |
| `"profile"`      | Only one path segment present; or second segment is a GitHub profile tab (`repositories`, `stars`, `followers`, `following`); or GitLab second segment is `-`           |
| `"pull_request"` | `parseRepoUrl` returns a `contribution` of type `pull_request`                                                                                                          |
| `"issue"`        | `parseRepoUrl` returns a `contribution` of type `issue`                                                                                                                 |
| `"repo"`         | Two or more valid path segments that pass `parseRepoUrl`                                                                                                                |
| `"other"`        | Two or more path segments that did not match any of the above                                                                                                           |

### Null cases

`parseGitLink` returns `null` (silently discards the URL) when:

* The URL cannot be parsed, or the hostname is not in `GIT_HOSTS`
* The last path segment ends with a static asset extension: `.png`, `.svg`, `.xml`, `.json`, `.ico`, `.txt`, `.woff`, `.woff2`, `.ttf`, `.css`, `.js`, `.map`
* The first path segment matches a reserved system path for that provider (e.g. `features`, `settings`, `explore`, `admin`)
* No path segments at all (bare host URL)

### Examples

```typescript theme={null}
import { parseGitLink } from '@clyrisai/gitresolve';

// Profile
parseGitLink('https://github.com/torvalds');
// { url: 'https://github.com/torvalds', provider: 'github', type: 'profile', username: 'torvalds' }

// Repo
parseGitLink('https://github.com/vercel/next.js');
// { url: 'https://github.com/vercel/next.js', provider: 'github', type: 'repo', username: 'vercel', repo: 'next.js' }

// gist.github.com is NOT in GIT_HOSTS — returns null
parseGitLink('https://gist.github.com/sindresorhus/abc123'); // null

// Pull request
parseGitLink('https://github.com/facebook/react/pull/28987');
// { url: '...', provider: 'github', type: 'pull_request', username: 'facebook', repo: 'react', number: '28987' }

// Static asset — silently discarded
parseGitLink('https://github.com/some/repo/logo.png'); // null

// Non-git host — silently discarded
parseGitLink('https://example.com/user/repo');          // null

// Reserved path — silently discarded
parseGitLink('https://github.com/settings/profile');    // null
```

***

## `extractGitUrlsFromText`

Scans a block of plain text (or raw HTML) with a regex and returns every unique git provider URL it finds. This is used internally by `parseResume` and `extractLinksFromHtml`.

```typescript theme={null}
function extractGitUrlsFromText(text: string): string[]
```

### Parameters

<ParamField path="text" type="string" required>
  Any arbitrary string — resume text, raw HTML, a markdown document, etc.
</ParamField>

### Returns

An array of unique, normalised URL strings. Each returned value:

* Has an `https://` prefix (bare `github.com/...` fragments are promoted)
* Has trailing slashes stripped
* Appears only once (the array is deduplicated before returning)
* Matches only `github.com`, `gitlab.com`, or `bitbucket.org` hostnames

<Note>
  The regex captures at most **two path segments** beyond the hostname, so `https://github.com/owner/repo` is captured but `https://github.com/owner/repo/blob/main/README.md` is truncated to `https://github.com/owner/repo`. This is intentional — deeper paths are not useful for profile resolution and create noise.
</Note>

### Examples

```typescript theme={null}
import { extractGitUrlsFromText } from '@clyrisai/gitresolve';

const text = `
  Check out my projects at github.com/janedoe and
  https://gitlab.com/janedoe/api-service.
  I also contributed to https://github.com/facebook/react/pull/42.
`;

extractGitUrlsFromText(text);
// [
//   'https://github.com/janedoe',
//   'https://gitlab.com/janedoe/api-service',
//   'https://github.com/facebook/react',  // truncated at 2 segments
// ]
```

***

## `isGitProviderUrl`

Returns `true` if and only if the URL's hostname is one of the six recognised git provider hostnames. Useful as a fast filter before calling heavier parsing functions.

```typescript theme={null}
function isGitProviderUrl(link: string): boolean
```

### Parameters

<ParamField path="link" type="string" required>
  An absolute URL string. Invalid URLs return `false` rather than throwing.
</ParamField>

### Returns

`true` if the hostname is in `GIT_HOSTS`, `false` otherwise.

The six recognised hostnames are:

| Hostname            | Provider    |
| ------------------- | ----------- |
| `github.com`        | `github`    |
| `www.github.com`    | `github`    |
| `gitlab.com`        | `gitlab`    |
| `www.gitlab.com`    | `gitlab`    |
| `bitbucket.org`     | `bitbucket` |
| `www.bitbucket.org` | `bitbucket` |

### Examples

```typescript theme={null}
import { isGitProviderUrl } from '@clyrisai/gitresolve';

isGitProviderUrl('https://github.com/torvalds/linux');  // true
isGitProviderUrl('https://www.github.com/torvalds');    // true
isGitProviderUrl('https://bitbucket.org/owner/repo');   // true
isGitProviderUrl('https://example.com/owner/repo');     // false
isGitProviderUrl('not-a-url');                          // false
```

***

## `GIT_HOSTS`

A constant lookup map from hostname string to `GitProvider`. Exported for cases where you need to check or iterate the recognised hosts without importing `isGitProviderUrl`.

```typescript theme={null}
import { GIT_HOSTS } from '@clyrisai/gitresolve';

// Type: Record<string, GitProvider>
// Value:
{
  'github.com':         'github',
  'www.github.com':     'github',
  'gitlab.com':         'gitlab',
  'www.gitlab.com':     'gitlab',
  'bitbucket.org':      'bitbucket',
  'www.bitbucket.org':  'bitbucket',
}
```

### Usage

```typescript theme={null}
import { GIT_HOSTS } from '@clyrisai/gitresolve';

const hostname = new URL(someUrl).hostname.toLowerCase();
const provider = GIT_HOSTS[hostname]; // 'github' | 'gitlab' | 'bitbucket' | undefined

if (provider) {
  console.log(`This is a ${provider} URL`);
}
```
