-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 40990d9
Showing
8 changed files
with
2,160 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
dist | ||
node_modules |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
<div align="center"> | ||
|
||
# verzod | ||
|
||
</div> | ||
|
||
A simple versioning and migration library based on Zod schemas. | ||
|
||
## Concept | ||
*Verzod* allows you to define an 'entity' that can have multiple versions. Each version is defined by a Zod schema. You can then use the library to check if a given data matches the schema of the entity, and if not, migrate it to the latest version and use it. | ||
|
||
## Installation | ||
- Install the NPM package | ||
```bash | ||
$ npm install verzod | ||
``` | ||
|
||
## Usage | ||
- Create a versioned *entity* that you want to use | ||
```ts | ||
import { createVersionedEntity, InferredEntity } from "verzod" | ||
import { z } from "zod" | ||
|
||
const Environment_V1 = z.object({ | ||
name: z.string(), | ||
v: z.literal(1), | ||
variables: z.array( | ||
z.object({ | ||
key: z.string(), | ||
value: z.string(), | ||
masked: z.boolean() | ||
}) | ||
) | ||
}) | ||
|
||
const Environment_V2 = z.object({ | ||
name: z.string(), | ||
v: z.literal(2), | ||
variables: z.array( | ||
z.union([ | ||
z.object({ | ||
name: z.string(), | ||
value: z.string(), | ||
masked: z.literal(false) | ||
}), | ||
z.object({ | ||
name: z.string(), | ||
masked: z.literal(true) | ||
}) | ||
]) | ||
) | ||
}) | ||
|
||
const Environment = createVersionedEntity({ | ||
latestVersion: 2, | ||
versionMap: { | ||
1: defineVersion({ | ||
initial: true, | ||
schema: Environment_V1 | ||
}), | ||
2: defineVersion({ | ||
initial: false, | ||
schema: Environment_V2, | ||
up(old: z.infer<typeof Environment_V1>) { | ||
return <z.infer<typeof Environment_V2>>{ | ||
...old, | ||
v: 2, | ||
variables: old.variables.map(v => ({ | ||
...v, | ||
masked: false | ||
})) | ||
} | ||
} | ||
}) | ||
}, | ||
getVersion(data: unknown) { | ||
return typeof data === "object" | ||
&& data !== null | ||
&& "v" in data | ||
&& typeof data["v"] === "number" | ||
? data["v"] | ||
: null | ||
} | ||
}) | ||
``` | ||
|
||
- You can use the various library functionality demoed below. | ||
```ts | ||
import { InferredEntity } from "verzod" | ||
|
||
// Get the type of the entity (will resolve to the type of the latest version schema) | ||
type Environment = InferredEntity<typeof Environment> | ||
|
||
|
||
// You can use `is` method to check if the data given matches the schema | ||
const v2_data = { | ||
name: "test", | ||
v: 2, | ||
variables: [{ key: "hello", masked: true }] | ||
} | ||
|
||
Environment.is(v2_data) // Returns true | ||
|
||
const v1_data = { name: "test", v: 1, variables: [{ key: "hello", value: "there" }]} | ||
Environment.is(v1_data) // Returns true (it returns true for old versions) | ||
|
||
const invalid_ver_data = { name: "test", v: 3, variables: [] } | ||
Environment.is(invalid_ver_data) // false (invalid version) | ||
|
||
const invalid_schema_data = { name: "test", v: 2, vars: [] } | ||
Environment.is(invalid_schema_data) // false (invalid schema) | ||
|
||
// NOTE: There is also `isLatest` to check only for the latest version | ||
// This also narrows the type to only the latest version unlike `is` which | ||
// narrows to all given versions | ||
Environment.isLatest(v2_data) // true | ||
|
||
Environment.isLatest(v1_data) // false | ||
|
||
// You can use `safeParse` method to parse (and if needed, migrate) the data | ||
Environment.safeParse(v2_data) // { type: "ok", value: v2_data } | ||
Environment.safeParse(v1_data) // { type: "ok", value: { name: "test", v: 2, variables: [{ name: "hello", value: "there", masked: false }]}} <- Migrated old schema | ||
|
||
Environment.safeParse(invalid_ver_data) // { type: "err", error: { type: "INVALID_VER", version: 3 } <- invalid version | ||
|
||
Environment.safeParse(invalid_schema_data) // { type: "err", error: { type: "GIVEN_VER_VALIDATION_FAIL", version: 2, versionDef: <relevant version map entry> } } <- correct version, but invalid data | ||
|
||
``` | ||
|
||
<br /> | ||
<br /> | ||
<p align="center"><b>made with ❤️ by <a href="https://github.com/AndrewBastin">andrew bastin</a></b></p> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
{ | ||
"name": "verzod", | ||
"version": "0.1.0", | ||
"license": "MIT", | ||
"private": "false", | ||
"description": "A simple versioning and migration library based on Zod schemas", | ||
"author": "Andrew Bastin ([email protected])", | ||
"homepage": "https://github.com/AndrewBastin/verzod", | ||
"bugs": { | ||
"url": "https://github.com/AndrewBastin/verzod/issues" | ||
}, | ||
"keywords": [ | ||
"versioning", | ||
"migration", | ||
"zod" | ||
], | ||
"engines": { | ||
"node": ">=16" | ||
}, | ||
"type": "module", | ||
"files": [ | ||
"dist" | ||
], | ||
"exports": "./dist/index.js", | ||
"scripts": { | ||
"test": "vitest --run", | ||
"build": "tsup", | ||
"prepublish": "tsup" | ||
}, | ||
"dependencies": { | ||
"zod": "^3.22.2" | ||
}, | ||
"devDependencies": { | ||
"jiti": "^1.20.0", | ||
"tsup": "^7.2.0", | ||
"typescript": "^5.2.2", | ||
"vitest": "^0.34.6" | ||
} | ||
} |
Oops, something went wrong.