├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .prettierrc.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── assets └── logo.svg ├── jest.config.js ├── package-lock.json ├── package.json ├── rollup.config.ts ├── src ├── checker.ts ├── index.ts └── types.ts ├── test-d └── index.test-d.ts ├── test └── checker.test.ts └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | build/ 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/gts/" 3 | } 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [main] 5 | jobs: 6 | ci: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v2 11 | - name: Setup Node 12 | uses: actions/setup-node@v2 13 | with: 14 | node-version: '14.x' 15 | - name: Install Dependencies 16 | run: npm ci 17 | - name: Lint 18 | run: npm run lint 19 | - name: Test 20 | run: npm run test 21 | - name: Test Definitions 22 | run: npm run test:d 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | build/ 3 | node_modules/ 4 | .idea/ 5 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('gts/.prettierrc.json') 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 1.0.1 (2021-06-12) 4 | 5 | - Updated README.md 6 | 7 | ## 1.0.0 (2021-06-01) 8 | 9 | - Released 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 kawmra 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 | A simple runtime JSON type checker. 22 |
23 | 24 | # Features 25 | 26 | - **Simple**. No JSON Schema, No validation rules 27 | - **Type-safe**. Written in TypeScript 28 | - **Intuitive**. Familiar syntax like TypeScript interface 29 | 30 | Typist JSON is focused on type checking, so there is no validation rules like range of numbers or length of strings. 31 | 32 | # Install 33 | 34 | ```shell 35 | npm install typist-json 36 | ``` 37 | 38 | **NOTE:** Require TypeScript 4.1 or higher because Typist JSON uses [`Key Remapping`](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#key-remapping-via-as) and [`Template Literal Types`](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html). 39 | 40 | # Example 41 | 42 | ```typescript 43 | import { j } from "typist-json"; 44 | 45 | const NameJson = j.object({ 46 | firstname: j.string, 47 | lastname: j.string, 48 | }); 49 | 50 | const UserJson = j.object({ 51 | name: NameJson, 52 | age: j.number, 53 | "nickname?": j.string, // optional property 54 | }); 55 | 56 | const userJson = await fetch("/api/user") 57 | .then(res => res.json()); 58 | 59 | if (UserJson.check(userJson)) { 60 | // now, the userJson is narrowed to: 61 | // { 62 | // name: { 63 | // firstname: string 64 | // lastname: string 65 | // } 66 | // age: number 67 | // nickname?: string | undefined 68 | // } 69 | } 70 | ``` 71 | 72 | ## Circular References 73 | 74 | Sometimes JSON structures can form circular references. 75 | 76 | Typist JSON can represent circular references by wrapping checkers in the arrow function. 77 | 78 | ```ts 79 | const FileJson = j.object({ 80 | filename: j.string, 81 | }); 82 | 83 | const DirJson = j.object({ 84 | dirname: j.string, 85 | entries: () => j.array(j.any([FileJson, DirJson])), // references itself 86 | }); 87 | 88 | DirJson.check({ 89 | dirname: "animals", 90 | entries: [ 91 | { 92 | dirname: "cat", 93 | entries: [ 94 | { filename: "american-shorthair.jpg" }, 95 | { filename: "munchkin.jpg" }, 96 | { filename: "persian.jpg" }, 97 | ], 98 | }, 99 | { 100 | dirname: "dog", 101 | entries: [ 102 | { filename: "chihuahua.jpg" }, 103 | { filename: "pug.jpg" }, 104 | { filename: "shepherd.jpg" }, 105 | ], 106 | }, 107 | { filename: "turtle.jpg" }, 108 | { filename: "shark.jpg" }, 109 | ], 110 | }); // true 111 | ``` 112 | 113 | # Type checkers 114 | 115 | ## Strings 116 | 117 | ```ts 118 | j.string.check("foo"); // true 119 | j.string.check("bar"); // true 120 | ``` 121 | 122 | ## Numbers 123 | 124 | ```ts 125 | j.number.check(42); // true 126 | j.number.check(12.3); // true 127 | j.number.check("100"); // false 128 | ``` 129 | 130 | ## Booleans 131 | 132 | ```ts 133 | j.boolean.check(true); // true 134 | j.boolean.check(false); // true 135 | ``` 136 | 137 | ## Literals 138 | 139 | ```ts 140 | j.literal("foo").check("foo"); // true 141 | j.literal("foo").check("fooooo"); // false 142 | ``` 143 | 144 | ## Arrays 145 | 146 | ```ts 147 | j.array(j.string).check(["foo", "bar"]); // true 148 | j.array(j.string).check(["foo", 42]); // false 149 | j.array(j.string).check([]); // true 150 | j.array(j.number).check([]); // true 151 | ``` 152 | 153 | ## Objects 154 | 155 | ```ts 156 | j.object({ 157 | name: j.string, 158 | age: j.number, 159 | "nickname?": j.string, 160 | }).check({ 161 | name: "John", 162 | age: 20, 163 | nickname: "Johnny", 164 | }); // true 165 | 166 | j.object({ 167 | name: j.string, 168 | age: j.number, 169 | "nickname?": j.string, 170 | }).check({ 171 | name: "Emma", 172 | age: 20, 173 | }); // true, since "nickname" is optional 174 | 175 | j.object({ 176 | name: j.string, 177 | age: j.number, 178 | "nickname?": j.string, 179 | }).check({ 180 | id: "xxxx", 181 | type: "android", 182 | }); // false, since "name" and "age" is required 183 | ``` 184 | 185 | If a property that ends with `?` is not optional, you should replace all trailing `?` by `??`. 186 | 187 |(
158 | target: object,
159 | property: P
160 | ): target is {[K in P]: unknown} {
161 | return property in target;
162 | }
163 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export {Checker, JsonTypeOf} from './types';
2 | export * as j from './checker';
3 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Checker