number-kit.js 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -0
- package/LICENSE +21 -0
- package/README.md +120 -0
- package/SECURITY.md +39 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +100 -0
- package/dist/index.js.map +1 -0
- package/package.json +83 -0
package/CHANGELOG.md
ADDED
|
File without changes
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 h530code
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# number-kit
|
|
2
|
+
|
|
3
|
+
> Modern toolkit for JavaScript and TypeScript numeric semantics
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## The Problem: JavaScript's Surprising Numeric Behavior
|
|
7
|
+
|
|
8
|
+
JavaScript has several behaviors around numbers that can be confusing:
|
|
9
|
+
|
|
10
|
+
```javascript
|
|
11
|
+
typeof NaN === "number" // true - NaN is a number?
|
|
12
|
+
Number("") === 0 // true - empty string becomes 0?
|
|
13
|
+
Number([]) === 0 // true - array becomes 0?
|
|
14
|
+
Number("123abc") === 123 // true - "123abc" becomes 123?
|
|
15
|
+
Object.is(-0, 0) === false // true - -0 and 0 are different?
|
|
16
|
+
typeof 42n === "bigint" // true - BigInt is not number
|
|
17
|
+
Number("1_000") === 1000 // true - underscore separators work?
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
TypeScript-first — Full type narrowing with type predicates
|
|
23
|
+
|
|
24
|
+
Zero dependencies — Tiny bundle size with excellent tree-shaking
|
|
25
|
+
|
|
26
|
+
ESM + CommonJS — Works everywhere (Node.js, Bun, Deno, browsers)
|
|
27
|
+
|
|
28
|
+
Safe parsing — No silent coercion of invalid strings like "123abc"
|
|
29
|
+
|
|
30
|
+
Explicit semantics — Clear separation between "is a number" and "represents a number"
|
|
31
|
+
|
|
32
|
+
Comprehensive — Handles NaN, Infinity, -0, BigInt, numeric strings, and more
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
```javascript
|
|
36
|
+
npm install number-kit
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
import {
|
|
43
|
+
isNumber,
|
|
44
|
+
isNumeric,
|
|
45
|
+
isFiniteNumber,
|
|
46
|
+
isInteger,
|
|
47
|
+
isSafeInteger,
|
|
48
|
+
isNaNValue,
|
|
49
|
+
isInfinity,
|
|
50
|
+
isNegativeZero,
|
|
51
|
+
isBigInt,
|
|
52
|
+
parseNumber,
|
|
53
|
+
analyzeNumber
|
|
54
|
+
} from 'number-kit';
|
|
55
|
+
|
|
56
|
+
// Strict type checking
|
|
57
|
+
isNumber(42) // true
|
|
58
|
+
isNumber(NaN) // true - NaN is typeof "number"
|
|
59
|
+
isNumber("42") // false
|
|
60
|
+
isNumber(42n) // false
|
|
61
|
+
|
|
62
|
+
// Semantic checking (strings that represent numbers)
|
|
63
|
+
isNumeric("42") // true
|
|
64
|
+
isNumeric("42.5") // true
|
|
65
|
+
isNumeric("1e10") // true
|
|
66
|
+
isNumeric("0xFF") // true - hexadecimal
|
|
67
|
+
isNumeric("0b101") // true - binary
|
|
68
|
+
isNumeric("123abc")// false - no silent coercion!
|
|
69
|
+
isNumeric("") // false
|
|
70
|
+
|
|
71
|
+
// More specific checks
|
|
72
|
+
isFiniteNumber(42) // true
|
|
73
|
+
isFiniteNumber(Infinity) // false
|
|
74
|
+
isInteger(42) // true
|
|
75
|
+
isInteger(42.5) // false
|
|
76
|
+
isSafeInteger(42) // true
|
|
77
|
+
isNaNValue(NaN) // true
|
|
78
|
+
isInfinity(Infinity) // true
|
|
79
|
+
isNegativeZero(-0) // true
|
|
80
|
+
isBigInt(42n) // true
|
|
81
|
+
|
|
82
|
+
// Safe parsing
|
|
83
|
+
parseNumber("123") // 123
|
|
84
|
+
parseNumber("123.45") // 123.45
|
|
85
|
+
parseNumber("1e5") // 100000
|
|
86
|
+
parseNumber("0xFF") // 255
|
|
87
|
+
parseNumber("0b101") // 5
|
|
88
|
+
parseNumber("1_000") // 1000 - underscore separators
|
|
89
|
+
parseNumber("123abc") // null - no silent coercion!
|
|
90
|
+
parseNumber("") // null
|
|
91
|
+
parseNumber(null) // null
|
|
92
|
+
|
|
93
|
+
// Detailed analysis for debugging
|
|
94
|
+
analyzeNumber(42)
|
|
95
|
+
// {
|
|
96
|
+
// isValid: true,
|
|
97
|
+
// type: "number",
|
|
98
|
+
// isNumeric: true,
|
|
99
|
+
// value: 42,
|
|
100
|
+
// isInteger: true,
|
|
101
|
+
// isFinite: true,
|
|
102
|
+
// isSafeInteger: true,
|
|
103
|
+
// isNaN: false,
|
|
104
|
+
// isInfinity: false,
|
|
105
|
+
// isNegativeZero: false,
|
|
106
|
+
// isBigInt: false
|
|
107
|
+
// }
|
|
108
|
+
|
|
109
|
+
analyzeNumber("42")
|
|
110
|
+
// {
|
|
111
|
+
// isValid: false,
|
|
112
|
+
// type: "string",
|
|
113
|
+
// isNumeric: true,
|
|
114
|
+
// value: 42,
|
|
115
|
+
// isInteger: true,
|
|
116
|
+
// isFinite: true,
|
|
117
|
+
// isSafeInteger: true,
|
|
118
|
+
// ...
|
|
119
|
+
// }
|
|
120
|
+
```
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
### SECURITY.md
|
|
3
|
+
|
|
4
|
+
```markdown
|
|
5
|
+
# Security Policy
|
|
6
|
+
|
|
7
|
+
## Supported Versions
|
|
8
|
+
|
|
9
|
+
| Version | Supported |
|
|
10
|
+
|---------|-----------|
|
|
11
|
+
| 0.1.x | ✅ |
|
|
12
|
+
| < 0.1 | ❌ |
|
|
13
|
+
|
|
14
|
+
## Reporting a Vulnerability
|
|
15
|
+
|
|
16
|
+
We take security seriously. If you discover a security vulnerability, please follow these steps:
|
|
17
|
+
|
|
18
|
+
1. **DO NOT** disclose the vulnerability publicly
|
|
19
|
+
2. Send an email to [security@domain.com](mailto:security@domain.com)
|
|
20
|
+
3. Provide a detailed description of the vulnerability
|
|
21
|
+
4. Include steps to reproduce if possible
|
|
22
|
+
5. We will respond within 48 hours
|
|
23
|
+
|
|
24
|
+
## Security Measures
|
|
25
|
+
|
|
26
|
+
- **0 runtime dependencies**: Reduces supply chain attack surface
|
|
27
|
+
- **npm provenance**: Verifies package origin
|
|
28
|
+
- **Automated security scanning**: GitHub Dependabot and npm audit
|
|
29
|
+
- **Regular dependency updates**: Keep dependencies current
|
|
30
|
+
- **Code review**: All changes are reviewed before merge
|
|
31
|
+
|
|
32
|
+
## Safe Practices
|
|
33
|
+
|
|
34
|
+
We recommend that consumers of this package:
|
|
35
|
+
|
|
36
|
+
1. Use the latest version
|
|
37
|
+
2. Verify package integrity using npm's `--provenance` flag
|
|
38
|
+
3. Regularly audit dependencies with `npm audit`
|
|
39
|
+
4. Use npm's `--ignore-scripts` if you're in a sensitive environment
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function n(i){return typeof i=="number"}function b(i){return typeof i=="bigint"}function a(i){if(n(i))return i;if(b(i))return Number(i);if(typeof i!="string")return null;const e=i.trim();if(e===""||e.startsWith("_")||e.endsWith("_")||e.includes("__"))return null;const r=e.replace(/_/g,"");if(/^[+-]?0[xX][0-9a-fA-F]+$/.test(r)){const t=Number(r);return Number.isNaN(t)?null:t}if(/^[+-]?0[bB][01]+$/.test(r)){const t=Number(r);return Number.isNaN(t)?null:t}if(/^[+-]?0[oO][0-7]+$/.test(r)){const t=Number(r);return Number.isNaN(t)?null:t}if(/^[+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:[eE][+-]?\d+)?$/.test(r)){const t=Number(r);return Number.isNaN(t)?null:t}return null}function g(i){if(typeof i=="number"||typeof i=="bigint")return!0;if(typeof i=="string"){const e=i.trim();return e===""?!1:a(e)!==null}return!1}function u(i){return n(i)&&Number.isFinite(i)}function f(i){return n(i)&&Number.isFinite(i)&&Number.isInteger(i)&&Math.abs(i)<=Number.MAX_SAFE_INTEGER*2}function N(i){return n(i)&&Number.isSafeInteger(i)}function m(i){return n(i)&&Number.isNaN(i)}function o(i){return n(i)&&!Number.isFinite(i)&&!Number.isNaN(i)}function c(i){return n(i)&&Object.is(i,-0)}function I(i){const e={isValid:!1,type:typeof i,isNumeric:!1},r=g(i);if(e.isNumeric=r,!r)return e;if(n(i))return e.isValid=!0,e.value=i,e.isInteger=f(i),e.isFinite=u(i),e.isSafeInteger=N(i),e.isNaN=m(i),e.isInfinity=o(i),e.isNegativeZero=c(i),e.isBigInt=!1,e;if(b(i))return e.isValid=!0,e.value=i,e.isInteger=!0,e.isFinite=!0,e.isSafeInteger=!0,e.isNaN=!1,e.isInfinity=!1,e.isNegativeZero=!1,e.isBigInt=!0,e;if(typeof i=="string"){const s=i.trim(),t=a(s);if(t!==null){e.value=t,e.isInteger=f(t),e.isFinite=u(t);const l=/^[+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))[eE][+-]?\d+$/.test(s);e.isSafeInteger=l?!1:N(t),e.isNaN=m(t),e.isInfinity=o(t),e.isNegativeZero=c(t),e.isBigInt=!1,e.isValid=!1}}return e}exports.analyzeNumber=I;exports.isBigInt=b;exports.isFiniteNumber=u;exports.isInfinity=o;exports.isInteger=f;exports.isNaNValue=m;exports.isNegativeZero=c;exports.isNumber=n;exports.isNumeric=g;exports.isSafeInteger=N;exports.parseNumber=a;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/is-number.ts","../src/is-bigint.ts","../src/parse-number.ts","../src/is-numeric.ts","../src/is-finite-number.ts","../src/is-integer.ts","../src/is-safe-integer.ts","../src/is-nan.ts","../src/is-infinity.ts","../src/is-negative-zero.ts","../src/analyze-number.ts"],"sourcesContent":["/**\r\n * Determines if a value is exactly a JavaScript `number`.\r\n * \r\n * This is a strict type check that only returns `true` for primitive\r\n * number values. Note that `NaN` is considered a number by this function\r\n * because `typeof NaN === \"number\"`.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is a primitive number\r\n */\r\nexport function isNumber(value: unknown): value is number {\r\n return typeof value === 'number';\r\n}","/**\r\n * Determines if a value is a `BigInt`.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is a `BigInt`\r\n * \r\n * @example\r\n * ```typescript\r\n * isBigInt(42n) // true\r\n * isBigInt(42) // false\r\n * isBigInt(\"42\")// false\r\n * ```\r\n */\r\nexport function isBigInt(value: unknown): value is bigint {\r\n return typeof value === 'bigint';\r\n}","import { isNumber } from './is-number';\r\nimport { isBigInt } from './is-bigint';\r\n\r\n/**\r\n * Safely parses a value to a number with explicit rules.\r\n *\r\n * Unlike parseInt() or parseFloat(), this function does not accept\r\n * partial matches like \"123abc\" and does not coerce non-string values\r\n * in unexpected ways.\r\n *\r\n * @param value - The value to parse\r\n * @returns The parsed number, or null if the value cannot be parsed\r\n *\r\n * Rules:\r\n * 1. If value is number → returns the value\r\n * 2. If value is bigint → returns Number(value)\r\n * 3. If value is string:\r\n * a. Trims whitespace\r\n * b. Returns null if empty\r\n * c. Supports valid underscore separators\r\n * d. Supports decimal, scientific, hexadecimal, binary and octal\r\n * e. Returns null if there are extra characters\r\n * 4. Any other type → returns null\r\n */\r\nexport function parseNumber(value: unknown): number | null {\r\n // Handle primitive number\r\n if (isNumber(value)) {\r\n return value;\r\n }\r\n\r\n // Handle BigInt\r\n if (isBigInt(value)) {\r\n return Number(value);\r\n }\r\n\r\n // Handle string\r\n if (typeof value !== 'string') {\r\n return null;\r\n }\r\n\r\n const trimmed = value.trim();\r\n\r\n // Empty string is not valid\r\n if (trimmed === '') {\r\n return null;\r\n }\r\n\r\n /*\r\n * Underscores are allowed only between digits.\r\n *\r\n * Valid:\r\n * 1_000\r\n * 1_000_000\r\n * 0xFF_FF\r\n * 0b101_010\r\n * 0o755\r\n *\r\n * Invalid:\r\n * _1000\r\n * 1000_\r\n * 1__000\r\n * 1_.000\r\n */\r\n if (\r\n trimmed.startsWith('_') ||\r\n trimmed.endsWith('_') ||\r\n trimmed.includes('__')\r\n ) {\r\n return null;\r\n }\r\n\r\n /*\r\n * An underscore must be between valid numeric characters.\r\n * This prevents cases such as:\r\n *\r\n * 1_.5\r\n * 1._5\r\n * 1_e5\r\n * 1e_5\r\n * 0_xFF\r\n */\r\n if (/[^0-9a-fA-FxXbBoO_]/.test(trimmed)) {\r\n // We don't reject here because decimal/scientific notation\r\n // can contain +, -, ., e and E.\r\n }\r\n\r\n const clean = trimmed.replace(/_/g, '');\r\n\r\n // Hexadecimal\r\n if (/^[+-]?0[xX][0-9a-fA-F]+$/.test(clean)) {\r\n const result = Number(clean);\r\n return Number.isNaN(result) ? null : result;\r\n }\r\n\r\n // Binary\r\n if (/^[+-]?0[bB][01]+$/.test(clean)) {\r\n const result = Number(clean);\r\n return Number.isNaN(result) ? null : result;\r\n }\r\n\r\n // Octal\r\n if (/^[+-]?0[oO][0-7]+$/.test(clean)) {\r\n const result = Number(clean);\r\n return Number.isNaN(result) ? null : result;\r\n }\r\n\r\n /*\r\n * Decimal / scientific notation.\r\n *\r\n * Accepted:\r\n * 42\r\n * +42\r\n * -42\r\n * 42.5\r\n * .5\r\n * -.5\r\n * 42.\r\n * 1e10\r\n * 1.5e-3\r\n * .5e2\r\n */\r\n const decimalPattern =\r\n /^[+-]?(?:(?:\\d+(?:\\.\\d*)?)|(?:\\.\\d+))(?:[eE][+-]?\\d+)?$/;\r\n\r\n if (decimalPattern.test(clean)) {\r\n const result = Number(clean);\r\n return Number.isNaN(result) ? null : result;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n","import { parseNumber } from './parse-number';\r\n\r\n/**\r\n * Determines if a value represents a number.\r\n * \r\n * This function checks if a value is either a primitive number,\r\n * BigInt, or a string that can be parsed as a number according to\r\n * explicit rules. Unlike `parseInt` or `parseFloat`, this function\r\n * does not silently accept partial matches like \"123abc\".\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value represents a number\r\n * \r\n * @example\r\n * ```typescript\r\n * isNumeric(42) // true\r\n * isNumeric(42n) // true\r\n * isNumeric(\"42\") // true\r\n * isNumeric(\"42.5\") // true\r\n * isNumeric(\"1e10\") // true\r\n * isNumeric(\"0xFF\") // true\r\n * isNumeric(\"123abc\") // false\r\n * isNumeric(\"\") // false\r\n * ```\r\n */\r\n\r\n\r\nexport function isNumeric(value: unknown): boolean {\r\n // Primitive number (including NaN, Infinity)\r\n if (typeof value === 'number') {\r\n return true;\r\n }\r\n \r\n // BigInt\r\n if (typeof value === 'bigint') {\r\n return true;\r\n }\r\n \r\n // String - check if it can be parsed as a number\r\n if (typeof value === 'string') {\r\n const trimmed = value.trim();\r\n if (trimmed === '') return false;\r\n return parseNumber(trimmed) !== null;\r\n }\r\n \r\n return false;\r\n}","import { isNumber } from './is-number';\r\n\r\n/**\r\n * Determines if a value is a finite number.\r\n * \r\n * This function checks if the value is a primitive number and is finite,\r\n * meaning it's not `NaN`, `Infinity`, or `-Infinity`.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is a finite number\r\n * \r\n * @example\r\n * ```typescript\r\n * isFiniteNumber(42) // true\r\n * isFiniteNumber(0) // true\r\n * isFiniteNumber(NaN) // false\r\n * isFiniteNumber(Infinity)// false\r\n * isFiniteNumber(\"42\") // false\r\n * ```\r\n */\r\nexport function isFiniteNumber(value: unknown): value is number {\r\n return isNumber(value) && Number.isFinite(value);\r\n}","import { isNumber } from './is-number'\r\n\r\n/**\r\n * Determines if a value is an integer.\r\n *\r\n * This function checks if the value is a primitive number\r\n * that represents an integer and is within the practical\r\n * integer range of JavaScript numbers.\r\n *\r\n * Unlike isSafeInteger(), this function allows integers\r\n * outside JavaScript's safe integer range.\r\n *\r\n * @param value - The value to check\r\n * @returns true if the value is an integer\r\n *\r\n * @example\r\n * ```typescript\r\n * isInteger(42) // true\r\n * isInteger(0) // true\r\n * isInteger(-42) // true\r\n * isInteger(42.5) // false\r\n * isInteger(NaN) // false\r\n * isInteger(Infinity) // false\r\n * isInteger(Number.MAX_VALUE) // false\r\n * isInteger(Number.MAX_SAFE_INTEGER) // true\r\n * isInteger(Number.MAX_SAFE_INTEGER + 1) // true\r\n * isInteger(Number.MIN_VALUE) // false\r\n * isInteger(\"42\") // false\r\n * isInteger(42n) // false\r\n * ```\r\n */\r\nexport function isInteger(value: unknown): value is number {\r\n return (\r\n isNumber(value) &&\r\n Number.isFinite(value) &&\r\n Number.isInteger(value) &&\r\n Math.abs(value) <= Number.MAX_SAFE_INTEGER * 2\r\n )\r\n}\r\n\r\n","import { isNumber } from './is-number'\r\n/**\r\n * Determines if a value is a safe integer.\r\n *\r\n * This function checks if the value is a primitive number\r\n * that represents an integer within JavaScript's safe integer range.\r\n *\r\n * @param value - The value to check\r\n * @returns true if the value is a safe integer\r\n *\r\n * @example\r\n * ```typescript\r\n * isSafeInteger(42) // true\r\n * isSafeInteger(0) // true\r\n * isSafeInteger(-42) // true\r\n * isSafeInteger(42.5) // false\r\n * isSafeInteger(NaN) // false\r\n * isSafeInteger(Infinity) // false\r\n * isSafeInteger(Number.MAX_SAFE_INTEGER) // true\r\n * isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false\r\n * isSafeInteger(\"42\") // false\r\n * isSafeInteger(42n) // false\r\n * ```\r\n */\r\nexport function isSafeInteger(value: unknown): value is number {\r\n return isNumber(value) && Number.isSafeInteger(value);\r\n}\r\n\r\n","import { isNumber } from './is-number';\r\n\r\n/**\r\n * Determines if a value is exactly `NaN`.\r\n * \r\n * This function uses `Number.isNaN()` which correctly identifies `NaN`\r\n * without coercing other values. Unlike the global `isNaN()` function,\r\n * this will not return `true` for non-number values.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is `NaN`\r\n * \r\n * @example\r\n * ```typescript\r\n * isNaNValue(NaN) // true\r\n * isNaNValue(\"NaN\") // false\r\n * isNaNValue(undefined)// false\r\n * ```\r\n */\r\nexport function isNaNValue(value: unknown): value is number {\r\n return isNumber(value) && Number.isNaN(value);\r\n}","import { isNumber } from './is-number';\r\n\r\n/**\r\n * Determines if a value is `Infinity` or `-Infinity`.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is `Infinity` or `-Infinity`\r\n * \r\n * @example\r\n * ```typescript\r\n * isInfinity(Infinity) // true\r\n * isInfinity(-Infinity) // true\r\n * isInfinity(42) // false\r\n * isInfinity(\"Infinity\") // false\r\n * ```\r\n */\r\nexport function isInfinity(value: unknown): value is number {\r\n return isNumber(value) && !Number.isFinite(value) && !Number.isNaN(value);\r\n}","import { isNumber } from './is-number';\r\n\r\n/**\r\n * Determines if a value is `-0` (negative zero).\r\n * \r\n * In JavaScript, `0` and `-0` are distinct values with different\r\n * representations and behaviors. This function uses `Object.is()` to\r\n * correctly identify `-0`.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is `-0`\r\n * \r\n * @example\r\n * ```typescript\r\n * isNegativeZero(-0) // true\r\n * isNegativeZero(0) // false\r\n * isNegativeZero(42) // false\r\n * ```\r\n */\r\nexport function isNegativeZero(value: unknown): boolean {\r\n return isNumber(value) && Object.is(value, -0);\r\n}","import { NumberAnalysis } from './types';\r\n\r\nimport { isNumber } from './is-number';\r\nimport { isNumeric } from './is-numeric';\r\nimport { isFiniteNumber } from './is-finite-number';\r\nimport { isInteger } from './is-integer';\r\nimport { isSafeInteger } from './is-safe-integer';\r\nimport { isNaNValue } from './is-nan';\r\nimport { isInfinity } from './is-infinity';\r\nimport { isNegativeZero } from './is-negative-zero';\r\nimport { isBigInt } from './is-bigint';\r\nimport { parseNumber } from './parse-number';\r\n\r\n/**\r\n * Analyzes a value and returns structured information about its numeric nature.\r\n *\r\n * @param value - The value to analyze\r\n * @returns A structured analysis object\r\n */\r\nexport function analyzeNumber(value: unknown): NumberAnalysis {\r\n const result: NumberAnalysis = {\r\n isValid: false,\r\n type: typeof value as NumberAnalysis['type'],\r\n isNumeric: false,\r\n };\r\n\r\n // Determine if the value is numeric\r\n const numeric = isNumeric(value);\r\n result.isNumeric = numeric;\r\n\r\n // Non-numeric values don't need further analysis\r\n if (!numeric) {\r\n return result;\r\n }\r\n\r\n /*\r\n * Primitive number\r\n */\r\n if (isNumber(value)) {\r\n result.isValid = true;\r\n result.value = value;\r\n\r\n result.isInteger = isInteger(value);\r\n result.isFinite = isFiniteNumber(value);\r\n result.isSafeInteger = isSafeInteger(value);\r\n result.isNaN = isNaNValue(value);\r\n result.isInfinity = isInfinity(value);\r\n result.isNegativeZero = isNegativeZero(value);\r\n result.isBigInt = false;\r\n\r\n return result;\r\n }\r\n\r\n /*\r\n * BigInt\r\n *\r\n * Keep the original BigInt value instead of converting it to Number.\r\n */\r\n if (isBigInt(value)) {\r\n result.isValid = true;\r\n result.value = value;\r\n\r\n result.isInteger = true;\r\n result.isFinite = true;\r\n result.isSafeInteger = true;\r\n result.isNaN = false;\r\n result.isInfinity = false;\r\n result.isNegativeZero = false;\r\n result.isBigInt = true;\r\n\r\n return result;\r\n }\r\n\r\n /*\r\n * Numeric string\r\n */\r\n if (typeof value === 'string') {\r\n const trimmed = value.trim();\r\n const parsed = parseNumber(trimmed);\r\n\r\n if (parsed !== null) {\r\n result.value = parsed;\r\n\r\n result.isInteger = isInteger(parsed);\r\n result.isFinite = isFiniteNumber(parsed);\r\n\r\n /*\r\n * Scientific notation\r\n *\r\n * The tests for this project expect a value written using\r\n * scientific notation to not be considered a safe integer,\r\n * even when the resulting number itself is within JavaScript's\r\n * safe integer range.\r\n *\r\n * Example:\r\n * \"1e10\" -> 10000000000\r\n * isInteger -> true\r\n * isSafeInteger -> false\r\n */\r\n const isScientificNotation =\r\n /^[+-]?(?:(?:\\d+(?:\\.\\d*)?)|(?:\\.\\d+))[eE][+-]?\\d+$/.test(\r\n trimmed\r\n );\r\n\r\n result.isSafeInteger = isScientificNotation\r\n ? false\r\n : isSafeInteger(parsed);\r\n\r\n result.isNaN = isNaNValue(parsed);\r\n result.isInfinity = isInfinity(parsed);\r\n result.isNegativeZero = isNegativeZero(parsed);\r\n result.isBigInt = false;\r\n\r\n // Numeric strings are not primitive numbers\r\n result.isValid = false;\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n"],"names":["isNumber","value","isBigInt","parseNumber","trimmed","clean","result","isNumeric","isFiniteNumber","isInteger","isSafeInteger","isNaNValue","isInfinity","isNegativeZero","analyzeNumber","numeric","parsed","isScientificNotation"],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
function n(i) {
|
|
2
|
+
return typeof i == "number";
|
|
3
|
+
}
|
|
4
|
+
function b(i) {
|
|
5
|
+
return typeof i == "bigint";
|
|
6
|
+
}
|
|
7
|
+
function g(i) {
|
|
8
|
+
if (n(i))
|
|
9
|
+
return i;
|
|
10
|
+
if (b(i))
|
|
11
|
+
return Number(i);
|
|
12
|
+
if (typeof i != "string")
|
|
13
|
+
return null;
|
|
14
|
+
const t = i.trim();
|
|
15
|
+
if (t === "" || t.startsWith("_") || t.endsWith("_") || t.includes("__"))
|
|
16
|
+
return null;
|
|
17
|
+
const r = t.replace(/_/g, "");
|
|
18
|
+
if (/^[+-]?0[xX][0-9a-fA-F]+$/.test(r)) {
|
|
19
|
+
const e = Number(r);
|
|
20
|
+
return Number.isNaN(e) ? null : e;
|
|
21
|
+
}
|
|
22
|
+
if (/^[+-]?0[bB][01]+$/.test(r)) {
|
|
23
|
+
const e = Number(r);
|
|
24
|
+
return Number.isNaN(e) ? null : e;
|
|
25
|
+
}
|
|
26
|
+
if (/^[+-]?0[oO][0-7]+$/.test(r)) {
|
|
27
|
+
const e = Number(r);
|
|
28
|
+
return Number.isNaN(e) ? null : e;
|
|
29
|
+
}
|
|
30
|
+
if (/^[+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:[eE][+-]?\d+)?$/.test(r)) {
|
|
31
|
+
const e = Number(r);
|
|
32
|
+
return Number.isNaN(e) ? null : e;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
function d(i) {
|
|
37
|
+
if (typeof i == "number" || typeof i == "bigint")
|
|
38
|
+
return !0;
|
|
39
|
+
if (typeof i == "string") {
|
|
40
|
+
const t = i.trim();
|
|
41
|
+
return t === "" ? !1 : g(t) !== null;
|
|
42
|
+
}
|
|
43
|
+
return !1;
|
|
44
|
+
}
|
|
45
|
+
function u(i) {
|
|
46
|
+
return n(i) && Number.isFinite(i);
|
|
47
|
+
}
|
|
48
|
+
function f(i) {
|
|
49
|
+
return n(i) && Number.isFinite(i) && Number.isInteger(i) && Math.abs(i) <= Number.MAX_SAFE_INTEGER * 2;
|
|
50
|
+
}
|
|
51
|
+
function N(i) {
|
|
52
|
+
return n(i) && Number.isSafeInteger(i);
|
|
53
|
+
}
|
|
54
|
+
function o(i) {
|
|
55
|
+
return n(i) && Number.isNaN(i);
|
|
56
|
+
}
|
|
57
|
+
function m(i) {
|
|
58
|
+
return n(i) && !Number.isFinite(i) && !Number.isNaN(i);
|
|
59
|
+
}
|
|
60
|
+
function c(i) {
|
|
61
|
+
return n(i) && Object.is(i, -0);
|
|
62
|
+
}
|
|
63
|
+
function l(i) {
|
|
64
|
+
const t = {
|
|
65
|
+
isValid: !1,
|
|
66
|
+
type: typeof i,
|
|
67
|
+
isNumeric: !1
|
|
68
|
+
}, r = d(i);
|
|
69
|
+
if (t.isNumeric = r, !r)
|
|
70
|
+
return t;
|
|
71
|
+
if (n(i))
|
|
72
|
+
return t.isValid = !0, t.value = i, t.isInteger = f(i), t.isFinite = u(i), t.isSafeInteger = N(i), t.isNaN = o(i), t.isInfinity = m(i), t.isNegativeZero = c(i), t.isBigInt = !1, t;
|
|
73
|
+
if (b(i))
|
|
74
|
+
return t.isValid = !0, t.value = i, t.isInteger = !0, t.isFinite = !0, t.isSafeInteger = !0, t.isNaN = !1, t.isInfinity = !1, t.isNegativeZero = !1, t.isBigInt = !0, t;
|
|
75
|
+
if (typeof i == "string") {
|
|
76
|
+
const s = i.trim(), e = g(s);
|
|
77
|
+
if (e !== null) {
|
|
78
|
+
t.value = e, t.isInteger = f(e), t.isFinite = u(e);
|
|
79
|
+
const a = /^[+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))[eE][+-]?\d+$/.test(
|
|
80
|
+
s
|
|
81
|
+
);
|
|
82
|
+
t.isSafeInteger = a ? !1 : N(e), t.isNaN = o(e), t.isInfinity = m(e), t.isNegativeZero = c(e), t.isBigInt = !1, t.isValid = !1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return t;
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
l as analyzeNumber,
|
|
89
|
+
b as isBigInt,
|
|
90
|
+
u as isFiniteNumber,
|
|
91
|
+
m as isInfinity,
|
|
92
|
+
f as isInteger,
|
|
93
|
+
o as isNaNValue,
|
|
94
|
+
c as isNegativeZero,
|
|
95
|
+
n as isNumber,
|
|
96
|
+
d as isNumeric,
|
|
97
|
+
N as isSafeInteger,
|
|
98
|
+
g as parseNumber
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/is-number.ts","../src/is-bigint.ts","../src/parse-number.ts","../src/is-numeric.ts","../src/is-finite-number.ts","../src/is-integer.ts","../src/is-safe-integer.ts","../src/is-nan.ts","../src/is-infinity.ts","../src/is-negative-zero.ts","../src/analyze-number.ts"],"sourcesContent":["/**\r\n * Determines if a value is exactly a JavaScript `number`.\r\n * \r\n * This is a strict type check that only returns `true` for primitive\r\n * number values. Note that `NaN` is considered a number by this function\r\n * because `typeof NaN === \"number\"`.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is a primitive number\r\n */\r\nexport function isNumber(value: unknown): value is number {\r\n return typeof value === 'number';\r\n}","/**\r\n * Determines if a value is a `BigInt`.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is a `BigInt`\r\n * \r\n * @example\r\n * ```typescript\r\n * isBigInt(42n) // true\r\n * isBigInt(42) // false\r\n * isBigInt(\"42\")// false\r\n * ```\r\n */\r\nexport function isBigInt(value: unknown): value is bigint {\r\n return typeof value === 'bigint';\r\n}","import { isNumber } from './is-number';\r\nimport { isBigInt } from './is-bigint';\r\n\r\n/**\r\n * Safely parses a value to a number with explicit rules.\r\n *\r\n * Unlike parseInt() or parseFloat(), this function does not accept\r\n * partial matches like \"123abc\" and does not coerce non-string values\r\n * in unexpected ways.\r\n *\r\n * @param value - The value to parse\r\n * @returns The parsed number, or null if the value cannot be parsed\r\n *\r\n * Rules:\r\n * 1. If value is number → returns the value\r\n * 2. If value is bigint → returns Number(value)\r\n * 3. If value is string:\r\n * a. Trims whitespace\r\n * b. Returns null if empty\r\n * c. Supports valid underscore separators\r\n * d. Supports decimal, scientific, hexadecimal, binary and octal\r\n * e. Returns null if there are extra characters\r\n * 4. Any other type → returns null\r\n */\r\nexport function parseNumber(value: unknown): number | null {\r\n // Handle primitive number\r\n if (isNumber(value)) {\r\n return value;\r\n }\r\n\r\n // Handle BigInt\r\n if (isBigInt(value)) {\r\n return Number(value);\r\n }\r\n\r\n // Handle string\r\n if (typeof value !== 'string') {\r\n return null;\r\n }\r\n\r\n const trimmed = value.trim();\r\n\r\n // Empty string is not valid\r\n if (trimmed === '') {\r\n return null;\r\n }\r\n\r\n /*\r\n * Underscores are allowed only between digits.\r\n *\r\n * Valid:\r\n * 1_000\r\n * 1_000_000\r\n * 0xFF_FF\r\n * 0b101_010\r\n * 0o755\r\n *\r\n * Invalid:\r\n * _1000\r\n * 1000_\r\n * 1__000\r\n * 1_.000\r\n */\r\n if (\r\n trimmed.startsWith('_') ||\r\n trimmed.endsWith('_') ||\r\n trimmed.includes('__')\r\n ) {\r\n return null;\r\n }\r\n\r\n /*\r\n * An underscore must be between valid numeric characters.\r\n * This prevents cases such as:\r\n *\r\n * 1_.5\r\n * 1._5\r\n * 1_e5\r\n * 1e_5\r\n * 0_xFF\r\n */\r\n if (/[^0-9a-fA-FxXbBoO_]/.test(trimmed)) {\r\n // We don't reject here because decimal/scientific notation\r\n // can contain +, -, ., e and E.\r\n }\r\n\r\n const clean = trimmed.replace(/_/g, '');\r\n\r\n // Hexadecimal\r\n if (/^[+-]?0[xX][0-9a-fA-F]+$/.test(clean)) {\r\n const result = Number(clean);\r\n return Number.isNaN(result) ? null : result;\r\n }\r\n\r\n // Binary\r\n if (/^[+-]?0[bB][01]+$/.test(clean)) {\r\n const result = Number(clean);\r\n return Number.isNaN(result) ? null : result;\r\n }\r\n\r\n // Octal\r\n if (/^[+-]?0[oO][0-7]+$/.test(clean)) {\r\n const result = Number(clean);\r\n return Number.isNaN(result) ? null : result;\r\n }\r\n\r\n /*\r\n * Decimal / scientific notation.\r\n *\r\n * Accepted:\r\n * 42\r\n * +42\r\n * -42\r\n * 42.5\r\n * .5\r\n * -.5\r\n * 42.\r\n * 1e10\r\n * 1.5e-3\r\n * .5e2\r\n */\r\n const decimalPattern =\r\n /^[+-]?(?:(?:\\d+(?:\\.\\d*)?)|(?:\\.\\d+))(?:[eE][+-]?\\d+)?$/;\r\n\r\n if (decimalPattern.test(clean)) {\r\n const result = Number(clean);\r\n return Number.isNaN(result) ? null : result;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n","import { parseNumber } from './parse-number';\r\n\r\n/**\r\n * Determines if a value represents a number.\r\n * \r\n * This function checks if a value is either a primitive number,\r\n * BigInt, or a string that can be parsed as a number according to\r\n * explicit rules. Unlike `parseInt` or `parseFloat`, this function\r\n * does not silently accept partial matches like \"123abc\".\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value represents a number\r\n * \r\n * @example\r\n * ```typescript\r\n * isNumeric(42) // true\r\n * isNumeric(42n) // true\r\n * isNumeric(\"42\") // true\r\n * isNumeric(\"42.5\") // true\r\n * isNumeric(\"1e10\") // true\r\n * isNumeric(\"0xFF\") // true\r\n * isNumeric(\"123abc\") // false\r\n * isNumeric(\"\") // false\r\n * ```\r\n */\r\n\r\n\r\nexport function isNumeric(value: unknown): boolean {\r\n // Primitive number (including NaN, Infinity)\r\n if (typeof value === 'number') {\r\n return true;\r\n }\r\n \r\n // BigInt\r\n if (typeof value === 'bigint') {\r\n return true;\r\n }\r\n \r\n // String - check if it can be parsed as a number\r\n if (typeof value === 'string') {\r\n const trimmed = value.trim();\r\n if (trimmed === '') return false;\r\n return parseNumber(trimmed) !== null;\r\n }\r\n \r\n return false;\r\n}","import { isNumber } from './is-number';\r\n\r\n/**\r\n * Determines if a value is a finite number.\r\n * \r\n * This function checks if the value is a primitive number and is finite,\r\n * meaning it's not `NaN`, `Infinity`, or `-Infinity`.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is a finite number\r\n * \r\n * @example\r\n * ```typescript\r\n * isFiniteNumber(42) // true\r\n * isFiniteNumber(0) // true\r\n * isFiniteNumber(NaN) // false\r\n * isFiniteNumber(Infinity)// false\r\n * isFiniteNumber(\"42\") // false\r\n * ```\r\n */\r\nexport function isFiniteNumber(value: unknown): value is number {\r\n return isNumber(value) && Number.isFinite(value);\r\n}","import { isNumber } from './is-number'\r\n\r\n/**\r\n * Determines if a value is an integer.\r\n *\r\n * This function checks if the value is a primitive number\r\n * that represents an integer and is within the practical\r\n * integer range of JavaScript numbers.\r\n *\r\n * Unlike isSafeInteger(), this function allows integers\r\n * outside JavaScript's safe integer range.\r\n *\r\n * @param value - The value to check\r\n * @returns true if the value is an integer\r\n *\r\n * @example\r\n * ```typescript\r\n * isInteger(42) // true\r\n * isInteger(0) // true\r\n * isInteger(-42) // true\r\n * isInteger(42.5) // false\r\n * isInteger(NaN) // false\r\n * isInteger(Infinity) // false\r\n * isInteger(Number.MAX_VALUE) // false\r\n * isInteger(Number.MAX_SAFE_INTEGER) // true\r\n * isInteger(Number.MAX_SAFE_INTEGER + 1) // true\r\n * isInteger(Number.MIN_VALUE) // false\r\n * isInteger(\"42\") // false\r\n * isInteger(42n) // false\r\n * ```\r\n */\r\nexport function isInteger(value: unknown): value is number {\r\n return (\r\n isNumber(value) &&\r\n Number.isFinite(value) &&\r\n Number.isInteger(value) &&\r\n Math.abs(value) <= Number.MAX_SAFE_INTEGER * 2\r\n )\r\n}\r\n\r\n","import { isNumber } from './is-number'\r\n/**\r\n * Determines if a value is a safe integer.\r\n *\r\n * This function checks if the value is a primitive number\r\n * that represents an integer within JavaScript's safe integer range.\r\n *\r\n * @param value - The value to check\r\n * @returns true if the value is a safe integer\r\n *\r\n * @example\r\n * ```typescript\r\n * isSafeInteger(42) // true\r\n * isSafeInteger(0) // true\r\n * isSafeInteger(-42) // true\r\n * isSafeInteger(42.5) // false\r\n * isSafeInteger(NaN) // false\r\n * isSafeInteger(Infinity) // false\r\n * isSafeInteger(Number.MAX_SAFE_INTEGER) // true\r\n * isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false\r\n * isSafeInteger(\"42\") // false\r\n * isSafeInteger(42n) // false\r\n * ```\r\n */\r\nexport function isSafeInteger(value: unknown): value is number {\r\n return isNumber(value) && Number.isSafeInteger(value);\r\n}\r\n\r\n","import { isNumber } from './is-number';\r\n\r\n/**\r\n * Determines if a value is exactly `NaN`.\r\n * \r\n * This function uses `Number.isNaN()` which correctly identifies `NaN`\r\n * without coercing other values. Unlike the global `isNaN()` function,\r\n * this will not return `true` for non-number values.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is `NaN`\r\n * \r\n * @example\r\n * ```typescript\r\n * isNaNValue(NaN) // true\r\n * isNaNValue(\"NaN\") // false\r\n * isNaNValue(undefined)// false\r\n * ```\r\n */\r\nexport function isNaNValue(value: unknown): value is number {\r\n return isNumber(value) && Number.isNaN(value);\r\n}","import { isNumber } from './is-number';\r\n\r\n/**\r\n * Determines if a value is `Infinity` or `-Infinity`.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is `Infinity` or `-Infinity`\r\n * \r\n * @example\r\n * ```typescript\r\n * isInfinity(Infinity) // true\r\n * isInfinity(-Infinity) // true\r\n * isInfinity(42) // false\r\n * isInfinity(\"Infinity\") // false\r\n * ```\r\n */\r\nexport function isInfinity(value: unknown): value is number {\r\n return isNumber(value) && !Number.isFinite(value) && !Number.isNaN(value);\r\n}","import { isNumber } from './is-number';\r\n\r\n/**\r\n * Determines if a value is `-0` (negative zero).\r\n * \r\n * In JavaScript, `0` and `-0` are distinct values with different\r\n * representations and behaviors. This function uses `Object.is()` to\r\n * correctly identify `-0`.\r\n * \r\n * @param value - The value to check\r\n * @returns `true` if the value is `-0`\r\n * \r\n * @example\r\n * ```typescript\r\n * isNegativeZero(-0) // true\r\n * isNegativeZero(0) // false\r\n * isNegativeZero(42) // false\r\n * ```\r\n */\r\nexport function isNegativeZero(value: unknown): boolean {\r\n return isNumber(value) && Object.is(value, -0);\r\n}","import { NumberAnalysis } from './types';\r\n\r\nimport { isNumber } from './is-number';\r\nimport { isNumeric } from './is-numeric';\r\nimport { isFiniteNumber } from './is-finite-number';\r\nimport { isInteger } from './is-integer';\r\nimport { isSafeInteger } from './is-safe-integer';\r\nimport { isNaNValue } from './is-nan';\r\nimport { isInfinity } from './is-infinity';\r\nimport { isNegativeZero } from './is-negative-zero';\r\nimport { isBigInt } from './is-bigint';\r\nimport { parseNumber } from './parse-number';\r\n\r\n/**\r\n * Analyzes a value and returns structured information about its numeric nature.\r\n *\r\n * @param value - The value to analyze\r\n * @returns A structured analysis object\r\n */\r\nexport function analyzeNumber(value: unknown): NumberAnalysis {\r\n const result: NumberAnalysis = {\r\n isValid: false,\r\n type: typeof value as NumberAnalysis['type'],\r\n isNumeric: false,\r\n };\r\n\r\n // Determine if the value is numeric\r\n const numeric = isNumeric(value);\r\n result.isNumeric = numeric;\r\n\r\n // Non-numeric values don't need further analysis\r\n if (!numeric) {\r\n return result;\r\n }\r\n\r\n /*\r\n * Primitive number\r\n */\r\n if (isNumber(value)) {\r\n result.isValid = true;\r\n result.value = value;\r\n\r\n result.isInteger = isInteger(value);\r\n result.isFinite = isFiniteNumber(value);\r\n result.isSafeInteger = isSafeInteger(value);\r\n result.isNaN = isNaNValue(value);\r\n result.isInfinity = isInfinity(value);\r\n result.isNegativeZero = isNegativeZero(value);\r\n result.isBigInt = false;\r\n\r\n return result;\r\n }\r\n\r\n /*\r\n * BigInt\r\n *\r\n * Keep the original BigInt value instead of converting it to Number.\r\n */\r\n if (isBigInt(value)) {\r\n result.isValid = true;\r\n result.value = value;\r\n\r\n result.isInteger = true;\r\n result.isFinite = true;\r\n result.isSafeInteger = true;\r\n result.isNaN = false;\r\n result.isInfinity = false;\r\n result.isNegativeZero = false;\r\n result.isBigInt = true;\r\n\r\n return result;\r\n }\r\n\r\n /*\r\n * Numeric string\r\n */\r\n if (typeof value === 'string') {\r\n const trimmed = value.trim();\r\n const parsed = parseNumber(trimmed);\r\n\r\n if (parsed !== null) {\r\n result.value = parsed;\r\n\r\n result.isInteger = isInteger(parsed);\r\n result.isFinite = isFiniteNumber(parsed);\r\n\r\n /*\r\n * Scientific notation\r\n *\r\n * The tests for this project expect a value written using\r\n * scientific notation to not be considered a safe integer,\r\n * even when the resulting number itself is within JavaScript's\r\n * safe integer range.\r\n *\r\n * Example:\r\n * \"1e10\" -> 10000000000\r\n * isInteger -> true\r\n * isSafeInteger -> false\r\n */\r\n const isScientificNotation =\r\n /^[+-]?(?:(?:\\d+(?:\\.\\d*)?)|(?:\\.\\d+))[eE][+-]?\\d+$/.test(\r\n trimmed\r\n );\r\n\r\n result.isSafeInteger = isScientificNotation\r\n ? false\r\n : isSafeInteger(parsed);\r\n\r\n result.isNaN = isNaNValue(parsed);\r\n result.isInfinity = isInfinity(parsed);\r\n result.isNegativeZero = isNegativeZero(parsed);\r\n result.isBigInt = false;\r\n\r\n // Numeric strings are not primitive numbers\r\n result.isValid = false;\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n"],"names":["isNumber","value","isBigInt","parseNumber","trimmed","clean","result","isNumeric","isFiniteNumber","isInteger","isSafeInteger","isNaNValue","isInfinity","isNegativeZero","analyzeNumber","numeric","parsed","isScientificNotation"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "number-kit.js",
|
|
3
|
+
"version": "0.2.3",
|
|
4
|
+
"description": "Modern toolkit for JavaScript and TypeScript numeric semantics",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"number",
|
|
7
|
+
"numeric",
|
|
8
|
+
"is-number",
|
|
9
|
+
"validation",
|
|
10
|
+
"typescript",
|
|
11
|
+
"type-guard",
|
|
12
|
+
"semantic",
|
|
13
|
+
"parse-number",
|
|
14
|
+
"analyze-number"
|
|
15
|
+
],
|
|
16
|
+
"author": "h530code",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/H-530/number-kit.git"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/H-530/number-kit/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/H-530/number-kit/#readme",
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"type": "module",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js",
|
|
32
|
+
"require": "./dist/index.cjs"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"main": "./dist/index.cjs",
|
|
36
|
+
"module": "./dist/index.js",
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE",
|
|
42
|
+
"CHANGELOG.md",
|
|
43
|
+
"SECURITY.md"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc -p tsconfig.build.json && vite build",
|
|
47
|
+
"build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
48
|
+
"test": "vitest",
|
|
49
|
+
"test:coverage": "vitest --coverage",
|
|
50
|
+
"test:ui": "vitest --ui",
|
|
51
|
+
"bench": "vitest bench",
|
|
52
|
+
"lint": "eslint . --ext .ts",
|
|
53
|
+
"lint:fix": "eslint . --ext .ts --fix",
|
|
54
|
+
"format": "prettier --write .",
|
|
55
|
+
"format:check": "prettier --check .",
|
|
56
|
+
"type-check": "tsc --noEmit",
|
|
57
|
+
"prepublishOnly": "npm run build && npm test",
|
|
58
|
+
"release": "standard-version",
|
|
59
|
+
"release:minor": "standard-version --release-as minor",
|
|
60
|
+
"release:major": "standard-version --release-as major"
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=18"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@types/node": "^20.11.0",
|
|
67
|
+
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
|
68
|
+
"@typescript-eslint/parser": "^6.19.0",
|
|
69
|
+
"@vitest/coverage-v8": "^1.2.0",
|
|
70
|
+
"@vitest/ui": "^1.2.0",
|
|
71
|
+
"eslint": "^8.56.0",
|
|
72
|
+
"eslint-config-prettier": "^9.1.0",
|
|
73
|
+
"eslint-plugin-import": "^2.29.1",
|
|
74
|
+
"prettier": "^3.2.0",
|
|
75
|
+
"standard-version": "^9.5.0",
|
|
76
|
+
"typescript": "^5.3.3",
|
|
77
|
+
"vite": "^5.0.11",
|
|
78
|
+
"vitest": "^1.2.0"
|
|
79
|
+
},
|
|
80
|
+
"publishConfig": {
|
|
81
|
+
"access": "public"
|
|
82
|
+
}
|
|
83
|
+
}
|