-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(deps): update effect schema 0.68 #91
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Upgraded @types/node from 20.16.3 to 22.5.2 in package.json and pnpm-lock.yaml. This update resolves compatibility issues and ensures the latest type definitions are used. Signed-off-by: Giovanni Ravalico <[email protected]>
🦋 Changeset detectedLatest commit: bf08ea3 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
suddenlyGiovanni
force-pushed
the
renovate/effect-schema-068
branch
2 times, most recently
from
September 3, 2024 10:02
737680f
to
ae9b886
Compare
Patch Changes #2955 d79ca17 Thanks @gcanti! - The minItems filter now checks for an invalid argument (n < 1) and, when valid, refines the type to NonEmptyReadonlyArray<A>. Updated dependencies [eb98c5b, 184fed8, 6068e07, 3a77e20]: [email protected] Signed-off-by: Giovanni Ravalico <[email protected]>
Patch Changes Updated dependencies [3572646, 1aed347, df4bf4b, f085f92]: [email protected] Signed-off-by: Giovanni Ravalico <[email protected]>
Patch Changes This commit addresses concerns raised by users about the confusing behavior when 'optional' is misused in a schema definition. Previously, users experienced unexpected results, such as a schema returning 'Schema.All' when 'optional' was used incorrectly, without clear guidance on the correct usage or error messages. Changes: Enhanced the 'optional' method to return a descriptive type-level error when used incorrectly, helping users identify and correct their schema definitions. Updated the Schema.optional() implementation to check its context within a pipeline and ensure it is being used correctly. Added unit tests to verify that the new error handling works as expected and to ensure that correct usage does not affect existing functionality. This commit addresses an issue where users encountered unexpected decoding behaviors, specifically regarding how undefined values and missing properties are handled. The default behavior of the @effect/schema library treats missing properties as undefined during decoding, which can lead to confusion when stricter validation is expected. Changes: Exposed an internal configuration option exțact (default: false), which when set to true, enforces strict decoding that will error on missing properties instead of treating them as undefined. Updated documentation to clearly outline the default and strict decoding behaviors, providing users with guidance on how to enable strict validation. Updated dependencies [06ede85, 7204ca5]: [email protected] Signed-off-by: Giovanni Ravalico <[email protected]>
- [#2906](Effect-TS/effect#2906) [`f6c7977`](Effect-TS/effect@f6c7977) Thanks @gcanti! - ## Refactoring of the `ParseIssue` Model The `ParseIssue` model in the `@effect/schema/ParseResult` module has undergone a comprehensive redesign and simplification that enhances its expressiveness without compromising functionality. This section explores the motivation and details of this refactoring. ### Enhanced `Schema.filter` API The `Schema.filter` API has been improved to support more complex filtering that can involve multiple properties of a struct. This is especially useful for validations that compare two fields, such as ensuring that a `password` field matches a `confirm_password` field, a common requirement in form validations. **Previous Limitations:** Previously, while it was possible to implement a filter that compared two fields, there was no straightforward way to attach validation messages to a specific field. This posed challenges, especially in form validations where precise error reporting is crucial. **Example of Previous Implementation:** ```ts import { ArrayFormatter, Schema } from "@effect/schema" import { Either } from "effect" const Password = Schema.Trim.pipe(Schema.minLength(1)) const MyForm = Schema.Struct({ password: Password, confirm_password: Password }).pipe( Schema.filter((input) => { if (input.password !== input.confirm_password) { return "Passwords do not match" } }) ) console.log( "%o", Schema.decodeUnknownEither(MyForm)({ password: "abc", confirm_password: "d" }).pipe(Either.mapLeft((error) => ArrayFormatter.formatErrorSync(error))) ) /* { _id: 'Either', _tag: 'Left', left: [ { _tag: 'Type', path: [], message: 'Passwords do not match' } ] } */ ``` In this scenario, while the filter functionally works, the lack of a specific error path (`path: []`) means errors are not as descriptive or helpful as they could be. ### Specifying Error Paths With the new improvements, it's now possible to specify an error path along with the message, which enhances error specificity and is particularly beneficial for integration with tools like `react-hook-form`. **Updated Implementation Example:** ```ts import { ArrayFormatter, Schema } from "@effect/schema" import { Either } from "effect" const Password = Schema.Trim.pipe(Schema.minLength(1)) const MyForm = Schema.Struct({ password: Password, confirm_password: Password }).pipe( Schema.filter((input) => { if (input.password !== input.confirm_password) { return { path: ["confirm_password"], message: "Passwords do not match" } } }) ) console.log( "%o", Schema.decodeUnknownEither(MyForm)({ password: "abc", confirm_password: "d" }).pipe(Either.mapLeft((error) => ArrayFormatter.formatErrorSync(error))) ) /* { _id: 'Either', _tag: 'Left', left: [ { _tag: 'Type', path: [ 'confirm_password' ], message: 'Passwords do not match' } ] } */ ``` This modification allows the error to be directly associated with the `confirm_password` field, improving clarity for the end-user. ### Multiple Error Reporting The refactored API also supports reporting multiple issues at once, which is useful in forms where several validation checks might fail simultaneously. **Example of Multiple Issues Reporting:** ```ts import { ArrayFormatter, Schema } from "@effect/schema" import { Either } from "effect" const Password = Schema.Trim.pipe(Schema.minLength(1)) const OptionalString = Schema.optional(Schema.String) const MyForm = Schema.Struct({ password: Password, confirm_password: Password, name: OptionalString, surname: OptionalString }).pipe( Schema.filter((input) => { const issues: Array<Schema.FilterIssue> = [] // passwords must match if (input.password !== input.confirm_password) { issues.push({ path: ["confirm_password"], message: "Passwords do not match" }) } // either name or surname must be present if (!input.name && !input.surname) { issues.push({ path: ["surname"], message: "Surname must be present if name is not present" }) } return issues }) ) console.log( "%o", Schema.decodeUnknownEither(MyForm)({ password: "abc", confirm_password: "d" }).pipe(Either.mapLeft((error) => ArrayFormatter.formatErrorSync(error))) ) /* { _id: 'Either', _tag: 'Left', left: [ { _tag: 'Type', path: [ 'confirm_password' ], message: 'Passwords do not match' }, { _tag: 'Type', path: [ 'surname' ], message: 'Surname must be present if name is not present' } ] } */ ``` ### The new `ParseIssue` Model The `ParseIssue` type has undergone a significant restructuring to improve its expressiveness and simplicity. This new model categorizes issues into leaf and composite types, enhancing clarity and making error handling more systematic. **Structure of `ParseIsssue` Type:** ```ts export type ParseIssue = // leaf | Type | Missing | Unexpected | Forbidden // composite | Pointer | Refinement | Transformation | Composite ``` **Key Changes in the Model:** 1. **New Members:** - `Composite`: A new class that aggregates multiple `ParseIssue` instances. - `Missing`: Identifies when a required element or value is absent. - `Unexpected`: Flags unexpected elements or values in the input. - `Pointer`: Points to the part of the data structure where an issue occurs. 2. **Removed Members:** - Previous categories like `Declaration`, `TupleType`, `TypeLiteral`, `Union`, `Member`, `Key`, and `Index` have been consolidated under the `Composite` type for a more streamlined approach. **Definition of `Composite`:** ```ts interface Composite { readonly _tag: "Composite" readonly ast: AST.Annotated readonly actual: unknown readonly issues: ParseIssue | NonEmptyReadonlyArray<ParseIssue> readonly output?: unknown } ``` ## Refined Error Messaging System We've updated our internal function `getErrorMessage` to enhance how error messages are formatted throughout our application. This function constructs an error message that includes the reason for the error, additional details, the path to where the error occurred, and the schema's AST representation if available. **Example** ```ts import { JSONSchema, Schema } from "@effect/schema" JSONSchema.make(Schema.Struct({ a: Schema.Void })) /* throws: Error: Missing annotation at path: ["a"] details: Generating a JSON Schema for this schema requires a "jsonSchema" annotation schema (VoidKeyword): void */ ``` ## Enhancing Tuples with Element Annotations Annotations are used to add metadata to tuple elements, which can describe the purpose or requirements of each element more clearly. This can be particularly useful when generating documentation or JSON schemas from your schemas. ```ts import { JSONSchema, Schema } from "@effect/schema" // Defining a tuple with annotations for each coordinate in a point const Point = Schema.Tuple( Schema.element(Schema.Number).annotations({ title: "X", description: "X coordinate" }), Schema.optionalElement(Schema.Number).annotations({ title: "Y", description: "optional Y coordinate" }) ) // Generating a JSON Schema from the tuple console.log(JSONSchema.make(Point)) /* Output: { '$schema': 'http://json-schema.org/draft-07/schema#', type: 'array', minItems: 1, items: [ { type: 'number', description: 'X coordinate', title: 'X' }, { type: 'number', description: 'optional Y coordinate', title: 'Y' } ], additionalItems: false } */ ``` ## Missing messages You can provide custom messages for missing fields or elements using the new `missingMessage` annotation. Example (missing field) ```ts import { Schema } from "@effect/schema" const Person = Schema.Struct({ name: Schema.propertySignature(Schema.String).annotations({ missingMessage: () => "Name is required" }) }) Schema.decodeUnknownSync(Person)({}) /* Output: Error: { readonly name: string } └─ ["name"] └─ Name is required */ ``` Example (missing element) ```ts import { Schema } from "@effect/schema" const Point = Schema.Tuple( Schema.element(Schema.Number).annotations({ missingMessage: () => "X coordinate is required" }), Schema.element(Schema.Number).annotations({ missingMessage: () => "Y coordinate is required" }) ) Schema.decodeUnknownSync(Point)([], { errors: "all" }) /* Output: Error: readonly [number, number] ├─ [0] │ └─ X coordinate is required └─ [1] └─ Y coordinate is required */ ``` ## Streamlining Annotations The individual APIs that were previously used to add annotations to schemas have been removed. This change was made because these individual annotation APIs did not provide significant value and were burdensome to maintain. Instead, you can now use the `annotations` method directly or the `Schema.annotations` API for a `pipe`-able approach. Before ```ts import { Schema } from "@effect/schema" // Example of adding an identifier using a dedicated API const schema = Schema.String.pipe(Schema.identifier("myIdentitifer")) ``` Now ```ts import { Schema } from "@effect/schema" // Directly using the annotations method const schema = Schema.String.annotations({ identifier: "myIdentitifer" }) // or const schema2 = Schema.String.pipe( // Using the annotations function in a pipe-able format Schema.annotations({ identifier: "myIdentitifer" }) ) ``` ## Standardize Error Handling for `*Either`, `*Sync` and `asserts` APIs Now the `*Sync` and `asserts` APIs throw a `ParseError` while before they was throwing a simple `Error` with a `cause` containing a `ParseIssue` ```ts import { ParseResult, Schema } from "@effect/schema" try { Schema.decodeUnknownSync(Schema.String)(null) } catch (e) { console.log(ParseResult.isParseError(e)) // true } const asserts: (u: unknown) => asserts u is string = Schema.asserts( Schema.String ) try { asserts(null) } catch (e) { console.log(ParseResult.isParseError(e)) // true } ``` ## List of Changes AST - add `MissingMessageAnnotation` annotations - add `Type` - remove `verbose` option from `toString()` methods **Breaking** - rename `Element` to `OptionalType` and add an `annotations` field - change `TupleType` definition: from `rest: ReadonlyArray<AST>` to `rest: ReadonlyArray<Type>` - remove `TemplateLiteral.make` Schema - add `missingMessage` annotation to `PropertySignature` - add `FilterIssue` helper interface **Breaking** - remove `TupleType.Element` type - replace `OptionalElement` API interface with `Element` API interface - remove `PropertySignature.GetToken` - remove duplicated annotation APIs - `message` - `identifier` - `title` - `description` - `examples` - `default` - `documentation` - `jsonSchema` - `equivalence` - `concurrency` - `concurrency` - `parseIssueTitle` - remove `Secret` and `SecretFromSelf` ParseResult - add `isParseError` type guard **Breaking** - `ParseIssue` refactoring - make `Missing` and `Unexpected` parse issues - replace `Declaration` with `Composite` - remove `Union` in favour of `Composite` - remove `TypeLiteral` in favour of `Composite` - remove `TupleType` in favour of `Composite` - remove `Member` class - merge `Key` and `Index` into `Pointer` - `Type` - change `message` field from `Option<string>` to `string | undefined` - `Refinement` - rename `error` field to `issue` - `Transformation` - rename `error` field to `issue` - `Missing` - add `ast: AST.Type` field - add `message` field - add `actual` field - `Unexpected` - replace `ast` field with a `message` field - add `actual` field - `ParseError` - rename `error` property to `issue` - remove `missing` export - Standardize Error Handling for `*Either`, `*Sync` and `asserts` APIs, closes #2968 - Updated dependencies [[`a67b8fe`](Effect-TS/effect@a67b8fe)]: - [email protected] Signed-off-by: Giovanni Ravalico <[email protected]>
suddenlyGiovanni
force-pushed
the
renovate/effect-schema-068
branch
from
September 3, 2024 10:17
ae9b886
to
bf08ea3
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
No description provided.