umsizi 0.1.0 → 0.3.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/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Umsizi
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/umsizi.svg)](https://www.npmjs.com/package/umsizi)
4
+ [![CI](https://github.com/Jack-WebDev/umsizi/actions/workflows/ci.yml/badge.svg)](https://github.com/Jack-WebDev/umsizi/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
6
+
3
7
  > The missing TypeScript standard library.
4
8
 
5
9
  **Umsizi** (pronounced *oom-see-zee*) is a modern, zero-dependency utility library built from the ground up for TypeScript applications. The name comes from the Zulu word for **"helper"** or **"assistant"**—which is exactly what this library is designed to be.
@@ -113,6 +117,114 @@ const value = identity("umsizi");
113
117
 
114
118
  ```
115
119
 
120
+ #### `typedKeys`
121
+
122
+ ```ts
123
+ import { typedKeys } from "umsizi";
124
+
125
+ const user = { id: "1", name: "Jack" } as const;
126
+
127
+ typedKeys(user);
128
+ // ["id", "name"]
129
+ ```
130
+
131
+ #### `typedEntries`
132
+
133
+ ```ts
134
+ import { typedEntries } from "umsizi";
135
+
136
+ const user = { id: "1", active: true } as const;
137
+
138
+ typedEntries(user);
139
+ // [["id", "1"], ["active", true]]
140
+ ```
141
+
142
+ #### `typedFromEntries`
143
+
144
+ ```ts
145
+ import { typedFromEntries } from "umsizi";
146
+
147
+ const user = typedFromEntries([
148
+ ["id", "1"],
149
+ ["active", true],
150
+ ] as const);
151
+ ```
152
+
153
+ #### `pick`
154
+
155
+ ```ts
156
+ import { pick } from "umsizi";
157
+
158
+ pick({ id: "1", name: "Jack", role: "admin" }, "id", "role");
159
+ // { id: "1", role: "admin" }
160
+ ```
161
+
162
+ #### `omit`
163
+
164
+ ```ts
165
+ import { omit } from "umsizi";
166
+
167
+ omit({ id: "1", name: "Jack", role: "admin" }, "role");
168
+ // { id: "1", name: "Jack" }
169
+ ```
170
+
171
+ For the best autocomplete, prefer the rest-key form for `pick()` and `omit()`.
172
+ If you pass an array literal and want exact key inference, use `as const`:
173
+
174
+ ```ts
175
+ pick(user, ["id", "role"] as const);
176
+ omit(user, ["createdAt"] as const);
177
+ ```
178
+
179
+ #### `isEmpty`
180
+
181
+ ```ts
182
+ import { isEmpty } from "umsizi";
183
+
184
+ isEmpty({});
185
+ // true
186
+ ```
187
+
188
+ #### `hasOwn`
189
+
190
+ ```ts
191
+ import { hasOwn } from "umsizi";
192
+
193
+ const user = { id: "1" };
194
+ const key: string = "id";
195
+
196
+ if (hasOwn(user, key)) {
197
+ user[key];
198
+ }
199
+ ```
200
+
201
+ #### `mapValues`
202
+
203
+ ```ts
204
+ import { mapValues } from "umsizi";
205
+
206
+ mapValues({ draft: 1, published: 2 }, (value) => value * 2);
207
+ // { draft: 2, published: 4 }
208
+ ```
209
+
210
+ #### `filterValues`
211
+
212
+ ```ts
213
+ import { filterValues } from "umsizi";
214
+
215
+ filterValues({ a: 1, b: 0, c: null }, (value) => value !== null);
216
+ // { a: 1, b: 0 }
217
+ ```
218
+
219
+ #### `compactObject`
220
+
221
+ ```ts
222
+ import { compactObject } from "umsizi";
223
+
224
+ compactObject({ id: "1", nickname: null, active: false });
225
+ // { id: "1", active: false }
226
+ ```
227
+
116
228
  ### React Utilities (`umsizi/react`)
117
229
 
118
230
  #### `isRenderFunction`
@@ -163,6 +275,36 @@ hasFileExtension("package.json", "json");
163
275
 
164
276
  ---
165
277
 
278
+ ## Compatibility
279
+
280
+ - **ESM-only.** Umsizi ships only as ECMAScript modules (no CommonJS build). `require("umsizi")` will not work; use `import`. If your project is on CommonJS, you'll need a dynamic `import()` or a bundler that handles ESM dependencies.
281
+ - **Node.js 20+.** Enforced via `engines.node` in `package.json`.
282
+ - **Browsers:** the code targets ES2022 and has no Node-specific APIs in `umsizi` (core), `umsizi/react`, and `umsizi/next`; `umsizi/node` is Node-only by design. Bundle through your usual toolchain (Vite, Webpack, etc.) — there's no separate browser build.
283
+
284
+ ## Error Handling Philosophy
285
+
286
+ Umsizi utilities **trust their inputs** to match their TypeScript signatures. They do not perform runtime validation, and they do not throw — invalid input (e.g. calling a Node-typed function with a non-string) produces an unspecified but non-throwing result rather than an exception.
287
+
288
+ If you're handling untrusted input (user input, network responses, `unknown`/`any` values), validate or narrow it *before* passing it into Umsizi. This keeps the utilities small, predictable, and fast, matching their role as thin building blocks rather than a validation layer.
289
+
290
+ ## Versioning & Stability
291
+
292
+ Umsizi follows [semantic versioning](https://semver.org/). While the package is `0.x`:
293
+
294
+ - Minor versions (`0.x.0`) may include breaking changes to the public API.
295
+ - Patch versions (`0.0.x`) are bug fixes only.
296
+ - Once the API stabilizes, `1.0.0` will commit to standard semver guarantees (breaking changes only on major versions).
297
+
298
+ Releases are managed via [Changesets](https://github.com/changesets/changesets) and npm trusted publishing from GitHub Actions; see the generated `CHANGELOG.md` for version history.
299
+
300
+ ---
301
+
302
+ ## Examples
303
+
304
+ See [`examples/`](./examples) for runnable, slightly more realistic usage of each utility beyond the snippets below.
305
+
306
+ ---
307
+
166
308
  ## Current Status
167
309
 
168
310
  Umsizi is still in early development. The package structure is in place, the initial utilities are implemented, and the public API is intentionally small.
@@ -197,6 +339,12 @@ If you want to introduce a helper, ensure it meets the baseline:
197
339
 
198
340
  ---
199
341
 
342
+ ## Security
343
+
344
+ See [SECURITY.md](./SECURITY.md) for the vulnerability reporting policy.
345
+
346
+ ---
347
+
200
348
  ## License
201
349
 
202
350
  MIT
@@ -0,0 +1,19 @@
1
+ //#region src/node/has-file-extension.d.ts
2
+ /**
3
+ * Checks whether a file path ends with the given extension.
4
+ *
5
+ * The leading dot on `extension` is optional — both `"ts"` and `".ts"` are
6
+ * accepted. The comparison is case-sensitive and is a plain `endsWith`
7
+ * check, so it does not validate that `filePath` is a well-formed path.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * hasFileExtension("src/index.ts", ".ts"); // true
12
+ * hasFileExtension("package.json", "json"); // true
13
+ * hasFileExtension("README.md", "ts"); // false
14
+ * ```
15
+ */
16
+ declare function hasFileExtension(filePath: string, extension: string): boolean;
17
+ //#endregion
18
+ export { hasFileExtension as t };
19
+ //# sourceMappingURL=index-DtjbEW43.d.ts.map
@@ -0,0 +1,22 @@
1
+ //#region src/react/is-render-function.d.ts
2
+ /**
3
+ * Type guard for values that are callable in render-oriented code paths
4
+ * (e.g. `children` passed as a render prop).
5
+ *
6
+ * Matches any callable value, including async functions, generator
7
+ * functions, and class constructors — it does not distinguish between
8
+ * function kinds, only "is this safe to call as a function".
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const children: unknown = () => "ready";
13
+ *
14
+ * if (isRenderFunction(children)) {
15
+ * children();
16
+ * }
17
+ * ```
18
+ */
19
+ declare function isRenderFunction(value: unknown): value is (...args: readonly unknown[]) => unknown;
20
+ //#endregion
21
+ export { isRenderFunction as t };
22
+ //# sourceMappingURL=index-dktuz4mv.d.ts.map
@@ -0,0 +1,23 @@
1
+ //#region src/next/normalize-pathname.d.ts
2
+ /**
3
+ * Normalizes a path-like string for routing/comparison purposes.
4
+ *
5
+ * - Ensures a leading slash.
6
+ * - Collapses consecutive slashes into one.
7
+ * - Strips a trailing slash (except for the root path).
8
+ * - An empty string normalizes to `"/"`.
9
+ *
10
+ * Query strings and fragments are treated as opaque path characters and are
11
+ * not parsed or stripped — pass only the pathname segment of a URL.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * normalizePathname("dashboard"); // "/dashboard"
16
+ * normalizePathname("//dashboard///settings/"); // "/dashboard/settings"
17
+ * normalizePathname(""); // "/"
18
+ * ```
19
+ */
20
+ declare function normalizePathname(pathname: string): string;
21
+ //#endregion
22
+ export { normalizePathname as t };
23
+ //# sourceMappingURL=index-rZiv1o95.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,9 +1,202 @@
1
- import { t as normalizePathname } from "./index-Cfup-UnB.js";
2
- import { t as hasFileExtension } from "./index-Bi-DJKKn.js";
3
- import { t as isRenderFunction } from "./index-uHJbGgdS.js";
1
+ import { t as normalizePathname } from "./index-rZiv1o95.js";
2
+ import { t as hasFileExtension } from "./index-DtjbEW43.js";
3
+ import { t as isRenderFunction } from "./index-dktuz4mv.js";
4
4
 
5
+ //#region src/core/types.d.ts
6
+ type StringKeyOf<T extends object> = Extract<keyof T, string>;
7
+ type ObjectEntry<T extends object> = { [K in StringKeyOf<T>]: readonly [K, T[K]] }[StringKeyOf<T>];
8
+ type ObjectEntries<T extends object> = Array<ObjectEntry<T>>;
9
+ type EntryTuple = readonly [PropertyKey, unknown];
10
+ type EntryTuples = ReadonlyArray<EntryTuple>;
11
+ type ObjectFromEntries<T extends EntryTuples> = { [K in T[number] as K[0]]: K[1] };
12
+ type ValueMapper<T extends object, R> = (value: T[StringKeyOf<T>], key: StringKeyOf<T>, object: T) => R;
13
+ type ValuePredicate<T extends object> = (value: T[StringKeyOf<T>], key: StringKeyOf<T>, object: T) => boolean;
14
+ type ValueGuard<T extends object, S extends T[StringKeyOf<T>]> = (value: T[StringKeyOf<T>], key: StringKeyOf<T>, object: T) => value is S;
15
+ type MappedValues<T extends object, R> = { [K in StringKeyOf<T>]: R };
16
+ type FilteredValues<T extends object, S extends T[StringKeyOf<T>]> = Partial<{ [K in StringKeyOf<T>]: Extract<T[K], S> }>;
17
+ type CompactedObject<T extends object> = Partial<{ [K in StringKeyOf<T>]: Exclude<T[K], null | undefined> }>;
18
+ //#endregion
19
+ //#region src/core/compact-object.d.ts
20
+ /**
21
+ * Creates a new object with all `null` and `undefined` values removed.
22
+ *
23
+ * Other falsy values such as `0`, `false`, `""`, and `NaN` are preserved.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const user = { id: "1", nickname: null, active: false } as const;
28
+ *
29
+ * compactObject(user); // { id: "1", active: false }
30
+ * ```
31
+ */
32
+ declare function compactObject<T extends object>(object: T): CompactedObject<T>;
33
+ //#endregion
34
+ //#region src/core/filter-values.d.ts
35
+ /**
36
+ * Filters an object's own enumerable string-keyed properties by value.
37
+ *
38
+ * Supports both boolean predicates and type-guard predicates. The result type
39
+ * remains partial because any property may be removed at runtime.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const settings = { retries: 3, label: "", timeout: null } as const;
44
+ *
45
+ * filterValues(settings, (value) => value !== null);
46
+ * // { retries: 3, label: "" }
47
+ * ```
48
+ */
49
+ declare function filterValues<T extends object, S extends T[Extract<keyof T, string>]>(object: T, predicate: ValueGuard<T, S>): FilteredValues<T, S>;
50
+ declare function filterValues<T extends object>(object: T, predicate: ValuePredicate<T>): FilteredValues<T, T[Extract<keyof T, string>]>;
51
+ //#endregion
52
+ //#region src/core/has-own.d.ts
53
+ /**
54
+ * Checks whether an object has the given property as its own key.
55
+ *
56
+ * This is a typed wrapper around `Object.hasOwn` that narrows the provided key
57
+ * when the check succeeds.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const user = { id: "1" };
62
+ * const key: string = "id";
63
+ *
64
+ * if (hasOwn(user, key)) {
65
+ * user[key]; // key is narrowed to "id"
66
+ * }
67
+ * ```
68
+ */
69
+ declare function hasOwn<T extends object, K$1 extends PropertyKey>(object: T, key: K$1): key is Extract<K$1, keyof T>;
70
+ //#endregion
5
71
  //#region src/core/identity.d.ts
72
+ /**
73
+ * Returns the given value unchanged.
74
+ *
75
+ * Useful as a default callback, a type-inference anchor, or a no-op
76
+ * placeholder where a transform function is expected.
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * identity("umsizi"); // "umsizi"
81
+ * ```
82
+ */
6
83
  declare function identity<T>(value: T): T;
7
84
  //#endregion
8
- export { hasFileExtension, identity, isRenderFunction, normalizePathname };
85
+ //#region src/core/is-empty.d.ts
86
+ /**
87
+ * Returns `true` when an object has no own enumerable properties.
88
+ *
89
+ * Both string keys and symbol keys are considered. Non-enumerable properties
90
+ * are ignored.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * isEmpty({}); // true
95
+ * isEmpty({ id: "1" }); // false
96
+ * ```
97
+ */
98
+ declare function isEmpty(object: object): boolean;
99
+ //#endregion
100
+ //#region src/core/map-values.d.ts
101
+ /**
102
+ * Maps the values of an object's own enumerable string-keyed properties while
103
+ * preserving the original enumerable string-key set.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * const counts = { draft: 1, published: 2 };
108
+ *
109
+ * mapValues(counts, (value) => value * 2);
110
+ * // { draft: 2, published: 4 }
111
+ * ```
112
+ */
113
+ declare function mapValues<T extends object, R>(object: T, mapper: ValueMapper<T, R>): MappedValues<T, R>;
114
+ //#endregion
115
+ //#region src/core/omit.d.ts
116
+ /**
117
+ * Creates a new object excluding the selected own enumerable properties.
118
+ *
119
+ * Prefer the rest-key form for the strongest autocomplete and inference.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * const user = { id: "1", name: "Umsizi", role: "admin" } as const;
124
+ *
125
+ * omit(user, "id", "name"); // { role: "admin" }
126
+ * omit(user, ["role"] as const); // { id: "1", name: "Umsizi" }
127
+ * ```
128
+ */
129
+ declare function omit<T extends object, const Keys extends readonly (keyof T)[]>(object: T, ...keys: Keys): Omit<T, Keys[number]>;
130
+ declare function omit<T extends object, const FirstKey extends keyof T, const RestKeys extends readonly (keyof T)[]>(object: T, keys: readonly [FirstKey, ...RestKeys]): Omit<T, FirstKey | RestKeys[number]>;
131
+ declare function omit<T extends object>(object: T, keys: readonly (keyof T)[]): Partial<T>;
132
+ //#endregion
133
+ //#region src/core/pick.d.ts
134
+ /**
135
+ * Creates a new object containing only the selected own properties.
136
+ *
137
+ * Prefer the rest-key form for the strongest autocomplete and inference.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * const user = { id: "1", name: "Umsizi", role: "admin" } as const;
142
+ *
143
+ * pick(user, "name"); // { name: "Umsizi" }
144
+ * pick(user, ["id", "role"] as const); // { id: "1", role: "admin" }
145
+ * ```
146
+ */
147
+ declare function pick<T extends object, const Keys extends readonly (keyof T)[]>(object: T, ...keys: Keys): Pick<T, Keys[number]>;
148
+ declare function pick<T extends object, const FirstKey extends keyof T, const RestKeys extends readonly (keyof T)[]>(object: T, keys: readonly [FirstKey, ...RestKeys]): Pick<T, FirstKey | RestKeys[number]>;
149
+ declare function pick<T extends object>(object: T, keys: readonly (keyof T)[]): Partial<T>;
150
+ //#endregion
151
+ //#region src/core/typed-entries.d.ts
152
+ /**
153
+ * Returns the own enumerable string-keyed entries of an object with preserved
154
+ * key/value pairing.
155
+ *
156
+ * This is a typed wrapper around `Object.entries`.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * const user = { id: "1", active: true } as const;
161
+ *
162
+ * typedEntries(user); // [["id", "1"], ["active", true]]
163
+ * ```
164
+ */
165
+ declare function typedEntries<T extends object>(object: T): ObjectEntries<T>;
166
+ //#endregion
167
+ //#region src/core/typed-from-entries.d.ts
168
+ /**
169
+ * Creates an object from entries while preserving the key and value types from
170
+ * the input tuple array.
171
+ *
172
+ * This is a typed wrapper around `Object.fromEntries`.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * const status = typedFromEntries([
177
+ * ["id", "1"],
178
+ * ["active", true],
179
+ * ] as const);
180
+ *
181
+ * // inferred as: { id: "1"; active: true }
182
+ * ```
183
+ */
184
+ declare function typedFromEntries<const T extends EntryTuples>(entries: T): ObjectFromEntries<T>;
185
+ //#endregion
186
+ //#region src/core/typed-keys.d.ts
187
+ /**
188
+ * Returns the own enumerable string keys of an object with preserved key types.
189
+ *
190
+ * This is a typed wrapper around `Object.keys`.
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * const user = { id: "1", name: "Umsizi" } as const;
195
+ *
196
+ * typedKeys(user); // ["id", "name"]
197
+ * ```
198
+ */
199
+ declare function typedKeys<T extends object>(object: T): Array<StringKeyOf<T>>;
200
+ //#endregion
201
+ export { compactObject, filterValues, hasFileExtension, hasOwn, identity, isEmpty, isRenderFunction, mapValues, normalizePathname, omit, pick, typedEntries, typedFromEntries, typedKeys };
9
202
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,12 +1,197 @@
1
- import { t as normalizePathname } from "./next-B9pvCR1P.js";
2
- import { t as hasFileExtension } from "./node-Di-uva1n.js";
3
- import { t as isRenderFunction } from "./react-DPRQiKYh.js";
1
+ import { t as normalizePathname } from "./next-C3wp7UoQ.js";
2
+ import { t as hasFileExtension } from "./node-D-nlzpmG.js";
3
+ import { t as isRenderFunction } from "./react-BCidSnzT.js";
4
4
 
5
+ //#region src/core/typed-keys.ts
6
+ /**
7
+ * Returns the own enumerable string keys of an object with preserved key types.
8
+ *
9
+ * This is a typed wrapper around `Object.keys`.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const user = { id: "1", name: "Umsizi" } as const;
14
+ *
15
+ * typedKeys(user); // ["id", "name"]
16
+ * ```
17
+ */
18
+ function typedKeys(object) {
19
+ return Object.keys(object);
20
+ }
21
+
22
+ //#endregion
23
+ //#region src/core/compact-object.ts
24
+ /**
25
+ * Creates a new object with all `null` and `undefined` values removed.
26
+ *
27
+ * Other falsy values such as `0`, `false`, `""`, and `NaN` are preserved.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const user = { id: "1", nickname: null, active: false } as const;
32
+ *
33
+ * compactObject(user); // { id: "1", active: false }
34
+ * ```
35
+ */
36
+ function compactObject(object) {
37
+ const result = {};
38
+ for (const key of typedKeys(object)) {
39
+ const value = object[key];
40
+ if (value != null) result[key] = value;
41
+ }
42
+ return result;
43
+ }
44
+
45
+ //#endregion
46
+ //#region src/core/filter-values.ts
47
+ function filterValues(object, predicate) {
48
+ const result = {};
49
+ for (const key of typedKeys(object)) {
50
+ const value = object[key];
51
+ if (predicate(value, key, object)) result[key] = value;
52
+ }
53
+ return result;
54
+ }
55
+
56
+ //#endregion
57
+ //#region src/core/has-own.ts
58
+ /**
59
+ * Checks whether an object has the given property as its own key.
60
+ *
61
+ * This is a typed wrapper around `Object.hasOwn` that narrows the provided key
62
+ * when the check succeeds.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const user = { id: "1" };
67
+ * const key: string = "id";
68
+ *
69
+ * if (hasOwn(user, key)) {
70
+ * user[key]; // key is narrowed to "id"
71
+ * }
72
+ * ```
73
+ */
74
+ function hasOwn(object, key) {
75
+ return Object.hasOwn(object, key);
76
+ }
77
+
78
+ //#endregion
5
79
  //#region src/core/identity.ts
80
+ /**
81
+ * Returns the given value unchanged.
82
+ *
83
+ * Useful as a default callback, a type-inference anchor, or a no-op
84
+ * placeholder where a transform function is expected.
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * identity("umsizi"); // "umsizi"
89
+ * ```
90
+ */
6
91
  function identity(value) {
7
92
  return value;
8
93
  }
9
94
 
10
95
  //#endregion
11
- export { hasFileExtension, identity, isRenderFunction, normalizePathname };
96
+ //#region src/core/is-empty.ts
97
+ /**
98
+ * Returns `true` when an object has no own enumerable properties.
99
+ *
100
+ * Both string keys and symbol keys are considered. Non-enumerable properties
101
+ * are ignored.
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * isEmpty({}); // true
106
+ * isEmpty({ id: "1" }); // false
107
+ * ```
108
+ */
109
+ function isEmpty(object) {
110
+ if (Object.keys(object).length > 0) return false;
111
+ for (const key of Object.getOwnPropertySymbols(object)) if (Object.prototype.propertyIsEnumerable.call(object, key)) return false;
112
+ return true;
113
+ }
114
+
115
+ //#endregion
116
+ //#region src/core/map-values.ts
117
+ /**
118
+ * Maps the values of an object's own enumerable string-keyed properties while
119
+ * preserving the original enumerable string-key set.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * const counts = { draft: 1, published: 2 };
124
+ *
125
+ * mapValues(counts, (value) => value * 2);
126
+ * // { draft: 2, published: 4 }
127
+ * ```
128
+ */
129
+ function mapValues(object, mapper) {
130
+ const result = {};
131
+ for (const key of typedKeys(object)) result[key] = mapper(object[key], key, object);
132
+ return result;
133
+ }
134
+
135
+ //#endregion
136
+ //#region src/core/omit.ts
137
+ function omit(object, firstKeyOrKeys, ...restKeys) {
138
+ const keys = Array.isArray(firstKeyOrKeys) ? firstKeyOrKeys : [firstKeyOrKeys, ...restKeys];
139
+ const omittedKeys = new Set(keys);
140
+ const result = {};
141
+ for (const key of Reflect.ownKeys(object)) if (Object.prototype.propertyIsEnumerable.call(object, key) && !omittedKeys.has(key)) result[key] = object[key];
142
+ return result;
143
+ }
144
+
145
+ //#endregion
146
+ //#region src/core/pick.ts
147
+ function pick(object, firstKeyOrKeys, ...restKeys) {
148
+ const keys = Array.isArray(firstKeyOrKeys) ? firstKeyOrKeys : [firstKeyOrKeys, ...restKeys];
149
+ const result = {};
150
+ for (const key of keys) if (hasOwn(object, key)) result[key] = object[key];
151
+ return result;
152
+ }
153
+
154
+ //#endregion
155
+ //#region src/core/typed-entries.ts
156
+ /**
157
+ * Returns the own enumerable string-keyed entries of an object with preserved
158
+ * key/value pairing.
159
+ *
160
+ * This is a typed wrapper around `Object.entries`.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * const user = { id: "1", active: true } as const;
165
+ *
166
+ * typedEntries(user); // [["id", "1"], ["active", true]]
167
+ * ```
168
+ */
169
+ function typedEntries(object) {
170
+ return Object.entries(object);
171
+ }
172
+
173
+ //#endregion
174
+ //#region src/core/typed-from-entries.ts
175
+ /**
176
+ * Creates an object from entries while preserving the key and value types from
177
+ * the input tuple array.
178
+ *
179
+ * This is a typed wrapper around `Object.fromEntries`.
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * const status = typedFromEntries([
184
+ * ["id", "1"],
185
+ * ["active", true],
186
+ * ] as const);
187
+ *
188
+ * // inferred as: { id: "1"; active: true }
189
+ * ```
190
+ */
191
+ function typedFromEntries(entries) {
192
+ return Object.fromEntries(entries);
193
+ }
194
+
195
+ //#endregion
196
+ export { compactObject, filterValues, hasFileExtension, hasOwn, identity, isEmpty, isRenderFunction, mapValues, normalizePathname, omit, pick, typedEntries, typedFromEntries, typedKeys };
12
197
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/core/identity.ts"],"sourcesContent":["export function identity<T>(value: T): T {\n\treturn value;\n}\n"],"mappings":";;;;;AAAA,SAAgB,SAAY,OAAa;AACxC,QAAO"}
1
+ {"version":3,"file":"index.js","names":["result: Partial<T>","result: Partial<T>"],"sources":["../src/core/typed-keys.ts","../src/core/compact-object.ts","../src/core/filter-values.ts","../src/core/has-own.ts","../src/core/identity.ts","../src/core/is-empty.ts","../src/core/map-values.ts","../src/core/omit.ts","../src/core/pick.ts","../src/core/typed-entries.ts","../src/core/typed-from-entries.ts"],"sourcesContent":["import type { StringKeyOf } from \"./types\";\n\n/**\n * Returns the own enumerable string keys of an object with preserved key types.\n *\n * This is a typed wrapper around `Object.keys`.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", name: \"Umsizi\" } as const;\n *\n * typedKeys(user); // [\"id\", \"name\"]\n * ```\n */\nexport function typedKeys<T extends object>(object: T): Array<StringKeyOf<T>> {\n\treturn Object.keys(object) as Array<StringKeyOf<T>>;\n}\n","import { typedKeys } from \"./typed-keys\";\nimport type { CompactedObject } from \"./types\";\n\n/**\n * Creates a new object with all `null` and `undefined` values removed.\n *\n * Other falsy values such as `0`, `false`, `\"\"`, and `NaN` are preserved.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", nickname: null, active: false } as const;\n *\n * compactObject(user); // { id: \"1\", active: false }\n * ```\n */\nexport function compactObject<T extends object>(object: T): CompactedObject<T> {\n\tconst result = {} as CompactedObject<T>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tconst value = object[key];\n\n\t\tif (value != null) {\n\t\t\tresult[key] = value as Exclude<T[typeof key], null | undefined>;\n\t\t}\n\t}\n\n\treturn result;\n}\n","import { typedKeys } from \"./typed-keys\";\nimport type { FilteredValues, ValueGuard, ValuePredicate } from \"./types\";\n\n/**\n * Filters an object's own enumerable string-keyed properties by value.\n *\n * Supports both boolean predicates and type-guard predicates. The result type\n * remains partial because any property may be removed at runtime.\n *\n * @example\n * ```ts\n * const settings = { retries: 3, label: \"\", timeout: null } as const;\n *\n * filterValues(settings, (value) => value !== null);\n * // { retries: 3, label: \"\" }\n * ```\n */\nexport function filterValues<\n\tT extends object,\n\tS extends T[Extract<keyof T, string>],\n>(object: T, predicate: ValueGuard<T, S>): FilteredValues<T, S>;\nexport function filterValues<T extends object>(\n\tobject: T,\n\tpredicate: ValuePredicate<T>,\n): FilteredValues<T, T[Extract<keyof T, string>]>;\nexport function filterValues<T extends object>(\n\tobject: T,\n\tpredicate: ValuePredicate<T>,\n): FilteredValues<T, T[Extract<keyof T, string>]> {\n\tconst result = {} as FilteredValues<T, T[Extract<keyof T, string>]>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tconst value = object[key];\n\n\t\tif (predicate(value, key, object)) {\n\t\t\tresult[key] = value;\n\t\t}\n\t}\n\n\treturn result;\n}\n","/**\n * Checks whether an object has the given property as its own key.\n *\n * This is a typed wrapper around `Object.hasOwn` that narrows the provided key\n * when the check succeeds.\n *\n * @example\n * ```ts\n * const user = { id: \"1\" };\n * const key: string = \"id\";\n *\n * if (hasOwn(user, key)) {\n * user[key]; // key is narrowed to \"id\"\n * }\n * ```\n */\nexport function hasOwn<T extends object, K extends PropertyKey>(\n\tobject: T,\n\tkey: K,\n): key is Extract<K, keyof T> {\n\treturn Object.hasOwn(object, key);\n}\n","/**\n * Returns the given value unchanged.\n *\n * Useful as a default callback, a type-inference anchor, or a no-op\n * placeholder where a transform function is expected.\n *\n * @example\n * ```ts\n * identity(\"umsizi\"); // \"umsizi\"\n * ```\n */\nexport function identity<T>(value: T): T {\n\treturn value;\n}\n","/**\n * Returns `true` when an object has no own enumerable properties.\n *\n * Both string keys and symbol keys are considered. Non-enumerable properties\n * are ignored.\n *\n * @example\n * ```ts\n * isEmpty({}); // true\n * isEmpty({ id: \"1\" }); // false\n * ```\n */\nexport function isEmpty(object: object): boolean {\n\tif (Object.keys(object).length > 0) {\n\t\treturn false;\n\t}\n\n\tfor (const key of Object.getOwnPropertySymbols(object)) {\n\t\tif (Object.prototype.propertyIsEnumerable.call(object, key)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n","import { typedKeys } from \"./typed-keys\";\nimport type { MappedValues, ValueMapper } from \"./types\";\n\n/**\n * Maps the values of an object's own enumerable string-keyed properties while\n * preserving the original enumerable string-key set.\n *\n * @example\n * ```ts\n * const counts = { draft: 1, published: 2 };\n *\n * mapValues(counts, (value) => value * 2);\n * // { draft: 2, published: 4 }\n * ```\n */\nexport function mapValues<T extends object, R>(\n\tobject: T,\n\tmapper: ValueMapper<T, R>,\n): MappedValues<T, R> {\n\tconst result = {} as MappedValues<T, R>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tresult[key] = mapper(object[key], key, object);\n\t}\n\n\treturn result;\n}\n","/**\n * Creates a new object excluding the selected own enumerable properties.\n *\n * Prefer the rest-key form for the strongest autocomplete and inference.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", name: \"Umsizi\", role: \"admin\" } as const;\n *\n * omit(user, \"id\", \"name\"); // { role: \"admin\" }\n * omit(user, [\"role\"] as const); // { id: \"1\", name: \"Umsizi\" }\n * ```\n */\nexport function omit<T extends object, const Keys extends readonly (keyof T)[]>(\n\tobject: T,\n\t...keys: Keys\n): Omit<T, Keys[number]>;\nexport function omit<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tobject: T,\n\tkeys: readonly [FirstKey, ...RestKeys],\n): Omit<T, FirstKey | RestKeys[number]>;\nexport function omit<T extends object>(\n\tobject: T,\n\tkeys: readonly (keyof T)[],\n): Partial<T>;\nexport function omit<T extends object>(\n\tobject: T,\n\tfirstKeyOrKeys: keyof T | readonly (keyof T)[],\n\t...restKeys: readonly (keyof T)[]\n): Partial<T> {\n\tconst keys = (\n\t\tArray.isArray(firstKeyOrKeys)\n\t\t\t? firstKeyOrKeys\n\t\t\t: [firstKeyOrKeys, ...restKeys]\n\t) as readonly (keyof T)[];\n\tconst omittedKeys = new Set<PropertyKey>(keys as readonly PropertyKey[]);\n\tconst result: Partial<T> = {};\n\n\tfor (const key of Reflect.ownKeys(object) as (keyof T)[]) {\n\t\tif (\n\t\t\tObject.prototype.propertyIsEnumerable.call(object, key) &&\n\t\t\t!omittedKeys.has(key)\n\t\t) {\n\t\t\t(result as T)[key] = object[key];\n\t\t}\n\t}\n\n\treturn result;\n}\n","import { hasOwn } from \"./has-own\";\n\n/**\n * Creates a new object containing only the selected own properties.\n *\n * Prefer the rest-key form for the strongest autocomplete and inference.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", name: \"Umsizi\", role: \"admin\" } as const;\n *\n * pick(user, \"name\"); // { name: \"Umsizi\" }\n * pick(user, [\"id\", \"role\"] as const); // { id: \"1\", role: \"admin\" }\n * ```\n */\nexport function pick<T extends object, const Keys extends readonly (keyof T)[]>(\n\tobject: T,\n\t...keys: Keys\n): Pick<T, Keys[number]>;\nexport function pick<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tobject: T,\n\tkeys: readonly [FirstKey, ...RestKeys],\n): Pick<T, FirstKey | RestKeys[number]>;\nexport function pick<T extends object>(\n\tobject: T,\n\tkeys: readonly (keyof T)[],\n): Partial<T>;\nexport function pick<T extends object>(\n\tobject: T,\n\tfirstKeyOrKeys: keyof T | readonly (keyof T)[],\n\t...restKeys: readonly (keyof T)[]\n): Partial<T> {\n\tconst keys = (\n\t\tArray.isArray(firstKeyOrKeys)\n\t\t\t? firstKeyOrKeys\n\t\t\t: [firstKeyOrKeys, ...restKeys]\n\t) as readonly (keyof T)[];\n\tconst result: Partial<T> = {};\n\n\tfor (const key of keys) {\n\t\tif (hasOwn(object, key)) {\n\t\t\tresult[key] = object[key];\n\t\t}\n\t}\n\n\treturn result;\n}\n","import type { ObjectEntries } from \"./types\";\n\n/**\n * Returns the own enumerable string-keyed entries of an object with preserved\n * key/value pairing.\n *\n * This is a typed wrapper around `Object.entries`.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", active: true } as const;\n *\n * typedEntries(user); // [[\"id\", \"1\"], [\"active\", true]]\n * ```\n */\nexport function typedEntries<T extends object>(object: T): ObjectEntries<T> {\n\treturn Object.entries(object) as unknown as ObjectEntries<T>;\n}\n","import type { EntryTuples, ObjectFromEntries } from \"./types\";\n\n/**\n * Creates an object from entries while preserving the key and value types from\n * the input tuple array.\n *\n * This is a typed wrapper around `Object.fromEntries`.\n *\n * @example\n * ```ts\n * const status = typedFromEntries([\n * [\"id\", \"1\"],\n * [\"active\", true],\n * ] as const);\n *\n * // inferred as: { id: \"1\"; active: true }\n * ```\n */\nexport function typedFromEntries<const T extends EntryTuples>(\n\tentries: T,\n): ObjectFromEntries<T> {\n\treturn Object.fromEntries(entries) as ObjectFromEntries<T>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAcA,SAAgB,UAA4B,QAAkC;AAC7E,QAAO,OAAO,KAAK,OAAO;;;;;;;;;;;;;;;;;ACA3B,SAAgB,cAAgC,QAA+B;CAC9E,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,UAAU,OAAO,EAAE;EACpC,MAAM,QAAQ,OAAO;AAErB,MAAI,SAAS,KACZ,QAAO,OAAO;;AAIhB,QAAO;;;;;ACDR,SAAgB,aACf,QACA,WACiD;CACjD,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,UAAU,OAAO,EAAE;EACpC,MAAM,QAAQ,OAAO;AAErB,MAAI,UAAU,OAAO,KAAK,OAAO,CAChC,QAAO,OAAO;;AAIhB,QAAO;;;;;;;;;;;;;;;;;;;;;ACvBR,SAAgB,OACf,QACA,KAC6B;AAC7B,QAAO,OAAO,OAAO,QAAQ,IAAI;;;;;;;;;;;;;;;;ACTlC,SAAgB,SAAY,OAAa;AACxC,QAAO;;;;;;;;;;;;;;;;;ACAR,SAAgB,QAAQ,QAAyB;AAChD,KAAI,OAAO,KAAK,OAAO,CAAC,SAAS,EAChC,QAAO;AAGR,MAAK,MAAM,OAAO,OAAO,sBAAsB,OAAO,CACrD,KAAI,OAAO,UAAU,qBAAqB,KAAK,QAAQ,IAAI,CAC1D,QAAO;AAIT,QAAO;;;;;;;;;;;;;;;;;ACRR,SAAgB,UACf,QACA,QACqB;CACrB,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,UAAU,OAAO,CAClC,QAAO,OAAO,OAAO,OAAO,MAAM,KAAK,OAAO;AAG/C,QAAO;;;;;ACIR,SAAgB,KACf,QACA,gBACA,GAAG,UACU;CACb,MAAM,OACL,MAAM,QAAQ,eAAe,GAC1B,iBACA,CAAC,gBAAgB,GAAG,SAAS;CAEjC,MAAM,cAAc,IAAI,IAAiB,KAA+B;CACxE,MAAMA,SAAqB,EAAE;AAE7B,MAAK,MAAM,OAAO,QAAQ,QAAQ,OAAO,CACxC,KACC,OAAO,UAAU,qBAAqB,KAAK,QAAQ,IAAI,IACvD,CAAC,YAAY,IAAI,IAAI,CAErB,CAAC,OAAa,OAAO,OAAO;AAI9B,QAAO;;;;;ACpBR,SAAgB,KACf,QACA,gBACA,GAAG,UACU;CACb,MAAM,OACL,MAAM,QAAQ,eAAe,GAC1B,iBACA,CAAC,gBAAgB,GAAG,SAAS;CAEjC,MAAMC,SAAqB,EAAE;AAE7B,MAAK,MAAM,OAAO,KACjB,KAAI,OAAO,QAAQ,IAAI,CACtB,QAAO,OAAO,OAAO;AAIvB,QAAO;;;;;;;;;;;;;;;;;;AClCR,SAAgB,aAA+B,QAA6B;AAC3E,QAAO,OAAO,QAAQ,OAAO;;;;;;;;;;;;;;;;;;;;;ACE9B,SAAgB,iBACf,SACuB;AACvB,QAAO,OAAO,YAAY,QAAQ"}
@@ -0,0 +1,29 @@
1
+ //#region src/next/normalize-pathname.ts
2
+ /**
3
+ * Normalizes a path-like string for routing/comparison purposes.
4
+ *
5
+ * - Ensures a leading slash.
6
+ * - Collapses consecutive slashes into one.
7
+ * - Strips a trailing slash (except for the root path).
8
+ * - An empty string normalizes to `"/"`.
9
+ *
10
+ * Query strings and fragments are treated as opaque path characters and are
11
+ * not parsed or stripped — pass only the pathname segment of a URL.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * normalizePathname("dashboard"); // "/dashboard"
16
+ * normalizePathname("//dashboard///settings/"); // "/dashboard/settings"
17
+ * normalizePathname(""); // "/"
18
+ * ```
19
+ */
20
+ function normalizePathname(pathname) {
21
+ if (pathname === "") return "/";
22
+ const normalized = pathname.replace(/\/{2,}/g, "/").replace(/\/$/, "");
23
+ if (normalized === "") return "/";
24
+ return normalized.startsWith("/") ? normalized : `/${normalized}`;
25
+ }
26
+
27
+ //#endregion
28
+ export { normalizePathname as t };
29
+ //# sourceMappingURL=next-C3wp7UoQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-C3wp7UoQ.js","names":[],"sources":["../src/next/normalize-pathname.ts"],"sourcesContent":["/**\n * Normalizes a path-like string for routing/comparison purposes.\n *\n * - Ensures a leading slash.\n * - Collapses consecutive slashes into one.\n * - Strips a trailing slash (except for the root path).\n * - An empty string normalizes to `\"/\"`.\n *\n * Query strings and fragments are treated as opaque path characters and are\n * not parsed or stripped — pass only the pathname segment of a URL.\n *\n * @example\n * ```ts\n * normalizePathname(\"dashboard\"); // \"/dashboard\"\n * normalizePathname(\"//dashboard///settings/\"); // \"/dashboard/settings\"\n * normalizePathname(\"\"); // \"/\"\n * ```\n */\nexport function normalizePathname(pathname: string): string {\n\tif (pathname === \"\") {\n\t\treturn \"/\";\n\t}\n\n\tconst normalized = pathname.replace(/\\/{2,}/g, \"/\").replace(/\\/$/, \"\");\n\n\tif (normalized === \"\") {\n\t\treturn \"/\";\n\t}\n\n\treturn normalized.startsWith(\"/\") ? normalized : `/${normalized}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,SAAgB,kBAAkB,UAA0B;AAC3D,KAAI,aAAa,GAChB,QAAO;CAGR,MAAM,aAAa,SAAS,QAAQ,WAAW,IAAI,CAAC,QAAQ,OAAO,GAAG;AAEtE,KAAI,eAAe,GAClB,QAAO;AAGR,QAAO,WAAW,WAAW,IAAI,GAAG,aAAa,IAAI"}
package/dist/next.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { t as normalizePathname } from "./index-Cfup-UnB.js";
1
+ import { t as normalizePathname } from "./index-rZiv1o95.js";
2
2
  export { normalizePathname };
package/dist/next.js CHANGED
@@ -1,3 +1,3 @@
1
- import { t as normalizePathname } from "./next-B9pvCR1P.js";
1
+ import { t as normalizePathname } from "./next-C3wp7UoQ.js";
2
2
 
3
3
  export { normalizePathname };
@@ -0,0 +1,23 @@
1
+ //#region src/node/has-file-extension.ts
2
+ /**
3
+ * Checks whether a file path ends with the given extension.
4
+ *
5
+ * The leading dot on `extension` is optional — both `"ts"` and `".ts"` are
6
+ * accepted. The comparison is case-sensitive and is a plain `endsWith`
7
+ * check, so it does not validate that `filePath` is a well-formed path.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * hasFileExtension("src/index.ts", ".ts"); // true
12
+ * hasFileExtension("package.json", "json"); // true
13
+ * hasFileExtension("README.md", "ts"); // false
14
+ * ```
15
+ */
16
+ function hasFileExtension(filePath, extension) {
17
+ const normalizedExtension = extension.startsWith(".") ? extension : `.${extension}`;
18
+ return filePath.endsWith(normalizedExtension);
19
+ }
20
+
21
+ //#endregion
22
+ export { hasFileExtension as t };
23
+ //# sourceMappingURL=node-D-nlzpmG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-D-nlzpmG.js","names":[],"sources":["../src/node/has-file-extension.ts"],"sourcesContent":["/**\n * Checks whether a file path ends with the given extension.\n *\n * The leading dot on `extension` is optional — both `\"ts\"` and `\".ts\"` are\n * accepted. The comparison is case-sensitive and is a plain `endsWith`\n * check, so it does not validate that `filePath` is a well-formed path.\n *\n * @example\n * ```ts\n * hasFileExtension(\"src/index.ts\", \".ts\"); // true\n * hasFileExtension(\"package.json\", \"json\"); // true\n * hasFileExtension(\"README.md\", \"ts\"); // false\n * ```\n */\nexport function hasFileExtension(filePath: string, extension: string): boolean {\n\tconst normalizedExtension = extension.startsWith(\".\")\n\t\t? extension\n\t\t: `.${extension}`;\n\n\treturn filePath.endsWith(normalizedExtension);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAcA,SAAgB,iBAAiB,UAAkB,WAA4B;CAC9E,MAAM,sBAAsB,UAAU,WAAW,IAAI,GAClD,YACA,IAAI;AAEP,QAAO,SAAS,SAAS,oBAAoB"}
package/dist/node.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { t as hasFileExtension } from "./index-Bi-DJKKn.js";
1
+ import { t as hasFileExtension } from "./index-DtjbEW43.js";
2
2
  export { hasFileExtension };
package/dist/node.js CHANGED
@@ -1,3 +1,3 @@
1
- import { t as hasFileExtension } from "./node-Di-uva1n.js";
1
+ import { t as hasFileExtension } from "./node-D-nlzpmG.js";
2
2
 
3
3
  export { hasFileExtension };
@@ -0,0 +1,25 @@
1
+ //#region src/react/is-render-function.ts
2
+ /**
3
+ * Type guard for values that are callable in render-oriented code paths
4
+ * (e.g. `children` passed as a render prop).
5
+ *
6
+ * Matches any callable value, including async functions, generator
7
+ * functions, and class constructors — it does not distinguish between
8
+ * function kinds, only "is this safe to call as a function".
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const children: unknown = () => "ready";
13
+ *
14
+ * if (isRenderFunction(children)) {
15
+ * children();
16
+ * }
17
+ * ```
18
+ */
19
+ function isRenderFunction(value) {
20
+ return typeof value === "function";
21
+ }
22
+
23
+ //#endregion
24
+ export { isRenderFunction as t };
25
+ //# sourceMappingURL=react-BCidSnzT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-BCidSnzT.js","names":[],"sources":["../src/react/is-render-function.ts"],"sourcesContent":["/**\n * Type guard for values that are callable in render-oriented code paths\n * (e.g. `children` passed as a render prop).\n *\n * Matches any callable value, including async functions, generator\n * functions, and class constructors — it does not distinguish between\n * function kinds, only \"is this safe to call as a function\".\n *\n * @example\n * ```ts\n * const children: unknown = () => \"ready\";\n *\n * if (isRenderFunction(children)) {\n * children();\n * }\n * ```\n */\nexport function isRenderFunction(\n\tvalue: unknown,\n): value is (...args: readonly unknown[]) => unknown {\n\treturn typeof value === \"function\";\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,SAAgB,iBACf,OACoD;AACpD,QAAO,OAAO,UAAU"}
package/dist/react.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { t as isRenderFunction } from "./index-uHJbGgdS.js";
1
+ import { t as isRenderFunction } from "./index-dktuz4mv.js";
2
2
  export { isRenderFunction };
package/dist/react.js CHANGED
@@ -1,3 +1,3 @@
1
- import { t as isRenderFunction } from "./react-DPRQiKYh.js";
1
+ import { t as isRenderFunction } from "./react-BCidSnzT.js";
2
2
 
3
3
  export { isRenderFunction };
package/package.json CHANGED
@@ -1,85 +1,111 @@
1
1
  {
2
- "name": "umsizi",
3
- "version": "0.1.0",
4
- "description": "A zero-dependency TypeScript utility library.",
5
- "license": "MIT",
6
- "author": "Jack-WebDev",
7
- "type": "module",
8
- "repository": {
9
- "type": "git",
10
- "url": "https://github.com/Jack-WebDev/umsizi.git"
11
- },
12
- "homepage": "https://github.com/Jack-WebDev/umsizi#readme",
13
- "bugs": {
14
- "url": "https://github.com/Jack-WebDev/umsizi/issues"
15
- },
16
- "keywords": [
17
- "typescript",
18
- "utilities",
19
- "helpers",
20
- "toolkit",
21
- "zero-dependency"
22
- ],
23
- "files": [
24
- "dist"
25
- ],
26
- "sideEffects": false,
27
- "exports": {
28
- ".": {
29
- "types": "./dist/index.d.ts",
30
- "import": "./dist/index.js"
31
- },
32
- "./react": {
33
- "types": "./dist/react.d.ts",
34
- "import": "./dist/react.js"
35
- },
36
- "./next": {
37
- "types": "./dist/next.d.ts",
38
- "import": "./dist/next.js"
39
- },
40
- "./node": {
41
- "types": "./dist/node.d.ts",
42
- "import": "./dist/node.js"
43
- }
44
- },
45
- "types": "./dist/index.d.ts",
46
- "main": "./dist/index.js",
47
- "module": "./dist/index.js",
48
- "scripts": {
49
- "build": "tsdown",
50
- "ci": "pnpm run lint && pnpm run check-types && pnpm run test && pnpm run build && pnpm run check:package",
51
- "check:package": "pnpm run check:package:npm && pnpm run check:package:jsr",
52
- "check:package:jsr": "pnpm dlx jsr publish --dry-run --allow-dirty",
53
- "check:package:npm": "HUSKY=0 npm_config_cache=/tmp/umsizi-npm-cache npm pack --dry-run --ignore-scripts",
54
- "dev": "tsdown --watch",
55
- "format": "biome format --write .",
56
- "lint": "biome check .",
57
- "lint:fix": "biome check --write .",
58
- "check-types": "tsc --noEmit",
59
- "release:publish": "pnpm run build && pnpm exec changeset publish && pnpm dlx jsr publish --allow-dirty",
60
- "release:version": "pnpm exec changeset version && node ./scripts/sync-release-version.mjs",
61
- "test": "vitest run",
62
- "prepare": "husky"
63
- },
64
- "devDependencies": {
65
- "@biomejs/biome": "2.5.1",
66
- "husky": "^9.1.7",
67
- "tsdown": "^0.16.8",
68
- "typescript": "5.9.2",
69
- "vitest": "4.1.9",
70
- "lint-staged": "^16.1.2",
71
- "@changesets/cli": "2.31.0"
72
- },
73
- "packageManager": "pnpm@10.32.1",
74
- "publishConfig": {
75
- "access": "public"
76
- },
77
- "lint-staged": {
78
- "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": [
79
- "biome check --write ."
80
- ]
81
- },
82
- "engines": {
83
- "node": ">=20"
84
- }
85
- }
2
+ "name": "umsizi",
3
+ "version": "0.3.0",
4
+ "description": "A zero-dependency TypeScript utility library.",
5
+ "license": "MIT",
6
+ "author": "Jack-WebDev",
7
+ "type": "module",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/Jack-WebDev/umsizi.git"
11
+ },
12
+ "homepage": "https://github.com/Jack-WebDev/umsizi#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/Jack-WebDev/umsizi/issues"
15
+ },
16
+ "keywords": [
17
+ "typescript",
18
+ "utilities",
19
+ "helpers",
20
+ "toolkit",
21
+ "zero-dependency"
22
+ ],
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "sideEffects": false,
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js"
31
+ },
32
+ "./react": {
33
+ "types": "./dist/react.d.ts",
34
+ "import": "./dist/react.js"
35
+ },
36
+ "./next": {
37
+ "types": "./dist/next.d.ts",
38
+ "import": "./dist/next.js"
39
+ },
40
+ "./node": {
41
+ "types": "./dist/node.d.ts",
42
+ "import": "./dist/node.js"
43
+ }
44
+ },
45
+ "types": "./dist/index.d.ts",
46
+ "main": "./dist/index.js",
47
+ "module": "./dist/index.js",
48
+ "devDependencies": {
49
+ "@biomejs/biome": "2.5.1",
50
+ "@changesets/cli": "2.31.0",
51
+ "@size-limit/preset-small-lib": "12.1.0",
52
+ "@vitest/coverage-v8": "4.1.9",
53
+ "husky": "^9.1.7",
54
+ "lint-staged": "^16.1.2",
55
+ "size-limit": "12.1.0",
56
+ "tsdown": "^0.16.8",
57
+ "typescript": "5.9.2",
58
+ "vitest": "4.1.9"
59
+ },
60
+ "publishConfig": {
61
+ "access": "public"
62
+ },
63
+ "lint-staged": {
64
+ "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": [
65
+ "biome check --write ."
66
+ ]
67
+ },
68
+ "engines": {
69
+ "node": ">=20"
70
+ },
71
+ "size-limit": [
72
+ {
73
+ "name": "umsizi (core)",
74
+ "path": "dist/index.js",
75
+ "limit": "512 B"
76
+ },
77
+ {
78
+ "name": "umsizi/react",
79
+ "path": "dist/react.js",
80
+ "limit": "512 B"
81
+ },
82
+ {
83
+ "name": "umsizi/next",
84
+ "path": "dist/next.js",
85
+ "limit": "512 B"
86
+ },
87
+ {
88
+ "name": "umsizi/node",
89
+ "path": "dist/node.js",
90
+ "limit": "512 B"
91
+ }
92
+ ],
93
+ "scripts": {
94
+ "build": "tsdown",
95
+ "ci": "pnpm run lint && pnpm run check-types && pnpm run check-types:examples && pnpm run test:coverage && pnpm run build && pnpm exec size-limit && pnpm run check:package",
96
+ "check:package": "pnpm run check:package:npm && pnpm run check:package:jsr",
97
+ "check:package:jsr": "pnpm dlx jsr publish --dry-run --allow-dirty",
98
+ "check:package:npm": "HUSKY=0 npm_config_cache=/tmp/umsizi-npm-cache npm pack --dry-run --ignore-scripts",
99
+ "dev": "tsdown --watch",
100
+ "format": "biome format --write .",
101
+ "lint": "biome check .",
102
+ "lint:fix": "biome check --write .",
103
+ "check-types": "tsc --noEmit",
104
+ "check-types:examples": "tsc --noEmit --project tsconfig.json --pretty false",
105
+ "release:publish": "pnpm run build && pnpm exec changeset publish && pnpm dlx jsr publish --allow-dirty",
106
+ "release:version": "pnpm exec changeset version && node ./scripts/sync-release-version.mjs",
107
+ "test": "vitest run",
108
+ "test:coverage": "vitest run --coverage",
109
+ "size": "pnpm run build && size-limit"
110
+ }
111
+ }
@@ -1,5 +0,0 @@
1
- //#region src/node/has-file-extension.d.ts
2
- declare function hasFileExtension(filePath: string, extension: string): boolean;
3
- //#endregion
4
- export { hasFileExtension as t };
5
- //# sourceMappingURL=index-Bi-DJKKn.d.ts.map
@@ -1,5 +0,0 @@
1
- //#region src/next/normalize-pathname.d.ts
2
- declare function normalizePathname(pathname: string): string;
3
- //#endregion
4
- export { normalizePathname as t };
5
- //# sourceMappingURL=index-Cfup-UnB.d.ts.map
@@ -1,5 +0,0 @@
1
- //#region src/react/is-render-function.d.ts
2
- declare function isRenderFunction(value: unknown): value is (...args: readonly unknown[]) => unknown;
3
- //#endregion
4
- export { isRenderFunction as t };
5
- //# sourceMappingURL=index-uHJbGgdS.d.ts.map
@@ -1,11 +0,0 @@
1
- //#region src/next/normalize-pathname.ts
2
- function normalizePathname(pathname) {
3
- if (pathname === "") return "/";
4
- const normalized = pathname.replace(/\/{2,}/g, "/").replace(/\/$/, "");
5
- if (normalized === "") return "/";
6
- return normalized.startsWith("/") ? normalized : `/${normalized}`;
7
- }
8
-
9
- //#endregion
10
- export { normalizePathname as t };
11
- //# sourceMappingURL=next-B9pvCR1P.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"next-B9pvCR1P.js","names":[],"sources":["../src/next/normalize-pathname.ts"],"sourcesContent":["export function normalizePathname(pathname: string): string {\n\tif (pathname === \"\") {\n\t\treturn \"/\";\n\t}\n\n\tconst normalized = pathname.replace(/\\/{2,}/g, \"/\").replace(/\\/$/, \"\");\n\n\tif (normalized === \"\") {\n\t\treturn \"/\";\n\t}\n\n\treturn normalized.startsWith(\"/\") ? normalized : `/${normalized}`;\n}\n"],"mappings":";AAAA,SAAgB,kBAAkB,UAA0B;AAC3D,KAAI,aAAa,GAChB,QAAO;CAGR,MAAM,aAAa,SAAS,QAAQ,WAAW,IAAI,CAAC,QAAQ,OAAO,GAAG;AAEtE,KAAI,eAAe,GAClB,QAAO;AAGR,QAAO,WAAW,WAAW,IAAI,GAAG,aAAa,IAAI"}
@@ -1,9 +0,0 @@
1
- //#region src/node/has-file-extension.ts
2
- function hasFileExtension(filePath, extension) {
3
- const normalizedExtension = extension.startsWith(".") ? extension : `.${extension}`;
4
- return filePath.endsWith(normalizedExtension);
5
- }
6
-
7
- //#endregion
8
- export { hasFileExtension as t };
9
- //# sourceMappingURL=node-Di-uva1n.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"node-Di-uva1n.js","names":[],"sources":["../src/node/has-file-extension.ts"],"sourcesContent":["export function hasFileExtension(filePath: string, extension: string): boolean {\n\tconst normalizedExtension = extension.startsWith(\".\")\n\t\t? extension\n\t\t: `.${extension}`;\n\n\treturn filePath.endsWith(normalizedExtension);\n}\n"],"mappings":";AAAA,SAAgB,iBAAiB,UAAkB,WAA4B;CAC9E,MAAM,sBAAsB,UAAU,WAAW,IAAI,GAClD,YACA,IAAI;AAEP,QAAO,SAAS,SAAS,oBAAoB"}
@@ -1,8 +0,0 @@
1
- //#region src/react/is-render-function.ts
2
- function isRenderFunction(value) {
3
- return typeof value === "function";
4
- }
5
-
6
- //#endregion
7
- export { isRenderFunction as t };
8
- //# sourceMappingURL=react-DPRQiKYh.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"react-DPRQiKYh.js","names":[],"sources":["../src/react/is-render-function.ts"],"sourcesContent":["export function isRenderFunction(\n\tvalue: unknown,\n): value is (...args: readonly unknown[]) => unknown {\n\treturn typeof value === \"function\";\n}\n"],"mappings":";AAAA,SAAgB,iBACf,OACoD;AACpD,QAAO,OAAO,UAAU"}