@thomasfosterau/effect-parse 0.2.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.
@@ -1,6 +1,28 @@
1
+ import * as Result from "effect/Result";
1
2
  import { Parser } from "./Parser.js";
2
3
  import * as Schema from "effect/Schema";
3
4
  //#region src/ParserSchema.d.ts
5
+ /**
6
+ * The key of the annotation that says how a schema is written as text
7
+ * ({@link Annotation}), namespaced to this package so it cannot collide with
8
+ * another library's. {@link annotate} sets it.
9
+ *
10
+ * @since 0.3.0
11
+ * @category annotations
12
+ */
13
+ export declare const annotationKey: "@thomasfosterau/effect-parse/ParserSchema";
14
+ declare module "effect/Schema" {
15
+ namespace Annotations {
16
+ interface Annotations {
17
+ /**
18
+ * How the schema is written as text, read by `ParserSchema.toParser`
19
+ * and `ParserSchema.toPrinter`: a parser for the schema's type, or a
20
+ * `ParserSchema.Grammar`.
21
+ */
22
+ readonly [annotationKey]?: Annotation<any> | undefined;
23
+ }
24
+ }
25
+ }
4
26
  /**
5
27
  * Options for {@link make}.
6
28
  *
@@ -28,5 +50,181 @@ export interface ParserSchema<A> extends Schema.decodeTo<Schema.declare<A>, Sche
28
50
  * @category constructors
29
51
  */
30
52
  export declare const make: <A, E>(parser: Parser<A, E, never, string>, options?: Options<A>) => ParserSchema<A>;
53
+ /**
54
+ * How a schema is written as text, given in its annotation (see
55
+ * {@link annotate}) and read by {@link toParser} and {@link toPrinter}.
56
+ * Every field is optional; a schema without one is written as described on
57
+ * {@link toParser}.
58
+ *
59
+ * @since 0.3.0
60
+ * @category models
61
+ */
62
+ export interface Grammar<A = unknown> {
63
+ /**
64
+ * Parses the schema's type outright, replacing what {@link toParser} would
65
+ * derive. Its output is still validated against the schema's type and
66
+ * checks, and its failures' causes become `SchemaError`s with their message.
67
+ * Give a {@link Grammar.print} with it, or the schema cannot be printed.
68
+ */
69
+ readonly parser?: Parser<A, unknown, never, string> | undefined;
70
+ /** Writes a value as the text {@link Grammar.parser} reads, replacing what {@link toPrinter} would derive. */
71
+ readonly print?: ((value: A) => string) | undefined;
72
+ /** Text written before the value. */
73
+ readonly prefix?: string | undefined;
74
+ /** Text written after the value. */
75
+ readonly suffix?: string | undefined;
76
+ /** Text written between the fields of a struct, the elements of a tuple or array, or the entries of a record. */
77
+ readonly separator?: string | undefined;
78
+ /**
79
+ * Text written between a key and its value. On a struct, it writes each
80
+ * field as `key`, separator, value, in any order; records always need one.
81
+ */
82
+ readonly keySeparator?: string | undefined;
83
+ /**
84
+ * Whether whitespace may surround the text this schema writes (its prefix,
85
+ * suffix and separators), and whitespace around unannotated strings is
86
+ * trimmed. Inherited by the schemas inside it. Printers write no
87
+ * whitespace.
88
+ */
89
+ readonly whitespace?: boolean | undefined;
90
+ }
91
+ /**
92
+ * The value of the annotation under {@link annotationKey}: a
93
+ * {@link Grammar}, or a parser for the schema's type (short for
94
+ * `{ parser }`, which cannot be printed).
95
+ *
96
+ * @since 0.3.0
97
+ * @category models
98
+ */
99
+ export type Annotation<A = unknown> = Grammar<A> | Parser<A, unknown, never, string>;
100
+ /**
101
+ * Annotates a schema with how it is written as text, for {@link toParser}
102
+ * and {@link toPrinter}. The same as
103
+ * `schema.annotate({ [ParserSchema.annotationKey]: annotation })`, except
104
+ * that the parser's output must have the schema's type.
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * import { Schema } from "effect"
109
+ * import { ParserSchema } from "@thomasfosterau/effect-parse"
110
+ *
111
+ * const Point = Schema.Struct({ x: Schema.Int, y: Schema.Int }).pipe(
112
+ * ParserSchema.annotate({ prefix: "(", separator: ",", suffix: ")" })
113
+ * )
114
+ * ```
115
+ *
116
+ * @since 0.3.0
117
+ * @category annotations
118
+ */
119
+ export declare const annotate: {
120
+ <A = never>(annotation: Annotation<A>): <S extends Schema.Top>(self: S & ([A] extends [S["Type"]] ? unknown : never)) => S["Rebuild"];
121
+ <S extends Schema.Top>(self: S, annotation: Annotation<S["Type"]>): S["Rebuild"];
122
+ };
123
+ /**
124
+ * Derives a parser from a schema. The parser reads the text the schema's
125
+ * annotations ({@link Grammar}) describe and returns a value of the schema's
126
+ * type, which the schema's checks and transformations have already
127
+ * validated; their failures become parse errors whose `cause` is the
128
+ * `SchemaError`.
129
+ *
130
+ * Without an annotation, a schema is parsed as follows:
131
+ *
132
+ * - `String`: one or more characters up to the next separator, key
133
+ * separator, suffix or literal around it (to the end of the input at the
134
+ * top level).
135
+ * - `Number`: a decimal number (`Ascii.float`), or a decimal integer when
136
+ * the schema checks `isInt` (as `Schema.Int` does). `BigInt`: a decimal
137
+ * integer. `Boolean`: `true` or `false`. `Null`: `null`. `Undefined` and
138
+ * `Void`: nothing.
139
+ * - `Literal`, `Enum` and `TemplateLiteral`: their text.
140
+ * - `Struct` and `Tuple`: their fields or elements in order, between
141
+ * separators; an optional one may be left out along with its separator.
142
+ * `Array`: elements between separators.
143
+ * - `Record`, and `Struct` with a `keySeparator`: `key`, key separator,
144
+ * value entries in any order, between separators.
145
+ * - `Union`: the first member that parses, in order (literals longest
146
+ * first). `suspend`: recursion.
147
+ * - A transformation (a `Class`, `NumberFromString`, ...): its encoded side,
148
+ * decoded by the schema. A grammar on it with a separator applies to the
149
+ * encoded side.
150
+ *
151
+ * A parser that fails where the schema starts reports the schema's
152
+ * `identifier` annotation (or its `expected` annotation, unless that belongs
153
+ * to a check) as what it expected. Other declarations, `Unknown`, `Any`,
154
+ * symbols and `object` need a parser in their annotation; without one,
155
+ * `toParser` throws. Transformations must decode synchronously.
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * import { Schema } from "effect"
160
+ * import { Parser, ParserSchema } from "@thomasfosterau/effect-parse"
161
+ *
162
+ * const Version = Schema.Struct({ major: Schema.Int, minor: Schema.Int }).pipe(
163
+ * ParserSchema.annotate({ separator: "." })
164
+ * )
165
+ *
166
+ * Parser.parse(ParserSchema.toParser(Version), "1.2") // Result.succeed({ major: 1, minor: 2 })
167
+ * ```
168
+ *
169
+ * @since 0.3.0
170
+ * @category derivation
171
+ */
172
+ export declare const toParser: <S extends Schema.ConstraintDecoder<unknown>>(schema: S) => Parser<S["Type"], Schema.SchemaError, never, string>;
173
+ /**
174
+ * Derives a printer from a schema: it writes a value of the schema's type as
175
+ * the text {@link toParser} reads, following the same annotations, with no
176
+ * optional whitespace. Transformations encode the value first, and a
177
+ * {@link Grammar.print} replaces the derived printer.
178
+ *
179
+ * The printer fails with a `SchemaError` when the value is not of the
180
+ * schema's type, or cannot be written so that it reads back: a string that
181
+ * is empty or contains a character that would end it (a separator, a
182
+ * suffix), or a part annotated with a parser but no `print`. Where the
183
+ * grammar is ambiguous (an optional field followed by a field of the same
184
+ * type), the text can still read back as a different value;
185
+ * {@link fromSchema} checks that it doesn't.
186
+ *
187
+ * @example
188
+ * ```ts
189
+ * import { Schema } from "effect"
190
+ * import { ParserSchema } from "@thomasfosterau/effect-parse"
191
+ *
192
+ * const Version = Schema.Struct({ major: Schema.Int, minor: Schema.Int }).pipe(
193
+ * ParserSchema.annotate({ separator: "." })
194
+ * )
195
+ *
196
+ * ParserSchema.toPrinter(Version)({ major: 1, minor: 2 }) // Result.succeed("1.2")
197
+ * ```
198
+ *
199
+ * @since 0.3.0
200
+ * @category derivation
201
+ */
202
+ export declare const toPrinter: <S extends Schema.ConstraintCodec<unknown, unknown, unknown, never>>(schema: S) => ((value: S["Type"]) => Result.Result<string, Schema.SchemaError>);
203
+ /**
204
+ * Creates a schema that decodes a string with the parser {@link toParser}
205
+ * derives from `schema`, into `schema`'s type, and encodes with the printer
206
+ * {@link toPrinter} derives, or with `encode` when given. A derived printer's
207
+ * text is parsed back, and encoding fails unless it gives a value equivalent
208
+ * to the one encoded, so decoding what was encoded always gives it back.
209
+ *
210
+ * @example
211
+ * ```ts
212
+ * import { Schema } from "effect"
213
+ * import { ParserSchema } from "@thomasfosterau/effect-parse"
214
+ *
215
+ * const Pair = ParserSchema.fromSchema(
216
+ * Schema.Tuple([Schema.String, Schema.Number]).pipe(ParserSchema.annotate({ separator: "=" }))
217
+ * )
218
+ *
219
+ * Schema.decodeUnknownSync(Pair)("width=10") // ["width", 10]
220
+ * Schema.encodeSync(Pair)(["height", 2]) // "height=2"
221
+ * ```
222
+ *
223
+ * @since 0.3.0
224
+ * @category constructors
225
+ */
226
+ export declare const fromSchema: <S extends Schema.ConstraintCodec<unknown, unknown, never, never> & Schema.Top>(schema: S, options?: {
227
+ readonly encode?: ((value: S["Type"]) => string) | undefined;
228
+ }) => Schema.decodeTo<Schema.toType<S>, Schema.String>;
31
229
  //#endregion
32
230
  //# sourceMappingURL=ParserSchema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ParserSchema.d.ts","names":[],"sources":["../src/ParserSchema.ts"],"mappings":";;;;;;;;;iBAyCiB,QAAQ;;WAEd,WAAW,OAAO;;WAElB;;;;;;;;iBASM,aAAa,WAAW,OAAO,SAAS,OAAO,QAAQ,IAAI,OAAO;;;;;;;;qBAStE,OAAQ,GAAG,GAAG,QAAQ,OAAO,GAAG,mBAAmB,UAAU,QAAQ,OAAK,aAAa"}
1
+ {"version":3,"file":"ParserSchema.d.ts","names":[],"sources":["../src/ParserSchema.ts"],"mappings":";;;;;;;;;;;;qBA4Da;;YAGD;cACE;;;;;;gBAME,iBAAiB;;;;;;;;;;iBAWhB,QAAQ;;WAEd,WAAW,OAAO;;WAElB;;;;;;;;iBASM,aAAa,WAAW,OAAO,SAAS,OAAO,QAAQ,IAAI,OAAO;;;;;;;;qBA0CtE,OAAQ,GAAG,GAAG,QAAQ,OAAO,GAAG,mBAAmB,UAAU,QAAQ,OAAK,aAAa;;;;;;;;;;iBAuBnF,QAAQ;;;;;;;WAOd,SAAS,OAAO;;WAEhB,UAAU,OAAO;;WAEjB;;WAEA;;WAEA;;;;;WAKA;;;;;;;WAOA;;;;;;;;;;YAWC,WAAW,eAAe,QAAQ,KAAK,OAAO;;;;;;;;;;;;;;;;;;;;qBAqB7C;GAEV,WACC,YAAY,WAAW,MACrB,UAAU,OAAO,KAAK,MAAM,MAAM,YAAY,kCAAkC;GACnF,UAAU,OAAO,KAAK,MAAM,GAAG,YAAY,WAAW,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAsDzD,WAAY,UAAU,OAAO,4BACxC,QAAQ,MACP,OAAO,WAAW,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAmCf,YAAa,UAAU,OAAO,mDACzC,QAAQ,QACL,OAAO,cAAc,OAAO,eAAe,OAAO;;;;;;;;;;;;;;;;;;;;;;;;qBAmC1C,aAAc,UAAU,OAAO,kDAAkD,OAAO,KACnG,QAAQ,GACR;WAAqB,WAAW,OAAO;MACtC,OAAO,SAAS,OAAO,OAAO,IAAI,OAAO"}