@rightcapital/assert 0.0.0 → 2.1.3-feature-assertion-helpers-api-refinement.2357.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 RightCapital
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 CHANGED
@@ -1,3 +1,148 @@
1
1
  # @rightcapital/assert
2
2
 
3
- Placeholder release real implementation coming in a future version.
3
+ Type-safe assertion utilities for defensive programming in TypeScript applications.
4
+
5
+ ## Key Features
6
+
7
+ - **Compile-Time Exhaustiveness (`assertExhaustive`)**: Enforce full coverage of union types at compile time with TypeScript `never`.
8
+ - **Control-Flow Guard (`assertUnreachable`)**: Mark unreachable branches for control-flow analysis and runtime safety.
9
+ - **Expression-Level Assertions (`ensure` / `ensureNonNullable`)**: Assert and return narrowed values in single-line expressions.
10
+ - **Type Narrowing (`assert` / `assertNonNullable`)**: Narrow types with standard TypeScript assertion signatures.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @rightcapital/assert
16
+ # or
17
+ pnpm add @rightcapital/assert
18
+ # or
19
+ yarn add @rightcapital/assert
20
+ ```
21
+
22
+ ## Usage Examples
23
+
24
+ ### Compile-Time Exhaustiveness Checking (`assertExhaustive`)
25
+
26
+ Use `assertExhaustive` in `switch` statements or `if-else` chains. It leverages TypeScript `never` to catch missing cases at compile time.
27
+
28
+ ```typescript
29
+ import { assertExhaustive } from '@rightcapital/assert';
30
+
31
+ type Action = { type: 'open' } | { type: 'close' };
32
+
33
+ function handleAction(action: Action) {
34
+ switch (action.type) {
35
+ case 'open':
36
+ return 'Opening';
37
+ case 'close':
38
+ return 'Closing';
39
+ default:
40
+ // If a new Action type is added without a case,
41
+ // TypeScript reports a compile error here.
42
+ return assertExhaustive(action);
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### Control Flow & Unreachable Code Guard (`assertUnreachable`)
48
+
49
+ Use `assertUnreachable` for code branches that should never execute. Because `assertUnreachable` returns `never`, TypeScript understands control flow stops at this point.
50
+
51
+ ```typescript
52
+ import { assertUnreachable } from '@rightcapital/assert';
53
+
54
+ function processStatus(status: 'active' | 'inactive') {
55
+ if (status === 'active') {
56
+ handleActive();
57
+ } else if (status === 'inactive') {
58
+ handleInactive();
59
+ } else {
60
+ // TypeScript knows execution stops here because `assertUnreachable` returns `never`.
61
+ assertUnreachable(`Unexpected status: ${status}`);
62
+ }
63
+ }
64
+ ```
65
+
66
+ > **Tip**: If your project enforces the ESLint `consistent-return` rule, add `return` before the function call (for example, `return assertUnreachable(...)`) to satisfy ESLint.
67
+
68
+ ### Expression-Level Type Narrowing (`ensure` & `ensureNonNullable`)
69
+
70
+ Unlike `assert`, `ensure` and `ensureNonNullable` validate a value and return it with a narrowed type. This allows assertions inside single-line expressions or method chains.
71
+
72
+ ```typescript
73
+ import { ensure, ensureNonNullable } from '@rightcapital/assert';
74
+
75
+ // Assert and get a non-nullable value in one expression
76
+ const userName = ensureNonNullable(getUser(), 'User must exist').name;
77
+
78
+ // Assert with a custom type guard
79
+ const admin = ensure(currentUser, isAdminUser, 'Admin privileges required');
80
+ // `admin` is typed as AdminUser
81
+ ```
82
+
83
+ ### Basic Assertion & Type Narrowing (`assert` & `assertNonNullable`)
84
+
85
+ Use `assert` and `assertNonNullable` for standalone statement assertions.
86
+
87
+ ```typescript
88
+ import { assert, assertNonNullable } from '@rightcapital/assert';
89
+
90
+ // Basic condition assertion
91
+ assert(user.age >= 18, 'User must be at least 18 years old');
92
+
93
+ // Non-nullable assertion with type narrowing
94
+ assertNonNullable(user, 'User cannot be null');
95
+ // `user` is narrowed to NonNullable<User>
96
+ ```
97
+
98
+ ### Error Handling (`AssertError`)
99
+
100
+ All assertion functions throw `AssertError` (which extends `Error`) when an assertion fails.
101
+
102
+ ```typescript
103
+ import { assert, AssertError } from '@rightcapital/assert';
104
+
105
+ try {
106
+ assert(user.age >= 18, 'User must be at least 18 years old');
107
+ } catch (error) {
108
+ if (error instanceof AssertError) {
109
+ console.error('Assertion failed:', error.message);
110
+ }
111
+ }
112
+ ```
113
+
114
+ ## API Summary
115
+
116
+ | API | Return / Type Behavior | Typical Use Case |
117
+ | :------------------------------- | :-------------------------------- | :---------------------------------------------------- |
118
+ | `AssertError` | `class extends Error` | Error thrown on assertion failure |
119
+ | `assertExhaustive(value, msg?)` | `never` | Enforce exhaustiveness check in `switch` or `if-else` |
120
+ | `assertUnreachable(msg?)` | `never` | Mark logically unreachable code branches |
121
+ | `ensure(value, predicate, msg?)` | `S extends T` | Validate and return value with narrowed type |
122
+ | `ensureNonNullable(value, msg?)` | `NonNullable<T>` | Validate non-null/undefined and return value |
123
+ | `assert(value, msg?)` | `asserts value` | Standard boolean condition assertion |
124
+ | `assertNonNullable(value, msg?)` | `asserts value is NonNullable<T>` | Standard non-null/undefined assertion |
125
+
126
+ ## Agent Skills
127
+
128
+ This package ships with an [Agent Skill](https://agentskills.io) that teaches AI coding agents (Claude Code, Cursor, etc.) how to use the assert API correctly, following the [npm-based Agent Skills Convention](https://github.com/antfu/skills-npm).
129
+
130
+ ### Automatic discovery (recommended)
131
+
132
+ If your project uses [`skills-npm`](https://github.com/antfu/skills-npm), the skill is discovered automatically from `node_modules`:
133
+
134
+ ```bash
135
+ npx skills-npm
136
+ ```
137
+
138
+ ### Manual installation
139
+
140
+ You can also install the skill directly using the [`skills` CLI](https://github.com/vercel-labs/skills):
141
+
142
+ ```bash
143
+ npx skills add https://github.com/RightCapitalHQ/frontend-libraries/tree/main/packages/assert/skills
144
+ ```
145
+
146
+ ## API Reference
147
+
148
+ See the [generated documentation](./docs/README.md) for detailed API reference.
package/lib/index.d.ts ADDED
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Assertion functions provide type-safe assertions and validation.
3
+ * When assertions fail, they throw `AssertError`.
4
+ *
5
+ * @author lixiaoyan <lxy.lixiaoyan@gmail.com>
6
+ * @example
7
+ * ```typescript
8
+ * // Basic assertion
9
+ * assert(user.age >= 18, 'User must be at least 18 years old');
10
+ *
11
+ * // Non-nullable assertion with type narrowing
12
+ * assertNonNullable(user, 'User cannot be null');
13
+ * // user is now typed as NonNullable<T>
14
+ *
15
+ * // Ensure with type guard
16
+ * const admin = ensure(currentUser, isAdminUser, 'Admin required');
17
+ * // admin is now typed as AdminUser
18
+ * ```
19
+ */
20
+ /**
21
+ * Error thrown when an assertion fails.
22
+ */
23
+ export declare class AssertError extends Error {
24
+ readonly name = "AssertError";
25
+ }
26
+ /**
27
+ * Basic assertion: verifies that a value or expression is `true`, otherwise throws an exception.
28
+ *
29
+ * @param value - The value to assert as truthy
30
+ * @param message - Optional custom error message
31
+ * @throws {AssertError} Throws an error if `value` is not `true`.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * // Basic usage
36
+ * assert(user.age >= 18, 'User must be at least 18 years old');
37
+ *
38
+ * // Condition validation
39
+ * const isValid = validateData(data);
40
+ * assert(isValid, 'Data validation failed');
41
+ * ```
42
+ */
43
+ export declare function assert(value: unknown, message?: string): asserts value;
44
+ /**
45
+ * Asserts that a value is not `null` or `undefined`, providing TypeScript type narrowing to `NonNullable<T>`.
46
+ * Ensures subsequent code can safely access the value.
47
+ *
48
+ * @param value - The value to check for null/undefined
49
+ * @param message - Optional custom error message
50
+ * @throws {AssertError} Throws an error if `value` is `null` or `undefined`.
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * function processUser(user: User | null | undefined) {
55
+ * assertNonNullable(user, 'User cannot be null');
56
+ * // user is now typed as User
57
+ * console.log(user.name); // Safe to access
58
+ * }
59
+ * ```
60
+ */
61
+ export declare function assertNonNullable<T>(value: T, message?: string): asserts value is NonNullable<T>;
62
+ /**
63
+ * Similar to `assert`, but returns the value. Ensures a value matches a type predicate and returns it with narrowed type.
64
+ *
65
+ * @param value - The value to validate
66
+ * @param predicate - Type guard function that validates the value
67
+ * @param message - Optional custom error message
68
+ * @returns The value with narrowed type
69
+ * @throws {AssertError} Throws an error if `predicate` returns `false`.
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * // Define type guard
74
+ * function isAdminUser(user: User): user is AdminUser {
75
+ * return user.role === 'admin';
76
+ * }
77
+ *
78
+ * // Use ensure to get type-safe value
79
+ * const admin = ensure(
80
+ * currentUser,
81
+ * isAdminUser,
82
+ * 'Admin privileges required'
83
+ * );
84
+ * // admin is typed as AdminUser
85
+ * ```
86
+ */
87
+ export declare function ensure<T, S extends T>(value: T, predicate: (value: T) => value is S, message?: string): S;
88
+ /**
89
+ * Similar to `assertNonNullable`, but returns the value. Ensures a value is not null/undefined and returns it.
90
+ *
91
+ * @param value - The value to check for null/undefined
92
+ * @param message - Optional custom error message
93
+ * @returns The non-nullable value
94
+ * @throws {AssertError} Throws an error if `value` is `null` or `undefined`.
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * // Use in expressions
99
+ * const config = ensureNonNullable(
100
+ * getConfig(),
101
+ * 'Configuration not found'
102
+ * );
103
+ *
104
+ * // Chain calls
105
+ * const userName = ensureNonNullable(user, 'User not found').name;
106
+ * ```
107
+ */
108
+ export declare function ensureNonNullable<T>(value: T, message?: string): NonNullable<T>;
109
+ /**
110
+ * Marks code branches that should theoretically never be reached.
111
+ * Used for defensive programming to prevent unexpected code execution when data or logic doesn't match expectations.
112
+ *
113
+ * @param message - Optional custom error message
114
+ * @returns Never returns (always throws)
115
+ * @throws {AssertError} Always thrown.
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * function processStatus(status: 'active' | 'inactive' | 'activating') {
120
+ * if (status === 'active') {
121
+ * // Handle active state
122
+ * } else if (status === 'inactive') {
123
+ * // Handle inactive state
124
+ * } else {
125
+ * // According to business logic, this should never be reached
126
+ * assertUnreachable(`Unexpected status value: ${status}`);
127
+ * }
128
+ * }
129
+ * ```
130
+ */
131
+ export declare function assertUnreachable(message?: string): never;
132
+ /**
133
+ * Used for exhaustiveness checking of union types. Ensures switch or if-else statements cover all possible types.
134
+ * Leverages TypeScript's `never` type to catch missing branches at compile time.
135
+ *
136
+ * @param value - The value that should be `never` if all cases are handled
137
+ * @param message - Optional custom error message
138
+ * @returns Never returns (always throws)
139
+ * @throws {AssertError} Always thrown.
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * type Action =
144
+ * | { type: 'ADD'; payload: number }
145
+ * | { type: 'SUBTRACT'; payload: number }
146
+ * | { type: 'MULTIPLY'; payload: number };
147
+ *
148
+ * function reducer(action: Action) {
149
+ * switch (action.type) {
150
+ * case 'ADD':
151
+ * return state + action.payload;
152
+ * case 'SUBTRACT':
153
+ * return state - action.payload;
154
+ * case 'MULTIPLY':
155
+ * return state * action.payload;
156
+ * default:
157
+ * // If all types are exhausted, action is of type never
158
+ * // If new Action types are added but not handled, TypeScript will report error
159
+ * return assertExhaustive(action);
160
+ * // ^ never
161
+ * }
162
+ * }
163
+ * ```
164
+ */
165
+ export declare function assertExhaustive(value: never, message?: string): never;
166
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,SAAyB,IAAI,iBAAiB;CAC/C;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAItE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,KAAK,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,KAAK,IAAI,WAAW,CAAC,CAAC,CAAC,CAIjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,EACnC,KAAK,EAAE,CAAC,EACR,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,EACnC,OAAO,CAAC,EAAE,MAAM,GACf,CAAC,CAGH;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,KAAK,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,MAAM,GACf,WAAW,CAAC,CAAC,CAAC,CAKhB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAEzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAEtE"}
package/lib/index.js ADDED
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ /**
3
+ * Assertion functions provide type-safe assertions and validation.
4
+ * When assertions fail, they throw `AssertError`.
5
+ *
6
+ * @author lixiaoyan <lxy.lixiaoyan@gmail.com>
7
+ * @example
8
+ * ```typescript
9
+ * // Basic assertion
10
+ * assert(user.age >= 18, 'User must be at least 18 years old');
11
+ *
12
+ * // Non-nullable assertion with type narrowing
13
+ * assertNonNullable(user, 'User cannot be null');
14
+ * // user is now typed as NonNullable<T>
15
+ *
16
+ * // Ensure with type guard
17
+ * const admin = ensure(currentUser, isAdminUser, 'Admin required');
18
+ * // admin is now typed as AdminUser
19
+ * ```
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.assertExhaustive = exports.assertUnreachable = exports.ensureNonNullable = exports.ensure = exports.assertNonNullable = exports.assert = exports.AssertError = void 0;
23
+ /**
24
+ * Error thrown when an assertion fails.
25
+ */
26
+ class AssertError extends Error {
27
+ constructor() {
28
+ super(...arguments);
29
+ this.name = 'AssertError';
30
+ }
31
+ }
32
+ exports.AssertError = AssertError;
33
+ /**
34
+ * Throws an AssertError for failed assertions.
35
+ */
36
+ function throwError(name, value, message) {
37
+ throw new AssertError(message !== null && message !== void 0 ? message : `${name}: Unexpected ${String(value)}`);
38
+ }
39
+ /**
40
+ * Basic assertion: verifies that a value or expression is `true`, otherwise throws an exception.
41
+ *
42
+ * @param value - The value to assert as truthy
43
+ * @param message - Optional custom error message
44
+ * @throws {AssertError} Throws an error if `value` is not `true`.
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * // Basic usage
49
+ * assert(user.age >= 18, 'User must be at least 18 years old');
50
+ *
51
+ * // Condition validation
52
+ * const isValid = validateData(data);
53
+ * assert(isValid, 'Data validation failed');
54
+ * ```
55
+ */
56
+ function assert(value, message) {
57
+ if (value !== true) {
58
+ throwError('assert', value, message);
59
+ }
60
+ }
61
+ exports.assert = assert;
62
+ /**
63
+ * Asserts that a value is not `null` or `undefined`, providing TypeScript type narrowing to `NonNullable<T>`.
64
+ * Ensures subsequent code can safely access the value.
65
+ *
66
+ * @param value - The value to check for null/undefined
67
+ * @param message - Optional custom error message
68
+ * @throws {AssertError} Throws an error if `value` is `null` or `undefined`.
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * function processUser(user: User | null | undefined) {
73
+ * assertNonNullable(user, 'User cannot be null');
74
+ * // user is now typed as User
75
+ * console.log(user.name); // Safe to access
76
+ * }
77
+ * ```
78
+ */
79
+ function assertNonNullable(value, message) {
80
+ if (value === null || value === undefined) {
81
+ throwError('assertNonNullable', value, message);
82
+ }
83
+ }
84
+ exports.assertNonNullable = assertNonNullable;
85
+ /**
86
+ * Similar to `assert`, but returns the value. Ensures a value matches a type predicate and returns it with narrowed type.
87
+ *
88
+ * @param value - The value to validate
89
+ * @param predicate - Type guard function that validates the value
90
+ * @param message - Optional custom error message
91
+ * @returns The value with narrowed type
92
+ * @throws {AssertError} Throws an error if `predicate` returns `false`.
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * // Define type guard
97
+ * function isAdminUser(user: User): user is AdminUser {
98
+ * return user.role === 'admin';
99
+ * }
100
+ *
101
+ * // Use ensure to get type-safe value
102
+ * const admin = ensure(
103
+ * currentUser,
104
+ * isAdminUser,
105
+ * 'Admin privileges required'
106
+ * );
107
+ * // admin is typed as AdminUser
108
+ * ```
109
+ */
110
+ function ensure(value, predicate, message) {
111
+ assert(predicate(value), message);
112
+ return value;
113
+ }
114
+ exports.ensure = ensure;
115
+ /**
116
+ * Similar to `assertNonNullable`, but returns the value. Ensures a value is not null/undefined and returns it.
117
+ *
118
+ * @param value - The value to check for null/undefined
119
+ * @param message - Optional custom error message
120
+ * @returns The non-nullable value
121
+ * @throws {AssertError} Throws an error if `value` is `null` or `undefined`.
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * // Use in expressions
126
+ * const config = ensureNonNullable(
127
+ * getConfig(),
128
+ * 'Configuration not found'
129
+ * );
130
+ *
131
+ * // Chain calls
132
+ * const userName = ensureNonNullable(user, 'User not found').name;
133
+ * ```
134
+ */
135
+ function ensureNonNullable(value, message) {
136
+ if (value === null || value === undefined) {
137
+ throwError('ensureNonNullable', value, message);
138
+ }
139
+ return value;
140
+ }
141
+ exports.ensureNonNullable = ensureNonNullable;
142
+ /**
143
+ * Marks code branches that should theoretically never be reached.
144
+ * Used for defensive programming to prevent unexpected code execution when data or logic doesn't match expectations.
145
+ *
146
+ * @param message - Optional custom error message
147
+ * @returns Never returns (always throws)
148
+ * @throws {AssertError} Always thrown.
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * function processStatus(status: 'active' | 'inactive' | 'activating') {
153
+ * if (status === 'active') {
154
+ * // Handle active state
155
+ * } else if (status === 'inactive') {
156
+ * // Handle inactive state
157
+ * } else {
158
+ * // According to business logic, this should never be reached
159
+ * assertUnreachable(`Unexpected status value: ${status}`);
160
+ * }
161
+ * }
162
+ * ```
163
+ */
164
+ function assertUnreachable(message) {
165
+ throwError('assertUnreachable', null, message);
166
+ }
167
+ exports.assertUnreachable = assertUnreachable;
168
+ /**
169
+ * Used for exhaustiveness checking of union types. Ensures switch or if-else statements cover all possible types.
170
+ * Leverages TypeScript's `never` type to catch missing branches at compile time.
171
+ *
172
+ * @param value - The value that should be `never` if all cases are handled
173
+ * @param message - Optional custom error message
174
+ * @returns Never returns (always throws)
175
+ * @throws {AssertError} Always thrown.
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * type Action =
180
+ * | { type: 'ADD'; payload: number }
181
+ * | { type: 'SUBTRACT'; payload: number }
182
+ * | { type: 'MULTIPLY'; payload: number };
183
+ *
184
+ * function reducer(action: Action) {
185
+ * switch (action.type) {
186
+ * case 'ADD':
187
+ * return state + action.payload;
188
+ * case 'SUBTRACT':
189
+ * return state - action.payload;
190
+ * case 'MULTIPLY':
191
+ * return state * action.payload;
192
+ * default:
193
+ * // If all types are exhausted, action is of type never
194
+ * // If new Action types are added but not handled, TypeScript will report error
195
+ * return assertExhaustive(action);
196
+ * // ^ never
197
+ * }
198
+ * }
199
+ * ```
200
+ */
201
+ function assertExhaustive(value, message) {
202
+ throwError('assertExhaustive', value, message);
203
+ }
204
+ exports.assertExhaustive = assertExhaustive;
205
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;AAEH;;GAEG;AACH,MAAa,WAAY,SAAQ,KAAK;IAAtC;;QAC2B,SAAI,GAAG,aAAa,CAAC;IAChD,CAAC;CAAA;AAFD,kCAEC;AAED;;GAEG;AACH,SAAS,UAAU,CACjB,IAAY,EACZ,KAAc,EACd,OAA2B;IAE3B,MAAM,IAAI,WAAW,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,GAAG,IAAI,gBAAgB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,MAAM,CAAC,KAAc,EAAE,OAAgB;IACrD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAJD,wBAIC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,iBAAiB,CAC/B,KAAQ,EACR,OAAgB;IAEhB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,UAAU,CAAC,mBAAmB,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAPD,8CAOC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,SAAgB,MAAM,CACpB,KAAQ,EACR,SAAmC,EACnC,OAAgB;IAEhB,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC;AACf,CAAC;AAPD,wBAOC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAgB,iBAAiB,CAC/B,KAAQ,EACR,OAAgB;IAEhB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,UAAU,CAAC,mBAAmB,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AARD,8CAQC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAgB,iBAAiB,CAAC,OAAgB;IAChD,UAAU,CAAC,mBAAmB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC;AAFD,8CAEC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,SAAgB,gBAAgB,CAAC,KAAY,EAAE,OAAgB;IAC7D,UAAU,CAAC,kBAAkB,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC;AAFD,4CAEC"}
package/package.json CHANGED
@@ -1,14 +1,42 @@
1
1
  {
2
2
  "name": "@rightcapital/assert",
3
- "version": "0.0.0",
3
+ "version": "2.1.3-feature-assertion-helpers-api-refinement.2357.1.0",
4
+ "description": "Type-safe assertion utilities for defensive programming.",
5
+ "author": "RightCapital Ecosystem team <npm-publisher@rightcapital.com>",
6
+ "keywords": [
7
+ "assertion",
8
+ "type-safe",
9
+ "validation",
10
+ "defensive",
11
+ "TypeScript",
12
+ "tanstack-intent",
13
+ "utilities"
14
+ ],
15
+ "sideEffects": false,
4
16
  "license": "MIT",
17
+ "main": "lib/index.js",
18
+ "typings": "lib/index.d.ts",
5
19
  "repository": {
6
20
  "type": "git",
7
21
  "url": "git+https://github.com/RightCapitalHQ/frontend-libraries.git",
8
22
  "directory": "packages/assert"
9
23
  },
24
+ "directories": {
25
+ "lib": "lib"
26
+ },
27
+ "files": [
28
+ "lib",
29
+ "skills",
30
+ "src"
31
+ ],
10
32
  "publishConfig": {
11
- "registry": "https://registry.npmjs.org",
12
- "access": "public"
33
+ "registry": "https://registry.npmjs.org"
34
+ },
35
+ "devDependencies": {
36
+ "typedoc": "0.25.7",
37
+ "typedoc-plugin-markdown": "3.17.1"
38
+ },
39
+ "scripts": {
40
+ "docs": "pnpm exec typedoc --plugin typedoc-plugin-markdown --out docs src/index.ts"
13
41
  }
14
- }
42
+ }
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: assert
3
+ description: >-
4
+ Type-safe assertion and validation utilities for defensive TypeScript programming.
5
+ Use when writing runtime assertions, null checks, type guard validations, unreachable code markers, or exhaustive switch/if-else checking.
6
+ Import named functions from @rightcapital/assert.
7
+ license: MIT
8
+ metadata:
9
+ author: RightCapital
10
+ package: '@rightcapital/assert'
11
+ ---
12
+
13
+ # assert
14
+
15
+ Type-safe assertion utilities for defensive TypeScript programming. All functions throw `AssertError` (which extends `Error`) on failure. Default error message format is `${functionName}: Unexpected ${String(value)}`.
16
+
17
+ ## Import
18
+
19
+ ```typescript
20
+ import {
21
+ assert,
22
+ AssertError,
23
+ assertExhaustive,
24
+ assertNonNullable,
25
+ assertUnreachable,
26
+ ensure,
27
+ ensureNonNullable,
28
+ } from '@rightcapital/assert';
29
+ ```
30
+
31
+ ## Quick Reference
32
+
33
+ | Class / Function | Signature / Return | Use Case |
34
+ | -------------------------------- | --------------------------------- | ------------------------------------------------------------------- |
35
+ | `AssertError` | `class extends Error` | Error type thrown when any assertion in this package fails. |
36
+ | `assert(value, msg?)` | `asserts value` | Precondition or boolean check (verifies `value === true`). |
37
+ | `assertNonNullable(value, msg?)` | `asserts value is NonNullable<T>` | Guard statement against `null` or `undefined`. |
38
+ | `ensure(value, predicate, msg?)` | `S extends T` | Inline validation using type guard function `(val: T) => val is S`. |
39
+ | `ensureNonNullable(value, msg?)` | `NonNullable<T>` | Inline assignment or method chain for non-null value. |
40
+ | `assertExhaustive(value, msg?)` | `value: never` -> `never` | Exhaustiveness check in `switch` `default` case or `if-else` chain. |
41
+ | `assertUnreachable(msg?)` | `never` | Mark logically impossible code paths. |
42
+
43
+ ## Error Handling with `AssertError`
44
+
45
+ All assertion functions throw `AssertError` when a condition is not met. Use `instanceof AssertError` to catch assertion failures specifically:
46
+
47
+ ```typescript
48
+ import { assert, AssertError } from '@rightcapital/assert';
49
+
50
+ try {
51
+ assert(age >= 18, 'User must be an adult');
52
+ } catch (error) {
53
+ if (error instanceof AssertError) {
54
+ console.error('Assertion failed:', error.message);
55
+ } else {
56
+ throw error;
57
+ }
58
+ }
59
+ ```
60
+
61
+ ## Critical Rules for Code Generation
62
+
63
+ ### 1. `assert()` Checks Strict Boolean Equality (`value !== true`)
64
+
65
+ `assert(value)` throws if `value !== true`. It throws for truthy non-boolean values like objects or strings.
66
+
67
+ - **Incorrect**: `assert(user);` (throws even if `user` is an object)
68
+ - **Correct**: `assertNonNullable(user);`
69
+ - **Correct**: `assert(user.age >= 18, 'Must be 18+');`
70
+
71
+ ### 2. Choose `assert*` Statements vs `ensure*` Expressions
72
+
73
+ - **`assert*` functions** are statements. They narrow the type of an existing variable for subsequent code.
74
+ - **`ensure*` functions** are expressions. They return the validated value with a narrowed type for direct assignment or chaining.
75
+
76
+ ```typescript
77
+ // Statement form
78
+ assertNonNullable(user);
79
+ console.log(user.name);
80
+
81
+ // Expression form
82
+ const userName = ensureNonNullable(getUser()).name;
83
+ ```
84
+
85
+ ### 3. `ensure()` Requires a Type Guard Predicate
86
+
87
+ The `predicate` parameter in `ensure(val, predicate)` must be a TypeScript type guard (`(val: T) => val is S`). A standard boolean function without a type predicate will cause a compile error.
88
+
89
+ ```typescript
90
+ function isAdminUser(user: User): user is AdminUser {
91
+ return user.role === 'admin';
92
+ }
93
+
94
+ const admin = ensure(currentUser, isAdminUser, 'Admin required');
95
+ ```
96
+
97
+ ### 4. `assertExhaustive` vs `assertUnreachable`
98
+
99
+ - Use `assertExhaustive(value)` when TypeScript can prove all union cases are handled (e.g., `switch` default case). It catches missing union members at compile time because `value` must be typed as `never`.
100
+ - Use `assertUnreachable(message)` for defensive checks in branches that TypeScript cannot prove unreachable.
101
+ - Prefix with `return` in non-void functions (for example, `return assertExhaustive(val);` or `return assertUnreachable(msg);`) to satisfy ESLint `consistent-return`.
102
+
103
+ ```typescript
104
+ // Exhaustive switch over union
105
+ switch (shape.kind) {
106
+ case 'circle':
107
+ return Math.PI * shape.radius ** 2;
108
+ case 'square':
109
+ return shape.side ** 2;
110
+ default:
111
+ return assertExhaustive(shape);
112
+ }
113
+
114
+ // Unreachable defensive branch
115
+ if (status === 'active') {
116
+ handleActive();
117
+ } else if (status === 'inactive') {
118
+ handleInactive();
119
+ } else {
120
+ return assertUnreachable(`Unexpected status: ${status}`);
121
+ }
122
+ ```
package/src/index.ts ADDED
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Assertion functions provide type-safe assertions and validation.
3
+ * When assertions fail, they throw `AssertError`.
4
+ *
5
+ * @author lixiaoyan <lxy.lixiaoyan@gmail.com>
6
+ * @example
7
+ * ```typescript
8
+ * // Basic assertion
9
+ * assert(user.age >= 18, 'User must be at least 18 years old');
10
+ *
11
+ * // Non-nullable assertion with type narrowing
12
+ * assertNonNullable(user, 'User cannot be null');
13
+ * // user is now typed as NonNullable<T>
14
+ *
15
+ * // Ensure with type guard
16
+ * const admin = ensure(currentUser, isAdminUser, 'Admin required');
17
+ * // admin is now typed as AdminUser
18
+ * ```
19
+ */
20
+
21
+ /**
22
+ * Error thrown when an assertion fails.
23
+ */
24
+ export class AssertError extends Error {
25
+ public override readonly name = 'AssertError';
26
+ }
27
+
28
+ /**
29
+ * Throws an AssertError for failed assertions.
30
+ */
31
+ function throwError(
32
+ name: string,
33
+ value: unknown,
34
+ message: string | undefined,
35
+ ): never {
36
+ throw new AssertError(message ?? `${name}: Unexpected ${String(value)}`);
37
+ }
38
+
39
+ /**
40
+ * Basic assertion: verifies that a value or expression is `true`, otherwise throws an exception.
41
+ *
42
+ * @param value - The value to assert as truthy
43
+ * @param message - Optional custom error message
44
+ * @throws {AssertError} Throws an error if `value` is not `true`.
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * // Basic usage
49
+ * assert(user.age >= 18, 'User must be at least 18 years old');
50
+ *
51
+ * // Condition validation
52
+ * const isValid = validateData(data);
53
+ * assert(isValid, 'Data validation failed');
54
+ * ```
55
+ */
56
+ export function assert(value: unknown, message?: string): asserts value {
57
+ if (value !== true) {
58
+ throwError('assert', value, message);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Asserts that a value is not `null` or `undefined`, providing TypeScript type narrowing to `NonNullable<T>`.
64
+ * Ensures subsequent code can safely access the value.
65
+ *
66
+ * @param value - The value to check for null/undefined
67
+ * @param message - Optional custom error message
68
+ * @throws {AssertError} Throws an error if `value` is `null` or `undefined`.
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * function processUser(user: User | null | undefined) {
73
+ * assertNonNullable(user, 'User cannot be null');
74
+ * // user is now typed as User
75
+ * console.log(user.name); // Safe to access
76
+ * }
77
+ * ```
78
+ */
79
+ export function assertNonNullable<T>(
80
+ value: T,
81
+ message?: string,
82
+ ): asserts value is NonNullable<T> {
83
+ if (value === null || value === undefined) {
84
+ throwError('assertNonNullable', value, message);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Similar to `assert`, but returns the value. Ensures a value matches a type predicate and returns it with narrowed type.
90
+ *
91
+ * @param value - The value to validate
92
+ * @param predicate - Type guard function that validates the value
93
+ * @param message - Optional custom error message
94
+ * @returns The value with narrowed type
95
+ * @throws {AssertError} Throws an error if `predicate` returns `false`.
96
+ *
97
+ * @example
98
+ * ```typescript
99
+ * // Define type guard
100
+ * function isAdminUser(user: User): user is AdminUser {
101
+ * return user.role === 'admin';
102
+ * }
103
+ *
104
+ * // Use ensure to get type-safe value
105
+ * const admin = ensure(
106
+ * currentUser,
107
+ * isAdminUser,
108
+ * 'Admin privileges required'
109
+ * );
110
+ * // admin is typed as AdminUser
111
+ * ```
112
+ */
113
+ export function ensure<T, S extends T>(
114
+ value: T,
115
+ predicate: (value: T) => value is S,
116
+ message?: string,
117
+ ): S {
118
+ assert(predicate(value), message);
119
+ return value;
120
+ }
121
+
122
+ /**
123
+ * Similar to `assertNonNullable`, but returns the value. Ensures a value is not null/undefined and returns it.
124
+ *
125
+ * @param value - The value to check for null/undefined
126
+ * @param message - Optional custom error message
127
+ * @returns The non-nullable value
128
+ * @throws {AssertError} Throws an error if `value` is `null` or `undefined`.
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * // Use in expressions
133
+ * const config = ensureNonNullable(
134
+ * getConfig(),
135
+ * 'Configuration not found'
136
+ * );
137
+ *
138
+ * // Chain calls
139
+ * const userName = ensureNonNullable(user, 'User not found').name;
140
+ * ```
141
+ */
142
+ export function ensureNonNullable<T>(
143
+ value: T,
144
+ message?: string,
145
+ ): NonNullable<T> {
146
+ if (value === null || value === undefined) {
147
+ throwError('ensureNonNullable', value, message);
148
+ }
149
+ return value;
150
+ }
151
+
152
+ /**
153
+ * Marks code branches that should theoretically never be reached.
154
+ * Used for defensive programming to prevent unexpected code execution when data or logic doesn't match expectations.
155
+ *
156
+ * @param message - Optional custom error message
157
+ * @returns Never returns (always throws)
158
+ * @throws {AssertError} Always thrown.
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * function processStatus(status: 'active' | 'inactive' | 'activating') {
163
+ * if (status === 'active') {
164
+ * // Handle active state
165
+ * } else if (status === 'inactive') {
166
+ * // Handle inactive state
167
+ * } else {
168
+ * // According to business logic, this should never be reached
169
+ * assertUnreachable(`Unexpected status value: ${status}`);
170
+ * }
171
+ * }
172
+ * ```
173
+ */
174
+ export function assertUnreachable(message?: string): never {
175
+ throwError('assertUnreachable', null, message);
176
+ }
177
+
178
+ /**
179
+ * Used for exhaustiveness checking of union types. Ensures switch or if-else statements cover all possible types.
180
+ * Leverages TypeScript's `never` type to catch missing branches at compile time.
181
+ *
182
+ * @param value - The value that should be `never` if all cases are handled
183
+ * @param message - Optional custom error message
184
+ * @returns Never returns (always throws)
185
+ * @throws {AssertError} Always thrown.
186
+ *
187
+ * @example
188
+ * ```typescript
189
+ * type Action =
190
+ * | { type: 'ADD'; payload: number }
191
+ * | { type: 'SUBTRACT'; payload: number }
192
+ * | { type: 'MULTIPLY'; payload: number };
193
+ *
194
+ * function reducer(action: Action) {
195
+ * switch (action.type) {
196
+ * case 'ADD':
197
+ * return state + action.payload;
198
+ * case 'SUBTRACT':
199
+ * return state - action.payload;
200
+ * case 'MULTIPLY':
201
+ * return state * action.payload;
202
+ * default:
203
+ * // If all types are exhausted, action is of type never
204
+ * // If new Action types are added but not handled, TypeScript will report error
205
+ * return assertExhaustive(action);
206
+ * // ^ never
207
+ * }
208
+ * }
209
+ * ```
210
+ */
211
+ export function assertExhaustive(value: never, message?: string): never {
212
+ throwError('assertExhaustive', value, message);
213
+ }