@thomasfosterau/effect-parse 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +550 -2
  3. package/dist/Ascii.d.ts +392 -0
  4. package/dist/Ascii.d.ts.map +1 -0
  5. package/dist/Ascii.js +610 -0
  6. package/dist/Ascii.js.map +1 -0
  7. package/dist/Binary.d.ts +153 -0
  8. package/dist/Binary.d.ts.map +1 -0
  9. package/dist/Binary.js +171 -0
  10. package/dist/Binary.js.map +1 -0
  11. package/dist/Bits.d.ts +60 -0
  12. package/dist/Bits.d.ts.map +1 -0
  13. package/dist/Bits.js +144 -0
  14. package/dist/Bits.js.map +1 -0
  15. package/dist/Encoding.d.ts +116 -0
  16. package/dist/Encoding.d.ts.map +1 -0
  17. package/dist/Encoding.js +85 -0
  18. package/dist/Encoding.js.map +1 -0
  19. package/dist/Expression.d.ts +124 -0
  20. package/dist/Expression.d.ts.map +1 -0
  21. package/dist/Expression.js +139 -0
  22. package/dist/Expression.js.map +1 -0
  23. package/dist/Input.d.ts +301 -0
  24. package/dist/Input.d.ts.map +1 -0
  25. package/dist/Input.js +312 -0
  26. package/dist/Input.js.map +1 -0
  27. package/dist/Nom.d.ts +518 -0
  28. package/dist/Nom.d.ts.map +1 -0
  29. package/dist/Nom.js +519 -0
  30. package/dist/Nom.js.map +1 -0
  31. package/dist/ParseError.d.ts +120 -0
  32. package/dist/ParseError.d.ts.map +1 -0
  33. package/dist/ParseError.js +301 -0
  34. package/dist/ParseError.js.map +1 -0
  35. package/dist/Parser.d.ts +1312 -0
  36. package/dist/Parser.d.ts.map +1 -0
  37. package/dist/Parser.js +1936 -0
  38. package/dist/Parser.js.map +1 -0
  39. package/dist/ParserSchema.d.ts +31 -0
  40. package/dist/ParserSchema.d.ts.map +1 -0
  41. package/dist/ParserSchema.js +56 -0
  42. package/dist/ParserSchema.js.map +1 -0
  43. package/dist/ParserStream.d.ts +127 -0
  44. package/dist/ParserStream.d.ts.map +1 -0
  45. package/dist/ParserStream.js +270 -0
  46. package/dist/ParserStream.js.map +1 -0
  47. package/dist/Text.d.ts +330 -0
  48. package/dist/Text.d.ts.map +1 -0
  49. package/dist/Text.js +529 -0
  50. package/dist/Text.js.map +1 -0
  51. package/dist/Token.d.ts +225 -0
  52. package/dist/Token.d.ts.map +1 -0
  53. package/dist/Token.js +294 -0
  54. package/dist/Token.js.map +1 -0
  55. package/dist/index.d.ts +17 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +17 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/internal/compiler/closure.d.ts +25 -0
  60. package/dist/internal/compiler/closure.d.ts.map +1 -0
  61. package/dist/internal/compiler/closure.js +1668 -0
  62. package/dist/internal/compiler/closure.js.map +1 -0
  63. package/dist/internal/compiler/entries.d.ts +19 -0
  64. package/dist/internal/compiler/entries.d.ts.map +1 -0
  65. package/dist/internal/compiler/entries.js +32 -0
  66. package/dist/internal/compiler/entries.js.map +1 -0
  67. package/dist/internal/compiler/first.d.ts +33 -0
  68. package/dist/internal/compiler/first.d.ts.map +1 -0
  69. package/dist/internal/compiler/first.js +235 -0
  70. package/dist/internal/compiler/first.js.map +1 -0
  71. package/dist/internal/compiler/jit.d.ts +20 -0
  72. package/dist/internal/compiler/jit.d.ts.map +1 -0
  73. package/dist/internal/compiler/jit.js +1030 -0
  74. package/dist/internal/compiler/jit.js.map +1 -0
  75. package/dist/internal/compiler/registry.d.ts +34 -0
  76. package/dist/internal/compiler/registry.d.ts.map +1 -0
  77. package/dist/internal/compiler/registry.js +46 -0
  78. package/dist/internal/compiler/registry.js.map +1 -0
  79. package/dist/internal/compiler/sets.d.ts +29 -0
  80. package/dist/internal/compiler/sets.d.ts.map +1 -0
  81. package/dist/internal/compiler/sets.js +85 -0
  82. package/dist/internal/compiler/sets.js.map +1 -0
  83. package/dist/internal/entries.d.ts +27 -0
  84. package/dist/internal/entries.d.ts.map +1 -0
  85. package/dist/internal/entries.js +42 -0
  86. package/dist/internal/entries.js.map +1 -0
  87. package/dist/internal/node.d.ts +251 -0
  88. package/dist/internal/node.d.ts.map +1 -0
  89. package/dist/internal/node.js +73 -0
  90. package/dist/internal/node.js.map +1 -0
  91. package/dist/internal/numbers.d.ts +41 -0
  92. package/dist/internal/numbers.d.ts.map +1 -0
  93. package/dist/internal/numbers.js +302 -0
  94. package/dist/internal/numbers.js.map +1 -0
  95. package/dist/internal/resume.d.ts +39 -0
  96. package/dist/internal/resume.d.ts.map +1 -0
  97. package/dist/internal/resume.js +37 -0
  98. package/dist/internal/resume.js.map +1 -0
  99. package/dist/internal/text.d.ts +72 -0
  100. package/dist/internal/text.d.ts.map +1 -0
  101. package/dist/internal/text.js +391 -0
  102. package/dist/internal/text.js.map +1 -0
  103. package/dist/internal/tokens.d.ts +93 -0
  104. package/dist/internal/tokens.d.ts.map +1 -0
  105. package/dist/internal/tokens.js +400 -0
  106. package/dist/internal/tokens.js.map +1 -0
  107. package/package.json +115 -3
  108. package/src/Ascii.ts +741 -0
  109. package/src/Binary.ts +228 -0
  110. package/src/Bits.ts +192 -0
  111. package/src/Encoding.ts +128 -0
  112. package/src/Expression.ts +245 -0
  113. package/src/Input.ts +429 -0
  114. package/src/Nom.ts +642 -0
  115. package/src/ParseError.ts +378 -0
  116. package/src/Parser.ts +2763 -0
  117. package/src/ParserSchema.ts +87 -0
  118. package/src/ParserStream.ts +390 -0
  119. package/src/Text.ts +757 -0
  120. package/src/Token.ts +416 -0
  121. package/src/index.ts +16 -0
  122. package/src/internal/compiler/closure.ts +1583 -0
  123. package/src/internal/compiler/entries.ts +36 -0
  124. package/src/internal/compiler/first.ts +252 -0
  125. package/src/internal/compiler/jit.ts +1091 -0
  126. package/src/internal/compiler/registry.ts +79 -0
  127. package/src/internal/compiler/sets.ts +100 -0
  128. package/src/internal/entries.ts +51 -0
  129. package/src/internal/node.ts +207 -0
  130. package/src/internal/numbers.ts +291 -0
  131. package/src/internal/resume.ts +55 -0
  132. package/src/internal/text.ts +411 -0
  133. package/src/internal/tokens.ts +409 -0
package/src/Token.ts ADDED
@@ -0,0 +1,416 @@
1
+ /**
2
+ * Parsers for individual tokens and slices of tokens (winnow's `token`
3
+ * module, nom's `bytes` module).
4
+ *
5
+ * Parsers here work on every input kind: `string` (tokens are code points),
6
+ * `Uint8Array` (tokens are bytes) and arrays (tokens are elements). Parsers
7
+ * whose input type cannot be inferred from their arguments take a type
8
+ * parameter that defaults to `string`:
9
+ *
10
+ * ```ts
11
+ * import { Token } from "@thomasfosterau/effect-parse"
12
+ *
13
+ * Token.take(4) // Parser<string, never, never, string>
14
+ * Token.take<Uint8Array>(4) // Parser<Uint8Array, never, never, Uint8Array>
15
+ * ```
16
+ *
17
+ * On partial input (see `Parser.parsePartial`), parsers that reach the end
18
+ * of the available data report `Incomplete` rather than succeeding early or
19
+ * failing.
20
+ *
21
+ * @since 0.1.0
22
+ */
23
+ import type { Input, Slice, State, Token } from "./Input.js"
24
+ import {
25
+ advance,
26
+ compileAny,
27
+ countTokens,
28
+ describeBytes,
29
+ End,
30
+ indexOf,
31
+ matchLiteral,
32
+ nextIf,
33
+ NoMatch,
34
+ scan,
35
+ splitSurrogate
36
+ } from "./internal/tokens.js"
37
+ import type { ErrorKind } from "./ParseError.js"
38
+ import { bounds } from "./internal/node.js"
39
+ import type { Parser, Range } from "./Parser.js"
40
+ import { described } from "./Parser.js"
41
+
42
+ export type {
43
+ /**
44
+ * @since 0.1.0
45
+ * @category models
46
+ */
47
+ Token
48
+ }
49
+
50
+ /**
51
+ * An inclusive range of tokens, e.g. `Token.range("a", "z")`.
52
+ *
53
+ * @since 0.1.0
54
+ * @category models
55
+ */
56
+ export interface TokenRange<T> {
57
+ readonly _tag: "TokenRange"
58
+ readonly from: T
59
+ readonly to: T
60
+ }
61
+
62
+ /**
63
+ * Creates an inclusive token range (winnow's `'a'..='z'`).
64
+ *
65
+ * @since 0.1.0
66
+ * @category constructors
67
+ */
68
+ export const range = <T extends string | number>(from: T, to: T): TokenRange<T> => ({ _tag: "TokenRange", from, to })
69
+
70
+ /**
71
+ * A set of string tokens: the characters of a string, a range, a predicate,
72
+ * or an array of these.
73
+ *
74
+ * @since 0.1.0
75
+ * @category models
76
+ */
77
+ export type StringTokenSet =
78
+ | string
79
+ | TokenRange<string>
80
+ | ((char: string) => boolean)
81
+ | ReadonlyArray<StringTokenSet>
82
+
83
+ /**
84
+ * A set of byte tokens: a byte, the (ASCII) characters of a string, a
85
+ * `Uint8Array` of bytes, a range, a predicate, or an array of these.
86
+ *
87
+ * @since 0.1.0
88
+ * @category models
89
+ */
90
+ export type ByteTokenSet =
91
+ | number
92
+ | string
93
+ | Uint8Array
94
+ | TokenRange<number>
95
+ | ((byte: number) => boolean)
96
+ | ReadonlyArray<ByteTokenSet>
97
+
98
+ /**
99
+ * A set of tokens (winnow's `ContainsToken`). For array inputs, a set is a
100
+ * predicate or an array of allowed elements (compared with `===`).
101
+ *
102
+ * @since 0.1.0
103
+ * @category models
104
+ */
105
+ export type TokenSet<I> = I extends string ? StringTokenSet
106
+ : I extends Uint8Array ? ByteTokenSet
107
+ : I extends ReadonlyArray<infer T> ? ((token: T) => boolean) | ReadonlyArray<T>
108
+ : never
109
+
110
+ const expectedAny = ["any token"]
111
+
112
+ const anyStep = (state: State<Input>): unknown => {
113
+ const pos = state.pos
114
+ if (pos >= state.end) return state.eoi("Token", expectedAny, 1)
115
+ switch (state.inputKind) {
116
+ case 0: {
117
+ const s = state.input as string
118
+ if (splitSurrogate(state, pos)) return state.incomplete(1, expectedAny)
119
+ const c = s.charCodeAt(pos)
120
+ if (c >= 0xd800 && c <= 0xdbff && pos + 1 < s.length && (s.charCodeAt(pos + 1) & 0xfc00) === 0xdc00) {
121
+ state.pos = pos + 2
122
+ return s.slice(pos, pos + 2)
123
+ }
124
+ state.pos = pos + 1
125
+ return s[pos]
126
+ }
127
+ case 1:
128
+ state.pos = pos + 1
129
+ return (state.input as Uint8Array)[pos]
130
+ default:
131
+ state.pos = pos + 1
132
+ return (state.input as ReadonlyArray<unknown>)[pos]
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Matches any single token: a character of a string (winnow's `any`, nom's
138
+ * `anychar`).
139
+ *
140
+ * @since 0.1.0
141
+ * @category tokens
142
+ */
143
+ export const any: Parser<string> = described(anyStep as any, "any", { _tag: "Any", encoding: undefined })
144
+
145
+ /**
146
+ * Matches any single token of an input of type `I`.
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * import { Parser, Token } from "@thomasfosterau/effect-parse"
151
+ *
152
+ * const byte = Token.anyToken<Uint8Array>()
153
+ * Parser.parse(byte, new Uint8Array([7])) // Result.succeed(7)
154
+ * ```
155
+ *
156
+ * @since 0.1.0
157
+ * @category tokens
158
+ */
159
+ export const anyToken = <I extends Input = string>(): Parser<Token<NoInfer<I>>, never, never, NoInfer<I>> => any as any
160
+
161
+ /**
162
+ * Matches a literal sequence of tokens (winnow's `literal`, nom's `tag`).
163
+ * Strings are matched against string input, `Uint8Array`s against byte
164
+ * input, and arrays element-wise (with `===`) against array input.
165
+ *
166
+ * @example
167
+ * ```ts
168
+ * import { Parser, Token } from "@thomasfosterau/effect-parse"
169
+ *
170
+ * const keyword = Parser.alt(Token.literal("true"), Token.literal("false"))
171
+ * // ^? Parser<"true" | "false">
172
+ * ```
173
+ *
174
+ * @since 0.1.0
175
+ * @category tokens
176
+ */
177
+ export const literal: {
178
+ <const L extends string>(literal: L): Parser<L, never, never, string>
179
+ (literal: Uint8Array): Parser<Uint8Array, never, never, Uint8Array>
180
+ <const T>(literal: ReadonlyArray<T>): Parser<ReadonlyArray<T>, never, never, ReadonlyArray<T>>
181
+ } = (lit: Input): Parser<any, never, never, any> => literalImpl(lit, false)
182
+
183
+ /** @internal */
184
+ export const literalImpl = (lit: Input, caseless: boolean): Parser<any, never, never, any> => {
185
+ const description = typeof lit === "string"
186
+ ? JSON.stringify(lit)
187
+ : lit instanceof Uint8Array
188
+ ? describeBytes(lit)
189
+ : `[${lit.map((t) => JSON.stringify(t)).join(", ")}]`
190
+ const expected = [caseless ? `${description} (case insensitive)` : description]
191
+ // A string literal may also be matched against byte input (as UTF-8)
192
+ let asBytes: Uint8Array | undefined
193
+ const literalKind = typeof lit === "string" ? 0 : lit instanceof Uint8Array ? 1 : 2
194
+ return described((state: State<Input>) => {
195
+ const pos = state.pos
196
+ const l = literalKind === 0 && state.inputKind === 1 ? (asBytes ??= new TextEncoder().encode(lit as string)) : lit
197
+ const len = l.length
198
+ const r = matchLiteral(state, l, caseless)
199
+ if (r === -1) return state.backtrack("Literal", expected)
200
+ if (r === -2) {
201
+ if (state.partial) return state.incomplete(len - (state.end - pos), expected)
202
+ return state.backtrack("Literal", expected)
203
+ }
204
+ state.pos = pos + len
205
+ return caseless || state.inputKind !== literalKind ? state.slice(pos, pos + len) : lit
206
+ }, description, { _tag: "Literal", literal: lit, caseless, encoding: undefined })
207
+ }
208
+
209
+ /**
210
+ * Matches one token belonging to a set, returning it (winnow's and nom's
211
+ * `one_of`).
212
+ *
213
+ * @example
214
+ * ```ts
215
+ * import { Parser, Token } from "@thomasfosterau/effect-parse"
216
+ *
217
+ * const sign = Token.oneOf("+-")
218
+ * const lower = Token.oneOf(Token.range("a", "z"))
219
+ * const hexByte = Token.oneOf<Uint8Array>([Token.range(0x30, 0x39), Token.range(0x61, 0x66)])
220
+ * ```
221
+ *
222
+ * @since 0.1.0
223
+ * @category tokens
224
+ */
225
+ export const oneOf = <I extends Input = string>(set: TokenSet<I>): Parser<Token<NoInfer<I>>, never, never, NoInfer<I>> => {
226
+ const m = compileAny(set)
227
+ const expected = [m.description]
228
+ return described((state) => {
229
+ const t = nextIf(state, m, false)
230
+ if (t === End) return state.eoi("OneOf", expected, 1)
231
+ if (t === NoMatch) return state.backtrack("OneOf", expected)
232
+ return t as Token<I>
233
+ }, m.description, { _tag: "OneOf", set, negate: false, encoding: undefined })
234
+ }
235
+
236
+ /**
237
+ * Matches one token *not* belonging to a set, returning it (winnow's and
238
+ * nom's `none_of`).
239
+ *
240
+ * @since 0.1.0
241
+ * @category tokens
242
+ */
243
+ export const noneOf = <I extends Input = string>(set: TokenSet<I>): Parser<Token<NoInfer<I>>, never, never, NoInfer<I>> => {
244
+ const m = compileAny(set)
245
+ const expected = [`anything but ${m.description}`]
246
+ return described((state) => {
247
+ const t = nextIf(state, m, true)
248
+ if (t === End) return state.eoi("NoneOf", expected, 1)
249
+ if (t === NoMatch) return state.backtrack("NoneOf", expected)
250
+ return t as Token<I>
251
+ }, expected[0], { _tag: "OneOf", set, negate: true, encoding: undefined })
252
+ }
253
+
254
+ /**
255
+ * Takes exactly `count` tokens (winnow's and nom's `take`).
256
+ *
257
+ * @since 0.1.0
258
+ * @category slices
259
+ */
260
+ export const take = <I extends Input = string>(count: number): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> => {
261
+ const expected = [count === 1 ? "1 token" : `${count} tokens`]
262
+ return described((state) => {
263
+ const start = state.pos
264
+ const { count: got, offset } = advance(state, start, count)
265
+ if (got < count) return state.eoi("Take", expected, count - got)
266
+ state.pos = offset
267
+ return state.slice(start, offset)
268
+ }, "take", { _tag: "Take", count, encoding: undefined })
269
+ }
270
+
271
+ const normalize = (r: Range | undefined): [number, number] => {
272
+ if (r === undefined) return [0, Infinity]
273
+ if (typeof r === "number") return [r, r]
274
+ return [r.min ?? 0, r.max ?? Infinity]
275
+ }
276
+
277
+ /** @internal */
278
+ export const takeWhileImpl = <I extends Input>(
279
+ set: unknown,
280
+ r: Range | undefined,
281
+ negate: boolean,
282
+ name: string,
283
+ description?: string,
284
+ kind: ErrorKind = "TakeWhile",
285
+ hint = false
286
+ ): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> => {
287
+ const m = compileAny(set)
288
+ const [min, max] = normalize(r)
289
+ const expected = [description ?? (negate ? `anything but ${m.description}` : m.description)]
290
+ return described((state) => {
291
+ const start = state.pos
292
+ const { count, hitEnd, offset } = scan(state, m, negate, max)
293
+ if (hitEnd && state.partial) return state.incomplete(1, expected)
294
+ if (count < min) return state.backtrack(kind, expected, offset)
295
+ // More matching tokens would have been accepted where we stopped
296
+ if (hint && count < max) state.setHint(offset, expected)
297
+ state.pos = offset
298
+ return state.slice(start, offset)
299
+ }, name, { _tag: "TakeWhile", set, negate, min, max, encoding: undefined })
300
+ }
301
+
302
+ /**
303
+ * Takes the longest run of tokens belonging to a set, with the number of
304
+ * tokens constrained by `range` (default: zero or more). This is winnow's
305
+ * `take_while(range, set)`, and nom's `take_while`, `take_while1` and
306
+ * `take_while_m_n`.
307
+ *
308
+ * @example
309
+ * ```ts
310
+ * import { Parser, Token } from "@thomasfosterau/effect-parse"
311
+ *
312
+ * const identifier = Token.takeWhile(
313
+ * [Token.range("a", "z"), Token.range("A", "Z"), "_"],
314
+ * { min: 1 }
315
+ * )
316
+ * ```
317
+ *
318
+ * @since 0.1.0
319
+ * @category slices
320
+ */
321
+ export const takeWhile = <I extends Input = string>(
322
+ set: TokenSet<I>,
323
+ range?: Range
324
+ ): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> => takeWhileImpl(set, range, false, "takeWhile")
325
+
326
+ /**
327
+ * Takes the longest run of tokens *not* belonging to a set (winnow's
328
+ * `take_till`, nom's `take_till` and `take_till1`).
329
+ *
330
+ * @since 0.1.0
331
+ * @category slices
332
+ */
333
+ export const takeTill = <I extends Input = string>(
334
+ set: TokenSet<I>,
335
+ range?: Range
336
+ ): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> => takeWhileImpl(set, range, true, "takeTill")
337
+
338
+ /**
339
+ * Takes tokens up to (not including) the first occurrence of a literal
340
+ * (winnow's `take_until`, nom's `take_until`). The literal is not
341
+ * consumed. `range` constrains the number of tokens taken.
342
+ *
343
+ * @since 0.1.0
344
+ * @category slices
345
+ */
346
+ export const takeUntil: {
347
+ (literal: string, range?: Range): Parser<string, never, never, string>
348
+ (literal: Uint8Array, range?: Range): Parser<Uint8Array, never, never, Uint8Array>
349
+ <T>(literal: ReadonlyArray<T>, range?: Range): Parser<ReadonlyArray<T>, never, never, ReadonlyArray<T>>
350
+ } = (lit: Input, r?: Range): Parser<any, never, never, any> => {
351
+ const [min, max] = normalize(r)
352
+ const description = typeof lit === "string"
353
+ ? JSON.stringify(lit)
354
+ : lit instanceof Uint8Array
355
+ ? describeBytes(lit)
356
+ : `[${lit.map((t) => JSON.stringify(t)).join(", ")}]`
357
+ const expected = [description]
358
+ return described((state: State<Input>) => {
359
+ const start = state.pos
360
+ const idx = indexOf(state, lit, start)
361
+ if (idx < 0) {
362
+ if (state.partial) return state.incomplete(0, expected)
363
+ return state.backtrack("TakeUntil", expected, state.end)
364
+ }
365
+ // As in winnow, the first occurrence must lie within the range
366
+ if (min > 0 || max !== Infinity) {
367
+ const count = countTokens(state, start, idx)
368
+ if (count < min) return state.backtrack("TakeUntil", expected, idx)
369
+ if (count > max) return state.backtrack("TakeUntil", expected)
370
+ }
371
+ state.pos = idx
372
+ return state.slice(start, idx)
373
+ }, "takeUntil", { _tag: "TakeUntil", literal: lit, ...bounds(r), encoding: undefined })
374
+ }
375
+
376
+ /**
377
+ * Takes the rest of the input (winnow's and nom's `rest`).
378
+ *
379
+ * @since 0.1.0
380
+ * @category slices
381
+ */
382
+ export const rest: Parser<string> = described((state: State<any>) => {
383
+ const start = state.pos
384
+ state.pos = state.end
385
+ return state.slice(start, state.end) as string
386
+ }, "rest", { _tag: "Rest", encoding: undefined })
387
+
388
+ /**
389
+ * Takes the rest of an input of type `I`.
390
+ *
391
+ * @since 0.1.0
392
+ * @category slices
393
+ */
394
+ export const restOf = <I extends Input = string>(): Parser<Slice<NoInfer<I>>, never, never, NoInfer<I>> => rest as any
395
+
396
+ /**
397
+ * Returns the length of the remaining input without consuming it (winnow's
398
+ * and nom's `rest_len`).
399
+ *
400
+ * @since 0.1.0
401
+ * @category slices
402
+ */
403
+ export const restLen: Parser<number, never, never, Input> = described((state) => state.end - state.pos, "restLen", {
404
+ _tag: "RestLen"
405
+ })
406
+
407
+ /**
408
+ * Matches a token satisfying a predicate (nom's `satisfy`). Equivalent to
409
+ * `Token.oneOf(predicate)`.
410
+ *
411
+ * @since 0.1.0
412
+ * @category tokens
413
+ */
414
+ export const satisfy = <I extends Input = string>(
415
+ predicate: (token: Token<I>) => boolean
416
+ ): Parser<Token<NoInfer<I>>, never, never, NoInfer<I>> => oneOf<I>(predicate as any)
package/src/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @since 0.1.0
3
+ */
4
+ export * as Input from "./Input.js"
5
+ export * as Parser from "./Parser.js"
6
+ export * as ParseError from "./ParseError.js"
7
+ export * as Token from "./Token.js"
8
+ export * as Ascii from "./Ascii.js"
9
+ export * as Text from "./Text.js"
10
+ export * as Encoding from "./Encoding.js"
11
+ export * as Binary from "./Binary.js"
12
+ export * as Bits from "./Bits.js"
13
+ export * as Expression from "./Expression.js"
14
+ export * as Nom from "./Nom.js"
15
+ export * as ParserSchema from "./ParserSchema.js"
16
+ export * as ParserStream from "./ParserStream.js"