nalloc 0.2.2 → 0.5.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 +326 -178
- package/build/codemod-cli.cjs +153 -0
- package/build/codemod-cli.cjs.map +1 -0
- package/build/codemod-cli.d.ts +2 -0
- package/build/codemod-cli.js +103 -0
- package/build/codemod-cli.js.map +1 -0
- package/build/codemod.cjs +652 -0
- package/build/codemod.cjs.map +1 -0
- package/build/codemod.d.ts +29 -0
- package/build/codemod.js +634 -0
- package/build/codemod.js.map +1 -0
- package/build/eslint.cjs +221 -0
- package/build/eslint.cjs.map +1 -0
- package/build/eslint.d.ts +36 -0
- package/build/eslint.js +198 -0
- package/build/eslint.js.map +1 -0
- package/build/http.cjs +31 -0
- package/build/http.cjs.map +1 -0
- package/build/http.d.ts +31 -0
- package/build/http.js +13 -0
- package/build/http.js.map +1 -0
- package/build/nonempty.cjs +35 -0
- package/build/nonempty.cjs.map +1 -0
- package/build/nonempty.d.ts +34 -0
- package/build/nonempty.js +14 -0
- package/build/nonempty.js.map +1 -0
- package/build/option.cjs +1 -1
- package/build/option.cjs.map +1 -1
- package/build/option.d.ts +2 -2
- package/build/option.js +1 -1
- package/build/option.js.map +1 -1
- package/build/result.cjs +10 -18
- package/build/result.cjs.map +1 -1
- package/build/result.d.ts +3 -34
- package/build/result.js +10 -15
- package/build/result.js.map +1 -1
- package/build/safe.cjs +8 -0
- package/build/safe.cjs.map +1 -1
- package/build/safe.d.ts +3 -0
- package/build/safe.js +2 -0
- package/build/safe.js.map +1 -1
- package/build/schema.cjs +32 -0
- package/build/schema.cjs.map +1 -0
- package/build/schema.d.ts +44 -0
- package/build/schema.js +14 -0
- package/build/schema.js.map +1 -0
- package/package.json +63 -10
- package/src/__tests__/codemod.ts +211 -0
- package/src/__tests__/eslint.ts +99 -0
- package/src/__tests__/fixtures/tsconfig.json +10 -0
- package/src/__tests__/http.ts +64 -0
- package/src/__tests__/iter.ts +18 -0
- package/src/__tests__/nonempty.ts +46 -0
- package/src/__tests__/nonempty.types.ts +38 -0
- package/src/__tests__/option.ts +4 -0
- package/src/__tests__/result.ts +104 -129
- package/src/__tests__/result.types.ts +2 -2
- package/src/__tests__/schema.ts +58 -0
- package/src/codemod-cli.ts +108 -0
- package/src/codemod.ts +623 -0
- package/src/eslint.ts +145 -0
- package/src/http.ts +42 -0
- package/src/nonempty.ts +48 -0
- package/src/option.ts +3 -4
- package/src/result.ts +18 -49
- package/src/safe.ts +3 -0
- package/src/schema.ts +52 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
|
+
import { fromResponse, fromFetch } from '../http.js';
|
|
3
|
+
import { isOk, isErr } from '../types.js';
|
|
4
|
+
|
|
5
|
+
describe('http', () => {
|
|
6
|
+
describe('fromResponse', () => {
|
|
7
|
+
it('returns Ok carrying the response for a 2xx status', () => {
|
|
8
|
+
const response = new Response('ok', { status: 200 });
|
|
9
|
+
const result = fromResponse(response);
|
|
10
|
+
expect(isOk(result)).toBe(true);
|
|
11
|
+
expect(result).toBe(response);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('returns Err carrying the response for a non-2xx status', () => {
|
|
15
|
+
const response = new Response('nope', { status: 404 });
|
|
16
|
+
const result = fromResponse(response);
|
|
17
|
+
expect(isErr(result)).toBe(true);
|
|
18
|
+
expect((result as { error: Response }).error).toBe(response);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('fromFetch', () => {
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
vi.unstubAllGlobals();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('returns Ok carrying the response for a 2xx status', async () => {
|
|
28
|
+
const response = new Response('ok', { status: 200 });
|
|
29
|
+
const fetchMock = vi.fn().mockResolvedValue(response);
|
|
30
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
31
|
+
const init = { method: 'POST' };
|
|
32
|
+
const result = await fromFetch('https://example.test', init);
|
|
33
|
+
expect(isOk(result)).toBe(true);
|
|
34
|
+
expect(result).toBe(response);
|
|
35
|
+
expect(fetchMock).toHaveBeenCalledWith('https://example.test', init);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns Err carrying the response for a non-2xx status', async () => {
|
|
39
|
+
const response = new Response('nope', { status: 500 });
|
|
40
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(response));
|
|
41
|
+
const result = await fromFetch('https://example.test');
|
|
42
|
+
expect(isErr(result)).toBe(true);
|
|
43
|
+
expect((result as { error: Response }).error).toBe(response);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('returns Err carrying the thrown value on transport failure', async () => {
|
|
47
|
+
const failure = new TypeError('fetch failed');
|
|
48
|
+
vi.stubGlobal('fetch', vi.fn().mockRejectedValue(failure));
|
|
49
|
+
const result = await fromFetch('https://example.test');
|
|
50
|
+
expect(isErr(result)).toBe(true);
|
|
51
|
+
expect((result as { error: unknown }).error).toBe(failure);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('returns Err with an AbortError DOMException for a pre-aborted signal', async () => {
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
controller.abort();
|
|
57
|
+
const result = await fromFetch('http://127.0.0.1:1', { signal: controller.signal });
|
|
58
|
+
expect(isErr(result)).toBe(true);
|
|
59
|
+
const error = (result as { error: unknown }).error;
|
|
60
|
+
expect(error).toBeInstanceOf(DOMException);
|
|
61
|
+
expect((error as DOMException).name).toBe('AbortError');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
package/src/__tests__/iter.ts
CHANGED
|
@@ -96,6 +96,24 @@ describe('Iter', () => {
|
|
|
96
96
|
expect(returned).toBe(true);
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
+
it('return() after exhaustion is a no-op', () => {
|
|
100
|
+
let returnCalls = 0;
|
|
101
|
+
const iter: Iterable<number> = {
|
|
102
|
+
[Symbol.iterator]: () => {
|
|
103
|
+
let i = 0;
|
|
104
|
+
return {
|
|
105
|
+
next() { return i++ < 1 ? { value: i, done: false } : { value: undefined as unknown as number, done: true }; },
|
|
106
|
+
return() { returnCalls++; return { value: undefined, done: true }; },
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
const gen = safeIter(iter);
|
|
111
|
+
expect([...gen]).toHaveLength(1);
|
|
112
|
+
const final = gen.return!(undefined as never);
|
|
113
|
+
expect(final.done).toBe(true);
|
|
114
|
+
expect(returnCalls).toBe(0);
|
|
115
|
+
});
|
|
116
|
+
|
|
99
117
|
it('yields values then stops on throw', () => {
|
|
100
118
|
function* twoThenThrow() {
|
|
101
119
|
yield 1;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { isNonEmpty, assertNonEmpty, fromArray } from '../nonempty.js';
|
|
3
|
+
import { isSome, isNone } from '../types.js';
|
|
4
|
+
|
|
5
|
+
describe('NonEmpty', () => {
|
|
6
|
+
describe('isNonEmpty', () => {
|
|
7
|
+
it('returns false for an empty array', () => {
|
|
8
|
+
expect(isNonEmpty([])).toBe(false);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('returns true for a single-element array', () => {
|
|
12
|
+
expect(isNonEmpty([1])).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('returns true for a multi-element array', () => {
|
|
16
|
+
expect(isNonEmpty([1, 2, 3])).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('assertNonEmpty', () => {
|
|
21
|
+
it('throws on an empty array', () => {
|
|
22
|
+
expect(() => assertNonEmpty([])).toThrow('Expected array to be non-empty');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('throws with a custom message', () => {
|
|
26
|
+
expect(() => assertNonEmpty([], 'nope')).toThrow('nope');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('does not throw on a non-empty array', () => {
|
|
30
|
+
expect(() => assertNonEmpty([1])).not.toThrow();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('fromArray', () => {
|
|
35
|
+
it('returns None for an empty array', () => {
|
|
36
|
+
expect(isNone(fromArray([]))).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('returns Some wrapping the same array value for a non-empty array', () => {
|
|
40
|
+
const input = [1, 2];
|
|
41
|
+
const result = fromArray(input);
|
|
42
|
+
expect(isSome(result)).toBe(true);
|
|
43
|
+
expect(result).toBe(input);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { assert, type Equals } from 'tsafe';
|
|
2
|
+
import {
|
|
3
|
+
isNonEmpty,
|
|
4
|
+
assertNonEmpty,
|
|
5
|
+
fromArray,
|
|
6
|
+
type NonEmptyArray,
|
|
7
|
+
type ReadonlyNonEmptyArray,
|
|
8
|
+
} from '../nonempty.js';
|
|
9
|
+
import type { Option } from '../types.js';
|
|
10
|
+
|
|
11
|
+
const readonlyValues: readonly number[] = [1, 2, 3];
|
|
12
|
+
const mutableValues: number[] = [1, 2, 3];
|
|
13
|
+
|
|
14
|
+
if (isNonEmpty(readonlyValues)) {
|
|
15
|
+
assert<Equals<typeof readonlyValues, ReadonlyNonEmptyArray<number>>>;
|
|
16
|
+
const _head: number = readonlyValues[0];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (isNonEmpty(mutableValues)) {
|
|
20
|
+
const _head: number = mutableValues[0];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const asserted: readonly number[] = [1];
|
|
24
|
+
assertNonEmpty(asserted);
|
|
25
|
+
assert<Equals<typeof asserted, ReadonlyNonEmptyArray<number>>>;
|
|
26
|
+
const _assertedHead: number = asserted[0];
|
|
27
|
+
|
|
28
|
+
const maybeNonEmpty = fromArray<number>([1, 2]);
|
|
29
|
+
assert<Equals<typeof maybeNonEmpty, Option<ReadonlyNonEmptyArray<number>>>>;
|
|
30
|
+
|
|
31
|
+
const fromEmpty = fromArray([] as const);
|
|
32
|
+
assert<Equals<typeof fromEmpty, Option<ReadonlyNonEmptyArray<never>>>>;
|
|
33
|
+
|
|
34
|
+
type _MutableShape = Equals<NonEmptyArray<number>, [number, ...number[]]>;
|
|
35
|
+
assert<_MutableShape>;
|
|
36
|
+
|
|
37
|
+
type _ReadonlyShape = Equals<ReadonlyNonEmptyArray<number>, readonly [number, ...number[]]>;
|
|
38
|
+
assert<_ReadonlyShape>;
|
package/src/__tests__/option.ts
CHANGED
|
@@ -426,6 +426,10 @@ describe('Option', () => {
|
|
|
426
426
|
it('returns false for None', () => {
|
|
427
427
|
expect(contains(none, 42)).toBe(false);
|
|
428
428
|
});
|
|
429
|
+
|
|
430
|
+
it('treats NaN as equal to NaN', () => {
|
|
431
|
+
expect(contains(of(NaN), NaN)).toBe(true);
|
|
432
|
+
});
|
|
429
433
|
});
|
|
430
434
|
|
|
431
435
|
describe('isSomeAnd', () => {
|