├── .eslintrc.json
├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── decs.d.ts
├── favicon.ico
├── index.html
├── index.js
├── package-lock.json
├── package.json
├── t.js
└── test.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2020": true,
5 | "node": true
6 | },
7 | "extends": "eslint:recommended",
8 | "parserOptions": {
9 | "ecmaVersion": 11,
10 | "sourceType": "module"
11 | },
12 | "rules": {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: cris691
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | typetests
2 | .*.swp
3 |
4 | # Logs
5 | logs
6 | *.log
7 | npm-debug.log*
8 | yarn-debug.log*
9 | yarn-error.log*
10 |
11 | # Runtime data
12 | pids
13 | *.pid
14 | *.seed
15 | *.pid.lock
16 |
17 | # Directory for instrumented libs generated by jscoverage/JSCover
18 | lib-cov
19 |
20 | # Coverage directory used by tools like istanbul
21 | coverage
22 |
23 | # nyc test coverage
24 | .nyc_output
25 |
26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
27 | .grunt
28 |
29 | # Bower dependency directory (https://bower.io/)
30 | bower_components
31 |
32 | # node-waf configuration
33 | .lock-wscript
34 |
35 | # Compiled binary addons (https://nodejs.org/api/addons.html)
36 | build/Release
37 |
38 | # Dependency directories
39 | node_modules/
40 | jspm_packages/
41 |
42 | # TypeScript v1 declaration files
43 | typings/
44 |
45 | # Optional npm cache directory
46 | .npm
47 |
48 | # Optional eslint cache
49 | .eslintcache
50 |
51 | # Optional REPL history
52 | .node_repl_history
53 |
54 | # Output of 'npm pack'
55 | *.tgz
56 |
57 | # Yarn Integrity file
58 | .yarn-integrity
59 |
60 | # dotenv environment variables file
61 | .env
62 |
63 | # next.js build output
64 | .next
65 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Cris Stringfellow & The Dosyago Corporation
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # :icecream: [vanillatype](https://github.com/crislin2046/vanillatype)  
2 |
3 |
4 | Lightweight run time types for vanilla JavaScript and Node.JS.
5 |
6 |
7 | ## A Users example from production
8 |
9 | *users.js:*
10 | ```javascript
11 | import {T} from 'vanillatype';
12 |
13 | T.def('User', {
14 | _id: T`ID`,
15 | _owner: T`ID`,
16 | username: T`Username`,
17 | email: T`Email`,
18 | newEmail: T.maybe(T`Email`),
19 | salt: T`Integer`,
20 | passwordHash: T`Hash`,
21 | groups: T`GroupArray`,
22 | stripeCustomerID: T`String`,
23 | verified: T.maybe(T`Boolean`)
24 | });
25 |
26 | export default function validate(user) {
27 | const errors = T.errors(T`User`, user);
28 |
29 | validateUsernameUniqueness(user, errors);
30 |
31 | return errors;
32 | }
33 |
34 | //...
35 | ```
36 |
37 | *types.js:*
38 | ```javascript
39 | import {T} from 'vanillatype';
40 |
41 | // regexes
42 |
43 | const UsernameRegExp = /^[a-zA-Z][a-zA-Z0-9]{4,16}$/
44 | const EmailRegExp = /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/;
45 | const HexRegExp = /^[a-f0-9]{8,100}$/i;
46 |
47 | // common types
48 |
49 | T.defOr('MaybeBoolean', T`Boolean`, T`None`);
50 |
51 | T.defOr('ID', T`String`, T`Number`);
52 |
53 | T.def('URL', null, {
54 | verify: i => {
55 | try {
56 | return new URL(i);
57 | } catch(e) {
58 | return false;
59 | }
60 | },
61 | help: "A valid URL"
62 | });
63 |
64 | // user field types
65 |
66 | T.defCollection('GroupArray', {
67 | container: T`Array`,
68 | member: T`String`
69 | });
70 |
71 | T.def('Username', null, {
72 | verify: i => UsernameRegExp.test(i) && i.length < 200,
73 | help:"Alphanumeric between 5 and 16 characters"
74 | });
75 |
76 | T.def('Email', null, {
77 | verify: i => EmailRegExp.test(i) && i.length < 200,
78 | help: "A valid email address"
79 | });
80 |
81 | T.def('Hash', null, {
82 | verify: i => HexRegExp.test(i) && i.length < 200,
83 | help: "A hexadecimal hash value, between 8 and 100 characters"
84 | });
85 | ```
86 |
87 | Taken from [servedata/_schemas/users.js](https://github.com/cris691/servedata/blob/master/_schemas/users.js) and [servedata/types.js](https://github.com/cris691/servedata/blob/master/types.js)
88 |
89 | ## Features
90 |
91 | - built-in support for built-in types!
92 | - common patterns like **collection, or, maybe** and **enum** types
93 | - fully optional
94 | - simple literate syntax
95 | - custom help fields to add context to type errors
96 | - optional partial (subset) matching
97 |
98 | ## Function list
99 | - T.check
100 | - T.sub
101 | - T.verify
102 | - T.validate
103 | - T.partialMatch
104 | - T.defEnum
105 | - T.defSub
106 | - T.defTuple
107 | - T.defCollection
108 | - T.defOr
109 | - T.option
110 | - T.defOption
111 | - T.maybe
112 | - T.guard
113 | - T.errors
114 | - annotate a function to take and return types ([coming](https://github.com/cris691/vanillatype/issues/13)!)
115 | - built in specials:
116 | ```js
117 | function defineSpecials() {
118 | T.def(`Any`, null, {verify: () => true});
119 | T.def(`Some`, null, {verify: i => !isUnset(i)});
120 | T.def(`None`, null, {verify: i => isUnset(i)});
121 | T.def(`Function`, null, {verify: i => i instanceof Function});
122 | T.def(`Integer`, null, {verify: i => Number.isInteger(i)});
123 | T.def(`Array`, null, {verify: i => Array.isArray(i)});
124 | T.def(`Iterable`, null, {verify: i => i[Symbol.iterator] instanceof Function});
125 | }
126 | ```
127 |
128 | ## Another reason I like this
129 |
130 | Apart from writing it myself to suit my own work style, which is a great reason to like something, I like this because, if I want to change the syntax, or add some new feature that I want, it's really easy to change the library, which is only a couple hundred lines of code. If I wanted the same results from a third-party library, I'd have to wait.
131 |
132 | ## More examples
133 |
134 | For more comprehensive examples see [vanillatype's test file](https://github.com/cris691/vanillatype/blob/master/test.js).
135 |
136 | ## getting and incorporating
137 |
138 | You can use the template repo or import using the old name on npm (vanillatype wasn't available to me, it is now).
139 |
140 | We use ES modules.
141 |
142 | You can use in your client side code like:
143 |
144 | ```JavaScript
145 | import {T} from 'https://unpkg.com/jtype-system/t.js';
146 | ```
147 |
148 | While the tests are currently only written for client side, you can use in Node.js like so:
149 |
150 | ```shell
151 | $ npm i --save vanillatype
152 | ```
153 |
154 | or using the old name
155 |
156 | ```shell
157 | $ npm i --save jtype-system
158 | ```
159 |
160 | Then:
161 |
162 | ```JavaScript
163 | import {T} from 'jtype-system';
164 | ```
165 |
166 | But you'll need to be using [ESM](https://www.npmjs.com/package/esm) or ES Modules.
167 |
168 |
169 | -------------
170 |
171 | ***VanillaType!***
172 |
--------------------------------------------------------------------------------
/decs.d.ts:
--------------------------------------------------------------------------------
1 | declare var T;
2 | declare var typeCache;
3 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/o0101/vanillatype/58c5e559531574cdf2bf6d83d4b499bd99473786/favicon.ico
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | require = require("esm")(module)
2 | module.exports = require("./t.js")
3 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vanillatype",
3 | "version": "1.4.1",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@babel/code-frame": {
8 | "version": "7.10.3",
9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.3.tgz",
10 | "integrity": "sha512-fDx9eNW0qz0WkUeqL6tXEXzVlPh6Y5aCDEZesl0xBGA8ndRukX91Uk44ZqnkECp01NAZUdCAl+aiQNGi0k88Eg==",
11 | "dev": true,
12 | "requires": {
13 | "@babel/highlight": "^7.10.3"
14 | }
15 | },
16 | "@babel/helper-validator-identifier": {
17 | "version": "7.10.3",
18 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz",
19 | "integrity": "sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw==",
20 | "dev": true
21 | },
22 | "@babel/highlight": {
23 | "version": "7.10.3",
24 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.3.tgz",
25 | "integrity": "sha512-Ih9B/u7AtgEnySE2L2F0Xm0GaM729XqqLfHkalTsbjXGyqmf/6M0Cu0WpvqueUlW+xk88BHw9Nkpj49naU+vWw==",
26 | "dev": true,
27 | "requires": {
28 | "@babel/helper-validator-identifier": "^7.10.3",
29 | "chalk": "^2.0.0",
30 | "js-tokens": "^4.0.0"
31 | },
32 | "dependencies": {
33 | "chalk": {
34 | "version": "2.4.2",
35 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
36 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
37 | "dev": true,
38 | "requires": {
39 | "ansi-styles": "^3.2.1",
40 | "escape-string-regexp": "^1.0.5",
41 | "supports-color": "^5.3.0"
42 | }
43 | }
44 | }
45 | },
46 | "@types/color-name": {
47 | "version": "1.1.1",
48 | "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
49 | "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
50 | "dev": true
51 | },
52 | "@types/node": {
53 | "version": "14.0.13",
54 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.13.tgz",
55 | "integrity": "sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA==",
56 | "dev": true
57 | },
58 | "acorn": {
59 | "version": "7.3.1",
60 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz",
61 | "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==",
62 | "dev": true
63 | },
64 | "acorn-jsx": {
65 | "version": "5.2.0",
66 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz",
67 | "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==",
68 | "dev": true
69 | },
70 | "ajv": {
71 | "version": "6.12.2",
72 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
73 | "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
74 | "dev": true,
75 | "requires": {
76 | "fast-deep-equal": "^3.1.1",
77 | "fast-json-stable-stringify": "^2.0.0",
78 | "json-schema-traverse": "^0.4.1",
79 | "uri-js": "^4.2.2"
80 | }
81 | },
82 | "ansi-colors": {
83 | "version": "3.2.4",
84 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
85 | "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
86 | "dev": true
87 | },
88 | "ansi-regex": {
89 | "version": "5.0.0",
90 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
91 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
92 | "dev": true
93 | },
94 | "ansi-styles": {
95 | "version": "3.2.1",
96 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
97 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
98 | "dev": true,
99 | "requires": {
100 | "color-convert": "^1.9.0"
101 | }
102 | },
103 | "argparse": {
104 | "version": "1.0.10",
105 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
106 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
107 | "dev": true,
108 | "requires": {
109 | "sprintf-js": "~1.0.2"
110 | }
111 | },
112 | "astral-regex": {
113 | "version": "1.0.0",
114 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
115 | "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
116 | "dev": true
117 | },
118 | "balanced-match": {
119 | "version": "1.0.0",
120 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
121 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
122 | "dev": true
123 | },
124 | "brace-expansion": {
125 | "version": "1.1.11",
126 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
127 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
128 | "dev": true,
129 | "requires": {
130 | "balanced-match": "^1.0.0",
131 | "concat-map": "0.0.1"
132 | }
133 | },
134 | "callsites": {
135 | "version": "3.1.0",
136 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
137 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
138 | "dev": true
139 | },
140 | "chalk": {
141 | "version": "4.1.0",
142 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
143 | "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
144 | "dev": true,
145 | "requires": {
146 | "ansi-styles": "^4.1.0",
147 | "supports-color": "^7.1.0"
148 | },
149 | "dependencies": {
150 | "ansi-styles": {
151 | "version": "4.2.1",
152 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
153 | "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
154 | "dev": true,
155 | "requires": {
156 | "@types/color-name": "^1.1.1",
157 | "color-convert": "^2.0.1"
158 | }
159 | },
160 | "color-convert": {
161 | "version": "2.0.1",
162 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
163 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
164 | "dev": true,
165 | "requires": {
166 | "color-name": "~1.1.4"
167 | }
168 | },
169 | "color-name": {
170 | "version": "1.1.4",
171 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
172 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
173 | "dev": true
174 | },
175 | "has-flag": {
176 | "version": "4.0.0",
177 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
178 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
179 | "dev": true
180 | },
181 | "supports-color": {
182 | "version": "7.1.0",
183 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
184 | "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
185 | "dev": true,
186 | "requires": {
187 | "has-flag": "^4.0.0"
188 | }
189 | }
190 | }
191 | },
192 | "color-convert": {
193 | "version": "1.9.3",
194 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
195 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
196 | "dev": true,
197 | "requires": {
198 | "color-name": "1.1.3"
199 | }
200 | },
201 | "color-name": {
202 | "version": "1.1.3",
203 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
204 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
205 | "dev": true
206 | },
207 | "concat-map": {
208 | "version": "0.0.1",
209 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
210 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
211 | "dev": true
212 | },
213 | "cross-spawn": {
214 | "version": "7.0.3",
215 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
216 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
217 | "dev": true,
218 | "requires": {
219 | "path-key": "^3.1.0",
220 | "shebang-command": "^2.0.0",
221 | "which": "^2.0.1"
222 | }
223 | },
224 | "debug": {
225 | "version": "4.1.1",
226 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
227 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
228 | "dev": true,
229 | "requires": {
230 | "ms": "^2.1.1"
231 | }
232 | },
233 | "deep-is": {
234 | "version": "0.1.3",
235 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
236 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
237 | "dev": true
238 | },
239 | "doctrine": {
240 | "version": "3.0.0",
241 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
242 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
243 | "dev": true,
244 | "requires": {
245 | "esutils": "^2.0.2"
246 | }
247 | },
248 | "emoji-regex": {
249 | "version": "7.0.3",
250 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
251 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
252 | "dev": true
253 | },
254 | "enquirer": {
255 | "version": "2.3.5",
256 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz",
257 | "integrity": "sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==",
258 | "dev": true,
259 | "requires": {
260 | "ansi-colors": "^3.2.1"
261 | }
262 | },
263 | "escape-string-regexp": {
264 | "version": "1.0.5",
265 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
266 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
267 | "dev": true
268 | },
269 | "eslint": {
270 | "version": "7.3.0",
271 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.3.0.tgz",
272 | "integrity": "sha512-dJMVXwfU5PT1cj2Nv2VPPrKahKTGdX+5Dh0Q3YuKt+Y2UhdL2YbzsVaBMyG9HC0tBismlv/r1+eZqs6SMIV38Q==",
273 | "dev": true,
274 | "requires": {
275 | "@babel/code-frame": "^7.0.0",
276 | "ajv": "^6.10.0",
277 | "chalk": "^4.0.0",
278 | "cross-spawn": "^7.0.2",
279 | "debug": "^4.0.1",
280 | "doctrine": "^3.0.0",
281 | "enquirer": "^2.3.5",
282 | "eslint-scope": "^5.1.0",
283 | "eslint-utils": "^2.0.0",
284 | "eslint-visitor-keys": "^1.2.0",
285 | "espree": "^7.1.0",
286 | "esquery": "^1.2.0",
287 | "esutils": "^2.0.2",
288 | "file-entry-cache": "^5.0.1",
289 | "functional-red-black-tree": "^1.0.1",
290 | "glob-parent": "^5.0.0",
291 | "globals": "^12.1.0",
292 | "ignore": "^4.0.6",
293 | "import-fresh": "^3.0.0",
294 | "imurmurhash": "^0.1.4",
295 | "is-glob": "^4.0.0",
296 | "js-yaml": "^3.13.1",
297 | "json-stable-stringify-without-jsonify": "^1.0.1",
298 | "levn": "^0.4.1",
299 | "lodash": "^4.17.14",
300 | "minimatch": "^3.0.4",
301 | "natural-compare": "^1.4.0",
302 | "optionator": "^0.9.1",
303 | "progress": "^2.0.0",
304 | "regexpp": "^3.1.0",
305 | "semver": "^7.2.1",
306 | "strip-ansi": "^6.0.0",
307 | "strip-json-comments": "^3.1.0",
308 | "table": "^5.2.3",
309 | "text-table": "^0.2.0",
310 | "v8-compile-cache": "^2.0.3"
311 | }
312 | },
313 | "eslint-scope": {
314 | "version": "5.1.0",
315 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz",
316 | "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==",
317 | "dev": true,
318 | "requires": {
319 | "esrecurse": "^4.1.0",
320 | "estraverse": "^4.1.1"
321 | }
322 | },
323 | "eslint-utils": {
324 | "version": "2.1.0",
325 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
326 | "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
327 | "dev": true,
328 | "requires": {
329 | "eslint-visitor-keys": "^1.1.0"
330 | }
331 | },
332 | "eslint-visitor-keys": {
333 | "version": "1.3.0",
334 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
335 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
336 | "dev": true
337 | },
338 | "esm": {
339 | "version": "3.1.0",
340 | "resolved": "https://registry.npmjs.org/esm/-/esm-3.1.0.tgz",
341 | "integrity": "sha512-r4Go7Wh7Wh0WPinRXeeM9PIajRsUdt8SAyki5R1obVc0+BwtqvtjbngVSSdXg0jCe2xZkY8hyBMx6q/uymUkPw=="
342 | },
343 | "espree": {
344 | "version": "7.1.0",
345 | "resolved": "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz",
346 | "integrity": "sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==",
347 | "dev": true,
348 | "requires": {
349 | "acorn": "^7.2.0",
350 | "acorn-jsx": "^5.2.0",
351 | "eslint-visitor-keys": "^1.2.0"
352 | }
353 | },
354 | "esprima": {
355 | "version": "4.0.1",
356 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
357 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
358 | "dev": true
359 | },
360 | "esquery": {
361 | "version": "1.3.1",
362 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
363 | "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
364 | "dev": true,
365 | "requires": {
366 | "estraverse": "^5.1.0"
367 | },
368 | "dependencies": {
369 | "estraverse": {
370 | "version": "5.1.0",
371 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz",
372 | "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==",
373 | "dev": true
374 | }
375 | }
376 | },
377 | "esrecurse": {
378 | "version": "4.2.1",
379 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
380 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
381 | "dev": true,
382 | "requires": {
383 | "estraverse": "^4.1.0"
384 | }
385 | },
386 | "estraverse": {
387 | "version": "4.3.0",
388 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
389 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
390 | "dev": true
391 | },
392 | "esutils": {
393 | "version": "2.0.3",
394 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
395 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
396 | "dev": true
397 | },
398 | "fast-deep-equal": {
399 | "version": "3.1.3",
400 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
401 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
402 | "dev": true
403 | },
404 | "fast-json-stable-stringify": {
405 | "version": "2.1.0",
406 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
407 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
408 | "dev": true
409 | },
410 | "fast-levenshtein": {
411 | "version": "2.0.6",
412 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
413 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
414 | "dev": true
415 | },
416 | "file-entry-cache": {
417 | "version": "5.0.1",
418 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
419 | "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
420 | "dev": true,
421 | "requires": {
422 | "flat-cache": "^2.0.1"
423 | }
424 | },
425 | "flat-cache": {
426 | "version": "2.0.1",
427 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
428 | "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
429 | "dev": true,
430 | "requires": {
431 | "flatted": "^2.0.0",
432 | "rimraf": "2.6.3",
433 | "write": "1.0.3"
434 | }
435 | },
436 | "flatted": {
437 | "version": "2.0.2",
438 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
439 | "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
440 | "dev": true
441 | },
442 | "fs.realpath": {
443 | "version": "1.0.0",
444 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
445 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
446 | "dev": true
447 | },
448 | "functional-red-black-tree": {
449 | "version": "1.0.1",
450 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
451 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
452 | "dev": true
453 | },
454 | "glob": {
455 | "version": "7.1.6",
456 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
457 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
458 | "dev": true,
459 | "requires": {
460 | "fs.realpath": "^1.0.0",
461 | "inflight": "^1.0.4",
462 | "inherits": "2",
463 | "minimatch": "^3.0.4",
464 | "once": "^1.3.0",
465 | "path-is-absolute": "^1.0.0"
466 | }
467 | },
468 | "glob-parent": {
469 | "version": "5.1.1",
470 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
471 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
472 | "dev": true,
473 | "requires": {
474 | "is-glob": "^4.0.1"
475 | }
476 | },
477 | "globals": {
478 | "version": "12.4.0",
479 | "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
480 | "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
481 | "dev": true,
482 | "requires": {
483 | "type-fest": "^0.8.1"
484 | }
485 | },
486 | "has-flag": {
487 | "version": "3.0.0",
488 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
489 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
490 | "dev": true
491 | },
492 | "ignore": {
493 | "version": "4.0.6",
494 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
495 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
496 | "dev": true
497 | },
498 | "import-fresh": {
499 | "version": "3.2.1",
500 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
501 | "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
502 | "dev": true,
503 | "requires": {
504 | "parent-module": "^1.0.0",
505 | "resolve-from": "^4.0.0"
506 | }
507 | },
508 | "imurmurhash": {
509 | "version": "0.1.4",
510 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
511 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
512 | "dev": true
513 | },
514 | "inflight": {
515 | "version": "1.0.6",
516 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
517 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
518 | "dev": true,
519 | "requires": {
520 | "once": "^1.3.0",
521 | "wrappy": "1"
522 | }
523 | },
524 | "inherits": {
525 | "version": "2.0.4",
526 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
527 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
528 | "dev": true
529 | },
530 | "is-extglob": {
531 | "version": "2.1.1",
532 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
533 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
534 | "dev": true
535 | },
536 | "is-fullwidth-code-point": {
537 | "version": "2.0.0",
538 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
539 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
540 | "dev": true
541 | },
542 | "is-glob": {
543 | "version": "4.0.1",
544 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
545 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
546 | "dev": true,
547 | "requires": {
548 | "is-extglob": "^2.1.1"
549 | }
550 | },
551 | "isexe": {
552 | "version": "2.0.0",
553 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
554 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
555 | "dev": true
556 | },
557 | "js-tokens": {
558 | "version": "4.0.0",
559 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
560 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
561 | "dev": true
562 | },
563 | "js-yaml": {
564 | "version": "3.14.0",
565 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
566 | "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
567 | "dev": true,
568 | "requires": {
569 | "argparse": "^1.0.7",
570 | "esprima": "^4.0.0"
571 | }
572 | },
573 | "json-schema-traverse": {
574 | "version": "0.4.1",
575 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
576 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
577 | "dev": true
578 | },
579 | "json-stable-stringify-without-jsonify": {
580 | "version": "1.0.1",
581 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
582 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
583 | "dev": true
584 | },
585 | "levn": {
586 | "version": "0.4.1",
587 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
588 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
589 | "dev": true,
590 | "requires": {
591 | "prelude-ls": "^1.2.1",
592 | "type-check": "~0.4.0"
593 | }
594 | },
595 | "lodash": {
596 | "version": "4.17.19",
597 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
598 | "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
599 | "dev": true
600 | },
601 | "minimatch": {
602 | "version": "3.0.4",
603 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
604 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
605 | "dev": true,
606 | "requires": {
607 | "brace-expansion": "^1.1.7"
608 | }
609 | },
610 | "minimist": {
611 | "version": "1.2.5",
612 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
613 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
614 | "dev": true
615 | },
616 | "mkdirp": {
617 | "version": "0.5.5",
618 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
619 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
620 | "dev": true,
621 | "requires": {
622 | "minimist": "^1.2.5"
623 | }
624 | },
625 | "ms": {
626 | "version": "2.1.2",
627 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
628 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
629 | "dev": true
630 | },
631 | "natural-compare": {
632 | "version": "1.4.0",
633 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
634 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
635 | "dev": true
636 | },
637 | "once": {
638 | "version": "1.4.0",
639 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
640 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
641 | "dev": true,
642 | "requires": {
643 | "wrappy": "1"
644 | }
645 | },
646 | "optionator": {
647 | "version": "0.9.1",
648 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
649 | "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
650 | "dev": true,
651 | "requires": {
652 | "deep-is": "^0.1.3",
653 | "fast-levenshtein": "^2.0.6",
654 | "levn": "^0.4.1",
655 | "prelude-ls": "^1.2.1",
656 | "type-check": "^0.4.0",
657 | "word-wrap": "^1.2.3"
658 | }
659 | },
660 | "parent-module": {
661 | "version": "1.0.1",
662 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
663 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
664 | "dev": true,
665 | "requires": {
666 | "callsites": "^3.0.0"
667 | }
668 | },
669 | "path-is-absolute": {
670 | "version": "1.0.1",
671 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
672 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
673 | "dev": true
674 | },
675 | "path-key": {
676 | "version": "3.1.1",
677 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
678 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
679 | "dev": true
680 | },
681 | "prelude-ls": {
682 | "version": "1.2.1",
683 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
684 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
685 | "dev": true
686 | },
687 | "progress": {
688 | "version": "2.0.3",
689 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
690 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
691 | "dev": true
692 | },
693 | "punycode": {
694 | "version": "2.1.1",
695 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
696 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
697 | "dev": true
698 | },
699 | "regexpp": {
700 | "version": "3.1.0",
701 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
702 | "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
703 | "dev": true
704 | },
705 | "resolve-from": {
706 | "version": "4.0.0",
707 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
708 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
709 | "dev": true
710 | },
711 | "rimraf": {
712 | "version": "2.6.3",
713 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
714 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
715 | "dev": true,
716 | "requires": {
717 | "glob": "^7.1.3"
718 | }
719 | },
720 | "semver": {
721 | "version": "7.3.2",
722 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
723 | "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
724 | "dev": true
725 | },
726 | "shebang-command": {
727 | "version": "2.0.0",
728 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
729 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
730 | "dev": true,
731 | "requires": {
732 | "shebang-regex": "^3.0.0"
733 | }
734 | },
735 | "shebang-regex": {
736 | "version": "3.0.0",
737 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
738 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
739 | "dev": true
740 | },
741 | "slice-ansi": {
742 | "version": "2.1.0",
743 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
744 | "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
745 | "dev": true,
746 | "requires": {
747 | "ansi-styles": "^3.2.0",
748 | "astral-regex": "^1.0.0",
749 | "is-fullwidth-code-point": "^2.0.0"
750 | }
751 | },
752 | "sprintf-js": {
753 | "version": "1.0.3",
754 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
755 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
756 | "dev": true
757 | },
758 | "string-width": {
759 | "version": "3.1.0",
760 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
761 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
762 | "dev": true,
763 | "requires": {
764 | "emoji-regex": "^7.0.1",
765 | "is-fullwidth-code-point": "^2.0.0",
766 | "strip-ansi": "^5.1.0"
767 | },
768 | "dependencies": {
769 | "ansi-regex": {
770 | "version": "4.1.0",
771 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
772 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
773 | "dev": true
774 | },
775 | "strip-ansi": {
776 | "version": "5.2.0",
777 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
778 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
779 | "dev": true,
780 | "requires": {
781 | "ansi-regex": "^4.1.0"
782 | }
783 | }
784 | }
785 | },
786 | "strip-ansi": {
787 | "version": "6.0.0",
788 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
789 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
790 | "dev": true,
791 | "requires": {
792 | "ansi-regex": "^5.0.0"
793 | }
794 | },
795 | "strip-json-comments": {
796 | "version": "3.1.0",
797 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz",
798 | "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==",
799 | "dev": true
800 | },
801 | "supports-color": {
802 | "version": "5.5.0",
803 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
804 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
805 | "dev": true,
806 | "requires": {
807 | "has-flag": "^3.0.0"
808 | }
809 | },
810 | "table": {
811 | "version": "5.4.6",
812 | "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
813 | "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
814 | "dev": true,
815 | "requires": {
816 | "ajv": "^6.10.2",
817 | "lodash": "^4.17.14",
818 | "slice-ansi": "^2.1.0",
819 | "string-width": "^3.0.0"
820 | }
821 | },
822 | "text-table": {
823 | "version": "0.2.0",
824 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
825 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
826 | "dev": true
827 | },
828 | "type-check": {
829 | "version": "0.4.0",
830 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
831 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
832 | "dev": true,
833 | "requires": {
834 | "prelude-ls": "^1.2.1"
835 | }
836 | },
837 | "type-fest": {
838 | "version": "0.8.1",
839 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
840 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
841 | "dev": true
842 | },
843 | "typescript": {
844 | "version": "3.9.5",
845 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz",
846 | "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
847 | "dev": true
848 | },
849 | "uri-js": {
850 | "version": "4.2.2",
851 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
852 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
853 | "dev": true,
854 | "requires": {
855 | "punycode": "^2.1.0"
856 | }
857 | },
858 | "v8-compile-cache": {
859 | "version": "2.1.1",
860 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
861 | "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
862 | "dev": true
863 | },
864 | "which": {
865 | "version": "2.0.2",
866 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
867 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
868 | "dev": true,
869 | "requires": {
870 | "isexe": "^2.0.0"
871 | }
872 | },
873 | "word-wrap": {
874 | "version": "1.2.3",
875 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
876 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
877 | "dev": true
878 | },
879 | "wrappy": {
880 | "version": "1.0.2",
881 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
882 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
883 | "dev": true
884 | },
885 | "write": {
886 | "version": "1.0.3",
887 | "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
888 | "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
889 | "dev": true,
890 | "requires": {
891 | "mkdirp": "^0.5.1"
892 | }
893 | }
894 | }
895 | }
896 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": {
3 | "name": "@dosy"
4 | },
5 | "bundleDependencies": [],
6 | "dependencies": {
7 | "esm": "^3.0.74"
8 | },
9 | "deprecated": false,
10 | "description": "Lightweight runtime types for vanilla JS and Node",
11 | "keywords": [
12 | "javascript",
13 | "type-system",
14 | "vanillatype",
15 | "jtype",
16 | "dosy"
17 | ],
18 | "license": "MIT",
19 | "main": "index.js",
20 | "name": "vanillatype",
21 | "repository": {
22 | "type": "git",
23 | "url": "https://github.com//crislin2046/jtype"
24 | },
25 | "scripts": {
26 | "test": "serve -p 8080",
27 | "tscheck-client": "tsc --types node --target ES2020 --checkJs --allowJs --outFile typetests/client.js --module System t.js test.js decs.d.ts",
28 | "tscheck": "npm run tscheck-client",
29 | "lint": "npx eslint t.js test.js",
30 | "check": "npm run lint && npm run tscheck"
31 | },
32 | "version": "1.4.1",
33 | "devDependencies": {
34 | "@types/node": "^14.0.13",
35 | "eslint": "^7.3.0",
36 | "typescript": "^3.9.5"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/t.js:
--------------------------------------------------------------------------------
1 |
2 | export const BROWSER_SIDE = (() => {try{ return self.DOMParser && true; } catch(e) { return false; }})();
3 |
4 | const BuiltIns = [
5 | Symbol, Boolean, Number, String, Object, Set, Map, WeakMap, WeakSet,
6 | Uint8Array, Uint16Array, Uint32Array, Float32Array, Float64Array,
7 | Int8Array, Int16Array, Int32Array,
8 | Uint8ClampedArray,
9 | ...(BROWSER_SIDE ? [
10 | Node,NodeList,Element,HTMLElement, Blob, ArrayBuffer,
11 | FileList, Text, HTMLDocument, Document, DocumentFragment,
12 | Error, File, Event, EventTarget, URL
13 | /* eslint-disable no-undef */
14 | ] : [ Buffer ])
15 | /* eslint-enable no-undef */
16 | ]
17 |
18 | const DEBUG = false;
19 | const SEALED_DEFAULT = true;
20 | const isNone = instance => instance == null || instance == undefined;
21 |
22 | const typeCache = new Map();
23 |
24 | T.def = def;
25 | T.check = check;
26 | T.sub = sub;
27 | T.verify = verify;
28 | T.validate = validate;
29 | T.partialMatch = partialMatch;
30 | T.defEnum = defEnum;
31 | T.defSub = defSub;
32 | T.defTuple = defTuple;
33 | T.defCollection = defCollection;
34 | T.defOr = defOr;
35 | T.option = option;
36 | T.defOption = defOption;
37 | T.maybe = maybe;
38 | T.guard = guard;
39 | T.errors = errors;
40 |
41 | // debug
42 | if ( DEBUG ) {
43 | self.T = T;
44 | self.typeCache = typeCache;
45 | }
46 |
47 | T[Symbol.for('jtype-system.typeCache')] = typeCache;
48 |
49 | defineSpecials();
50 | mapBuiltins();
51 |
52 | export function T(parts, ...vals) {
53 | const cooked = vals.reduce((prev,cur,i) => prev+cur+parts[i+1], parts[0]);
54 | const typeName = cooked;
55 | if ( !typeCache.has(typeName) ) throw new TypeError(`Cannot use type ${typeName} before it is defined.`);
56 | return typeCache.get(typeName).type;
57 | }
58 |
59 | function partialMatch(type, instance) {
60 | return validate(type, instance, {partial:true});
61 | }
62 |
63 | function validate(type, instance, {partial: partial = false} = {}) {
64 | guardType(type);
65 | guardExists(type);
66 | const typeName = type.name;
67 |
68 | const {spec,kind,help,verify,verifiers,sealed} = typeCache.get(typeName);
69 |
70 | const specKeyPaths = spec ? allKeyPaths(spec).sort() : [];
71 | const specKeyPathSet = new Set(specKeyPaths);
72 |
73 | const bigErrors = [];
74 |
75 | switch(kind) {
76 | case "def": {
77 | let allValid = true;
78 | if ( spec ) {
79 | const keyPaths = partial ? allKeyPaths(instance, specKeyPathSet) : specKeyPaths;
80 | allValid = !isNone(instance) && keyPaths.every(kp => {
81 | // Allow lookup errors if the type match for the key path can include None
82 |
83 | const {resolved, errors:lookupErrors} = lookup(instance,kp,() => checkTypeMatch(lookup(spec,kp).resolved, T`None`));
84 | bigErrors.push(...lookupErrors);
85 |
86 | if ( lookupErrors.length ) return false;
87 |
88 | const keyType = lookup(spec,kp).resolved;
89 | if ( !keyType || !(keyType instanceof Type) ) {
90 | bigErrors.push({
91 | error: `Key path '${kp}' is not present in the spec for type '${typeName}'`
92 | });
93 | return false;
94 | }
95 |
96 | const {valid, errors: validationErrors} = validate(keyType, resolved);
97 | bigErrors.push(...validationErrors);
98 |
99 | return valid;
100 | });
101 | }
102 | let verified = true;
103 | if ( partial && ! spec && !!verify ) {
104 | throw new TypeError(`Type checking with option 'partial' is not a valid option for types that` +
105 | ` only use a verify function but have no spec`);
106 | } else if ( verify ) {
107 | try {
108 | verified = verify(instance);
109 | if ( ! verified ) {
110 | if ( verifiers ) {
111 | throw {
112 | error:`Type ${typeName} value '${JSON.stringify(instance)}' violated at least 1 verify function in:\n${
113 | verifiers.map(f => '\t'+(f.help||'') + ' ('+f.verify.toString()+')').join('\n')
114 | }`
115 | };
116 | } else if ( type.isSumType ) {
117 | throw {
118 | error: `Value '${JSON.stringify(instance)}' did not match any of: ${[...type.types.keys()].map(t => t.name)}`,
119 | verify, verifiers
120 | }
121 | } else {
122 | let helpMsg = '';
123 | if ( help ) {
124 | helpMsg = `Help: ${help}. `;
125 | }
126 | throw {error:`${helpMsg}Type ${typeName} Value '${JSON.stringify(instance)}' violated verify function in: ${verify.toString()}`};
127 | }
128 | }
129 | } catch(e) {
130 | bigErrors.push(e);
131 | verified = false;
132 | }
133 | }
134 | let sealValid = true;
135 | if ( !!sealed && !! spec ) {
136 | const type_key_paths = specKeyPaths;
137 | const all_key_paths = allKeyPaths(instance, specKeyPathSet).sort();
138 | sealValid = all_key_paths.join(',') == type_key_paths.join(',');
139 | if ( ! sealValid ) {
140 | if ( all_key_paths.length < type_key_paths.length ) {
141 | sealValid = true;
142 | } else {
143 | const errorKeys = [];
144 | const tkp = new Set(type_key_paths);
145 | for( const k of all_key_paths ) {
146 | if ( ! tkp.has(k) ) {
147 | errorKeys.push({
148 | error: `Key path '${k}' is not in the spec for type ${typeName}`
149 | });
150 | }
151 | }
152 | if ( errorKeys.length ) {
153 | bigErrors.push(...errorKeys);
154 | }
155 | }
156 | }
157 | }
158 | return {valid: allValid && verified && sealValid, errors: bigErrors, partial}
159 | } case "defCollection": {
160 | const {valid:containerValid, errors:containerErrors} = validate(spec.container, instance);
161 | let membersValid = true;
162 | let verified = true;
163 |
164 | bigErrors.push(...containerErrors);
165 | if ( partial ) {
166 | throw new TypeError(`Type checking with option 'partial' is not a valid option for Collection types`);
167 | } else {
168 | if ( containerValid ) {
169 | membersValid= [...instance].every(member => {
170 | const {valid, errors} = validate(spec.member, member);
171 | bigErrors.push(...errors);
172 | return valid;
173 | });
174 | }
175 | if ( verify ) {
176 | try {
177 | verified = verify(instance);
178 | } catch(e) {
179 | bigErrors.push(e);
180 | verified = false;
181 | }
182 | }
183 | }
184 |
185 | return {valid:containerValid && membersValid && verified, errors:bigErrors};
186 | } default: {
187 | throw new TypeError(`Checking for type kind ${kind} is not yet implemented.`);
188 | }
189 | }
190 | }
191 |
192 | function check(...args) {
193 | return validate(...args).valid;
194 | }
195 |
196 | function lookup(obj, keyPath, canBeNone) {
197 | if ( isNone(obj) ) throw new TypeError(`Lookup requires a non-unset object.`);
198 |
199 | if ( !keyPath ) throw new TypeError(`keyPath must not be empty`);
200 |
201 |
202 | const keys = keyPath.split(/\./g);
203 | const pathComplete = [];
204 | const errors = [];
205 |
206 | let resolved = obj;
207 |
208 | while(keys.length) {
209 | const nextKey = keys.shift();
210 | resolved = resolved[nextKey];
211 | pathComplete.push(nextKey);
212 | if ( (resolved === null || resolved === undefined) ) {
213 | if ( keys.length ) {
214 | errors.push({
215 | error:
216 | `Lookup on key path '${keyPath}' failed at '` +
217 | pathComplete.join('.') +
218 | `' when ${resolved} was found at '${nextKey}'.`
219 | });
220 | } else if ( !!canBeNone && canBeNone() ) {
221 | resolved = undefined;
222 | } else {
223 | errors.push({
224 | error:
225 | `Resolution on key path '${keyPath}' failed` +
226 | `when ${resolved} was found at '${nextKey}' and the Type of this` +
227 | `key's value cannot be None.`
228 | });
229 | }
230 | break;
231 | }
232 | }
233 | return {resolved,errors};
234 | }
235 |
236 | function checkTypeMatch(typeA, typeB) {
237 | guardType(typeA);
238 | guardExists(typeA);
239 | guardType(typeB);
240 | guardExists(typeB);
241 |
242 | if ( typeA === typeB ) {
243 | return true;
244 | } else if ( typeA.isSumType && typeA.types.has(typeB) ) {
245 | return true;
246 | } else if ( typeB.isSumType && typeB.types.has(typeA) ) {
247 | return true;
248 | } else if ( typeA.name.startsWith('?') && typeB == T`None` ) {
249 | return true;
250 | } else if ( typeB.name.startsWith('?') && typeA == T`None` ) {
251 | return true;
252 | }
253 |
254 | if ( typeA.name.startsWith('>') || typeB.name.startsWith('>') ) {
255 | console.error(new Error(`Check type match has not been implemented for derived//sub types yet.`));
256 | }
257 |
258 | return false;
259 | }
260 |
261 | function option(type) {
262 | return T`?${type.name}`;
263 | }
264 |
265 | function sub(type) {
266 | return T`>${type.name}`;
267 | }
268 |
269 | function defSub(type, spec, {verify: verify = undefined, help:help = ''} = {}, name = '') {
270 | guardType(type);
271 | guardExists(type);
272 |
273 | let verifiers;
274 |
275 | if ( ! verify ) {
276 | verify = () => true;
277 | }
278 |
279 | if ( type.native ) {
280 | verifiers = [ {help,verify} ];
281 | verify = i => i instanceof type.native;
282 | const helpMsg = `Needs to be of type ${type.native.name}. ${help||''}`;
283 | verifiers.push({help:helpMsg,verify});
284 | }
285 |
286 | const newType = def(`${name}>${type.name}`, spec, {verify,help, verifiers});
287 | return newType;
288 | }
289 |
290 | function defEnum(name, ...values) {
291 | if ( !name ) throw new TypeError(`Type must be named.`);
292 | guardRedefinition(name);
293 |
294 | const valueSet = new Set(values);
295 | const verify = i => valueSet.has(i);
296 | const help = `Value of Enum type ${name} must be one of ${values.join(',')}`;
297 |
298 | return def(name, null, {verify,help});
299 | }
300 |
301 | function exists(name) {
302 | return typeCache.has(name);
303 | }
304 |
305 | function guardRedefinition(name) {
306 | if ( exists(name) ) throw new TypeError(`Type ${name} cannot be redefined.`);
307 | }
308 |
309 | function allKeyPaths(o, specKeyPaths) {
310 | const isTypeSpec = ! specKeyPaths;
311 | const keyPaths = new Set();
312 | return recurseObject(o, keyPaths, '');
313 |
314 | function recurseObject(o, keyPathSet, lastLevel = '') {
315 | const levelKeys = Object.getOwnPropertyNames(o);
316 | const keyPaths = levelKeys
317 | .map(k => lastLevel + (lastLevel.length ? '.' : '') + k)
318 | levelKeys.forEach((k,i) => {
319 | const v = o[k];
320 | if ( isTypeSpec ) {
321 | if ( v instanceof Type ) {
322 | keyPathSet.add(keyPaths[i]);
323 | } else if ( typeof v == "object" ) {
324 | if ( ! Array.isArray(v) ) {
325 | recurseObject(v, keyPathSet, keyPaths[i]);
326 | } else {
327 | DEBUG && console.warn({o,v,keyPathSet, lastLevel});
328 | throw new TypeError(`We don't support Types that use Arrays as structure, just yet.`);
329 | }
330 | } else {
331 | throw new TypeError(`Spec cannot contain leaf values that are not valid Types`);
332 | }
333 | } else {
334 | if ( specKeyPaths.has(keyPaths[i]) ) {
335 | keyPathSet.add(keyPaths[i]);
336 | } else if ( typeof v == "object" ) {
337 | if ( ! Array.isArray(v) ) {
338 | recurseObject(v, keyPathSet, keyPaths[i]);
339 | } else {
340 | v.forEach((item,index) => recurseObject(item, keyPathSet, keyPaths[i] + '.' + index));
341 | //throw new TypeError(`We don't support Instances that use Arrays as structure, just yet.`);
342 | }
343 | } else {
344 | //console.warn("Spec has no such key", keyPaths[i]);
345 | keyPathSet.add(keyPaths[i]);
346 | }
347 | }
348 | });
349 | return [...keyPathSet];
350 | }
351 | }
352 |
353 | function defOption(type) {
354 | guardType(type);
355 | const typeName = type.name;
356 | return T.def(`?${typeName}`, null, {verify: i => isUnset(i) || T.check(type,i)});
357 | }
358 |
359 | function maybe(type) {
360 | try {
361 | return defOption(type);
362 | } catch(e) {
363 | // console.log(`Option Type ${type.name} already declared.`, e);
364 | }
365 | return T`?${type.name}`;
366 | }
367 |
368 | function verify(...args) { return check(...args); }
369 |
370 | function defCollection(name, {container, member}, {sealed: sealed = SEALED_DEFAULT, verify: verify = undefined} = {}) {
371 | if ( !name ) throw new TypeError(`Type must be named.`);
372 | if ( !container || !member ) throw new TypeError(`Type must be specified.`);
373 | guardRedefinition(name);
374 |
375 | const kind = 'defCollection';
376 | const t = new Type(name);
377 | const spec = {kind, spec: { container, member}, verify, sealed, type: t};
378 | typeCache.set(name, spec);
379 | return t;
380 | }
381 |
382 | function defTuple(name, {pattern}) {
383 | if ( !name ) throw new TypeError(`Type must be named.`);
384 | if ( !pattern ) throw new TypeError(`Type must be specified.`);
385 | const kind = 'def';
386 | const specObj = {};
387 | pattern.forEach((type,key) => specObj[key] = type);
388 | const t = new Type(name);
389 | const spec = {kind, spec: specObj, type:t};
390 | typeCache.set(name, spec);
391 | return t;
392 | }
393 |
394 | function Type(name, mods = {}) {
395 | if ( ! new.target ) throw new TypeError(`Type with new only.`);
396 | Object.defineProperty(this,'name', {get: () => name});
397 | this.typeName = name;
398 |
399 | if ( mods.types ) {
400 | const {types} = mods;
401 | const typeSet = new Set(types);
402 | Object.defineProperty(this,'isSumType', {get: () => true});
403 | Object.defineProperty(this,'types', {get: () => typeSet});
404 | }
405 |
406 | if ( mods.native ) {
407 | const {native} = mods;
408 | Object.defineProperty(this,'native', {get: () => native});
409 | }
410 | }
411 |
412 | Type.prototype.toString = function () {
413 | return `${this.typeName} Type`;
414 | };
415 |
416 | function def(name, spec, {help:help = '', verify:verify = undefined, sealed:sealed = undefined, types:types = undefined, verifiers:verifiers = undefined, native:native = undefined} = {}) {
417 | if ( !name ) throw new TypeError(`Type must be named.`);
418 | guardRedefinition(name);
419 |
420 | if ( name.startsWith('?') ) {
421 | if ( spec ) {
422 | throw new TypeError(`Option type can not have a spec.`);
423 | }
424 |
425 | if ( ! verify(null) ) {
426 | throw new TypeError(`Option type must be OK to be unset.`);
427 | }
428 | }
429 |
430 | const kind = 'def';
431 | if ( sealed === undefined ) {
432 | sealed = true;
433 | }
434 | const t = new Type(name, {types, native});
435 | const cache = {spec,kind,help,verify,verifiers,sealed,types,native,type:t};
436 | typeCache.set(name, cache);
437 | return t;
438 | }
439 |
440 | function defOr(name, ...types) {
441 | return T.def(name, null, {types, verify: i => types.some(t => check(t,i))});
442 | }
443 |
444 | function guard(type, instance) {
445 | guardType(type);
446 | guardExists(type);
447 | const {valid, errors} = validate(type, instance);
448 | if ( ! valid ) throw new TypeError(`Type ${type} requested, but item is not of that type: ${errors.join(', ')}`);
449 | }
450 |
451 | function guardType(t) {
452 | //console.log(t);
453 | if ( !(t instanceof Type) ) throw new TypeError(`Type must be a valid Type object.`);
454 | }
455 |
456 | function guardExists(t) {
457 | const name = originalName(t);
458 | if ( ! exists(name) ) throw new TypeError(`Type must exist. Type ${name} has not been defined.`);
459 | }
460 |
461 | function errors(...args) {
462 | return validate(...args).errors;
463 | }
464 |
465 | function mapBuiltins() {
466 | BuiltIns.forEach(t => def(originalName(t), null, {native: t, verify: i => originalName(i.constructor) === originalName(t)}));
467 | BuiltIns.forEach(t => defSub(T`${originalName(t)}`));
468 | }
469 |
470 | function defineSpecials() {
471 | T.def(`Any`, null, {verify: () => true});
472 | T.def(`Some`, null, {verify: i => !isUnset(i)});
473 | T.def(`None`, null, {verify: i => isUnset(i)});
474 | T.def(`Function`, null, {verify: i => i instanceof Function});
475 | T.def(`Integer`, null, {verify: i => Number.isInteger(i)});
476 | T.def(`Array`, null, {verify: i => Array.isArray(i)});
477 | T.def(`Iterable`, null, {verify: i => i[Symbol.iterator] instanceof Function});
478 | }
479 |
480 | function isUnset(i) {
481 | return i === null || i === undefined;
482 | }
483 |
484 | function originalName(t) {
485 | if (!!t && t.name) {
486 | return t.name;
487 | }
488 | const oName = Object.prototype.toString.call(t).replace(/\[object |\]/g, '');
489 | if ( oName.endsWith('Constructor') ) {
490 | return oName.replace(/Constructor$/,'');
491 | }
492 | return oName;
493 | }
494 |
495 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 |
2 | import {T} from './t.js';
3 | Object.assign(self, {T});
4 |
5 | const result0 = T.validate(T`Number`, 0);
6 | console.log({result0});
7 | console.assert(result0.valid);
8 |
9 | T.defOr('KeyVal', T`String`, T`Number`);
10 | const result01 = T.validate(T`KeyVal`, 0);
11 | console.log({result01});
12 | console.assert(result01.valid);
13 |
14 | T.def('Cris', {
15 | a: { b: { c: T`String` }}
16 | });
17 |
18 | const result1 = T.validate(T`Cris`, {a:1});
19 | console.log({result1});
20 | console.assert(!result1.valid);
21 |
22 | const result2 = T.validate(T`Cris`, {a:{b:{c:'asdsad'}}});
23 | console.log({result2});
24 | console.assert(result2.valid);
25 |
26 | T.defCollection(`DOMList`, {
27 | container: T`>NodeList`,
28 | member: T`>Node`
29 | });
30 |
31 | const result3 = T.validate(T`DOMList`, document.querySelectorAll('*'));
32 | const result4 = T.validate(T`DOMList`, document.body.childNodes);
33 |
34 | console.log({result3});
35 | console.assert(result3.valid);
36 | console.log({result4});
37 | console.assert(result4.valid);
38 |
39 | T.defTuple(`TypeMapping`, {
40 | pattern: [T`String`, T`>Object`]
41 | });
42 |
43 | T.defCollection(`TypeMap`, {
44 | container: T`Map`,
45 | member: T`TypeMapping`
46 | });
47 |
48 | const result5 = T.validate(T`TypeMap`, T[Symbol.for('jtype-system.typeCache')]);
49 |
50 | console.log({result5});
51 | console.assert(result5.valid);
52 |
53 | const result6 = [
54 | T.check(T`Iterable`, []),
55 | T.check(T`Iterable`, "ASDSAD"),
56 | T.check(T`Iterable`, new Set()),
57 | T.check(T`Iterable`, document.querySelectorAll('*')),
58 | T.check(T`Iterable`, {}),
59 | T.check(T`Iterable`, 12312),
60 | ];
61 |
62 | console.log({result6});
63 | console.assert(result6.join(',') == [true, true, true, true, false, false].join(','));
64 |
65 | T.defOr(`Key`, T`String`, T`Integer`);
66 | T.defOption(T`Key`);
67 |
68 | const keys = [
69 | "ASDSA",
70 | 1312312,
71 | "asd",
72 | 123122232
73 | ];
74 | const not_keys = [
75 | "ASDSA",
76 | 1312312,
77 | "asd",
78 | 1231.22232
79 | ];
80 | const gappy_keys = [
81 | "ASDSA",
82 | 1312312,
83 | "asd",
84 | null,
85 | 908098,
86 | null,
87 | "1232",
88 | 'safsda'
89 | ];
90 |
91 | T.defCollection(`KeyList`, {container: T`Iterable`, member: T`Key`});
92 | T.defCollection(`OptionalKeyList`, {container: T`Iterable`, member: T`?Key`});
93 |
94 | const result7 = T.validate(T`KeyList`, keys);
95 | console.log({result7});
96 | console.assert(result7.valid);
97 | const result8 = T.validate(T`KeyList`, not_keys);
98 | console.log({result8});
99 | console.assert(!result8.valid);
100 | const result9 = T.validate(T`OptionalKeyList`, gappy_keys);
101 | console.log({result9});
102 | console.assert(result9.valid);
103 |
104 |
105 | T.def(`StrictContact`, {
106 | name: T`String`,
107 | mobile: T`Number`,
108 | email: T`String`
109 | }, {sealed:true});
110 |
111 | const result10 = T.validate(T`StrictContact`, {name:'Cris', mobile:999, email:'777@gmail.com'});
112 | const result11 = T.validate(T`StrictContact`, {name:'Cris', mobile:999, email:'777@gmail.com', new:true});
113 |
114 | console.log({result10});
115 | console.assert(result10.valid);
116 | console.log({result11});
117 | console.assert(!result11.valid);
118 |
119 | const result12 = T.partialMatch(T`StrictContact`, {name:'Mobile'});
120 | console.log({result12});
121 | console.assert(result12.valid);
122 |
123 | const result13 = T.partialMatch(T`StrictContact`, {name:'Mobile', blockhead:133133});
124 | console.log({result13});
125 | console.assert(!result13.valid);
126 |
127 | T.def('Err', {
128 | error: T`String`,
129 | status: T.defOr('MaybeInteger', T`Integer`, T`None`),
130 | });
131 |
132 | const result14 = T.validate(T`Err`, {error:'No such page'});
133 | console.log({result14});
134 | console.assert(result14.valid);
135 |
136 | T.def('Session', {
137 | id: T`String`
138 | });
139 |
140 | T.def('WrappedSession', {
141 | session: T`Session`
142 | });
143 |
144 | const result15 = T.validate(T`WrappedSession`, { session: {id : 'OK' }});
145 | console.log({result15});
146 | console.assert(result15.valid);
147 |
148 | T.defEnum('Fruit', 'Apple', 'Pear', 'Pineapple', 'Melon');
149 | const result16 = T.validate(T`Fruit`, 'Melon');
150 | const result17 = T.validate(T`Fruit`, 'Rock');
151 | console.log({result16,result17});
152 | console.assert(result16.valid);
153 | console.assert(!result17.valid);
154 |
155 |
--------------------------------------------------------------------------------