├── .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 | [![Build Status](https://secure.travis-ci.org/phadej/typify.svg?branch=master)](http://travis-ci.org/phadej/typify) 6 | [![NPM version](https://badge.fury.io/js/typify.svg)](http://badge.fury.io/js/typify) 7 | [![Dependency Status](https://gemnasium.com/phadej/typify.svg)](https://gemnasium.com/phadej/typify) 8 | [![Code Climate](https://img.shields.io/codeclimate/github/phadej/typify.svg)](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":"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"} -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------