decoders 2.4.2 → 2.6.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/dist/index.cjs CHANGED
@@ -242,6 +242,41 @@ ${annotation}`;
242
242
  function formatShort(ann) {
243
243
  return summarize(ann, []).join("\n");
244
244
  }
245
+ function* iterAnnotation(ann, stack) {
246
+ if (ann.text) {
247
+ if (stack.length > 0) {
248
+ yield { message: ann.text, path: [...stack] };
249
+ } else {
250
+ yield { message: ann.text };
251
+ }
252
+ }
253
+ switch (ann.type) {
254
+ case "array": {
255
+ let index = 0;
256
+ for (const item of ann.items) {
257
+ stack.push(index++);
258
+ yield* iterAnnotation(item, stack);
259
+ stack.pop();
260
+ }
261
+ break;
262
+ }
263
+ case "object": {
264
+ for (const [key, value] of ann.fields) {
265
+ stack.push(key);
266
+ yield* iterAnnotation(value, stack);
267
+ stack.pop();
268
+ }
269
+ break;
270
+ }
271
+ case "scalar":
272
+ case "opaque": {
273
+ break;
274
+ }
275
+ }
276
+ }
277
+ function formatAsIssues(ann) {
278
+ return Array.from(iterAnnotation(ann, []));
279
+ }
245
280
 
246
281
  // src/core/Result.ts
247
282
  function ok(value) {
@@ -342,7 +377,20 @@ function define(fn) {
342
377
  reject,
343
378
  describe,
344
379
  then,
345
- pipe
380
+ pipe,
381
+ "~standard": {
382
+ version: 1,
383
+ vendor: "decoders",
384
+ validate: (blob) => {
385
+ const result = decode(blob);
386
+ if (result.ok) {
387
+ return { value: result.value };
388
+ } else {
389
+ const issues = formatAsIssues(result.error);
390
+ return { issues };
391
+ }
392
+ }
393
+ }
346
394
  });
347
395
  }
348
396
  var _register2 = /* @__PURE__ */ new WeakSet();
@@ -709,6 +757,18 @@ var nonEmptyString = regex(/\S/, "Must be non-empty string");
709
757
  function regex(regex2, msg) {
710
758
  return string.refine((s) => regex2.test(s), msg);
711
759
  }
760
+ function startsWith(prefix) {
761
+ return string.refine(
762
+ (s) => s.startsWith(prefix),
763
+ `Must start with '${prefix}'`
764
+ );
765
+ }
766
+ function endsWith(suffix) {
767
+ return string.refine(
768
+ (s) => s.endsWith(suffix),
769
+ `Must end with '${suffix}'`
770
+ );
771
+ }
712
772
  var email = regex(
713
773
  // The almost perfect email regex, taken from https://emailregex.com/
714
774
  /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
@@ -873,4 +933,6 @@ var json = either(
873
933
 
874
934
 
875
935
 
876
- exports.always = always; exports.anyNumber = anyNumber; exports.array = array; exports.bigint = bigint; exports.boolean = boolean; exports.constant = constant; exports.date = date; exports.datelike = datelike; exports.decimal = decimal; exports.define = define; exports.dict = dict; exports.either = either; exports.email = email; exports.enum_ = enum_; exports.err = err; exports.exact = exact; exports.fail = fail; exports.formatInline = formatInline; exports.formatShort = formatShort; exports.hardcoded = hardcoded; exports.hexadecimal = hexadecimal; exports.httpsUrl = httpsUrl; exports.identifier = identifier; exports.inexact = inexact; exports.instanceOf = instanceOf; exports.integer = integer; exports.iso8601 = iso8601; exports.json = json; exports.jsonArray = jsonArray; exports.jsonObject = jsonObject; exports.lazy = lazy; exports.mapping = mapping; exports.maybe = maybe; exports.mixed = mixed; exports.nanoid = nanoid; exports.never = never; exports.nonEmptyArray = nonEmptyArray; exports.nonEmptyString = nonEmptyString; exports.null_ = null_; exports.nullable = nullable; exports.nullish = nullish; exports.number = number; exports.numeric = numeric; exports.object = object; exports.ok = ok; exports.oneOf = oneOf; exports.optional = optional; exports.poja = poja; exports.pojo = pojo; exports.positiveInteger = positiveInteger; exports.positiveNumber = positiveNumber; exports.prep = prep; exports.record = record; exports.regex = regex; exports.select = select; exports.set = set; exports.setFromArray = setFromArray; exports.string = string; exports.taggedUnion = taggedUnion; exports.truthy = truthy; exports.tuple = tuple; exports.undefined_ = undefined_; exports.unknown = unknown; exports.url = url; exports.uuid = uuid; exports.uuidv1 = uuidv1; exports.uuidv4 = uuidv4;
936
+
937
+
938
+ exports.always = always; exports.anyNumber = anyNumber; exports.array = array; exports.bigint = bigint; exports.boolean = boolean; exports.constant = constant; exports.date = date; exports.datelike = datelike; exports.decimal = decimal; exports.define = define; exports.dict = dict; exports.either = either; exports.email = email; exports.endsWith = endsWith; exports.enum_ = enum_; exports.err = err; exports.exact = exact; exports.fail = fail; exports.formatInline = formatInline; exports.formatShort = formatShort; exports.hardcoded = hardcoded; exports.hexadecimal = hexadecimal; exports.httpsUrl = httpsUrl; exports.identifier = identifier; exports.inexact = inexact; exports.instanceOf = instanceOf; exports.integer = integer; exports.iso8601 = iso8601; exports.json = json; exports.jsonArray = jsonArray; exports.jsonObject = jsonObject; exports.lazy = lazy; exports.mapping = mapping; exports.maybe = maybe; exports.mixed = mixed; exports.nanoid = nanoid; exports.never = never; exports.nonEmptyArray = nonEmptyArray; exports.nonEmptyString = nonEmptyString; exports.null_ = null_; exports.nullable = nullable; exports.nullish = nullish; exports.number = number; exports.numeric = numeric; exports.object = object; exports.ok = ok; exports.oneOf = oneOf; exports.optional = optional; exports.poja = poja; exports.pojo = pojo; exports.positiveInteger = positiveInteger; exports.positiveNumber = positiveNumber; exports.prep = prep; exports.record = record; exports.regex = regex; exports.select = select; exports.set = set; exports.setFromArray = setFromArray; exports.startsWith = startsWith; exports.string = string; exports.taggedUnion = taggedUnion; exports.truthy = truthy; exports.tuple = tuple; exports.undefined_ = undefined_; exports.unknown = unknown; exports.url = url; exports.uuid = uuid; exports.uuidv1 = uuidv1; exports.uuidv4 = uuidv4;
package/dist/index.d.cts CHANGED
@@ -45,6 +45,62 @@ declare function ok<T>(value: T): Ok<T>;
45
45
  */
46
46
  declare function err<E>(error: E): Err<E>;
47
47
 
48
+ /** The Standard Schema interface. */
49
+ interface StandardSchemaV1<Input = unknown, Output = Input> {
50
+ /** The Standard Schema properties. */
51
+ readonly '~standard': StandardSchemaV1.Props<Input, Output>;
52
+ }
53
+ declare namespace StandardSchemaV1 {
54
+ /** The Standard Schema properties interface. */
55
+ interface Props<Input = unknown, Output = Input> {
56
+ /** The version number of the standard. */
57
+ readonly version: 1;
58
+ /** The vendor name of the schema library. */
59
+ readonly vendor: string;
60
+ /** Validates unknown input values. */
61
+ readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
62
+ /** Inferred types associated with the schema. */
63
+ readonly types?: Types<Input, Output> | undefined;
64
+ }
65
+ /** The result interface of the validate function. */
66
+ type Result<Output> = SuccessResult<Output> | FailureResult;
67
+ /** The result interface if validation succeeds. */
68
+ interface SuccessResult<Output> {
69
+ /** The typed output value. */
70
+ readonly value: Output;
71
+ /** The non-existent issues. */
72
+ readonly issues?: undefined;
73
+ }
74
+ /** The result interface if validation fails. */
75
+ interface FailureResult {
76
+ /** The issues of failed validation. */
77
+ readonly issues: ReadonlyArray<Issue>;
78
+ }
79
+ /** The issue interface of the failure output. */
80
+ interface Issue {
81
+ /** The error message of the issue. */
82
+ readonly message: string;
83
+ /** The path of the issue, if any. */
84
+ readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
85
+ }
86
+ /** The path segment interface of the issue. */
87
+ interface PathSegment {
88
+ /** The key representing a path segment. */
89
+ readonly key: PropertyKey;
90
+ }
91
+ /** The Standard Schema types interface. */
92
+ interface Types<Input = unknown, Output = Input> {
93
+ /** The input type of the schema. */
94
+ readonly input: Input;
95
+ /** The output type of the schema. */
96
+ readonly output: Output;
97
+ }
98
+ /** Infers the input type of a Standard Schema. */
99
+ type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input'];
100
+ /** Infers the output type of a Standard Schema. */
101
+ type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output'];
102
+ }
103
+
48
104
  type DecodeResult<T> = Result<T, Annotation>;
49
105
  /**
50
106
  * A function taking a untrusted input, and returning a DecodeResult<T>. The
@@ -114,6 +170,10 @@ interface Decoder<T> {
114
170
  */
115
171
  pipe<V, D extends Decoder<V>>(next: D): Decoder<DecoderType<D>>;
116
172
  pipe<V, D extends Decoder<V>>(next: (blob: T) => D): Decoder<DecoderType<D>>;
173
+ /**
174
+ * The Standard Schema interface for this decoder.
175
+ */
176
+ '~standard': StandardSchemaV1.Props<unknown, T>;
117
177
  }
118
178
  /**
119
179
  * Helper type to return the output type of a Decoder.
@@ -476,6 +536,14 @@ declare const nonEmptyString: Decoder<string>;
476
536
  * Accepts and returns strings that match the given regular expression.
477
537
  */
478
538
  declare function regex(regex: RegExp, msg: string): Decoder<string>;
539
+ /**
540
+ * Accepts and returns strings that start with the given prefix.
541
+ */
542
+ declare function startsWith<P extends string>(prefix: P): Decoder<`${P}${string}`>;
543
+ /**
544
+ * Accepts and returns strings that end with the given suffix.
545
+ */
546
+ declare function endsWith<S extends string>(suffix: S): Decoder<`${string}${S}`>;
479
547
  /**
480
548
  * Accepts and returns strings that are syntactically valid email addresses.
481
549
  * (This will not mean that the email address actually exist.)
@@ -592,4 +660,4 @@ declare function taggedUnion<O extends Record<string, Decoder<unknown>>>(field:
592
660
  */
593
661
  declare function select<T, D extends Decoder<unknown>>(scout: Decoder<T>, selectFn: (result: T) => D): Decoder<DecoderType<D>>;
594
662
 
595
- export { type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type Ok, type Result, type Scalar, type SizeOptions, always, anyNumber, array, bigint, boolean, constant, date, datelike, decimal, define, dict, either, email, enum_, err, exact, fail, formatInline, formatShort, hardcoded, hexadecimal, httpsUrl, identifier, inexact, instanceOf, integer, iso8601, json, jsonArray, jsonObject, lazy, mapping, maybe, mixed, nanoid, never, nonEmptyArray, nonEmptyString, null_, nullable, nullish, number, numeric, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, record, regex, select, set, setFromArray, string, taggedUnion, truthy, tuple, undefined_, unknown, url, uuid, uuidv1, uuidv4 };
663
+ export { type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type Ok, type Result, type Scalar, type SizeOptions, always, anyNumber, array, bigint, boolean, constant, date, datelike, decimal, define, dict, either, email, endsWith, enum_, err, exact, fail, formatInline, formatShort, hardcoded, hexadecimal, httpsUrl, identifier, inexact, instanceOf, integer, iso8601, json, jsonArray, jsonObject, lazy, mapping, maybe, mixed, nanoid, never, nonEmptyArray, nonEmptyString, null_, nullable, nullish, number, numeric, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, record, regex, select, set, setFromArray, startsWith, string, taggedUnion, truthy, tuple, undefined_, unknown, url, uuid, uuidv1, uuidv4 };
package/dist/index.d.ts CHANGED
@@ -45,6 +45,62 @@ declare function ok<T>(value: T): Ok<T>;
45
45
  */
46
46
  declare function err<E>(error: E): Err<E>;
47
47
 
48
+ /** The Standard Schema interface. */
49
+ interface StandardSchemaV1<Input = unknown, Output = Input> {
50
+ /** The Standard Schema properties. */
51
+ readonly '~standard': StandardSchemaV1.Props<Input, Output>;
52
+ }
53
+ declare namespace StandardSchemaV1 {
54
+ /** The Standard Schema properties interface. */
55
+ interface Props<Input = unknown, Output = Input> {
56
+ /** The version number of the standard. */
57
+ readonly version: 1;
58
+ /** The vendor name of the schema library. */
59
+ readonly vendor: string;
60
+ /** Validates unknown input values. */
61
+ readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
62
+ /** Inferred types associated with the schema. */
63
+ readonly types?: Types<Input, Output> | undefined;
64
+ }
65
+ /** The result interface of the validate function. */
66
+ type Result<Output> = SuccessResult<Output> | FailureResult;
67
+ /** The result interface if validation succeeds. */
68
+ interface SuccessResult<Output> {
69
+ /** The typed output value. */
70
+ readonly value: Output;
71
+ /** The non-existent issues. */
72
+ readonly issues?: undefined;
73
+ }
74
+ /** The result interface if validation fails. */
75
+ interface FailureResult {
76
+ /** The issues of failed validation. */
77
+ readonly issues: ReadonlyArray<Issue>;
78
+ }
79
+ /** The issue interface of the failure output. */
80
+ interface Issue {
81
+ /** The error message of the issue. */
82
+ readonly message: string;
83
+ /** The path of the issue, if any. */
84
+ readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
85
+ }
86
+ /** The path segment interface of the issue. */
87
+ interface PathSegment {
88
+ /** The key representing a path segment. */
89
+ readonly key: PropertyKey;
90
+ }
91
+ /** The Standard Schema types interface. */
92
+ interface Types<Input = unknown, Output = Input> {
93
+ /** The input type of the schema. */
94
+ readonly input: Input;
95
+ /** The output type of the schema. */
96
+ readonly output: Output;
97
+ }
98
+ /** Infers the input type of a Standard Schema. */
99
+ type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input'];
100
+ /** Infers the output type of a Standard Schema. */
101
+ type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output'];
102
+ }
103
+
48
104
  type DecodeResult<T> = Result<T, Annotation>;
49
105
  /**
50
106
  * A function taking a untrusted input, and returning a DecodeResult<T>. The
@@ -114,6 +170,10 @@ interface Decoder<T> {
114
170
  */
115
171
  pipe<V, D extends Decoder<V>>(next: D): Decoder<DecoderType<D>>;
116
172
  pipe<V, D extends Decoder<V>>(next: (blob: T) => D): Decoder<DecoderType<D>>;
173
+ /**
174
+ * The Standard Schema interface for this decoder.
175
+ */
176
+ '~standard': StandardSchemaV1.Props<unknown, T>;
117
177
  }
118
178
  /**
119
179
  * Helper type to return the output type of a Decoder.
@@ -476,6 +536,14 @@ declare const nonEmptyString: Decoder<string>;
476
536
  * Accepts and returns strings that match the given regular expression.
477
537
  */
478
538
  declare function regex(regex: RegExp, msg: string): Decoder<string>;
539
+ /**
540
+ * Accepts and returns strings that start with the given prefix.
541
+ */
542
+ declare function startsWith<P extends string>(prefix: P): Decoder<`${P}${string}`>;
543
+ /**
544
+ * Accepts and returns strings that end with the given suffix.
545
+ */
546
+ declare function endsWith<S extends string>(suffix: S): Decoder<`${string}${S}`>;
479
547
  /**
480
548
  * Accepts and returns strings that are syntactically valid email addresses.
481
549
  * (This will not mean that the email address actually exist.)
@@ -592,4 +660,4 @@ declare function taggedUnion<O extends Record<string, Decoder<unknown>>>(field:
592
660
  */
593
661
  declare function select<T, D extends Decoder<unknown>>(scout: Decoder<T>, selectFn: (result: T) => D): Decoder<DecoderType<D>>;
594
662
 
595
- export { type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type Ok, type Result, type Scalar, type SizeOptions, always, anyNumber, array, bigint, boolean, constant, date, datelike, decimal, define, dict, either, email, enum_, err, exact, fail, formatInline, formatShort, hardcoded, hexadecimal, httpsUrl, identifier, inexact, instanceOf, integer, iso8601, json, jsonArray, jsonObject, lazy, mapping, maybe, mixed, nanoid, never, nonEmptyArray, nonEmptyString, null_, nullable, nullish, number, numeric, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, record, regex, select, set, setFromArray, string, taggedUnion, truthy, tuple, undefined_, unknown, url, uuid, uuidv1, uuidv4 };
663
+ export { type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type Ok, type Result, type Scalar, type SizeOptions, always, anyNumber, array, bigint, boolean, constant, date, datelike, decimal, define, dict, either, email, endsWith, enum_, err, exact, fail, formatInline, formatShort, hardcoded, hexadecimal, httpsUrl, identifier, inexact, instanceOf, integer, iso8601, json, jsonArray, jsonObject, lazy, mapping, maybe, mixed, nanoid, never, nonEmptyArray, nonEmptyString, null_, nullable, nullish, number, numeric, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, record, regex, select, set, setFromArray, startsWith, string, taggedUnion, truthy, tuple, undefined_, unknown, url, uuid, uuidv1, uuidv4 };
package/dist/index.js CHANGED
@@ -242,6 +242,41 @@ ${annotation}`;
242
242
  function formatShort(ann) {
243
243
  return summarize(ann, []).join("\n");
244
244
  }
245
+ function* iterAnnotation(ann, stack) {
246
+ if (ann.text) {
247
+ if (stack.length > 0) {
248
+ yield { message: ann.text, path: [...stack] };
249
+ } else {
250
+ yield { message: ann.text };
251
+ }
252
+ }
253
+ switch (ann.type) {
254
+ case "array": {
255
+ let index = 0;
256
+ for (const item of ann.items) {
257
+ stack.push(index++);
258
+ yield* iterAnnotation(item, stack);
259
+ stack.pop();
260
+ }
261
+ break;
262
+ }
263
+ case "object": {
264
+ for (const [key, value] of ann.fields) {
265
+ stack.push(key);
266
+ yield* iterAnnotation(value, stack);
267
+ stack.pop();
268
+ }
269
+ break;
270
+ }
271
+ case "scalar":
272
+ case "opaque": {
273
+ break;
274
+ }
275
+ }
276
+ }
277
+ function formatAsIssues(ann) {
278
+ return Array.from(iterAnnotation(ann, []));
279
+ }
245
280
 
246
281
  // src/core/Result.ts
247
282
  function ok(value) {
@@ -342,7 +377,20 @@ function define(fn) {
342
377
  reject,
343
378
  describe,
344
379
  then,
345
- pipe
380
+ pipe,
381
+ "~standard": {
382
+ version: 1,
383
+ vendor: "decoders",
384
+ validate: (blob) => {
385
+ const result = decode(blob);
386
+ if (result.ok) {
387
+ return { value: result.value };
388
+ } else {
389
+ const issues = formatAsIssues(result.error);
390
+ return { issues };
391
+ }
392
+ }
393
+ }
346
394
  });
347
395
  }
348
396
  var _register2 = /* @__PURE__ */ new WeakSet();
@@ -709,6 +757,18 @@ var nonEmptyString = regex(/\S/, "Must be non-empty string");
709
757
  function regex(regex2, msg) {
710
758
  return string.refine((s) => regex2.test(s), msg);
711
759
  }
760
+ function startsWith(prefix) {
761
+ return string.refine(
762
+ (s) => s.startsWith(prefix),
763
+ `Must start with '${prefix}'`
764
+ );
765
+ }
766
+ function endsWith(suffix) {
767
+ return string.refine(
768
+ (s) => s.endsWith(suffix),
769
+ `Must end with '${suffix}'`
770
+ );
771
+ }
712
772
  var email = regex(
713
773
  // The almost perfect email regex, taken from https://emailregex.com/
714
774
  /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
@@ -819,6 +879,7 @@ export {
819
879
  dict,
820
880
  either,
821
881
  email,
882
+ endsWith,
822
883
  enum_,
823
884
  err,
824
885
  exact,
@@ -863,6 +924,7 @@ export {
863
924
  select,
864
925
  set,
865
926
  setFromArray,
927
+ startsWith,
866
928
  string,
867
929
  taggedUnion,
868
930
  truthy,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "decoders",
3
- "version": "2.4.2",
3
+ "version": "2.6.0",
4
4
  "description": "Elegant and battle-tested validation library for type-safe input data for TypeScript",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -61,27 +61,28 @@
61
61
  "verify"
62
62
  ],
63
63
  "devDependencies": {
64
- "@arethetypeswrong/cli": "^0.15.3",
65
- "@release-it/keep-a-changelog": "^5.0.0",
64
+ "@arethetypeswrong/cli": "^0.17.3",
65
+ "@release-it/keep-a-changelog": "^6.0.0",
66
+ "@standard-schema/spec": "^1.0.0",
66
67
  "@types/eslint": "^8.56.10",
67
68
  "@typescript-eslint/eslint-plugin": "^7.14.1",
68
69
  "@typescript-eslint/parser": "^7.14.1",
69
- "@vitest/coverage-istanbul": "^1.6.0",
70
+ "@vitest/coverage-istanbul": "^3.0.5",
70
71
  "eslint": "^8.57.0",
71
72
  "eslint-plugin-import": "^2.29.1",
72
73
  "eslint-plugin-simple-import-sort": "^12.1.0",
73
- "fast-check": "^3.19.0",
74
+ "fast-check": "^3.23.2",
74
75
  "itertools": "^2.3.2",
75
- "pkg-pr-new": "^0.0.9",
76
- "prettier": "^3.3.2",
77
- "publint": "^0.2.8",
78
- "release-it": "^17.4.0",
79
- "ts-morph": "^23.0.0",
80
- "tsd": "^0.31.1",
81
- "tsup": "^8.1.0",
82
- "typescript": "^5.5.2",
83
- "vite-tsconfig-paths": "^4.3.2",
84
- "vitest": "^1.6.0"
76
+ "pkg-pr-new": "^0.0.39",
77
+ "prettier": "^3.4.2",
78
+ "publint": "^0.3.2",
79
+ "release-it": "^18.1.2",
80
+ "ts-morph": "^25.0.0",
81
+ "tsd": "^0.31.2",
82
+ "tsup": "^8.3.6",
83
+ "typescript": "^5.7.3",
84
+ "vite-tsconfig-paths": "^5.1.4",
85
+ "vitest": "^3.0.5"
85
86
  },
86
87
  "githubUrl": "https://github.com/nvie/decoders",
87
88
  "sideEffects": false