├── .gitignore ├── .vscode └── settings.json ├── README.md ├── package-lock.json ├── package.json ├── src ├── ext │ ├── allow-null.ts │ ├── index.ts │ ├── strict-properties.ts │ └── trim.ts ├── index.ts ├── schema.ts ├── util.ts └── validator.ts ├── test-typedefs ├── tsconfig.json └── typedefs.ts ├── test ├── allow-null.spec.ts ├── ext.spec.ts ├── index.spec.ts ├── mocha.opts ├── strict-properties.spec.ts ├── trim.spec.ts └── tsconfig.json ├── tsconfig.json ├── tslint.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | lib/ -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Typed-JSON-Schema 2 | ------------------ 3 |
Version 4 | 5 | ## TypeScript-Friendly JSON-Schema Definitions 6 | 7 | This library is able to validate JSON-Schema at runtime, and also emit type definitions for the validated data. This means that if you define your data using our JSON-schema builder, you automatically get TypeScript safety on those types. 8 | 9 | 10 | 11 | ## Examples 12 | 13 | ### Schema generation: 14 | 15 | ``` typescript 16 | await validator.validate(string.minLength(3), 'asdf') // type: string 17 | 18 | await validator.validate(array(string.pattern(/\w+/))) // result type: string[] 19 | 20 | await validator.validate(object.required('a', 'b').properties({ 21 | a: string, 22 | b: array(number) 23 | }) // result type: {a: string, b: number[] } 24 | 25 | ``` 26 | 27 | ### Validation 28 | 29 | ```typescript 30 | import { schema, string, Validator } from 'typed-json-schema' 31 | 32 | const validator = new Validator() 33 | 34 | const StringOrNull = schema.type(['string', 'null']) 35 | 36 | const result = await validator.validate(StringOrNull, 'Hello'), 37 | 38 | result.toFixed(1) // error: Property 'toFixed' does not exist on type 'string'. 39 | result.toLowerCase() //error: object is possibly null 40 | result && validation.result.toLowerCase() //success! 41 | 42 | ``` 43 | 44 | 45 | ## Usage 46 | 47 | ### Schema Creation 48 | 49 | In general, all [JSON-Schema keywords](https://spacetelescope.github.io/understanding-json-schema/reference/index.html) can be used as builders on the `schema` object. 50 | 51 | For example: 52 | 53 | ```typescript 54 | import { schema } from 'typed-json-schema' 55 | 56 | const mySchema = schema 57 | .type('string') 58 | .minLength(3) 59 | .pattern(/regex/) 60 | ``` 61 | 62 | Refer to [JSON-Schema keywords](https://spacetelescope.github.io/understanding-json-schema/reference/index.html) for a list of available keywords. 63 | 64 | ### Shortcuts: 65 | ```typescript 66 | import { string, boolean, number, array, object } 67 | 68 | const mySchema = string //same as schema.type('string') 69 | const mySchema = number //same as schema.type('number') 70 | const mySchema = boolean //same as schema.type('boolean') 71 | const mySchema = array(string) //same as schema.type('array').items(string) 72 | const mySchema = object({ a: string, b: array(number) }) //same as schema.type('object').properties({ a: string, b: array(number) }) 73 | ``` 74 | 75 | ### Validation: 76 | 77 | Use a `Validator` to validate a json schema: 78 | 79 | ```typescript 80 | import { schema, Validator } 81 | 82 | const validator = new Validator({ coerceTypes: true }) //any AJV options can be supplied 83 | const result = await validator.validate(schema.type('number')) //result is a number 84 | 85 | 86 | ``` 87 | 88 | see [AJV](http://epoberezkin.github.io/ajv/) for a list of options that can be passed to the validator. 89 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typed-json-schema", 3 | "version": "4.0.4", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/chai": { 8 | "version": "4.0.1", 9 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.0.1.tgz", 10 | "integrity": "sha512-DWrdkraJO+KvBB7+Jc6AuDd2+fwV6Z9iK8cqEEoYpcurYrH7GiUZmwjFuQIIWj5HhFz6NsSxdN72YMIHT7Fy2Q==", 11 | "dev": true 12 | }, 13 | "@types/mocha": { 14 | "version": "2.2.41", 15 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.41.tgz", 16 | "integrity": "sha1-4nzwgXFT658nE7LT9saPHhw8pgg=", 17 | "dev": true 18 | }, 19 | "ajv": { 20 | "version": "6.12.6", 21 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 22 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 23 | "requires": { 24 | "fast-deep-equal": "^3.1.1", 25 | "fast-json-stable-stringify": "^2.0.0", 26 | "json-schema-traverse": "^0.4.1", 27 | "uri-js": "^4.2.2" 28 | } 29 | }, 30 | "ansi-regex": { 31 | "version": "2.1.1", 32 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 33 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 34 | "dev": true 35 | }, 36 | "ansi-styles": { 37 | "version": "3.2.1", 38 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 39 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 40 | "dev": true, 41 | "requires": { 42 | "color-convert": "^1.9.0" 43 | } 44 | }, 45 | "arrify": { 46 | "version": "1.0.1", 47 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", 48 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", 49 | "dev": true 50 | }, 51 | "assertion-error": { 52 | "version": "1.1.0", 53 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 54 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 55 | "dev": true 56 | }, 57 | "babel-code-frame": { 58 | "version": "6.26.0", 59 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 60 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 61 | "dev": true, 62 | "requires": { 63 | "chalk": "^1.1.3", 64 | "esutils": "^2.0.2", 65 | "js-tokens": "^3.0.2" 66 | }, 67 | "dependencies": { 68 | "ansi-styles": { 69 | "version": "2.2.1", 70 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 71 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 72 | "dev": true 73 | }, 74 | "chalk": { 75 | "version": "1.1.3", 76 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 77 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 78 | "dev": true, 79 | "requires": { 80 | "ansi-styles": "^2.2.1", 81 | "escape-string-regexp": "^1.0.2", 82 | "has-ansi": "^2.0.0", 83 | "strip-ansi": "^3.0.0", 84 | "supports-color": "^2.0.0" 85 | } 86 | }, 87 | "supports-color": { 88 | "version": "2.0.0", 89 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 90 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 91 | "dev": true 92 | } 93 | } 94 | }, 95 | "balanced-match": { 96 | "version": "1.0.0", 97 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 98 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 99 | "dev": true 100 | }, 101 | "brace-expansion": { 102 | "version": "1.1.11", 103 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 104 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 105 | "dev": true, 106 | "requires": { 107 | "balanced-match": "^1.0.0", 108 | "concat-map": "0.0.1" 109 | } 110 | }, 111 | "browser-stdout": { 112 | "version": "1.3.0", 113 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", 114 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", 115 | "dev": true 116 | }, 117 | "camelcase": { 118 | "version": "3.0.0", 119 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", 120 | "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", 121 | "dev": true 122 | }, 123 | "chai": { 124 | "version": "4.1.0", 125 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.0.tgz", 126 | "integrity": "sha1-MxoDkbVcOvh0CunDt0WLwcOAXm0=", 127 | "dev": true, 128 | "requires": { 129 | "assertion-error": "^1.0.1", 130 | "check-error": "^1.0.1", 131 | "deep-eql": "^2.0.1", 132 | "get-func-name": "^2.0.0", 133 | "pathval": "^1.0.0", 134 | "type-detect": "^4.0.0" 135 | } 136 | }, 137 | "chalk": { 138 | "version": "2.4.2", 139 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 140 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 141 | "dev": true, 142 | "requires": { 143 | "ansi-styles": "^3.2.1", 144 | "escape-string-regexp": "^1.0.5", 145 | "supports-color": "^5.3.0" 146 | }, 147 | "dependencies": { 148 | "has-flag": { 149 | "version": "3.0.0", 150 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 151 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 152 | "dev": true 153 | }, 154 | "supports-color": { 155 | "version": "5.5.0", 156 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 157 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 158 | "dev": true, 159 | "requires": { 160 | "has-flag": "^3.0.0" 161 | } 162 | } 163 | } 164 | }, 165 | "check-error": { 166 | "version": "1.0.2", 167 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 168 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 169 | "dev": true 170 | }, 171 | "cliui": { 172 | "version": "3.2.0", 173 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", 174 | "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", 175 | "dev": true, 176 | "requires": { 177 | "string-width": "^1.0.1", 178 | "strip-ansi": "^3.0.1", 179 | "wrap-ansi": "^2.0.0" 180 | } 181 | }, 182 | "code-point-at": { 183 | "version": "1.1.0", 184 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 185 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 186 | "dev": true 187 | }, 188 | "color-convert": { 189 | "version": "1.9.3", 190 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 191 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 192 | "dev": true, 193 | "requires": { 194 | "color-name": "1.1.3" 195 | } 196 | }, 197 | "color-name": { 198 | "version": "1.1.3", 199 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 200 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 201 | "dev": true 202 | }, 203 | "colors": { 204 | "version": "1.4.0", 205 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 206 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", 207 | "dev": true 208 | }, 209 | "commander": { 210 | "version": "2.9.0", 211 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", 212 | "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", 213 | "dev": true, 214 | "requires": { 215 | "graceful-readlink": ">= 1.0.0" 216 | } 217 | }, 218 | "concat-map": { 219 | "version": "0.0.1", 220 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 221 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 222 | "dev": true 223 | }, 224 | "cross-env": { 225 | "version": "5.0.5", 226 | "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.0.5.tgz", 227 | "integrity": "sha1-Q4PTZNlmCHPdGFs5ivO/717//vM=", 228 | "dev": true, 229 | "requires": { 230 | "cross-spawn": "^5.1.0", 231 | "is-windows": "^1.0.0" 232 | } 233 | }, 234 | "cross-spawn": { 235 | "version": "5.1.0", 236 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", 237 | "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", 238 | "dev": true, 239 | "requires": { 240 | "lru-cache": "^4.0.1", 241 | "shebang-command": "^1.2.0", 242 | "which": "^1.2.9" 243 | } 244 | }, 245 | "debug": { 246 | "version": "2.6.0", 247 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", 248 | "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", 249 | "dev": true, 250 | "requires": { 251 | "ms": "0.7.2" 252 | } 253 | }, 254 | "decamelize": { 255 | "version": "1.2.0", 256 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 257 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 258 | "dev": true 259 | }, 260 | "deep-eql": { 261 | "version": "2.0.2", 262 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-2.0.2.tgz", 263 | "integrity": "sha1-sbrAblbwp2d3aG1Qyf63XC7XZ5o=", 264 | "dev": true, 265 | "requires": { 266 | "type-detect": "^3.0.0" 267 | }, 268 | "dependencies": { 269 | "type-detect": { 270 | "version": "3.0.0", 271 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-3.0.0.tgz", 272 | "integrity": "sha1-RtDMhVOrt7E6NSsNbeov1Y8tm1U=", 273 | "dev": true 274 | } 275 | } 276 | }, 277 | "diff": { 278 | "version": "3.2.0", 279 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", 280 | "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", 281 | "dev": true 282 | }, 283 | "error-ex": { 284 | "version": "1.3.2", 285 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 286 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 287 | "dev": true, 288 | "requires": { 289 | "is-arrayish": "^0.2.1" 290 | } 291 | }, 292 | "escape-string-regexp": { 293 | "version": "1.0.5", 294 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 295 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 296 | "dev": true 297 | }, 298 | "esutils": { 299 | "version": "2.0.3", 300 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 301 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 302 | "dev": true 303 | }, 304 | "fast-deep-equal": { 305 | "version": "3.1.3", 306 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 307 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 308 | }, 309 | "fast-json-stable-stringify": { 310 | "version": "2.1.0", 311 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 312 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 313 | }, 314 | "find-up": { 315 | "version": "1.1.2", 316 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", 317 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", 318 | "dev": true, 319 | "requires": { 320 | "path-exists": "^2.0.0", 321 | "pinkie-promise": "^2.0.0" 322 | } 323 | }, 324 | "fs.realpath": { 325 | "version": "1.0.0", 326 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 327 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 328 | "dev": true 329 | }, 330 | "function-bind": { 331 | "version": "1.1.1", 332 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 333 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 334 | "dev": true 335 | }, 336 | "get-caller-file": { 337 | "version": "1.0.3", 338 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", 339 | "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", 340 | "dev": true 341 | }, 342 | "get-func-name": { 343 | "version": "2.0.0", 344 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 345 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 346 | "dev": true 347 | }, 348 | "glob": { 349 | "version": "7.1.1", 350 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", 351 | "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", 352 | "dev": true, 353 | "requires": { 354 | "fs.realpath": "^1.0.0", 355 | "inflight": "^1.0.4", 356 | "inherits": "2", 357 | "minimatch": "^3.0.2", 358 | "once": "^1.3.0", 359 | "path-is-absolute": "^1.0.0" 360 | } 361 | }, 362 | "graceful-fs": { 363 | "version": "4.2.4", 364 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", 365 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", 366 | "dev": true 367 | }, 368 | "graceful-readlink": { 369 | "version": "1.0.1", 370 | "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", 371 | "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", 372 | "dev": true 373 | }, 374 | "growl": { 375 | "version": "1.9.2", 376 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", 377 | "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", 378 | "dev": true 379 | }, 380 | "has": { 381 | "version": "1.0.3", 382 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 383 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 384 | "dev": true, 385 | "requires": { 386 | "function-bind": "^1.1.1" 387 | } 388 | }, 389 | "has-ansi": { 390 | "version": "2.0.0", 391 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 392 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 393 | "dev": true, 394 | "requires": { 395 | "ansi-regex": "^2.0.0" 396 | } 397 | }, 398 | "has-flag": { 399 | "version": "1.0.0", 400 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 401 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", 402 | "dev": true 403 | }, 404 | "homedir-polyfill": { 405 | "version": "1.0.3", 406 | "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", 407 | "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", 408 | "dev": true, 409 | "requires": { 410 | "parse-passwd": "^1.0.0" 411 | } 412 | }, 413 | "hosted-git-info": { 414 | "version": "2.8.8", 415 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", 416 | "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", 417 | "dev": true 418 | }, 419 | "inflight": { 420 | "version": "1.0.6", 421 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 422 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 423 | "dev": true, 424 | "requires": { 425 | "once": "^1.3.0", 426 | "wrappy": "1" 427 | } 428 | }, 429 | "inherits": { 430 | "version": "2.0.4", 431 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 432 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 433 | "dev": true 434 | }, 435 | "invert-kv": { 436 | "version": "1.0.0", 437 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", 438 | "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", 439 | "dev": true 440 | }, 441 | "is-arrayish": { 442 | "version": "0.2.1", 443 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 444 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 445 | "dev": true 446 | }, 447 | "is-core-module": { 448 | "version": "2.0.0", 449 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.0.0.tgz", 450 | "integrity": "sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==", 451 | "dev": true, 452 | "requires": { 453 | "has": "^1.0.3" 454 | } 455 | }, 456 | "is-fullwidth-code-point": { 457 | "version": "1.0.0", 458 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 459 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 460 | "dev": true, 461 | "requires": { 462 | "number-is-nan": "^1.0.0" 463 | } 464 | }, 465 | "is-utf8": { 466 | "version": "0.2.1", 467 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", 468 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", 469 | "dev": true 470 | }, 471 | "is-windows": { 472 | "version": "1.0.2", 473 | "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", 474 | "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", 475 | "dev": true 476 | }, 477 | "isexe": { 478 | "version": "2.0.0", 479 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 480 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 481 | "dev": true 482 | }, 483 | "js-tokens": { 484 | "version": "3.0.2", 485 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 486 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 487 | "dev": true 488 | }, 489 | "json-schema-traverse": { 490 | "version": "0.4.1", 491 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 492 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 493 | }, 494 | "json3": { 495 | "version": "3.3.2", 496 | "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", 497 | "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", 498 | "dev": true 499 | }, 500 | "lcid": { 501 | "version": "1.0.0", 502 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", 503 | "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", 504 | "dev": true, 505 | "requires": { 506 | "invert-kv": "^1.0.0" 507 | } 508 | }, 509 | "load-json-file": { 510 | "version": "1.1.0", 511 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", 512 | "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", 513 | "dev": true, 514 | "requires": { 515 | "graceful-fs": "^4.1.2", 516 | "parse-json": "^2.2.0", 517 | "pify": "^2.0.0", 518 | "pinkie-promise": "^2.0.0", 519 | "strip-bom": "^2.0.0" 520 | }, 521 | "dependencies": { 522 | "strip-bom": { 523 | "version": "2.0.0", 524 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", 525 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", 526 | "dev": true, 527 | "requires": { 528 | "is-utf8": "^0.2.0" 529 | } 530 | } 531 | } 532 | }, 533 | "lodash": { 534 | "version": "4.17.20", 535 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 536 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", 537 | "dev": true 538 | }, 539 | "lodash._baseassign": { 540 | "version": "3.2.0", 541 | "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", 542 | "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", 543 | "dev": true, 544 | "requires": { 545 | "lodash._basecopy": "^3.0.0", 546 | "lodash.keys": "^3.0.0" 547 | } 548 | }, 549 | "lodash._basecopy": { 550 | "version": "3.0.1", 551 | "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", 552 | "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", 553 | "dev": true 554 | }, 555 | "lodash._basecreate": { 556 | "version": "3.0.3", 557 | "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", 558 | "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", 559 | "dev": true 560 | }, 561 | "lodash._getnative": { 562 | "version": "3.9.1", 563 | "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", 564 | "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", 565 | "dev": true 566 | }, 567 | "lodash._isiterateecall": { 568 | "version": "3.0.9", 569 | "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", 570 | "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", 571 | "dev": true 572 | }, 573 | "lodash.create": { 574 | "version": "3.1.1", 575 | "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", 576 | "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", 577 | "dev": true, 578 | "requires": { 579 | "lodash._baseassign": "^3.0.0", 580 | "lodash._basecreate": "^3.0.0", 581 | "lodash._isiterateecall": "^3.0.0" 582 | } 583 | }, 584 | "lodash.isarguments": { 585 | "version": "3.1.0", 586 | "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", 587 | "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", 588 | "dev": true 589 | }, 590 | "lodash.isarray": { 591 | "version": "3.0.4", 592 | "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", 593 | "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", 594 | "dev": true 595 | }, 596 | "lodash.keys": { 597 | "version": "3.1.2", 598 | "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", 599 | "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", 600 | "dev": true, 601 | "requires": { 602 | "lodash._getnative": "^3.0.0", 603 | "lodash.isarguments": "^3.0.0", 604 | "lodash.isarray": "^3.0.0" 605 | } 606 | }, 607 | "lru-cache": { 608 | "version": "4.1.5", 609 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", 610 | "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", 611 | "dev": true, 612 | "requires": { 613 | "pseudomap": "^1.0.2", 614 | "yallist": "^2.1.2" 615 | } 616 | }, 617 | "make-error": { 618 | "version": "1.3.6", 619 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 620 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 621 | "dev": true 622 | }, 623 | "minimatch": { 624 | "version": "3.0.4", 625 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 626 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 627 | "dev": true, 628 | "requires": { 629 | "brace-expansion": "^1.1.7" 630 | } 631 | }, 632 | "minimist": { 633 | "version": "0.0.8", 634 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 635 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 636 | "dev": true 637 | }, 638 | "mkdirp": { 639 | "version": "0.5.1", 640 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 641 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 642 | "dev": true, 643 | "requires": { 644 | "minimist": "0.0.8" 645 | } 646 | }, 647 | "mocha": { 648 | "version": "3.4.2", 649 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.4.2.tgz", 650 | "integrity": "sha1-0O9NMyEm2/GNDWQMmzgt1IvpdZQ=", 651 | "dev": true, 652 | "requires": { 653 | "browser-stdout": "1.3.0", 654 | "commander": "2.9.0", 655 | "debug": "2.6.0", 656 | "diff": "3.2.0", 657 | "escape-string-regexp": "1.0.5", 658 | "glob": "7.1.1", 659 | "growl": "1.9.2", 660 | "json3": "3.3.2", 661 | "lodash.create": "3.1.1", 662 | "mkdirp": "0.5.1", 663 | "supports-color": "3.1.2" 664 | } 665 | }, 666 | "ms": { 667 | "version": "0.7.2", 668 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 669 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", 670 | "dev": true 671 | }, 672 | "normalize-package-data": { 673 | "version": "2.5.0", 674 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", 675 | "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", 676 | "dev": true, 677 | "requires": { 678 | "hosted-git-info": "^2.1.4", 679 | "resolve": "^1.10.0", 680 | "semver": "2 || 3 || 4 || 5", 681 | "validate-npm-package-license": "^3.0.1" 682 | } 683 | }, 684 | "number-is-nan": { 685 | "version": "1.0.1", 686 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 687 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 688 | "dev": true 689 | }, 690 | "once": { 691 | "version": "1.4.0", 692 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 693 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 694 | "dev": true, 695 | "requires": { 696 | "wrappy": "1" 697 | } 698 | }, 699 | "os-locale": { 700 | "version": "1.4.0", 701 | "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", 702 | "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", 703 | "dev": true, 704 | "requires": { 705 | "lcid": "^1.0.0" 706 | } 707 | }, 708 | "parse-json": { 709 | "version": "2.2.0", 710 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 711 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 712 | "dev": true, 713 | "requires": { 714 | "error-ex": "^1.2.0" 715 | } 716 | }, 717 | "parse-passwd": { 718 | "version": "1.0.0", 719 | "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", 720 | "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", 721 | "dev": true 722 | }, 723 | "path-exists": { 724 | "version": "2.1.0", 725 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", 726 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", 727 | "dev": true, 728 | "requires": { 729 | "pinkie-promise": "^2.0.0" 730 | } 731 | }, 732 | "path-is-absolute": { 733 | "version": "1.0.1", 734 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 735 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 736 | "dev": true 737 | }, 738 | "path-parse": { 739 | "version": "1.0.6", 740 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 741 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 742 | "dev": true 743 | }, 744 | "path-type": { 745 | "version": "1.1.0", 746 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", 747 | "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", 748 | "dev": true, 749 | "requires": { 750 | "graceful-fs": "^4.1.2", 751 | "pify": "^2.0.0", 752 | "pinkie-promise": "^2.0.0" 753 | } 754 | }, 755 | "pathval": { 756 | "version": "1.1.0", 757 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", 758 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", 759 | "dev": true 760 | }, 761 | "pify": { 762 | "version": "2.3.0", 763 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 764 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 765 | "dev": true 766 | }, 767 | "pinkie": { 768 | "version": "2.0.4", 769 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 770 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 771 | "dev": true 772 | }, 773 | "pinkie-promise": { 774 | "version": "2.0.1", 775 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 776 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 777 | "dev": true, 778 | "requires": { 779 | "pinkie": "^2.0.0" 780 | } 781 | }, 782 | "pseudomap": { 783 | "version": "1.0.2", 784 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 785 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", 786 | "dev": true 787 | }, 788 | "punycode": { 789 | "version": "2.1.1", 790 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 791 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 792 | }, 793 | "read-pkg": { 794 | "version": "1.1.0", 795 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", 796 | "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", 797 | "dev": true, 798 | "requires": { 799 | "load-json-file": "^1.0.0", 800 | "normalize-package-data": "^2.3.2", 801 | "path-type": "^1.0.0" 802 | } 803 | }, 804 | "read-pkg-up": { 805 | "version": "1.0.1", 806 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", 807 | "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", 808 | "dev": true, 809 | "requires": { 810 | "find-up": "^1.0.0", 811 | "read-pkg": "^1.0.0" 812 | } 813 | }, 814 | "require-directory": { 815 | "version": "2.1.1", 816 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 817 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 818 | "dev": true 819 | }, 820 | "require-main-filename": { 821 | "version": "1.0.1", 822 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", 823 | "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", 824 | "dev": true 825 | }, 826 | "resolve": { 827 | "version": "1.18.1", 828 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", 829 | "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", 830 | "dev": true, 831 | "requires": { 832 | "is-core-module": "^2.0.0", 833 | "path-parse": "^1.0.6" 834 | } 835 | }, 836 | "semver": { 837 | "version": "5.7.1", 838 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 839 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 840 | "dev": true 841 | }, 842 | "set-blocking": { 843 | "version": "2.0.0", 844 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 845 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 846 | "dev": true 847 | }, 848 | "shebang-command": { 849 | "version": "1.2.0", 850 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 851 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 852 | "dev": true, 853 | "requires": { 854 | "shebang-regex": "^1.0.0" 855 | } 856 | }, 857 | "shebang-regex": { 858 | "version": "1.0.0", 859 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 860 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 861 | "dev": true 862 | }, 863 | "source-map": { 864 | "version": "0.5.7", 865 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 866 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 867 | "dev": true 868 | }, 869 | "source-map-support": { 870 | "version": "0.4.18", 871 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", 872 | "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", 873 | "dev": true, 874 | "requires": { 875 | "source-map": "^0.5.6" 876 | } 877 | }, 878 | "spdx-correct": { 879 | "version": "3.1.1", 880 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", 881 | "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", 882 | "dev": true, 883 | "requires": { 884 | "spdx-expression-parse": "^3.0.0", 885 | "spdx-license-ids": "^3.0.0" 886 | } 887 | }, 888 | "spdx-exceptions": { 889 | "version": "2.3.0", 890 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", 891 | "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", 892 | "dev": true 893 | }, 894 | "spdx-expression-parse": { 895 | "version": "3.0.1", 896 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", 897 | "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", 898 | "dev": true, 899 | "requires": { 900 | "spdx-exceptions": "^2.1.0", 901 | "spdx-license-ids": "^3.0.0" 902 | } 903 | }, 904 | "spdx-license-ids": { 905 | "version": "3.0.6", 906 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", 907 | "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", 908 | "dev": true 909 | }, 910 | "string-width": { 911 | "version": "1.0.2", 912 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 913 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 914 | "dev": true, 915 | "requires": { 916 | "code-point-at": "^1.0.0", 917 | "is-fullwidth-code-point": "^1.0.0", 918 | "strip-ansi": "^3.0.0" 919 | } 920 | }, 921 | "strip-ansi": { 922 | "version": "3.0.1", 923 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 924 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 925 | "dev": true, 926 | "requires": { 927 | "ansi-regex": "^2.0.0" 928 | } 929 | }, 930 | "strip-bom": { 931 | "version": "3.0.0", 932 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 933 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", 934 | "dev": true 935 | }, 936 | "strip-json-comments": { 937 | "version": "2.0.1", 938 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 939 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 940 | "dev": true 941 | }, 942 | "supports-color": { 943 | "version": "3.1.2", 944 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", 945 | "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", 946 | "dev": true, 947 | "requires": { 948 | "has-flag": "^1.0.0" 949 | } 950 | }, 951 | "ts-node": { 952 | "version": "3.3.0", 953 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-3.3.0.tgz", 954 | "integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=", 955 | "dev": true, 956 | "requires": { 957 | "arrify": "^1.0.0", 958 | "chalk": "^2.0.0", 959 | "diff": "^3.1.0", 960 | "make-error": "^1.1.1", 961 | "minimist": "^1.2.0", 962 | "mkdirp": "^0.5.1", 963 | "source-map-support": "^0.4.0", 964 | "tsconfig": "^6.0.0", 965 | "v8flags": "^3.0.0", 966 | "yn": "^2.0.0" 967 | }, 968 | "dependencies": { 969 | "minimist": { 970 | "version": "1.2.5", 971 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 972 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 973 | "dev": true 974 | } 975 | } 976 | }, 977 | "tsconfig": { 978 | "version": "6.0.0", 979 | "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-6.0.0.tgz", 980 | "integrity": "sha1-aw6DdgA9evGGT434+J3QBZ/80DI=", 981 | "dev": true, 982 | "requires": { 983 | "strip-bom": "^3.0.0", 984 | "strip-json-comments": "^2.0.0" 985 | } 986 | }, 987 | "tslib": { 988 | "version": "1.14.1", 989 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 990 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", 991 | "dev": true 992 | }, 993 | "tslint": { 994 | "version": "5.7.0", 995 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.7.0.tgz", 996 | "integrity": "sha1-wl4NDJL6EgHCvDDoROCOaCtPNVI=", 997 | "dev": true, 998 | "requires": { 999 | "babel-code-frame": "^6.22.0", 1000 | "colors": "^1.1.2", 1001 | "commander": "^2.9.0", 1002 | "diff": "^3.2.0", 1003 | "glob": "^7.1.1", 1004 | "minimatch": "^3.0.4", 1005 | "resolve": "^1.3.2", 1006 | "semver": "^5.3.0", 1007 | "tslib": "^1.7.1", 1008 | "tsutils": "^2.8.1" 1009 | } 1010 | }, 1011 | "tsutils": { 1012 | "version": "2.29.0", 1013 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 1014 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 1015 | "dev": true, 1016 | "requires": { 1017 | "tslib": "^1.8.1" 1018 | } 1019 | }, 1020 | "type-detect": { 1021 | "version": "4.0.8", 1022 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 1023 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 1024 | "dev": true 1025 | }, 1026 | "typescript": { 1027 | "version": "2.5.3", 1028 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", 1029 | "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", 1030 | "dev": true 1031 | }, 1032 | "typings-checker": { 1033 | "version": "2.0.0", 1034 | "resolved": "https://registry.npmjs.org/typings-checker/-/typings-checker-2.0.0.tgz", 1035 | "integrity": "sha1-xtWvD/P8cGXaIqaTPhKQ0Wr2zFY=", 1036 | "dev": true, 1037 | "requires": { 1038 | "lodash": "^4.17.4", 1039 | "yargs": "^6.6.0" 1040 | } 1041 | }, 1042 | "uri-js": { 1043 | "version": "4.4.0", 1044 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", 1045 | "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", 1046 | "requires": { 1047 | "punycode": "^2.1.0" 1048 | } 1049 | }, 1050 | "v8flags": { 1051 | "version": "3.2.0", 1052 | "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", 1053 | "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", 1054 | "dev": true, 1055 | "requires": { 1056 | "homedir-polyfill": "^1.0.1" 1057 | } 1058 | }, 1059 | "validate-npm-package-license": { 1060 | "version": "3.0.4", 1061 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", 1062 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", 1063 | "dev": true, 1064 | "requires": { 1065 | "spdx-correct": "^3.0.0", 1066 | "spdx-expression-parse": "^3.0.0" 1067 | } 1068 | }, 1069 | "which": { 1070 | "version": "1.3.1", 1071 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1072 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1073 | "dev": true, 1074 | "requires": { 1075 | "isexe": "^2.0.0" 1076 | } 1077 | }, 1078 | "which-module": { 1079 | "version": "1.0.0", 1080 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", 1081 | "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", 1082 | "dev": true 1083 | }, 1084 | "wrap-ansi": { 1085 | "version": "2.1.0", 1086 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 1087 | "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 1088 | "dev": true, 1089 | "requires": { 1090 | "string-width": "^1.0.1", 1091 | "strip-ansi": "^3.0.1" 1092 | } 1093 | }, 1094 | "wrappy": { 1095 | "version": "1.0.2", 1096 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1097 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1098 | "dev": true 1099 | }, 1100 | "y18n": { 1101 | "version": "3.2.1", 1102 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", 1103 | "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", 1104 | "dev": true 1105 | }, 1106 | "yallist": { 1107 | "version": "2.1.2", 1108 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 1109 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", 1110 | "dev": true 1111 | }, 1112 | "yargs": { 1113 | "version": "6.6.0", 1114 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", 1115 | "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", 1116 | "dev": true, 1117 | "requires": { 1118 | "camelcase": "^3.0.0", 1119 | "cliui": "^3.2.0", 1120 | "decamelize": "^1.1.1", 1121 | "get-caller-file": "^1.0.1", 1122 | "os-locale": "^1.4.0", 1123 | "read-pkg-up": "^1.0.1", 1124 | "require-directory": "^2.1.1", 1125 | "require-main-filename": "^1.0.1", 1126 | "set-blocking": "^2.0.0", 1127 | "string-width": "^1.0.2", 1128 | "which-module": "^1.0.0", 1129 | "y18n": "^3.2.1", 1130 | "yargs-parser": "^4.2.0" 1131 | } 1132 | }, 1133 | "yargs-parser": { 1134 | "version": "4.2.1", 1135 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", 1136 | "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", 1137 | "dev": true, 1138 | "requires": { 1139 | "camelcase": "^3.0.0" 1140 | } 1141 | }, 1142 | "yn": { 1143 | "version": "2.0.0", 1144 | "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", 1145 | "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", 1146 | "dev": true 1147 | } 1148 | } 1149 | } 1150 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typed-json-schema", 3 | "version": "4.0.5", 4 | "description": "", 5 | "main": "index", 6 | "typings": "index.d.ts", 7 | "scripts": { 8 | "mocha": "cross-env TS_NODE_CACHE=false mocha test/**/*.spec.ts", 9 | "test-typedefs": "typings-checker --project test-typedefs/tsconfig.json --allow-expect-error test-typedefs/*.ts", 10 | "lint": "tslint --project . && tslint --project test && tslint --project test-typedefs", 11 | "test": "npm run mocha && npm run test-typedefs && npm run lint", 12 | "clean": "rm *.js *.d.ts; rm -rf ext/;true", 13 | "tsc": "tsc --declaration", 14 | "build": "npm run clean && npm run tsc", 15 | "prepublish": "npm test && npm run build", 16 | "postpublish": "npm run clean" 17 | }, 18 | "files": [ 19 | "*.js", 20 | "*.d.ts", 21 | "ext" 22 | ], 23 | "author": "Sam Beran (sberan@gmail.com)", 24 | "license": "MIT", 25 | "repository": { 26 | "type": "git", 27 | "url": "git@github.com:sberan/typed-json-schema.git" 28 | }, 29 | "dependencies": { 30 | "ajv": "6.12.6" 31 | }, 32 | "devDependencies": { 33 | "@types/chai": "4.0.1", 34 | "@types/mocha": "2.2.41", 35 | "chai": "4.1.0", 36 | "cross-env": "5.0.5", 37 | "mocha": "3.4.2", 38 | "ts-node": "3.3.0", 39 | "tslint": "5.7.0", 40 | "typescript": "2.5", 41 | "typings-checker": "2.0.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/ext/allow-null.ts: -------------------------------------------------------------------------------- 1 | import { Schema } from '../schema' 2 | import { Diff, JSONObject } from '../util' 3 | import { CustomKeyword } from '../validator' 4 | 5 | declare module '../schema' { 6 | interface Schema { 7 | allowNull (): SchemaUpdate 8 | } 9 | } 10 | 11 | Schema.prototype.allowNull = function () { 12 | const 13 | props = this.props, 14 | enums = props.enum 15 | 16 | let type = props.type 17 | 18 | if (Array.isArray(enums) && !enums.includes(null)) { 19 | enums.push(null) 20 | } 21 | if (!type || type === 'null') { 22 | return this 23 | } 24 | if (!Array.isArray(type)) { 25 | type = [type] 26 | } 27 | if (!type.includes('null')) { 28 | type.push('null') 29 | } 30 | return this.setProps({ type }) 31 | } 32 | 33 | export const allowNull = [] 34 | -------------------------------------------------------------------------------- /src/ext/index.ts: -------------------------------------------------------------------------------- 1 | import { CustomKeywords } from '../validator' 2 | import './allow-null' 3 | import { allowNull } from './allow-null' 4 | import './strict-properties' 5 | import { strictProperties } from './strict-properties' 6 | import './trim' 7 | import { trim } from './trim' 8 | 9 | export { CustomKeyword } from '../validator' 10 | 11 | export const ext: CustomKeywords = [ 12 | allowNull, 13 | strictProperties, 14 | trim 15 | ] 16 | 17 | export * from '../index' 18 | -------------------------------------------------------------------------------- /src/ext/strict-properties.ts: -------------------------------------------------------------------------------- 1 | import { Schema } from '../schema' 2 | import { Diff, JSONObject } from '../util' 3 | import { CustomKeyword } from '../validator' 4 | 5 | declare module '../schema' { 6 | interface TypeDefs { 7 | strictObject: {[P in Diff]: State['strictProperties'][P] } 8 | & {[P in State['optional']]?: State['strictProperties'][P] } 9 | } 10 | 11 | interface SchemaState { 12 | strictProperties: any 13 | optional: string 14 | } 15 | 16 | interface DefaultSchemaState { 17 | strictProperties: {} 18 | optional: never 19 | } 20 | 21 | interface Schema { 22 | strictProperties}> (properties: Properties) 23 | : SchemaMultiUpdate 27 | 28 | optional (...properties: Properties[]) 29 | : SchemaUpdate 30 | } 31 | } 32 | 33 | Schema.prototype.strictProperties = function (strictProperties): any { 34 | const 35 | optional = this.getState('optional') as string[] | undefined, 36 | strictKeys = Object.keys(strictProperties).filter(p => { 37 | return !optional || optional.indexOf(p) < 0 38 | }) 39 | return this 40 | .properties(strictProperties) 41 | .additionalProperties(false) 42 | .required(...strictKeys) 43 | } 44 | 45 | Schema.prototype.optional = function (...properties): any { 46 | this.setState('optional', properties) 47 | const props = this.props, 48 | existingRequireds = props && props.required 49 | if (Array.isArray(existingRequireds)) { 50 | properties.forEach(property => { 51 | const existingIndex = existingRequireds.indexOf(property) 52 | if (existingIndex !== -1) { 53 | existingRequireds.splice(existingIndex, 1) 54 | } 55 | }) 56 | } 57 | return this 58 | } 59 | 60 | export const strictProperties = [] 61 | -------------------------------------------------------------------------------- /src/ext/trim.ts: -------------------------------------------------------------------------------- 1 | import { Schema } from '../schema' 2 | import { CustomKeyword } from '../validator' 3 | 4 | declare module '../schema' { 5 | interface Schema { 6 | trim (trim?: boolean): Schema 7 | } 8 | } 9 | 10 | Schema.prototype.trim = function (trim = true) { 11 | return this.setProps({ trim }) 12 | } 13 | 14 | export const trim: CustomKeyword = { 15 | name: 'trim', 16 | modifying: true, 17 | validate: ( 18 | schema: any, 19 | data: any, 20 | parentSchema?: object, 21 | dataPath?: string, 22 | parentData?: object | any[], 23 | parentDataProperty?: string | number, 24 | rootData?: object | any[] 25 | ) => { 26 | if (typeof data === 'string' && parentData !== undefined && parentDataProperty !== undefined) { 27 | const trimmedString = data.trim(); 28 | (parentData as any)[parentDataProperty] = trimmedString 29 | } 30 | return true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Schema } from './schema' 2 | import { DefaultSchemaState } from './schema' 3 | import { callableInstance } from './util' 4 | 5 | export { Schema } from './schema' 6 | export { Validator, ValidationError } from './validator' 7 | 8 | export type schema> = T['TypeOf'] 9 | 10 | export const 11 | schema = new Schema(), 12 | number = schema.type('number'), // tslint:disable-line:variable-name 13 | integer = schema.type('integer'), 14 | string = schema.type('string'), // tslint:disable-line:variable-name 15 | boolean = schema.type('boolean'), // tslint:disable-line:variable-name 16 | array = callableInstance(schema.type('array'), 'items'), 17 | object = callableInstance(schema.type('object'), 'properties') 18 | -------------------------------------------------------------------------------- /src/schema.ts: -------------------------------------------------------------------------------- 1 | import { AnyJSON, copyJson, Diff, JSONObject, Omit, Overwrite } from './util' 2 | 3 | export type SchemaUpdate< 4 | State extends SchemaState, K extends keyof SchemaState, 5 | V extends SchemaState[K] 6 | > = Schema & {[P in K]: V}> 7 | 8 | export type SchemaMultiUpdate< 9 | State extends SchemaState, 10 | K extends keyof SchemaState, 11 | U extends {[P in K]: SchemaState[P]} 12 | > = Schema> 13 | 14 | export type TypeNames = 'string' | 'number' | 'integer' | 'boolean' | 'null' | 'array' | 'object' 15 | 16 | export interface TypeDefs { 17 | any: any 18 | string: string 19 | number: number 20 | integer: number 21 | boolean: boolean 22 | null: null 23 | array: Array 24 | object: State['anyOf'] & State['oneOf'] & State['allOf'] 25 | & {[P in State['required']]: State['properties'][P]} 26 | & {[P in Diff]?: State['properties'][P] } 27 | & {[P in State['additionalProperties']['key'] | State['patternProperties']['key']] 28 | ?: State['additionalProperties']['type'] | State['patternProperties']['type'] }, 29 | enum: State['enum'] 30 | const: State['const'] 31 | } 32 | 33 | export interface SchemaState { 34 | type: keyof TypeDefs 35 | items: any 36 | additionalItems: any 37 | properties: any 38 | required: string 39 | additionalProperties: {key: string, type: any} 40 | patternProperties: {key: string, type: any} 41 | enum: any 42 | anyOf: any 43 | oneOf: any 44 | allOf: any 45 | const: any 46 | } 47 | 48 | export interface DefaultSchemaState { 49 | type: 'any' 50 | items: any 51 | additionalItems: never 52 | properties: any 53 | required: never 54 | additionalProperties: {key: string, type: any} 55 | patternProperties: {key: never, type: never} 56 | enum: any 57 | const: any 58 | anyOf: {} 59 | oneOf: {} 60 | allOf: {} 61 | } 62 | 63 | export class Schema { 64 | TypeOf: TypeDefs[State['type']] 65 | 66 | constructor (readonly props: JSONObject = {}, private readonly state: JSONObject = {}) { } 67 | 68 | setProps (props: JSONObject): any { 69 | return new Schema({ ...copyJson(this.props), ...props }, { ...this.state }) 70 | } 71 | 72 | getState (key: string) { 73 | return this.state[key] 74 | } 75 | 76 | setState (key: string, val: AnyJSON) { 77 | this.state[key] = val 78 | } 79 | 80 | toJSON () { 81 | return copyJson(this.props) 82 | } 83 | 84 | /*====================== 85 | GLOBAL 86 | ========================*/ 87 | type (type: TypeKeys[] | TypeKeys): SchemaUpdate { 88 | return this.setProps({ type }) 89 | } 90 | 91 | enum (values: T[]): SchemaMultiUpdate { 92 | return this.setProps({ enum: values }) 93 | } 94 | 95 | const (constValue: T): SchemaMultiUpdate { 96 | return this.setProps({ const: constValue }) 97 | } 98 | 99 | anyOf> (schemas: S[]): SchemaUpdate { 100 | return this.setProps({ anyOf: schemas.map((s) => s.props) }) 101 | } 102 | 103 | oneOf> (schemas: S[]): SchemaUpdate { 104 | return this.setProps({ oneOf: schemas.map((s) => s.props) }) 105 | } 106 | 107 | // TODO: these should be intersection types but that doesn't work :( 108 | allOf> (schemas: S[]): SchemaUpdate { 109 | return this.setProps({ allOf: schemas.map((s) => s.props) }) 110 | } 111 | 112 | title (title: string): this { 113 | return this.setProps({ title }) 114 | } 115 | 116 | description (description: string): this { 117 | return this.setProps({ description }) 118 | } 119 | 120 | default (defaultValue: AnyJSON): this { 121 | return this.setProps({ default: defaultValue }) 122 | } 123 | 124 | example> (example: S['TypeOf']): this { 125 | return this.setProps({ example }) 126 | } 127 | 128 | not (schema: Schema): this { 129 | return this.setProps({ not: schema.props }) 130 | } 131 | 132 | /*============ 133 | Array 134 | =============*/ 135 | items> (items: ItemsSchema[] | ItemsSchema) 136 | : SchemaUpdate { 137 | if (Array.isArray(items)) { 138 | return this.setProps({ items: items.map((i) => i.props)}) 139 | } else { 140 | return this.setProps({ items: items.props }) 141 | } 142 | } 143 | 144 | additionalItems (additionalItems: true): SchemaUpdate 145 | additionalItems (additionalItems: false): this 146 | additionalItems> (additionalItems: ItemsSchema) 147 | : SchemaUpdate 148 | additionalItems> (additionalItems: boolean | ItemsSchema) { 149 | if (additionalItems === true) { 150 | return this.setProps({ additionalItems: true }) 151 | } else if (additionalItems === false) { 152 | return this 153 | } else { 154 | return this.setProps({ additionalItems: additionalItems.props }) 155 | } 156 | } 157 | 158 | contains (contains: Schema): this { 159 | return this.setProps({ contains: contains.props }) 160 | } 161 | 162 | maxItems (maxItems: number): this { 163 | return this.setProps({ maxItems }) 164 | } 165 | 166 | minItems (minItems: number): this { 167 | return this.setProps({ minItems }) 168 | } 169 | 170 | uniqueItems (uniqueItems: boolean): this { 171 | return this.setProps({ uniqueItems }) 172 | } 173 | 174 | /*=============== 175 | OBJECT 176 | =================*/ 177 | properties}> (properties: Properties) 178 | : SchemaUpdate { 179 | const props = Object.keys(properties).reduce((acc, key: keyof Properties) => { 180 | acc[key] = (properties[key] as Schema).props 181 | return acc 182 | }, {}) 183 | return this.setProps({ properties: props }) 184 | } 185 | 186 | required (...required: K[]): SchemaUpdate { 187 | return this.setProps({ required }) 188 | } 189 | 190 | additionalProperties (additionalProperties: true) 191 | : SchemaUpdate 192 | additionalProperties (additionalProperties: false) 193 | : SchemaUpdate 194 | additionalProperties> (additionalProperties: T) 195 | : SchemaUpdate 196 | additionalProperties (additionalProperties: boolean | Schema): any { 197 | if (additionalProperties instanceof Schema) { 198 | return this.setProps({ additionalProperties: additionalProperties.props }) 199 | } else { 200 | return this.setProps({ additionalProperties }) 201 | } 202 | } 203 | 204 | patternProperties> (patternProperties: { [key: string]: T }) 205 | : SchemaUpdate { 206 | const props = Object.keys(patternProperties).reduce((acc, key: keyof typeof patternProperties) => { 207 | acc[key] = patternProperties[key].props 208 | return acc 209 | }, {}) 210 | return this.setProps({ patternProperties: props }) 211 | } 212 | 213 | dependencies (dependencies: {[key: string]: Schema | string[]}): this { 214 | const props = Object.keys(dependencies).reduce((acc, key) => { 215 | const value = dependencies[key] 216 | if (Array.isArray(value)) { 217 | acc[key] = value 218 | } else { 219 | acc[key] = value.props 220 | } 221 | return acc 222 | }, {}) 223 | return this.setProps({ dependencies: props }) 224 | } 225 | 226 | maxProperties (maxProperties: number): this { 227 | return this.setProps({ maxProperties }) 228 | } 229 | 230 | minProperties (minProperties: number): this { 231 | return this.setProps({ minProperties }) 232 | } 233 | 234 | /*=================== 235 | NUMBER 236 | =====================*/ 237 | maximum (maximum: number): this { 238 | return this.setProps({ maximum }) 239 | } 240 | 241 | minimum (minimum: number): this { 242 | return this.setProps({ minimum }) 243 | } 244 | 245 | exclusiveMaximum (exclusiveMaximum: number | boolean): this { 246 | return this.setProps({ exclusiveMaximum }) 247 | } 248 | 249 | exclusiveMinimum (exclusiveMinimum: number | boolean): this { 250 | return this.setProps({ exclusiveMinimum }) 251 | } 252 | 253 | multipleOf (multipleOf: number): this { 254 | return this.setProps({ multipleOf }) 255 | } 256 | 257 | /*============= 258 | STRING 259 | ===============*/ 260 | maxLength (maxLength: number): this { 261 | return this.setProps({ maxLength }) 262 | } 263 | 264 | minLength (minLength: number): this { 265 | return this.setProps({ minLength }) 266 | } 267 | 268 | pattern (pattern: RegExp): this { 269 | return this.setProps({ pattern: pattern.source }) 270 | } 271 | 272 | format (format: string): this { 273 | return this.setProps({ format }) 274 | } 275 | } 276 | 277 | // make schema instances newable so that they can be validated using decorators 278 | declare module './schema' { 279 | // tslint:disable-next-line:no-shadowed-variable 280 | export interface Schema { 281 | new (...args: any[]): never 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | export type JSONPrimitive = string | number | boolean | null 2 | export interface JSONArray extends Array {} // tslint:disable-line:no-empty-interface 3 | export interface JSONObject { [key: string]: AnyJSON } 4 | export type AnyJSON = JSONPrimitive | JSONArray | JSONObject 5 | 6 | export function copyJson (json: T) { 7 | return JSON.parse(JSON.stringify(json)) as T 8 | } 9 | 10 | // tslint:disable-next-line:ban-types 11 | export function callableInstance (obj: T, key: K): T & T[K] { 12 | const 13 | boundMethod: T[K] = (obj[key] as Function).bind(obj), // tslint:disable-line:ban-types 14 | merged = Object.assign(boundMethod, obj) 15 | 16 | // tslint:disable-next-line:align 17 | ; (boundMethod as any).__proto__ = (obj as any).__proto__ 18 | return merged 19 | } 20 | 21 | export type Diff 22 | = ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T] 23 | export type Overwrite = { [P in Diff]: T[P] } & U 24 | export type Omit = { [P in Diff]: T[P] } 25 | -------------------------------------------------------------------------------- /src/validator.ts: -------------------------------------------------------------------------------- 1 | 2 | import Ajv = require('ajv') 3 | import { ErrorObject } from 'ajv' 4 | import { Schema } from './schema' 5 | import { AnyJSON } from './util' 6 | 7 | export interface CustomKeyword extends Ajv.KeywordDefinition { 8 | name: string 9 | } 10 | 11 | export type CustomKeywords = Array 12 | 13 | export interface ValidatorOptions extends Ajv.Options { 14 | customKeywords?: CustomKeywords 15 | } 16 | 17 | function addCustomKeywords (ajv: Ajv.Ajv, customKeywords: CustomKeywords) { 18 | customKeywords.forEach(kw => { 19 | if (Array.isArray(kw)) { 20 | addCustomKeywords(ajv, kw) 21 | } else { 22 | ajv.addKeyword(kw.name, kw) 23 | } 24 | }) 25 | } 26 | 27 | export class ValidationError extends Error { 28 | constructor (input: any, schema: Schema, public errors: ErrorObject[]) { 29 | super(` 30 | 31 | could not validate object: 32 | ${JSON.stringify(input, null, 2)} 33 | 34 | against schema: 35 | ${JSON.stringify(schema.toJSON(), null, 2)} 36 | 37 | errors: 38 | * ${errors.map(e => e.message).join('\n * ')}`) 39 | } 40 | } 41 | 42 | // tslint:disable-next-line:max-classes-per-file 43 | export class Validator { 44 | ajv: Ajv.Ajv 45 | 46 | constructor (options: ValidatorOptions = {}) { 47 | this.ajv = new Ajv(options) 48 | if (options.customKeywords) { 49 | addCustomKeywords(this.ajv, options.customKeywords) 50 | } 51 | } 52 | 53 | /** 54 | * @deprecated use validate instead 55 | */ 56 | validateSync > (schema: T, obj: any) 57 | : { valid: false, errors: ErrorObject[], result: null } 58 | | { valid: true, errors: null, result: T['TypeOf'] } { 59 | const validate = this.ajv.compile(schema.toJSON()) 60 | const coercedValue: { result?: T } = { } 61 | const isValid = validate(obj, undefined, coercedValue, 'result') 62 | if (isValid) { 63 | return { errors: null, result: coercedValue.result !== undefined ? coercedValue.result : obj, valid: true } 64 | } else { 65 | return { errors: validate.errors!, result: null, valid: false } 66 | } 67 | } 68 | 69 | validate > (schema: T, obj: any): Promise { 70 | const validate = this.ajv.compile(schema.toJSON()) 71 | const coercedValue: { result?: T } = { } 72 | validate(obj, undefined, coercedValue, 'result') 73 | if (!validate.errors) { 74 | return Promise.resolve(coercedValue.result !== undefined ? coercedValue.result : obj) 75 | } else { 76 | return Promise.reject(new ValidationError(obj, schema, validate.errors)) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /test-typedefs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "module": "commonjs", 6 | "lib": [ "es2016" ], 7 | "baseDir": ".", 8 | "strict": true, 9 | "noEmitOnError": true, 10 | "experimentalDecorators": true, 11 | "emitDecoratorMetadata": true 12 | 13 | }, 14 | "include": [ 15 | "./**/*.ts" 16 | ], 17 | "exclude": [ ] 18 | } 19 | -------------------------------------------------------------------------------- /test-typedefs/typedefs.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-expression */ 2 | import { array, boolean, number, object, schema, string } from '../src' 3 | import '../src/ext' 4 | 5 | schema.TypeOf // $ExpectType any 6 | 7 | schema.type('number').TypeOf // $ExpectType number 8 | 9 | schema.type(['string', 'number']).TypeOf // $ExpectType string | number 10 | 11 | array.TypeOf // $ExpectType any[] 12 | 13 | array.items(string).TypeOf // $ExpectType string[] 14 | 15 | schema.type(['number', 'array']).items(string).TypeOf // $ExpectType number | string[] 16 | 17 | array.items(string).additionalItems(number).TypeOf // $ExpectType (string | number)[] 18 | 19 | array.items([string, number]).TypeOf // $ExpectType (string | number)[] 20 | 21 | array.items([string, number]).additionalItems(boolean).TypeOf // $ExpectType (string | number | boolean)[] 22 | 23 | object.TypeOf.someRandomProperty // $ExpectType any 24 | 25 | object.properties({ a: string }).TypeOf.a // $ExpectType string | undefined 26 | 27 | object.TypeOf.b // $ExpectType any 28 | 29 | object.properties({ a: string }).required('a').TypeOf.a // $ExpectType string 30 | 31 | object.properties({ a: string }).required('b').TypeOf.b // $ExpectType any 32 | 33 | object.properties({ a: string }).additionalProperties(false).TypeOf.a // $ExpectType string | undefined 34 | 35 | // $ExpectType string | boolean | undefined 36 | object.properties({ a: string }).additionalProperties(schema.type(['string', 'boolean'])).TypeOf.b 37 | 38 | // $ExpectType string | boolean | undefined 39 | object.properties({ a: string }) 40 | .additionalProperties(false) 41 | .patternProperties({ '\\w+': string, 'a': boolean }) 42 | .TypeOf.c 43 | 44 | // $ExpectType string | undefined 45 | object.properties({ a: string }) 46 | .additionalProperties(false) 47 | .patternProperties({ '\\w+': object.properties({a: string}) }) 48 | .TypeOf.c!.a 49 | 50 | schema.enum([true, 'a', 42]).TypeOf // $ExpectType true | "a" | 42 51 | 52 | const b = object.properties({ brand: object.enum(['b']), b: string }).required('brand', 'b').additionalProperties(false) 53 | const c = object.properties({ brand: object.enum(['c']), c: string }).required('brand', 'c').additionalProperties(false) 54 | const x = object.properties({ a: number }).additionalProperties(false).anyOf([b, c]).TypeOf 55 | 56 | x.a // $ExpectType number | undefined 57 | 58 | if (x.brand === 'b') { 59 | x.b // $ExpectType string 60 | x.c // $ExpectError Property 'c' does not exist 61 | } else { 62 | x.c // $ExpectType string 63 | x.b // $ExpectError Property 'b' does not exist 64 | } 65 | 66 | const oneOf = object.properties({ a: number }).additionalProperties(false).oneOf([b]).TypeOf 67 | 68 | oneOf.a // $ExpectType number | undefined 69 | 70 | oneOf.b // $ExpectType string 71 | 72 | const ASchema = schema.type(['string', 'null']) 73 | type ASchema = schema 74 | 75 | function foo (value: ASchema) { 76 | value // $ExpectType string | null 77 | } 78 | 79 | schema.const(3).TypeOf // $ExpectType 3 80 | 81 | // $ExpectType { a: string; b: number; } & {} 82 | object.strictProperties({ a: string, b: number }).TypeOf 83 | 84 | // $ExpectType { b: number; } & { a?: string | undefined; c?: boolean | undefined; } 85 | object.optional('a', 'c').strictProperties({ a: string, b: number, c: boolean }).TypeOf 86 | 87 | // $ExpectType string | null 88 | string.allowNull().TypeOf 89 | 90 | // $ExpectType any 91 | schema.allowNull().TypeOf 92 | 93 | // $ExpectType string | null 94 | schema.type('string').allowNull().TypeOf 95 | 96 | // $ExpectType ({} & {} & {}) | null 97 | object.additionalProperties(false).allowNull().TypeOf 98 | 99 | // $ExpectType 3 | 1 | 2 | null 100 | schema.enum([1, 2, 3]).allowNull().TypeOf 101 | 102 | // $ExpectType 3 | 1 | 2 | null 103 | string.enum([1, 2, 3]).allowNull().TypeOf 104 | -------------------------------------------------------------------------------- /test/allow-null.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { schema, Validator } from '../src' 3 | import '../src/ext/allow-null' 4 | 5 | describe('allowNull keyword', () => { 6 | it('should create the schema for a nullable string', () => { 7 | const nullableString = schema.type('string').allowNull() 8 | 9 | expect(nullableString.toJSON()).to.eql({ type: ['string', 'null'] }) 10 | }) 11 | 12 | it('should create the schema for a typeless schema', () => { 13 | const nullableAny = schema.allowNull() 14 | 15 | expect(nullableAny.toJSON()).to.eql({}) 16 | }) 17 | 18 | it('should create the schema for an enum', () => { 19 | const nullableEnum = schema.enum([1, 2, 3]).allowNull() 20 | 21 | expect(nullableEnum.toJSON()).to.eql({ enum: [1, 2, 3, null]}) 22 | }) 23 | 24 | it('should create the schema for a typed enum', () => { 25 | const nullableEnum = schema.type('string').enum([1, 2, 3]).allowNull() 26 | 27 | expect(nullableEnum.toJSON()).to.eql({ type: ['string', 'null'], enum: [1, 2, 3, null]}) 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /test/ext.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { schema, Validator } from '../src' 3 | import { ext } from '../src/ext' 4 | 5 | describe('ext index', () => { 6 | it('should trim the value when validating', async () => { 7 | const trimmedStringSchema = schema.type('string').trim(true), 8 | validator = new Validator({ coerceTypes: true, customKeywords: ext }) 9 | 10 | const trimmedString = await validator.validate(trimmedStringSchema, ' asdf ') 11 | expect(trimmedString).to.eql('asdf') 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /test/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { 3 | array, 4 | boolean, 5 | integer, 6 | number, 7 | object, 8 | schema, 9 | string, 10 | Validator 11 | } from '../src' 12 | 13 | describe('JSON schema', () => { 14 | it('should create a number schema', () => { 15 | const numberSchema = schema.type('number') 16 | 17 | expect(numberSchema.toJSON()).to.eql({ 18 | type: 'number' 19 | }) 20 | 21 | const numberMinMax = number.maximum(4).minimum(3) 22 | 23 | expect(numberMinMax.toJSON()).to.eql({ 24 | type: 'number', 25 | maximum: 4, 26 | minimum: 3 27 | }) 28 | 29 | const numberWithExclusives = number.exclusiveMaximum(4).exclusiveMinimum(2) 30 | 31 | expect(numberWithExclusives.toJSON()).to.eql({ 32 | type: 'number', 33 | exclusiveMaximum: 4, 34 | exclusiveMinimum: 2 35 | }) 36 | 37 | const complexNumber = number 38 | .maximum(4) 39 | .minimum(3) 40 | .exclusiveMaximum(true) 41 | .exclusiveMinimum(true) 42 | 43 | expect(complexNumber.toJSON()).to.eql({ 44 | type: 'number', 45 | maximum: 4, 46 | minimum: 3, 47 | exclusiveMaximum: true, 48 | exclusiveMinimum: true 49 | }) 50 | 51 | const numberWithMultiple = number.multipleOf(3) 52 | 53 | expect(numberWithMultiple.toJSON()).to.eql({ 54 | type: 'number', 55 | multipleOf: 3 56 | }) 57 | 58 | const integerSchema = schema.type('integer') 59 | 60 | expect(integerSchema.toJSON()).to.eql({ 61 | type: 'integer' 62 | }) 63 | 64 | expect(integer.toJSON()).to.eql({ 65 | type: 'integer' 66 | }) 67 | }) 68 | 69 | it('should create a string schema', () => { 70 | const stringSchema = schema.type('string') 71 | 72 | expect(stringSchema.toJSON()).to.eql({ 73 | type: 'string' 74 | }) 75 | 76 | const stringLengths = string.minLength(3).maxLength(5) 77 | 78 | expect(stringLengths.toJSON()).to.eql({ 79 | type: 'string', 80 | minLength: 3, 81 | maxLength: 5 82 | }) 83 | 84 | const stringPattern = string.pattern(/\w+/) 85 | 86 | expect(stringPattern.toJSON()).to.eql({ 87 | type: 'string', 88 | pattern: '\\w+' 89 | }) 90 | const stringFormat = string.format('email') 91 | 92 | expect(stringFormat.toJSON()).to.eql({ 93 | type: 'string', 94 | format: 'email' 95 | }) 96 | }) 97 | 98 | it('should create a boolean schema', () => { 99 | const booleanSchema = schema.type('boolean') 100 | 101 | expect(booleanSchema.toJSON()).to.eql({ 102 | type: 'boolean' 103 | }) 104 | }) 105 | it('should create a null schema', () => { 106 | const nullSchema = schema.type('null') 107 | 108 | expect(nullSchema.toJSON()).to.eql({ 109 | type: 'null' 110 | }) 111 | }) 112 | 113 | it('should create an array schema', () => { 114 | const arraySchema = schema.type('array') 115 | 116 | expect(arraySchema.toJSON()).to.eql({ 117 | type: 'array' 118 | }) 119 | 120 | const minMaxArray = array.minItems(3).maxItems(5) 121 | 122 | expect(minMaxArray.toJSON()).to.eql({ 123 | type: 'array', 124 | minItems: 3, 125 | maxItems: 5 126 | }) 127 | 128 | const uniqueItems = array.uniqueItems(true) 129 | 130 | expect(uniqueItems.toJSON()).to.eql({ 131 | type: 'array', 132 | uniqueItems: true 133 | }) 134 | 135 | const arrayOfStrings = array(string) 136 | 137 | expect(arrayOfStrings.toJSON()).to.eql({ 138 | type: 'array', 139 | items: { type: 'string' } 140 | }) 141 | 142 | const stringTuple = array([string]) 143 | 144 | expect(stringTuple.toJSON()).to.eql({ 145 | type: 'array', 146 | items: [{ type: 'string' }] 147 | }) 148 | 149 | const complexTuple = array([string, array(number), number]) 150 | 151 | expect(complexTuple.toJSON()).to.eql({ 152 | type: 'array', 153 | items: [ 154 | { type: 'string' }, 155 | { type: 'array', items: { type: 'number' } }, 156 | { type: 'number' } 157 | ] 158 | }) 159 | 160 | const tupleWithAdditionalItems = array([string, array(number), number]).additionalItems(true) 161 | 162 | expect(tupleWithAdditionalItems.toJSON()).to.eql({ 163 | type: 'array', 164 | items: [ 165 | { type: 'string' }, 166 | { type: 'array', items: { type: 'number' } }, 167 | { type: 'number' } 168 | ], 169 | additionalItems: true 170 | }) 171 | 172 | const tupleWithBooleanAdditionalItems = array([ 173 | string, 174 | array(number), 175 | number 176 | ]) 177 | .additionalItems(boolean) 178 | 179 | expect(tupleWithBooleanAdditionalItems.toJSON()).to.eql({ 180 | type: 'array', items: [ 181 | { type: 'string' }, 182 | { type: 'array', items: { type: 'number' } }, 183 | { type: 'number' } 184 | ], 185 | additionalItems: { type: 'boolean' } 186 | }) 187 | 188 | const arrayContains = array(string) 189 | .contains(schema.type('null')) 190 | 191 | expect(arrayContains.toJSON()).to.eql({ 192 | type: 'array', 193 | items: { type: 'string' }, 194 | contains: { type: 'null' } 195 | }) 196 | }) 197 | 198 | it('should create an object schema', () => { 199 | const objectSchema = schema.type('object') 200 | 201 | expect(objectSchema.toJSON()).to.eql({ 202 | type: 'object' 203 | }) 204 | 205 | const minMaxProperties = object.maxProperties(3).minProperties(1) 206 | 207 | expect(minMaxProperties.toJSON()).to.eql({ 208 | type: 'object', 209 | maxProperties: 3, 210 | minProperties: 1 211 | }) 212 | 213 | const schemaWithProperties = object({ 214 | a: string, 215 | b: array(number) 216 | }) 217 | 218 | expect(schemaWithProperties.toJSON()).to.eql({ 219 | type: 'object', 220 | properties: { 221 | a: { type: 'string' }, 222 | b: { type: 'array', items: { type: 'number' }} 223 | } 224 | }) 225 | 226 | const schemaWithRequiredProperties = object({ 227 | a: string, 228 | b: array(number) 229 | }) 230 | .required('a', 'b', 'c') 231 | 232 | expect(schemaWithRequiredProperties.toJSON()).to.eql({ 233 | type: 'object', 234 | properties: { 235 | a: { type: 'string' }, 236 | b: { type: 'array', items: { type: 'number' }} 237 | }, 238 | required: ['a', 'b', 'c'] 239 | }) 240 | 241 | const schemaWithNoAdditionalProperties = object.required('a', 'b', 'c').properties({ 242 | a: string, 243 | b: array(number), 244 | d: boolean 245 | }) 246 | .additionalProperties(false) 247 | 248 | expect(schemaWithNoAdditionalProperties.toJSON()).to.eql({ 249 | type: 'object', 250 | properties: { 251 | a: { type: 'string' }, 252 | b: { type: 'array', items: { type: 'number' }}, 253 | d: { type: 'boolean' } 254 | }, 255 | required: ['a', 'b', 'c'], 256 | additionalProperties: false 257 | }) 258 | 259 | const schemaWithAdditionalProperties = object 260 | .properties({ a: string }) 261 | .required('b') 262 | .additionalProperties(number) 263 | 264 | expect(schemaWithAdditionalProperties.toJSON()).to.eql({ 265 | type: 'object', 266 | properties: { 267 | a: { type: 'string' } 268 | }, 269 | required: ['b'], 270 | additionalProperties: { type: 'number' } 271 | }) 272 | 273 | const objectWithPatternProperties = object.patternProperties({ 274 | '$foo^': string, 275 | '$bar^': number 276 | }) 277 | .additionalProperties(false) 278 | 279 | expect(objectWithPatternProperties.toJSON()).to.eql({ 280 | type: 'object', 281 | additionalProperties: false, 282 | patternProperties: { 283 | '$foo^': { type: 'string' }, 284 | '$bar^': { type: 'number' } 285 | } 286 | }) 287 | 288 | const objectWithRequiredPatternProperties = object.patternProperties({ 289 | '$foo^': string, 290 | '$bar^': number 291 | }) 292 | .required('a') 293 | .additionalProperties(false) 294 | 295 | expect(objectWithRequiredPatternProperties.toJSON()).to.eql({ 296 | type: 'object', 297 | required: ['a'], 298 | additionalProperties: false, 299 | patternProperties: { 300 | '$foo^': { type: 'string' }, 301 | '$bar^': { type: 'number' } 302 | } 303 | }) 304 | 305 | const objectWithDependencies = object.additionalProperties(false) 306 | .dependencies({ 307 | a: string, 308 | b: ['c', 'd'] 309 | }) 310 | 311 | expect(objectWithDependencies.toJSON()).to.eql({ 312 | type: 'object', 313 | additionalProperties: false, 314 | dependencies: { 315 | a: { type: 'string' }, 316 | b: ['c', 'd'] 317 | } 318 | }) 319 | }) 320 | 321 | it('should create a schema with multiple types (as an array)', () => { 322 | const schemaWithMultipleTypes = schema.type(['string', 'null']) 323 | 324 | expect(schemaWithMultipleTypes.toJSON()).to.eql({ 325 | type: ['string', 'null'] 326 | }) 327 | }) 328 | 329 | it('should allow any combination of keywords from different types', () => { 330 | const crazySchema = schema 331 | .type(['number', 'boolean']) 332 | .properties({a: string}) 333 | .maxLength(42) 334 | 335 | expect(crazySchema.toJSON()).to.eql({ 336 | type: ['number', 'boolean'], 337 | properties: { a: { type: 'string' } }, 338 | maxLength: 42 339 | }) 340 | }) 341 | 342 | it('should allow metadata values', () => { 343 | const schemaWithMetadata = schema.title('someTitle').description('foo') 344 | 345 | expect(schemaWithMetadata.toJSON()).to.eql({ 346 | title: 'someTitle', 347 | description: 'foo' 348 | }) 349 | }) 350 | 351 | it('should allow default values', () => { 352 | const schemaWithDefault = string.default('asdf') 353 | 354 | expect(schemaWithDefault.toJSON()).to.eql({ 355 | type: 'string', 356 | default: 'asdf' 357 | }) 358 | }) 359 | 360 | it('should allow examples', () => { 361 | const schemaWithDefault = string.example('fizz') 362 | 363 | expect(schemaWithDefault.toJSON()).to.eql({ 364 | type: 'string', 365 | example: 'fizz' 366 | }) 367 | }) 368 | 369 | it('should allow enumerated values', () => { 370 | const enumSchema = schema.enum([[4, 5], '3', false, null]) 371 | 372 | expect(enumSchema.toJSON()).to.eql({ 373 | enum: [ [4, 5], '3', false, null] 374 | }) 375 | 376 | const enumWithType = string.enum(['5', null]) 377 | 378 | expect(enumWithType.toJSON()).to.eql({ 379 | type: 'string', 380 | enum: [ '5', null ] 381 | }) 382 | }) 383 | 384 | it('should allow const values', () => { 385 | const constSchema = schema.const(4) 386 | 387 | expect(constSchema.toJSON()).to.eql({ 388 | const: 4 389 | }) 390 | }) 391 | 392 | it('should combine schemas using allOf', () => { 393 | const s = schema.allOf([ 394 | array(string), 395 | number 396 | ]) 397 | 398 | expect(s.toJSON()).to.eql({ 399 | allOf: [ 400 | { type: 'array', items: { type: 'string'} }, 401 | { type: 'number' } 402 | ] 403 | }) 404 | }) 405 | 406 | it('should combine schemas using anyOf', () => { 407 | const s = schema.anyOf([ 408 | string, 409 | number, 410 | object({ a: string }).required('a') 411 | ]) 412 | 413 | expect(s.toJSON()).to.eql({ 414 | anyOf: [ 415 | { type: 'string' }, 416 | { type: 'number' }, 417 | { type: 'object', properties: { a: { type: 'string' }}, required: ['a'] } 418 | ] 419 | }) 420 | }) 421 | 422 | it('should combine schemas using oneOf', () => { 423 | const s = schema.oneOf([ 424 | string, 425 | number, 426 | array(string) 427 | ]) 428 | 429 | expect(s.toJSON()).to.eql({ 430 | oneOf: [ 431 | { type: 'string' }, 432 | { type: 'number' }, 433 | { type: 'array', items: { type: 'string' } } 434 | ] 435 | }) 436 | }) 437 | 438 | it('should combine schemas using not', () => { 439 | const s = string.not(schema.enum(['fizz'])) 440 | 441 | expect(s.toJSON()).to.eql({ 442 | type: 'string', 443 | not: { 444 | enum: ['fizz'] 445 | } 446 | }) 447 | }) 448 | 449 | it('should validate a schema', async () => { 450 | const result = await new Validator().validate(schema.anyOf([string]), 'a') 451 | 452 | expect(result).to.eql('a') 453 | }) 454 | 455 | it('should coerce validated data', async () => { 456 | const result = await new Validator({ coerceTypes: true }).validate(string, 1) 457 | 458 | expect(result).to.eql('1') 459 | }) 460 | }) 461 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --compilers ts:ts-node/register 2 | -------------------------------------------------------------------------------- /test/strict-properties.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { boolean, number, object, schema, string, Validator } from '../src' 3 | import '../src/ext/strict-properties' 4 | 5 | describe('strict properties', () => { 6 | it('should create the schema', () => { 7 | const strictSchema = object.strictProperties({ a: number, b: string }) 8 | 9 | expect(strictSchema.toJSON()).to.eql({ 10 | type: 'object', 11 | properties: { 12 | a: { type: 'number' }, 13 | b: { type: 'string' } 14 | }, 15 | required: ['a', 'b'], 16 | additionalProperties: false 17 | }) 18 | }) 19 | 20 | it('should allow optional properties', () => { 21 | const strictSchema = object.strictProperties({ a: number, b: string }).optional('a') 22 | 23 | expect(strictSchema.toJSON()).to.eql({ 24 | type: 'object', 25 | properties: { 26 | a: { type: 'number' }, 27 | b: { type: 'string' } 28 | }, 29 | required: ['b'], 30 | additionalProperties: false 31 | }) 32 | }) 33 | 34 | it('should allow optional properties specified before strict', () => { 35 | const strictSchema = object.optional('a', 'b').strictProperties({ a: number, b: string, c: boolean }) 36 | 37 | expect(strictSchema.toJSON()).to.eql({ 38 | type: 'object', 39 | properties: { 40 | a: { type: 'number' }, 41 | b: { type: 'string' }, 42 | c: { type: 'boolean' } 43 | }, 44 | required: ['c'], 45 | additionalProperties: false 46 | }) 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /test/trim.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { schema, Validator } from '../src' 3 | import { trim } from '../src/ext/trim' 4 | 5 | describe('trim keyword', () => { 6 | it('should create the schema', () => { 7 | const trimmedString = schema.type('string').trim(true) 8 | 9 | expect(trimmedString.toJSON()).to.eql({ type: 'string', trim: true }) 10 | }) 11 | 12 | it('should trim the value when validating', async () => { 13 | const trimmedStringSchema = schema.type('string').trim(true), 14 | validator = new Validator({ coerceTypes: true, customKeywords: [trim] }) 15 | 16 | const trimmedString = await validator.validate(trimmedStringSchema, ' asdf ') 17 | expect(trimmedString).to.eql('asdf') 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "lib": [ 5 | "es2016", 6 | "dom" 7 | ], 8 | "rootDir": ".." 9 | }, 10 | "include": [ 11 | "**/*.ts" 12 | ] 13 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "lib": [ "es2016" ], 6 | "outDir": ".", 7 | "strict": true, 8 | "noEmitOnError": true, 9 | "experimentalDecorators": true, 10 | "emitDecoratorMetadata": true 11 | }, 12 | "include": [ 13 | "src/**/*.ts" 14 | ], 15 | "exclude": [] 16 | } 17 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "rules": { 7 | "semicolon": [ true, "never" ], 8 | "quotemark": [ true, "single", "avoid-escape" ], 9 | "trailing-comma": [ false ], 10 | "space-before-function-paren": { 11 | "anonymous": "always", 12 | "constructor": "always", 13 | "method": "always", 14 | "named": "always" 15 | }, 16 | "object-literal-sort-keys": [false], 17 | "member-access": [true, "no-public"], 18 | "interface-name": [true, "never-prefix"], 19 | "one-variable-per-declaration": [false], 20 | "arrow-parens": [false], 21 | "no-shadowed-variable": [false] 22 | } 23 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/ajv@^1.0.0": 6 | version "1.0.0" 7 | resolved "https://registry.yarnpkg.com/@types/ajv/-/ajv-1.0.0.tgz#4fb2440742f2f6c30e7fb0797b839fc6f696682a" 8 | dependencies: 9 | ajv "*" 10 | 11 | "@types/chai@^4.0.1": 12 | version "4.0.1" 13 | resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.0.1.tgz#37fea779617cfec3fd2b19a0247e8bbdd5133bf6" 14 | 15 | "@types/mocha@^2.2.41": 16 | version "2.2.41" 17 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.41.tgz#e27cf0817153eb9f2713b2d3f6c68f1e1c3ca608" 18 | 19 | ajv@*, ajv@^5.2.2: 20 | version "5.2.2" 21 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.2.tgz#47c68d69e86f5d953103b0074a9430dc63da5e39" 22 | dependencies: 23 | co "^4.6.0" 24 | fast-deep-equal "^1.0.0" 25 | json-schema-traverse "^0.3.0" 26 | json-stable-stringify "^1.0.1" 27 | 28 | ansi-regex@^2.0.0: 29 | version "2.1.1" 30 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 31 | 32 | ansi-styles@^2.2.1: 33 | version "2.2.1" 34 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 35 | 36 | ansi-styles@^3.1.0: 37 | version "3.2.0" 38 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" 39 | dependencies: 40 | color-convert "^1.9.0" 41 | 42 | arrify@^1.0.0: 43 | version "1.0.1" 44 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 45 | 46 | assertion-error@^1.0.1: 47 | version "1.0.2" 48 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" 49 | 50 | babel-code-frame@^6.22.0: 51 | version "6.26.0" 52 | resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" 53 | dependencies: 54 | chalk "^1.1.3" 55 | esutils "^2.0.2" 56 | js-tokens "^3.0.2" 57 | 58 | balanced-match@^1.0.0: 59 | version "1.0.0" 60 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 61 | 62 | brace-expansion@^1.1.7: 63 | version "1.1.8" 64 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" 65 | dependencies: 66 | balanced-match "^1.0.0" 67 | concat-map "0.0.1" 68 | 69 | browser-stdout@1.3.0: 70 | version "1.3.0" 71 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" 72 | 73 | builtin-modules@^1.0.0: 74 | version "1.1.1" 75 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 76 | 77 | camelcase@^3.0.0: 78 | version "3.0.0" 79 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" 80 | 81 | chai@^4.1.0: 82 | version "4.1.0" 83 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.0.tgz#331a0391b55c3af8740ae9c3b7458bc1c3805e6d" 84 | dependencies: 85 | assertion-error "^1.0.1" 86 | check-error "^1.0.1" 87 | deep-eql "^2.0.1" 88 | get-func-name "^2.0.0" 89 | pathval "^1.0.0" 90 | type-detect "^4.0.0" 91 | 92 | chalk@^1.1.3: 93 | version "1.1.3" 94 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 95 | dependencies: 96 | ansi-styles "^2.2.1" 97 | escape-string-regexp "^1.0.2" 98 | has-ansi "^2.0.0" 99 | strip-ansi "^3.0.0" 100 | supports-color "^2.0.0" 101 | 102 | chalk@^2.0.0: 103 | version "2.0.1" 104 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.0.1.tgz#dbec49436d2ae15f536114e76d14656cdbc0f44d" 105 | dependencies: 106 | ansi-styles "^3.1.0" 107 | escape-string-regexp "^1.0.5" 108 | supports-color "^4.0.0" 109 | 110 | check-error@^1.0.1: 111 | version "1.0.2" 112 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 113 | 114 | cliui@^3.2.0: 115 | version "3.2.0" 116 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" 117 | dependencies: 118 | string-width "^1.0.1" 119 | strip-ansi "^3.0.1" 120 | wrap-ansi "^2.0.0" 121 | 122 | co@^4.6.0: 123 | version "4.6.0" 124 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 125 | 126 | code-point-at@^1.0.0: 127 | version "1.1.0" 128 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 129 | 130 | color-convert@^1.9.0: 131 | version "1.9.0" 132 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" 133 | dependencies: 134 | color-name "^1.1.1" 135 | 136 | color-name@^1.1.1: 137 | version "1.1.3" 138 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 139 | 140 | colors@^1.1.2: 141 | version "1.1.2" 142 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" 143 | 144 | commander@2.9.0, commander@^2.9.0: 145 | version "2.9.0" 146 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" 147 | dependencies: 148 | graceful-readlink ">= 1.0.0" 149 | 150 | concat-map@0.0.1: 151 | version "0.0.1" 152 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 153 | 154 | cross-env@^5.0.5: 155 | version "5.0.5" 156 | resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.0.5.tgz#4383d364d9660873dd185b398af3bfef5efffef3" 157 | dependencies: 158 | cross-spawn "^5.1.0" 159 | is-windows "^1.0.0" 160 | 161 | cross-spawn@^5.1.0: 162 | version "5.1.0" 163 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" 164 | dependencies: 165 | lru-cache "^4.0.1" 166 | shebang-command "^1.2.0" 167 | which "^1.2.9" 168 | 169 | debug@2.6.0: 170 | version "2.6.0" 171 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" 172 | dependencies: 173 | ms "0.7.2" 174 | 175 | decamelize@^1.1.1: 176 | version "1.2.0" 177 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 178 | 179 | deep-eql@^2.0.1: 180 | version "2.0.2" 181 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-2.0.2.tgz#b1bac06e56f0a76777686d50c9feb75c2ed7679a" 182 | dependencies: 183 | type-detect "^3.0.0" 184 | 185 | diff@3.2.0, diff@^3.1.0, diff@^3.2.0: 186 | version "3.2.0" 187 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" 188 | 189 | error-ex@^1.2.0: 190 | version "1.3.1" 191 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" 192 | dependencies: 193 | is-arrayish "^0.2.1" 194 | 195 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: 196 | version "1.0.5" 197 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 198 | 199 | esutils@^2.0.2: 200 | version "2.0.2" 201 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 202 | 203 | fast-deep-equal@^1.0.0: 204 | version "1.0.0" 205 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" 206 | 207 | find-up@^1.0.0: 208 | version "1.1.2" 209 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" 210 | dependencies: 211 | path-exists "^2.0.0" 212 | pinkie-promise "^2.0.0" 213 | 214 | fs.realpath@^1.0.0: 215 | version "1.0.0" 216 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 217 | 218 | get-caller-file@^1.0.1: 219 | version "1.0.2" 220 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" 221 | 222 | get-func-name@^2.0.0: 223 | version "2.0.0" 224 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 225 | 226 | glob@7.1.1, glob@^7.1.1: 227 | version "7.1.1" 228 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 229 | dependencies: 230 | fs.realpath "^1.0.0" 231 | inflight "^1.0.4" 232 | inherits "2" 233 | minimatch "^3.0.2" 234 | once "^1.3.0" 235 | path-is-absolute "^1.0.0" 236 | 237 | graceful-fs@^4.1.2: 238 | version "4.1.11" 239 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 240 | 241 | "graceful-readlink@>= 1.0.0": 242 | version "1.0.1" 243 | resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" 244 | 245 | growl@1.9.2: 246 | version "1.9.2" 247 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" 248 | 249 | has-ansi@^2.0.0: 250 | version "2.0.0" 251 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 252 | dependencies: 253 | ansi-regex "^2.0.0" 254 | 255 | has-flag@^1.0.0: 256 | version "1.0.0" 257 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" 258 | 259 | has-flag@^2.0.0: 260 | version "2.0.0" 261 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" 262 | 263 | hosted-git-info@^2.1.4: 264 | version "2.5.0" 265 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" 266 | 267 | inflight@^1.0.4: 268 | version "1.0.6" 269 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 270 | dependencies: 271 | once "^1.3.0" 272 | wrappy "1" 273 | 274 | inherits@2: 275 | version "2.0.3" 276 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 277 | 278 | invert-kv@^1.0.0: 279 | version "1.0.0" 280 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" 281 | 282 | is-arrayish@^0.2.1: 283 | version "0.2.1" 284 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 285 | 286 | is-builtin-module@^1.0.0: 287 | version "1.0.0" 288 | resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" 289 | dependencies: 290 | builtin-modules "^1.0.0" 291 | 292 | is-fullwidth-code-point@^1.0.0: 293 | version "1.0.0" 294 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 295 | dependencies: 296 | number-is-nan "^1.0.0" 297 | 298 | is-utf8@^0.2.0: 299 | version "0.2.1" 300 | resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" 301 | 302 | is-windows@^1.0.0: 303 | version "1.0.1" 304 | resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9" 305 | 306 | isexe@^2.0.0: 307 | version "2.0.0" 308 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 309 | 310 | js-tokens@^3.0.2: 311 | version "3.0.2" 312 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" 313 | 314 | json-schema-traverse@^0.3.0: 315 | version "0.3.1" 316 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" 317 | 318 | json-stable-stringify@^1.0.1: 319 | version "1.0.1" 320 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 321 | dependencies: 322 | jsonify "~0.0.0" 323 | 324 | json3@3.3.2: 325 | version "3.3.2" 326 | resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" 327 | 328 | jsonify@~0.0.0: 329 | version "0.0.0" 330 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 331 | 332 | lcid@^1.0.0: 333 | version "1.0.0" 334 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" 335 | dependencies: 336 | invert-kv "^1.0.0" 337 | 338 | load-json-file@^1.0.0: 339 | version "1.1.0" 340 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" 341 | dependencies: 342 | graceful-fs "^4.1.2" 343 | parse-json "^2.2.0" 344 | pify "^2.0.0" 345 | pinkie-promise "^2.0.0" 346 | strip-bom "^2.0.0" 347 | 348 | lodash._baseassign@^3.0.0: 349 | version "3.2.0" 350 | resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" 351 | dependencies: 352 | lodash._basecopy "^3.0.0" 353 | lodash.keys "^3.0.0" 354 | 355 | lodash._basecopy@^3.0.0: 356 | version "3.0.1" 357 | resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" 358 | 359 | lodash._basecreate@^3.0.0: 360 | version "3.0.3" 361 | resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" 362 | 363 | lodash._getnative@^3.0.0: 364 | version "3.9.1" 365 | resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" 366 | 367 | lodash._isiterateecall@^3.0.0: 368 | version "3.0.9" 369 | resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" 370 | 371 | lodash.create@3.1.1: 372 | version "3.1.1" 373 | resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" 374 | dependencies: 375 | lodash._baseassign "^3.0.0" 376 | lodash._basecreate "^3.0.0" 377 | lodash._isiterateecall "^3.0.0" 378 | 379 | lodash.isarguments@^3.0.0: 380 | version "3.1.0" 381 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" 382 | 383 | lodash.isarray@^3.0.0: 384 | version "3.0.4" 385 | resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" 386 | 387 | lodash.keys@^3.0.0: 388 | version "3.1.2" 389 | resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" 390 | dependencies: 391 | lodash._getnative "^3.0.0" 392 | lodash.isarguments "^3.0.0" 393 | lodash.isarray "^3.0.0" 394 | 395 | lodash@^4.17.4: 396 | version "4.17.4" 397 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 398 | 399 | lru-cache@^4.0.1: 400 | version "4.1.1" 401 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" 402 | dependencies: 403 | pseudomap "^1.0.2" 404 | yallist "^2.1.2" 405 | 406 | make-error@^1.1.1: 407 | version "1.3.0" 408 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.0.tgz#52ad3a339ccf10ce62b4040b708fe707244b8b96" 409 | 410 | minimatch@^3.0.2, minimatch@^3.0.4: 411 | version "3.0.4" 412 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 413 | dependencies: 414 | brace-expansion "^1.1.7" 415 | 416 | minimist@0.0.8: 417 | version "0.0.8" 418 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 419 | 420 | minimist@^1.2.0: 421 | version "1.2.0" 422 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 423 | 424 | mkdirp@0.5.1, mkdirp@^0.5.1: 425 | version "0.5.1" 426 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 427 | dependencies: 428 | minimist "0.0.8" 429 | 430 | mocha@^3.4.2: 431 | version "3.4.2" 432 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.4.2.tgz#d0ef4d332126dbf18d0d640c9b382dd48be97594" 433 | dependencies: 434 | browser-stdout "1.3.0" 435 | commander "2.9.0" 436 | debug "2.6.0" 437 | diff "3.2.0" 438 | escape-string-regexp "1.0.5" 439 | glob "7.1.1" 440 | growl "1.9.2" 441 | json3 "3.3.2" 442 | lodash.create "3.1.1" 443 | mkdirp "0.5.1" 444 | supports-color "3.1.2" 445 | 446 | ms@0.7.2: 447 | version "0.7.2" 448 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" 449 | 450 | normalize-package-data@^2.3.2: 451 | version "2.4.0" 452 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" 453 | dependencies: 454 | hosted-git-info "^2.1.4" 455 | is-builtin-module "^1.0.0" 456 | semver "2 || 3 || 4 || 5" 457 | validate-npm-package-license "^3.0.1" 458 | 459 | number-is-nan@^1.0.0: 460 | version "1.0.1" 461 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 462 | 463 | once@^1.3.0: 464 | version "1.4.0" 465 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 466 | dependencies: 467 | wrappy "1" 468 | 469 | os-locale@^1.4.0: 470 | version "1.4.0" 471 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" 472 | dependencies: 473 | lcid "^1.0.0" 474 | 475 | parse-json@^2.2.0: 476 | version "2.2.0" 477 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" 478 | dependencies: 479 | error-ex "^1.2.0" 480 | 481 | path-exists@^2.0.0: 482 | version "2.1.0" 483 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" 484 | dependencies: 485 | pinkie-promise "^2.0.0" 486 | 487 | path-is-absolute@^1.0.0: 488 | version "1.0.1" 489 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 490 | 491 | path-parse@^1.0.5: 492 | version "1.0.5" 493 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" 494 | 495 | path-type@^1.0.0: 496 | version "1.1.0" 497 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" 498 | dependencies: 499 | graceful-fs "^4.1.2" 500 | pify "^2.0.0" 501 | pinkie-promise "^2.0.0" 502 | 503 | pathval@^1.0.0: 504 | version "1.1.0" 505 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" 506 | 507 | pify@^2.0.0: 508 | version "2.3.0" 509 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 510 | 511 | pinkie-promise@^2.0.0: 512 | version "2.0.1" 513 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 514 | dependencies: 515 | pinkie "^2.0.0" 516 | 517 | pinkie@^2.0.0: 518 | version "2.0.4" 519 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 520 | 521 | pseudomap@^1.0.2: 522 | version "1.0.2" 523 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" 524 | 525 | read-pkg-up@^1.0.1: 526 | version "1.0.1" 527 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" 528 | dependencies: 529 | find-up "^1.0.0" 530 | read-pkg "^1.0.0" 531 | 532 | read-pkg@^1.0.0: 533 | version "1.1.0" 534 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" 535 | dependencies: 536 | load-json-file "^1.0.0" 537 | normalize-package-data "^2.3.2" 538 | path-type "^1.0.0" 539 | 540 | require-directory@^2.1.1: 541 | version "2.1.1" 542 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 543 | 544 | require-main-filename@^1.0.1: 545 | version "1.0.1" 546 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" 547 | 548 | resolve@^1.3.2: 549 | version "1.4.0" 550 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" 551 | dependencies: 552 | path-parse "^1.0.5" 553 | 554 | "semver@2 || 3 || 4 || 5", semver@^5.3.0: 555 | version "5.4.1" 556 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" 557 | 558 | set-blocking@^2.0.0: 559 | version "2.0.0" 560 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 561 | 562 | shebang-command@^1.2.0: 563 | version "1.2.0" 564 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 565 | dependencies: 566 | shebang-regex "^1.0.0" 567 | 568 | shebang-regex@^1.0.0: 569 | version "1.0.0" 570 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 571 | 572 | source-map-support@^0.4.0: 573 | version "0.4.15" 574 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" 575 | dependencies: 576 | source-map "^0.5.6" 577 | 578 | source-map@^0.5.6: 579 | version "0.5.6" 580 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" 581 | 582 | spdx-correct@~1.0.0: 583 | version "1.0.2" 584 | resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" 585 | dependencies: 586 | spdx-license-ids "^1.0.2" 587 | 588 | spdx-expression-parse@~1.0.0: 589 | version "1.0.4" 590 | resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" 591 | 592 | spdx-license-ids@^1.0.2: 593 | version "1.2.2" 594 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" 595 | 596 | string-width@^1.0.1, string-width@^1.0.2: 597 | version "1.0.2" 598 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 599 | dependencies: 600 | code-point-at "^1.0.0" 601 | is-fullwidth-code-point "^1.0.0" 602 | strip-ansi "^3.0.0" 603 | 604 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 605 | version "3.0.1" 606 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 607 | dependencies: 608 | ansi-regex "^2.0.0" 609 | 610 | strip-bom@^2.0.0: 611 | version "2.0.0" 612 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" 613 | dependencies: 614 | is-utf8 "^0.2.0" 615 | 616 | strip-bom@^3.0.0: 617 | version "3.0.0" 618 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 619 | 620 | strip-json-comments@^2.0.0: 621 | version "2.0.1" 622 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 623 | 624 | supports-color@3.1.2: 625 | version "3.1.2" 626 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" 627 | dependencies: 628 | has-flag "^1.0.0" 629 | 630 | supports-color@^2.0.0: 631 | version "2.0.0" 632 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 633 | 634 | supports-color@^4.0.0: 635 | version "4.2.1" 636 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.2.1.tgz#65a4bb2631e90e02420dba5554c375a4754bb836" 637 | dependencies: 638 | has-flag "^2.0.0" 639 | 640 | ts-node@^3.3.0: 641 | version "3.3.0" 642 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-3.3.0.tgz#c13c6a3024e30be1180dd53038fc209289d4bf69" 643 | dependencies: 644 | arrify "^1.0.0" 645 | chalk "^2.0.0" 646 | diff "^3.1.0" 647 | make-error "^1.1.1" 648 | minimist "^1.2.0" 649 | mkdirp "^0.5.1" 650 | source-map-support "^0.4.0" 651 | tsconfig "^6.0.0" 652 | v8flags "^3.0.0" 653 | yn "^2.0.0" 654 | 655 | tsconfig@^6.0.0: 656 | version "6.0.0" 657 | resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-6.0.0.tgz#6b0e8376003d7af1864f8df8f89dd0059ffcd032" 658 | dependencies: 659 | strip-bom "^3.0.0" 660 | strip-json-comments "^2.0.0" 661 | 662 | tslib@^1.7.1: 663 | version "1.7.1" 664 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec" 665 | 666 | tslint@^5.7.0: 667 | version "5.7.0" 668 | resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.7.0.tgz#c25e0d0c92fa1201c2bc30e844e08e682b4f3552" 669 | dependencies: 670 | babel-code-frame "^6.22.0" 671 | colors "^1.1.2" 672 | commander "^2.9.0" 673 | diff "^3.2.0" 674 | glob "^7.1.1" 675 | minimatch "^3.0.4" 676 | resolve "^1.3.2" 677 | semver "^5.3.0" 678 | tslib "^1.7.1" 679 | tsutils "^2.8.1" 680 | 681 | tsutils@^2.8.1: 682 | version "2.8.2" 683 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.8.2.tgz#2c1486ba431260845b0ac6f902afd9d708a8ea6a" 684 | dependencies: 685 | tslib "^1.7.1" 686 | 687 | type-detect@^3.0.0: 688 | version "3.0.0" 689 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-3.0.0.tgz#46d0cc8553abb7b13a352b0d6dea2fd58f2d9b55" 690 | 691 | type-detect@^4.0.0: 692 | version "4.0.3" 693 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.3.tgz#0e3f2670b44099b0b46c284d136a7ef49c74c2ea" 694 | 695 | typescript@2.5: 696 | version "2.5.1" 697 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.1.tgz#ce7cc93ada3de19475cc9d17e3adea7aee1832aa" 698 | 699 | typings-checker@^2.0.0: 700 | version "2.0.0" 701 | resolved "https://registry.yarnpkg.com/typings-checker/-/typings-checker-2.0.0.tgz#c6d5af0ff3fc7065da22a6933e1290d16af6cc56" 702 | dependencies: 703 | lodash "^4.17.4" 704 | yargs "^6.6.0" 705 | 706 | user-home@^1.1.1: 707 | version "1.1.1" 708 | resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" 709 | 710 | v8flags@^3.0.0: 711 | version "3.0.0" 712 | resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.0.0.tgz#4be9604488e0c4123645def705b1848d16b8e01f" 713 | dependencies: 714 | user-home "^1.1.1" 715 | 716 | validate-npm-package-license@^3.0.1: 717 | version "3.0.1" 718 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" 719 | dependencies: 720 | spdx-correct "~1.0.0" 721 | spdx-expression-parse "~1.0.0" 722 | 723 | which-module@^1.0.0: 724 | version "1.0.0" 725 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" 726 | 727 | which@^1.2.9: 728 | version "1.3.0" 729 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" 730 | dependencies: 731 | isexe "^2.0.0" 732 | 733 | wrap-ansi@^2.0.0: 734 | version "2.1.0" 735 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" 736 | dependencies: 737 | string-width "^1.0.1" 738 | strip-ansi "^3.0.1" 739 | 740 | wrappy@1: 741 | version "1.0.2" 742 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 743 | 744 | y18n@^3.2.1: 745 | version "3.2.1" 746 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" 747 | 748 | yallist@^2.1.2: 749 | version "2.1.2" 750 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" 751 | 752 | yargs-parser@^4.2.0: 753 | version "4.2.1" 754 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" 755 | dependencies: 756 | camelcase "^3.0.0" 757 | 758 | yargs@^6.6.0: 759 | version "6.6.0" 760 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" 761 | dependencies: 762 | camelcase "^3.0.0" 763 | cliui "^3.2.0" 764 | decamelize "^1.1.1" 765 | get-caller-file "^1.0.1" 766 | os-locale "^1.4.0" 767 | read-pkg-up "^1.0.1" 768 | require-directory "^2.1.1" 769 | require-main-filename "^1.0.1" 770 | set-blocking "^2.0.0" 771 | string-width "^1.0.2" 772 | which-module "^1.0.0" 773 | y18n "^3.2.1" 774 | yargs-parser "^4.2.0" 775 | 776 | yn@^2.0.0: 777 | version "2.0.0" 778 | resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" 779 | --------------------------------------------------------------------------------