Add transformed
This commit is contained in:
parent
03b0949d39
commit
71a6d5c7d7
4 changed files with 52 additions and 3 deletions
21
README.md
21
README.md
|
@ -74,6 +74,7 @@ required and will default to an generic version of the parser.
|
||||||
- `Parse.regex(regex: RegExp): (val: unknown) => string`
|
- `Parse.regex(regex: RegExp): (val: unknown) => string`
|
||||||
- `Parse.literal(literal: unknown): (val: unknown) => literal`
|
- `Parse.literal(literal: unknown): (val: unknown) => literal`
|
||||||
- `Parse.instanceOf<T>(classDef: Class): (val: unknown) => T`
|
- `Parse.instanceOf<T>(classDef: Class): (val: unknown) => T`
|
||||||
|
- `Parse.recordOf<K, V>(keyParser: Parser<K>, valParser: Parser<V>): (val: unknown) => Record<K, V>`
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// An array of strings
|
// An array of strings
|
||||||
|
@ -117,6 +118,26 @@ const numberOrNull = Parse.nullable(Parse.number);
|
||||||
const optionalArrayOfStrings = Parse.optional(Parse.arrayOf(Parse.string)));
|
const optionalArrayOfStrings = Parse.optional(Parse.arrayOf(Parse.string)));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Both `nullable` and `optional` can be passed `true` as a second parameter
|
||||||
|
to allow parsing `null` or `undefined` into the respective empty value.
|
||||||
|
|
||||||
|
For example, if you want to allow parsing a field that may be `null` or `undefined`,
|
||||||
|
but want to return only `null` if either is parsed, you can use:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const nullifiedVal = Parse.nullable(undefined, true); // parses to null
|
||||||
|
```
|
||||||
|
|
||||||
|
### Defaulting and Transforming
|
||||||
|
|
||||||
|
Use `Parse.defaulted()` and `Parse.transformed()` to wrap parsers and provide
|
||||||
|
a default value or value transformer
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const parsedWithDefault = Parse.defaulted(Parse.number, 42)(undefined); // 42
|
||||||
|
const asNum = Parse.transformed(Parse.string, (val) => parseInt(val, 10))("42"); // 42
|
||||||
|
```
|
||||||
|
|
||||||
### Extracting Types from Parsers
|
### Extracting Types from Parsers
|
||||||
|
|
||||||
When composing parsers to create more complex types, you can use the `ReturnType`
|
When composing parsers to create more complex types, you can use the `ReturnType`
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@endeavorance/parsec",
|
"name": "@endeavorance/parsec",
|
||||||
"version": "0.7.0",
|
"version": "0.8.0",
|
||||||
"author": "Endeavorance",
|
"author": "Endeavorance",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"module": "dist/index.js",
|
"module": "dist/index.js",
|
||||||
|
|
17
src/index.ts
17
src/index.ts
|
@ -241,6 +241,23 @@ export const Parse = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
transformed<I, O>(
|
||||||
|
parser: (val: unknown) => I,
|
||||||
|
transformer: (val: I) => O,
|
||||||
|
shapeName = "Transformed Value",
|
||||||
|
): (val: unknown) => O {
|
||||||
|
return (val: unknown) => {
|
||||||
|
try {
|
||||||
|
return transformer(parser(val));
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof ParseError) {
|
||||||
|
error.path += shapeName;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
oneOf<T extends Parser<unknown>[]>(
|
oneOf<T extends Parser<unknown>[]>(
|
||||||
parsers: T,
|
parsers: T,
|
||||||
shapeName = "Union",
|
shapeName = "Union",
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import { Parse, ParseError } from "../index.ts";
|
import { Parse, ParseError } from "../index.ts";
|
||||||
|
|
||||||
|
class TestClass { }
|
||||||
|
|
||||||
describe(Parse.unknown, () => {
|
describe(Parse.unknown, () => {
|
||||||
test("returns the value as provided", () => {
|
test("returns the value as provided", () => {
|
||||||
const val = Parse.unknown("hello");
|
const val = Parse.unknown("hello");
|
||||||
|
@ -282,8 +284,6 @@ describe(Parse.nan, () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
class TestClass { }
|
|
||||||
|
|
||||||
describe(Parse.instanceOf, () => {
|
describe(Parse.instanceOf, () => {
|
||||||
test("Parses instances of a class", () => {
|
test("Parses instances of a class", () => {
|
||||||
const testClass = new TestClass();
|
const testClass = new TestClass();
|
||||||
|
@ -339,3 +339,14 @@ describe(Parse.recordOf, () => {
|
||||||
expect(() => stringToString(badRec)).toThrow(ParseError);
|
expect(() => stringToString(badRec)).toThrow(ParseError);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe(Parse.transformed, () => {
|
||||||
|
test("It transforms the parsed value", () => {
|
||||||
|
const parser = Parse.transformed(Parse.string, (val) =>
|
||||||
|
Number.parseInt(val, 10),
|
||||||
|
);
|
||||||
|
|
||||||
|
const parsedVal = parser("123");
|
||||||
|
expect(parsedVal).toBe(123);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue