Skip to content

Commit 635a75f

Browse files
committed
feat!: migrate to arktype
1 parent 254e8c7 commit 635a75f

File tree

7 files changed

+89
-71
lines changed

7 files changed

+89
-71
lines changed

.vscode/settings.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
// allow autocomplete for ArkType expressions like "string | num"
3+
"editor.quickSuggestions": {
4+
"strings": "on"
5+
},
6+
// prioritize ArkType's "type" for autoimports
7+
"typescript.preferences.autoImportSpecifierExcludeRegexes": [
8+
"^(node:)?os$"
9+
]
10+
}

src/generators/emoji-test.ts

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,38 @@
1-
import { z } from "zod";
1+
import { type } from "arktype";
22
import bundledFlags from "../bundled-json-files/emoji-test-flags.json" with { type: "json" };
33
import bundledSmileys from "../bundled-json-files/emoji-test-smileys.json" with { type: "json" };
44
import { createLoom } from "../loom";
55

6+
// eslint-disable-next-line unused-imports/no-unused-vars
67
const VALID_STATUS = [
78
"component",
89
"fully-qualified",
910
"minimally-qualified",
1011
"unqualified",
1112
] as const;
1213

13-
const entry = z.object({
14-
codePoints: z.array(z.string()),
14+
const entrySchema = type({
15+
codePoints: "string[]",
1516
// can't use union of literals since typescript can only infer
1617
// the status type to a string, and not the union of literals
17-
status: z.string().refine(
18-
(val) => VALID_STATUS.includes(val as (typeof VALID_STATUS)[number]),
19-
{
20-
message: `status must be one of: ${VALID_STATUS.join(", ")}`,
21-
},
22-
),
23-
comment: z.string(),
18+
status: "string",
19+
comment: "string",
2420
});
2521

26-
const emojiTestInputSchema = z.object({
27-
group: z.string(),
28-
subgroups: z.array(z.object({
29-
subgroup: z.string(),
30-
entries: z.array(entry),
31-
})),
22+
const subgroupEntrySchema = type({
23+
subgroup: "string",
24+
entries: entrySchema.array(),
3225
});
3326

34-
const emojiTestOptionsSchema = z.object({
35-
separator: z.string(),
36-
commentPrefix: z.string(),
37-
version: z.string(),
27+
const emojiTestInputSchema = type({
28+
group: "string",
29+
subgroups: subgroupEntrySchema.array(),
30+
});
31+
32+
const emojiTestOptionsSchema = type({
33+
separator: "string",
34+
commentPrefix: "string",
35+
version: "string",
3836
});
3937

4038
export const emojiTest = createLoom({

src/generators/sequences.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
1-
import { z } from "zod";
1+
import { type } from "arktype";
22
import { createLoom } from "../loom";
33

4-
const sequencesInputSchema = z.object({
5-
codePoints: z.array(z.string()),
6-
type: z.string(),
7-
description: z.string(),
8-
comment: z.string(),
4+
const ark_sequencesInputSchema = type({
5+
codePoints: "string[]",
6+
type: "string",
7+
description: "string",
8+
comment: "string",
99
});
1010

11-
const sequencesOptionsSchema = z.object({
12-
separator: z.string(),
13-
commentPrefix: z.string(),
14-
version: z.string(),
11+
const ark_sequencesOptionsSchema = type({
12+
separator: "string",
13+
commentPrefix: "string",
14+
version: "string",
1515
});
1616

1717
export const sequences = createLoom({
18-
inputSchema: sequencesInputSchema,
19-
optionsSchema: sequencesOptionsSchema,
18+
inputSchema: ark_sequencesInputSchema,
19+
optionsSchema: ark_sequencesOptionsSchema,
2020
template: (ctx, item) => {
21+
// ^?
2122
return `${item.codePoints.join(" ")} ${ctx.options.separator} ${item.type} ${ctx.options.separator} ${item.description} ${ctx.options.commentPrefix} ${item.comment}`;
2223
},
2324
});

src/generators/zwj-sequences.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import { z } from "zod";
1+
import { type } from "arktype";
22
import { createLoom } from "../loom";
33

4-
const zwjSequencesInputSchema = z.object({
5-
codePoints: z.array(z.string()),
6-
type: z.string(),
7-
description: z.string(),
8-
comment: z.string(),
4+
const zwjSequencesInputSchema = type({
5+
codePoints: "string[]",
6+
type: "string",
7+
description: "string",
8+
comment: "string",
99
});
1010

11-
const zwjSequencesOptionsSchema = z.object({
12-
separator: z.string(),
13-
commentPrefix: z.string(),
14-
version: z.string(),
11+
const zwjSequencesOptionsSchema = type({
12+
separator: "string",
13+
commentPrefix: "string",
14+
version: "string",
1515
});
1616

1717
export const zwjSequences = createLoom({

src/loom.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
import type { LoomConfig, LoomContext, LoomInstance } from "./types";
2+
import { type } from "arktype";
23
import { compare } from "compare-versions";
34
import { z } from "zod";
45

6+
function _validate<T extends type.Any>(value: T["infer"], schema: T): T["infer"] {
7+
const out = schema(value);
8+
if (out instanceof type.errors) {
9+
throw new TypeError(out.summary);
10+
}
11+
return out;
12+
}
13+
514
export function createLoom<
6-
TInputSchema extends z.ZodType,
7-
TOptionsSchema extends z.ZodType,
8-
TPresets extends Record<string, TInputSchema["_input"][]>,
15+
TInputSchema extends type.Any,
16+
TOptionsSchema extends type.Any,
17+
TPresets extends Record<string, TInputSchema["infer"][]>,
918
>(
1019
config: LoomConfig<TInputSchema, TOptionsSchema, TPresets>,
1120
): LoomInstance<TInputSchema, TOptionsSchema, TPresets> {
1221
const baseLoomFn = (
13-
options: TOptionsSchema["_input"] & { input: TInputSchema["_input"][] },
22+
options: TOptionsSchema["infer"] & { input: TInputSchema["infer"][] },
1423
): string => {
1524
// validate options against schema
16-
const validatedOptions = config.optionsSchema.parse(options);
25+
const validatedOptions = _validate(options, config.optionsSchema);
1726

18-
// validate input against schema
19-
const validatedInput = z.array(config.inputSchema).parse(options.input);
27+
const validatedInput = _validate(options.input, config.inputSchema.array());
2028

2129
// create context for template
2230
const ctx: LoomContext<TOptionsSchema> = Object.freeze(
@@ -49,7 +57,7 @@ export function createLoom<
4957
? Object.fromEntries(
5058
Object.entries(config.presets).map(([key, value]) => [
5159
key,
52-
(options: TOptionsSchema["_input"]) =>
60+
(options: TOptionsSchema["infer"]) =>
5361
baseLoomFn({ ...options, input: value }),
5462
]),
5563
)
@@ -62,8 +70,8 @@ export function createLoom<
6270
>;
6371
}
6472

65-
function buildLoomContext<TOptionsSchema extends z.ZodType>(
66-
options: TOptionsSchema["_input"],
73+
function buildLoomContext<TOptionsSchema extends type.Any>(
74+
options: TOptionsSchema["infer"],
6775
): LoomContext<TOptionsSchema> {
6876
return {
6977
options,

src/types.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { type } from "arktype";
12
import type { z } from "zod";
23

34
export type LoomContextHelperFn = (version: string) => boolean;
@@ -29,17 +30,17 @@ export interface LoomContextHelpers {
2930
isVersionLessThanOrEqual: LoomContextHelperFn;
3031
}
3132

32-
export interface LoomContext<TOptionsSchema extends z.ZodType> extends LoomContextHelpers {
33+
export interface LoomContext<TOptionsSchema extends type.Any> extends LoomContextHelpers {
3334
/**
3435
* The options.
3536
*/
36-
options: TOptionsSchema["_input"];
37+
options: TOptionsSchema["infer"];
3738
}
3839

3940
export interface LoomConfig<
40-
TInputSchema extends z.ZodType,
41-
TOptionsSchema extends z.ZodType,
42-
TPresets extends Record<string, TInputSchema["_input"][]>,
41+
TInputSchema extends type.Any,
42+
TOptionsSchema extends type.Any,
43+
TPresets extends Record<string, TInputSchema["infer"][]>,
4344
> {
4445
/**
4546
* The schema of the input data.
@@ -56,7 +57,7 @@ export interface LoomConfig<
5657
*/
5758
template: (
5859
ctx: LoomContext<TOptionsSchema>,
59-
item: TInputSchema["_input"]
60+
item: TInputSchema["infer"]
6061
) => string;
6162

6263
/**
@@ -67,7 +68,7 @@ export interface LoomConfig<
6768
/**
6869
* The predicate function. If provided, the loom will only process items that return true.
6970
*/
70-
predicate?: (ctx: LoomContext<TOptionsSchema>, item: TInputSchema["_input"]) => boolean;
71+
predicate?: (ctx: LoomContext<TOptionsSchema>, item: TInputSchema["infer"]) => boolean;
7172

7273
/**
7374
* Attach custom presets to the loom.
@@ -76,11 +77,11 @@ export interface LoomConfig<
7677
}
7778

7879
export type LoomInstance<
79-
TInputSchema extends z.ZodType,
80-
TOptionsSchema extends z.ZodType,
81-
TPresets extends Record<string, TInputSchema["_input"][]>,
80+
TInputSchema extends type.Any,
81+
TOptionsSchema extends type.Any,
82+
TPresets extends Record<string, TInputSchema["infer"][]>,
8283
> = {
83-
(options: TOptionsSchema["_input"] & { input: TInputSchema["_input"][] }): string;
84+
(options: TOptionsSchema["infer"] & { input: TInputSchema["infer"][] }): string;
8485
} & {
85-
[key in keyof TPresets]: (options: TOptionsSchema["_input"]) => string;
86+
[key in keyof TPresets]: (options: TOptionsSchema["infer"]) => string;
8687
};

test/loom.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1+
import { type } from "arktype";
12
import { expect, it } from "vitest";
2-
import { z } from "zod";
33
import { createLoom } from "../src/loom";
44

5-
const testInputSchema = z.object({
6-
name: z.string(),
7-
value: z.number(),
5+
const testInputSchema = type({
6+
name: "string",
7+
value: "number",
88
});
99

10-
const testOptionsSchema = z.object({
11-
version: z.string(),
12-
prefix: z.string(),
10+
const testOptionsSchema = type({
11+
version: "string",
12+
prefix: "string",
1313
});
1414

1515
it("should create a loom instance that processes input correctly", () => {

0 commit comments

Comments
 (0)