@endevops/effect-codec-xml 0.1.0-beta.1 → 0.1.0-effect.1
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 +62 -63
- package/dist/codec.d.ts +9 -17
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +16 -25
- package/dist/codec.js.map +1 -1
- package/dist/conventions.d.ts +4 -4
- package/dist/conventions.js +7 -7
- package/dist/conventions.js.map +1 -1
- package/dist/entities/entity-decoder.d.ts +33 -33
- package/dist/entities/entity-decoder.d.ts.map +1 -1
- package/dist/entities/entity-decoder.js +64 -63
- package/dist/entities/entity-decoder.js.map +1 -1
- package/dist/errors.d.ts +2 -2
- package/dist/errors.js +2 -2
- package/dist/errors.js.map +1 -1
- package/dist/namespaces.js +2 -2
- package/dist/namespaces.js.map +1 -1
- package/dist/naming.d.ts +6 -6
- package/dist/naming.d.ts.map +1 -1
- package/dist/naming.js +3 -3
- package/dist/naming.js.map +1 -1
- package/dist/parse.d.ts +5 -5
- package/dist/parse.js +14 -14
- package/dist/parse.js.map +1 -1
- package/dist/render.d.ts +1 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +28 -28
- package/dist/render.js.map +1 -1
- package/dist/xml-error.d.ts +9 -9
- package/dist/xml-error.js +18 -18
- package/dist/xml-error.js.map +1 -1
- package/dist/xml-value.d.ts +7 -7
- package/dist/xml-value.d.ts.map +1 -1
- package/dist/xml-value.js +7 -6
- package/dist/xml-value.js.map +1 -1
- package/package.json +1 -1
- package/src/codec.ts +71 -91
- package/src/conventions.ts +7 -7
- package/src/entities/entity-decoder.ts +99 -98
- package/src/errors.ts +3 -3
- package/src/index.ts +3 -3
- package/src/namespaces.ts +16 -16
- package/src/naming.ts +35 -34
- package/src/parse.ts +26 -26
- package/src/render.ts +44 -44
- package/src/xml-error.ts +18 -18
- package/src/xml-value.ts +11 -10
package/src/xml-error.ts
CHANGED
|
@@ -6,38 +6,38 @@
|
|
|
6
6
|
*
|
|
7
7
|
* ## Why one error with a `reason`, and not one error per cause
|
|
8
8
|
*
|
|
9
|
-
* The causes would mean a class each, and a caller handling "any of these" would need `catchTags` with all of them.
|
|
10
|
-
*
|
|
11
|
-
* versus a bad _document_. So there is one error, and `reason` narrows to the specific cause. Recovery is a `catchReason` away:
|
|
9
|
+
* The causes would mean a class each, and a caller handling "any of these" would need `catchTags` with all of them. The causes are not independent
|
|
10
|
+
* decisions a caller usually wants to make separately — they are all "this XML input was not acceptable", and the useful split is coarse: a bad
|
|
11
|
+
* _configuration_ versus a bad _document_. So there is one error, and `reason` narrows to the specific cause. Recovery is a `catchReason` away:
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```typescript
|
|
15
15
|
* import { Effect } from 'effect';
|
|
16
|
-
* import { EntityDecoder, XmlError } from '@endevops/effect-codec
|
|
16
|
+
* import { EntityDecoder, XmlError } from '@endevops/effect-xml-codec';
|
|
17
17
|
*
|
|
18
18
|
* const limited = new EntityDecoder({ limit: { maxTotalExpansions: 2 } }).decode('&&&').pipe(
|
|
19
19
|
* Effect.catchReason('XmlError', 'ExpansionLimitExceeded', reason => Effect.succeed(`gave up after ${reason.actual}`)),
|
|
20
20
|
* );
|
|
21
21
|
* ```;
|
|
22
22
|
*
|
|
23
|
-
* The message is kept alongside `reason` and is part of the schema, because
|
|
24
|
-
* `[EntityReplacer]` prefix in particular is documented as something callers match on, so
|
|
25
|
-
* rather than
|
|
23
|
+
* The message is kept alongside `reason` and is part of the schema, because the text is load-bearing: the
|
|
24
|
+
* `[EntityReplacer]` prefix in particular is documented as something callers match on, so it is reproduced exactly
|
|
25
|
+
* rather than reworded.
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
import { Schema } from 'effect';
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* @description The specific cause of an {@link XmlError}, as a tagged union. The `_tag` on each member is the discriminant `Effect.catchReason` matches on, and
|
|
32
|
-
* the payload is what a handler needs in order to decide or to report. Every member is a case the decoder or the name validators actually raise
|
|
33
|
-
*
|
|
32
|
+
* the payload is what a handler needs in order to decide or to report. Every member is a case the decoder or the name validators actually raise —
|
|
33
|
+
* there is no catch-all member, so an exhaustive `match` stays exhaustive as causes are added.
|
|
34
34
|
*/
|
|
35
35
|
export const XmlErrorReason = Schema.TaggedUnion({
|
|
36
36
|
/**
|
|
37
37
|
* @description A required argument was `null` or another non-value where the package requires a real one. Raised by the factories that take caller-supplied
|
|
38
|
-
* input
|
|
39
|
-
* case from the rest because the argument is not _wrong_, it is _absent_, and a caller who wrote `make(null)` meant something the type
|
|
40
|
-
* not allow
|
|
38
|
+
* input — {@link EntityDecoder.make} among them — when they are handed `null` for an options object that has no meaningful default. It is a
|
|
39
|
+
* distinct case from the rest because the argument is not _wrong_, it is _absent_, and a caller who wrote `make(null)` meant something the type
|
|
40
|
+
* system does not allow: a decoder with every default is `make({})`, and saying so here is more useful than silently producing one.
|
|
41
41
|
*/
|
|
42
42
|
MissingOptions: {
|
|
43
43
|
/**
|
|
@@ -48,7 +48,7 @@ export const XmlErrorReason = Schema.TaggedUnion({
|
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* @description A name was checked against one of the five XML name productions and given a different one. Unreachable from TypeScript, where `Production` is a
|
|
51
|
-
* closed union
|
|
51
|
+
* closed union — it is the guard for untyped JavaScript callers and for values that crossed a boundary as `unknown`.
|
|
52
52
|
*/
|
|
53
53
|
InvalidProduction: {
|
|
54
54
|
production: Schema.String,
|
|
@@ -78,7 +78,7 @@ export const XmlErrorReason = Schema.TaggedUnion({
|
|
|
78
78
|
*/
|
|
79
79
|
EntityRejected: {
|
|
80
80
|
/**
|
|
81
|
-
* @description Which registration was in progress.
|
|
81
|
+
* @description Which registration was in progress. Both are runtime-injected, which is why they share a tier for limit accounting.
|
|
82
82
|
*/
|
|
83
83
|
context: Schema.Literals(['external', 'input']),
|
|
84
84
|
/**
|
|
@@ -93,7 +93,7 @@ export const XmlErrorReason = Schema.TaggedUnion({
|
|
|
93
93
|
*/
|
|
94
94
|
ExpansionLimitExceeded: {
|
|
95
95
|
/**
|
|
96
|
-
* @description The count that tripped the limit.
|
|
96
|
+
* @description The count that tripped the limit. Deliberately not reset on failure, so this is the real over-limit total rather than the ceiling.
|
|
97
97
|
*/
|
|
98
98
|
actual: Schema.Number,
|
|
99
99
|
/**
|
|
@@ -139,14 +139,14 @@ export const XmlErrorReason = Schema.TaggedUnion({
|
|
|
139
139
|
export type XmlErrorReason = typeof XmlErrorReason.Type;
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
|
-
* @description Every failure this package can report, in the `E` channel of the effects that can fail. Carries both a `reason
|
|
142
|
+
* @description Every failure this package can report, in the `E` channel of the effects that can fail. Carries both a `reason` — the typed, matchable cause — and
|
|
143
143
|
* a `message`, which is the human-readable form the package has always produced. Both are part of the schema, so an error survives a round-trip
|
|
144
144
|
* through a serialised boundary without losing either.
|
|
145
145
|
*
|
|
146
146
|
* @example
|
|
147
147
|
* ```typescript
|
|
148
148
|
* import { Effect } from 'effect';
|
|
149
|
-
* import { EntityDecoder } from '@endevops/effect-codec
|
|
149
|
+
* import { EntityDecoder } from '@endevops/effect-xml-codec';
|
|
150
150
|
*
|
|
151
151
|
* const program = Effect.gen(function*() {
|
|
152
152
|
* const decoder = yield* EntityDecoder.make({});
|
|
@@ -162,7 +162,7 @@ export class XmlError extends Schema.TaggedError<XmlError>()('XmlError', {
|
|
|
162
162
|
|
|
163
163
|
/**
|
|
164
164
|
* @description Human-readable description. The `[EntityReplacer]` and `[EntityDecoder]` prefixes are reproduced verbatim from the original throw sites, because
|
|
165
|
-
*
|
|
165
|
+
* they are documented as load-bearing for anything matching on them.
|
|
166
166
|
*/
|
|
167
167
|
message: Schema.String,
|
|
168
168
|
}) {}
|
package/src/xml-value.ts
CHANGED
|
@@ -11,10 +11,10 @@ export interface XmlRecord {
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @description One value in an XML document: nothing at all, character data, a repeated run of children, or a record of attributes, text and child elements.
|
|
14
|
-
* `undefined` is a value of its own rather than an omission, because that is how an absent optional field survives a round trip
|
|
15
|
-
* value stays distinguishable from a field whose value is the empty string, and the renderer writes neither of them. The shape is the
|
|
16
|
-
* `Schema.toCodecStringTree` derives,
|
|
17
|
-
*
|
|
14
|
+
* `undefined` is a value of its own rather than an omission, because that is how an absent optional field survives a round trip: a field with no
|
|
15
|
+
* value stays distinguishable from a field whose value is the empty string, and the renderer writes neither of them. The shape is deliberately the
|
|
16
|
+
* same one `Schema.toCodecStringTree` derives, which is what lets every schema feature Effect supports round-trip through this package without
|
|
17
|
+
* re-implementing the derivation.
|
|
18
18
|
*/
|
|
19
19
|
export type XmlValue = string | undefined | ReadonlyArray<XmlValue> | XmlRecord;
|
|
20
20
|
|
|
@@ -34,9 +34,10 @@ const MAX_GUARD_DEPTH = 512;
|
|
|
34
34
|
export const isXmlValue = (input: unknown): input is XmlValue => check(input, 0);
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* @description One level of {@link isXmlValue}, with the depth it was reached at. The depth is the whole defence against a value built to be hostile
|
|
38
|
-
* self-referential object would otherwise recurse until the stack gave out, and a value nested thousands deep would take it with it.
|
|
39
|
-
*
|
|
37
|
+
* @description One level of {@link isXmlValue}, with the depth it was reached at. The depth is the whole defence against a value built to be hostile: a
|
|
38
|
+
* self-referential object would otherwise recurse until the stack gave out, and a value nested thousands deep would take it with it. Both are
|
|
39
|
+
* rejected here instead, which is why this is a real recursion with a bound rather than a loop — the model is a tree, and a tree is walked by walking
|
|
40
|
+
* it.
|
|
40
41
|
*
|
|
41
42
|
* @param input - The candidate value.
|
|
42
43
|
* @param depth - How many levels down this value sits.
|
|
@@ -89,13 +90,13 @@ const everyFieldIs = (input: object, depth: number): boolean => {
|
|
|
89
90
|
};
|
|
90
91
|
|
|
91
92
|
/**
|
|
92
|
-
* @description A schema for {@link XmlValue}, so a value can be validated on its own
|
|
93
|
-
*
|
|
93
|
+
* @description A schema for {@link XmlValue}, so a value can be validated on its own — when it arrives from a store or a queue rather than from {@link parseXml},
|
|
94
|
+
* and the schema it belongs to is not in hand.
|
|
94
95
|
*
|
|
95
96
|
* @example
|
|
96
97
|
* ```typescript
|
|
97
98
|
* import { Schema } from 'effect';
|
|
98
|
-
* import { XmlValue } from '@endevops/effect-codec
|
|
99
|
+
* import { XmlValue } from '@endevops/effect-xml-codec';
|
|
99
100
|
*
|
|
100
101
|
* Schema.decodeUnknownSync(XmlValue)({ book: { '@id': '1', title: 'Dune' } }); // => { book: { '@id': '1', title: 'Dune' } }
|
|
101
102
|
* Schema.decodeUnknownSync(XmlValue)({ book: { title: 42 } }); // => throws XmlValue
|