-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f63b76c
commit 4f471e2
Showing
5 changed files
with
179 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,37 @@ | ||
# npi-validator | ||
Validate NPI numbers for healthcare physicians or organizations | ||
|
||
Validation function for National Provider Identifier (NPI) numbers. Works for healthcare physicians and organizations in the United States or other countries that use the NPI standard. | ||
|
||
This is an implementation of the Luhn formula (mod 10 double add double) check digit, see the [CMS.gov specification](https://www.cms.gov/Regulations-and-Guidance/Administrative-Simplification/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf) for more information. | ||
|
||
## Install | ||
|
||
```sh | ||
npm install npi-validator | ||
``` | ||
|
||
## Usage | ||
|
||
```js | ||
import npiValid from 'npi-validator'; | ||
|
||
const npi = 1234567893; | ||
const valid = npiValid(npi); | ||
|
||
console.log(valid); | ||
//=> true | ||
``` | ||
|
||
## API | ||
|
||
### `function npiValid(id: string | number, prefix?: string | number): boolean` | ||
|
||
```js | ||
import npiValid from 'npi-validator'; | ||
|
||
const npi = 1234567893; | ||
const valid = npiValid(npi); | ||
|
||
console.log(valid); | ||
//=> true | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
Validates NPI numbers. See the [CMS.gov specification](https://www.cms.gov/Regulations-and-Guidance/Administrative-Simplification/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf) for more information. | ||
@example | ||
``` | ||
import npiValid from 'npi-validator'; | ||
const npi = 1234567893; | ||
const valid = npiValid(npi); | ||
console.log(valid); | ||
//=> true | ||
``` | ||
@param id - npi number; must be 10 digits | ||
@param prefix - prefix number; defaults to 80840; must start with 80,the health prefix, and be followed by the 3 digit country code | ||
*/ | ||
export function npiValid(id: string | number, prefix?: string | number): boolean; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
const {ceil, floor} = Math; | ||
const toInt = s => Number.parseInt(s, 10); | ||
|
||
const sumDigits = int => { | ||
let sum = 0; | ||
while (int) { | ||
sum += int % 10; | ||
int = floor(int / 10); | ||
} | ||
|
||
return sum; | ||
}; | ||
|
||
const doubleAlternate = (value, index) => { | ||
let pos = index ?? value.length - 1; | ||
let sum = 0; | ||
let alt = true; | ||
for (; pos >= 0; pos--) { | ||
const cur = toInt(value.charAt(pos)); | ||
sum += alt ? sumDigits(cur * 2) : cur; | ||
alt = !alt; | ||
} | ||
|
||
return sum; | ||
}; | ||
|
||
export function npiValid(id, prefix = '80840') { | ||
const prefixRegex = /^80\d{3}$/; | ||
const npiRegex = /^\d{10}$/; | ||
const usPrefixSum = 24; // Precalculated value for 80840 (United States) | ||
const npi = id?.toString() ?? ''; | ||
const pre = prefix?.toString() ?? ''; | ||
|
||
if (!npiRegex.test(npi) || !prefixRegex.test(pre)) { | ||
return false; | ||
} | ||
|
||
const check = toInt(npi.charAt(9)); | ||
const npiSum = doubleAlternate(npi, 8); | ||
const preSum = pre === '80840' ? usPrefixSum : doubleAlternate(pre, 3); | ||
const total = npiSum + preSum; | ||
const totalCeil = ceil(total / 10) * 10; | ||
|
||
return totalCeil - total === check; | ||
} | ||
|
||
export default npiValid; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
{ | ||
"name": "npi-validator", | ||
"version": "1.0.0", | ||
"description": "Validate NPI numbers for healthcare physicians or organizations.", | ||
"homepage": "https://github.com/coryasilva/npi-validator#readme", | ||
"bugs": { | ||
"url": "https://github.com/coryasilva/npi-validator/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/coryasilva/npi-validator.git" | ||
}, | ||
"author": { | ||
"name": "Cory Silva", | ||
"url": "https://corysilva.com" | ||
}, | ||
"keywords": [ | ||
"healthcare", | ||
"npi", | ||
"validation" | ||
], | ||
"engines": { | ||
"node": ">=18" | ||
}, | ||
"type": "module", | ||
"sideEffects": false, | ||
"main": "index.js", | ||
"exports": { | ||
"types": "./index.d.ts", | ||
"default": "./index.js" | ||
}, | ||
"scripts": { | ||
"test": "xo && ava && tsc index.d.ts" | ||
}, | ||
"devDependencies": { | ||
"ava": "^6.0.1", | ||
"typescript": "^5.3.3", | ||
"xo": "^0.56.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* eslint-disable unicorn/numeric-separators-style */ | ||
import test from 'ava'; | ||
import npiValid from './index.js'; | ||
|
||
test('NPI validation with default United States prefix', t => { | ||
t.is(npiValid(1234567893), true); | ||
t.is(npiValid('1234567893'), true); | ||
t.is(npiValid(1234567890), false); | ||
|
||
// Bad inputs | ||
t.is(npiValid(''), false); | ||
t.is(npiValid(' '), false); | ||
t.is(npiValid(undefined), false); | ||
t.is(npiValid(null), false); | ||
t.is(npiValid({}), false); | ||
t.is(npiValid([]), false); | ||
t.is(npiValid(true), false); | ||
t.is(npiValid(false), false); | ||
t.is(npiValid(), false); | ||
}); | ||
|
||
test('NPI validation with custom prefix', t => { | ||
t.is(npiValid(1234567894, 80123), true); | ||
t.is(npiValid(1234567894, '80123'), true); | ||
t.is(npiValid(1234567894, 8012), false); | ||
t.is(npiValid(1234567894, 81840), false); | ||
|
||
// Bad inputs | ||
t.is(npiValid(1234567893, ''), false); | ||
t.is(npiValid(1234567893, ' '), false); | ||
t.is(npiValid(1234567893, '80 '), false); | ||
t.is(npiValid(1234567893, undefined), true); | ||
t.is(npiValid(1234567893, null), false); | ||
t.is(npiValid(1234567893, {}), false); | ||
t.is(npiValid(1234567893, []), false); | ||
t.is(npiValid(1234567893, true), false); | ||
t.is(npiValid(1234567893, false), false); | ||
}); |