issue-parser
A synchronous text parser for issue references, issue-closing actions, duplicate markers, and user mentions written in GitHub, GitLab, or Bitbucket conventions. It turns strings such as `Fix owner/repo#42 and ping @sam` into separate action and mention records, and can be configured with custom keywords, prefixes, hosts, and URL path segments. It is a regex-based extractor for release notes, commit messages, and bot input. It does not contact a forge or determine whether a referenced user, issue, or repository exists.
A focused and configurable extractor for automation that already knows its repository context. Do not mistake regex recognition for Markdown parsing or forge validation, and copy `allRefs` before serializing the result.
Use it if
- You need to extract issue actions and mentions from commit messages, release notes, pull request text, or bot commands
- You support GitHub, GitLab, or Bitbucket syntax and want provider presets instead of maintaining several regular expressions
- You need custom action groups such as parent, related, or blocked while retaining a provider's built-in rules
- You want inline code, fenced code, HTML code tags, and HTML comments excluded from ordinary reference matching
- You need to validate that issues or users exist, fetch titles, or apply closing actions: this library performs no network requests and only returns text matches
- You need source offsets, line numbers, or a Markdown syntax tree: records contain raw text and parsed fields but no positions, and code exclusion is implemented with regular expressions
- You publish strict ESM or TypeScript code without interop: version 7.0.2 is CommonJS, has no exports map, and ships no TypeScript declarations
- You need arbitrary forge grammar or context-sensitive parsing: the recognizer is built from configurable regex fragments and only understands numeric issue identifiers plus configured prefixes, hosts, and URL segments
- You expect JSON.stringify(result) to include every reference: allRefs is defined as a non-enumerable getter, so read or copy it explicitly before serialization
Setup reality
Install with `npm install issue-parser`; there are no peer dependencies, credentials, native builds, or config files. Version 7.0.2 requires Node 18.17 or Node 20.6.1 and later, and it exposes a CommonJS factory. Call the factory once with `github`, `gitlab`, `bitbucket`, or a custom option object, then reuse the returned synchronous parser. The factory compiles regular expressions, so do not rebuild it for every line in a large log. Provider options are presets rather than API clients: parsing `Fix #12` cannot tell you which repository owns the issue unless the text includes a slug or your application supplies repository context afterward. Issue numbers remain strings. The result always separates unqualified references, action matches, and mentions; action keys with configured keywords appear as arrays even when empty. `allRefs` combines ordinary and action references and deduplicates by raw text, but the source defines it as a non-enumerable getter, which means object spread and JSON.stringify omit it. Copy it to a normal property when sending results across a process boundary. The parser removes triple or quadruple backtick fences, inline backticks, HTML code tags, and HTML comments before matching. That avoids common false positives but is not a full Markdown parser, so unusual fence lengths, malformed markup, nested constructs, or provider-specific rich text can still surprise you. Custom actions merge by action-key, while arrays on an overridden key replace that preset's array rather than append automatically. Strings are accepted where arrays are documented and normalized internally. Prefixes and keywords are regex-escaped, but very broad values can still create noisy matches. Five lodash subpackages are installed at runtime. No bundled types are provided, so TypeScript teams must add a local declaration or wrapper type.
Patterns
Parse GitHub actions, references, and mentionsparse-github-text
const issueParser = require('issue-parser')
const parse = issueParser('github')
const result = parse('Fix #12, see owner/docs#8, and ping @alex')
console.log(result.actions.close)
console.log(result.refs)
console.log(result.mentions)A bare #12 has no slug. Your application must attach the current repository context if it needs a fully qualified identifier.
Recognize GitLab issue and merge-request syntaxparse-gitlab-text
const parse = require('issue-parser')('gitlab')
const result = parse('Implement group/project#31; review group/project!9; /cc @lee')
console.log(result.actions.close, result.refs)Issue identifiers are returned as strings. A `!` prefix identifies GitLab merge-request references according to the preset.
Parse Bitbucket referencesparse-bitbucket-text
const parse = require('issue-parser')('bitbucket')
const result = parse('Fixing team/repo#4 and notify @owner')The Bitbucket preset supports its documented closing, reference, and mention forms but does not add the GitHub duplicate vocabulary automatically.
Combine action and ordinary referencescollect-all-references
const parse = require('issue-parser')('github')
const result = parse('Fix #2 and compare #3')
const payload = {
...result,
allRefs: result.allRefs,
}
console.log(JSON.stringify(payload))allRefs is a non-enumerable getter and is omitted by JSON.stringify or object spread unless copied explicitly as shown.
Extract issue and pull request URLsparse-full-urls
const parse = require('issue-parser')('github')
const result = parse([
'See https://github.com/acme/widget/pull/17',
'Fix https://github.com/acme/widget/issues/22',
].join('\n'))Full URLs produce a slug and issue number. The parser still does not make an HTTP request or verify the URL.
Add action groups to a provider presetextend-action-keywords
const issueParser = require('issue-parser')
const parse = issueParser('github', {
actions: {
parent: ['parent of'],
related: ['related to'],
},
})
const result = parse('Parent of #3; related to #9; fix #12')New action keys merge with the preset. Reusing an existing key such as close replaces that key's keyword array rather than appending to it.
Define a custom issue markercustom-issue-prefix
const parse = require('issue-parser')({
actions: { close: ['complete'], blocked: ['blocked by'] },
issuePrefixes: ['BUG-'],
mentionsPrefixes: ['@'],
})
const result = parse('Complete BUG-41, blocked by BUG-39')Identifiers must still end in digits. The returned prefix is the configured marker and issue remains a string.
Recognize a self-hosted GitHub-style URLself-hosted-forge
const issueParser = require('issue-parser')
const parse = issueParser('github', {
hosts: ['https://git.example.com'],
issueURLSegments: ['issues', 'pull'],
})
const result = parse('Fix https://git.example.com/acme/api/issues/7')Overriding hosts replaces the preset host list. Include every public and private base URL that the input may contain.
Allow punctuation after action wordscustom-delimiters
const issueParser = require('issue-parser')
const parse = issueParser('github', { delimiters: [':', '-'] })
const result = parse('Fix: #1 and resolves - #2')Spaces and tabs are always accepted. Delimiters are literal strings and are escaped before the regular expression is built.
Recognize a custom mention markercustom-mention-prefix
const issueParser = require('issue-parser')
const parse = issueParser('github', { mentionsPrefixes: ['~'] })
const result = parse('Fix #2 and ask ~alex instead of @sam')
console.log(result.mentions) // [{ raw: '~alex', prefix: '~', user: 'alex' }]Overriding mentionsPrefixes replaces the provider default, so @sam is no longer recognized in this parser.
Avoid references inside Markdown codeignore-code-examples
const parse = require('issue-parser')('github')
const text = [
'Fix #1',
'`Fix #2`',
'```js',
'// Fix #3',
'```',
].join('\n')
console.log(parse(text).allRefs.map((ref) => ref.issue)) // ['1']The exclusion is regex-based rather than a Markdown AST. Test malformed or unusual Markdown produced by your own editor before relying on it as a security boundary.
Create one parser for a batchreuse-compiled-parser
const parse = require('issue-parser')('github')
const parsedCommits = commits.map((commit) => ({
hash: commit.hash,
references: [...parse(commit.message).allRefs],
}))The factory builds provider-specific regular expressions. Reuse the returned function instead of reconstructing it for each commit.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| conventional-commits-parser | npm | Your primary input is Conventional Commits and you need headers, notes, scopes, and references parsed together |
| git-url-parse | npm | You only need provider, owner, repository, and ref information from Git remote URLs |
| hosted-git-info | npm | You need normalized hosted-repository metadata from package-style git specifications rather than prose references |
| @github/issue-parser | npm | You need to turn a GitHub issue-form Markdown response into field-value JSON, not find issue numbers in prose |