typanic 1.0.1 → 1.0.2

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/README.md CHANGED
@@ -41,6 +41,7 @@ Every helper takes the value and an optional `label` used in the error message
41
41
  | --- | --- | --- |
42
42
  | `forcedString(value, label?)` | `string` | throws unless `typeof value === "string"` |
43
43
  | `forcedInteger(value, label?)` | `number` | accepts integers and integer-looking strings (`"42"`) |
44
+ | `forcedIntegerFromString(value, label?)` | `number` | accepts safe decimal integer strings only; useful for form/query values |
44
45
  | `forcedFloat(value, label?)` | `number` | accepts finite numbers and numeric strings; rejects `NaN`/`Infinity` |
45
46
  | `forcedBoolean(value, label?)` | `boolean` | does **not** coerce `"true"`/`1` — pass a real boolean |
46
47
 
@@ -50,6 +51,7 @@ Every helper takes the value and an optional `label` used in the error message
50
51
  | --- | --- |
51
52
  | `optionalString(value, label?)` | `string \| null` |
52
53
  | `optionalInteger(value, label?)` | `number \| null` |
54
+ | `optionalIntegerFromString(value, label?)` | `number \| null` |
53
55
  | `optionalFloat(value, label?)` | `number \| null` |
54
56
  | `optionalBoolean(value, label?)` | `boolean \| null` |
55
57
 
@@ -58,11 +60,11 @@ Every helper takes the value and an optional `label` used in the error message
58
60
  different things.
59
61
 
60
62
  ```js
61
- import {forcedInteger, optionalString} from "typanic"
63
+ import {forcedIntegerFromString, optionalString} from "typanic"
62
64
 
63
- const cols = forcedInteger(payload.cols, "cols") // number, or throws
64
- const cursor = optionalString(payload.cursor, "cursor") // string | null
65
- const status = optionalString(payload.status, "status") ?? "ok" // default only when you truly need one
65
+ const cols = forcedIntegerFromString(payload.cols, "cols") // decimal string -> number, or throws
66
+ const cursor = optionalString(payload.cursor, "cursor") // string | null
67
+ const status = optionalString(payload.status, "status") ?? "ok" // default only when you truly need one
66
68
  ```
67
69
 
68
70
  ## Why "forced"?
package/build/index.d.ts CHANGED
@@ -35,6 +35,24 @@ export function forcedInteger(value: unknown, label?: string): number;
35
35
  * @returns {number | null} the integer value, or null when absent
36
36
  */
37
37
  export function optionalInteger(value: unknown, label?: string): number | null;
38
+ /**
39
+ * Returns a decimal integer parsed from a string, otherwise throws. Use this
40
+ * for form, route, or query values that must be strings before parsing.
41
+ *
42
+ * @param {unknown} value the value to assert
43
+ * @param {string} [label] name used in the thrown error message
44
+ * @returns {number} the value, parsed as a decimal integer
45
+ */
46
+ export function forcedIntegerFromString(value: unknown, label?: string): number;
47
+ /**
48
+ * Like {@link forcedIntegerFromString}, but allows the value to be absent
49
+ * (null/undefined become null). A present invalid value still throws.
50
+ *
51
+ * @param {unknown} value the value to assert
52
+ * @param {string} [label] name used in the thrown error message
53
+ * @returns {number | null} the parsed integer value, or null when absent
54
+ */
55
+ export function optionalIntegerFromString(value: unknown, label?: string): number | null;
38
56
  /**
39
57
  * Returns the value as a finite number, otherwise throws. Numeric strings are
40
58
  * parsed; everything else (including NaN and Infinity) throws.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAgBA;;;;;;;;GAQG;AACH,oCAJW,OAAO,UACP,MAAM,GACJ,MAAM,CAQlB;AAED;;;;;;;GAOG;AACH,sCAJW,OAAO,UACP,MAAM,GACJ,MAAM,GAAG,IAAI,CAMzB;AAED;;;;;;;GAOG;AACH,qCAJW,OAAO,UACP,MAAM,GACJ,MAAM,CAYlB;AAED;;;;;;;GAOG;AACH,uCAJW,OAAO,UACP,MAAM,GACJ,MAAM,GAAG,IAAI,CAMzB;AAED;;;;;;;GAOG;AACH,mCAJW,OAAO,UACP,MAAM,GACJ,MAAM,CAYlB;AAED;;;;;;;GAOG;AACH,qCAJW,OAAO,UACP,MAAM,GACJ,MAAM,GAAG,IAAI,CAMzB;AAED;;;;;;;GAOG;AACH,qCAJW,OAAO,UACP,MAAM,GACJ,OAAO,CAQnB;AAED;;;;;;;GAOG;AACH,uCAJW,OAAO,UACP,MAAM,GACJ,OAAO,GAAG,IAAI,CAM1B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAgBA;;;;;;;;GAQG;AACH,oCAJW,OAAO,UACP,MAAM,GACJ,MAAM,CAQlB;AAED;;;;;;;GAOG;AACH,sCAJW,OAAO,UACP,MAAM,GACJ,MAAM,GAAG,IAAI,CAMzB;AAED;;;;;;;GAOG;AACH,qCAJW,OAAO,UACP,MAAM,GACJ,MAAM,CAYlB;AAED;;;;;;;GAOG;AACH,uCAJW,OAAO,UACP,MAAM,GACJ,MAAM,GAAG,IAAI,CAMzB;AAED;;;;;;;GAOG;AACH,+CAJW,OAAO,UACP,MAAM,GACJ,MAAM,CAclB;AAED;;;;;;;GAOG;AACH,iDAJW,OAAO,UACP,MAAM,GACJ,MAAM,GAAG,IAAI,CAMzB;AAED;;;;;;;GAOG;AACH,mCAJW,OAAO,UACP,MAAM,GACJ,MAAM,CAYlB;AAED;;;;;;;GAOG;AACH,qCAJW,OAAO,UACP,MAAM,GACJ,MAAM,GAAG,IAAI,CAMzB;AAED;;;;;;;GAOG;AACH,qCAJW,OAAO,UACP,MAAM,GACJ,OAAO,CAQnB;AAED;;;;;;;GAOG;AACH,uCAJW,OAAO,UACP,MAAM,GACJ,OAAO,GAAG,IAAI,CAM1B"}
package/build/index.js CHANGED
@@ -72,6 +72,38 @@ export function optionalInteger(value, label = "value") {
72
72
  return null;
73
73
  return forcedInteger(value, label);
74
74
  }
75
+ /**
76
+ * Returns a decimal integer parsed from a string, otherwise throws. Use this
77
+ * for form, route, or query values that must be strings before parsing.
78
+ *
79
+ * @param {unknown} value the value to assert
80
+ * @param {string} [label] name used in the thrown error message
81
+ * @returns {number} the value, parsed as a decimal integer
82
+ */
83
+ export function forcedIntegerFromString(value, label = "value") {
84
+ if (typeof value === "string") {
85
+ const trimmedValue = value.trim();
86
+ if (/^-?\d+$/.test(trimmedValue)) {
87
+ const parsedValue = Number.parseInt(trimmedValue, 10);
88
+ if (Number.isSafeInteger(parsedValue))
89
+ return parsedValue;
90
+ }
91
+ }
92
+ throw new TypeError(`Expected ${label} to be an integer string but got ${describeType(value)}`);
93
+ }
94
+ /**
95
+ * Like {@link forcedIntegerFromString}, but allows the value to be absent
96
+ * (null/undefined become null). A present invalid value still throws.
97
+ *
98
+ * @param {unknown} value the value to assert
99
+ * @param {string} [label] name used in the thrown error message
100
+ * @returns {number | null} the parsed integer value, or null when absent
101
+ */
102
+ export function optionalIntegerFromString(value, label = "value") {
103
+ if (value === null || value === undefined)
104
+ return null;
105
+ return forcedIntegerFromString(value, label);
106
+ }
75
107
  /**
76
108
  * Returns the value as a finite number, otherwise throws. Numeric strings are
77
109
  * parsed; everything else (including NaN and Infinity) throws.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typanic",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Forced runtime type assertions for untrusted input — get the type you expect or throw, instead of silently coercing a wrong value to \"\" / 0 / false.",
5
5
  "keywords": [
6
6
  "type",
@@ -46,13 +46,14 @@
46
46
  "LICENSE"
47
47
  ],
48
48
  "scripts": {
49
- "all-checks": "npm run lint && npm run typecheck && npm test",
49
+ "all-checks": "npm run lint && npm test",
50
50
  "build": "tsc --project tsconfig.json",
51
- "lint": "eslint .",
51
+ "lint": "npm run eslint && npm run typecheck",
52
52
  "prepare": "npm run build",
53
53
  "release:patch": "release-patch",
54
54
  "test": "jasmine",
55
- "typecheck": "tsc --project tsconfig.json --noEmit"
55
+ "typecheck": "tsc --project tsconfig.json --noEmit",
56
+ "eslint": "eslint ."
56
57
  },
57
58
  "devDependencies": {
58
59
  "@eslint/js": "^10.0.1",