├── .eslintrc
├── .gitignore
├── .travis.yml
├── LICENSE
├── Makefile
├── README.md
├── bower.json
├── dist
├── typify.min.js
├── typify.min.js.map
└── typify.standalone.js
├── lib
├── aparser.js
├── builtin.js
├── checkableCompiler.js
├── checkableConstructors.js
├── checkableParser.js
├── functionParser.js
├── predicates.js
├── show.js
├── typify.js
└── utils.js
├── package.json
├── prepublish.sh
├── test
├── assert.js
├── builtin.js
├── errors.js
├── map.js
├── number.js
├── record.js
├── show.js
├── typify.js
└── version.js
└── verify-branch.sh
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | env: { node: true },
3 | rules: {
4 | // Generated using magic regex:
5 | // from: ^([a-z-]+) - (.*)$
6 | // to: // \2: http://eslint.org/docs/rules/\1\n \1: 2,\n
7 | //
8 | // Use http://oleg.fi/relaxed-json/ to convert to plain json
9 |
10 | // Possible Errors
11 | // disallow or enforce trailing commas (recommended): http://eslint.org/docs/rules/comma-dangle
12 | comma-dangle: [2, "always-multiline"],
13 |
14 | // disallow assignment in conditional expressions (recommended): http://eslint.org/docs/rules/no-cond-assign
15 | no-cond-assign: 2,
16 |
17 | // disallow use of console in the node environment (recommended): http://eslint.org/docs/rules/no-console
18 | no-console: 0, // TODO: Maybe one should annotate console.logs
19 |
20 | // disallow use of constant expressions in conditions (recommended): http://eslint.org/docs/rules/no-constant-condition
21 | no-constant-condition: 0,
22 |
23 | // disallow control characters in regular expressions (recommended): http://eslint.org/docs/rules/no-control-regex
24 | no-control-regex: 2,
25 |
26 | // disallow use of debugger (recommended): http://eslint.org/docs/rules/no-debugger
27 | no-debugger: 2,
28 |
29 | // disallow duplicate arguments in functions (recommended): http://eslint.org/docs/rules/no-dupe-args
30 | no-dupe-args: 2,
31 |
32 | // disallow duplicate keys when creating object literals (recommended): http://eslint.org/docs/rules/no-dupe-keys
33 | no-dupe-keys: 2,
34 |
35 | // disallow a duplicate case label. (recommended): http://eslint.org/docs/rules/no-duplicate-case
36 | no-duplicate-case: 2,
37 |
38 | // disallow the use of empty character classes in regular expressions (recommended): http://eslint.org/docs/rules/no-empty-character-class
39 | no-empty-character-class: 2,
40 |
41 | // disallow empty statements (recommended): http://eslint.org/docs/rules/no-empty
42 | no-empty: 2,
43 |
44 | // disallow assigning to the exception in a catch block (recommended): http://eslint.org/docs/rules/no-ex-assign
45 | no-ex-assign: 2,
46 |
47 | // disallow double-negation boolean casts in a boolean context (recommended): http://eslint.org/docs/rules/no-extra-boolean-cast
48 | no-extra-boolean-cast: 2,
49 |
50 | // disallow unnecessary parentheses: http://eslint.org/docs/rules/no-extra-parens
51 | no-extra-parens: 0,
52 |
53 | // disallow unnecessary semicolons (recommended): http://eslint.org/docs/rules/no-extra-semi
54 | no-extra-semi: 2,
55 |
56 | // disallow overwriting functions written as function declarations (recommended): http://eslint.org/docs/rules/no-func-assign
57 | no-func-assign: 2,
58 |
59 | // disallow function or variable declarations in nested blocks (recommended): http://eslint.org/docs/rules/no-inner-declarations
60 | no-inner-declarations: 2,
61 |
62 | // disallow invalid regular expression strings in the RegExp constructor (recommended): http://eslint.org/docs/rules/no-invalid-regexp
63 | no-invalid-regexp: 2,
64 |
65 | // disallow irregular whitespace outside of strings and comments (recommended): http://eslint.org/docs/rules/no-irregular-whitespace
66 | no-irregular-whitespace: 2,
67 |
68 | // disallow negation of the left operand of an in expression (recommended): http://eslint.org/docs/rules/no-negated-in-lhs
69 | no-negated-in-lhs: 2,
70 |
71 | // disallow the use of object properties of the global object (Math and JSON) as functions (recommended): http://eslint.org/docs/rules/no-obj-calls
72 | no-obj-calls: 2,
73 |
74 | // disallow multiple spaces in a regular expression literal (recommended): http://eslint.org/docs/rules/no-regex-spaces
75 | no-regex-spaces: 2,
76 |
77 | // disallow sparse arrays (recommended): http://eslint.org/docs/rules/no-sparse-arrays
78 | no-sparse-arrays: 2,
79 |
80 | // disallow unreachable statements after a return, throw, continue, or break statement (recommended): http://eslint.org/docs/rules/no-unreachable
81 | no-unreachable: 2,
82 |
83 | // disallow comparisons with the value NaN (recommended): http://eslint.org/docs/rules/use-isnan
84 | use-isnan: 2,
85 |
86 | // Ensure JSDoc comments are valid: http://eslint.org/docs/rules/valid-jsdoc
87 | valid-jsdoc: 0,
88 |
89 | // Ensure that the results of typeof are compared against a valid string (recommended): http://eslint.org/docs/rules/valid-typeof
90 | valid-typeof: 2,
91 |
92 | // Avoid code that looks like two expressions but is actually one: http://eslint.org/docs/rules/no-unexpected-multiline
93 | no-unexpected-multiline: 2,
94 |
95 |
96 | // Best Practices
97 |
98 | // Enforces getter/setter pairs in objects: http://eslint.org/docs/rules/accessor-pairs
99 | accessor-pairs: 2,
100 |
101 | // treat var statements as if they were block scoped: http://eslint.org/docs/rules/block-scoped-var
102 | block-scoped-var: 2,
103 |
104 | // specify the maximum cyclomatic complexity allowed in a program: http://eslint.org/docs/rules/complexity
105 | complexity: 2,
106 |
107 | // require return statements to either always or never specify values: http://eslint.org/docs/rules/consistent-return
108 | consistent-return: 0,
109 |
110 | // specify curly brace conventions for all control statements: http://eslint.org/docs/rules/curly
111 | curly: 2,
112 |
113 | // require default case in switch statements: http://eslint.org/docs/rules/default-case
114 | default-case: 0,
115 |
116 | // encourages use of dot notation whenever possible: http://eslint.org/docs/rules/dot-notation
117 | dot-notation: 2,
118 |
119 | // enforces consistent newlines before or after dots: http://eslint.org/docs/rules/dot-location
120 | dot-location: [2, "property"],
121 |
122 | // require the use of === and !==: http://eslint.org/docs/rules/eqeqeq
123 | eqeqeq: 2,
124 |
125 | // make sure for-in loops have an if statement: http://eslint.org/docs/rules/guard-for-in
126 | guard-for-in: 0,
127 |
128 | // disallow the use of alert, confirm, and prompt: http://eslint.org/docs/rules/no-alert
129 | no-alert: 2,
130 |
131 | // disallow use of arguments.caller or arguments.callee: http://eslint.org/docs/rules/no-caller
132 | no-caller: 2,
133 |
134 | // disallow division operators explicitly at beginning of regular expression: http://eslint.org/docs/rules/no-div-regex
135 | no-div-regex: 2,
136 |
137 | // disallow else after a return in an if: http://eslint.org/docs/rules/no-else-return
138 | no-else-return: 0,
139 |
140 | // disallow comparisons to null without a type-checking operator: http://eslint.org/docs/rules/no-eq-null
141 | no-eq-null: 2,
142 |
143 | // disallow use of eval(): http://eslint.org/docs/rules/no-eval
144 | no-eval: 2,
145 |
146 | // disallow adding to native types: http://eslint.org/docs/rules/no-extend-native
147 | no-extend-native: 2,
148 |
149 | // disallow unnecessary function binding: http://eslint.org/docs/rules/no-extra-bind
150 | no-extra-bind: 2,
151 |
152 | // disallow fallthrough of case statements (recommended): http://eslint.org/docs/rules/no-fallthrough
153 | no-fallthrough: 2,
154 |
155 | // disallow the use of leading or trailing decimal points in numeric literals: http://eslint.org/docs/rules/no-floating-decimal
156 | no-floating-decimal: 2,
157 |
158 | // disallow the type conversions with shorter notations: http://eslint.org/docs/rules/no-implicit-coercion
159 | no-implicit-coercion: 0,
160 |
161 | // disallow use of eval()-like methods: http://eslint.org/docs/rules/no-implied-eval
162 | no-implied-eval: 2,
163 |
164 | // disallow this keywords outside of classes or class-like objects: http://eslint.org/docs/rules/no-invalid-this
165 | no-invalid-this: 0,
166 |
167 | // disallow usage of __iterator__ property: http://eslint.org/docs/rules/no-iterator
168 | no-iterator: 2,
169 |
170 | // disallow use of labeled statements: http://eslint.org/docs/rules/no-labels
171 | no-labels: 2,
172 |
173 | // disallow unnecessary nested blocks: http://eslint.org/docs/rules/no-lone-blocks
174 | no-lone-blocks: 2,
175 |
176 | // disallow creation of functions within loops: http://eslint.org/docs/rules/no-loop-func
177 | no-loop-func: 2,
178 |
179 | // disallow use of multiple spaces: http://eslint.org/docs/rules/no-multi-spaces
180 | no-multi-spaces: 2,
181 |
182 | // disallow use of multiline strings: http://eslint.org/docs/rules/no-multi-str
183 | no-multi-str: 2,
184 |
185 | // disallow reassignments of native objects: http://eslint.org/docs/rules/no-native-reassign
186 | no-native-reassign: 2,
187 |
188 | // disallow use of new operator for Function object: http://eslint.org/docs/rules/no-new-func
189 | no-new-func: 2,
190 |
191 | // disallows creating new instances of String,Number, and Boolean: http://eslint.org/docs/rules/no-new-wrappers
192 | no-new-wrappers: 2,
193 |
194 | // disallow use of the new operator when not part of an assignment or comparison: http://eslint.org/docs/rules/no-new
195 | no-new: 2,
196 |
197 | // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251";: http://eslint.org/docs/rules/no-octal-escape
198 | no-octal-escape: 2,
199 |
200 | // disallow use of octal literals (recommended): http://eslint.org/docs/rules/no-octal
201 | no-octal: 2,
202 |
203 | // disallow reassignment of function parameters: http://eslint.org/docs/rules/no-param-reassign
204 | no-param-reassign: 0, // TODO: consider
205 |
206 | // disallow use of process.env: http://eslint.org/docs/rules/no-process-env
207 | no-process-env: 2,
208 |
209 | // disallow usage of __proto__ property: http://eslint.org/docs/rules/no-proto
210 | no-proto: 2,
211 |
212 | // disallow declaring the same variable more than once (recommended): http://eslint.org/docs/rules/no-redeclare
213 | no-redeclare: 2,
214 |
215 | // disallow use of assignment in return statement: http://eslint.org/docs/rules/no-return-assign
216 | no-return-assign: 2,
217 |
218 | // disallow use of javascript: urls.: http://eslint.org/docs/rules/no-script-url
219 | no-script-url: 2,
220 |
221 | // disallow comparisons where both sides are exactly the same: http://eslint.org/docs/rules/no-self-compare
222 | no-self-compare: 0, // TODO: consider, we have quite a much reflexivity tests
223 |
224 | // disallow use of the comma operator: http://eslint.org/docs/rules/no-sequences
225 | no-sequences: 2,
226 |
227 | // restrict what can be thrown as an exception: http://eslint.org/docs/rules/no-throw-literal
228 | no-throw-literal: 0,
229 |
230 | // disallow usage of expressions in statement position: http://eslint.org/docs/rules/no-unused-expressions
231 | no-unused-expressions: 2,
232 |
233 | // disallow unnecessary .call() and .apply(): http://eslint.org/docs/rules/no-useless-call
234 | no-useless-call: 2,
235 |
236 | // disallow use of the void operator: http://eslint.org/docs/rules/no-void
237 | no-void: 2,
238 |
239 | // disallow usage of configurable warning terms in comments - e.g. TODO or FIXME: http://eslint.org/docs/rules/no-warning-comments
240 | no-warning-comments: 0,
241 |
242 | // disallow use of the with statement: http://eslint.org/docs/rules/no-with
243 | no-with: 2,
244 |
245 | // require use of the second argument for parseInt(): http://eslint.org/docs/rules/radix
246 | radix: 2,
247 |
248 | // require declaration of all vars at the top of their containing scope: http://eslint.org/docs/rules/vars-on-top
249 | vars-on-top: 0,
250 |
251 | // require immediate function invocation to be wrapped in parentheses: http://eslint.org/docs/rules/wrap-iife
252 | wrap-iife: 2,
253 |
254 | // require or disallow Yoda conditions: http://eslint.org/docs/rules/yoda
255 | yoda: 2,
256 |
257 |
258 |
259 |
260 | // Strict Mode
261 | // controls location of Use Strict Directives: http://eslint.org/docs/rules/strict
262 | strict: [2, global],
263 |
264 |
265 | // Variables
266 | // enforce or disallow variable initializations at definition: http://eslint.org/docs/rules/init-declarations
267 | init-declarations: 0, // TODO: annotate?
268 |
269 | // disallow the catch clause parameter name being the same as a variable in the outer scope: http://eslint.org/docs/rules/no-catch-shadow
270 | no-catch-shadow: 2,
271 |
272 | // disallow deletion of variables (recommended): http://eslint.org/docs/rules/no-delete-var
273 | no-delete-var: 2,
274 |
275 | // disallow labels that share a name with a variable: http://eslint.org/docs/rules/no-label-var
276 | no-label-var: 2,
277 |
278 | // disallow shadowing of names such as arguments: http://eslint.org/docs/rules/no-shadow-restricted-names
279 | no-shadow-restricted-names: 2,
280 |
281 | // disallow declaration of variables already declared in the outer scope: http://eslint.org/docs/rules/no-shadow
282 | no-shadow: 2,
283 |
284 | // disallow use of undefined when initializing variables: http://eslint.org/docs/rules/no-undef-init
285 | no-undef-init: 2,
286 |
287 | // disallow use of undeclared variables unless mentioned in a /*global */ block (recommended): http://eslint.org/docs/rules/no-undef
288 | no-undef: 2,
289 |
290 | // disallow use of undefined variable: http://eslint.org/docs/rules/no-undefined
291 | no-undefined: 0,
292 |
293 | // disallow declaration of variables that are not used in the code (recommended): http://eslint.org/docs/rules/no-unused-vars
294 | no-unused-vars: 0,
295 |
296 | // disallow use of variables before they are defined: http://eslint.org/docs/rules/no-use-before-define
297 | no-use-before-define: 0,
298 |
299 | // Node.js
300 | // enforce return after a callback: http://eslint.org/docs/rules/callback-return
301 | callback-return: 2,
302 |
303 | // enforce error handling in callbacks: http://eslint.org/docs/rules/handle-callback-err
304 | handle-callback-err: 2,
305 |
306 | // disallow mixing regular variable and require declarations: http://eslint.org/docs/rules/no-mixed-requires
307 | no-mixed-requires: 2,
308 |
309 | // disallow use of new operator with the require function: http://eslint.org/docs/rules/no-new-require
310 | no-new-require: 2,
311 |
312 | // disallow string concatenation with __dirname and __filename: http://eslint.org/docs/rules/no-path-concat
313 | no-path-concat: 2,
314 |
315 | // disallow process.exit(): http://eslint.org/docs/rules/no-process-exit
316 | no-process-exit: 2,
317 |
318 | // restrict usage of specified node modules: http://eslint.org/docs/rules/no-restricted-modules
319 | no-restricted-modules: 2,
320 |
321 | // disallow use of synchronous methods: http://eslint.org/docs/rules/no-sync
322 | no-sync: 2,
323 |
324 |
325 | // Stylistic issues
326 | // enforce spacing inside array brackets: http://eslint.org/docs/rules/array-bracket-spacing
327 | array-bracket-spacing: 2,
328 |
329 | // disallow or enforce spaces inside of single line blocks: http://eslint.org/docs/rules/block-spacing
330 | block-spacing: 2,
331 |
332 | // enforce one true brace style: http://eslint.org/docs/rules/brace-style
333 | brace-style: [2, "1tbs", { "allowSingleLine": true }],
334 |
335 | // require camel case names: http://eslint.org/docs/rules/camelcase
336 | camelcase: 2,
337 |
338 | // enforce spacing before and after comma: http://eslint.org/docs/rules/comma-spacing
339 | comma-spacing: 2,
340 |
341 | // enforce one true comma style: http://eslint.org/docs/rules/comma-style
342 | comma-style: 2,
343 |
344 | // require or disallow padding inside computed properties: http://eslint.org/docs/rules/computed-property-spacing
345 | computed-property-spacing: 2,
346 |
347 | // enforce consistent naming when capturing the current execution context: http://eslint.org/docs/rules/consistent-this
348 | consistent-this: 0,
349 |
350 | // enforce newline at the end of file, with no multiple empty lines: http://eslint.org/docs/rules/eol-last
351 | eol-last: 2,
352 |
353 | // require function expressions to have a name: http://eslint.org/docs/rules/func-names
354 | func-names: 0,
355 |
356 | // enforce use of function declarations or expressions: http://eslint.org/docs/rules/func-style
357 | func-style: 0,
358 |
359 | // this option enforces minimum and maximum identifier lengths (variable names, property names etc.): http://eslint.org/docs/rules/id-length
360 | id-length: 0,
361 |
362 | // require identifiers to match the provided regular expression: http://eslint.org/docs/rules/id-match
363 | id-match: 2,
364 |
365 | // specify tab or space width for your code: http://eslint.org/docs/rules/indent
366 | indent: [2, 2, { SwitchCase: 1 }],
367 |
368 | // enforce spacing between keys and values in object literal properties: http://eslint.org/docs/rules/key-spacing
369 | key-spacing: 2,
370 |
371 | // enforce empty lines around comments: http://eslint.org/docs/rules/lines-around-comment
372 | lines-around-comment: 0,
373 |
374 | // disallow mixed 'LF' and 'CRLF' as linebreaks: http://eslint.org/docs/rules/linebreak-style
375 | linebreak-style: 2,
376 |
377 | // specify the maximum depth callbacks can be nested: http://eslint.org/docs/rules/max-nested-callbacks
378 | max-nested-callbacks: 2,
379 |
380 | // require a capital letter for constructors: http://eslint.org/docs/rules/new-cap
381 | new-cap: 2,
382 |
383 | // disallow the omission of parentheses when invoking a constructor with no arguments: http://eslint.org/docs/rules/new-parens
384 | new-parens: 2,
385 |
386 | // require or disallow an empty newline after variable declarations: http://eslint.org/docs/rules/newline-after-var
387 | newline-after-var: 0,
388 |
389 | // disallow use of the Array constructor: http://eslint.org/docs/rules/no-array-constructor
390 | no-array-constructor: 2,
391 |
392 | // disallow use of the continue statement: http://eslint.org/docs/rules/no-continue
393 | no-continue: 0,
394 |
395 | // disallow comments inline after code: http://eslint.org/docs/rules/no-inline-comments
396 | no-inline-comments: 0,
397 |
398 | // disallow if as the only statement in an else block: http://eslint.org/docs/rules/no-lonely-if
399 | no-lonely-if: 2,
400 |
401 | // disallow mixed spaces and tabs for indentation (recommended): http://eslint.org/docs/rules/no-mixed-spaces-and-tabs
402 | no-mixed-spaces-and-tabs: 2,
403 |
404 | // disallow multiple empty lines: http://eslint.org/docs/rules/no-multiple-empty-lines
405 | no-multiple-empty-lines: 2,
406 |
407 | // disallow nested ternary expressions: http://eslint.org/docs/rules/no-nested-ternary
408 | no-nested-ternary: 2,
409 |
410 | // disallow the use of the Object constructor: http://eslint.org/docs/rules/no-new-object
411 | no-new-object: 2,
412 |
413 | // disallow space between function identifier and application: http://eslint.org/docs/rules/no-spaced-func
414 | no-spaced-func: 2,
415 |
416 | // disallow the use of ternary operators: http://eslint.org/docs/rules/no-ternary
417 | no-ternary: 0,
418 |
419 | // disallow trailing whitespace at the end of lines: http://eslint.org/docs/rules/no-trailing-spaces
420 | no-trailing-spaces: 2,
421 |
422 | // disallow dangling underscores in identifiers: http://eslint.org/docs/rules/no-underscore-dangle
423 | no-underscore-dangle: 2,
424 |
425 | // disallow the use of Boolean literals in conditional expressions: http://eslint.org/docs/rules/no-unneeded-ternary
426 | no-unneeded-ternary: 2,
427 |
428 | // require or disallow padding inside curly braces: http://eslint.org/docs/rules/object-curly-spacing
429 | object-curly-spacing: [2, "always"],
430 |
431 | // require or disallow one variable declaration per function: http://eslint.org/docs/rules/one-var
432 | one-var: [2, never],
433 |
434 | // require assignment operator shorthand where possible or prohibit it entirely: http://eslint.org/docs/rules/operator-assignment
435 | operator-assignment: 2,
436 |
437 | // enforce operators to be placed before or after line breaks: http://eslint.org/docs/rules/operator-linebreak
438 | operator-linebreak: 2,
439 |
440 | // enforce padding within blocks: http://eslint.org/docs/rules/padded-blocks
441 | padded-blocks: 0,
442 |
443 | // require quotes around object literal property names: http://eslint.org/docs/rules/quote-props
444 | quote-props: 0,
445 |
446 | // specify whether backticks, double or single quotes should be used: http://eslint.org/docs/rules/quotes
447 | quotes: 2,
448 |
449 | // enforce spacing before and after semicolons: http://eslint.org/docs/rules/semi-spacing
450 | semi-spacing: 2,
451 |
452 | // require or disallow use of semicolons instead of ASI: http://eslint.org/docs/rules/semi
453 | semi: 2,
454 |
455 | // sort variables within the same declaration block: http://eslint.org/docs/rules/sort-vars
456 | sort-vars: 2,
457 |
458 | keyword-spacing: 2,
459 |
460 | // require or disallow a space before blocks: http://eslint.org/docs/rules/space-before-blocks
461 | space-before-blocks: 2,
462 |
463 | // require or disallow a space before function opening parenthesis: http://eslint.org/docs/rules/space-before-function-paren
464 | space-before-function-paren: [2, {"anonymous": "always", "named": "never"}],
465 |
466 | // require or disallow spaces inside parentheses: http://eslint.org/docs/rules/space-in-parens
467 | space-in-parens: 2,
468 |
469 | // require spaces around operators: http://eslint.org/docs/rules/space-infix-ops
470 | space-infix-ops: 2,
471 |
472 | // require or disallow spaces before/after unary operators: http://eslint.org/docs/rules/space-unary-ops
473 | space-unary-ops: 2,
474 |
475 | // require or disallow a space immediately following the // or /* in a comment: http://eslint.org/docs/rules/spaced-comment
476 | spaced-comment: [2, always, { markers: ["/"] }],
477 |
478 | // require regex literals to be wrapped in parentheses: http://eslint.org/docs/rules/wrap-regex
479 | wrap-regex: 2,
480 |
481 |
482 | // ECMAScript 6
483 | // require parens in arrow function arguments: http://eslint.org/docs/rules/arrow-parens
484 | arrow-parens: 2,
485 |
486 | // require space before/after arrow function's arrow: http://eslint.org/docs/rules/arrow-spacing
487 | arrow-spacing: 2,
488 |
489 | // verify calls of super() in constructors: http://eslint.org/docs/rules/constructor-super
490 | constructor-super: 2,
491 |
492 | // enforce spacing around the * in generator functions: http://eslint.org/docs/rules/generator-star-spacing
493 | generator-star-spacing: 2,
494 |
495 | // disallow modifying variables of class declarations: http://eslint.org/docs/rules/no-class-assign
496 | no-class-assign: 2,
497 |
498 | // disallow modifying variables that are declared using const: http://eslint.org/docs/rules/no-const-assign
499 | no-const-assign: 2,
500 |
501 | // disallow duplicate name in class members: http://eslint.org/docs/rules/no-dupe-class-members
502 | no-dupe-class-members: 2,
503 |
504 | // disallow use of this/super before calling super() in constructors.: http://eslint.org/docs/rules/no-this-before-super
505 | no-this-before-super: 2,
506 |
507 | // require let or const instead of var: http://eslint.org/docs/rules/no-var
508 | no-var: 0,
509 |
510 | // require method and property shorthand syntax for object literals: http://eslint.org/docs/rules/object-shorthand
511 | object-shorthand: [2, "never"],
512 |
513 | // suggest using arrow functions as callbacks: http://eslint.org/docs/rules/prefer-arrow-callback
514 | prefer-arrow-callback: 0,
515 |
516 | // suggest using const declaration for variables that are never modified after declared: http://eslint.org/docs/rules/prefer-const
517 | prefer-const: 0,
518 |
519 | // suggest using the spread operator instead of .apply().: http://eslint.org/docs/rules/prefer-spread
520 | prefer-spread: 0,
521 |
522 | // suggest using Reflect methods where applicable: http://eslint.org/docs/rules/prefer-reflect
523 | prefer-reflect: 0,
524 |
525 | // suggest using template literals instead of strings concatenation: http://eslint.org/docs/rules/prefer-template
526 | prefer-template: 0,
527 |
528 | // disallow generator functions that do not have yield: http://eslint.org/docs/rules/require-yield
529 | require-yield: 2,
530 | }}
531 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | coverage/
3 | .nyc_output/
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 |
4 | node_js:
5 | - "11"
6 | - "10"
7 | - "8"
8 | - "8.10" # bionic
9 |
10 | # Timeouts?
11 | # - "6"
12 |
13 | # eslint doesn't support node 4 anymore?
14 | # - "4"
15 | # - "4.2" # xenial
16 |
17 | branches:
18 | only:
19 | - master
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright Oleg Grenrus 2013
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 |
16 | * Neither the name of Oleg Grenrus nor the names of other
17 | contributors may be used to endorse or promote products derived
18 | from this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | all : test
2 |
3 | SRC=lib/*.js
4 | TESTSRC=test
5 |
6 | DISTDIR=dist
7 | DISTPREFIX=typify
8 |
9 | BUNDLESRC=lib/typify.js
10 | BUNDLEDST=$(DISTDIR)/$(DISTPREFIX).standalone.js
11 | BUNDLEVAR=jsc
12 |
13 | MINSRC=$(BUNDLEDST)
14 | MINDST=$(DISTDIR)/$(DISTPREFIX).min.js
15 | MINMAP=$(DISTDIR)/$(DISTPREFIX).min.js.map
16 |
17 | .PHONY : all test eslint mocha istanbul browserify typify dist david
18 |
19 | BINDIR=node_modules/.bin
20 |
21 | MOCHA=$(BINDIR)/_mocha
22 | ESLINT=$(BINDIR)/eslint
23 | NYC=$(BINDIR)/nyc
24 | BROWSERIFY=$(BINDIR)/browserify
25 | UGLIFY=$(BINDIR)/uglifyjs
26 | TYPIFY=$(BINDIR)/typify
27 | DAVID=$(BINDIR)/david
28 |
29 | test : eslint mocha istanbul typify david
30 |
31 | eslint :
32 | $(ESLINT) $(SRC)
33 |
34 | mocha :
35 | $(MOCHA) --reporter=spec $(TESTSRC)
36 |
37 | istanbul :
38 | $(NYC) -r text -r html $(MOCHA) test
39 | $(NYC) check-coverage -statements -11 --branches -5 --functions -6
40 |
41 | browserify : $(SRC)
42 | mkdir -p $(DISTDIR)
43 | $(BROWSERIFY) -s $(BUNDLEVAR) -o $(BUNDLEDST) $(BUNDLESRC)
44 |
45 | uglify : browserify $(SRC)
46 | mkdir -p $(DISTDIR)
47 | $(UGLIFY) -o $(MINDST) --source-map $(MINMAP) $(MINSRC)
48 |
49 | typify :
50 | $(TYPIFY) -- $(MOCHA) --timeout 20000 $(TESTSRC)
51 |
52 | david :
53 | $(DAVID)
54 |
55 | dist : test uglify
56 | git clean -fdx -e node_modules
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # typify
2 |
3 | > Runtime type-checking.
4 |
5 | [](http://travis-ci.org/phadej/typify)
6 | [](http://badge.fury.io/js/typify)
7 | [](https://gemnasium.com/phadej/typify)
8 | [](https://codeclimate.com/github/phadej/typify)
9 |
10 | ## Getting Started
11 |
12 | Install the module with: `npm install typify`
13 |
14 | ## Synopsis
15 |
16 | ```javascript
17 | // Browser
18 | //
19 |
20 | // Node
21 | var typify = require("typify");
22 |
23 | /*
24 | * `sum` function takes either two numbers or two strings as a parameter,
25 | * and returns a number or a string respectively.
26 | */
27 | var sum = typify("sum :: a : number|string => a -> a -> a", function (a, b) {
28 | return a + b;
29 | });
30 |
31 | /*
32 | * `toArray` function takes either an array of numbers or a single number,
33 | * and returns an array of numbers.
34 | *
35 | * We could write a more general, polymorphic function with type signature
36 | * `toArray :: a : *, (array a)|a -> array a`, where `*` means _any type_.
37 | *
38 | * Unfortunately any type `*` is seriously any.
39 | * Types as *typify* understands them, are more like Java's interfaces or Haskell's typeclasses.
40 | * Of course, we can iterate through them all, but we cannot deduce the most principal type (because it doesn't exist).
41 | * So eg. function signature `id :: a : *, a -> a` behaves similarly to `id :: * -> *`, which isn't strict enough.
42 | */
43 | var toNumberArray = typify("toNumberArray :: (array number)|number -> array number", function (a) {
44 | return Array.isArray(a) ? a : [a];
45 | });
46 |
47 | /*
48 | * `myParseInt` takes a string and an optional number (radix) and returns a number.
49 | */
50 | var myParseInt = typify("myParseInt :: string -> number? -> number", function (n, radix) {
51 | return parseInt(n, radix || 10)
52 | });
53 |
54 | /*
55 | * `foo` takes at least one number parameter and returns a number.
56 | */
57 | var foo = typify("foo :: number -> number.. -> number", function (a) {
58 | return a + arguments.length;
59 | });
60 | ```
61 |
62 | ## Documentation
63 |
64 | ### API
65 |
66 | - `typify(functionSpec, fun)` - decorate function with run-time type check
67 | - `typify.create()` - create new typify environment
68 | - `typify.type(typename, checkFun)` - add new type with user-supplied existence check
69 | - `typify.record(typename, recordspec)` - add new record type
70 | - `typify.alias(typename, typespec)` - give name to the compound type
71 | - `typify.mutual(typespecs)` - define multiple (possibly mutually recursive) types at once
72 | - `typify.instance(name, cls)` - add new instance type
73 | - `typify.check(typename, value) -> bool` - check membership of value in the type. `check` is [autoCurried](http://fitzgen.github.io/wu.js/#wu-autocurry)
74 |
75 | ### Checkable type
76 |
77 | *Checkable* means, that given an object you can check whether an object is or isn't of the particular type.
78 | For example `number` is checkable type, given any object you can tell if it's a number.
79 |
80 | ```javascript
81 | typify.check('number', 1); // => true
82 | typify.check('number', 'foobar'); // => false
83 | ```
84 |
85 | You could use `typify.assert` for type assertions:
86 |
87 | ```javascript
88 | typify.check('number', 'foo'); // will throw `TypeError` exception
89 | ```
90 |
91 |
92 | There are few predefined checkable types:
93 |
94 | - `number`
95 | - `integer`
96 | - `nat`: non-negative integer
97 | - `positive` _x_
98 | - `nonnegative` _x_
99 | - `finite` _x_
100 | - `string`
101 | - `boolean`
102 | - `date`
103 | - `regexp`
104 | - `function`, `fn`
105 | - `array` _a_
106 | - `map` _a_
107 | - `tuple` _a_ _b_...
108 | - `null`, `undefined`, `infinity`, `ninfinity`, `nan`, `true` and `false`
109 |
110 | #### Formal syntax of checkable type declaration:
111 |
112 | - *checkable type* σ ::= σ_or
113 | - σ_or ::= σ_and (`|` σ_and)*
114 | - σ_and ::= σ_poly (`&` σ_poly)*
115 | - σ_poly ::= *typename* σ_opt+ | σ_opt
116 | - σ_opt = σ_term | σ_term `?`
117 | - σ_record ::= `{` `}` | `{` σ_pair (`,` σ_pair)* `}`
118 | - σ_pair ::= *identifier* `:` σ_term
119 | - σ_term ::= `*` | α | *literal* | *typename* | `(` σ_alt `)`
120 | - *type variable* α ::= *identifier*
121 | - *literal* ::= /\d+/ | /"[^"]*"/ | /'[^']*'/ | true | false | null | undefined | nan | infinity | ninfinity
122 | - *identifier*, *typename* ::= /[a-zA-Z_][a-zA-Z0-9_]*/
123 |
124 | ### Function type
125 |
126 | Function types are difficult to check. Given a function object, only you can tell, it's a function object.
127 | To be more precise, you can decorate your function with *function type* signature to verify parameters' and result's types, but the check will occur only when function is executed ie. run-time.
128 |
129 | ```javascript
130 | var add = typify("add :: number -> number -> number", function (a, b) {
131 | return a + b;
132 | });
133 |
134 | console.log(add(1, 2)); // ok
135 | console.log(add("foo", "bar")); // throws TypeError
136 | ```
137 |
138 | #### Formal syntax of function type declaration:
139 |
140 | - *function type* λ ::= ν μ | ν Γ (σ `->`)* ρ σ
141 | - *action* μ ::= `->` τ
142 | - *context* Γ ::= α `:` Σ (`,` α `:` Σ)* `=>` | ε
143 | - *typeset* Σ ::= σ_poly (`|` σ_poly)*
144 | - *rest parameters* ρ ::= σ `...` `->` | `...` `->` | ε
145 | - *function name* ν ::= *identifier* `::` | ε
146 |
147 | ### New types
148 |
149 | New types can be added with `typify.type` method:
150 |
151 | ```javascript
152 | typify.type("char", function(n) {
153 | return typeof n === "string" && n.length === 1;
154 | });
155 | ```
156 |
157 | *Note:* opaque type checks should return `true`,
158 | other *truthy* values will be considered errorneous in later versions.
159 |
160 | You can give names to (recursive) compound types with `typify.alias`:
161 | ```javascript
162 | typify.alias("numstr", "number|string"); // numbers or strings
163 | typify.alias("rarray", "array rarray"); // arrays of itself, eg [[[[[[]]]]]
164 | ```
165 |
166 | For mutually recursive types use `typify.mutual`:
167 | ```javascript
168 | typify.mutual({
169 | "foo": "list bar",
170 | "bar": "list foo",
171 | });
172 | ```
173 |
174 | Also you can define *record* types with `typify.record`:
175 |
176 | ```javascript
177 | typify.record("person", {
178 | name: "string",
179 | age: "number",
180 | });
181 | ```
182 |
183 | Record types may be recursive:
184 |
185 | ```javascript
186 | typ.record("bst", {
187 | left: "bst?",
188 | right: "bst?",
189 | });
190 | ```
191 |
192 | If you prefer `instanceof`, there is `typify.instance` helper in place:
193 | ```javascript
194 | function Foo() {}
195 | typ.instance("Foo", Foo);
196 | typ.check("Foo", new Foo());
197 | ```
198 |
199 | ### Hygiene usage
200 |
201 | If you don't want to use global type database, you can create your own instance of *typify*:
202 |
203 | ```js
204 | // In browser
205 | var myTypify = typify.create();
206 |
207 | // or alternatively, using "let-binding":
208 | (function (typify) {
209 | // use typify as it would be global
210 | }(typify.create()));
211 |
212 | // In node
213 | var typify = require("typify").create();
214 | ```
215 |
216 | ## Contributing
217 |
218 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using `npm test` command.
219 |
220 | ## Release History
221 |
222 | - 0.2.9 Closed records
223 | - `typify.record(name, def, closed)`
224 | - 0.2.8
225 | - Change `date` and `regexp` checks to work in multiframe environments [#34](https://github.com/phadej/typify/issues/34)
226 | - Fix typo in README.md [#35](https://github.com/phadej/typify/issues/35)
227 | - Update dependencies
228 | - 0.2.7
229 | - Use make
230 | - 0.2.6
231 | - Updated dependencies
232 | - 0.2.5
233 | - `typify.assert`
234 | - Added note about opaque type checks (`typify.type`)
235 | - 0.2.4
236 | - `arguments` built-in type
237 | - `any` built-in type. Like `*` but not optional
238 | - typified most of functions
239 | - 0.2.3
240 | - `fn` shorthand for the function type
241 | - `typify.wrap` to typify modules
242 | - [istanbul](http://gotwarlost.github.io/istanbul/) code covarage as part of the test suite
243 | - `typify.adt` helper for specifying abstract data types -like structures
244 | - `infinity`, `ninfinity` and `nan` literals
245 | - unified implementation of `typify.type`, `typify.alias` and `typify.record`.
246 | - The latter two will be deprecated in 0.3.0 and removed in 0.4.0
247 | - 0.2.2
248 | - mutually recursive types
249 | - instanceof types
250 | - 0.2.1
251 | - anonymous record types
252 | - tuple, numeric types
253 | - mocha test-suite
254 | - major code refactor
255 | - 0.2.0
256 | - Recursive record types
257 | - Recursive aliases
258 | - Intersection types
259 | - Hygiene type environments
260 |
261 | - 0.1.1
262 | - Record type
263 | - Fixed typos in README.md
264 |
265 | - 0.1.0 Initial release
266 |
267 | ## License
268 |
269 | Copyright (c) 2013 Oleg Grenrus. Licensed under the BSD3 license.
270 |
271 | ## Related work
272 |
273 | ### Javascript
274 |
275 | - [rho-contracts](https://github.com/sefaira/rho-contracts.js)
276 | - [ducktype](https://github.com/josdejong/ducktype)
277 | - [type-check](https://github.com/gkz/type-check)
278 |
279 | ### Others
280 |
281 | - [Racket - Contracts for higher-order functions](http://dl.acm.org/citation.cfm?id=581484)
282 | - [Typed Clojure](https://github.com/clojure/core.typed)
283 | - [The Ruby Type Checker](http://www.cs.umd.edu/~jfoster/papers/oops13.pdf)
284 |
285 | ### Gradual typing (of existing languages)
286 |
287 | - [TypeScript](http://www.typescriptlang.org/)
288 | - [hack](http://hacklang.org/)
289 | - [Gradual typing on Wikipedia](http://en.wikipedia.org/wiki/Gradual_typing)
290 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "typify",
3 | "description": "Runtime type-checking for JavaScript.",
4 | "version": "0.2.0",
5 | "homepage": "https://github.com/phadej/typify",
6 | "author": "Oleg Grenrus ",
7 | "repository": {
8 | "type": "git",
9 | "url": "git://github.com/phadej/typify.git"
10 | },
11 | "main": "dist/typify.standalone.js",
12 | "keywords": [
13 | "type",
14 | "checking"
15 | ],
16 | "ignore": [
17 | ".gitignore",
18 | ".jshint.rc",
19 | ".travis.yml",
20 | "node_modules",
21 | "Gruntfile.js",
22 | "package.json",
23 | "spec"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/dist/typify.min.js:
--------------------------------------------------------------------------------
1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jsc=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o=tokens.length){return res[0]}else{return undefined}}function eof(tokens,idx){if(idx=tokens.length){return undefined}if(tokens[idx]===tok){return[tok,idx+1]}else{return undefined}}}function satisfying(predicate){return function(tokens,idx){if(idx>=tokens.length){return undefined}if(predicate(tokens[idx])){return[tokens[idx],idx+1]}else{return undefined}}}function any(){return function(tokens,idx){if(idx0);if(options.length===1){return options[0]}return options.reduce(function(a,b){return{type:type,options:mergeOptions(type,a,b)}})}function user(predicate){return{type:"user",predicate:predicate}}module.exports={any:any,variable:variable,number:number,string:string,opt:opt,poly:poly,record:record,and:andOr.bind(undefined,"and"),alt:andOr.bind(undefined,"alt"),user:user}},{assert:11}],5:[function(require,module,exports){"use strict";var A=require("./aparser.js");var cons=require("./checkableConstructors.js");var identifierRe=/^[a-zA-Z_][a-zA-Z0-9_]*$/;var numberRe=/^[0-9]+$/;var stringRe=/^('[^']*'|"[^"]*")$/;function isIdentifier(token){return identifierRe.test(token)}function isNumber(token){return numberRe.test(token)}function isString(token){return stringRe.test(token)}var altP;function parensP(p){return A.lift(A.token("("),p,A.token(")"),function(a,b,c){return b})}var identifierP=A.satisfying(isIdentifier);var numberP=A.lift(A.satisfying(isNumber),function(x){return cons.number(parseFloat(x))});var stringP=A.lift(A.satisfying(isString),function(x){x=x.substr(1,x.length-2);return cons.string(x)});var literalP=A.or(numberP,stringP);var anyP=A.lift(A.token("*"),function(){return cons.any});var varP=A.lift(identifierP,cons.variable);var emptyRecordP=A.lift(A.token("{"),A.token("}"),function(){return cons.record({})});var pairP=A.lift(identifierP,A.token(":"),A.delay(function(){return altP}),function(k,c,v){return{ident:k,value:v}});var nonEmptyRecordP=A.lift(A.token("{"),A.sepBy(pairP,","),A.token("}"),function(o,ps,c){var obj={};ps.forEach(function(p){obj[p.ident]=p.value});return cons.record(obj)});var recordP=A.or(emptyRecordP,nonEmptyRecordP);var termP=A.or(anyP,literalP,varP,recordP,parensP(A.delay(function(){return altP})));var optP=A.lift(termP,A.optional(A.token("?")),function(term,opt){if(opt==="?"&&term.type!=="opt"&&term.type!=="any"){return cons.opt(term)}else{return term}});var polyP1=A.lift(identifierP,A.some(optP),cons.poly);var polyP=A.or(polyP1,optP);var andP=A.lift(A.sepBy(polyP,"&"),cons.and);altP=A.lift(A.sepBy(andP,"|"),cons.alt);var checkableP=altP;var checkableTypeCheckRe=/^([a-zA-Z_][a-zA-Z0-9_]*|"[^"]*"|'[^']*'|[0-9]+|:|,|\{|\}|\*|\?|\||&|\(|\)|\s+)*$/;var checkableTypeTokenRe=/([a-zA-Z_][a-zA-Z0-9_]*|"[^"]*"|'[^']*'|[0-9]+|:|,|\{|\}|\*|\?|\||&|\(|\))/g;function parseCheckableType(type){if(!checkableTypeCheckRe.test(type)){throw new TypeError("invalid checkable type: "+type)}var tokens=type.match(checkableTypeTokenRe);var parsed=A.parse(checkableP,tokens);if(parsed===undefined){throw new TypeError("invalid checkable type: "+type)}return parsed}module.exports={identifierP:identifierP,checkableP:checkableP,polyP:polyP,parse:parseCheckableType}},{"./aparser.js":1,"./checkableConstructors.js":4}],6:[function(require,module,exports){"use strict";var A=require("./aparser.js");var identifierP=require("./checkableParser").identifierP;var polyP=require("./checkableParser").polyP;var checkableP=require("./checkableParser").checkableP;var nameP=A.optional(A.lift(identifierP,A.token("::"),function(identifier,sep){return identifier}),"");var actionP=A.lift(nameP,A.token("->"),checkableP,function(name,arrow,result){return{name:name,context:{},params:[],rest:undefined,result:result}});var typesetP=A.sepBy(polyP,"|");var contextDefP=A.lift(identifierP,A.token(":"),typesetP,function(name,sep,typeset){return{name:name,typeset:typeset}});var contextP=A.optional(A.lift(A.sepBy(contextDefP,","),A.token("=>"),function(defs,arrow){return defs.reduce(function(context,def){context[def.name]=def.typeset;return context},{})}),{});var paramsP=A.many(A.lift(checkableP,A.token("->"),function(param,arrow){return param}));var restP=A.optional(A.lift(A.optional(checkableP),A.token("..."),A.token("->"),function(type,ellipsis,arrow){return type||{type:"any"}}));var functionTypeP1=A.lift(nameP,contextP,paramsP,restP,checkableP,function(name,context,params,rest,result){return{name:name,context:context,params:params,rest:rest,result:result}});var functionTypeP=A.or(actionP,functionTypeP1);module.exports={functionP:functionTypeP}},{"./aparser.js":1,"./checkableParser":5}],7:[function(require,module,exports){"use strict";var toString=Object.prototype.toString;function isBoolean(val){return typeof val==="boolean"}function isNumber(val){return typeof val==="number"}function isInteger(val){return val===(val|0)}function isPositive(val){return typeof val==="number"&&val>0}function isNonNegative(val){return typeof val==="number"&&val>=0}function isFinite(val){return typeof val==="number"&&val!==Infinity&&val!==-Infinity&&val===+val}function isString(val){return typeof val==="string"}function isFunction(val){return typeof val==="function"}function isDate(val){return toString.call(val)==="[object Date]"}function isRegExp(val){return toString.call(val)==="[object RegExp]"}function isArray(val){return Array.isArray(val)}function isObject(val){return Object(val)===val}function isArguments(val){return val&&isObject(arguments)&&isInteger(val.length)&&Object.prototype.toString.call(val)==="[object Arguments]"||false}function constTrue(){return true}module.exports={isBoolean:isBoolean,isNumber:isNumber,isInteger:isInteger,isPositive:isPositive,isNonNegative:isNonNegative,isFinite:isFinite,isString:isString,isFunction:isFunction,isDate:isDate,isRegExp:isRegExp,isArray:isArray,isObject:isObject,isArguments:isArguments,constTrue:constTrue}},{}],8:[function(require,module,exports){"use strict";var utils=require("./utils.js");function parensS(guard,str){return guard?"("+str+")":str}var showCheckableTypePrecedence;function showLiteral(type){if(typeof type.value==="string"){return"'"+type.value+"'"}else{return""+type.value}}function showRecord(type){var pairs=[];for(var t in type.fields){pairs.push(t+": "+showCheckableTypePrecedence(0,type.fields[t]))}return"{"+pairs.join(", ")+"}"}function showCheckableTypePrecedence(precedence,type){switch(type.type){case"any":return"*";case"literal":return showLiteral(type);case"var":return type.name;case"record":return showRecord(type);case"alt":return parensS(precedence>0,utils.map(type.options,showCheckableTypePrecedence.bind(undefined,0)).join("|"));case"and":return parensS(precedence>1,utils.map(type.options,showCheckableTypePrecedence.bind(undefined,1)).join("&"));case"poly":return parensS(precedence>2,type.name+" "+utils.map(type.args,showCheckableTypePrecedence.bind(undefined,3)).join(" "));case"opt":return parensS(precedence>3,showCheckableTypePrecedence(3,type.term)+"?")}}function showCheckableType(type){return showCheckableTypePrecedence(0,type)}function showContext(context){var res="";for(var name in context){res+=name+" : "+utils.map(context[name],showCheckableTypePrecedence.bind(undefined,1)).join(" | ")}return res}module.exports={checkable:showCheckableType,context:showContext}},{"./utils.js":10}],9:[function(require,module,exports){"use strict";var VERSION=[0,2,9];var utils=require("./utils.js");var p=require("./predicates.js");var A=require("./aparser.js");var c=require("./checkableCompiler.js");var cons=require("./checkableConstructors.js");var show=require("./show.js");var parseCheckableType=require("./checkableParser").parse;var compileCheckableType=c.compile;var compileCheckableTypeRecursive=c.compileRecursive;var functionP=require("./functionParser.js").functionP;function throwAlways(){throw new Error("this shouldn't been called")}var functionTypeCheckRe=/^([a-zA-Z_][a-zA-Z0-9_]*|"[^"]*"|'[^']*'|[0-9]+|\*|\?|\||&|\(|\)|\{|\}|::|:|,|=>|->|\.\.\.|\s+)*$/;var functionTypeTokenRe=/([a-zA-Z_][a-zA-Z0-9_]*|"[^"]*"|'[^']*'|[0-9]+|\*|\?|\||&|\(|\)|\{|\}|::|:|,|=>|->|\.\.\.)/g;function optional(parsed){if(parsed.type==="any"){return true}if(parsed.type==="opt"){return true}if(parsed.type==="alt"){return parsed.options.some(optional)}return false}function maxParamsF(parsed){return parsed.rest===undefined?parsed.params.length:Infinity}function minParamsF(parsed){var result=parsed.params.length;for(var i=result-1;i>=0;i--){if(!optional(parsed.params[i])){break}result=i}return result}function compileContext(environment,context){return utils.mapValues(context,function(v){return utils.map(v,compileCheckableType.bind(undefined,environment,context))})}function parseFunctionType(type){if(!functionTypeCheckRe.test(type)){throw new TypeError("invalid function type: "+type)}var tokens=type.match(functionTypeTokenRe);var parsed=A.parse(functionP,tokens);if(parsed===undefined){throw new TypeError("invalid function type: "+type)}return parsed}function compileFunctionType(environment,parsed){return{name:parsed.name,context:compileContext(environment,parsed.context),params:utils.map(parsed.params,compileCheckableType.bind(undefined,environment,parsed.context)),rest:parsed.rest&&compileCheckableType(environment,parsed.context,parsed.rest),result:compileCheckableType(environment,parsed.context,parsed.result),minParams:minParamsF(parsed),maxParams:maxParamsF(parsed)}}function contextCheckGeneric(context,compiled,varname){var options=context[varname];var args=utils.slice(arguments,3);for(var i=0;icompiled.maxParams){if(compiled.minParams===compiled.maxParams){throw new TypeError("function "+compiled.name+" expects "+compiled.maxParams+" arguments, "+arguments.length+" given")}else{throw new TypeError("function "+compiled.name+" expects "+compiled.minParams+"-"+compiled.maxParams+" arguments, "+arguments.length+" given")}}var contextCheckUn=contextCheckGeneric.bind(undefined,utils.copyObj(compiled.context));var contextCheck=utils.y(contextCheckUn);for(var i=0;i fn -> *",alias:"string -> string -> *",record:"string -> map string -> boolean? -> *",mutual:"map string -> *",instance:"string -> fn -> *",wrap:"* -> map string -> *",adt:"string -> map string -> *"};function create(){var env=new Environment;var typify=decorate.bind(undefined,env);typify.type=addType.bind(undefined,env);typify.alias=addType.bind(undefined,env);typify.record=addType.bind(undefined,env);typify.mutual=mutual.bind(undefined,env);typify.adt=adt.bind(undefined,env);typify.instance=instance.bind(undefined,env);typify.check=check.bind(undefined,env);typify.assert=assert.bind(undefined,env);typify.wrap=wrap.bind(undefined,env);typify.version=VERSION;typify.create=create;return typify.wrap(typify,TYPE_SIGNATURES)}module.exports=create()},{"./aparser.js":1,"./builtin.js":2,"./checkableCompiler.js":3,"./checkableConstructors.js":4,"./checkableParser":5,"./functionParser.js":6,"./predicates.js":7,"./show.js":8,"./utils.js":10}],10:[function(require,module,exports){"use strict";function has(object,property){return Object.prototype.hasOwnProperty.call(object,property)}function contains(array,element){return array.indexOf(element)!==-1}function copyObj(obj){var res={};for(var k in obj){res[k]=obj[k]}return res}function values(obj){var res=[];for(var k in obj){if(has(obj,k)){res.push(obj[k])}}return res}function mapValues(obj,f){var res={};for(var k in obj){if(has(obj,k)){res[k]=f(obj[k])}}return res}function slice(array,n,m){return Array.prototype.slice.call(array,n,m)}function map(array,f){return array.map(function(x){return f(x)})}function every(array,f){var acc=true;for(var i=0;i=0){var next_line=out.indexOf("\n",idx+1);out=out.substring(next_line+1)}this.stack=out}}};util.inherits(assert.AssertionError,Error);function replacer(key,value){if(util.isUndefined(value)){return""+value}if(util.isNumber(value)&&!isFinite(value)){return value.toString()}if(util.isFunction(value)||util.isRegExp(value)){return value.toString()}return value}function truncate(s,n){if(util.isString(s)){return s.length=0;i--){if(ka[i]!=kb[i])return false}for(i=ka.length-1;i>=0;i--){key=ka[i];if(!_deepEqual(a[key],b[key]))return false}return true}assert.notDeepEqual=function notDeepEqual(actual,expected,message){if(_deepEqual(actual,expected)){fail(actual,expected,message,"notDeepEqual",assert.notDeepEqual)}};assert.strictEqual=function strictEqual(actual,expected,message){if(actual!==expected){fail(actual,expected,message,"===",assert.strictEqual)}};assert.notStrictEqual=function notStrictEqual(actual,expected,message){if(actual===expected){fail(actual,expected,message,"!==",assert.notStrictEqual)}};function expectedException(actual,expected){if(!actual||!expected){return false}if(Object.prototype.toString.call(expected)=="[object RegExp]"){return expected.test(actual)}else if(actual instanceof expected){return true}else if(expected.call({},actual)===true){return true}return false}function _throws(shouldThrow,block,expected,message){var actual;if(util.isString(expected)){message=expected;expected=null}try{block()}catch(e){actual=e}message=(expected&&expected.name?" ("+expected.name+").":".")+(message?" "+message:".");if(shouldThrow&&!actual){fail(actual,expected,"Missing expected exception"+message)}if(!shouldThrow&&expectedException(actual,expected)){fail(actual,expected,"Got unwanted exception"+message)}if(shouldThrow&&actual&&expected&&!expectedException(actual,expected)||!shouldThrow&&actual){throw actual}}assert.throws=function(block,error,message){_throws.apply(this,[true].concat(pSlice.call(arguments)))};assert.doesNotThrow=function(block,message){_throws.apply(this,[false].concat(pSlice.call(arguments)))};assert.ifError=function(err){if(err){throw err}};var objectKeys=Object.keys||function(obj){var keys=[];for(var key in obj){if(hasOwn.call(obj,key))keys.push(key)}return keys}},{"util/":15}],12:[function(require,module,exports){if(typeof Object.create==="function"){module.exports=function inherits(ctor,superCtor){ctor.super_=superCtor;ctor.prototype=Object.create(superCtor.prototype,{constructor:{value:ctor,enumerable:false,writable:true,configurable:true}})}}else{module.exports=function inherits(ctor,superCtor){ctor.super_=superCtor;var TempCtor=function(){};TempCtor.prototype=superCtor.prototype;ctor.prototype=new TempCtor;ctor.prototype.constructor=ctor}}},{}],13:[function(require,module,exports){var process=module.exports={};var queue=[];var draining=false;function drainQueue(){if(draining){return}draining=true;var currentQueue;var len=queue.length;while(len){currentQueue=queue;queue=[];var i=-1;while(++i=len)return x;switch(x){case"%s":return String(args[i++]);case"%d":return Number(args[i++]);case"%j":try{return JSON.stringify(args[i++])}catch(_){return"[Circular]"}default:return x}});for(var x=args[i];i=3)ctx.depth=arguments[2];if(arguments.length>=4)ctx.colors=arguments[3];if(isBoolean(opts)){ctx.showHidden=opts}else if(opts){exports._extend(ctx,opts)}if(isUndefined(ctx.showHidden))ctx.showHidden=false;if(isUndefined(ctx.depth))ctx.depth=2;if(isUndefined(ctx.colors))ctx.colors=false;if(isUndefined(ctx.customInspect))ctx.customInspect=true;if(ctx.colors)ctx.stylize=stylizeWithColor;return formatValue(ctx,obj,ctx.depth)}exports.inspect=inspect;inspect.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]};inspect.styles={special:"cyan",number:"yellow","boolean":"yellow",undefined:"grey","null":"bold",string:"green",date:"magenta",regexp:"red"};function stylizeWithColor(str,styleType){var style=inspect.styles[styleType];if(style){return"["+inspect.colors[style][0]+"m"+str+"["+inspect.colors[style][1]+"m"}else{return str}}function stylizeNoColor(str,styleType){return str}function arrayToHash(array){var hash={};array.forEach(function(val,idx){hash[val]=true});return hash}function formatValue(ctx,value,recurseTimes){if(ctx.customInspect&&value&&isFunction(value.inspect)&&value.inspect!==exports.inspect&&!(value.constructor&&value.constructor.prototype===value)){var ret=value.inspect(recurseTimes,ctx);if(!isString(ret)){ret=formatValue(ctx,ret,recurseTimes)}return ret}var primitive=formatPrimitive(ctx,value);if(primitive){return primitive}var keys=Object.keys(value);var visibleKeys=arrayToHash(keys);if(ctx.showHidden){keys=Object.getOwnPropertyNames(value)}if(isError(value)&&(keys.indexOf("message")>=0||keys.indexOf("description")>=0)){return formatError(value)}if(keys.length===0){if(isFunction(value)){var name=value.name?": "+value.name:"";return ctx.stylize("[Function"+name+"]","special")}if(isRegExp(value)){return ctx.stylize(RegExp.prototype.toString.call(value),"regexp")}if(isDate(value)){return ctx.stylize(Date.prototype.toString.call(value),"date")}if(isError(value)){return formatError(value)}}var base="",array=false,braces=["{","}"];if(isArray(value)){array=true;braces=["[","]"]}if(isFunction(value)){var n=value.name?": "+value.name:"";base=" [Function"+n+"]"}if(isRegExp(value)){base=" "+RegExp.prototype.toString.call(value)}if(isDate(value)){base=" "+Date.prototype.toUTCString.call(value)}if(isError(value)){base=" "+formatError(value)}if(keys.length===0&&(!array||value.length==0)){return braces[0]+base+braces[1]}if(recurseTimes<0){if(isRegExp(value)){return ctx.stylize(RegExp.prototype.toString.call(value),"regexp")}else{return ctx.stylize("[Object]","special")}}ctx.seen.push(value);var output;if(array){output=formatArray(ctx,value,recurseTimes,visibleKeys,keys)}else{output=keys.map(function(key){return formatProperty(ctx,value,recurseTimes,visibleKeys,key,array)})}ctx.seen.pop();return reduceToSingleString(output,base,braces)}function formatPrimitive(ctx,value){if(isUndefined(value))return ctx.stylize("undefined","undefined");if(isString(value)){var simple="'"+JSON.stringify(value).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return ctx.stylize(simple,"string")}if(isNumber(value))return ctx.stylize(""+value,"number");if(isBoolean(value))return ctx.stylize(""+value,"boolean");if(isNull(value))return ctx.stylize("null","null")}function formatError(value){return"["+Error.prototype.toString.call(value)+"]"}function formatArray(ctx,value,recurseTimes,visibleKeys,keys){var output=[];for(var i=0,l=value.length;i-1){if(array){str=str.split("\n").map(function(line){return" "+line}).join("\n").substr(2)}else{str="\n"+str.split("\n").map(function(line){return" "+line}).join("\n")}}}else{str=ctx.stylize("[Circular]","special")}}if(isUndefined(name)){if(array&&key.match(/^\d+$/)){return str}name=JSON.stringify(""+key);if(name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)){name=name.substr(1,name.length-2);name=ctx.stylize(name,"name")}else{name=name.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'");name=ctx.stylize(name,"string")}}return name+": "+str}function reduceToSingleString(output,base,braces){var numLinesEst=0;var length=output.reduce(function(prev,cur){numLinesEst++;if(cur.indexOf("\n")>=0)numLinesEst++;return prev+cur.replace(/\u001b\[\d\d?m/g,"").length+1},0);if(length>60){return braces[0]+(base===""?"":base+"\n ")+" "+output.join(",\n ")+" "+braces[1]}return braces[0]+base+" "+output.join(", ")+" "+braces[1]}function isArray(ar){return Array.isArray(ar)}exports.isArray=isArray;function isBoolean(arg){return typeof arg==="boolean"}exports.isBoolean=isBoolean;function isNull(arg){return arg===null}exports.isNull=isNull;function isNullOrUndefined(arg){return arg==null}exports.isNullOrUndefined=isNullOrUndefined;function isNumber(arg){return typeof arg==="number"}exports.isNumber=isNumber;function isString(arg){return typeof arg==="string"}exports.isString=isString;function isSymbol(arg){return typeof arg==="symbol"}exports.isSymbol=isSymbol;function isUndefined(arg){return arg===void 0}exports.isUndefined=isUndefined;function isRegExp(re){return isObject(re)&&objectToString(re)==="[object RegExp]"}exports.isRegExp=isRegExp;function isObject(arg){return typeof arg==="object"&&arg!==null}exports.isObject=isObject;function isDate(d){return isObject(d)&&objectToString(d)==="[object Date]"}exports.isDate=isDate;function isError(e){return isObject(e)&&(objectToString(e)==="[object Error]"||e instanceof Error)}exports.isError=isError;function isFunction(arg){return typeof arg==="function"}exports.isFunction=isFunction;function isPrimitive(arg){return arg===null||typeof arg==="boolean"||typeof arg==="number"||typeof arg==="string"||typeof arg==="symbol"||typeof arg==="undefined"}exports.isPrimitive=isPrimitive;exports.isBuffer=require("./support/isBuffer");function objectToString(o){return Object.prototype.toString.call(o)}function pad(n){return n<10?"0"+n.toString(10):n.toString(10)}var months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function timestamp(){var d=new Date;var time=[pad(d.getHours()),pad(d.getMinutes()),pad(d.getSeconds())].join(":");return[d.getDate(),months[d.getMonth()],time].join(" ")}exports.log=function(){console.log("%s - %s",timestamp(),exports.format.apply(exports,arguments))};exports.inherits=require("inherits");exports._extend=function(origin,add){if(!add||!isObject(add))return origin;var keys=Object.keys(add);var i=keys.length;while(i--){origin[keys[i]]=add[keys[i]]}return origin};function hasOwnProperty(obj,prop){return Object.prototype.hasOwnProperty.call(obj,prop)}}).call(this,require("_process"),typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{})},{"./support/isBuffer":14,_process:13,inherits:12}]},{},[9])(9)});
3 | //# sourceMappingURL=dist/typify.min.js.map
--------------------------------------------------------------------------------
/dist/typify.min.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"dist/typify.min.js","sources":["dist/typify.standalone.js"],"names":["f","exports","module","define","amd","g","window","global","self","this","jsc","e","t","n","r","s","o","u","a","require","i","Error","code","l","call","length",1,"utils","Thunk","thunk","forced","value","undefined","delay","force","parse","p","tokens","res","eof","idx","token","tok","satisfying","predicate","any","pure","x","or","args","slice","arguments","len","lift","resargs","Array","apply","manyLoop","aq","push","some","ap","many","sepBy","sep","optional","def","./utils.js",2,"number","isNumber","integer","isInteger","nat","val","isNonNegative","positive","valueCheck","isPositive","nonnegative","finite","isFinite","boolean","isBoolean","string","isString","date","isDate","regexp","isRegExp","function","isFunction","fn","isArguments","constTrue","array","arr","isArray","every","map","isObject","values","tuple","v","./predicates.js",3,"compileCheckableTypeRecursive","compileAndAlt","environment","context","recNames","parsed","operator","cs","options","bind","type","recChecks","varCheck","arg","c","compileVar","has","name","check","get","contains","compilePoly","compiledPolyEnv","argsChecks","argCheck","concat","polyCheck","compileOpt","term","compileLiteral","compileRecord","fields","closed","fieldName","key","compileUser","compileCheckableType","compile","compileRecursive",4,"assert","variable","Infinity","NaN","opt","poly","record","mergeOptions","b","andOr","reduce","user","and","alt",5,"A","cons","identifierRe","numberRe","stringRe","isIdentifier","test","altP","parensP","identifierP","numberP","parseFloat","stringP","substr","literalP","anyP","varP","emptyRecordP","pairP","k","ident","nonEmptyRecordP","ps","obj","forEach","recordP","termP","optP","polyP1","polyP","andP","checkableP","checkableTypeCheckRe","checkableTypeTokenRe","parseCheckableType","TypeError","match","./aparser.js","./checkableConstructors.js",6,"nameP","identifier","actionP","arrow","result","params","rest","typesetP","contextDefP","typeset","contextP","defs","paramsP","param","restP","ellipsis","functionTypeP1","functionTypeP","functionP","./checkableParser",7,"toString","Object","prototype",8,"parensS","guard","str","showCheckableTypePrecedence","showLiteral","showRecord","pairs","join","precedence","showCheckableType","showContext","checkable",9,"VERSION","show","throwAlways","functionTypeCheckRe","functionTypeTokenRe","maxParamsF","minParamsF","compileContext","mapValues","parseFunctionType","compileFunctionType","minParams","maxParams","contextCheckGeneric","compiled","varname","option","decorate","method","contextCheckUn","copyObj","contextCheck","y","argType","JSON","stringify","definition","variable1","result1","addParsedTypes","names","keys","checks","add","addType","mutual","definitions","adt","constructors","instance","cls","wrap","signatures","buildInTypes","Environment","types","environmentHas","environmentGet","environmentAdd","TYPE_SIGNATURES","alias","create","env","typify","version","./builtin.js","./checkableCompiler.js","./functionParser.js","./show.js",10,"object","property","hasOwnProperty","element","indexOf","m","acc","h",11,"util","pSlice","hasOwn","ok","AssertionError","actual","expected","message","generatedMessage","getMessage","stackStartFunction","fail","captureStackTrace","err","stack","out","fn_name","next_line","substring","inherits","replacer","isUndefined","truncate","equal","notEqual","deepEqual","_deepEqual","isBuffer","getTime","source","multiline","lastIndex","ignoreCase","objEquiv","isNullOrUndefined","isPrimitive","aIsArgs","bIsArgs","ka","objectKeys","kb","sort","notDeepEqual","strictEqual","notStrictEqual","expectedException","_throws","shouldThrow","block","throws","error","doesNotThrow","ifError","util/",12,"ctor","superCtor","super_","constructor","enumerable","writable","configurable","TempCtor",13,"process","queue","draining","drainQueue","currentQueue","nextTick","fun","setTimeout","title","browser","argv","versions","noop","on","addListener","once","off","removeListener","removeAllListeners","emit","binding","cwd","chdir","dir","umask",14,"copy","fill","readUInt8",15,"formatRegExp","format","objects","inspect","String","replace","Number","_","isNull","deprecate","msg","noDeprecation","warned","deprecated","throwDeprecation","traceDeprecation","console","trace","debugs","debugEnviron","debuglog","set","NODE_DEBUG","toUpperCase","RegExp","pid","opts","ctx","seen","stylize","stylizeNoColor","depth","colors","showHidden","_extend","customInspect","stylizeWithColor","formatValue","bold","italic","underline","inverse","white","grey","black","blue","cyan","green","magenta","red","yellow","styles","special","null","styleType","style","arrayToHash","hash","recurseTimes","ret","primitive","formatPrimitive","visibleKeys","getOwnPropertyNames","isError","formatError","Date","base","braces","toUTCString","output","formatArray","formatProperty","pop","reduceToSingleString","simple","desc","getOwnPropertyDescriptor","split","line","numLinesEst","prev","cur","ar","isSymbol","re","objectToString","d","pad","months","timestamp","time","getHours","getMinutes","getSeconds","getDate","getMonth","log","origin","prop","./support/isBuffer","_process"],"mappings":"CAAA,SAAUA,GAAG,SAAUC,WAAU,gBAAiBC,UAAS,YAAY,CAACA,OAAOD,QAAQD,QAAS,UAAUG,UAAS,YAAYA,OAAOC,IAAI,CAACD,UAAUH,OAAO,CAAC,GAAIK,EAAE,UAAUC,UAAS,YAAY,CAACD,EAAEC,WAAY,UAAUC,UAAS,YAAY,CAACF,EAAEE,WAAY,UAAUC,QAAO,YAAY,CAACH,EAAEG,SAAS,CAACH,EAAEI,KAAKJ,EAAEK,IAAMV,OAAO,WAAW,GAAIG,QAAOD,OAAOD,OAAQ,OAAO,SAAUU,GAAEC,EAAEC,EAAEC,GAAG,QAASC,GAAEC,EAAEC,GAAG,IAAIJ,EAAEG,GAAG,CAAC,IAAIJ,EAAEI,GAAG,CAAC,GAAIE,SAASC,UAAS,YAAYA,OAAQ,KAAIF,GAAGC,EAAE,MAAOA,GAAEF,GAAG,EAAG,IAAGI,EAAE,MAAOA,GAAEJ,GAAG,EAAG,IAAIhB,GAAE,GAAIqB,OAAM,uBAAuBL,EAAE,IAAK,MAAMhB,GAAEsB,KAAK,mBAAmBtB,EAAE,GAAIuB,GAAEV,EAAEG,IAAIf,WAAYW,GAAEI,GAAG,GAAGQ,KAAKD,EAAEtB,QAAQ,SAASU,GAAG,GAAIE,GAAED,EAAEI,GAAG,GAAGL,EAAG,OAAOI,GAAEF,EAAEA,EAAEF,IAAIY,EAAEA,EAAEtB,QAAQU,EAAEC,EAAEC,EAAEC,GAAG,MAAOD,GAAEG,GAAGf,QAAQ,GAAImB,SAASD,UAAS,YAAYA,OAAQ,KAAI,GAAIH,GAAE,EAAEA,EAAEF,EAAEW,OAAOT,IAAID,EAAED,EAAEE,GAAI,OAAOD,KAAKW,GAAG,SAASP,QAAQjB,OAAOD,SACl0B,YAEA,IAAI0B,OAAQR,QAAQ,aAMpB,SAASS,OAAM5B,GACbS,KAAKoB,MAAQ7B,CACbS,MAAKqB,OAAS,KACdrB,MAAKsB,MAAQC,UAIf,QAASC,OAAMjC,GACb,MAAO,IAAI4B,OAAM5B,GAInB,QAASkC,OAAML,OACb,GAAIA,gBAAiBD,OAAO,CAC1B,IAAKC,MAAMC,OAAQ,CACjBD,MAAME,MAAQF,MAAMA,OACpBA,OAAMC,OAAS,KAEjB,MAAOD,OAAME,UACR,CACL,MAAOF,QAKX,QAASM,OAAMC,EAAGC,QAChB,GAAIC,KAAMF,EAAEC,OAAQ,EAEpB,IAAIC,MAAQN,WAAaM,IAAI,IAAMD,OAAOZ,OAAQ,CAChD,MAAOa,KAAI,OACN,CACL,MAAON,YAKX,QAASO,KAAIF,OAAQG,KAEnB,GAAIA,IAAMH,OAAOZ,OAAQ,CACvB,MAAOO,eACF,CACL,OAAQA,UAAWQ,MAKvB,QAASC,OAAMC,KAEb,MAAO,UAAUL,OAAQG,KAEvB,GAAIA,KAAOH,OAAOZ,OAAQ,CAAE,MAAOO,WACnC,GAAIK,OAAOG,OAASE,IAAK,CACvB,OAAQA,IAAKF,IAAI,OACZ,CACL,MAAOR,aAMb,QAASW,YAAWC,WAElB,MAAO,UAAUP,OAAQG,KAEvB,GAAIA,KAAOH,OAAOZ,OAAQ,CAAE,MAAOO,WACnC,GAAIY,UAAUP,OAAOG,MAAO,CAC1B,OAAQH,OAAOG,KAAMA,IAAI,OACpB,CACL,MAAOR,aAMb,QAASa,OAEP,MAAO,UAAUR,OAAQG,KACvB,GAAIA,IAAMH,OAAOZ,OAAQ,CACvB,OAAQY,OAAOG,KAAMA,IAAI,OACpB,CACL,MAAOR,aAMb,QAASc,MAAKC,GAEZ,MAAO,UAAUV,OAAQG,KACvB,OAAQO,EAAGP,MAKf,QAASQ,MACP,GAAIC,MAAOtB,MAAMuB,MAAMC,UACvB,IAAIC,KAAMH,KAAKxB,MAEf,OAAO,UAAUY,OAAQG,KACvB,IAAK,GAAIpB,GAAI,EAAGA,EAAIgC,IAAKhC,IAAK,CAC5B,GAAIkB,KAAMJ,MAAMe,KAAK7B,IAAIiB,OAAQG,IACjC,IAAIF,MAAQN,UAAW,CAAE,MAAOM,MAElC,MAAON,YAKX,QAASqB,QACP,GAAID,KAAMD,UAAU1B,OAAS,CAC7B,IAAIzB,GAAImD,UAAUC,IAClB,IAAIH,MAAOtB,MAAMuB,MAAMC,UAAW,GAAI,EAEtC,OAAO,UAASd,OAAQG,KACtB,GAAIc,SAAU,GAAIC,OAAMH,IACxB,KAAK,GAAIhC,GAAI,EAAGA,EAAIgC,IAAKhC,IAAK,CAC5B,GAAIkB,KAAMJ,MAAMe,KAAK7B,IAAIiB,OAAQG,IAEjC,IAAIF,MAAQN,UAAW,CAAE,MAAOA,WAChCsB,QAAQlC,GAAKkB,IAAI,EACjBE,KAAMF,IAAI,GAGZ,OAAQtC,EAAEwD,MAAMxB,UAAWsB,SAAUd,MAKzC,QAASiB,UAASnB,IAAKpB,EAAGmB,OAAQG,KAChC,MAAO,KAAM,CACX,GAAIkB,IAAKxC,EAAEmB,OAAQG,IACnB,IAAIkB,KAAO1B,UAAW,CAAE,OAAQM,IAAKE,KACrCF,IAAIqB,KAAKD,GAAG,GACZlB,KAAMkB,GAAG,IAKb,QAASE,MAAK1C,GAEZ,MAAO,UAAUmB,OAAQG,KACvBtB,EAAIgB,MAAMhB,EACV,IAAIoB,OACJ,IAAIuB,IAAK3C,EAAEmB,OAAQG,IACnB,IAAIqB,KAAO7B,UAAW,CAAE,MAAOA,WAC/BM,IAAIqB,KAAKE,GAAG,GACZrB,KAAMqB,GAAG,EACT,OAAOJ,UAASnB,IAAKpB,EAAGmB,OAAQG,MAKpC,QAASsB,MAAK5C,GAEZ,MAAO,UAAUmB,OAAQG,KACvBtB,EAAIgB,MAAMhB,EACV,IAAIoB,OACJ,OAAOmB,UAASnB,IAAKpB,EAAGmB,OAAQG,MAKpC,QAASuB,OAAM7C,EAAG8C,KAEhB,MAAO,UAAU3B,OAAQG,KACvBtB,EAAIgB,MAAMhB,EACV,IAAIoB,OACJ,IAAIuB,IAAK3C,EAAEmB,OAAQG,IACnB,IAAIqB,KAAO7B,UAAW,CAAE,MAAOA,WAC/BM,IAAIqB,KAAKE,GAAG,GACZrB,KAAMqB,GAAG,EACT,OAAO,KAAM,CACX,GAAIxB,OAAOG,OAASwB,IAAK,CAAE,OAAQ1B,IAAKE,KACxCA,KAAO,CACP,IAAIkB,IAAKxC,EAAEmB,OAAQG,IACnB,IAAIkB,KAAO1B,UAAW,CAAE,OAAQM,IAAKE,KACrCF,IAAIqB,KAAKD,GAAG,GACZlB,KAAMkB,GAAG,KAMf,QAASO,UAAS7B,EAAG8B,KAEnB,MAAO,UAAU7B,OAAQG,KACvB,GAAIF,KAAMJ,MAAME,GAAGC,OAAQG,IAC3B,IAAIF,MAAQN,UAAW,CACrB,OAAQkC,IAAK1B,SACR,CACL,MAAOF,OAKbpC,OAAOD,SACLkC,MAAOA,MACPW,KAAMA,KACNE,GAAIA,GACJK,KAAMA,KACNS,KAAMA,KACNF,KAAMA,KACNG,MAAOA,MACPxB,IAAKA,IACLE,MAAOA,MACPI,IAAKA,IACLF,WAAYA,WACZsB,SAAUA,SACVhC,MAAOA,SAGNkC,aAAa,KAAKC,GAAG,SAASjD,QAAQjB,OAAOD,SAChD,YAEA,IAAImC,GAAIjB,QAAQ,kBAChB,IAAIQ,OAAQR,QAAQ,aAEpBjB,QAAOD,SACLoE,OAAUjC,EAAEkC,SACZC,QAAWnC,EAAEoC,UACbC,IAAO,SAAUC,KACf,MAAOtC,GAAEoC,UAAUE,MAAQtC,EAAEuC,cAAcD,MAE7CE,SAAY,SAAUF,IAAKG,YACzB,MAAOzC,GAAE0C,WAAWJ,QAAUG,YAAcA,WAAWH,OAEzDK,YAAe,SAAUL,IAAKG,YAC5B,MAAOzC,GAAEuC,cAAcD,QAAUG,YAAcA,WAAWH,OAE5DM,OAAU,SAAUN,IAAKG,YACvB,MAAOzC,GAAE6C,SAASP,QAAUG,YAAcA,WAAWH,OAEvDQ,UAAW9C,EAAE+C,UACbC,OAAUhD,EAAEiD,SACZC,KAAQlD,EAAEmD,OACVC,OAAUpD,EAAEqD,SACZC,WAAYtD,EAAEuD,WACdC,GAAMxD,EAAEuD,WACRxC,UAAaf,EAAEyD,YACfhD,IAAOT,EAAE0D,UACTC,MAAS,SAAUC,IAAKnB,YACtB,MAAOzC,GAAE6D,QAAQD,QAAUnB,YAAclD,MAAMuE,MAAMF,IAAKnB,cAE5DsB,IAAO,SAAUA,IAAKtB,YACpB,MAAQzC,GAAEgE,SAASD,OAAS/D,EAAE6D,QAAQE,QAAWtB,YAAclD,MAAMuE,MAAMvE,MAAM0E,OAAOF,KAAMtB,cAEhGyB,MAAS,SAAUC,GACjB,IAAKhD,MAAM0C,QAAQM,GAAI,CAAE,MAAO,OAChC,GAAItD,MAAOtB,MAAMuB,MAAMC,UAAW,EAClC,IAAIF,KAAKxB,SAAW8E,EAAE9E,OAAQ,CAAE,MAAO,OACvC,IAAK,GAAIL,GAAI,EAAGA,EAAI6B,KAAKxB,OAAQL,IAAK,CACpC,IAAK6B,KAAK7B,GAAGmF,EAAEnF,IAAK,CAClB,MAAO,QAGX,MAAO,UAIRoF,kBAAkB,EAAErC,aAAa,KAAKsC,GAAG,SAAStF,QAAQjB,OAAOD,SACpE,YAEA,IAAI0B,OAAQR,QAAQ,aACpB,IAAIiB,GAAIjB,QAAQ,kBAGhB,IAAIuF,8BAGJ,SAASC,eAAcC,YAAaC,QAASC,SAAUC,OAAQC,UAC7D,GAAIC,IAAKtF,MAAMwE,IAAIY,OAAOG,QAASR,8BAA8BS,KAAKnF,UAAW4E,YAAaC,QAASC,UAEvGE,UAAWD,OAAOK,OAAS,MAAQ,QAAU,MAC7C,OAAO,UAAUC,UAAWC,SAAUC,KACpC,MAAON,IAAGD,UAAU,SAAUQ,GAC5B,MAAOA,GAAEH,UAAWC,SAAUC,QAMpC,QAASE,YAAWb,YAAaC,QAASC,SAAUC,QAClD,GAAIpF,MAAM+F,IAAIb,QAASE,OAAOY,MAAO,CAEnC,MAAO,UAAUN,UAAWC,SAAUC,KAEpC,MAAOD,UAASP,OAAOY,KAAMJ,UAE1B,IAAIX,YAAYc,IAAIX,OAAOY,MAAO,CACvC,GAAIC,OAAQhB,YAAYiB,IAAId,OAAOY,KAEnC,OAAO,UAAUN,UAAWC,UAC1B,GAAIrE,MAAOtB,MAAMuB,MAAMC,UAAW,EAClC,OAAOyE,OAAMpE,MAAMxB,UAAWiB,WAE3B,IAAI6D,UAAYnF,MAAMmG,SAAShB,SAAUC,OAAOY,MAAO,CAE5D,MAAO,UAAUN,UAAWC,SAAUC,KACpC,MAAOF,WAAUN,OAAOY,MAAMN,UAAWC,SAAUC,UAEhD,CACL,KAAM,IAAIlG,OAAM,iBAAmB0F,OAAOY,OAK9C,QAASI,aAAYnB,YAAaC,QAASC,SAAUC,QACnD,GAAI9D,MAAOtB,MAAMwE,IAAIY,OAAO9D,KAAMyD,8BAA8BS,KAAKnF,UAAW4E,YAAaC,QAASC,UACtG,IAAInF,MAAM+F,IAAIb,QAASE,OAAOY,MAAO,CAEnC,MAAO,SAASK,iBAAgBX,UAAWC,SAAUC,KACnD,GAAIU,YAAahF,KAAKkD,IAAI,SAAU+B,UAClC,MAAOA,UAASf,KAAKnF,UAAWqF,UAAWC,WAE7C,OAAOA,UAAS9D,MAAMxB,WAAY+E,OAAOY,KAAMJ,KAAKY,OAAOF,kBAExD,IAAIrB,YAAYc,IAAIX,OAAOY,MAAO,CACvC,GAAIS,WAAYxB,YAAYiB,IAAId,OAAOY,KAEvC,OAAO,UAAUN,UAAWC,SAAUC,KACpC,GAAIU,YAAahF,KAAKkD,IAAI,SAAU+B,UAClC,MAAOA,UAASf,KAAKnF,UAAWqF,UAAWC,WAE7C,OAAOc,WAAU5E,MAAMxB,WAAYuF,KAAKY,OAAOF,kBAE5C,CACL,KAAM,IAAI5G,OAAM,iBAAmB0F,OAAOY,OAK9C,QAASU,YAAWzB,YAAaC,QAASC,SAAUC,QAClD,GAAIS,GAAId,8BAA8BE,YAAaC,QAASC,SAAUC,OAAOuB,KAE7E,OAAO,UAAUjB,UAAWC,SAAUC,KACpC,MAAOA,OAAQvF,WAAawF,EAAEH,UAAWC,SAAUC,MAKvD,QAASgB,gBAAe3B,YAAaC,QAASC,SAAUC,QACtD,GAAIA,OAAOhF,QAAUgF,OAAOhF,MAAO,CAGjC,MAAO,UAAUsF,UAAWC,SAAUC,KACpC,MAAOA,OAAQA,SAEZ,CAEL,MAAO,UAAUF,UAAWC,SAAUC,KACpC,MAAOA,OAAQR,OAAOhF,QAM5B,QAASyG,eAAc5B,YAAaC,QAASC,SAAUC,QACrD,GAAI0B,UACJ,KAAK,GAAId,QAAQZ,QAAO0B,OAAQ,CAC9BA,OAAOd,MAAQjB,8BAA8BE,YAAaC,QAASC,SAAUC,OAAO0B,OAAOd,OAE7F,GAAIe,QAAS3B,OAAO2B,MAGpB,OAAO,UAAUrB,UAAWC,SAAUC,KACpC,IAAKnF,EAAEgE,SAASmB,KAAM,CACpB,MAAO,OAGT,IAAK,GAAIoB,aAAaF,QAAQ,CAC5B,IAAKA,OAAOE,WAAWtB,UAAWC,SAAUC,IAAIoB,YAAa,CAC3D,MAAO,QAIX,GAAID,OAAQ,CACV,IAAK,GAAIE,OAAOrB,KAAK,CACnB,IAAKkB,OAAOG,KAAM,CAChB,MAAO,SAKb,MAAO,OAKX,QAASC,aAAYjC,YAAaC,QAASC,SAAUC,QAEnD,MAAO,UAAUM,UAAWC,SAAUC,KACpC,MAAOR,QAAOnE,UAAU2E,MAK5B,QAASb,+BAA8BE,YAAaC,QAASC,SAAUC,QACrE,OAAQA,OAAOK,MACb,IAAK,MAAO,MAAOK,YAAWb,YAAaC,QAASC,SAAUC,OAC9D,KAAK,UAAW,MAAOwB,gBAAe3B,YAAaC,QAASC,SAAUC,OACtE,KAAK,OAAQ,MAAOgB,aAAYnB,YAAaC,QAASC,SAAUC,OAChE,KAAK,MAAO,MAAO3E,GAAE0D,SACrB,KAAK,MAAO,MAAOuC,YAAWzB,YAAaC,QAASC,SAAUC,OAC9D,KAAK,MAAO,MAAOJ,eAAcC,YAAaC,QAASC,SAAUC,OACjE,KAAK,MAAO,MAAOJ,eAAcC,YAAaC,QAASC,SAAUC,OACjE,KAAK,SAAU,MAAOyB,eAAc5B,YAAaC,QAASC,SAAUC,OACpE,KAAK,OAAQ,MAAO8B,aAAYjC,YAAaC,QAASC,SAAUC,SAKpE,QAAS+B,sBAAqBlC,YAAaC,QAASE,QAClD,MAAOL,+BAA8BE,YAAaC,WAAaE,QAAQI,KAAKnF,cAG9E9B,OAAOD,SACL8I,QAASD,qBACTE,iBAAkBtC,8BAClB8B,cAAeA,iBAGdhC,kBAAkB,EAAErC,aAAa,KAAK8E,GAAG,SAAS9H,QAAQjB,OAAOD,SACpE,YAEA,IAAIiJ,QAAS/H,QAAQ,SAErB,IAAI0B,MAAQuE,KAAM,MAoBlB,SAAS+B,UAASxB,MAChB,OAAQA,MACN,IAAK,OAAQ,OAASP,KAAM,UAAWrF,MAAO,KAC9C,KAAK,QAAS,OAASqF,KAAM,UAAWrF,MAAO,MAC/C,KAAK,OAAQ,OAASqF,KAAM,UAAWrF,MAAO,KAC9C,KAAK,WAAY,OAASqF,KAAM,UAAWrF,MAAOqH,SAClD,KAAK,YAAa,OAAShC,KAAM,UAAWrF,OAAQqH,SACpD,KAAK,YAAa,OAAShC,KAAM,UAAWrF,MAAOC,UACnD,KAAK,MAAO,OAASoF,KAAM,UAAWrF,MAAOsH,KAE/C,OAASjC,KAAM,MAAOO,KAAMA,MAI9B,QAAStD,QAAOtC,OACdmH,aAAcnH,SAAU,SACxB,QAASqF,KAAM,UAAWrF,MAAOA,OAInC,QAASqD,QAAOrD,OACdmH,aAAcnH,SAAU,SACxB,QAASqF,KAAM,UAAWrF,MAAOA,OAInC,QAASuH,KAAI1I,GACX,GAAIA,EAAEwG,OAAS,MAAO,CACpB,MAAOxG,OACF,IAAIA,EAAEwG,OAAS,MAAO,CAC3B,MAAOxG,OACF,CACL,OAASwG,KAAM,MAAOkB,KAAM1H,IAKhC,QAAS2I,MAAK5B,KAAM1E,MAClB,OAASmE,KAAM,OAAQO,KAAMA,KAAM1E,KAAMA,MAI3C,QAASuG,QAAOf,OAAQC,QACtB,OAAStB,KAAM,SAAUqB,OAAQA,OAAQC,SAAUA,QAIrD,QAASe,cAAarC,KAAMlG,EAAGwI,GAC7B,GAAIxI,EAAEkG,OAASA,KAAM,CACnB,GAAIsC,EAAEtC,OAASA,KAAM,CACnB,MAAOlG,GAAEgG,QAAQiB,OAAOuB,EAAExC,aACrB,CACL,MAAOhG,GAAEgG,QAAQiB,QAAQuB,SAEtB,CACL,GAAIA,EAAEtC,OAASA,KAAM,CACnB,OAAQlG,GAAGiH,OAAOuB,EAAExC,aACf,CACL,OAAQhG,EAAGwI,KAMjB,QAASC,OAAMvC,KAAMF,SACnBgC,OAAOhC,QAAQzF,OAAS,EAExB,IAAIyF,QAAQzF,SAAW,EAAG,CACxB,MAAOyF,SAAQ,GAGjB,MAAOA,SAAQ0C,OAAO,SAAU1I,EAAGwI,GACjC,OACEtC,KAAMA,KACNF,QAASuC,aAAarC,KAAMlG,EAAGwI,MAMrC,QAASG,MAAKjH,WACZ,OAASwE,KAAM,OAAQxE,UAAWA,WAGpC1C,OAAOD,SACL4C,IAAKA,IACLsG,SAAUA,SACV9E,OAAQA,OACRe,OAAQA,OACRkE,IAAKA,IACLC,KAAMA,KACNC,OAAQA,OACRM,IAAKH,MAAMxC,KAAKnF,UAAW,OAC3B+H,IAAKJ,MAAMxC,KAAKnF,UAAW,OAC3B6H,KAAMA,QAGLX,OAAS,KAAKc,GAAG,SAAS7I,QAAQjB,OAAOD,SAC5C,YAEA,IAAIgK,GAAI9I,QAAQ,eAChB,IAAI+I,MAAO/I,QAAQ,6BAEnB,IAAIgJ,cAAe,0BACnB,IAAIC,UAAW,UACf,IAAIC,UAAW,qBAGf,SAASC,cAAa7H,OACpB,MAAO0H,cAAaI,KAAK9H,OAI3B,QAAS6B,UAAS7B,OAChB,MAAO2H,UAASG,KAAK9H,OAIvB,QAAS4C,UAAS5C,OAChB,MAAO4H,UAASE,KAAK9H,OAGvB,GAAI+H,KAGJ,SAASC,SAAQrI,GACf,MAAO6H,GAAE5G,KAAK4G,EAAExH,MAAM,KAAML,EAAG6H,EAAExH,MAAM,KAAM,SAASvB,EAAGwI,EAAGlC,GAC1D,MAAOkC,KAIX,GAAIgB,aAAcT,EAAEtH,WAAW2H,aAE/B,IAAIK,SAAUV,EAAE5G,KAAK4G,EAAEtH,WAAW2B,UAAW,SAAUvB,GACrD,MAAOmH,MAAK7F,OAAOuG,WAAW7H,KAGhC,IAAI8H,SAAUZ,EAAE5G,KAAK4G,EAAEtH,WAAW0C,UAAW,SAAUtC,GACrDA,EAAIA,EAAE+H,OAAO,EAAG/H,EAAEtB,OAAS,EAC3B,OAAOyI,MAAK9E,OAAOrC,IAGrB,IAAIgI,UAAWd,EAAEjH,GAAG2H,QAASE,QAE7B,IAAIG,MAAOf,EAAE5G,KAAK4G,EAAExH,MAAM,KAAM,WAC9B,MAAOyH,MAAKrH,KAGd,IAAIoI,MAAOhB,EAAE5G,KAAKqH,YAAaR,KAAKf,SAEpC,IAAI+B,cAAejB,EAAE5G,KAAK4G,EAAExH,MAAM,KAAMwH,EAAExH,MAAM,KAAM,WACpD,MAAOyH,MAAKV,YAGd,IAAI2B,OAAQlB,EAAE5G,KAAKqH,YAAaT,EAAExH,MAAM,KAAMwH,EAAEhI,MAAM,WAAc,MAAOuI,QAAU,SAAUY,EAAG5D,EAAGjB,GACnG,OACE8E,MAAOD,EACPrJ,MAAOwE,IAIX,IAAI+E,iBAAkBrB,EAAE5G,KAAK4G,EAAExH,MAAM,KAAMwH,EAAElG,MAAMoH,MAAO,KAAMlB,EAAExH,MAAM,KAAM,SAAUzB,EAAGuK,GAAI/D,GAC7F,GAAIgE,OACJD,IAAGE,QAAQ,SAAUrJ,GACnBoJ,IAAIpJ,EAAEiJ,OAASjJ,EAAEL,OAEnB,OAAOmI,MAAKV,OAAOgC,MAGrB,IAAIE,SAAUzB,EAAEjH,GAAGkI,aAAcI,gBAEjC,IAAIK,OAAQ1B,EAAEjH,GAAGgI,KAAMD,SAAUE,KAAMS,QAASjB,QAAQR,EAAEhI,MAAM,WAAc,MAAOuI,SAErF,IAAIoB,MAAO3B,EAAE5G,KAAKsI,MAAO1B,EAAEhG,SAASgG,EAAExH,MAAM,MAAO,SAAU6F,KAAMgB,KACjE,GAAIA,MAAQ,KAAOhB,KAAKlB,OAAS,OAASkB,KAAKlB,OAAS,MAAO,CAC7D,MAAO8C,MAAKZ,IAAIhB,UACX,CACL,MAAOA,QAIX,IAAIuD,QAAS5B,EAAE5G,KAAKqH,YAAaT,EAAErG,KAAKgI,MAAO1B,KAAKX,KAEpD,IAAIuC,OAAQ7B,EAAEjH,GAAG6I,OAAQD,KAEzB,IAAIG,MAAO9B,EAAE5G,KAAK4G,EAAElG,MAAM+H,MAAO,KAAM5B,KAAKJ,IAE5CU,MAAOP,EAAE5G,KAAK4G,EAAElG,MAAMgI,KAAM,KAAM7B,KAAKH,IAEvC,IAAIiC,YAAaxB,IAEjB,IAAIyB,sBAAuB,mFAC3B,IAAIC,sBAAuB,6EAG3B,SAASC,oBAAmB/E,MACzB,IAAK6E,qBAAqB1B,KAAKnD,MAAO,CAAE,KAAM,IAAIgF,WAAU,2BAA6BhF,MAC1F,GAAI/E,QAAS+E,KAAKiF,MAAMH,qBACxB,IAAInF,QAASkD,EAAE9H,MAAM6J,WAAY3J,OAChC,IAAI0E,SAAW/E,UAAW,CAAE,KAAM,IAAIoK,WAAU,2BAA6BhF,MAC7E,MAAOL,QAGV7G,OAAOD,SACLyK,YAAaA,YACbsB,WAAYA,WACZF,MAAOA,MACP3J,MAAOgK,sBAGNG,eAAe,EAAEC,6BAA6B,IAAIC,GAAG,SAASrL,QAAQjB,OAAOD,SAChF,YAEA,IAAIgK,GAAI9I,QAAQ,eAChB,IAAIuJ,aAAcvJ,QAAQ,qBAAqBuJ,WAC/C,IAAIoB,OAAQ3K,QAAQ,qBAAqB2K,KACzC,IAAIE,YAAa7K,QAAQ,qBAAqB6K,UAE9C,IAAIS,OAAQxC,EAAEhG,SAASgG,EAAE5G,KAAKqH,YAAaT,EAAExH,MAAM,MAAO,SAAUiK,WAAY1I,KAC9E,MAAO0I,cACL,GAEJ,IAAIC,SAAU1C,EAAE5G,KAAKoJ,MAAOxC,EAAExH,MAAM,MAAOuJ,WAAY,SAAUrE,KAAMiF,MAAOC,QAC5E,OACElF,KAAMA,KACNd,WACAiG,UACAC,KAAM/K,UACN6K,OAAQA,SAIZ,IAAIG,UAAW/C,EAAElG,MAAM+H,MAAO,IAE9B,IAAImB,aAAchD,EAAE5G,KAAKqH,YAAaT,EAAExH,MAAM,KAAMuK,SAAU,SAAUrF,KAAM3D,IAAKkJ,SAEjF,OACEvF,KAAMA,KACNuF,QAASA,UAIb,IAAIC,UAAWlD,EAAEhG,SAASgG,EAAE5G,KAAK4G,EAAElG,MAAMkJ,YAAa,KAAMhD,EAAExH,MAAM,MAAO,SAAU2K,KAAMR,OACzF,MAAOQ,MAAKxD,OAAO,SAAU/C,QAAS3C,KACpC2C,QAAQ3C,IAAIyD,MAAQzD,IAAIgJ,OACxB,OAAOrG,mBAIX,IAAIwG,SAAUpD,EAAEnG,KAAKmG,EAAE5G,KAAK2I,WAAY/B,EAAExH,MAAM,MAAO,SAAU6K,MAAOV,OACtE,MAAOU,SAGT,IAAIC,OAAQtD,EAAEhG,SAASgG,EAAE5G,KAAK4G,EAAEhG,SAAS+H,YAAa/B,EAAExH,MAAM,OAAQwH,EAAExH,MAAM,MAAO,SAAU2E,KAAMoG,SAAUZ,OAE7G,MAAOxF,QAAUA,KAAM,SAGzB,IAAIqG,gBAAiBxD,EAAE5G,KAAKoJ,MAAOU,SAAUE,QAASE,MAAOvB,WAAY,SAAUrE,KAAMd,QAASiG,OAAQC,KAAMF,QAE9G,OACElF,KAAMA,KACNd,QAASA,QACTiG,OAAQA,OACRC,KAAMA,KACNF,OAAQA,SAIZ,IAAIa,eAAgBzD,EAAEjH,GAAG2J,QAASc,eAElCvN,QAAOD,SACL0N,UAAWD,iBAGVpB,eAAe,EAAEsB,oBAAoB,IAAIC,GAAG,SAAS1M,QAAQjB,OAAOD,SACvE,YAGA,IAAI6N,UAAWC,OAAOC,UAAUF,QAGhC,SAAS3I,WAAUT,KACjB,aAAcA,OAAQ,UAIxB,QAASJ,UAASI,KAChB,aAAcA,OAAQ,SAIxB,QAASF,WAAUE,KACjB,MAAOA,QAASA,IAAI,GAItB,QAASI,YAAWJ,KAClB,aAAcA,OAAQ,UAAYA,IAAM,EAI1C,QAASC,eAAcD,KACrB,aAAcA,OAAQ,UAAYA,KAAO,EAI3C,QAASO,UAASP,KAChB,aAAcA,OAAQ,UAAYA,MAAQ0E,UAAY1E,OAAS0E,UAAY1E,OAASA,IAItF,QAASW,UAASX,KAChB,aAAcA,OAAQ,SAIxB,QAASiB,YAAWjB,KAClB,aAAcA,OAAQ,WAIxB,QAASa,QAAOb,KACd,MAAOoJ,UAAStM,KAAKkD,OAAS,gBAIhC,QAASe,UAASf,KAChB,MAAOoJ,UAAStM,KAAKkD,OAAS,kBAIhC,QAASuB,SAAQvB,KACf,MAAOnB,OAAM0C,QAAQvB,KAIvB,QAAS0B,UAAS1B,KAChB,MAAOqJ,QAAOrJ,OAASA,IAIzB,QAASmB,aAAYnB,KACnB,MAAOA,MAAO0B,SAASjD,YAAcqB,UAAUE,IAAIjD,SAAWsM,OAAOC,UAAUF,SAAStM,KAAKkD,OAAS,sBAAwB,MAIhI,QAASoB,aACP,MAAO,MAGT5F,OAAOD,SACLkF,UAAWA,UACXb,SAAUA,SACVE,UAAWA,UACXM,WAAYA,WACZH,cAAeA,cACfM,SAAUA,SACVI,SAAUA,SACVM,WAAYA,WACZJ,OAAQA,OACRE,SAAUA,SACVQ,QAASA,QACTG,SAAUA,SACVP,YAAaA,YACbC,UAAWA,gBAGPmI,GAAG,SAAS9M,QAAQjB,OAAOD,SACjC,YAEA,IAAI0B,OAAQR,QAAQ,aAGpB,SAAS+M,SAAQC,MAAOC,KACtB,MAAOD,OAAQ,IAAMC,IAAM,IAAMA,IAInC,GAAIC,4BAGJ,SAASC,aAAYlH,MACnB,SAAWA,MAAKrF,QAAU,SAAU,CAClC,MAAO,IAAMqF,KAAKrF,MAAQ,QACrB,CACL,MAAO,GAAKqF,KAAKrF,OAKrB,QAASwM,YAAWnH,MAClB,GAAIoH,SACJ,KAAK,GAAI5N,KAAKwG,MAAKqB,OAAQ,CACzB+F,MAAM7K,KAAK/C,EAAI,KAAOyN,4BAA4B,EAAGjH,KAAKqB,OAAO7H,KAEnE,MAAO,IAAM4N,MAAMC,KAAK,MAAQ,IAIlC,QAASJ,6BAA4BK,WAAYtH,MAC/C,OAAQA,KAAKA,MACX,IAAK,MAAO,MAAO,GACnB,KAAK,UAAW,MAAOkH,aAAYlH,KACnC,KAAK,MAAO,MAAOA,MAAKO,IACxB,KAAK,SACH,MAAO4G,YAAWnH,KACpB,KAAK,MACH,MAAO8G,SAAQQ,WAAa,EAC1B/M,MAAMwE,IAAIiB,KAAKF,QAASmH,4BAA4BlH,KAAKnF,UAAW,IAAIyM,KAAK,KACjF,KAAK,MACH,MAAOP,SAAQQ,WAAa,EAC1B/M,MAAMwE,IAAIiB,KAAKF,QAASmH,4BAA4BlH,KAAKnF,UAAW,IAAIyM,KAAK,KACjF,KAAK,OACH,MAAOP,SAAQQ,WAAa,EAC1BtH,KAAKO,KAAO,IAAMhG,MAAMwE,IAAIiB,KAAKnE,KAAMoL,4BAA4BlH,KAAKnF,UAAW,IAAIyM,KAAK,KAChG,KAAK,MACH,MAAOP,SAAQQ,WAAa,EAC1BL,4BAA4B,EAAGjH,KAAKkB,MAAQ,MAKpD,QAASqG,mBAAkBvH,MACzB,MAAOiH,6BAA4B,EAAGjH,MAIxC,QAASwH,aAAY/H,SACnB,GAAIvE,KAAM,EACV,KAAK,GAAIqF,QAAQd,SAAS,CACxBvE,KAAOqF,KAAO,MAAQhG,MAAMwE,IAAIU,QAAQc,MAAO0G,4BAA4BlH,KAAKnF,UAAW,IAAIyM,KAAK,OAEtG,MAAOnM,KAGTpC,OAAOD,SACL4O,UAAWF,kBACX9H,QAAS+H,eAGRzK,aAAa,KAAK2K,GAAG,SAAS3N,QAAQjB,OAAOD,SAQhD,YAEA,IAAI8O,UAAW,EAAG,EAAG,EAErB,IAAIpN,OAAQR,QAAQ,aACpB,IAAIiB,GAAIjB,QAAQ,kBAChB,IAAI8I,GAAI9I,QAAQ,eAChB,IAAIqG,GAAIrG,QAAQ,yBAChB,IAAI+I,MAAO/I,QAAQ,6BACnB,IAAI6N,MAAO7N,QAAQ,YACnB,IAAIgL,oBAAqBhL,QAAQ,qBAAqBgB,KACtD,IAAI2G,sBAAuBtB,EAAEuB,OAC7B,IAAIrC,+BAAgCc,EAAEwB,gBACtC,IAAI2E,WAAYxM,QAAQ,uBAAuBwM,SAI/C,SAASsB,eACP,KAAM,IAAI5N,OAAM,8BAGlB,GAAI6N,qBAAsB,mGAC1B,IAAIC,qBAAsB,6FAK1B,SAASlL,UAAS8C,QAChB,GAAIA,OAAOK,OAAS,MAAO,CAAE,MAAO,MACpC,GAAIL,OAAOK,OAAS,MAAO,CAAE,MAAO,MACpC,GAAIL,OAAOK,OAAS,MAAO,CAAE,MAAOL,QAAOG,QAAQtD,KAAKK,UACxD,MAAO,OAIT,QAASmL,YAAWrI,QAClB,MAAOA,QAAOgG,OAAS/K,UAAY+E,OAAO+F,OAAOrL,OAAS2H,SAI5D,QAASiG,YAAWtI,QAClB,GAAI8F,QAAS9F,OAAO+F,OAAOrL,MAC3B,KAAK,GAAIL,GAAIyL,OAAS,EAAGzL,GAAK,EAAGA,IAAK,CACpC,IAAK6C,SAAS8C,OAAO+F,OAAO1L,IAAK,CAC/B,MAEFyL,OAASzL,EAEX,MAAOyL,QAIT,QAASyC,gBAAe1I,YAAaC,SACnC,MAAOlF,OAAM4N,UAAU1I,QAAS,SAAUN,GACxC,MAAO5E,OAAMwE,IAAII,EAAGuC,qBAAqB3B,KAAKnF,UAAW4E,YAAaC,YAK1E,QAAS2I,mBAAkBpI,MACzB,IAAK8H,oBAAoB3E,KAAKnD,MAAO,CAAE,KAAM,IAAIgF,WAAU,0BAA4BhF,MACvF,GAAI/E,QAAS+E,KAAKiF,MAAM8C,oBACxB,IAAIpI,QAASkD,EAAE9H,MAAMwL,UAAWtL,OAChC,IAAI0E,SAAW/E,UAAW,CAAE,KAAM,IAAIoK,WAAU,0BAA4BhF,MAC5E,MAAOL,QAIT,QAAS0I,qBAAoB7I,YAAaG,QACxC,OACEY,KAAMZ,OAAOY,KACbd,QAASyI,eAAe1I,YAAaG,OAAOF,SAC5CiG,OAAQnL,MAAMwE,IAAIY,OAAO+F,OAAQhE,qBAAqB3B,KAAKnF,UAAW4E,YAAaG,OAAOF,UAC1FkG,KAAMhG,OAAOgG,MAAQjE,qBAAqBlC,YAAaG,OAAOF,QAASE,OAAOgG,MAC9EF,OAAQ/D,qBAAqBlC,YAAaG,OAAOF,QAASE,OAAO8F,QACjE6C,UAAWL,WAAWtI,QACtB4I,UAAWP,WAAWrI,SAK1B,QAAS6I,qBAAoB/I,QAASgJ,SAAUC,SAC9C,GAAI5I,SAAUL,QAAQiJ,QACtB,IAAI7M,MAAOtB,MAAMuB,MAAMC,UAAW,EAElC,KAAK,GAAI/B,GAAI,EAAGA,EAAI8F,QAAQzF,OAAQL,IAAK,CACvC,GAAI2O,QAAS7I,QAAQ9F,EACrB,IAAIkB,KAAMyN,OAAOvM,MAAMxB,WAAY6N,UAAU1H,OAAOlF,MACpD,IAAIX,IAAK,CACPuE,QAAQiJ,UAAYC,OACpB,OAAO,OAGX,MAAO,OAIT,QAASC,UAASpJ,YAAaQ,KAAM6I,QACnC,GAAIlJ,QAASyI,kBAAkBpI,KAC/B,IAAIyI,UAAWJ,oBAAoB7I,YAAaG,OAEhD,OAAO,YAEL,GAAI5D,UAAU1B,OAASoO,SAASH,WAAavM,UAAU1B,OAASoO,SAASF,UAAW,CAClF,GAAIE,SAASH,YAAcG,SAASF,UAAW,CAC7C,KAAM,IAAIvD,WAAU,YAAcyD,SAASlI,KAAO,YAAckI,SAASF,UAAY,eAAiBxM,UAAU1B,OAAS,cACpH,CACL,KAAM,IAAI2K,WAAU,YAAcyD,SAASlI,KAAO,YAAckI,SAASH,UAAY,IAAMG,SAASF,UAAY,eAAiBxM,UAAU1B,OAAS,WAIxJ,GAAIyO,gBAAiBN,oBAAoBzI,KAAKnF,UAAWL,MAAMwO,QAAQN,SAAShJ,SAChF,IAAIuJ,cAAezO,MAAM0O,EAAEH,eAG3B,KAAK,GAAI9O,GAAI,EAAGA,EAAI+B,UAAU1B,OAAQL,IAAK,CACzC,GAAI8G,UAAW9G,EAAIyO,SAAS/C,OAAOrL,OAASoO,SAAS/C,OAAO1L,GAAKyO,SAAS9C,IAC1E,IAAIuD,SAAWlP,EAAIyO,SAAS/C,OAAOrL,OAASsF,OAAO+F,OAAO1L,GAAK2F,OAAOgG,IACtE,KAAK7E,SAASkI,aAAcjN,UAAU/B,IAAK,CAEzC,KAAM,IAAIgL,WAAU,WAAarF,OAAOY,KAAO,KAAOvG,EAAE,GAAK,uBAAyB4N,KAAKH,UAAUyB,SAAW,iBAAmBtB,KAAKnI,QAAQE,OAAOF,SAAW,QAAU0J,KAAKC,UAAUrN,UAAU/B,MAKzM,GAAIN,GAAImP,OAAOzM,MAAM/C,KAAM0C,UAG3B,KAAK0M,SAAShD,OAAOuD,aAActP,GAAI,CAErC,KAAM,IAAIsL,WAAU,YAAcrF,OAAOY,KAAO,0BAA4BqH,KAAKH,UAAU9H,OAAO8F,QAAU,iBAAmBmC,KAAKnI,QAAQE,OAAOF,SAAW,QAAU/F,GAI1K,MAAOA,IAMX,QAASqB,OAAMsO,WAAY/H,QACzB,GAAItG,EAAEiD,SAASoL,YAAa,CAC1B,MAAOtE,oBAAmBsE,gBACrB,IAAIrO,EAAEuD,WAAW8K,YAAa,CACnC,MAAOvG,MAAKL,KAAK4G,gBACZ,IAAIrO,EAAE6D,QAAQwK,YAAa,CAChC,GAAIvJ,SAAUvF,MAAMwE,IAAIsK,WAAYtO,MACpC,OAAO+H,MAAKH,IAAI7C,aACuB,CACvC,GAAIuB,QAAS9G,MAAM4N,UAAUkB,WAAYtO,MACzC,OAAO+H,MAAKV,OAAOf,OAAQC,SAK/B,QAASd,OAAMhB,YAAaQ,KAAM+B,UAChC,GAAIhG,UAAU1B,SAAW,GAAK0B,UAAU1B,SAAW,EAAG,CACpD,KAAM,IAAI2K,WAAU,kCAAoCjJ,UAAU1B,OAAO,GAAK,aAGhF,GAAIsF,QAASoF,mBAAmB/E,KAGhC,IAAIyI,UAAW/G,qBAAqBlC,eAAiBG,OAErD,QAAQ5D,UAAU1B,QAChB,IAAK,GAAG,MAAO,UAAUiP,WACvB,MAAOb,UAASZ,YAAayB,aAAe,KAE9C,KAAK,GACH,MAAOb,UAASZ,YAAa9F,YAAc,MAIjD,QAASD,QAAOtC,YAAaQ,KAAM+B,UACjC,GAAIhG,UAAU1B,SAAW,GAAK0B,UAAU1B,SAAW,EAAG,CACpD,KAAM,IAAI2K,WAAU,mCAAqCjJ,UAAU1B,OAAO,GAAK,aAGjF,GAAIsF,QAASoF,mBAAmB/E,KAGhC,IAAIyI,UAAW/G,qBAAqBlC,eAAiBG,OAErD,QAAQ5D,UAAU1B,QAChB,IAAK,GAAG,MAAO,UAAUiP,WACvB,GAAIC,SAAUd,SAASZ,YAAayB,UACpC,IAAIC,UAAY,KAAM,CACpB,KAAM,IAAIvE,WAAUuE,UAGxB,KAAK,GACH,GAAI9D,QAASgD,SAASZ,YAAa9F,SACnC,IAAI0D,SAAW,KAAM,CACnB,KAAM,IAAIT,WAAUS,UAO5B,QAAS+D,gBAAehK,YAAaG,OAAQ2B,QAC3C,GAAImI,OAAQ9C,OAAO+C,KAAK/J,OACxB8J,OAAMpF,QAAQ,SAAU9D,MACtB,GAAIf,YAAYc,IAAIC,MAAO,CAAE,KAAM,IAAItG,OAAMsG,KAAO,yBAGtD,IAAIkI,UAAWlO,MAAM4N,UAAUxI,OAAQL,8BAA8BS,KAAKnF,UAAW4E,eAAiBiK,OACtG,IAAIE,QAASpP,MAAM4N,UAAUM,SAAU,SAAUjI,OAC/C,MAAOA,OAAMT,KAAKnF,UAAW6N,SAAUZ,cAGzCrI,aAAYoK,IAAID,QAGlB,QAASE,SAAQrK,YAAae,KAAM8I,WAAY/H,QAC9C,GAAI3B,UACJA,QAAOY,MAAQxF,MAAMsO,WAAY/H,OACjC,OAAOkI,gBAAehK,YAAaG,QAIrC,QAASmK,QAAOtK,YAAauK,aAC3B,GAAIpK,QAASpF,MAAM4N,UAAU4B,YAAahP,MAC1C,OAAOyO,gBAAehK,YAAaG,QAGrC,QAASqK,KAAIxK,YAAae,KAAMwJ,aAC9B,GAAIxP,MAAM+F,IAAIyJ,YAAaxJ,MAAO,CAChC,KAAM,IAAItG,OAAM,qDAGlB,GAAIgQ,cAAetD,OAAO+C,KAAKK,YAC/B,IAAIpK,QAASpF,MAAM4N,UAAU4B,YAAahP,MAC1C4E,QAAOY,MAAQxF,MAAMkP,aAErB,OAAOT,gBAAehK,YAAaG,QAGrC,QAASuK,UAAS1K,YAAae,KAAM4J,KACnC,MAAON,SAAQrK,YAAae,KAAM,SAAUJ,KAC1C,MAAOA,eAAegK,OAI1B,QAASC,MAAK5K,YAAa1G,OAAQuR,YACjC,IAAK,GAAI7L,MAAM6L,YAAY,CACzBvR,OAAO0F,IAAMoK,SAASpJ,YAAahB,GAAK,OAAS6L,WAAW7L,IAAK1F,OAAO0F,KAG1E,MAAO1F,QAGT,GAAIwR,cAAevQ,QAAQ,eAI3B,SAASwQ,eACPlR,KAAKmR,SAGPD,YAAY3D,UAAUtG,IAAM,QAASmK,gBAAezK,MAClD,MAAOzF,OAAM+F,IAAIjH,KAAKmR,MAAOxK,OAASzF,MAAM+F,IAAIgK,aAActK,MAGhEuK,aAAY3D,UAAUnG,IAAM,QAASiK,gBAAe1K,MAClD,MAAO3G,MAAKmR,MAAMxK,OAASsK,aAAatK,MAG1CuK,aAAY3D,UAAUgD,IAAM,QAASe,gBAAehB,QAClDhD,OAAO+C,KAAKC,QAAQtF,QAAQ,SAAUrE,MACpC3G,KAAKmR,MAAMxK,MAAQ2J,OAAO3J,OACzB3G,MAIL,IAAIuR,kBAEF5K,KAAM,oBAIN6K,MAAO,wBACPzI,OAAQ,wCACR0H,OAAQ,kBACRI,SAAU,oBACVE,KAAM,uBACNJ,IAAK,4BAMP,SAASc,UACP,GAAIC,KAAM,GAAIR,YAEd,IAAIS,QAASpC,SAAS7I,KAAKnF,UAAWmQ,IACtCC,QAAOhL,KAAO6J,QAAQ9J,KAAKnF,UAAWmQ,IACtCC,QAAOH,MAAQhB,QAAQ9J,KAAKnF,UAAWmQ,IACvCC,QAAO5I,OAASyH,QAAQ9J,KAAKnF,UAAWmQ,IACxCC,QAAOlB,OAASA,OAAO/J,KAAKnF,UAAWmQ,IACvCC,QAAOhB,IAAMA,IAAIjK,KAAKnF,UAAWmQ,IACjCC,QAAOd,SAAWA,SAASnK,KAAKnF,UAAWmQ,IAC3CC,QAAOxK,MAAQA,MAAMT,KAAKnF,UAAWmQ,IACrCC,QAAOlJ,OAASA,OAAO/B,KAAKnF,UAAWmQ,IACvCC,QAAOZ,KAAOA,KAAKrK,KAAKnF,UAAWmQ,IACnCC,QAAOC,QAAUtD,OAIjBqD,QAAOF,OAASA,MAEhB,OAAOE,QAAOZ,KAAKY,OAAQJ,iBAI7B9R,OAAOD,QAAUiS,WAEd5F,eAAe,EAAEgG,eAAe,EAAEC,yBAAyB,EAAEhG,6BAA6B,EAAEqB,oBAAoB,EAAE4E,sBAAsB,EAAEhM,kBAAkB,EAAEiM,YAAY,EAAEtO,aAAa,KAAKuO,IAAI,SAASvR,QAAQjB,OAAOD,SAC7N,YAIA,SAASyH,KAAIiL,OAAQC,UACnB,MAAO7E,QAAOC,UAAU6E,eAAerR,KAAKmR,OAAQC,UAItD,QAAS9K,UAAS/B,MAAO+M,SACvB,MAAO/M,OAAMgN,QAAQD,YAAc,EAKrC,QAAS3C,SAAQ3E,KACf,GAAIlJ,OACJ,KAAK,GAAI8I,KAAKI,KAAK,CACjBlJ,IAAI8I,GAAKI,IAAIJ,GAEf,MAAO9I,KAKT,QAAS+D,QAAOmF,KACd,GAAIlJ,OACJ,KAAK,GAAI8I,KAAKI,KAAK,CACjB,GAAI9D,IAAI8D,IAAKJ,GAAI,CACf9I,IAAIqB,KAAK6H,IAAIJ,KAGjB,MAAO9I,KAIT,QAASiN,WAAU/D,IAAKxL,GACtB,GAAIsC,OACJ,KAAK,GAAI8I,KAAKI,KAAK,CACjB,GAAI9D,IAAI8D,IAAKJ,GAAI,CACf9I,IAAI8I,GAAKpL,EAAEwL,IAAIJ,KAGnB,MAAO9I,KAIT,QAASY,OAAM6C,MAAOlF,EAAGmS,GACvB,MAAOzP,OAAMyK,UAAU9K,MAAM1B,KAAKuE,MAAOlF,EAAGmS,GAI9C,QAAS7M,KAAIJ,MAAO/F,GAClB,MAAO+F,OAAMI,IAAI,SAAUpD,GACzB,MAAO/C,GAAE+C,KAQb,QAASmD,OAAMH,MAAO/F,GACpB,GAAIiT,KAAM,IACV,KAAK,GAAI7R,GAAI,EAAGA,EAAI2E,MAAMtE,OAAQL,IAAK,CACrC6R,IAAMA,KAAOjT,EAAE+F,MAAM3E,GACrB,KAAK6R,IAAK,CACR,MAAOA,MAGX,MAAOA,KAIT,QAAS5C,GAAErQ,GAET,QAASoC,GAAE8Q,GACT,MAAO,YACL,GAAIjQ,MAAOM,MAAMyK,UAAU9K,MAAM1B,KAAK2B,UACtC,OAAOnD,GAAEwD,MAAMxB,WAAYkR,EAAEA,IAAI/K,OAAOlF,QAG5C,MAAOb,GAAEA,GAKXlC,OAAOD,SACLyH,IAAKA,IACLI,SAAUA,SACVqI,QAASA,QACT9J,OAAQA,OACRkJ,UAAWA,UACXrM,MAAOA,MACPiD,IAAKA,IACLD,MAAOA,MACPmK,EAAGA,QAGC8C,IAAI,SAAShS,QAAQjB,OAAOD,SA4BlC,GAAImT,MAAOjS,QAAQ,QAEnB,IAAIkS,QAAS9P,MAAMyK,UAAU9K,KAC7B,IAAIoQ,QAASvF,OAAOC,UAAU6E,cAM9B,IAAI3J,QAAShJ,OAAOD,QAAUsT,EAO9BrK,QAAOsK,eAAiB,QAASA,gBAAetM,SAC9CzG,KAAKkH,KAAO,gBACZlH,MAAKgT,OAASvM,QAAQuM,MACtBhT,MAAKiT,SAAWxM,QAAQwM,QACxBjT,MAAKuG,SAAWE,QAAQF,QACxB,IAAIE,QAAQyM,QAAS,CACnBlT,KAAKkT,QAAUzM,QAAQyM,OACvBlT,MAAKmT,iBAAmB,UACnB,CACLnT,KAAKkT,QAAUE,WAAWpT,KAC1BA,MAAKmT,iBAAmB,KAE1B,GAAIE,oBAAqB5M,QAAQ4M,oBAAsBC,IAEvD,IAAI1S,MAAM2S,kBAAmB,CAC3B3S,MAAM2S,kBAAkBvT,KAAMqT,wBAE3B,CAEH,GAAIG,KAAM,GAAI5S,MACd,IAAI4S,IAAIC,MAAO,CACb,GAAIC,KAAMF,IAAIC,KAGd,IAAIE,SAAUN,mBAAmBnM,IACjC,IAAInF,KAAM2R,IAAIpB,QAAQ,KAAOqB,QAC7B,IAAI5R,KAAO,EAAG,CAGZ,GAAI6R,WAAYF,IAAIpB,QAAQ,KAAMvQ,IAAM,EACxC2R,KAAMA,IAAIG,UAAUD,UAAY,GAGlC5T,KAAKyT,MAAQC,MAMnBf,MAAKmB,SAASrL,OAAOsK,eAAgBnS,MAErC,SAASmT,UAAS5L,IAAK7G,OACrB,GAAIqR,KAAKqB,YAAY1S,OAAQ,CAC3B,MAAO,GAAKA,MAEd,GAAIqR,KAAK9O,SAASvC,SAAWkD,SAASlD,OAAQ,CAC5C,MAAOA,OAAM+L,WAEf,GAAIsF,KAAKzN,WAAW5D,QAAUqR,KAAK3N,SAAS1D,OAAQ,CAClD,MAAOA,OAAM+L,WAEf,MAAO/L,OAGT,QAAS2S,UAAS3T,EAAGF,GACnB,GAAIuS,KAAK/N,SAAStE,GAAI,CACpB,MAAOA,GAAEU,OAASZ,EAAIE,EAAIA,EAAEmC,MAAM,EAAGrC,OAChC,CACL,MAAOE,IAIX,QAAS8S,YAAWrT,MAClB,MAAOkU,UAASnE,KAAKC,UAAUhQ,KAAKiT,OAAQe,UAAW,KAAO,IACvDhU,KAAKwG,SAAW,IAChB0N,SAASnE,KAAKC,UAAUhQ,KAAKkT,SAAUc,UAAW,KAc3D,QAAST,MAAKN,OAAQC,SAAUC,QAAS3M,SAAU8M,oBACjD,KAAM,IAAI5K,QAAOsK,gBACfG,QAASA,QACTF,OAAQA,OACRC,SAAUA,SACV1M,SAAUA,SACV8M,mBAAoBA,qBAKxB5K,OAAO6K,KAAOA,IASd,SAASR,IAAGxR,MAAO4R,SACjB,IAAK5R,MAAOgS,KAAKhS,MAAO,KAAM4R,QAAS,KAAMzK,OAAOqK,IAEtDrK,OAAOqK,GAAKA,EAMZrK,QAAOyL,MAAQ,QAASA,OAAMlB,OAAQC,SAAUC,SAC9C,GAAIF,QAAUC,SAAUK,KAAKN,OAAQC,SAAUC,QAAS,KAAMzK,OAAOyL,OAMvEzL,QAAO0L,SAAW,QAASA,UAASnB,OAAQC,SAAUC,SACpD,GAAIF,QAAUC,SAAU,CACtBK,KAAKN,OAAQC,SAAUC,QAAS,KAAMzK,OAAO0L,WAOjD1L,QAAO2L,UAAY,QAASA,WAAUpB,OAAQC,SAAUC,SACtD,IAAKmB,WAAWrB,OAAQC,UAAW,CACjCK,KAAKN,OAAQC,SAAUC,QAAS,YAAazK,OAAO2L,YAIxD,SAASC,YAAWrB,OAAQC,UAE1B,GAAID,SAAWC,SAAU,CACvB,MAAO,UAEF,IAAIN,KAAK2B,SAAStB,SAAWL,KAAK2B,SAASrB,UAAW,CAC3D,GAAID,OAAOhS,QAAUiS,SAASjS,OAAQ,MAAO,MAE7C,KAAK,GAAIL,GAAI,EAAGA,EAAIqS,OAAOhS,OAAQL,IAAK,CACtC,GAAIqS,OAAOrS,KAAOsS,SAAStS,GAAI,MAAO,OAGxC,MAAO,UAIF,IAAIgS,KAAK7N,OAAOkO,SAAWL,KAAK7N,OAAOmO,UAAW,CACvD,MAAOD,QAAOuB,YAActB,SAASsB,cAKhC,IAAI5B,KAAK3N,SAASgO,SAAWL,KAAK3N,SAASiO,UAAW,CAC3D,MAAOD,QAAOwB,SAAWvB,SAASuB,QAC3BxB,OAAOlT,SAAWmT,SAASnT,QAC3BkT,OAAOyB,YAAcxB,SAASwB,WAC9BzB,OAAO0B,YAAczB,SAASyB,WAC9B1B,OAAO2B,aAAe1B,SAAS0B,eAIjC,KAAKhC,KAAKhN,SAASqN,UAAYL,KAAKhN,SAASsN,UAAW,CAC7D,MAAOD,SAAUC,aAQZ,CACL,MAAO2B,UAAS5B,OAAQC,WAI5B,QAAS7N,aAAY8M,QACnB,MAAO5E,QAAOC,UAAUF,SAAStM,KAAKmR,SAAW,qBAGnD,QAAS0C,UAASnU,EAAGwI,GACnB,GAAI0J,KAAKkC,kBAAkBpU,IAAMkS,KAAKkC,kBAAkB5L,GACtD,MAAO,MAET,IAAIxI,EAAE8M,YAActE,EAAEsE,UAAW,MAAO,MAExC,IAAIoF,KAAKmC,YAAYrU,IAAMkS,KAAKmC,YAAY7L,GAAI,CAC9C,MAAOxI,KAAMwI,EAEf,GAAI8L,SAAU3P,YAAY3E,GACtBuU,QAAU5P,YAAY6D,EAC1B,IAAK8L,UAAYC,UAAcD,SAAWC,QACxC,MAAO,MACT,IAAID,QAAS,CACXtU,EAAImS,OAAO7R,KAAKN,EAChBwI,GAAI2J,OAAO7R,KAAKkI,EAChB,OAAOoL,YAAW5T,EAAGwI,GAEvB,GAAIgM,IAAKC,WAAWzU,GAChB0U,GAAKD,WAAWjM,GAChBd,IAAKxH,CAGT,IAAIsU,GAAGjU,QAAUmU,GAAGnU,OAClB,MAAO,MAETiU,IAAGG,MACHD,IAAGC,MAEH,KAAKzU,EAAIsU,GAAGjU,OAAS,EAAGL,GAAK,EAAGA,IAAK,CACnC,GAAIsU,GAAGtU,IAAMwU,GAAGxU,GACd,MAAO,OAIX,IAAKA,EAAIsU,GAAGjU,OAAS,EAAGL,GAAK,EAAGA,IAAK,CACnCwH,IAAM8M,GAAGtU,EACT,KAAK0T,WAAW5T,EAAE0H,KAAMc,EAAEd,MAAO,MAAO,OAE1C,MAAO,MAMTM,OAAO4M,aAAe,QAASA,cAAarC,OAAQC,SAAUC,SAC5D,GAAImB,WAAWrB,OAAQC,UAAW,CAChCK,KAAKN,OAAQC,SAAUC,QAAS,eAAgBzK,OAAO4M,eAO3D5M,QAAO6M,YAAc,QAASA,aAAYtC,OAAQC,SAAUC,SAC1D,GAAIF,SAAWC,SAAU,CACvBK,KAAKN,OAAQC,SAAUC,QAAS,MAAOzK,OAAO6M,cAOlD7M,QAAO8M,eAAiB,QAASA,gBAAevC,OAAQC,SAAUC,SAChE,GAAIF,SAAWC,SAAU,CACvBK,KAAKN,OAAQC,SAAUC,QAAS,MAAOzK,OAAO8M,iBAIlD,SAASC,mBAAkBxC,OAAQC,UACjC,IAAKD,SAAWC,SAAU,CACxB,MAAO,OAGT,GAAI3F,OAAOC,UAAUF,SAAStM,KAAKkS,WAAa,kBAAmB,CACjE,MAAOA,UAASnJ,KAAKkJ,YAChB,IAAIA,iBAAkBC,UAAU,CACrC,MAAO,UACF,IAAIA,SAASlS,QAASiS,UAAY,KAAM,CAC7C,MAAO,MAGT,MAAO,OAGT,QAASyC,SAAQC,YAAaC,MAAO1C,SAAUC,SAC7C,GAAIF,OAEJ,IAAIL,KAAK/N,SAASqO,UAAW,CAC3BC,QAAUD,QACVA,UAAW,KAGb,IACE0C,QACA,MAAOzV,GACP8S,OAAS9S,EAGXgT,SAAWD,UAAYA,SAAS/L,KAAO,KAAO+L,SAAS/L,KAAO,KAAO,MAC1DgM,QAAU,IAAMA,QAAU,IAErC,IAAIwC,cAAgB1C,OAAQ,CAC1BM,KAAKN,OAAQC,SAAU,6BAA+BC,SAGxD,IAAKwC,aAAeF,kBAAkBxC,OAAQC,UAAW,CACvDK,KAAKN,OAAQC,SAAU,yBAA2BC,SAGpD,GAAKwC,aAAe1C,QAAUC,WACzBuC,kBAAkBxC,OAAQC,YAAgByC,aAAe1C,OAAS,CACrE,KAAMA,SAOVvK,OAAOmN,OAAS,SAASD,MAAmBE,MAAmB3C,SAC7DuC,QAAQ1S,MAAM/C,MAAO,MAAM0H,OAAOkL,OAAO7R,KAAK2B,aAIhD+F,QAAOqN,aAAe,SAASH,MAAmBzC,SAChDuC,QAAQ1S,MAAM/C,MAAO,OAAO0H,OAAOkL,OAAO7R,KAAK2B,aAGjD+F,QAAOsN,QAAU,SAASvC,KAAO,GAAIA,IAAK,CAAC,KAAMA,MAEjD,IAAI0B,YAAa5H,OAAO+C,MAAQ,SAAUtF,KACxC,GAAIsF,QACJ,KAAK,GAAIlI,OAAO4C,KAAK,CACnB,GAAI8H,OAAO9R,KAAKgK,IAAK5C,KAAMkI,KAAKnN,KAAKiF,KAEvC,MAAOkI,SAGN2F,QAAQ,KAAKC,IAAI,SAASvV,QAAQjB,OAAOD,SAC5C,SAAW8N,QAAOmE,SAAW,WAAY,CAEvChS,OAAOD,QAAU,QAASsU,UAASoC,KAAMC,WACvCD,KAAKE,OAASD,SACdD,MAAK3I,UAAYD,OAAOmE,OAAO0E,UAAU5I,WACvC8I,aACE/U,MAAO4U,KACPI,WAAY,MACZC,SAAU,KACVC,aAAc,aAIf,CAEL/W,OAAOD,QAAU,QAASsU,UAASoC,KAAMC,WACvCD,KAAKE,OAASD,SACd,IAAIM,UAAW,YACfA,UAASlJ,UAAY4I,UAAU5I,SAC/B2I,MAAK3I,UAAY,GAAIkJ,SACrBP,MAAK3I,UAAU8I,YAAcH,YAI3BQ,IAAI,SAAShW,QAAQjB,OAAOD,SAGlC,GAAImX,SAAUlX,OAAOD,UACrB,IAAIoX,SACJ,IAAIC,UAAW,KAEf,SAASC,cACL,GAAID,SAAU,CACV,OAEJA,SAAW,IACX,IAAIE,aACJ,IAAIpU,KAAMiU,MAAM5V,MAChB,OAAM2B,IAAK,CACPoU,aAAeH,KACfA,SACA,IAAIjW,IAAK,CACT,SAASA,EAAIgC,IAAK,CACdoU,aAAapW,KAEjBgC,IAAMiU,MAAM5V,OAEhB6V,SAAW,MAEfF,QAAQK,SAAW,SAAUC,KACzBL,MAAM1T,KAAK+T,IACX,KAAKJ,SAAU,CACXK,WAAWJ,WAAY,IAI/BH,SAAQQ,MAAQ,SAChBR,SAAQS,QAAU,IAClBT,SAAQjF,MACRiF,SAAQU,OACRV,SAAQ/E,QAAU,EAClB+E,SAAQW,WAER,SAASC,SAETZ,QAAQa,GAAKD,IACbZ,SAAQc,YAAcF,IACtBZ,SAAQe,KAAOH,IACfZ,SAAQgB,IAAMJ,IACdZ,SAAQiB,eAAiBL,IACzBZ,SAAQkB,mBAAqBN,IAC7BZ,SAAQmB,KAAOP,IAEfZ,SAAQoB,QAAU,SAAU7Q,MACxB,KAAM,IAAItG,OAAM,oCAIpB+V,SAAQqB,IAAM,WAAc,MAAO,IACnCrB,SAAQsB,MAAQ,SAAUC,KACtB,KAAM,IAAItX,OAAM,kCAEpB+V,SAAQwB,MAAQ,WAAa,MAAO,SAE9BC,IAAI,SAAS1X,QAAQjB,OAAOD,SAClCC,OAAOD,QAAU,QAAS8U,UAASxN,KACjC,MAAOA,YAAcA,OAAQ,gBACjBA,KAAIuR,OAAS,kBACbvR,KAAIwR,OAAS,kBACbxR,KAAIyR,YAAc,iBAE1BC,IAAI,SAAS9X,QAAQjB,OAAOD,UAClC,SAAWmX,QAAQ7W,QAsBnB,GAAI2Y,cAAe,UACnBjZ,SAAQkZ,OAAS,SAASnZ;AACxB,IAAKqF,SAASrF,GAAI,CAChB,GAAIoZ,WACJ,KAAK,GAAIhY,GAAI,EAAGA,EAAI+B,UAAU1B,OAAQL,IAAK,CACzCgY,QAAQzV,KAAK0V,QAAQlW,UAAU/B,KAEjC,MAAOgY,SAAQ3K,KAAK,KAGtB,GAAIrN,GAAI,CACR,IAAI6B,MAAOE,SACX,IAAIC,KAAMH,KAAKxB,MACf,IAAI2M,KAAMkL,OAAOtZ,GAAGuZ,QAAQL,aAAc,SAASnW,GACjD,GAAIA,IAAM,KAAM,MAAO,GACvB,IAAI3B,GAAKgC,IAAK,MAAOL,EACrB,QAAQA,GACN,IAAK,KAAM,MAAOuW,QAAOrW,KAAK7B,KAC9B,KAAK,KAAM,MAAOoY,QAAOvW,KAAK7B,KAC9B,KAAK,KACH,IACE,MAAOmP,MAAKC,UAAUvN,KAAK7B,MAC3B,MAAOqY,GACP,MAAO,aAEX,QACE,MAAO1W,KAGb,KAAK,GAAIA,GAAIE,KAAK7B,GAAIA,EAAIgC,IAAKL,EAAIE,OAAO7B,GAAI,CAC5C,GAAIsY,OAAO3W,KAAOqD,SAASrD,GAAI,CAC7BqL,KAAO,IAAMrL,MACR,CACLqL,KAAO,IAAMiL,QAAQtW,IAGzB,MAAOqL,KAOTnO,SAAQ0Z,UAAY,SAAS/T,GAAIgU,KAE/B,GAAInF,YAAYlU,OAAO6W,SAAU,CAC/B,MAAO,YACL,MAAOnX,SAAQ0Z,UAAU/T,GAAIgU,KAAKpW,MAAM/C,KAAM0C,YAIlD,GAAIiU,QAAQyC,gBAAkB,KAAM,CAClC,MAAOjU,IAGT,GAAIkU,QAAS,KACb,SAASC,cACP,IAAKD,OAAQ,CACX,GAAI1C,QAAQ4C,iBAAkB,CAC5B,KAAM,IAAI3Y,OAAMuY,SACX,IAAIxC,QAAQ6C,iBAAkB,CACnCC,QAAQC,MAAMP,SACT,CACLM,QAAQ5D,MAAMsD,KAEhBE,OAAS,KAEX,MAAOlU,IAAGpC,MAAM/C,KAAM0C,WAGxB,MAAO4W,YAIT,IAAIK,UACJ,IAAIC,aACJpa,SAAQqa,SAAW,SAASC,KAC1B,GAAI9F,YAAY4F,cACdA,aAAejD,QAAQjF,IAAIqI,YAAc,EAC3CD,KAAMA,IAAIE,aACV,KAAKL,OAAOG,KAAM,CAChB,GAAI,GAAIG,QAAO,MAAQH,IAAM,MAAO,KAAKhQ,KAAK8P,cAAe,CAC3D,GAAIM,KAAMvD,QAAQuD,GAClBP,QAAOG,KAAO,WACZ,GAAIX,KAAM3Z,QAAQkZ,OAAO3V,MAAMvD,QAASkD,UACxC+W,SAAQ5D,MAAM,YAAaiE,IAAKI,IAAKf,UAElC,CACLQ,OAAOG,KAAO,cAGlB,MAAOH,QAAOG,KAYhB,SAASlB,SAAQ7N,IAAKoP,MAEpB,GAAIC,MACFC,QACAC,QAASC,eAGX,IAAI7X,UAAU1B,QAAU,EAAGoZ,IAAII,MAAQ9X,UAAU,EACjD,IAAIA,UAAU1B,QAAU,EAAGoZ,IAAIK,OAAS/X,UAAU,EAClD,IAAIgC,UAAUyV,MAAO,CAEnBC,IAAIM,WAAaP,SACZ,IAAIA,KAAM,CAEf3a,QAAQmb,QAAQP,IAAKD,MAGvB,GAAInG,YAAYoG,IAAIM,YAAaN,IAAIM,WAAa,KAClD,IAAI1G,YAAYoG,IAAII,OAAQJ,IAAII,MAAQ,CACxC,IAAIxG,YAAYoG,IAAIK,QAASL,IAAIK,OAAS,KAC1C,IAAIzG,YAAYoG,IAAIQ,eAAgBR,IAAIQ,cAAgB,IACxD,IAAIR,IAAIK,OAAQL,IAAIE,QAAUO,gBAC9B,OAAOC,aAAYV,IAAKrP,IAAKqP,IAAII,OAEnChb,QAAQoZ,QAAUA,OAIlBA,SAAQ6B,QACNM,MAAU,EAAG,IACbC,QAAY,EAAG,IACfC,WAAe,EAAG,IAClBC,SAAa,EAAG,IAChBC,OAAW,GAAI,IACfC,MAAU,GAAI,IACdC,OAAW,GAAI,IACfC,MAAU,GAAI,IACdC,MAAU,GAAI,IACdC,OAAW,GAAI,IACfC,SAAa,GAAI,IACjBC,KAAS,GAAI,IACbC,QAAY,GAAI,IAIlB/C,SAAQgD,QACNC,QAAW,OACXjY,OAAU,SACVa,UAAW,SACXlD,UAAa,OACbua,OAAQ,OACRnX,OAAU,QACVE,KAAQ,UAERE,OAAU,MAIZ,SAAS8V,kBAAiBlN,IAAKoO,WAC7B,GAAIC,OAAQpD,QAAQgD,OAAOG,UAE3B,IAAIC,MAAO,CACT,MAAO,KAAYpD,QAAQ6B,OAAOuB,OAAO,GAAK,IAAMrO,IAC7C,KAAYiL,QAAQ6B,OAAOuB,OAAO,GAAK,QACzC,CACL,MAAOrO,MAKX,QAAS4M,gBAAe5M,IAAKoO,WAC3B,MAAOpO,KAIT,QAASsO,aAAY3W,OACnB,GAAI4W,QAEJ5W,OAAM0F,QAAQ,SAAS/G,IAAKlC,KAC1Bma,KAAKjY,KAAO,MAGd,OAAOiY,MAIT,QAASpB,aAAYV,IAAK9Y,MAAO6a,cAG/B,GAAI/B,IAAIQ,eACJtZ,OACA4D,WAAW5D,MAAMsX,UAEjBtX,MAAMsX,UAAYpZ,QAAQoZ,WAExBtX,MAAM+U,aAAe/U,MAAM+U,YAAY9I,YAAcjM,OAAQ,CACjE,GAAI8a,KAAM9a,MAAMsX,QAAQuD,aAAc/B,IACtC,KAAKxV,SAASwX,KAAM,CAClBA,IAAMtB,YAAYV,IAAKgC,IAAKD,cAE9B,MAAOC,KAIT,GAAIC,WAAYC,gBAAgBlC,IAAK9Y,MACrC,IAAI+a,UAAW,CACb,MAAOA,WAIT,GAAIhM,MAAO/C,OAAO+C,KAAK/O,MACvB,IAAIib,aAAcN,YAAY5L,KAE9B,IAAI+J,IAAIM,WAAY,CAClBrK,KAAO/C,OAAOkP,oBAAoBlb,OAKpC,GAAImb,QAAQnb,SACJ+O,KAAKiC,QAAQ,YAAc,GAAKjC,KAAKiC,QAAQ,gBAAkB,GAAI,CACzE,MAAOoK,aAAYpb,OAIrB,GAAI+O,KAAKrP,SAAW,EAAG,CACrB,GAAIkE,WAAW5D,OAAQ,CACrB,GAAI4F,MAAO5F,MAAM4F,KAAO,KAAO5F,MAAM4F,KAAO,EAC5C,OAAOkT,KAAIE,QAAQ,YAAcpT,KAAO,IAAK,WAE/C,GAAIlC,SAAS1D,OAAQ,CACnB,MAAO8Y,KAAIE,QAAQL,OAAO1M,UAAUF,SAAStM,KAAKO,OAAQ,UAE5D,GAAIwD,OAAOxD,OAAQ,CACjB,MAAO8Y,KAAIE,QAAQqC,KAAKpP,UAAUF,SAAStM,KAAKO,OAAQ,QAE1D,GAAImb,QAAQnb,OAAQ,CAClB,MAAOob,aAAYpb,QAIvB,GAAIsb,MAAO,GAAItX,MAAQ,MAAOuX,QAAU,IAAK,IAG7C,IAAIrX,QAAQlE,OAAQ,CAClBgE,MAAQ,IACRuX,SAAU,IAAK,KAIjB,GAAI3X,WAAW5D,OAAQ,CACrB,GAAIlB,GAAIkB,MAAM4F,KAAO,KAAO5F,MAAM4F,KAAO,EACzC0V,MAAO,aAAexc,EAAI,IAI5B,GAAI4E,SAAS1D,OAAQ,CACnBsb,KAAO,IAAM3C,OAAO1M,UAAUF,SAAStM,KAAKO,OAI9C,GAAIwD,OAAOxD,OAAQ,CACjBsb,KAAO,IAAMD,KAAKpP,UAAUuP,YAAY/b,KAAKO,OAI/C,GAAImb,QAAQnb,OAAQ,CAClBsb,KAAO,IAAMF,YAAYpb,OAG3B,GAAI+O,KAAKrP,SAAW,KAAOsE,OAAShE,MAAMN,QAAU,GAAI,CACtD,MAAO6b,QAAO,GAAKD,KAAOC,OAAO,GAGnC,GAAIV,aAAe,EAAG,CACpB,GAAInX,SAAS1D,OAAQ,CACnB,MAAO8Y,KAAIE,QAAQL,OAAO1M,UAAUF,SAAStM,KAAKO,OAAQ,cACrD,CACL,MAAO8Y,KAAIE,QAAQ,WAAY,YAInCF,IAAIC,KAAKnX,KAAK5B,MAEd,IAAIyb,OACJ,IAAIzX,MAAO,CACTyX,OAASC,YAAY5C,IAAK9Y,MAAO6a,aAAcI,YAAalM,UACvD,CACL0M,OAAS1M,KAAK3K,IAAI,SAASyC,KACzB,MAAO8U,gBAAe7C,IAAK9Y,MAAO6a,aAAcI,YAAapU,IAAK7C,SAItE8U,IAAIC,KAAK6C,KAET,OAAOC,sBAAqBJ,OAAQH,KAAMC,QAI5C,QAASP,iBAAgBlC,IAAK9Y,OAC5B,GAAI0S,YAAY1S,OACd,MAAO8Y,KAAIE,QAAQ,YAAa,YAClC,IAAI1V,SAAStD,OAAQ,CACnB,GAAI8b,QAAS,IAAOtN,KAAKC,UAAUzO,OAAOwX,QAAQ,SAAU,IAClBA,QAAQ,KAAM,OACdA,QAAQ,OAAQ,KAAO,GACjE,OAAOsB,KAAIE,QAAQ8C,OAAQ,UAE7B,GAAIvZ,SAASvC,OACX,MAAO8Y,KAAIE,QAAQ,GAAKhZ,MAAO,SACjC,IAAIoD,UAAUpD,OACZ,MAAO8Y,KAAIE,QAAQ,GAAKhZ,MAAO,UAEjC,IAAI2X,OAAO3X,OACT,MAAO8Y,KAAIE,QAAQ,OAAQ,QAI/B,QAASoC,aAAYpb,OACnB,MAAO,IAAMV,MAAM2M,UAAUF,SAAStM,KAAKO,OAAS,IAItD,QAAS0b,aAAY5C,IAAK9Y,MAAO6a,aAAcI,YAAalM,MAC1D,GAAI0M,UACJ,KAAK,GAAIpc,GAAI,EAAGG,EAAIQ,MAAMN,OAAQL,EAAIG,IAAKH,EAAG,CAC5C,GAAIyR,eAAe9Q,MAAOuX,OAAOlY,IAAK,CACpCoc,OAAO7Z,KAAK+Z,eAAe7C,IAAK9Y,MAAO6a,aAAcI,YACjD1D,OAAOlY,GAAI,WACV,CACLoc,OAAO7Z,KAAK,KAGhBmN,KAAKrF,QAAQ,SAAS7C,KACpB,IAAKA,IAAIyD,MAAM,SAAU,CACvBmR,OAAO7Z,KAAK+Z,eAAe7C,IAAK9Y,MAAO6a,aAAcI,YACjDpU,IAAK,SAGb,OAAO4U,QAIT,QAASE,gBAAe7C,IAAK9Y,MAAO6a,aAAcI,YAAapU,IAAK7C,OAClE,GAAI4B,MAAMyG,IAAK0P,IACfA,MAAO/P,OAAOgQ,yBAAyBhc,MAAO6G,OAAU7G,MAAOA,MAAM6G,KACrE,IAAIkV,KAAKjW,IAAK,CACZ,GAAIiW,KAAKvD,IAAK,CACZnM,IAAMyM,IAAIE,QAAQ,kBAAmB,eAChC,CACL3M,IAAMyM,IAAIE,QAAQ,WAAY,gBAE3B,CACL,GAAI+C,KAAKvD,IAAK,CACZnM,IAAMyM,IAAIE,QAAQ,WAAY,YAGlC,IAAKlI,eAAemK,YAAapU,KAAM,CACrCjB,KAAO,IAAMiB,IAAM,IAErB,IAAKwF,IAAK,CACR,GAAIyM,IAAIC,KAAK/H,QAAQ+K,KAAK/b,OAAS,EAAG,CACpC,GAAI2X,OAAOkD,cAAe,CACxBxO,IAAMmN,YAAYV,IAAKiD,KAAK/b,MAAO,UAC9B,CACLqM,IAAMmN,YAAYV,IAAKiD,KAAK/b,MAAO6a,aAAe,GAEpD,GAAIxO,IAAI2E,QAAQ,OAAS,EAAG,CAC1B,GAAIhN,MAAO,CACTqI,IAAMA,IAAI4P,MAAM,MAAM7X,IAAI,SAAS8X,MACjC,MAAO,KAAOA,OACbxP,KAAK,MAAM3D,OAAO,OAChB,CACLsD,IAAM,KAAOA,IAAI4P,MAAM,MAAM7X,IAAI,SAAS8X,MACxC,MAAO,MAAQA,OACdxP,KAAK,YAGP,CACLL,IAAMyM,IAAIE,QAAQ,aAAc,YAGpC,GAAItG,YAAY9M,MAAO,CACrB,GAAI5B,OAAS6C,IAAIyD,MAAM,SAAU,CAC/B,MAAO+B,KAETzG,KAAO4I,KAAKC,UAAU,GAAK5H,IAC3B,IAAIjB,KAAK0E,MAAM,gCAAiC,CAC9C1E,KAAOA,KAAKmD,OAAO,EAAGnD,KAAKlG,OAAS,EACpCkG,MAAOkT,IAAIE,QAAQpT,KAAM,YACpB,CACLA,KAAOA,KAAK4R,QAAQ,KAAM,OACdA,QAAQ,OAAQ,KAChBA,QAAQ,WAAY,IAChC5R,MAAOkT,IAAIE,QAAQpT,KAAM,WAI7B,MAAOA,MAAO,KAAOyG,IAIvB,QAASwP,sBAAqBJ,OAAQH,KAAMC,QAC1C,GAAIY,aAAc,CAClB,IAAIzc,QAAS+b,OAAO5T,OAAO,SAASuU,KAAMC,KACxCF,aACA,IAAIE,IAAIrL,QAAQ,OAAS,EAAGmL,aAC5B,OAAOC,MAAOC,IAAI7E,QAAQ,kBAAmB,IAAI9X,OAAS,GACzD,EAEH,IAAIA,OAAS,GAAI,CACf,MAAO6b,QAAO,IACND,OAAS,GAAK,GAAKA,KAAO,OAC3B,IACAG,OAAO/O,KAAK,SACZ,IACA6O,OAAO,GAGhB,MAAOA,QAAO,GAAKD,KAAO,IAAMG,OAAO/O,KAAK,MAAQ,IAAM6O,OAAO,GAMnE,QAASrX,SAAQoY,IACf,MAAO9a,OAAM0C,QAAQoY,IAEvBpe,QAAQgG,QAAUA,OAElB,SAASd,WAAUoC,KACjB,aAAcA,OAAQ,UAExBtH,QAAQkF,UAAYA,SAEpB,SAASuU,QAAOnS,KACd,MAAOA,OAAQ,KAEjBtH,QAAQyZ,OAASA,MAEjB,SAASpE,mBAAkB/N,KACzB,MAAOA,MAAO,KAEhBtH,QAAQqV,kBAAoBA,iBAE5B,SAAShR,UAASiD,KAChB,aAAcA,OAAQ,SAExBtH,QAAQqE,SAAWA,QAEnB,SAASe,UAASkC,KAChB,aAAcA,OAAQ,SAExBtH,QAAQoF,SAAWA,QAEnB,SAASiZ,UAAS/W,KAChB,aAAcA,OAAQ,SAExBtH,QAAQqe,SAAWA,QAEnB,SAAS7J,aAAYlN,KACnB,MAAOA,WAAa,GAEtBtH,QAAQwU,YAAcA,WAEtB,SAAShP,UAAS8Y,IAChB,MAAOnY,UAASmY,KAAOC,eAAeD,MAAQ,kBAEhDte,QAAQwF,SAAWA,QAEnB,SAASW,UAASmB,KAChB,aAAcA,OAAQ,UAAYA,MAAQ,KAE5CtH,QAAQmG,SAAWA,QAEnB,SAASb,QAAOkZ,GACd,MAAOrY,UAASqY,IAAMD,eAAeC,KAAO,gBAE9Cxe,QAAQsF,OAASA,MAEjB,SAAS2X,SAAQvc,GACf,MAAOyF,UAASzF,KACX6d,eAAe7d,KAAO,kBAAoBA,YAAaU,QAE9DpB,QAAQid,QAAUA,OAElB,SAASvX,YAAW4B,KAClB,aAAcA,OAAQ,WAExBtH,QAAQ0F,WAAaA,UAErB,SAAS4P,aAAYhO,KACnB,MAAOA,OAAQ,YACDA,OAAQ,iBACRA,OAAQ,gBACRA,OAAQ,gBACRA,OAAQ,gBACRA,OAAQ,YAExBtH,QAAQsV,YAAcA,WAEtBtV,SAAQ8U,SAAW5T,QAAQ,qBAE3B,SAASqd,gBAAexd,GACtB,MAAO+M,QAAOC,UAAUF,SAAStM,KAAKR,GAIxC,QAAS0d,KAAI7d,GACX,MAAOA,GAAI,GAAK,IAAMA,EAAEiN,SAAS,IAAMjN,EAAEiN,SAAS,IAIpD,GAAI6Q,SAAU,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MACxD,MAAO,MAAO,MAG5B,SAASC,aACP,GAAIH,GAAI,GAAIrB,KACZ,IAAIyB,OAAQH,IAAID,EAAEK,YACNJ,IAAID,EAAEM,cACNL,IAAID,EAAEO,eAAevQ,KAAK,IACtC,QAAQgQ,EAAEQ,UAAWN,OAAOF,EAAES,YAAaL,MAAMpQ,KAAK,KAKxDxO,QAAQkf,IAAM,WACZjF,QAAQiF,IAAI,UAAWP,YAAa3e,QAAQkZ,OAAO3V,MAAMvD,QAASkD,YAiBpElD,SAAQsU,SAAWpT,QAAQ,WAE3BlB,SAAQmb,QAAU,SAASgE,OAAQpO,KAEjC,IAAKA,MAAQ5K,SAAS4K,KAAM,MAAOoO,OAEnC,IAAItO,MAAO/C,OAAO+C,KAAKE,IACvB,IAAI5P,GAAI0P,KAAKrP,MACb,OAAOL,IAAK,CACVge,OAAOtO,KAAK1P,IAAM4P,IAAIF,KAAK1P,IAE7B,MAAOge,QAGT,SAASvM,gBAAerH,IAAK6T,MAC3B,MAAOtR,QAAOC,UAAU6E,eAAerR,KAAKgK,IAAK6T,SAGhD7d,KAAKf,KAAKU,QAAQ,kBAAmBZ,UAAW,YAAcA,aAAgBC,QAAS,YAAcA,WAAcF,UAAW,YAAcA,aAC5Igf,qBAAqB,GAAGC,SAAW,GAAGhL,SAAW,UAAU,IAAI"}
--------------------------------------------------------------------------------
/lib/aparser.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var utils = require("./utils.js");
4 |
5 | // typify: instance Thunk
6 |
7 | // Thunk, for the lazy-evaluation and recursive parser.
8 | // :: fn -> undefined
9 | function Thunk(f) {
10 | this.thunk = f;
11 | this.forced = false;
12 | this.value = undefined;
13 | }
14 |
15 | // :: any -> Thunk
16 | function delay(f) {
17 | return new Thunk(f);
18 | }
19 |
20 | // :: any -> *
21 | function force(thunk) {
22 | if (thunk instanceof Thunk) {
23 | if (!thunk.forced) {
24 | thunk.value = thunk.thunk();
25 | thunk.forced = true;
26 | }
27 | return thunk.value;
28 | } else {
29 | return thunk;
30 | }
31 | }
32 |
33 | // :: fn -> array string -> *
34 | function parse(p, tokens) {
35 | var res = p(tokens, 0);
36 | // console.log("parse", res, tokens, tokens.length);
37 | if (res !== undefined && res[1] >= tokens.length) {
38 | return res[0];
39 | } else {
40 | return undefined;
41 | }
42 | }
43 |
44 | // :: array string -> nat -> (tuple undefined idx)?
45 | function eof(tokens, idx) {
46 | // console.log("eof", tokens, idx);
47 | if (idx < tokens.length) {
48 | return undefined;
49 | } else {
50 | return [undefined, idx];
51 | }
52 | }
53 |
54 | // :: string -> fn
55 | function token(tok) {
56 | // :: array string -> nat -> (tuple string nat)?
57 | return function (tokens, idx) {
58 | // console.log("token", tokens, idx, tok);
59 | if (idx >= tokens.length) { return undefined; }
60 | if (tokens[idx] === tok) {
61 | return [tok, idx + 1];
62 | } else {
63 | return undefined;
64 | }
65 | };
66 | }
67 |
68 | // :: fn -> fn
69 | function satisfying(predicate) {
70 | // :: array string -> nat -> (tuple string nat)?
71 | return function (tokens, idx) {
72 | // console.log("satisfying", predicate.name || predicate, tokens, idx);
73 | if (idx >= tokens.length) { return undefined; }
74 | if (predicate(tokens[idx])) {
75 | return [tokens[idx], idx + 1];
76 | } else {
77 | return undefined;
78 | }
79 | };
80 | }
81 |
82 | // :: -> fn
83 | function any() {
84 | // :: array string -> nat -> (tuple string nat)?
85 | return function (tokens, idx) {
86 | if (idx < tokens.length) {
87 | return [tokens[idx], idx + 1];
88 | } else {
89 | return undefined;
90 | }
91 | };
92 | }
93 |
94 | // :: * -> fn
95 | function pure(x) {
96 | // :: array string -> nat -> tuple * nat
97 | return function (tokens, idx) {
98 | return [x, idx];
99 | };
100 | }
101 |
102 | // :: fn... -> fn
103 | function or() {
104 | var args = utils.slice(arguments);
105 | var len = args.length;
106 | // :: array string -> nat -> (tuple * nat)?
107 | return function (tokens, idx) {
108 | for (var i = 0; i < len; i++) {
109 | var res = force(args[i])(tokens, idx);
110 | if (res !== undefined) { return res; }
111 | }
112 | return undefined;
113 | };
114 | }
115 |
116 | // :: fn | Thunk ... -> fn
117 | function lift() {
118 | var len = arguments.length - 1;
119 | var f = arguments[len];
120 | var args = utils.slice(arguments, 0, -1);
121 | // :: array string -> nat -> (tuple * nat)?
122 | return function (tokens, idx) {
123 | var resargs = new Array(len);
124 | for (var i = 0; i < len; i++) {
125 | var res = force(args[i])(tokens, idx);
126 | // console.log("lift argument:", res, force(args[i]));
127 | if (res === undefined) { return undefined; }
128 | resargs[i] = res[0];
129 | idx = res[1];
130 | }
131 | // console.log("lift value", f.apply(undefined, resargs), idx);
132 | return [f.apply(undefined, resargs), idx];
133 | };
134 | }
135 |
136 | // :: array -> * -> array string -> nat -> tuple array nat
137 | function manyLoop(res, a, tokens, idx) {
138 | while (true) {
139 | var aq = a(tokens, idx);
140 | if (aq === undefined) { return [res, idx]; }
141 | res.push(aq[0]);
142 | idx = aq[1];
143 | }
144 | }
145 |
146 | // :: fn -> fn
147 | function some(a) {
148 | // :: array string -> nat -> (tuple array nat)?
149 | return function (tokens, idx) {
150 | a = force(a);
151 | var res = [];
152 | var ap = a(tokens, idx);
153 | if (ap === undefined) { return undefined; }
154 | res.push(ap[0]);
155 | idx = ap[1];
156 | return manyLoop(res, a, tokens, idx);
157 | };
158 | }
159 |
160 | // :: fn -> fn
161 | function many(a) {
162 | // :: array string -> nat -> tuple array nat
163 | return function (tokens, idx) {
164 | a = force(a);
165 | var res = [];
166 | return manyLoop(res, a, tokens, idx);
167 | };
168 | }
169 |
170 | // :: fn -> string -> fn
171 | function sepBy(a, sep) {
172 | // :: array string -> nat -> (tuple array nat)?
173 | return function (tokens, idx) {
174 | a = force(a);
175 | var res = [];
176 | var ap = a(tokens, idx);
177 | if (ap === undefined) { return undefined; }
178 | res.push(ap[0]);
179 | idx = ap[1];
180 | while (true) {
181 | if (tokens[idx] !== sep) { return [res, idx]; }
182 | idx += 1;
183 | var aq = a(tokens, idx);
184 | if (aq === undefined) { return [res, idx]; }
185 | res.push(aq[0]);
186 | idx = aq[1];
187 | }
188 | };
189 | }
190 |
191 | // :: fn -> * -> fn
192 | function optional(p, def) {
193 | // :: array string -> nat -> (tuple * nat)?
194 | return function (tokens, idx) {
195 | var res = force(p)(tokens, idx);
196 | if (res === undefined) {
197 | return [def, idx];
198 | } else {
199 | return res;
200 | }
201 | };
202 | }
203 |
204 | module.exports = {
205 | parse: parse,
206 | pure: pure,
207 | or: or,
208 | lift: lift,
209 | many: many,
210 | some: some,
211 | sepBy: sepBy,
212 | eof: eof,
213 | token: token,
214 | any: any,
215 | satisfying: satisfying,
216 | optional: optional,
217 | delay: delay,
218 | };
219 |
--------------------------------------------------------------------------------
/lib/builtin.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var p = require("./predicates.js");
4 | var utils = require("./utils.js");
5 |
6 | module.exports = {
7 | "number": p.isNumber,
8 | "integer": p.isInteger,
9 | "nat": function (val) {
10 | return p.isInteger(val) && p.isNonNegative(val);
11 | },
12 | "positive": function (val, valueCheck) {
13 | return p.isPositive(val) && (!valueCheck || valueCheck(val));
14 | },
15 | "nonnegative": function (val, valueCheck) {
16 | return p.isNonNegative(val) && (!valueCheck || valueCheck(val));
17 | },
18 | "finite": function (val, valueCheck) {
19 | return p.isFinite(val) && (!valueCheck || valueCheck(val));
20 | },
21 | "boolean": p.isBoolean,
22 | "string": p.isString,
23 | "date": p.isDate,
24 | "regexp": p.isRegExp,
25 | "function": p.isFunction,
26 | "fn": p.isFunction,
27 | "arguments": p.isArguments,
28 | "any": p.constTrue,
29 | "array": function (arr, valueCheck) {
30 | return p.isArray(arr) && (!valueCheck || utils.every(arr, valueCheck));
31 | },
32 | "map": function (map, valueCheck) {
33 | return (p.isObject(map) && !p.isArray(map)) && (!valueCheck || utils.every(utils.values(map), valueCheck));
34 | },
35 | "tuple": function (v) {
36 | if (!Array.isArray(v)) { return false; }
37 | var args = utils.slice(arguments, 1);
38 | if (args.length !== v.length) { return false; }
39 | for (var i = 0; i < args.length; i++) {
40 | if (!args[i](v[i])) {
41 | return false;
42 | }
43 | }
44 | return true;
45 | },
46 | };
47 |
--------------------------------------------------------------------------------
/lib/checkableCompiler.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var utils = require("./utils.js");
4 | var p = require("./predicates.js");
5 |
6 | // :: Environment -> map (array checkable) -> array string -> checkableAlt | checkableAnd -> fn
7 | function compileAndAlt(environment, context, recNames, parsed, operator) {
8 | var cs = utils.map(parsed.options, compileCheckableTypeRecursive.bind(undefined, environment, context, recNames));
9 | // compiledOptAlt :: map fn -> fn -> any -> fn... -> boolean
10 | operator = parsed.type === "and" ? "every" : "some";
11 | return function (recChecks, varCheck, arg) {
12 | return cs[operator](function (c) {
13 | return c(recChecks, varCheck, arg);
14 | });
15 | };
16 | }
17 |
18 | // :: Environment -> map (array checkable) -> array string -> checkableVar -> fn
19 | function compileVar(environment, context, recNames, parsed) {
20 | if (utils.has(context, parsed.name)) {
21 | // compiledContext :: map fn -> fn -> any -> fn... -> boolean
22 | return function (recChecks, varCheck, arg) {
23 | // console.log("varcheck", varCheck, arg);
24 | return varCheck(parsed.name, arg);
25 | };
26 | } else if (environment.has(parsed.name)) {
27 | var check = environment.get(parsed.name);
28 | // compiledEnv :: map fn -> fn -> any -> fn... -> boolean
29 | return function (recChecks, varCheck) {
30 | var args = utils.slice(arguments, 2);
31 | return check.apply(undefined, args);
32 | };
33 | } else if (recNames && utils.contains(recNames, parsed.name)) {
34 | // compiledRec :: map fn -> fn -> any -> fn... -> boolean
35 | return function (recChecks, varCheck, arg) {
36 | return recChecks[parsed.name](recChecks, varCheck, arg);
37 | };
38 | } else {
39 | throw new Error("unknown type: " + parsed.name);
40 | }
41 | }
42 |
43 | // :: Environment -> map (array checkable) -> array string -> checkablePoly -> fn
44 | function compilePoly(environment, context, recNames, parsed) {
45 | var args = utils.map(parsed.args, compileCheckableTypeRecursive.bind(undefined, environment, context, recNames));
46 | if (utils.has(context, parsed.name)) {
47 | // compiledPoly :: map fn -> fn -> any -> fn... -> boolean
48 | return function compiledPolyEnv(recChecks, varCheck, arg) {
49 | var argsChecks = args.map(function (argCheck) {
50 | return argCheck.bind(undefined, recChecks, varCheck);
51 | });
52 | return varCheck.apply(undefined, [parsed.name, arg].concat(argsChecks));
53 | };
54 | } else if (environment.has(parsed.name)) {
55 | var polyCheck = environment.get(parsed.name);
56 | // compiledPoly :: map fn -> fn -> any -> fn... -> boolean
57 | return function (recChecks, varCheck, arg) {
58 | var argsChecks = args.map(function (argCheck) {
59 | return argCheck.bind(undefined, recChecks, varCheck);
60 | });
61 | return polyCheck.apply(undefined, [arg].concat(argsChecks));
62 | };
63 | } else {
64 | throw new Error("unknown type: " + parsed.name);
65 | }
66 | }
67 |
68 | // :: Environment -> map (array checkable) -> array string -> checkableOpt -> fn
69 | function compileOpt(environment, context, recNames, parsed) {
70 | var c = compileCheckableTypeRecursive(environment, context, recNames, parsed.term);
71 | // compiledOpt :: map fn -> fn -> any -> fn... -> boolean
72 | return function (recChecks, varCheck, arg) {
73 | return arg === undefined || c(recChecks, varCheck, arg);
74 | };
75 | }
76 |
77 | // :: Environment -> map (array checkable) -> array string -> checkableLiteral -> fn
78 | function compileLiteral(environment, context, recNames, parsed) {
79 | if (parsed.value !== parsed.value) {
80 | // NaN
81 | // compiledNaN :: map fn -> fn -> any -> fn... -> boolean
82 | return function (recChecks, varCheck, arg) {
83 | return arg !== arg;
84 | };
85 | } else {
86 | // compiledLiteral :: map fn -> fn -> any -> fn... -> boolean
87 | return function (recChecks, varCheck, arg) {
88 | return arg === parsed.value;
89 | };
90 | }
91 | }
92 |
93 | // :: Environment -> map (array checkable) -> array string -> checkableRecord -> fn
94 | function compileRecord(environment, context, recNames, parsed) {
95 | var fields = {};
96 | for (var name in parsed.fields) {
97 | fields[name] = compileCheckableTypeRecursive(environment, context, recNames, parsed.fields[name]);
98 | }
99 | var closed = parsed.closed;
100 |
101 | // compiledRecord : map fn -> fn -> any -> fn... -> boolean
102 | return function (recChecks, varCheck, arg) {
103 | if (!p.isObject(arg)) {
104 | return false;
105 | }
106 |
107 | for (var fieldName in fields) {
108 | if (!fields[fieldName](recChecks, varCheck, arg[fieldName])) {
109 | return false;
110 | }
111 | }
112 |
113 | if (closed) {
114 | for (var key in arg) {
115 | if (!fields[key]) {
116 | return false;
117 | }
118 | }
119 | }
120 |
121 | return true;
122 | };
123 | }
124 |
125 | // :: Environment -> map (array checkable) -> array string -> checkableUser -> fn
126 | function compileUser(environment, context, recNames, parsed) {
127 | // compiledUser :: map fn -> fn -> any -> fn... -> boolean
128 | return function (recChecks, varCheck, arg) {
129 | return parsed.predicate(arg);
130 | };
131 | }
132 |
133 | // :: Environment -> map (array checkable) -> array string -> checkable -> fn
134 | function compileCheckableTypeRecursive(environment, context, recNames, parsed) {
135 | switch (parsed.type) {
136 | case "var": return compileVar(environment, context, recNames, parsed);
137 | case "literal": return compileLiteral(environment, context, recNames, parsed);
138 | case "poly": return compilePoly(environment, context, recNames, parsed);
139 | case "any": return p.constTrue;
140 | case "opt": return compileOpt(environment, context, recNames, parsed);
141 | case "alt": return compileAndAlt(environment, context, recNames, parsed);
142 | case "and": return compileAndAlt(environment, context, recNames, parsed);
143 | case "record": return compileRecord(environment, context, recNames, parsed);
144 | case "user": return compileUser(environment, context, recNames, parsed);
145 | }
146 | }
147 |
148 | // :: Environment -> map (array checkable) -> checkable -> fn
149 | function compileCheckableType(environment, context, parsed) {
150 | return compileCheckableTypeRecursive(environment, context, [], parsed).bind(undefined, {});
151 | }
152 |
153 | module.exports = {
154 | compile: compileCheckableType,
155 | compileRecursive: compileCheckableTypeRecursive,
156 | compileRecord: compileRecord,
157 | };
158 |
--------------------------------------------------------------------------------
/lib/checkableConstructors.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var assert = require("assert");
4 |
5 | var any = { type: "any" };
6 |
7 | /*
8 | typify: adt checkable
9 | checkableAny: { type: 'any' }
10 | checkableLiteral: { type: 'literal', value: string|number|boolean|null|undefined|nan }
11 | checkableVar: { type: 'var', name: string }
12 | checkableRecord: { type: 'record', fields: map checkable, closed: boolean }
13 | checkablePoly: { type: 'poly', name: string, args: array checkable }
14 | checkableAlt: { type: 'alt', options: array checkable }
15 | checkableAnd: { type: 'and', options: array checkable }
16 | checkableOpt: { type: 'opt', term: checkable }
17 | checkableUser: { type: 'user', predicate: fn }
18 | */
19 |
20 | // typify: type contextDef = { name: string, typeset: array checkable }
21 | // typify: type context = map (array checkable)
22 | // typify: type functionType = { name: string, context: context, params: array checkable, rest: checkable?, result: checkable }
23 |
24 | // :: string -> { type: 'literal', value: null|boolean|infinity|ninfinity|undefined|nan } | checkableVar
25 | function variable(name) {
26 | switch (name) {
27 | case "true": return { type: "literal", value: true };
28 | case "false": return { type: "literal", value: false };
29 | case "null": return { type: "literal", value: null };
30 | case "infinity": return { type: "literal", value: Infinity };
31 | case "ninfinity": return { type: "literal", value: -Infinity };
32 | case "undefined": return { type: "literal", value: undefined };
33 | case "nan": return { type: "literal", value: NaN };
34 | }
35 | return { type: "var", name: name };
36 | }
37 |
38 | // :: number -> { type: 'literal', value: number }
39 | function number(value) {
40 | assert(typeof value === "number");
41 | return { type: "literal", value: value };
42 | }
43 |
44 | // :: string -> { type: 'literal', value: string }
45 | function string(value) {
46 | assert(typeof value === "string");
47 | return { type: "literal", value: value };
48 | }
49 |
50 | // :: checkable -> checkableOpt | checkableAny
51 | function opt(t) {
52 | if (t.type === "any") {
53 | return t;
54 | } else if (t.type === "opt") {
55 | return t;
56 | } else {
57 | return { type: "opt", term: t };
58 | }
59 | }
60 |
61 | // :: string -> array checkable -> checkablePoly
62 | function poly(name, args) {
63 | return { type: "poly", name: name, args: args };
64 | }
65 |
66 | // :: map checkable -> boolean? -> checkableRecord
67 | function record(fields, closed) {
68 | // TODO: remove optionality of closed
69 | return { type: "record", fields: fields, closed: !!closed };
70 | }
71 |
72 | // :: 'and'|'alt' -> checkable -> checkable -> checkable | array checkable
73 | function mergeOptions(type, a, b) {
74 | if (a.type === type) {
75 | if (b.type === type) {
76 | return a.options.concat(b.options);
77 | } else {
78 | return a.options.concat([b]);
79 | }
80 | } else if (b.type === type) {
81 | return [a].concat(b.options);
82 | } else {
83 | return [a, b];
84 | }
85 | }
86 |
87 | // :: 'and'|'alt' -> array checkable -> checkable
88 | function andOr(type, options) {
89 | assert(options.length > 0);
90 |
91 | if (options.length === 1) {
92 | return options[0];
93 | }
94 |
95 | return options.reduce(function (a, b) {
96 | return {
97 | type: type,
98 | options: mergeOptions(type, a, b),
99 | };
100 | });
101 | }
102 |
103 | // :: fn -> checkableUser
104 | function user(predicate) {
105 | return { type: "user", predicate: predicate };
106 | }
107 |
108 | module.exports = {
109 | any: any,
110 | variable: variable,
111 | number: number,
112 | string: string,
113 | opt: opt,
114 | poly: poly,
115 | record: record,
116 | and: andOr.bind(undefined, "and"),
117 | alt: andOr.bind(undefined, "alt"),
118 | user: user,
119 | };
120 |
--------------------------------------------------------------------------------
/lib/checkableParser.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var A = require("./aparser.js");
4 | var cons = require("./checkableConstructors.js");
5 |
6 | var identifierRe = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
7 | var numberRe = /^[0-9]+$/;
8 | var stringRe = /^('[^']*'|"[^"]*")$/;
9 |
10 | // :: string -> boolean
11 | function isIdentifier(token) {
12 | return identifierRe.test(token);
13 | }
14 |
15 | // :: string -> boolean
16 | function isNumber(token) {
17 | return numberRe.test(token);
18 | }
19 |
20 | // :: string -> boolean
21 | function isString(token) {
22 | return stringRe.test(token);
23 | }
24 |
25 | var altP;
26 |
27 | // :: fn|Thunk -> fn
28 | function parensP(p) {
29 | return A.lift(A.token("("), p, A.token(")"), function (a, b, c) {
30 | return b;
31 | });
32 | }
33 |
34 | var identifierP = A.satisfying(isIdentifier);
35 |
36 | var numberP = A.lift(A.satisfying(isNumber), function (x) {
37 | return cons.number(parseFloat(x));
38 | });
39 |
40 | var stringP = A.lift(A.satisfying(isString), function (x) {
41 | x = x.substr(1, x.length - 2);
42 | return cons.string(x);
43 | });
44 |
45 | var literalP = A.or(numberP, stringP);
46 |
47 | var anyP = A.lift(A.token("*"), function () {
48 | return cons.any;
49 | });
50 |
51 | var varP = A.lift(identifierP, cons.variable);
52 |
53 | var emptyRecordP = A.lift(A.token("{"), A.token("}"), function () {
54 | return cons.record({});
55 | });
56 |
57 | var pairP = A.lift(identifierP, A.token(":"), A.delay(function () { return altP; }), function (k, c, v) {
58 | return {
59 | ident: k,
60 | value: v,
61 | };
62 | });
63 |
64 | var nonEmptyRecordP = A.lift(A.token("{"), A.sepBy(pairP, ","), A.token("}"), function (o, ps, c) {
65 | var obj = {};
66 | ps.forEach(function (p) {
67 | obj[p.ident] = p.value;
68 | });
69 | return cons.record(obj);
70 | });
71 |
72 | var recordP = A.or(emptyRecordP, nonEmptyRecordP);
73 |
74 | var termP = A.or(anyP, literalP, varP, recordP, parensP(A.delay(function () { return altP; })));
75 |
76 | var optP = A.lift(termP, A.optional(A.token("?")), function (term, opt) {
77 | if (opt === "?" && term.type !== "opt" && term.type !== "any") {
78 | return cons.opt(term);
79 | } else {
80 | return term;
81 | }
82 | });
83 |
84 | var polyP1 = A.lift(identifierP, A.some(optP), cons.poly);
85 |
86 | var polyP = A.or(polyP1, optP);
87 |
88 | var andP = A.lift(A.sepBy(polyP, "&"), cons.and);
89 |
90 | altP = A.lift(A.sepBy(andP, "|"), cons.alt);
91 |
92 | var checkableP = altP;
93 |
94 | var checkableTypeCheckRe = /^([a-zA-Z_][a-zA-Z0-9_]*|"[^"]*"|'[^']*'|[0-9]+|:|,|\{|\}|\*|\?|\||&|\(|\)|\s+)*$/;
95 | var checkableTypeTokenRe = /([a-zA-Z_][a-zA-Z0-9_]*|"[^"]*"|'[^']*'|[0-9]+|:|,|\{|\}|\*|\?|\||&|\(|\))/g;
96 |
97 | // :: string -> checkable
98 | function parseCheckableType(type) {
99 | if (!checkableTypeCheckRe.test(type)) { throw new TypeError("invalid checkable type: " + type); }
100 | var tokens = type.match(checkableTypeTokenRe);
101 | var parsed = A.parse(checkableP, tokens);
102 | if (parsed === undefined) { throw new TypeError("invalid checkable type: " + type); }
103 | return parsed;
104 | }
105 |
106 | module.exports = {
107 | identifierP: identifierP,
108 | checkableP: checkableP,
109 | polyP: polyP,
110 | parse: parseCheckableType,
111 | };
112 |
--------------------------------------------------------------------------------
/lib/functionParser.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var A = require("./aparser.js");
4 | var identifierP = require("./checkableParser").identifierP;
5 | var polyP = require("./checkableParser").polyP;
6 | var checkableP = require("./checkableParser").checkableP;
7 |
8 | var nameP = A.optional(A.lift(identifierP, A.token("::"), function (identifier, sep) {
9 | return identifier;
10 | }), "");
11 |
12 | var actionP = A.lift(nameP, A.token("->"), checkableP, function (name, arrow, result) {
13 | return {
14 | name: name,
15 | context: {},
16 | params: [],
17 | rest: undefined,
18 | result: result,
19 | };
20 | });
21 |
22 | var typesetP = A.sepBy(polyP, "|");
23 |
24 | var contextDefP = A.lift(identifierP, A.token(":"), typesetP, function (name, sep, typeset) {
25 | // console.log("contextDefP", name, typeset);
26 | return {
27 | name: name,
28 | typeset: typeset,
29 | };
30 | });
31 |
32 | var contextP = A.optional(A.lift(A.sepBy(contextDefP, ","), A.token("=>"), function (defs, arrow) {
33 | return defs.reduce(function (context, def) {
34 | context[def.name] = def.typeset;
35 | return context;
36 | }, {});
37 | }), {});
38 |
39 | var paramsP = A.many(A.lift(checkableP, A.token("->"), function (param, arrow) {
40 | return param;
41 | }));
42 |
43 | var restP = A.optional(A.lift(A.optional(checkableP), A.token("..."), A.token("->"), function (type, ellipsis, arrow) {
44 | // console.log("restP", type, ellipsis, arrow);
45 | return type || { type: "any" };
46 | }));
47 |
48 | var functionTypeP1 = A.lift(nameP, contextP, paramsP, restP, checkableP, function (name, context, params, rest, result) {
49 | // console.log("functionTypeP1", name, context, params, rest, result);
50 | return {
51 | name: name,
52 | context: context,
53 | params: params,
54 | rest: rest,
55 | result: result,
56 | };
57 | });
58 |
59 | var functionTypeP = A.or(actionP, functionTypeP1);
60 |
61 | module.exports = {
62 | functionP: functionTypeP,
63 | };
64 |
--------------------------------------------------------------------------------
/lib/predicates.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | // Type predicates
4 | var toString = Object.prototype.toString;
5 |
6 | // :: any -> boolean
7 | function isBoolean(val) {
8 | return typeof val === "boolean";
9 | }
10 |
11 | // :: any -> boolean
12 | function isNumber(val) {
13 | return typeof val === "number";
14 | }
15 |
16 | // :: any -> boolean
17 | function isInteger(val) {
18 | return val === (val | 0);
19 | }
20 |
21 | // :: any -> boolean
22 | function isPositive(val) {
23 | return typeof val === "number" && val > 0;
24 | }
25 |
26 | // :: any -> boolean
27 | function isNonNegative(val) {
28 | return typeof val === "number" && val >= 0;
29 | }
30 |
31 | // :: any -> boolean
32 | function isFinite(val) {
33 | return typeof val === "number" && val !== Infinity && val !== -Infinity && val === +val;
34 | }
35 |
36 | // :: any -> boolean
37 | function isString(val) {
38 | return typeof val === "string";
39 | }
40 |
41 | // :: any -> boolean
42 | function isFunction(val) {
43 | return typeof val === "function";
44 | }
45 |
46 | // :: any -> boolean
47 | function isDate(val) {
48 | return toString.call(val) === "[object Date]";
49 | }
50 |
51 | // :: any -> boolean
52 | function isRegExp(val) {
53 | return toString.call(val) === "[object RegExp]";
54 | }
55 |
56 | // :: any -> boolean
57 | function isArray(val) {
58 | return Array.isArray(val);
59 | }
60 |
61 | // :: any -> boolean
62 | function isObject(val) {
63 | return Object(val) === val;
64 | }
65 |
66 | // :: any -> boolean
67 | function isArguments(val) {
68 | return val && isObject(arguments) && isInteger(val.length) && Object.prototype.toString.call(val) === "[object Arguments]" || false;
69 | }
70 |
71 | // :: *... -> true
72 | function constTrue() {
73 | return true;
74 | }
75 |
76 | module.exports = {
77 | isBoolean: isBoolean,
78 | isNumber: isNumber,
79 | isInteger: isInteger,
80 | isPositive: isPositive,
81 | isNonNegative: isNonNegative,
82 | isFinite: isFinite,
83 | isString: isString,
84 | isFunction: isFunction,
85 | isDate: isDate,
86 | isRegExp: isRegExp,
87 | isArray: isArray,
88 | isObject: isObject,
89 | isArguments: isArguments,
90 | constTrue: constTrue,
91 | };
92 |
--------------------------------------------------------------------------------
/lib/show.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var utils = require("./utils.js");
4 |
5 | // :: boolean -> string -> string
6 | function parensS(guard, str) {
7 | return guard ? "(" + str + ")" : str;
8 | }
9 |
10 | // :: checkableLiteral -> string
11 | function showLiteral(type) {
12 | if (typeof type.value === "string") {
13 | return "'" + type.value + "'";
14 | } else {
15 | return "" + type.value;
16 | }
17 | }
18 |
19 | // :: checkableRecord -> string
20 | function showRecord(type) {
21 | var pairs = [];
22 | for (var t in type.fields) {
23 | pairs.push(t + ": " + showCheckableTypePrecedence(0, type.fields[t]));
24 | }
25 | return "{" + pairs.join(", ") + "}";
26 | }
27 |
28 | // :: nat -> checkable -> string
29 | function showCheckableTypePrecedence(precedence, type) {
30 | switch (type.type) {
31 | case "any": return "*";
32 | case "literal": return showLiteral(type);
33 | case "var": return type.name;
34 | case "record":
35 | return showRecord(type);
36 | case "alt":
37 | return parensS(precedence > 0,
38 | utils.map(type.options, showCheckableTypePrecedence.bind(undefined, 0)).join("|"));
39 | case "and":
40 | return parensS(precedence > 1,
41 | utils.map(type.options, showCheckableTypePrecedence.bind(undefined, 1)).join("&"));
42 | case "poly":
43 | return parensS(precedence > 2,
44 | type.name + " " + utils.map(type.args, showCheckableTypePrecedence.bind(undefined, 3)).join(" "));
45 | case "opt":
46 | return parensS(precedence > 3,
47 | showCheckableTypePrecedence(3, type.term) + "?");
48 | }
49 | }
50 |
51 | // :: checkable -> string
52 | function showCheckableType(type) {
53 | return showCheckableTypePrecedence(0, type);
54 | }
55 |
56 | // :: map (array checkable) -> string
57 | function showContext(context) {
58 | var res = "";
59 | for (var name in context) {
60 | res += name + " : " + utils.map(context[name], showCheckableTypePrecedence.bind(undefined, 1)).join(" | ");
61 | }
62 | return res;
63 | }
64 |
65 | module.exports = {
66 | checkable: showCheckableType,
67 | context: showContext,
68 | };
69 |
--------------------------------------------------------------------------------
/lib/typify.js:
--------------------------------------------------------------------------------
1 | /*
2 | * typify
3 | * https://github.com/phadej/typify
4 | *
5 | * Copyright (c) 2013 Oleg Grenrus
6 | * Licensed under the MIT license.
7 | */
8 | "use strict";
9 |
10 | var VERSION = [0, 2, 10];
11 |
12 | var utils = require("./utils.js");
13 | var p = require("./predicates.js");
14 | var A = require("./aparser.js");
15 | var c = require("./checkableCompiler.js");
16 | var cons = require("./checkableConstructors.js");
17 | var show = require("./show.js");
18 | var parseCheckableType = require("./checkableParser").parse;
19 | var compileCheckableType = c.compile;
20 | var compileCheckableTypeRecursive = c.compileRecursive;
21 | var functionP = require("./functionParser.js").functionP;
22 |
23 | // Few almost predicates
24 | // :: *... -> *
25 | function throwAlways() {
26 | throw new Error("this shouldn't been called");
27 | }
28 |
29 | var functionTypeCheckRe = /^([a-zA-Z_][a-zA-Z0-9_]*|"[^"]*"|'[^']*'|[0-9]+|\*|\?|\||&|\(|\)|\{|\}|::|:|,|=>|->|\.\.\.|\s+)*$/;
30 | var functionTypeTokenRe = /([a-zA-Z_][a-zA-Z0-9_]*|"[^"]*"|'[^']*'|[0-9]+|\*|\?|\||&|\(|\)|\{|\}|::|:|,|=>|->|\.\.\.)/g;
31 |
32 | // Function type parsing, checks pre-compiling & pretty-printing
33 |
34 | // :: checkable -> *... -> boolean
35 | function optional(parsed) {
36 | if (parsed.type === "any") { return true; }
37 | if (parsed.type === "opt") { return true; }
38 | if (parsed.type === "alt") { return parsed.options.some(optional); }
39 | return false;
40 | }
41 |
42 | // :: functionType -> nat | infinity
43 | function maxParamsF(parsed) {
44 | return parsed.rest === undefined ? parsed.params.length : Infinity;
45 | }
46 |
47 | // :: functionType -> nat
48 | function minParamsF(parsed) {
49 | var result = parsed.params.length;
50 | for (var i = result - 1; i >= 0; i--) {
51 | if (!optional(parsed.params[i])) {
52 | break;
53 | }
54 | result = i;
55 | }
56 | return result;
57 | }
58 |
59 | // :: Environment -> map (array checkable) -> map (array fn)
60 | function compileContext(environment, context) {
61 | return utils.mapValues(context, function (v) {
62 | return utils.map(v, compileCheckableType.bind(undefined, environment, context));
63 | });
64 | }
65 |
66 | // :: string -> functionType
67 | function parseFunctionType(type) {
68 | if (!functionTypeCheckRe.test(type)) { throw new TypeError("invalid function type: " + type); }
69 | var tokens = type.match(functionTypeTokenRe);
70 | var parsed = A.parse(functionP, tokens);
71 | if (parsed === undefined) { throw new TypeError("invalid function type: " + type); }
72 | return parsed;
73 | }
74 |
75 | // :: Environment -> functionType -> *
76 | function compileFunctionType(environment, parsed) {
77 | return {
78 | name: parsed.name,
79 | context: compileContext(environment, parsed.context),
80 | params: utils.map(parsed.params, compileCheckableType.bind(undefined, environment, parsed.context)),
81 | rest: parsed.rest && compileCheckableType(environment, parsed.context, parsed.rest),
82 | result: compileCheckableType(environment, parsed.context, parsed.result),
83 | minParams: minParamsF(parsed),
84 | maxParams: maxParamsF(parsed),
85 | };
86 | }
87 |
88 | // :: map (array fn) -> fn -> string -> *... -> boolean
89 | function contextCheckGeneric(context, compiled, varname) {
90 | var options = context[varname];
91 | var args = utils.slice(arguments, 3);
92 |
93 | for (var i = 0; i < options.length; i++) {
94 | var option = options[i];
95 | var res = option.apply(undefined, [compiled].concat(args));
96 | if (res) {
97 | context[varname] = [option];
98 | return true;
99 | }
100 | }
101 | return false;
102 | }
103 |
104 | // Decorate function with type-signature check
105 | function decorate(environment, type, method) {
106 | var parsed = parseFunctionType(type);
107 | var compiled = compileFunctionType(environment, parsed);
108 |
109 | return function () {
110 | // check there are enough parameters
111 | if (arguments.length < compiled.minParams || arguments.length > compiled.maxParams) {
112 | if (compiled.minParams === compiled.maxParams) {
113 | throw new TypeError("function " + compiled.name + " expects " + compiled.maxParams + " arguments, " + arguments.length + " given");
114 | } else {
115 | throw new TypeError("function " + compiled.name + " expects " + compiled.minParams + "-" + compiled.maxParams + " arguments, " + arguments.length + " given");
116 | }
117 | }
118 |
119 | var contextCheckUn = contextCheckGeneric.bind(undefined, utils.copyObj(compiled.context));
120 | var contextCheck = utils.y(contextCheckUn);
121 |
122 | // check that parameters are of right type
123 | for (var i = 0; i < arguments.length; i++) {
124 | var argCheck = i < compiled.params.length ? compiled.params[i] : compiled.rest;
125 | var argType = i < compiled.params.length ? parsed.params[i] : parsed.rest;
126 | if (!argCheck(contextCheck, arguments[i])) {
127 | // TODO: str checkable type
128 | throw new TypeError("type of " + parsed.name + " " + (i + 1) + ". parameter is not `" + show.checkable(argType) + "` in context `" + show.context(parsed.context) + "` -- " + JSON.stringify(arguments[i]));
129 | }
130 | }
131 |
132 | // call original function
133 | var r = method.apply(this, arguments);
134 |
135 | // check type of return value
136 | if (!compiled.result(contextCheck, r)) {
137 | // TODO: str checkable type
138 | throw new TypeError("type of `" + parsed.name + "` return value is not `" + show.checkable(parsed.result) + "` in context `" + show.context(parsed.context) + "` -- " + r);
139 | }
140 |
141 | // return
142 | return r;
143 | };
144 | }
145 |
146 | function parse(definition, closed) {
147 | if (p.isString(definition)) {
148 | return parseCheckableType(definition);
149 | } else if (p.isFunction(definition)) {
150 | return cons.user(definition);
151 | } else if (p.isArray(definition)) {
152 | var options = utils.map(definition, parse);
153 | return cons.alt(options);
154 | } else /* if (p.isObject(definition)) */ {
155 | var fields = utils.mapValues(definition, parse);
156 | return cons.record(fields, closed);
157 | }
158 | }
159 |
160 | // Check checkable type
161 | function check(environment, type, variable) {
162 | if (arguments.length !== 2 && arguments.length !== 3) {
163 | throw new TypeError("check takes 1 or 2 arguments, " + (arguments.length - 1) + " provided");
164 | }
165 |
166 | var parsed = parseCheckableType(type);
167 | // console.log(parsed);
168 | // console.log(JSON.stringify(parsed, null));
169 | var compiled = compileCheckableType(environment, {}, parsed); // using empty context
170 |
171 | switch (arguments.length) {
172 | case 2: return function (variable1) {
173 | return compiled(throwAlways, variable1) === true;
174 | };
175 | case 3:
176 | return compiled(throwAlways, variable) === true;
177 | }
178 | }
179 |
180 | function assert(environment, type, variable) {
181 | if (arguments.length !== 2 && arguments.length !== 3) {
182 | throw new TypeError("assert takes 1 or 2 arguments, " + (arguments.length - 1) + " provided");
183 | }
184 |
185 | var parsed = parseCheckableType(type);
186 | // console.log(parsed);
187 | // console.log(JSON.stringify(parsed, null));
188 | var compiled = compileCheckableType(environment, {}, parsed); // using empty context
189 |
190 | switch (arguments.length) {
191 | case 2: return function (variable1) {
192 | var result1 = compiled(throwAlways, variable1);
193 | if (result1 !== true) {
194 | throw new TypeError(result1);
195 | }
196 | };
197 | case 3:
198 | var result = compiled(throwAlways, variable);
199 | if (result !== true) {
200 | throw new TypeError(result);
201 | }
202 | }
203 | }
204 |
205 | // Add single parsable type
206 | // :: Environment -> map checkable -> undefined
207 | function addParsedTypes(environment, parsed, closed) {
208 | var names = Object.keys(parsed);
209 | names.forEach(function (name) {
210 | if (environment.has(name)) { throw new Error(name + " is already defined"); }
211 | });
212 |
213 | var compiled = utils.mapValues(parsed, compileCheckableTypeRecursive.bind(undefined, environment, {}, names));
214 | var checks = utils.mapValues(compiled, function (check2) {
215 | return check2.bind(undefined, compiled, throwAlways);
216 | });
217 |
218 | environment.add(checks);
219 | }
220 |
221 | function addType(environment, name, definition, closed) {
222 | var parsed = {};
223 | closed = !!closed;
224 | parsed[name] = parse(definition, closed);
225 | return addParsedTypes(environment, parsed);
226 | }
227 |
228 | // Or many simultanouslty
229 | function mutual(environment, definitions) {
230 | var parsed = utils.mapValues(definitions, parse);
231 | return addParsedTypes(environment, parsed);
232 | }
233 |
234 | function adt(environment, name, definitions) {
235 | if (utils.has(definitions, name)) {
236 | throw new Error("adt and it's constructor cannot has the same name");
237 | }
238 |
239 | var constructors = Object.keys(definitions);
240 | var parsed = utils.mapValues(definitions, parse);
241 | parsed[name] = parse(constructors);
242 |
243 | return addParsedTypes(environment, parsed);
244 | }
245 |
246 | function instance(environment, name, cls) {
247 | return addType(environment, name, function (arg) {
248 | return arg instanceof cls;
249 | });
250 | }
251 |
252 | function wrap(environment, module, signatures) {
253 | for (var fn in signatures) {
254 | module[fn] = decorate(environment, fn + " :: " + signatures[fn], module[fn]);
255 | }
256 |
257 | return module;
258 | }
259 |
260 | var buildInTypes = require("./builtin.js");
261 |
262 | // typify: instance Environment
263 | // :: -> undefined
264 | function Environment() {
265 | this.types = {};
266 | }
267 |
268 | Environment.prototype.has = function environmentHas(type) {
269 | return utils.has(this.types, type) || utils.has(buildInTypes, type);
270 | };
271 |
272 | Environment.prototype.get = function environmentGet(type) {
273 | return this.types[type] || buildInTypes[type];
274 | };
275 |
276 | Environment.prototype.add = function environmentAdd(checks) {
277 | Object.keys(checks).forEach(function (type) {
278 | this.types[type] = checks[type];
279 | }, this);
280 | };
281 |
282 | // typify public API type signatures
283 | var TYPE_SIGNATURES = {
284 | // TODO: change fn to multi type and deprecate alias & record
285 | type: "string -> fn -> *",
286 | // TODO: support alternative function signatures
287 | // TODO: support specifying required but "any" parameter
288 | // check: "string -> * -> boolean",
289 | alias: "string -> string -> *",
290 | record: "string -> map string -> boolean? -> *",
291 | mutual: "map string -> *",
292 | instance: "string -> fn -> *",
293 | wrap: "* -> map string -> *",
294 | adt: "string -> map string -> *",
295 | };
296 |
297 | // Create typify
298 | // We could want use prototype-style, instead of closure, but we cannot make callable objects.
299 | // TODO: add reference
300 | function create() {
301 | var env = new Environment();
302 |
303 | var typify = decorate.bind(undefined, env);
304 | typify.type = addType.bind(undefined, env);
305 | typify.alias = addType.bind(undefined, env);
306 | typify.record = addType.bind(undefined, env);
307 | typify.mutual = mutual.bind(undefined, env);
308 | typify.adt = adt.bind(undefined, env);
309 | typify.instance = instance.bind(undefined, env);
310 | typify.check = check.bind(undefined, env);
311 | typify.assert = assert.bind(undefined, env);
312 | typify.wrap = wrap.bind(undefined, env);
313 | typify.version = VERSION;
314 |
315 | // also add recursive create
316 | // make recursive environments or just possible to merge types from old?
317 | typify.create = create;
318 |
319 | return typify.wrap(typify, TYPE_SIGNATURES);
320 | }
321 |
322 | // Export stuff
323 | module.exports = create();
324 |
--------------------------------------------------------------------------------
/lib/utils.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | // Does the object contain given key? http://underscorejs.org/#has
4 | // :: map -> string -> boolean
5 | function has(object, property) {
6 | return Object.prototype.hasOwnProperty.call(object, property);
7 | }
8 |
9 | // :: array -> any -> boolean
10 | function contains(array, element) {
11 | return array.indexOf(element) !== -1;
12 | }
13 |
14 | // Create a shallow-copied clone of the object. http://underscorejs.org/#clone
15 | // :: map -> map
16 | function copyObj(obj) {
17 | var res = {};
18 | for (var k in obj) {
19 | res[k] = obj[k];
20 | }
21 | return res;
22 | }
23 |
24 | // Returns values of the object
25 | // :: map -> array
26 | function values(obj) {
27 | var res = [];
28 | for (var k in obj) {
29 | if (has(obj, k)) {
30 | res.push(obj[k]);
31 | }
32 | }
33 | return res;
34 | }
35 |
36 | // :: map -> fn -> map
37 | function mapValues(obj, f) {
38 | var res = {};
39 | for (var k in obj) {
40 | if (has(obj, k)) {
41 | res[k] = f(obj[k]);
42 | }
43 | }
44 | return res;
45 | }
46 |
47 | // :: array|arguments -> integer? -> integer? -> array
48 | function slice(array, n, m) {
49 | return Array.prototype.slice.call(array, n, m);
50 | }
51 |
52 | // :: array -> fn -> array
53 | function map(array, f) {
54 | return array.map(function (x) {
55 | return f(x);
56 | });
57 | }
58 |
59 | // This has different semantics than Array#every
60 | // utils.every([1, 2, 3], function (x) { return x; }); // 3
61 | // [1, 2, 3].every(function (x) { return x; }); // true
62 | // :: array -> fn -> *
63 | function every(array, f) {
64 | var acc = true;
65 | for (var i = 0; i < array.length; i++) {
66 | acc = acc && f(array[i]);
67 | if (!acc) {
68 | return acc;
69 | }
70 | }
71 | return acc;
72 | }
73 |
74 | // :: fn -> fn
75 | function y(f) {
76 | // :: fn -> fn
77 | function p(h) {
78 | return function () {
79 | var args = Array.prototype.slice.call(arguments);
80 | return f.apply(undefined, [h(h)].concat(args));
81 | };
82 | }
83 | return p(p);
84 | }
85 |
86 | // try { throw new Error(); } catch (e) { console.log(e.stack); }
87 |
88 | module.exports = {
89 | has: has,
90 | contains: contains,
91 | copyObj: copyObj,
92 | values: values,
93 | mapValues: mapValues,
94 | slice: slice,
95 | map: map,
96 | every: every,
97 | y: y,
98 | };
99 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "typify",
3 | "description": "Runtime type-checking for JavaScript.",
4 | "version": "0.2.10",
5 | "homepage": "https://github.com/phadej/typify",
6 | "author": {
7 | "name": "Oleg Grenrus",
8 | "email": "oleg.grenrus@iki.fi",
9 | "url": "http://oleg.fi"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git://github.com/phadej/typify.git"
14 | },
15 | "bugs": {
16 | "url": "https://github.com/phadej/typify/issues"
17 | },
18 | "license": "BSD-3-Clause",
19 | "main": "lib/typify",
20 | "engines": {
21 | "node": ">= 0.10.0"
22 | },
23 | "scripts": {
24 | "test": "make test"
25 | },
26 | "devDependencies": {
27 | "browserify": "^16.2.3",
28 | "david": "^11.0.0",
29 | "eslint": "^5.15.0",
30 | "jsverify": "^0.8.4",
31 | "lodash": "^4.17.11",
32 | "mocha": "^6.0.2",
33 | "nyc": "^13.3.0",
34 | "typify-bin": "0.0.7",
35 | "uglify-js": "^3.4.9"
36 | },
37 | "keywords": [
38 | "type",
39 | "checking",
40 | "typify",
41 | "data",
42 | "validation"
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/prepublish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Generate dist/typify.standalone.js and friends
4 | make dist
5 |
6 | if [ -n "`git status --porcelain`" ]; then
7 | echo "Error: dirty repository"
8 | exit 1
9 | fi
10 |
11 | NCOMMITS=`git describe --tags --match "v*" --dirty --long | cut -d "-" -f 2`
12 |
13 | if [ $NCOMMITS -ne 0 ]; then
14 | echo "Commits after last tag"
15 | exit 1
16 | fi
17 |
--------------------------------------------------------------------------------
/test/assert.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 |
3 | "use strict";
4 |
5 | var typify = require("../lib/typify.js");
6 | var assert = require("assert");
7 |
8 | describe("assert()", function () {
9 | it("throws", function () {
10 | assert.throws(function () { typify.assert("regexp", 1); });
11 | typify.assert("regexp", /foo/);
12 | });
13 |
14 | it("is autocurried", function () {
15 | var assertNumber = typify.assert("number");
16 | assert.throws(function () { assertNumber("foo"); });
17 | assertNumber(1);
18 | });
19 |
20 | it("takes one or two parameters", function () {
21 | assert.throws(function () { typify.assert("regexp", 1, 2); });
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/test/builtin.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 |
3 | "use strict";
4 |
5 | var typify = require("../lib/typify.js");
6 | var assert = require("assert");
7 | var _ = require("lodash");
8 |
9 | describe("regexp", function () {
10 | it("are RegExp objects", function () {
11 | assert(typify.check("regexp", /foo/));
12 | assert(typify.check("regexp", new RegExp("foo")));
13 | assert(!typify.check("regexp", 1));
14 | });
15 | });
16 |
17 | describe("date", function () {
18 | it("are Date objects", function () {
19 | assert(typify.check("date", new Date()));
20 | assert(!typify.check("date", 1));
21 | });
22 | });
23 |
24 | describe("null", function () {
25 | it("matches `null`", function () {
26 | assert(typify.check("null", null));
27 | assert(!typify.check("null", undefined));
28 | assert(!typify.check("null", {}));
29 | });
30 | });
31 |
32 | describe("literal numbers", function () {
33 | it("matches number exactly", function () {
34 | assert(typify.check("1", 1));
35 | assert(!typify.check("1", "1"));
36 | assert(!typify.check("1", 2));
37 | assert(typify.check("100", 100));
38 | });
39 | });
40 |
41 | describe("literal strings", function () {
42 | it("matches string exactly", function () {
43 | assert(typify.check("'foo'", "foo"));
44 | assert(typify.check("\"foo\"", "foo"));
45 | assert(!typify.check("'foo'", 2));
46 | assert(typify.check("'bar'", "bar"));
47 | });
48 | });
49 |
50 | describe("literal atoms", function () {
51 | it("matches true, false, null", function () {
52 | var literals = {
53 | "null": null,
54 | "true": true,
55 | "false": false,
56 | "infinity": Infinity,
57 | "ninfinity": -Infinity,
58 | "undefined": undefined,
59 | "nat": 1,
60 | "nan": NaN,
61 | };
62 |
63 | _.each(literals, function (v1, k1) {
64 | _.each(literals, function (v2, k2) {
65 | if (k1 === k2) {
66 | assert(typify.check(k1, v2));
67 | } else {
68 | assert(!typify.check(k1, v2), k1 + " - " + v2);
69 | }
70 | });
71 | });
72 |
73 | assert(typify.check("null", null));
74 | assert(!typify.check("true", null));
75 | assert(!typify.check("false", null));
76 | assert(!typify.check("number", null));
77 |
78 | assert(!typify.check("null", true));
79 | assert(typify.check("true", true));
80 | assert(!typify.check("false", true));
81 | assert(!typify.check("number", true));
82 |
83 | assert(!typify.check("null", false));
84 | assert(!typify.check("true", false));
85 | assert(typify.check("false", false));
86 | assert(!typify.check("number", false));
87 |
88 | assert(!typify.check("null", 1));
89 | assert(!typify.check("true", 1));
90 | assert(!typify.check("false", 1));
91 | assert(typify.check("number", 1));
92 | });
93 | });
94 |
95 | describe("tuple", function () {
96 | it("is fixed size array", function () {
97 | assert(typify.check("tuple integer string", [0, "foo"]));
98 | assert(!typify.check("tuple integer string", [0, 0]));
99 | assert(!typify.check("tuple integer string", [0]));
100 | assert(!typify.check("tuple integer string", 0));
101 | });
102 | });
103 |
104 | describe("arguments", function () {
105 | it("are special object", function () {
106 | assert(typify.check("arguments", arguments));
107 | assert(!typify.check("arguments", []));
108 | });
109 | });
110 |
--------------------------------------------------------------------------------
/test/errors.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, beforeEach */
2 |
3 | "use strict";
4 |
5 | var typify = require("../lib/typify.js");
6 | var assert = require("assert");
7 |
8 | describe("error cases", function () {
9 | var typ;
10 |
11 | beforeEach(function () {
12 | typ = typify.create();
13 | });
14 |
15 | it("throws if errorneous type is given", function () {
16 | assert.throws(function () {
17 | typ.check("#foo", 1);
18 | });
19 |
20 | assert.throws(function () {
21 | typ.check("foo??", 1);
22 | });
23 |
24 | assert.throws(function () {
25 | typ.check("number", 1, 1);
26 | });
27 | });
28 |
29 | it("throws if errorneous type if given to function", function () {
30 | assert.throws(function () {
31 | typify(1, function () {});
32 | });
33 |
34 | assert.throws(function () {
35 | typify("##", function () {});
36 | });
37 |
38 | assert.throws(function () {
39 | typify("=>", function () {});
40 | });
41 | });
42 |
43 | it("type() throws if wrong parameters", function () {
44 | assert.throws(function () {
45 | typ.type(1);
46 | });
47 |
48 | assert.throws(function () {
49 | typ.type("foo", 1);
50 | });
51 |
52 | assert.throws(function () {
53 | typ.type("foo", function () {});
54 | typ.type("foo", function () {});
55 | });
56 | });
57 |
58 | describe("check()", function () {
59 | it("throws if unknown type is given", function () {
60 | assert.throws(function () {
61 | typ.check("list number", [1, 1]);
62 | });
63 | });
64 | });
65 | });
66 |
--------------------------------------------------------------------------------
/test/map.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 |
3 | "use strict";
4 |
5 | var typify = require("../lib/typify.js");
6 | var assert = require("assert");
7 |
8 | describe("map", function () {
9 | it("matches objects", function () {
10 | assert(typify.check("map", {}));
11 | assert(!typify.check("map", 1));
12 | });
13 |
14 | it("could take type parameter", function () {
15 | var chk = typify.check("map nat");
16 | assert(chk({}));
17 | assert(chk({ a: 1, b: 2 }));
18 | assert(!chk({ a: 1, b: -1 }));
19 | });
20 |
21 | it("skips non own properties", function () {
22 | function C() {}
23 | C.prototype.a = "foo";
24 | var x = new C();
25 | x.b = 1;
26 |
27 | assert(typify.check("map nat", x));
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/test/number.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 | (function () {
3 | "use strict";
4 |
5 | var typify = require("../lib/typify.js");
6 | var assert = require("assert");
7 |
8 | describe("number", function () {
9 | it("works", function () {
10 | var chk = typify.check("number");
11 | assert(chk(0) === true);
12 | assert(chk(-0) === true);
13 | assert(chk(1) === true);
14 | assert(chk(-1) === true);
15 | assert(chk(0.1) === true);
16 | assert(chk(-1000.0001) === true);
17 | assert(chk(Infinity) === true);
18 | assert(chk(-Infinity) === true);
19 | assert(chk(NaN) === true);
20 | assert(chk("0") === false);
21 | });
22 | });
23 |
24 | describe("integer", function () {
25 | it("works", function () {
26 | var chk = typify.check("integer");
27 | assert(chk(0) === true);
28 | assert(chk(-0) === true);
29 | assert(chk(1) === true);
30 | assert(chk(-1) === true);
31 | assert(chk(0.1) === false);
32 | assert(chk(-1000.0001) === false);
33 | assert(chk(Infinity) === false);
34 | assert(chk(-Infinity) === false);
35 | assert(chk(NaN) === false);
36 | assert(chk("0") === false);
37 | });
38 | });
39 |
40 | describe("nat", function () {
41 | it("works", function () {
42 | var chk = typify.check("nat");
43 | assert(chk(0) === true);
44 | assert(chk(-0) === true);
45 | assert(chk(1) === true);
46 | assert(chk(-1) === false);
47 | assert(chk(0.1) === false);
48 | assert(chk(-1000.0001) === false);
49 | assert(chk(Infinity) === false);
50 | assert(chk(-Infinity) === false);
51 | assert(chk(NaN) === false);
52 | assert(chk("0") === false);
53 | });
54 | });
55 |
56 | describe("positive", function () {
57 | it("works", function () {
58 | var chk = typify.check("positive");
59 | assert(chk(0) === false);
60 | assert(chk(-0) === false);
61 | assert(chk(1) === true);
62 | assert(chk(-1) === false);
63 | assert(chk(0.1) === true);
64 | assert(chk(-1000.0001) === false);
65 | assert(chk(Infinity) === true);
66 | assert(chk(-Infinity) === false);
67 | assert(chk(NaN) === false);
68 | assert(chk("0") === false);
69 | });
70 |
71 | it("integer", function () {
72 | var chk = typify.check("positive integer");
73 | assert(chk(0) === false);
74 | assert(chk(-0) === false);
75 | assert(chk(1) === true);
76 | assert(chk(-1) === false);
77 | assert(chk(0.1) === false);
78 | assert(chk(-1000.0001) === false);
79 | assert(chk(Infinity) === false);
80 | assert(chk(-Infinity) === false);
81 | assert(chk(NaN) === false);
82 | assert(chk("0") === false);
83 | });
84 | });
85 |
86 | describe("nonnegative", function () {
87 | it("works", function () {
88 | var chk = typify.check("nonnegative");
89 | assert(chk(0) === true);
90 | assert(chk(-0) === true);
91 | assert(chk(1) === true);
92 | assert(chk(-1) === false);
93 | assert(chk(0.1) === true);
94 | assert(chk(-1000.0001) === false);
95 | assert(chk(Infinity) === true);
96 | assert(chk(-Infinity) === false);
97 | assert(chk(NaN) === false);
98 | assert(chk("0") === false);
99 | });
100 |
101 | it("integer", function () {
102 | var chk = typify.check("nonnegative integer");
103 | assert(chk(0) === true);
104 | assert(chk(-0) === true);
105 | assert(chk(1) === true);
106 | assert(chk(-1) === false);
107 | assert(chk(0.1) === false);
108 | assert(chk(-1000.0001) === false);
109 | assert(chk(Infinity) === false);
110 | assert(chk(-Infinity) === false);
111 | assert(chk(NaN) === false);
112 | assert(chk("0") === false);
113 | });
114 | });
115 |
116 | describe("finite", function () {
117 | it("works", function () {
118 | var chk = typify.check("finite");
119 | assert(chk(0) === true);
120 | assert(chk(-0) === true);
121 | assert(chk(1) === true);
122 | assert(chk(-1) === true);
123 | assert(chk(0.1) === true);
124 | assert(chk(-1000.0001) === true);
125 | assert(chk(Infinity) === false);
126 | assert(chk(-Infinity) === false);
127 | assert(chk(NaN) === false);
128 | assert(chk("0") === false);
129 | });
130 |
131 | it("integer", function () {
132 | var chk = typify.check("finite integer");
133 | assert(chk(0) === true);
134 | assert(chk(-0) === true);
135 | assert(chk(1) === true);
136 | assert(chk(-1) === true);
137 | assert(chk(0.1) === false);
138 | assert(chk(-1000.0001) === false);
139 | assert(chk(Infinity) === false);
140 | assert(chk(-Infinity) === false);
141 | assert(chk(NaN) === false);
142 | assert(chk("0") === false);
143 | });
144 | });
145 | }());
146 |
--------------------------------------------------------------------------------
/test/record.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, beforeEach */
2 |
3 | "use strict";
4 |
5 | var typify = require("../lib/typify.js");
6 | var assert = require("assert");
7 |
8 | describe("records", function () {
9 | var typ;
10 | beforeEach(function () {
11 | typ = typify.create();
12 | });
13 |
14 | describe("basic functionality", function () {
15 | var isPerson;
16 |
17 | beforeEach(function () {
18 | typ = typify.create();
19 | typ.record("person", {
20 | name: "string",
21 | age: "number",
22 | });
23 | isPerson = typ.check("person");
24 | });
25 |
26 | it("adds type definition which is falsy for non-objects", function () {
27 | assert(!isPerson(undefined));
28 | assert(!isPerson(null));
29 | assert(!isPerson(true));
30 | assert(!isPerson(false));
31 | assert(!isPerson(0));
32 | assert(!isPerson(1));
33 | assert(!isPerson(""));
34 | assert(!isPerson("foobar"));
35 | });
36 |
37 | it("is falsy for objects with missing properties", function () {
38 | assert(!isPerson({}));
39 | assert(!isPerson({ age: 10 }));
40 | assert(!isPerson({ name: "foo" }));
41 | });
42 |
43 | it("is truthy for objects with all properties", function () {
44 | assert(isPerson({ age: 10, name: "foo" }));
45 | });
46 |
47 | it("is truthy for objects with extra properties", function () {
48 | assert(isPerson({ age: 10, name: "foo", height: 175 }));
49 | });
50 | });
51 |
52 | describe("closed", function () {
53 | var isPerson;
54 |
55 | beforeEach(function () {
56 | typ.record("person", {
57 | name: "string",
58 | age: "number",
59 | }, true);
60 | isPerson = typ.check("person");
61 | });
62 |
63 | it("is falsy for objects with missing properties", function () {
64 | assert(!isPerson({}));
65 | assert(!isPerson({ age: 10 }));
66 | assert(!isPerson({ name: "foo" }));
67 | });
68 |
69 | it("is truthy for objects with all properties", function () {
70 | assert(isPerson({ age: 10, name: "foo" }));
71 | });
72 |
73 | it("is falsy for objects with extra properties", function () {
74 | assert(!isPerson({ age: 10, name: "foo", height: 175 }));
75 | });
76 | });
77 |
78 | describe("anonymous records", function () {
79 | var isPerson;
80 |
81 | beforeEach(function () {
82 | typ = typify.create();
83 | typ.alias("person", "{name: string, age: number}");
84 | isPerson = typ.check("person");
85 | });
86 |
87 | it("adds type definition which is falsy for non-objects", function () {
88 | assert(!isPerson(undefined));
89 | assert(!isPerson(null));
90 | assert(!isPerson(true));
91 | assert(!isPerson(false));
92 | assert(!isPerson(0));
93 | assert(!isPerson(1));
94 | assert(!isPerson(""));
95 | assert(!isPerson("foobar"));
96 | });
97 |
98 | it("is falsy for objects with missing properties", function () {
99 | assert(!isPerson({}));
100 | assert(!isPerson({ age: 10 }));
101 | assert(!isPerson({ name: "foo" }));
102 | });
103 |
104 | it("is truthy for objects with all properties", function () {
105 | assert(isPerson({ age: 10, name: "foo" }));
106 | });
107 |
108 | it("is truthy for objects with extra properties", function () {
109 | assert(isPerson({ age: 10, name: "foo", height: 175 }));
110 | });
111 | });
112 |
113 | describe("recursive", function () {
114 | it("you can have", function () {
115 | typ.record("bst", {
116 | left: "bst?",
117 | right: "bst?",
118 | });
119 |
120 | var tree = {
121 | left: {
122 | left: { value: 1 },
123 | right: { value: 2 },
124 | },
125 | value: 3,
126 | right: {
127 | value: 4,
128 | right: {
129 | value: 5,
130 | }
131 | },
132 | };
133 |
134 | assert(typ.check("bst", tree));
135 | });
136 | });
137 |
138 | describe("special cases", function () {
139 | it("doesn't check prototype properties", function () {
140 | function P () {}
141 | P.prototype.name = "string";
142 | P.prototype.age = "number";
143 | typ.record("person", new P());
144 |
145 | assert(typ.check("person", {}));
146 | });
147 | });
148 | });
149 |
--------------------------------------------------------------------------------
/test/show.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 |
3 | "use strict";
4 |
5 | var assert = require("assert");
6 | var parse = require("../lib/checkableParser.js").parse;
7 | var cons = require("../lib/checkableConstructors.js");
8 | var show = require("../lib/show.js");
9 | var jsc = require("jsverify");
10 |
11 | function assertC(from, expected) {
12 | var actual = show.checkable(parse(from));
13 | assert.strictEqual(actual, expected);
14 | }
15 |
16 | describe("show", function () {
17 | describe("checkable", function () {
18 | it("shows any", function () {
19 | assertC(" * ", "*");
20 | });
21 |
22 | it("shows var", function () {
23 | assertC("foo", "foo");
24 | });
25 |
26 | it("shows alt", function () {
27 | assertC("foo | bar", "foo|bar");
28 | });
29 |
30 | it("shows and", function () {
31 | assertC("foo & bar", "foo&bar");
32 | });
33 |
34 | it("shwos poly", function () {
35 | assertC("foo bar", "foo bar");
36 | });
37 |
38 | it("shows opt", function () {
39 | assertC("foo ?", "foo?");
40 | });
41 |
42 | it("parenthises", function () {
43 | assertC("foo (bar | baz)", "foo (bar|baz)");
44 | });
45 | });
46 | });
47 |
48 | function arbitraryArray(size, arbitrary) {
49 | size = 2 + jsc.random(0, size);
50 | var arr = [];
51 | for (var i = 0; i < size; i++) {
52 | arr.push(arbitrary());
53 | }
54 | return arr;
55 | }
56 |
57 | var idents = [ "foo", "bar", "baz", "quux", "true", "false", "null" ];
58 | var identArb = jsc.elements(idents);
59 |
60 | var checkableGenerator = jsc.generator.recursive(
61 | jsc.generator.oneof([
62 | jsc.generator.constant(cons.any),
63 | jsc.nat(10).generator.map(cons.number),
64 | identArb.generator.map(cons.string),
65 | identArb.generator.map(cons.variable),
66 | ]),
67 | function (gen) {
68 | return jsc.generator.oneof([
69 | jsc.generator.nearray(gen).map(cons.alt),
70 | jsc.generator.nearray(gen).map(cons.and),
71 | jsc.generator.combine(identArb.generator, jsc.generator.nearray(gen), cons.poly),
72 | gen.map(cons.opt),
73 | jsc.generator.array(jsc.generator.pair(identArb.generator, gen)).map(function (spec) {
74 | var fields = {};
75 | spec.forEach(function (pair) {
76 | fields[pair[0]] = pair[1];
77 | });
78 | return cons.record(fields);
79 | }),
80 | ]);
81 | }
82 | );
83 |
84 | var checkableArb = jsc.bless({
85 | generator: checkableGenerator
86 | });
87 |
88 | describe("show + parse", function () {
89 | it("show . parse . show = show", function () {
90 | function normalize(t) {
91 | return parse(show.checkable(t));
92 | }
93 |
94 | var property = jsc.forall(checkableArb, function (t) {
95 | var n = normalize(t);
96 | return show.checkable(t) === show.checkable(n);
97 | });
98 |
99 | jsc.assert(property);
100 | });
101 | });
102 |
--------------------------------------------------------------------------------
/test/typify.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, beforeEach */
2 | (function () {
3 | "use strict";
4 |
5 | var typify = require("../lib/typify.js");
6 | var assert = require("assert");
7 |
8 | // identity
9 | function id(x) { return x; }
10 |
11 | // safe executor
12 | Function.prototype.safeapply = function safe(args) {
13 | try {
14 | return this.apply(this, args);
15 | } catch (e) {
16 | // console.error(e.toString());
17 | return "_|_";
18 | }
19 | };
20 |
21 | function itreturns(fname, f, specs) {
22 | specs.forEach(function (v) {
23 | var params = v.slice(0, -1);
24 | var ret = v.slice(-1)[0];
25 |
26 | it(fname + "(" + params.map(JSON.stringify).join(", ") + ") == " + (ret === "_|_" ? ret : JSON.stringify(ret)), function() {
27 | assert.deepEqual(f.safeapply(params), ret);
28 | });
29 | });
30 | }
31 |
32 | describe("examples:", function () {
33 | var factorial = typify("number -> number", function factorial(n) {
34 | if (n === 0) {
35 | return 1;
36 | } else {
37 | return n * factorial(n-1);
38 | }
39 | });
40 |
41 | itreturns("factorial", factorial, [
42 | [3, 6],
43 | ["foo", "_|_"],
44 | [1, 2, "_|_"],
45 | ]);
46 |
47 | function doubleImpl(v) {
48 | return v + v;
49 | }
50 |
51 | var double1 = typify("* -> number", doubleImpl);
52 | itreturns("double1", double1, [
53 | [1, 2],
54 | ["foo", "_|_"],
55 | ]);
56 |
57 | var double2 = typify("number -> number", doubleImpl);
58 | itreturns("double2", double2, [
59 | [1, 2],
60 | ["foo", "_|_"],
61 | ]);
62 |
63 | var double3 = typify("number|string -> number|string", doubleImpl);
64 | itreturns("double3", double3, [
65 | [1, 2],
66 | ["foo", "foofoo"],
67 | [true, "_|_"],
68 | ]);
69 |
70 | var double4 = typify("a : number|string => a -> a", doubleImpl);
71 | itreturns("double4", double4, [
72 | [1, 2],
73 | ["foo", "foofoo"],
74 | [true, "_|_"],
75 | ]);
76 |
77 | var choose = typify("choose :: boolean -> number? -> number? -> number", function choose(test, t, f) {
78 | return test ? (t ? t : 1) : (f ? f : 0);
79 | });
80 | itreturns("choose", choose, [
81 | [true, 2, 1, 2],
82 | [true, 2, null, "_|_"],
83 | [true, undefined, 3, 1],
84 | [true, 2, undefined, 2],
85 | [true, 2, 2],
86 | [true, 1],
87 | ["_|_"],
88 | [true, 1, 2, 3, "_|_"],
89 | ]);
90 | });
91 |
92 | describe("separate instances - create()", function () {
93 | it("don't share types", function () {
94 | var typ1 = typify.create();
95 | var typ2 = typify.create();
96 |
97 | typ1.type("tru", function () { return true; });
98 | typ2.type("t", function () { return true; });
99 |
100 | assert(typ1.check("tru", 1));
101 | assert(typ2.check("t", 1));
102 |
103 | assert.throws(function () {
104 | typ1.check("t", 1);
105 | });
106 |
107 | assert.throws(function () {
108 | typ2.check("tru", 1);
109 | });
110 |
111 | assert.throws(function () {
112 | typify.check("t", 1);
113 | });
114 |
115 | assert.throws(function () {
116 | typify.check("tru", 1);
117 | });
118 | });
119 | });
120 |
121 | describe("intersection types", function () {
122 | typify.record("duck", {
123 | quack: "function",
124 | });
125 |
126 | typify.record("mammal", {
127 | milk: "function",
128 | });
129 |
130 | it("are useful when ducktyping", function () {
131 | var platypus = {
132 | quack: id,
133 | milk: id,
134 | };
135 |
136 | assert(typify.check("duck", platypus));
137 | assert(typify.check("mammal", platypus));
138 | assert(typify.check("mammal&duck", platypus));
139 |
140 | assert(!typify.check("number&string", 1));
141 | });
142 | });
143 |
144 | describe("aliases - alias()", function () {
145 | var typ;
146 |
147 | beforeEach(function () {
148 | typ = typify.create();
149 | });
150 |
151 | it("could be use to reduce repetition", function () {
152 | typ.alias("numstr", "number|string");
153 |
154 | assert(typ.check("numstr", 1));
155 | assert(typ.check("numstr", "foo"));
156 | assert(!typ.check("numstr", true));
157 | });
158 |
159 | it("can be recursive", function () {
160 | typ.alias("rarray", "array rarray");
161 |
162 | assert(typ.check("rarray", []));
163 | assert(!typ.check("rarray", 1));
164 | assert(typ.check("rarray", [[]]));
165 | assert(!typ.check("rarray", [[1]]));
166 | assert(typ.check("rarray", [[], [], [[[[[[[[]]]]]], []]]]));
167 | });
168 | });
169 |
170 | describe("mutual recursive types - mutual()", function () {
171 | var typ;
172 |
173 | beforeEach(function () {
174 | typ = typify.create();
175 | });
176 |
177 | it("can be recursive", function () {
178 | typ.mutual({
179 | "foo": "array bar",
180 | "bar": "array foo",
181 | });
182 |
183 | assert(typ.check("foo", []));
184 | assert(!typ.check("foo", 1));
185 | assert(typ.check("foo", [[]]));
186 | assert(!typ.check("foo", [[1]]));
187 | assert(typ.check("foo", [[], [], [[[[[[[[]]]]]], []]]]));
188 |
189 | assert(typ.check("bar", []));
190 | assert(!typ.check("bar", 1));
191 | assert(typ.check("bar", [[]]));
192 | assert(!typ.check("bar", [[1]]));
193 | assert(typ.check("bar", [[], [], [[[[[[[[]]]]]], []]]]));
194 | });
195 | });
196 |
197 | describe("(kind of) abstract data types", function () {
198 | var typ;
199 |
200 | beforeEach(function () {
201 | typ = typify.create();
202 | });
203 |
204 | it("work", function () {
205 | typ.adt("option", {
206 | "none": "{ type: 'none' }",
207 | "some": "{ type: 'some', value: * }",
208 | });
209 |
210 | var someValue = { type: "some", value: 1 };
211 | var noneValue = { type: "none" };
212 | var otherValue = 1;
213 |
214 | assert(typ.check("option", someValue));
215 | assert(typ.check("some", someValue));
216 | assert(!typ.check("none", someValue));
217 | assert(!typ.check("number", someValue));
218 |
219 | assert(typ.check("option", noneValue));
220 | assert(!typ.check("some", noneValue));
221 | assert(typ.check("none", noneValue));
222 | assert(!typ.check("number", noneValue));
223 |
224 | assert(!typ.check("option", otherValue));
225 | assert(!typ.check("some", otherValue));
226 | assert(!typ.check("none", otherValue));
227 | assert(typ.check("number", otherValue));
228 | });
229 |
230 | it("constructor cannot has the same name", function () {
231 | assert.throws(function () {
232 | typ.adt("foo", { foo: "number "});
233 | });
234 | });
235 | });
236 |
237 | describe("instanceof types - instance()", function () {
238 | var typ;
239 |
240 | beforeEach(function () {
241 | typ = typify.create();
242 | });
243 |
244 | it("work", function () {
245 | function Foo() {}
246 | function Bar() {}
247 |
248 | typ.instance("Foo", Foo);
249 | typ.instance("Bar", Bar);
250 |
251 | assert(typ.check("Foo", new Foo()));
252 | assert(!typ.check("Foo", new Bar()));
253 |
254 | assert(!typ.check("Bar", new Foo()));
255 | assert(typ.check("Bar", new Bar()));
256 | });
257 | });
258 |
259 | describe("function types - typify()", function () {
260 | describe("actions", function () {
261 | it("are functions without parameters", function () {
262 | var r = typify("r :: -> number", function () {
263 | return 4;
264 | });
265 |
266 | r();
267 | });
268 | });
269 |
270 | describe("context", function () {
271 | it("polytypes don't need braces", function () {
272 | var f = typify("a : array * => a -> a", id);
273 | assert.deepEqual(f(["foo"]), ["foo"]);
274 | });
275 |
276 | it("optional types don't need braces", function () {
277 | var f = typify("a : number? => a -> a", id);
278 | assert(f(undefined) === undefined);
279 | });
280 |
281 | it("alternative types need braces", function () {
282 | var f = typify("a : number|string => a -> a", id);
283 | assert(f(1) === 1);
284 | assert(f("foo") === "foo");
285 |
286 | var g = typify("a : (number|string) => a -> a", function() { return "const"; });
287 | assert(g(1) === "const");
288 | assert(g("foo") === "const");
289 |
290 | var h = typify("a : number|string => a -> a", function() { return "const"; });
291 | assert.throws(function () {
292 | return h(1);
293 | });
294 | });
295 |
296 | it("context variable may be polytype", function () {
297 | var f = typify("a : map | array, b : number | string => a b -> a b", id);
298 | assert.deepEqual(f([1, 2, 3]), [1, 2, 3]);
299 | assert.deepEqual(f(["foo", "bar"]), ["foo", "bar"]);
300 | assert.deepEqual(f({ "foo": 1, "bar": 2 }), { "foo": 1, "bar": 2 });
301 | assert.deepEqual(f({ "foo": "bar" }), { "foo": "bar" });
302 | assert.throws(function() { f([true]); });
303 | assert.throws(function() { f({ "foo": true }); });
304 | assert.throws(function() { f("foo"); });
305 | });
306 | });
307 |
308 | describe("rest parameters", function () {
309 | it("accepts any parameters", function () {
310 | var f = typify("... -> number", function () {
311 | return arguments.length;
312 | });
313 |
314 | var arr = [];
315 | for (var i = 0; i < 20; i++) {
316 | assert(f.apply(undefined, arr) === i);
317 | arr.push(i);
318 | }
319 | });
320 |
321 | it("accepts parameters of specified type", function () {
322 | var f = typify("number... -> number", function () {
323 | return arguments.length;
324 | });
325 |
326 | var arr = [];
327 | for (var i = 0; i < 20; i++) {
328 | assert(f.apply(undefined, arr) === i);
329 | arr.push(i);
330 | }
331 | });
332 |
333 | it("accepts context variable as rest type", function () {
334 | var f = typify("a : number|string => a... -> number", function () {
335 | return arguments.length;
336 | });
337 |
338 | var numarr = [];
339 | for (var i = 0; i < 20; i++) {
340 | assert(f.apply(undefined, numarr) === i);
341 | numarr.push(i);
342 | }
343 |
344 | var strarr = [];
345 | for (var j = 0; j < 20; j++) {
346 | assert(f.apply(undefined, strarr) === j);
347 | strarr.push(""+j);
348 | }
349 | });
350 | });
351 | });
352 | }());
353 |
--------------------------------------------------------------------------------
/test/version.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 |
3 | "use strict";
4 |
5 | var fs = require("fs");
6 | var typify = require("../lib/typify.js");
7 | var assert = require("assert");
8 |
9 | describe("version", function () {
10 | it("same in package.json and inside lib", function () {
11 | var pkg = JSON.parse(fs.readFileSync(__dirname + "/../package.json"));
12 | assert(pkg.version === typify.version.join("."), "version string should be same");
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/verify-branch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | # set -x
5 |
6 | COMMITS=`git log master.. --oneline | cut -d " " -f 1 | tail -r`
7 |
8 | for COMMIT in $COMMITS; do
9 | echo "Checking commit" $COMMIT
10 | git checkout $COMMIT
11 | npm install
12 | npm test
13 | done
14 |
--------------------------------------------------------------------------------