Socket
Socket
Sign inDemoInstall

intertype

Package Overview
Dependencies
Maintainers
1
Versions
101
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

intertype - npm Package Compare versions

Comparing version 7.7.1 to 10.0.0

build-npmignore

678

lib/declarations.js
(function() {
//...........................................................................................................
// { equals, } = require 'cnd'
var CHECKS, assign, jr, js_type_of, jsidentifier_pattern, xrpr,
modulo = function(a, b) { return (+a % (b = +b) + b) % b; };
({assign, jr, xrpr, js_type_of} = require('./helpers'));
CHECKS = require('./checks');
/* thx to
https://github.com/mathiasbynens/mothereff.in/blob/master/js-variables/eff.js
https://mathiasbynens.be/notes/javascript-identifiers-es6
*/
// jsidentifier_pattern = /^(?:[\$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D])(?:[\$0-9A-Z_a-z\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF])*$/
jsidentifier_pattern = /^(?:[$_]|\p{ID_Start})(?:[$_\u{200c}\u{200d}]|\p{ID_Continue})*$/u;
//===========================================================================================================
// XML Names, IDs
//-----------------------------------------------------------------------------------------------------------
/*
* https://www.w3.org/TR/xml/#NT-Name
* Observe that in HTML5 (but not earlier versions), most restrictions on ID values have been removed; to
quote: "There are no other restrictions on what form an ID can take; in particular, IDs can consist of
just digits, start with a digit, start with an underscore, consist of just punctuation, etc."
[4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
[5] Name ::= NameStartChar (NameChar)*
*/
//===========================================================================================================
// OTF Glyph Names
//-----------------------------------------------------------------------------------------------------------
/*
From https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#2.f.i
> A glyph name may be up to 63 characters in length, must be entirely comprised of characters from the
> following set:
>
> ```
> ABCDEFGHIJKLMNOPQRSTUVWXYZ
> abcdefghijklmnopqrstuvwxyz
> 0123456789
> . # period
> _ # underscore
> ```
>
> and must not start with a digit or period. The only exception is the special character “.notdef”.
>
> “twocents”, “a1”, and “_” are valid glyph names. “2cents” and “.twocents” are “not.
*/
//===========================================================================================================
// TYPE DECLARATIONS
//-----------------------------------------------------------------------------------------------------------
this.declare_types = function() {
/* NOTE to be called as `( require './declarations' ).declare_types.apply instance` */
this.declare('null', (x) => {
return x === null;
});
this.declare('undefined', (x) => {
return x === void 0;
});
this._provisional_declare_basic_types = function(hub) {
var declare;
({declare} = hub);
//---------------------------------------------------------------------------------------------------------
// Bottom Types
//.........................................................................................................
this.declare('sad', (x) => {
return CHECKS.is_sad(x);
declare.null({
isa: function(x) {
return x === null;
},
default: null
});
this.declare('happy', (x) => {
return CHECKS.is_happy(x);
});
this.declare('saddened', (x) => {
return CHECKS.is_saddened(x);
});
this.declare('symbol', (x) => {
return typeof x === 'symbol';
});
//.........................................................................................................
this.declare('boolean', {
tests: {
"x is true or false": (x) => {
return (x === true) || (x === false);
}
declare.undefined({
isa: function(x) {
return x === void 0;
},
casts: {
float: (x) => {
if (x) {
return 1;
} else {
return 0;
}
}
}
default: void 0
});
//.........................................................................................................
this.declare('nan', (x) => {
return Number.isNaN(x);
});
this.declare('finite', (x) => {
return Number.isFinite(x);
});
this./* TAINT make sure no non-numbers slip through */declare('integer', (x) => {
return Number.isInteger(x);
});
this./* TAINT make sure no non-numbers slip through */declare('safeinteger', (x) => {
return Number.isSafeInteger(x);
});
//.........................................................................................................
/* FTTB we are retaining `number` as a less-preferred synonym for `float`; in the future, `number` may
be removed because it conflicts with JS usage (where it includes `NaN` and `+/-Infinity`) and, moreover,
is not truthful (because it is a poor representation of what the modern understanding of 'number' in the
mathematical sense would imply). */
/* NOTE removed in v8: `@specs.number = @specs.float` */
this./* TAINT make sure no non-numbers slip through */declare('number', (x) => {
return false; // throw new Error "^intertype@84744^ type 'number' is deprecated"
});
this.declare('float', {
tests: (x) => {
return Number.isFinite(x);
declare.bottom({
isa: function(x) {
return (x === void 0) || (x === null);
},
casts: {
boolean: (x) => {
if (x === 0) {
return false;
} else {
return true;
}
},
integer: (x) => {
return Math.round(x);
}
}
default: void 0
});
//---------------------------------------------------------------------------------------------------------
// Existential Types
//.........................................................................................................
this.declare('frozen', (x) => {
return Object.isFrozen(x);
declare.anything(function(x) {
return true;
});
this.declare('sealed', (x) => {
return Object.isSealed(x);
declare.something(function(x) {
return x != null;
});
this.declare('extensible', (x) => {
return Object.isExtensible(x);
});
//.........................................................................................................
this.declare('numeric', (x) => {
return (js_type_of(x)) === 'number';
});
this.declare('function', (x) => {
return (js_type_of(x)) === 'function';
});
this.declare('asyncfunction', (x) => {
return (js_type_of(x)) === 'asyncfunction';
});
this.declare('generatorfunction', (x) => {
return (js_type_of(x)) === 'generatorfunction';
});
this.declare('asyncgeneratorfunction', (x) => {
return (js_type_of(x)) === 'asyncgeneratorfunction';
});
this.declare('asyncgenerator', (x) => {
return (js_type_of(x)) === 'asyncgenerator';
});
this.declare('generator', (x) => {
return (js_type_of(x)) === 'generator';
});
this.declare('date', (x) => {
return (js_type_of(x)) === 'date';
});
this.declare('listiterator', (x) => {
return (js_type_of(x)) === 'arrayiterator';
});
this.declare('textiterator', (x) => {
return (js_type_of(x)) === 'stringiterator';
});
this.declare('setiterator', (x) => {
return (js_type_of(x)) === 'setiterator';
});
this.declare('mapiterator', (x) => {
return (js_type_of(x)) === 'mapiterator';
});
this.declare('callable', (x) => {
var ref;
return (ref = this.type_of(x)) === 'function' || ref === 'asyncfunction' || ref === 'generatorfunction';
});
this.declare('promise', (x) => {
return (this.isa.nativepromise(x)) || (this.isa.thenable(x));
});
this.declare('nativepromise', (x) => {
return x instanceof Promise;
});
this.declare('thenable', (x) => {
return (this.type_of(x != null ? x.then : void 0)) === 'function';
});
this.declare('immediate', function(x) {
return !this.isa.promise(x);
});
//.........................................................................................................
this.declare('truthy', (x) => {
return !!x;
});
this.declare('falsy', (x) => {
return !x;
});
this.declare('true', (x) => {
return x === true;
});
this.declare('false', (x) => {
return x === false;
});
this.declare('unset', (x) => {
declare.nothing(function(x) {
return x == null;
});
this.declare('notunset', (x) => {
return x != null;
});
//---------------------------------------------------------------------------------------------------------
// Textual Types
//.........................................................................................................
this.declare('even', (x) => {
return (this.isa.safeinteger(x)) && (modulo(x, 2)) === 0;
declare.text({
collection: true,
isa: function(x) {
return (typeof x) === 'string';
},
default: ''
});
this.declare('odd', (x) => {
return (this.isa.safeinteger(x)) && (modulo(x, 2)) === 1;
});
this.declare('cardinal', function(x) {
return (this.isa.safeinteger(x)) && (this.isa.nonnegative(x));
});
this.declare('nonnegative', (x) => {
return (this.isa.infloat(x)) && (x >= 0);
});
this.declare('positive', (x) => {
return (this.isa.infloat(x)) && (x > 0);
});
this.declare('positive_float', (x) => {
return (this.isa.float(x)) && (x > 0);
});
this.declare('positive_integer', (x) => {
return (this.isa.integer(x)) && (x > 0);
});
this.declare('negative_integer', (x) => {
return (this.isa.integer(x)) && (x < 0);
});
this.declare('zero', (x) => {
return x === 0;
});
this.declare('infinity', (x) => {
return (x === +2e308) || (x === -2e308);
});
this.declare('infloat', (x) => {
return (this.isa.float(x)) || (x === 2e308) || (x === -2e308);
});
this.declare('nonpositive', (x) => {
return (this.isa.infloat(x)) && (x <= 0);
});
this.declare('negative', (x) => {
return (this.isa.infloat(x)) && (x < 0);
});
this.declare('negative_float', (x) => {
return (this.isa.float(x)) && (x < 0);
});
this.declare('proper_fraction', (x) => {
return (this.isa.float(x)) && ((0 <= x && x <= 1));
});
//.........................................................................................................
this.declare('empty', function(x) {
return (this.has_size(x)) && (this.size_of(x)) === 0;
declare.codepoint({
isa: function(x) {
return ((typeof x) === 'string') && /^.$/u.test(x);
},
default: '\x00'
});
this.declare('singular', function(x) {
return (this.has_size(x)) && (this.size_of(x)) === 1;
});
this.declare('nonempty', function(x) {
return (this.has_size(x)) && (this.size_of(x)) > 0;
});
this.declare('plural', function(x) {
return (this.has_size(x)) && (this.size_of(x)) > 1;
});
this.declare('blank_text', function(x) {
return (this.isa.text(x)) && ((x.match(/^\s*$/us)) != null);
});
this.declare('nonblank_text', function(x) {
return (this.isa.text(x)) && ((x.match(/^\s*$/us)) == null);
});
this.declare('chr', function(x) {
return (this.isa.text(x)) && ((x.match(/^.$/us)) != null);
});
this.declare('nonempty_text', function(x) {
return (this.isa.text(x)) && (this.isa.nonempty(x));
});
this.declare('nonempty_list', function(x) {
return (this.isa.list(x)) && (this.isa.nonempty(x));
});
this.declare('nonempty_object', function(x) {
return (this.isa.object(x)) && (this.isa.nonempty(x));
});
this.declare('nonempty_set', function(x) {
return (this.isa.set(x)) && (this.isa.nonempty(x));
});
this.declare('nonempty_map', function(x) {
return (this.isa.map(x)) && (this.isa.nonempty(x));
});
this.declare('empty_text', function(x) {
return (this.isa.text(x)) && (this.isa.empty(x));
});
this.declare('empty_list', function(x) {
return (this.isa.list(x)) && (this.isa.empty(x));
});
this.declare('empty_object', function(x) {
return (this.isa.object(x)) && (this.isa.empty(x));
});
this.declare('empty_set', function(x) {
return (this.isa.set(x)) && (this.isa.empty(x));
});
this.declare('empty_map', function(x) {
return (this.isa.map(x)) && (this.isa.empty(x));
});
// is_given = ( x ) -> not [ null, undefined, NaN, '', ].includes x
//.........................................................................................................
this.declare('buffer', {
size: 'length'
}, (x) => {
return Buffer.isBuffer(x);
declare.codepointid({
isa: function(x) {
return this.isa.integer(x && ((0x00000 <= x && x <= 0x1ffff)));
},
default: '\x00'
});
this.declare('arraybuffer', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'arraybuffer';
});
this.declare('int8array', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'int8array';
});
this.declare('uint8array', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'uint8array';
});
this.declare('uint8clampedarray', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'uint8clampedarray';
});
this.declare('int16array', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'int16array';
});
this.declare('uint16array', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'uint16array';
});
this.declare('int32array', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'int32array';
});
this.declare('uint32array', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'uint32array';
});
this.declare('float32array', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'float32array';
});
this.declare('float64array', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'float64array';
});
this.declare('list', {
size: 'length'
}, (x) => {
return (js_type_of(x)) === 'array';
});
this.declare('set', {
size: 'size'
}, function(x) {
return (js_type_of(x)) === 'set';
});
this.declare('map', {
size: 'size'
}, function(x) {
return (js_type_of(x)) === 'map';
});
this.declare('weakmap', function(x) {
return (js_type_of(x)) === 'weakmap';
});
this.declare('weakset', function(x) {
return (js_type_of(x)) === 'weakset';
});
this.declare('error', function(x) {
return (js_type_of(x)) === 'error';
});
this.declare('regex', function(x) {
return (js_type_of(x)) === 'regexp';
});
//---------------------------------------------------------------------------------------------------------
// Container Types
//.........................................................................................................
this.declare('object', {
tests: (x) => {
return (js_type_of(x)) === 'object';
declare.list({
collection: true,
isa: function(x) {
return Array.isArray(x);
},
size: (x) => {
return (Object.keys(x)).length;
}
default: []
});
//.........................................................................................................
this.declare('global', {
tests: (x) => {
return (js_type_of(x)) === 'global';
declare.set({
collection: true,
isa: function(x) {
return x instanceof Set;
},
size: (x) => {
return (Object.keys(x)).length;
create: function(cfg = []) {
return new Set(cfg);
}
});
//.........................................................................................................
this.declare('text', {
tests: (x) => {
return (js_type_of(x)) === 'string';
/* NOTE we use `GUY.props.get() for `sized` but direct property access for `iterable` b/c
`GUY.props.Strict_owner` special-cases access to `Symbol.iterator` (allowing it although not set) */
declare.sized({
collection: true,
isa: function(x) {
return (this.size_of(x, this._signals.nothing)) !== this._signals.nothing;
},
size: function(x, selector = 'codeunits') {
var ref;
switch (selector) {
case 'codepoints':
return (Array.from(x)).length;
case 'codeunits':
return x.length;
case 'bytes':
return Buffer.byteLength(x, (ref = typeof settings !== "undefined" && settings !== null ? settings['encoding'] : void 0) != null ? ref : 'utf-8');
default:
throw new Error(`unknown counting selector ${rpr(selector)}`);
}
}
default: []
});
//.........................................................................................................
this.declare('list_of', {
tests: {
"x is a list": (type, x, ...xP) => {
return this.isa.list(x);
},
/* TAINT should check for `@isa.type type` */
"type is nonempty_text": (type, x, ...xP) => {
return this.isa.nonempty_text(type);
},
"all elements pass test": (type, x, ...xP) => {
return x.every((xx) => {
return this.isa(type, xx, ...xP);
});
}
}
declare.iterable({
isa: function(x) {
return (x != null) && (x[Symbol.iterator] != null);
},
default: []
});
//.........................................................................................................
this.declare('object_of', {
tests: {
"x is a object": (type, x, ...xP) => {
return this.isa.object(x);
},
/* TAINT should check for `@isa.type type` */
"type is nonempty_text": (type, x, ...xP) => {
return this.isa.nonempty_text(type);
},
"all elements pass test": (type, x, ...xP) => {
var _, xx;
for (_ in x) {
xx = x[_];
if (!this.isa(type, xx, ...xP)) {
return false;
}
}
return true;
}
}
declare.container({
isa: function(x) {
return (typeof x) !== 'string' && (this.iterable(x)) && (this.sized(x));
},
default: []
});
//---------------------------------------------------------------------------------------------------------
// Numeric Types
//.........................................................................................................
this.declare('jsidentifier', {
tests: (x) => {
return (this.isa.text(x)) && jsidentifier_pattern.test(x);
}
declare.numeric({
isa: function(x) {
return (Number.isFinite(x)) || (typeof x === 'bigint');
},
default: 0
});
//.........................................................................................................
this.declare('int2text', {
tests: (x) => {
return (this.isa.text(x)) && ((x.match(/^[01]+$/)) != null);
declare.float({
isa: function(x) {
return Number.isFinite(x);
},
casts: {
float: (x) => {
return parseInt(x, 2);
}
}
default: 0
});
//.........................................................................................................
this.declare('int10text', {
tests: (x) => {
return (this.isa.text(x)) && ((x.match(/^[0-9]+$/)) != null);
declare.bigint({
isa: function(x) {
return typeof x === 'bigint';
},
casts: {
float: (x) => {
return parseInt(x, 10);
}
}
default: 0n
});
//.........................................................................................................
this.declare('int16text', {
tests: (x) => {
return (this.isa.text(x)) && ((x.match(/^[0-9a-fA-F]+$/)) != null);
declare.integer({
isa: function(x) {
return Number.isInteger(x);
},
casts: {
float: (x) => {
return parseInt(x, 16);
},
int2text: (x) => {
return (parseInt(x, 16)).toString(2);
}
}
default: 0
});
//.........................................................................................................
this./* TAINT could use `cast()` API */declare('int32', function(x) {
return (this.isa.integer(x)) && ((-2147483648 <= x && x <= 2147483647));
declare.negatable({ // numeric? numeral?
isa: function(x) {
return (typeof x) === (typeof -x);
},
default: 0
});
//.........................................................................................................
this.declare('vnr', function(x) {
/* A vectorial number (VNR) is a non-empty array of numbers, including infinity. */
return (this.isa_list_of.infloat(x)) && (x.length > 0);
declare.even({
default: 0,
isa: function(x) {
if (Number.isInteger(x)) {
return (x % 2) === 0;
} else if (typeof x === 'bigint') {
return (x % 2n) === 0n;
}
return false;
}
});
//.........................................................................................................
return this.declare('fs_stats', {
tests: {
'x is an object': function(x) {
return this.isa.object(x);
},
'x.size is a cardinal': function(x) {
return this.isa.cardinal(x.size);
},
'x.atimeMs is a float': function(x) {
return this.isa.float(x.atimeMs);
},
'x.atime is a date': function(x) {
return this.isa.date(x.atime);
declare.odd({
default: 1,
isa: function(x) {
if (Number.isInteger(x)) {
return (x % 2) !== 0;
} else if (typeof x === 'bigint') {
return (x % 2n) !== 0n;
}
return false;
}
});
};
//===========================================================================================================
// TYPE DECLARATIONS
//-----------------------------------------------------------------------------------------------------------
this.declare_checks = function() {
var FS, PATH;
PATH = require('path');
FS = require('fs');
//---------------------------------------------------------------------------------------------------------
// Other Types
//.........................................................................................................
/* NOTE: will throw error unless path exists, error is implicitly caught, represents sad path */
this.declare_check('fso_exists', function(path, stats = null) {
return FS.statSync(path);
declare.boolean({
isa: function(x) {
return (x === true) || (x === false);
},
default: false
});
// try ( stats ? FS.statSync path ) catch error then error
//.........................................................................................................
this.declare_check('is_file', function(path, stats = null) {
var bad;
if (this.is_sad((bad = stats = this.check.fso_exists(path, stats)))) {
return bad;
}
if (stats.isFile()) {
return stats;
}
return this.sadden(`not a file: ${path}`);
declare.object({
isa: function(x) {
return (x != null) && (typeof x) === 'object';
},
default: {}
});
//.........................................................................................................
return this.declare_check('is_json_file', function(path) {
var error;
try {
return JSON.parse(FS.readFileSync(path));
} catch (error1) {
error = error1;
return error;
}
});
return null;
};
// #.........................................................................................................
// @declare_check 'equals', ( a, P... ) ->
// for b in P
// return CHECKS.sad unless equals a, b
// return true
/* not supported until we figure out how to do it in strict mode: */
// @declare 'arguments', ( x ) -> ( js_type_of x ) is 'arguments'
// Array.isArray
// ArrayBuffer.isView
// Atomics.isLockFree
// Buffer.isBuffer
// Buffer.isEncoding
// constructor.is
// constructor.isExtensible
// constructor.isFrozen
// constructor.isSealed
// Number.isFinite
// Number.isInteger
// Number.isNaN
// Number.isSafeInteger
// Object.is
// Object.isExtensible
// Object.isFrozen
// Object.isSealed
// Reflect.isExtensible
// root.isFinite
// root.isNaN
// Symbol.isConcatSpreadable
}).call(this);
//# sourceMappingURL=declarations.js.map
(function() {
'use strict';
var LOUPE, inspect, rpr,
var E, GUY, Intertype_abc, misfit, notavalue,
indexOf = [].indexOf;
//-----------------------------------------------------------------------------------------------------------
({inspect} = require('util'));
GUY = require('guy');
this.assign = Object.assign;
misfit = Symbol('misfit');
// @jr = JSON.stringify
LOUPE = require('../deps/loupe.js');
notavalue = Symbol('notavalue');
this.rpr = rpr = (x) => {
return LOUPE.inspect(x, {
customInspect: false
E = require('./errors');
//...........................................................................................................
this.constructor_of_generators = ((function*() {
return (yield 42);
})()).constructor;
this.deep_copy = structuredClone;
this.equals = require('../deps/jkroso-equals');
this.nameit = function(name, f) {
return Object.defineProperty(f, 'name', {
value: name
});
};
this.xrpr = function(x) {
return (rpr(x)).slice(0, 1025);
};
//===========================================================================================================

@@ -41,3 +47,3 @@ // TYPE_OF FLAVORS

this.js_type_of = (x) => {
return ((Object.prototype.toString.call(x)).slice(8, -1)).toLowerCase().replace(/\s+/g, '');
return Object.prototype.toString.call(x);
};

@@ -90,4 +96,284 @@

//---------------------------------------------------------------------------------------------------------
this.size_of = function(x, fallback = misfit) {
var R;
if ((R = GUY.props.get(x, 'length', notavalue)) !== notavalue) {
return R;
}
if ((R = GUY.props.get(x, 'size', notavalue)) !== notavalue) {
return R;
}
if (fallback !== misfit) {
return fallback;
}
throw new E.Intertype_ETEMPTBD('^intertype.size_of@1^', `expected an object with \`x.length\` or \`x.size\`, got a ${this.type_of(x)} with neither`);
};
//---------------------------------------------------------------------------------------------------------
this.signals = GUY.lft.freeze(new GUY.props.Strict_owner({
target: {
return_true: Symbol('return_true'),
advance: Symbol('advance'),
// element_mode: Symbol 'element_mode'
nothing: Symbol('nothing')
}
}));
//-----------------------------------------------------------------------------------------------------------
this.type_of = function(x) {
var R, arity, c, tagname;
if ((arity = arguments.length) !== 1) {
throw new Error(`^7746^ expected 1 argument, got ${arity}`);
}
if (x === null) {
return 'null';
}
if (x === void 0) {
return 'undefined';
}
if ((x === 2e308) || (x === -2e308)) {
return 'infinity';
}
if ((x === true) || (x === false)) {
return 'boolean';
}
if (Number.isNaN(x)) {
return 'nan';
}
if (Number.isFinite(x)) {
return 'float';
}
if (Buffer.isBuffer(x)) {
return 'buffer';
}
if (Array.isArray(x)) {
return 'list';
}
//.........................................................................................................
/* TAINT Not needed (?) b/c `@js_type_of x` does work with these values, too */
/* this catches `Array Iterator`, `String Iterator`, `Map Iterator`, `Set Iterator`: */
if (((tagname = x[Symbol.toStringTag]) != null) && (typeof tagname) === 'string') {
return this._normalize_type(tagname);
}
if ((c = x.constructor) === void 0) {
//.........................................................................................................
/* Domenic Denicola Device, see https://stackoverflow.com/a/30560581 */
return 'nullobject';
}
if ((typeof c) !== 'function') {
return 'object';
}
if ((R = c.name.toLowerCase()) === '') {
if (x.constructor === this.constructor_of_generators) {
return 'generator';
}
/* NOTE: throw error since this should never happen */
return ((Object.prototype.toString.call(x)).slice(8, -1)).toLowerCase();
}
if ((typeof x === 'object') && (R === 'boolean' || R === 'number' || R === 'string')) {
//.........................................................................................................
/* Mark Miller Device */ return 'wrapper';
}
if (R === 'regexp') {
return 'regex';
}
if (R === 'string') {
return 'text';
}
if (R === 'function' && x.toString().startsWith('class ')) {
/* thx to https://stackoverflow.com/a/29094209 */
/* TAINT may produce an arbitrarily long throwaway string */
return 'class';
}
return R;
};
//===========================================================================================================
// INTERNAL TYPES
//-----------------------------------------------------------------------------------------------------------
this.types = new (require('intertype-legacy')).Intertype();
this.defaults = {};
//-----------------------------------------------------------------------------------------------------------
this.types.declare('deep_boolean', function(x) {
return x === 'deep' || x === false || x === true;
});
//-----------------------------------------------------------------------------------------------------------
this.types.declare('Type_cfg_constructor_cfg', {
tests: {
"@isa.object x": function(x) {
return this.isa.object(x);
},
"@isa.nonempty_text x.name": function(x) {
return this.isa.nonempty_text(x.name);
},
// "@isa.deep_boolean x.copy": ( x ) -> @isa.boolean x.copy
// "@isa.boolean x.seal": ( x ) -> @isa.boolean x.seal
"@isa.deep_boolean x.freeze": function(x) {
return this.isa.deep_boolean(x.freeze);
},
"@isa.boolean x.extras": function(x) {
return this.isa.boolean(x.extras);
},
"if extras is false, default must be an object": function(x) {
return x.extras || (this.isa.object(x.default));
},
"@isa_optional.function x.create": function(x) {
return this.isa_optional.function(x.create);
},
/* TAINT might want to check for existence of `$`-prefixed keys in case of `( not x.test? )` */
/* TAINT should validate values of `$`-prefixed keys are either function or non-empty strings */
"x.test is an optional function or non-empty list of functions": function(x) {
if (x.test == null) {
return true;
}
if (this.isa.function(x.test)) {
return true;
}
if (!this.isa_list_of.function(x.test)) {
return false;
}
if (x.test.length === 0) {
return false;
}
return true;
},
"x.groups is deprecated": function(x) {
return x.groups == null;
},
"@isa.boolean x.collection": function(x) {
return this.isa.boolean(x.collection);
}
}
});
//...........................................................................................................
this.defaults.Type_cfg_constructor_cfg = {
name: null,
test: null,
/* `default` omitted on purpose */
create: null,
// copy: false
// seal: false
freeze: false,
extras: true,
collection: false
};
//-----------------------------------------------------------------------------------------------------------
this.types.declare('Type_factory_type_dsc', {
tests: {
//.........................................................................................................
/* for later / under consideration */
// "@isa.deep_boolean x.copy": ( x ) -> @isa.boolean x.copy # refers to result of `type.create()`
// "@isa.boolean x.seal": ( x ) -> @isa.boolean x.seal # refers to result of `type.create()`
// "@isa.boolean x.oneshot": ( x ) -> @isa.boolean x.oneshot # refers to result of `type.create()`
// "@isa.deep_boolean x.freeze": ( x ) -> @isa.deep_boolean x.freeze # refers to result of `type.create()`
//.........................................................................................................
"@isa.object x": function(x) {
return this.isa.object(x);
},
"@isa.nonempty_text x.name": function(x) {
return this.isa.nonempty_text(x.name);
},
"@isa.nonempty_text x.typename": function(x) {
return this.isa.nonempty_text(x.typename);
},
"@isa.boolean x.collection": function(x) {
return this.isa.boolean(x.collection);
},
"@isa.function x.isa": function(x) {
return this.isa.function(x.isa);
},
"@isa optional list.of.function x.fields": function(x) {
if (!this.isa.list(x.fields)) {
return true;
}
return this.isa_list_of.function(x.fields);
},
"@isa.boolean x.extras": function(x) {
return this.isa.boolean(x.extras); // refers to result of `type.create()`
},
"if extras is false, default must be an object": function(x) {
return x.extras || (this.isa.object(x.default));
},
"@isa_optional.function x.create": function(x) {
return this.isa_optional.function(x.create);
}
}
});
//...........................................................................................................
this.defaults.Type_factory_type_dsc = {
name: null,
typename: null,
isa: null,
fields: null,
collection: false,
/* `default` omitted on purpose */
create: null, // refers to result of `type.create()`
// copy: false # refers to result of `type.create()`
// seal: false # refers to result of `type.create()`
freeze: false, // refers to result of `type.create()`
extras: true // refers to result of `type.create()`
};
//-----------------------------------------------------------------------------------------------------------
this.types.declare('Intertype_iterable', function(x) {
return (x != null) && (x[Symbol.iterator] != null);
});
//-----------------------------------------------------------------------------------------------------------
this.types.declare('Intertype_constructor_cfg', {
tests: {
"@isa.object x": function(x) {
return this.isa.object(x);
},
"@isa_optional.nonempty_text x.sep": function(x) {
return this.isa_optional.nonempty_text(x.sep);
},
"x.errors in [ false, 'throw', ]": function(x) {
var ref;
return (ref = x.errors) === false || ref === 'throw';
}
}
});
//...........................................................................................................
this.defaults.Intertype_constructor_cfg = {
sep: '.',
errors: false
};
// #-----------------------------------------------------------------------------------------------------------
// @types.declare 'Intertype_walk_hedgepaths_cfg', tests:
// "@isa.object x": ( x ) -> @isa.object x
// "@isa_optional.nonempty_text x.sep": ( x ) -> @isa_optional.nonempty_text x.sep
// "@isa_optional.function x.evaluate": ( x ) -> @isa_optional.function x.evaluate
// ### TAINT omitted other settings for `GUY.props.tree()` ###
// #...........................................................................................................
// @defaults.Intertype_walk_hedgepaths_cfg =
// sep: @defaults.Intertype_constructor_cfg.sep
// evaluate: ({ owner, key, value, }) ->
// return 'take' if ( types.type_of value ) is 'function'
// return 'take' unless GUY.props.has_any_keys value
// return 'descend'
//===========================================================================================================
//-----------------------------------------------------------------------------------------------------------
Intertype_abc = class Intertype_abc extends GUY.props.Strict_owner {};
//===========================================================================================================
//-----------------------------------------------------------------------------------------------------------
this.defaults = GUY.lft.freeze(this.defaults);
this.Intertype_abc = Intertype_abc;
}).call(this);
//# sourceMappingURL=helpers.js.map
(function() {
'use strict';
var HELPERS, Multimix, assign, cast, check, declarations, get_rprs_of_tprs, isa, isa_list_of, isa_object_of, isa_optional, jk_equals, jr, js_type_of, rpr, sad, validate, validate_list_of, validate_object_of, validate_optional, xrpr;
var DECLARATIONS, E, GUY, H, HEDGES, Intertype, Type_factory, debug, help, rpr, to_width, urge, warn,
splice = [].splice;
//###########################################################################################################
Multimix = require('multimix');
GUY = require('guy');
//...........................................................................................................
HELPERS = require('./helpers');
({debug, warn, urge, help} = GUY.trm.get_loggers('INTERTYPE'));
({assign, jr, rpr, xrpr, get_rprs_of_tprs, js_type_of} = HELPERS);
({rpr} = GUY.trm);
//...........................................................................................................
declarations = require('./declarations');
E = require('./errors');
sad = (require('./checks')).sad;
H = require('./helpers');
jk_equals = require('../deps/jkroso-equals');
HEDGES = require('./hedges');
//-----------------------------------------------------------------------------------------------------------
isa = function(type, ...xP) {
return this._satisfies_all_aspects(type, ...xP);
};
DECLARATIONS = require('./declarations');
isa_list_of = function(type, ...xP) {
return this.isa.list_of(type, ...xP);
};
({to_width} = require('to-width'));
isa_object_of = function(type, ...xP) {
return this.isa.object_of(type, ...xP);
};
({Type_factory} = require('./type-factory'));
validate_list_of = function(type, ...xP) {
return this.validate.list_of(type, ...xP);
};
Intertype = (function() {
// #===========================================================================================================
// class Type_cfg extends H.Intertype_abc
validate_object_of = function(type, ...xP) {
return this.validate.object_of(type, ...xP);
};
// #---------------------------------------------------------------------------------------------------------
// constructor: ( hub, cfg ) ->
// ### TAINT ensure type_cfg does not contain `type`, `name` ###
// ### TAINT do not use `tests.every()` when only 1 test given ###
// super()
// GUY.props.hide @, 'hub', hub
// cfg = { H.defaults.Type_cfg_constructor_cfg..., cfg..., }
// H.types.validate.Type_cfg_constructor_cfg cfg
// cfg.test = new Proxy ( @_compile_test hub, cfg ), hub._get_hedge_sub_proxy_cfg hub
// #.......................................................................................................
// ### TAINT not used by `size_of()` ###
// cfg.size = 'length' if cfg.isa_collection and not cfg.size?
// cfg.size ?= null
// #.......................................................................................................
// @[ k ] = v for k, v of cfg
// return self = GUY.lft.freeze @
isa_optional = function(type, ...xP) {
return (xP[0] == null) || this._satisfies_all_aspects(type, ...xP);
};
// #---------------------------------------------------------------------------------------------------------
// _compile_test: ( hub, cfg ) ->
// cfg.test = @_compile_object_as_test hub, cfg unless cfg.test?
// if not cfg.extras
// cfg.test = [ cfg.test, ] unless H.types.isa.list cfg.test
// keys = ( k for k of cfg.default ).sort()
// cfg.test.unshift no_extras = ( x ) => H.equals ( k for k of x ).sort(), keys
// test = null
// if H.types.isa.list cfg.test
// unless cfg.test.length is 1
// # fn_names = ( f.name for f in cfg.test )
// tests = ( f.bind hub for f in cfg.test )
// test = H.nameit cfg.name, ( x ) =>
// for test in tests
// return false if ( R = test x ) is false
// return R unless R is true
// return true
// return test
// test = cfg.test[ 0 ]
// test ?= cfg.test
// return H.nameit cfg.name, ( x ) =>
// try
// return test.call hub, x
// catch error
// throw error if @hub.cfg.errors is 'throw' or error instanceof E.Intertype_error
// @hub.state.error = error
// return false
validate_optional = function(type, ...xP) {
return (xP[0] == null) || this.validate(type, ...xP);
};
// #---------------------------------------------------------------------------------------------------------
// _compile_object_as_test: ( hub, cfg ) ->
// type = cfg.name
// R = []
// for key, test of cfg
// continue unless key.startsWith '$'
// if H.types.isa.function test
// R.push test
// continue
// field = key[ 1 .. ]
// R.push @_test_from_text hub, type, field, test
// return R
//-----------------------------------------------------------------------------------------------------------
cast = function(type_a, type_b, x, ...xP) {
var casts, converter;
this.validate(type_a, x, ...xP);
if (type_a === type_b) {
return x;
}
if (this.isa(type_b, x, ...xP)) {
return x;
}
if ((casts = this.specs[type_a].casts) != null) {
if ((converter = casts[type_b]) != null) {
return converter.call(this, x, ...xP);
// #---------------------------------------------------------------------------------------------------------
// _test_from_text: ( hub, type, field, property_chain ) ->
// property_chain = property_chain.split '.'
// if field is ''
// name = "#{type}:#{property_chain.join hub.cfg.sep}"
// return H.nameit name, ( x ) -> @_isa property_chain..., x
// name = "#{type}.#{field}:#{property_chain.join hub.cfg.sep}"
// return H.nameit name, ( x ) -> @_isa property_chain..., x[ name ]
//===========================================================================================================
class Intertype extends H.Intertype_abc {
//---------------------------------------------------------------------------------------------------------
constructor(cfg) {
super();
GUY.props.hide(this, 'cfg', {...H.defaults.Intertype_constructor_cfg, ...cfg});
H.types.validate.Intertype_constructor_cfg(this.cfg);
//.......................................................................................................
GUY.props.hide(this, '_hedges', new HEDGES.Intertype_hedges());
GUY.props.hide(this, '_collections', new Set());
GUY.props.hide(this, '_signals', H.signals);
// GUY.props.hide @, 'isa', new GUY.props.Strict_owner { reset: false, }
GUY.props.hide(this, 'isa', new Proxy({}, this._get_hedge_base_proxy_cfg(this, '_isa')));
GUY.props.hide(this, 'validate', new Proxy({}, this._get_hedge_base_proxy_cfg(this, '_validate')));
GUY.props.hide(this, 'create', new Proxy({}, this._get_hedge_base_proxy_cfg(this, '_create')));
GUY.props.hide(this, 'type_factory', new Type_factory(this));
//.......................................................................................................
/* TAINT squeezing this in here for the moment, pending reformulation of `isa` &c to make them callable: */
GUY.props.hide(this, 'declare', new Proxy(this._declare.bind(this), {
get: (_, name) => {
return (...P) => {
return this._declare(name, ...P);
};
}
}));
//.......................................................................................................
GUY.props.hide(this, 'registry', new GUY.props.Strict_owner({
oneshot: true
}));
// GUY.props.hide @, 'types', H.types
this.state = {};
this._initialize_state();
//.......................................................................................................
this._register_hedges();
DECLARATIONS._provisional_declare_basic_types(this);
return void 0;
}
}
if (type_b === 'text'/* TAINT use better method like util.inspect */) {
return `${x}`;
}
throw new Error(`^intertype/cast@1234^ unable to cast a ${type_a} as ${type_b}`);
};
//-----------------------------------------------------------------------------------------------------------
check = function(type, x, ...xP) {
var error;
if (this.specs[type] != null) {
if (this.isa(type, x, ...xP)) {
return true;
} else {
return sad;
//---------------------------------------------------------------------------------------------------------
_initialize_state() {
var base;
if (this.state.data === void 0) {
this.state.data = null;
}
this.state.extra_keys = null;
this.state.method = null;
if ((base = this.state).hedges == null) {
base.hedges = [];
}
this.state.hedges.length = 0;
this.state.error = null;
return null;
}
}
if ((check = this.checks[type]) == null) {
throw new Error(`^intertype/check@1345^ unknown type or check ${rpr(type)}`);
}
try {
return check.call(this, x, ...xP);
} catch (error1) {
error = error1;
return error;
}
};
//-----------------------------------------------------------------------------------------------------------
validate = function(type, ...xP) {
var P, aspect, message, rpr_of_tprs, srpr_of_tprs, x;
if ((aspect = this._get_unsatisfied_aspect(type, ...xP)) == null) {
return true;
}
[x, ...P] = xP;
({rpr_of_tprs, srpr_of_tprs} = get_rprs_of_tprs(P));
message = aspect === 'main' ? `^intertype/validate@1456^ not a valid ${type}: ${xrpr(x)}${srpr_of_tprs}` : `^intertype/validate@1567^ not a valid ${type} (violates ${rpr(aspect)}): ${xrpr(x)}${srpr_of_tprs}`;
throw new Error(message);
};
//---------------------------------------------------------------------------------------------------------
_register_hedges() {
var hedge, isa, ref;
ref = this._hedges._hedgemethods;
for (hedge in ref) {
isa = ref[hedge];
((hedge, isa) => {
return this.declare(hedge, {isa});
})(hedge, isa);
}
return null;
}
//===========================================================================================================
this.Intertype = (function() {
class Intertype extends Multimix {
//---------------------------------------------------------------------------------------------------------
constructor(target = null) {
super();
//.......................................................................................................
/* TAINT bug in MultiMix, should be possible to declare methods in class, not the constructor,
and still get a bound version with `export()`; declaring them here FTTB */
//.......................................................................................................
this.sad = sad;
this.specs = {};
this.checks = {};
this.isa = Multimix.get_keymethod_proxy(this, isa);
this.isa_optional = Multimix.get_keymethod_proxy(this, isa_optional);
this.isa_list_of = Multimix.get_keymethod_proxy(this, isa_list_of);
this.isa_object_of = Multimix.get_keymethod_proxy(this, isa_object_of);
this.cast = Multimix.get_keymethod_proxy(this, cast);
this.validate = Multimix.get_keymethod_proxy(this, validate);
this.validate_optional = Multimix.get_keymethod_proxy(this, validate_optional);
this.validate_list_of = Multimix.get_keymethod_proxy(this, validate_list_of);
this.validate_object_of = Multimix.get_keymethod_proxy(this, validate_object_of);
this.check = Multimix.get_keymethod_proxy(this, check);
this.nowait = function(x) {
this.validate.immediate(x);
return x;
/* TAINT ideally would put this stuff elsewhere */
_get_hedge_base_proxy_cfg(self, method_name) {
return {
// _method_name = method_name
// _method_name = "_#{method_name}" unless _method_name.startsWith '_'
//.......................................................................................................
get: (target, key) => {
var R, f;
if (key === Symbol.toStringTag) {
return void 0;
}
if (key === 'constructor') {
return target.constructor;
}
if (key === 'toString') {
return target.toString;
}
if (key === 'call') {
return target.call;
}
if (key === 'apply') {
return target.apply;
}
//...................................................................................................
self._initialize_state();
self.state.method = method_name;
self.state.hedges.push(key);
//...................................................................................................
if (key === 'of' || key === 'or') {
throw new E.Intertype_ETEMPTBD('^intertype.base_proxy@2^', `hedgerow cannot start with \`${key}\`, must be preceeded by hedge`);
}
if ((GUY.props.get(this.registry, key, null)) == null) {
throw new E.Intertype_ETEMPTBD('^intertype.base_proxy@3^', `unknown hedge or type ${rpr(key)}`);
}
if ((R = GUY.props.get(target, key, H.signals.nothing)) !== H.signals.nothing) {
return R;
}
if (method_name === '_create') {
f = H.nameit(key, function(cfg = null) {
return self[self.state.method](key, cfg);
});
} else {
f = H.nameit(key, function(...P) {
return self[self.state.method](...P);
});
}
GUY.props.hide(target, key, R = new Proxy(f, this._get_hedge_sub_proxy_cfg(self)));
return R;
}
};
this._helpers = HELPERS;
declarations.declare_types.apply(this);
declarations.declare_checks.apply(this);
if (target != null) {
this.export(target);
}
//---------------------------------------------------------------------------------------------------------
_get_hedge_sub_proxy_cfg(self) {
return {
get: (target, key) => {
var R, f, type_cfg;
if (key === Symbol.toStringTag) {
return void 0;
}
if (key === 'constructor') {
return target.constructor;
}
if (key === 'toString') {
return target.toString;
}
if (key === 'call') {
return target.call;
}
if (key === 'apply') {
return target.apply;
}
self.state.hedges.push(key);
if ((R = GUY.props.get(target, key, H.signals.nothing)) !== H.signals.nothing) {
return R;
}
//...................................................................................................
if ((type_cfg = GUY.props.get(this.registry, key, null)) == null) {
throw new E.Intertype_ETEMPTBD('^intertype.base_proxy@4^', `unknown hedge or type ${rpr(key)}`);
}
//...................................................................................................
/* check for preceding type being iterable when building hedgerow with `of`: */
if ((key === 'of') && (!this._collections.has(target.name))) {
throw new E.Intertype_ETEMPTBD('^intertype.sub_proxy@5^', `expected type before \`of\` to be a collection, got ${rpr(target.name)}`);
}
//...................................................................................................
f = H.nameit(key, function(x) {
return self[self.state.method](...self.state.hedges, x);
});
GUY.props.hide(target, key, R = new Proxy(f, this._get_hedge_sub_proxy_cfg(self)));
return R;
}
};
}
//---------------------------------------------------------------------------------------------------------
_declare(...P) {
/* TAINT handling of arguments here shimmed while we have not yet nailed down the exact calling
convention for this method. */
var dsc;
dsc = this.type_factory.create_type(...P);
this.registry[dsc.typename] = dsc;
/* TAINT need not call _get_hedge_sub_proxy_cfg() twice? */
this.isa[dsc.typename] = new Proxy(dsc, this._get_hedge_sub_proxy_cfg(this));
this.validate[dsc.typename] = new Proxy(((x) => {
return this._validate(dsc.typename, x);
}), this._get_hedge_sub_proxy_cfg(this));
if (dsc.collection) {
this._collections.add(dsc.typename);
}
return null;
}
//---------------------------------------------------------------------------------------------------------
equals(a, ...P) {
var arity, b, i, len, type_of_a;
if ((arity = arguments.length) < 2) {
throw new Error(`^intertype/equals@3489^ expected at least 2 arguments, got ${arity}`);
_validate_hedgerow(hedgerow) {
var ref, ref1, xr;
if (((ref = hedgerow[0]) === 'of' || ref === 'or') || ((ref1 = hedgerow[hedgerow.length - 1]) === 'of' || ref1 === 'or')) {
xr = rpr(hedgerow.join(this.cfg.sep));
throw new E.Intertype_ETEMPTBD('^intertype.validate_hedgerow@6^', `hedgerow cannot begin or end with \`of\` or \`or\`, must be surrounded by hedges, got ${xr}`);
}
type_of_a = this.type_of(a);
for (i = 0, len = P.length; i < len; i++) {
b = P[i];
if (type_of_a !== this.type_of(b)) {
return false;
return null;
}
//---------------------------------------------------------------------------------------------------------
_isa(...hedges) {
var error, ref, x;
ref = hedges, [...hedges] = ref, [x] = splice.call(hedges, -1);
try {
return this._inner_isa(...hedges, x);
} catch (error1) {
error = error1;
if (this.cfg.errors === 'throw' || error instanceof E.Intertype_error) {
throw error;
}
if ((type_of_a === 'set' || type_of_a === 'map') && this.equals([...a], [...b])) {
return true;
this.state.error = error;
}
return false;
}
//---------------------------------------------------------------------------------------------------------
_inner_isa(...hedges) {
var R, advance, element, error, hedge, hedge_idx, is_terminal, last_hedge_idx, ref, result, tail_hedges, type_cfg, x;
ref = hedges, [...hedges] = ref, [x] = splice.call(hedges, -1);
this._validate_hedgerow(hedges);
hedge_idx = -1;
last_hedge_idx = hedges.length - 1;
advance = false;
is_terminal = false;
R = true;
while (true) {
// element_mode = false
//.......................................................................................................
hedge_idx++;
if (hedge_idx > last_hedge_idx) {
return R;
}
if (!jk_equals(a, b)) {
/* TAINT this call involves its own typechecking code and thus may mysteriously fail */
return false;
hedge = hedges[hedge_idx];
is_terminal = (hedges[hedge_idx + 1] === 'or') || (hedge_idx === last_hedge_idx);
//.....................................................................................................
if (advance) {
if (is_terminal) {
return false;
}
if (hedge !== 'or') {
continue;
}
}
advance = false;
//.....................................................................................................
switch (hedge) {
//...................................................................................................
case 'of':
// element_mode = true
tail_hedges = hedges.slice(hedge_idx + 1);
try {
for (element of x) {
if ((this._inner_isa(...tail_hedges, element)) === false) {
return false;
}
}
} catch (error1) {
error = error1;
if (!((error.name === 'TypeError') && (error.message === 'x is not iterable'))) {
throw error;
}
throw new E.Intertype_ETEMPTBD('^intertype.isa@7^', `\`of\` must be preceded by collection name, got ${rpr(hedges[hedge_idx - 1])}`);
}
return true;
//...................................................................................................
case 'or':
R = true;
continue;
}
//.....................................................................................................
if ((type_cfg = GUY.props.get(this.registry, hedge, null)) == null) {
throw new E.Intertype_ETEMPTBD('^intertype.isa@8^', `unknown hedge or type ${rpr(hedge)}`);
}
//.....................................................................................................
result = type_cfg.call(this, x);
switch (result) {
case H.signals.return_true:
return this._protocol_isa({
term: hedge,
x,
value: H.signals.nothing,
verdict: true
});
// when H.signals.advance then return @_protocol_isa { term: hedge, x, value: H.signals.nothing, verdict: R, }
// when H.signals.process_list_elements then return @_protocol_isa { term: hedge, x, value: H.signals.nothing, verdict: R, }
// when H.signals.process_set_elements then return @_protocol_isa { term: hedge, x, value: H.signals.nothing, verdict: R, }
case false:
this._protocol_isa({
term: hedge,
x,
value: H.signals.nothing,
verdict: false
});
advance = true;
R = false;
continue;
case true:
this._protocol_isa({
term: hedge,
x,
value: H.signals.nothing,
verdict: true
});
if (is_terminal) {
return true;
}
continue;
}
//.....................................................................................................
throw new E.Intertype_internal_error('^intertype.isa@9^', `unexpected return value from hedgemethod for hedge ${rpr(hedge)}: ${rpr(R)}`);
}
return true;
//.......................................................................................................
return R;
}
//---------------------------------------------------------------------------------------------------------
_protocol_isa({term, x, value, verdict}) {
// urge '^4535^', GUY.trm.reverse { term, x, value, verdict, }
return verdict;
}
//---------------------------------------------------------------------------------------------------------
_validate(...hedges) {
var qtype, ref, type, x, xr;
ref = hedges, [...hedges] = ref, [type, x] = splice.call(hedges, -2);
if (this._isa(...hedges, type, x)) {
return x;
}
qtype = [...hedges, type].join(this.cfg.sep);
xr = to_width(rpr(x), 100);
throw new E.Intertype_ETEMPTBD('^intertype.validate@10^', `not a valid ${qtype}: ${xr}`);
}
//---------------------------------------------------------------------------------------------------------
_create(type, cfg) {
var R, create, t, type_cfg;
create = null;
//.......................................................................................................
if ((type_cfg = GUY.props.get(this.registry, type, null)) == null) {
throw new E.Intertype_ETEMPTBD('^intertype.create@11^', `unknown type ${rpr(type)}`);
}
//.......................................................................................................
/* Try to get `create` method, or, should that fail, the `default` value. Throw error when neither
`create` nor `default` are given: */
if ((create = GUY.props.get(type_cfg, 'create', null)) === null) {
if ((R = GUY.props.get(type_cfg, 'default', H.signals.nothing)) === H.signals.nothing) {
throw new E.Intertype_ETEMPTBD('^intertype.create@12^', `type ${rpr(type)} does not have a \`default\` value or a \`create()\` method`);
}
} else {
/* If `create` is given, call it to obtain default value: */
//.......................................................................................................
R = create.call(this, cfg);
}
//.......................................................................................................
if ((create == null) && (cfg != null)) {
if ((t = H.js_type_of(R)) === '[object Object]' || t === '[object Array]') {
R = Object.assign(structuredClone(R), cfg);
} else {
R = cfg;
}
} else {
R = structuredClone(R);
}
//.......................................................................................................
if (type_cfg.freeze === true) {
R = Object.freeze(R);
} else if (type_cfg.freeze === 'deep') {
R = GUY.lft.freeze(H.deep_copy(R));
}
//.......................................................................................................
return this._validate(type, R);
}
_normalize_type(type) {
return type.toLowerCase().replace(/\s+/g, '');
}
_split_hedgerow_text(hedgerow) {
return hedgerow.split(this.cfg.sep);
}
};
// @extend object_with_class_properties
Intertype.include(require('./sizing'));
//---------------------------------------------------------------------------------------------------------
Intertype.prototype.equals = H.equals;
Intertype.include(require('./declaring'));
Intertype.prototype.type_of = H.type_of;
Intertype.include(require('./checks'));
Intertype.prototype.size_of = H.size_of;

@@ -174,4 +483,18 @@ return Intertype;

// #-----------------------------------------------------------------------------------------------------------
// _walk_hedgepaths: ( cfg ) ->
// throw new Error "^intertype._walk_hedgepaths@9^ not implemented"
// # cfg = { H.defaults.Intertype_walk_hedgepaths_cfg..., cfg..., }
// # yield from GUY.props.walk_tree @isa, cfg
// # return null
//###########################################################################################################
this.Type_factory = Type_factory;
this.Intertype = Intertype;
this.Intertype_user_error = E.Intertype_user_error;
}).call(this);
//# sourceMappingURL=main.js.map
{
"name": "intertype",
"version": "7.7.1",
"version": "10.0.0",
"description": "A JavaScript typechecker",

@@ -17,3 +17,5 @@ "main": "lib/main.js",

"dependencies": {
"multimix": "^5.0.0"
"guy": "11.2.0",
"intertype-legacy": "^7.7.1",
"to-width": "^1.2.0"
},

@@ -20,0 +22,0 @@ "scripts": {

# InterType
# ▞ InterType

@@ -11,564 +11,565 @@ A JavaScript type checker with helpers to implement own types and do object shape validation.

- [Concepts](#concepts)
- [Usage](#usage)
- [Declaring New Types](#declaring-new-types)
- [Typed Value Casting](#typed-value-casting)
- [Checks](#checks)
- [Concatenating Checks](#concatenating-checks)
- [Formal Definition of the Type Concept](#formal-definition-of-the-type-concept)
- [`immediate` and `nowait`](#immediate-and-nowait)
- [ECMAScript6 Classes and Type Checking](#ecmascript6-classes-and-type-checking)
- [Segue on The Miller Device](#segue-on-the-miller-device)
- [Related](#related)
- [To Do](#to-do)
- [Quick Links](#quick-links)
- [▞ InterType](#%E2%96%9E-intertype)
- [Motivation](#motivation)
- [Contracts of Type Tests and the Verbs `isa`, `validate`](#contracts-of-type-tests-and-the-verbs-isa-validate)
- [Type Tests](#type-tests)
- [`isa`](#isa)
- [`validate`](#validate)
- [Hedgerows](#hedgerows)
- [Diagram](#diagram)
- [xxx](#xxx)
- [Intertype `state` Property](#intertype-state-property)
- [Intertype `create`](#intertype-create)
- [Intertype `equals()`](#intertype-equals)
- [To Do](#to-do)
- [Is Done](#is-done)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Quick Links
* [Type Declarations](README-declare.md)
# ▞ InterType
# Concepts
## Motivation
* what is a type
* fundamental types vs. domain types
* `isa`
* `validate`
* `type_of`
* `types_of`
* structural typing
* inspired by [Clojure spec](https://typedclojure.org)[https://www.youtube.com/watch?v=B_Farscj0hY]
* most of the time used to perform a 'lower bounds' check of Plain Old Dictionaries (objects), i.e. objects
must satisfy all key/constraint checks of a given type declaration, but object may have additional
key/value pairs
* Types are defined using an ordered set of (one or more) named boolean test functions known as 'aspects'.
In order for a value `x` to be of type `T`, all aspects—when called in their defined order with `x` (and
possibly other arguments, see below)—have to return `true`. Aspect satisfication tests are done in a lazy
fashion, so that no tests are performed after one has failed. Likewise for type validation, the difference
being that the first failing aspect will cause an error to thrown that quotes the aspect's name.
## Contracts of Type Tests and the Verbs `isa`, `validate`
* Types may be parametrized. For example, there's a 'partial' type `multiple_of` which needs a module (a
number to be a multiple of) as extra parameters; thus, we can test `isa.multiple_of 121, 11`.
### Type Tests
* In InterType, a 'type' is, on the one hand, essentially an ordered set of aspects; on the other hand,
since within the context of a given InterType instance, each type corresponds to exactly one type name (a
nonempty text), a 'type' can be identified with a string. Thus, the type of, say, `[]` *is* `'list'` (i.e.
the string that spells its name).
* A type test (TT) is a function that accepts a single argument and returns a boolean.
* TTs should not normally throw errors; however, that can sometimes be inconvenient to implement. For this
reason, InterType implements 'exception-guarding' which entails that should a type tester inadvertently
cause an exception, that exception will be silently caught and stored in the `state.error` property of the
`Intertype` instance; the return value of the call will be set `false`. The following types `nevah` and
`oops` are almost equivalent in that they return `false` for any input; however, immediately after using
`oops`, the suppressed error may be accessed through `types.state.error` property:
Conversely, any list of functions that **1)**&nbsp;can be called with a value as first arguments (possibly
plus a number of extra parameters), that **2)**&nbsp;never throws an error and **3)**&nbsp;always returns
a Boolean value can be regarded as a list of aspects, hence defining a (possibly empty) set of values.
```coffee
{ Intertype
Intertype_user_error } = require 'intertype'
types = new Intertype
types.declare.nevah ( x ) -> false
types.declare.oops ( x ) -> throw new Error 'oops'
types.declare.oops_anyway ( x ) -> throw new Intertype_user_error 'oops'
types.isa.oops 42 # `false`
types.state.error? # `true` (i.e. `types.state.error` contains error)
types.isa.nevah 42 # `false`
types.state.error? # `false` (i.e. no error, all OK)
types.isa.oops_anyway 42 # !!! throws an error
```
Because silently suppressed errors
can be tricky to debug and checking for `state.error` is easily forgotten (and should not normally be
necessary), users may elect to switch off exception-guarding by setting `errors` to `'throw'` (as in,
`types = new Intertype { errors: 'throw', }`)
* Users may always construct type testers whose intentional errors will not be silently caught by deriving
their errors from `Intertype_user_error`
# Usage
[WIP]
### `isa`
One usage pattern for InterType is to make it so that one (sub-) project gets a module—call it `types`—that
is dedicated to type declarations; `require`ing that `types` module then makes type checking and type
validation methods available. Say we have:
* However, when called in the context of a hedgerow as in `isa.collection.of.type x`, an exception may be
thrown, e.g. when a type name is undeclared or `of` is preceded by a non-iterable type name (cf the
non-sensical `isa.integer.of.integer 42`). This is not the type test, this is the verb `isa` complaining
about a malformed chain of type tests.
* It is not allowed to use a name in an `isa` (or `validate` or `create`) hedgerow without that name being
`declare`d prior to that.
```coffee
# in module `types.coffee`
## `validate`
# instantiate InterType instance, export its methods to `module.exports` in one go:
intertype = new ( require 'intertype' ) module.exports
* `validate` is a verb that performs an `isa` test; should that return `false`, an exception is thrown; if
it returns `true`, *the tested value* will be returned.
* convenient for writing postconditions, as in `f = ( a, b ) -> validate.integer a * b`.
# now you can call methods of InterType instance as *module* methods:
@declare 'mytype', ( x ) -> ( @isa number ) and ( x > 12 ) and ( x <= 42 )
```
## Hedgerows
In another module:
* simplest form: test for a value; preferred form is to use property accessor syntax (a.k.a. 'dot
notation'), e.g. `isa.integer x` (equivalent to `isa[ 'integer' ] x`)
```coffee
# now use the declared types:
{ isa, type_of, validate, } = require './types'
* these accessors are called 'hedges'
console.log isa.integer 100 # true
console.log isa.mytype 20 # true
console.log isa.mytype 100 # false
console.log type_of 20 # 'number'
console.log validate.mytype 20 # true
console.log validate.mytype 100 # throws "not a valid mytype"
```
* hedges can be combined in so-called 'hedgerows', e.g. `isa.positive0.integer x` tests whether `x >= 0`
# Declaring New Types
* hedgerows can be arbitrarily long, e.g. `isa.optional.nonempty.list_of.optional.negative1.integer x`
`intertype.declare()` allows to add new type specifications to `intertype.specs`. It may be called with one
to three arguments. The three argument types are:
* whether one wants lomng hedgerows or not is a matter of taste, but it will very probably be more
systematic and more readable to define meaningful intermediate types instead of using log hedgerows:
* `type` is the name of the new type. It is often customary to call `intertype.declare 'mytype', { ... }`,
but it is also possible to name the type within the spec and forego the first argument, as in
`intertype.declare { type: 'mytype', ... }`.
```coffee
declare.xy_count { test: ( ( x ) -> @isa.optional.set_of.negative1.integer x ), }
declare.maybe_xy_counts { test: ( ( x ) -> @isa.optional.nonempty.list_of.xy_count x ), }
...
validate.maybe_xy_counts some_value
```
* `spec` is an object that describes the type. It is essentially what will end up in `intertype.specs`, but
it will get copied and possibly rewritten in the process, depending on its content and the other
arguments. The `spec` object may have a property `type` that names the type to be added, and a property
`tests` which, where present, must be an object with one or more (duh) tests. It is customary but not
obligatory to name a single test `'main'`. In any event, *the ordering in which tests are executed is the
ordering of the properties of `spec.tests`* (which corresponds to the ordering in which those tests got
attached to `spec.tests`). The `spec` may also have further attributes, for which see below.
* in order to satisfy a hedgerow constraint, the value given must satisfy all individual terms, in the order
given. In other words, a hedgerow is a notation for a series of terms connected by logical conjunctions,
`a.b.c x ⇔ ( a x ) ∧ ( b x ) ∧ ( c x )` (in detail, `list_of` and `set_of` introduce a complication).
* `test` is a boolean function—a predicate—that accepts exactly one argument, the value `x` to be tested.
The boolean return value indicates whether `x` satisfies a certain condition. The `test` argument, where
present, will be registered as the 'main' (and only) test for the new type, `spec.tests.main`.
To re-use the slightly convoluted example from above, one can understand what
`isa.optional.nonempty.list_of.optional.negative1.integer x` means by rewriting it in pseudo-code along
the following lines:
The rule of thumb is that when one wants to declare a type that can be characterized by a single, concise
test, then giving a single anonymous one-liner (typically an arrow function) is OK; conversely, when a
complex type (think: structured objects) needs a number of tests, then it will be better to write a suite of
named tests (most of them typically one-liners) and pass them in as properties of `spec.tests`.
```coffee
test: ( x ) ->
return false unless isa.optional x # `optional x` is satisfied if `x` is `undefined` or `null`, otherwise go on
return false unless isa.nonempty x # `nonempty x` is true if `x` contains at least one element
return false unless isa.list x # `list_of...` tests whether `x` is a list, ...
for each e in x: # ... and then applies the rest of the hedgerow to each of its elements:
return false unless isa.optional e # this `optional` clause is run against each element, so list may have `null` elements
return false unless isa.negative1 e # `negative1 x` tests for `x < 0`
return false unless isa.integer e # `true` for whole numbers; uses `Number.isInteger()`
return true
```
The call signatures are:
* hedgerows will be evaluated in a 'short-circuited' manner like JavaScript logical operators; this means
that tests will only be performed up to the point where the result is definitely known. For example, if in
`z = ( a or b )` the left sub-expression has been found to be `true`, we already know that the outcome can
only be `true` as well, so we don't have to compute `b`. In `isa.optional.text x` we find that `x` is
`undefined` or `null` we are already done and can (and must) skip the test for `text`. Conversely, if we'd
find that `a` is `false` the second part of the disjunction could still be `true`, so we cannot
short-circuit but must evaluate the second part as well, and the same goes for `isa.optional.text x` if
`x?` (i.e. `x != null` or, even more explicitly, (JS) `( x !== null ) and ( x !== undefined )`).
* `intertype.declare spec`—In this form, `spec` must have a `type` property that names the new type, as well
as a `tests` property.
* a hedgerow may contain one or more `or` hedges that signify logical disjunction, e.g.
`isa.integer.or.nonempty.text.or.boolean x`. In this case, we partition the hedgerow into its constituent
terms: `( integer x ) ∨ ( nonempty.text ) ∨ ( boolean x )` and evaluate by walking through each
sub-hedgerow until it is either satisfied (which is when we can break the loop) or dissatisfied; in that
case, we jump forward to the next sub-hedgerow to repeat the same; when there are no more sub-hedgerows
left, the very last test then determines the result for the entire row.
* `intertype.declare type, spec`—This form works like the above, except that, if `spec.type` is set, it must
equal the `type` argument. It is primarily implemented for syntactical reasons (see examples).
* `intertype.declare type, test`—This form is handy for declaring types without any further details: you
just name it, define a test, done. For example, to declare a type for positive numbers: `@declare
'positive', ( x ) => ( @isa.number x ) and ( x > 0 )`. Also see the next.
### Diagram
* `intertype.declare type, spec, test`—This form is handy for declaring types with a minimal set of details
and a short test. For example, to define a type for NodeJS buffers: `@declare 'buffer', { size: 'length',
}, ( x ) => Buffer.isBuffer x` (here, the `size` spec defines how InterType's `size_of()` method should
deal with buffers).
```
isa.text
# Typed Value Casting
text is text isnt text
return true ATOERF¹
**XXX TBW XXX**
⊙ return true return false
¹ATOERF: Advance To OR, Else Return False
```
# Checks
```
isa.text.or.optional.list_of.positive1.integer
**WIP**
text is text isnt text
return true ATOERF¹
* `validate.t x, ...`—returns `true` on success, throws error otherwise
* `isa.t x, ...`—returns `true` on success, `false` otherwise
* `check.t x, ...`—returns any kind of happy value on success, a sad value otherwise
<!-- * `is.t x, ...`—short for `not is_sad check.t x, ...` (???) -->
or ————————————————————————
Distinguish between
integer is integer isnt integer
next ATOERF¹
* `isa.t x` with *single* argument: this tests for *constant* types (including `isa.even x` which tests
against remainder of constant `n = 2`). `isa` methods always return a boolean value.
⊙ return true return false
* `check.t x, ...` with *variable* number of arguments (which may include previously obtained results for
better speed, consistency); this includes `check.multiple_of x, 2` which is equivalent to `isa.even x`
but parametrizes `n`. Checks return arbitrary values; this also holds for failed checks since even a
failed check may have collected some potentially expensive data. A check has failed when its return
value is sad (i.e. when `is_sad check.t x, ...` or equivalently `not is_happy check.t x, ...` is
`true`), and vice versa.
Checks will never throw except when presented with an unknown type or check name.
Checks and types share a common namespace; overwriting or shadowing is not allowed.
`sad` is the JS symbol `intertype.sad`; it has the property that it 'is sad', i.e. `is_sad intertype.sad`
returns `true`.
`is_sad x` is `true` for
* `sad` itself,
* instances of `Error`s
* all objects that have an attribute `x[ sad ]` whose value is `true`.
Conversely, `is_sad x` is `false`
* all primitive values except `sad` itself,
* for all objects `x` except those where `x[ sad ] === true`.
One should never use <strike>`r is sad`</strike> to test for a bad result, as that will only capture cases
where a checker returned the `sad` symbol; instead, always use `is_sad r`.
There is an equivalence (invariance) between checks, isa-tests and validations such that it is always
possible to express one in terms of the other, e.g.
¹ATOERF: Advance To OR, Else Return False
```
check_integer = ( x ) -> return try x if ( validate.integer x ) catch error then error
isa_integer = ( x ) -> is_happy check_integer x
validate_integer = ( x ) -> if is_happy ( R = check_integer x ) then return R else throw R
```
## Concatenating Checks
Since checks never throw the programmer must be aware to check for sad results themself. It's advantageous
to not use nested `if/then/else` statements as that would quickly grow to a mess; instead, put related
checks into a function on their own and return as soon as any intermediate result is sad, then return the
result of the last check.
Another idiom is to use a `loop` (or `wjhile ( true ) { ... }`) construct and break as soon as a sad
intermediate result is encountered; not to be forgotten is the final `break` statement that is needed to
keep the code from looping indefinetly:
```
R = null
loop
break if ( R = check_fso_exists path, R ) is sad
break if ( R = check_is_file path, R ) is sad
break if is_sad ( R = check_is_json_file path, R )
break
if is_sad R then warn "fails with", ( rpr R )[ ... 80 ]
else help "is JSON file; contents:", ( jr R )[ ... 100 ]
```
isa.text.or.optional.list_of.positive1.integer
# Formal Definition of the Type Concept
text is text isnt text
return true ATOERF¹
For the purposes of InterType, **a 'type' is reified as (given by, defined by, represented as) a pure, named
function `t = ( x ) -> ...` that accepts exactly one argument `x` and always returns `true` or `false`**.
Then, the set of all `x` that are of type `t` are those where `t x` returns `true`, and the set of all `x`
that are not of type `t` are those where `t x` returns `false`; these two sets will always be disjunct
(otherwise `t` cannot be pure, invalidating the premise).
or ————————————————————————
Two trivial functions are the set of all members of all types, `any = ( x ) -> true`, and the set of values
(in the loose sense, but see [`value` and `nowait`](#value-and-nowait)) that have no type at all, `none = (
x ) -> false`; the former set contains anything representable by the VM at all, while the latter is the
empty set (i.e. all values have at least one type, `any`).
optional not x? x?
return true next
Observe that the above definition implies that *any and all* JS pure functions of arity one that always
return a boolean define a type, even if unintentionally so; for example `is_legal_input = ( x ) -> ( x is 42
) or ( x is 'foo' )` implicitly defines a weird type with the weird name 'is_legal_input' that has exactly
two members, an integer number and a three-character string. Less weird and more commonly used are such
types that include only a small, enumerable set of values, as in `traffic_light_color = ( x ) -> x in [
'red', 'amber', 'green', ]`, otherwise known as 'enumerations', or a smallish set defined by pattern
matching, as in `file_sequence_nr = ( x ) -> ( isa.text x ) and ( x.match /^nr[0-9]{3}$/ )?` (which allows
`nr031` but prohibits `nr03x`).
list_of: list is list isnt list
switch to EM² ATOERF¹
> Observe that in the last example, it is imperative to first test for `x` being a `text` before trying to
> use the `String.prototype.match()` method, this to ensure no exception will ever occur. The alternatives
> are clearly inferior:
>
> * One could `try` to call `x.match()` and then `catch` errors and return `false` instead; however, this
> will make arbitrary objects like `{ match: ( -> true ), }` pass the test which is probably not intended.
>
> * It is possible to `String::match.call x, pattern`, but that will throw for values like `null` and
> `undefined` so still needs to be guarded with `try` and `catch`.
>
> As for the `x in [ ... ]` check, such a safeguard is not needed, but observe that `( new String 'abc' ) in
> [ 'abc' ]` gives `false` which probably does indeed do what you wanted (namely, exclude those problematic
> and vexing [boxed (wrapped)
> values](https://developer.mozilla.org/en-US/docs/Glossary/Primitive#Primitive_wrapper_objects_in_JavaScript))
> that have no justification to be used, ever.
positive1 e > 0 not ( e > 0 )
next ATOERF¹
That a 'type' 'is' a function of a certain kind is indeed a desirable property. First of all, it makes
deciding whether a given thing is a type (in almost all cases: trivially) testable. Next, it specifies an
unambiguous method how to construct types, and the method of construction is using first principles—unary,
boolean pure functions, about the most elementary kind of callables. Not least, it assures us that **all
functions that are only composed of calls to type definitions and logical operators define a type, too**
(even if some of those happen to be synonymous to existing types or equivalent to trivial types like `any`
or `all`); in particular, this means that **unions (generalizations) of types** according to this definition
are unequivocally types according to this definition, too, as are **intersections (refinements) of types**.
And, of course, some functions that go beyond combining function calls by means of `and`, `or`, `not` can
shown to be materially types in the sense of this definition. Conversely, we can also be sure that any and
all functions that at least for some inputs will call an impure function cannot be said to represent types
(unless they `try`, `catch` and handle possible exceptions and turn them into a boolean).
integer is integer isnt integer
next ATOERF¹
> As for whether one should encourage or discourage synonymous types—types with multiple names and
> definitions but identical element sets—the policy is that unwarranted duplication is, of course, to be
> avoided, but clarity and specificity are desirable. In other words, when you find yourself writing
> `validate.integer x` a lot in a single module, chances are that you should really declare a custom type
> `declare mytype = ( x ) -> isa.integer x` *even if that at the moment is nothing more than replicating an
> existing definition*. If you find yourself writing things like `validate.positive_integer x; validate.even
> x` then you should almost certainly define a type that checks for `( isa.positive_integer x ) and ( isa.
> even x)`. Also observe that while the body of a type declaration as such are *extensional*—that is,
> stating the material tests a given value must pass in order to conform to a given type—the names and the
> usage of types should tend to be *intentional*, that is, express fitness for a purpose. Thus, one may want
> to separately define, say, `file_count` and `line_count`: while both are counts (zero or a positive
> natural number), they count different things and may, in a software system, be subject to different
> constraints.
⊙ return true return false
# `immediate` and `nowait`
The type `immediate` is defined as the complement of promises, that is, the set of all values `x` for which
`isa.promise x` returns `false` (so neither native promises nor any 'thenables'—objects where `x.then` is a
function).
The `immediate` type has been defined as a convenient way to ensure that a given synchronous function call
was actually synchronous, i.e. did not return a promise; this may be done as
```coffee
validate.immediate r = my_sync_function 'foo', 'bar', 'baz'
¹ATOERF: Advance To OR, Else Return False
²EM: Elements Mode
```
Observe that immediates do comprise `NaN`, `null`, `undefined`, `false` and anything else
except for promises, so `x?` is distinct from `isa.immediate x`.
Schema for `isa.negative1.integer.or.optional.empty.text -42` (`true`): Both `isa.negative1 -42` and
`isa.integer -42` evaluate to `true`; since these terms are implicitly connected with `and`, we must
evaluate them all to ensure no `false` term occurs; this is what the single triangle ▼ signifies, 'continue
with next'. When we reach the `or` clause, though, we can short-circuit (▼▼▼) the evaluation and return `true`:
Equivalently and more succinctly, the validation step can be written with `nowait()`:
| FALSE | isa | TRUE |
| ------: | :-------: | :----- |
| | negative1 | ▼ |
| | integer | ▼ |
| ───────── | OR | ▼▼▼────── |
| | optional | |
| | empty | |
| | text | |
| ═════════ | ═════════ | ═════════ |
| | -42 | TRUE |
```coffee
nowait r = my_sync_function 'foo', 'bar', 'baz'
```
`nowait x` will always either throw a validation error (when `x` is a promise) or else return `x` itself,
which means that we can write equivalently:
Schema for `isa.negative1.integer.or.optional.empty.text 'meep'` (`false`): `'meep'` cannot satisfy
`negative1` since it is not numeric, so the entire clause fails. We can again short-circuit, but *only up to
the next or-clause*, symbolized by ▼▼. The next term is `optional`; since all values (including `null` and
`undefined`) satisfy this constraint, we go to the next term, `empty`; since `'meep'.length` is `4`, this
term fails, so we have to ▼▼ advance to the end of the current clause which coincides with the end of the
hedgerow, meaning we can return `false`:
```coffee
r = nowait my_sync_function 'foo', 'bar', 'baz'
```
| FALSE | isa | TRUE |
| ------: | :-------: | :----- |
| ▼▼ | negative1 | |
| | integer | |
| ────────▼ | OR | ───────── |
| | optional | ▼ |
| ▼▼ | empty | |
| | text | |
| ═════════ | ═════════ | ═════════ |
| FALSE | 'meep' | |
At least in languages with optional parentheses like CoffeeScript, this looks exactly parallel to
```coffee
r = await my_async_function 'foo', 'bar', 'baz'
```
Schema for `isa.negative1.integer.or.optional.empty.text -42` (`true`): `null` is not negative (and, of
course, not positive either) so we can ▼▼ advance to the next 'gate'; there, `null` does fulfill `optional`
(like any value) but with a 'special effect': `isa.optional null` and `isa.optional undefined` cause a
global short-circuit, meaning we can return `true` right away and ignore any number of other constraints:
hence the name.
| FALSE | isa | TRUE |
| ------: | :-------: | :----- |
| ▼▼ | negative1 | |
| | integer | |
| ────────▼ | OR | ───────── |
| | optional | ▼▼▼ |
| | empty | |
| | text | |
| ═════════ | ═════════ | ═════════ |
| | null | TRUE |
This short-circuiting behavior of `optional` when seeing a nullish value is peculiar to `optional`; it is
similar to there only being a single empty exemplar of collections (strings, lists, sets) except applying to
all types: `( isa.empty.text a ) == ( isa.empty.text b )` entails `a == b == ''`; likewise, `(
isa.optional.$TYPE_A a ) == ( isa.optional.$TYPE_B b )` in conjunction with `( a == null )` implies `a ==
b`, so as soon as we learn that `a == null` and a value has an `optional` allowance, no other constraint has
to be considered.
# ECMAScript6 Classes and Type Checking
**Note** on `optional`: The types `optional.integer` and `optional.text` have `{ null, undefined }` as
intersection of their domains, meaning that in the case of their disjunction—`isa.optional.integer.or.text`,
`isa.integer.or.optional.text` and so on—are indistinguishable: all variations will, among (infinitely many)
other values accept all of `null`, `undefined`, `1`, `42`, `'x'`, `'foobar'` and so on. Because of this one
may want to restrict oneself to only allow `optional` as the *first* hedge, avoiding constructs like
`isa.integer.or.optional.text` as a matter of style.
> this text first appeared in [jsEq](https://github.com/loveencounterflow/jseq#ecmascript6-classes-and-type-checking)
Schema for `isa.nonempty.text.or.list_of.nonempty.text [ 'helo', 'world', ]` (`true`): `nonempty` gives
`true` for `[ 'helo', 'world', ]`, but since this is a `list` rather than a `text`, the first clause fails
nonetheless. Next up is `list_of`, which first calls `isa.list [ 'helo', 'world', ]`; that being true, it
then switches to element mode, meaning that rather than applaying the remaining tests against the argument
passed in (the list), they will be applied to each *element* of the collection; this is here symbolized by
`∈ nonempty` and `∈ text`; in total, four tests will be performed: `isa.nonempty 'helo'`, `isa.text 'helo'`,
`isa.nonempty 'world'`, and `isa.text 'world'`, all of which return `true`, which leads to the entire
compound type being satisfied:
Whenever one thinks one has tamed the utter madness that is JavaScript's type system, one can be reasonably
sure another one of the Hydra's ugly heads is waiting right behind the corner. This happens with ECMAScript6
Classes.
| FALSE | isa | TRUE |
| ------: | :-------: | :----- |
| | nonempty | ▼ |
| ▼▼ | text | |
| ────────▼ | OR | ───────── |
| | list_of | ▼ |
| | ∈ nonempty | ▼ |
| | ∈ text | ▼ |
| ═════════ | ═════════ | ═════════ |
| | [ 'helo', 'world', ] | TRUE |
Let us go on a Journey in Five Parts where I'd like to define a class that extends JS `Array`; I then
instantiate it and poke at it with all the sonic screwdrivers I have. This looks good until I use either
`typeof` or the old trusty (but, by now, a bit rusty) [Miller Device]() to ascertain the class name of that
thing:
Observe that in a compound type, once the mode has been switched to element testing mode `∈`, there's no
going back, so `isa.list_of.text.or.integer` is fundamentally different from `isa.integer.or.list_of.text`:
the first will be true for all lists that contain nothing but strings and integer numbers, the second will
be true for all values that are either an integer or a list of zero or more strings. This is a shortcoming
of the current algorithm and may be fixed in the future; currently, there's no way to write `(
isa.set_of.text x ) or ( isa.list_of.text x )` in a single go. Should you need such a type, it will probably
be best to give the type a name, as in
```coffee
# Preface. Packing for the Journey.
# ---------------------------------
types = new ( require 'intertype' ).Intertype() # https://github.com/loveencounterflow/intertype
class Myclass extends Array
# Chapter I. Embarking on the Boat.
# ---------------------------------
d = new Myclass() # in REPL, correctly echoes `Myclass(0) []`, `0` being array length
# Chapter II. No Problems (So Far.)
# ---------------------------------
Array.isArray d # `true`, no problem
d instanceof Array # `true`, no problem
d instanceof Myclass # `true`, no problem
types.isa.list d # `true`, no problem
# Chapter III. OMG It's the Titanic
# ---------------------------------
typeof d # 'object'; NB that `( typeof [] ) == 'object'`
types.type_of d # 'list' (our name for JS `Array` instances)
Object::toString.call d # 'Miller Device', gives '[object Array]'
# Chapter IV. One Single Raft Left.
# ---------------------------------
d.constructor.name # 'Myclass'! Yay!
declare.set_or_list test: ( x ) -> ( isa.set_of.text x ) or ( isa.list_of.text x )
...
isa.nonempty.set_or_list [ 'a', 'b', ] # true
isa.set_or_list.or.integer 123 # true
```
Turns out only `d.constructor.name` does the trick—let's call it the [Dominic Denicola
Device](https://stackoverflow.com/users/3191/domenic) since [he wrote the top-rated SO
answer](https://stackoverflow.com/a/30560581) to this pressing question back in 2015.
So let's try and see what the DDDevice can do for us.
### xxx
In essence, we just need to set up a function `ddd = ( x ) -> x.constructor.name`; the only problem with
that is of course that checking attributes on `null` and `undefined` will fail loudly (as if JS ever cared
but whatever), so we have to safeguard against that; these two definitions are equivalent:
```coffee
ddd = ( x ) -> if x? then x.constructor.name else ( if x is null then 'null' else 'undefined' )
ddd = ( x ) -> x?.constructor.name ? ( if x is null then 'null' else 'undefined' )
```
types.isa.integer 42
types.isa.even.integer -42
types.isa.odd.integer 41
types.isa.negative1.integer -42
types.isa.negative0.integer 0
types.isa.positive1.integer 42
types.isa.positive0.integer 0
types.isa.list_of.integer [ 42, ]
types.isa.nonempty.list_of.negative1.integer [ -42, ]
types.isa.nonempty.list_of.negative0.integer [ 0, ]
types.isa.nonempty.list_of.positive1.integer [ 42, ]
types.isa.nonempty.list_of.positive0.integer [ 0, ]
types.isa.empty.list_of.integer []
types.isa.nonempty.list_of.integer [ 42, ]
types.isa.optional.integer 42
types.isa.optional.list_of.integer [ 42, ]
types.isa.optional.empty.list_of.integer []
types.isa.optional.nonempty.list_of.integer [ 42, ]
types.isa.optional.negative1.integer -42
types.isa.optional.negative0.integer 0
types.isa.optional.positive1.integer 42
types.isa.optional.positive0.integer 0
types.isa.optional.nonempty.list_of.negative1.integer [ -42, ]
types.isa.optional.nonempty.list_of.negative0.integer [ 0, ]
types.isa.optional.nonempty.list_of.positive1.integer [ 42, ]
types.isa.optional.nonempty.list_of.positive0.integer [ 0, ]
types.isa.optional.empty.list_of.negative1.integer -42
types.isa.optional.empty.list_of.negative0.integer 0
types.isa.optional.empty.list_of.positive1.integer 42
types.isa.optional.empty.list_of.positive0.integer 0
Our `ddd()` method does give reasonable answers (for a JS type detecting method):
[all] [all] [isa_collection] [isa_collection] [isa_numeric] [isa_numeric] [mandatory]
————————————————————————————————————————————————————————————————————————————————————————————————————
isa optional empty list_of even negative0 <type>
validate nonempty odd negative1
positive0
positive1
```
ddd {} # 'Object'
ddd [] # 'Array'
ddd null # 'null'
ddd true # 'Boolean'
ddd 42 # 'Number'
ddd NaN # 'Number'
ddd Infinity # 'Number'
ddd ( new Myclass() ) # 'Myclass'
```
## Segue on The Miller Device
## Intertype `state` Property
A code comment from 2010 ([CND Types module]()):
* `Intertype` instances have a `state` property; initial value is `{ data: null, method: null, hedges: [],
error: null, }`
* when chained methods on `isa` and `validate` are called (as in `isa.optional.positive0.integer 42`),
`method` will be set to the name of method to be invokes (here `'_isa'`) and `hedges` will contain the
chain of hedges (including the type), in this case `[ 'optional', 'positive0', 'integer', ]`
* type testing methods are allowed to set or manipulate the `types.state.data` value; this can be used as a
side channel e.g. to cache intermediate and ancillary results from an expensive testing method
* should an `isa` method cause an error with an `Intertype` instance with an `errors: false` setting,
`state.error` will contain that error to enable applications to query for `types.state.error?` when an
`isa` test has failed
> It is outright incredible, some would think frightening, how much manpower has gone into reliable
> JavaScript type checking. Here is the latest and greatest for a language that can claim to be second
> to none when it comes to things that should be easy but aren’t: the ‘Miller Device’ by Mark Miller of
> Google (http://www.caplet.com), popularized by James Crockford of Yahoo!.
>
> As per https://groups.google.com/d/msg/nodejs/P_RzSyPkjkI/NvP28SXvf24J, now also called the 'Flanagan
> Device'
>
> * http://ajaxian.com/archives/isarray-why-is-it-so-bloody-hard-to-get-right
> * http://blog.360.yahoo.com/blog-TBPekxc1dLNy5DOloPfzVvFIVOWMB0li?p=916 # page gone
> * http://zaa.ch/past/2009/1/31/the_miller_device_on_null_and_other_lowly_unvalues/ # moved to:
> * http://zaa.ch/post/918977126/the-miller-device-on-null-and-other-lowly-unvalues
## Intertype `create`
* returns deep copy (structural clone) of `default` member of type declaration
* in the case of objects, uses `Object.assign()` to apply optional `cfg`
* all types can (and maybe should) have a `default` value:
* `types.create.text()` returns `''`
* `types.create.integer()` and `types.create.float()` return `0`
* `types.create.object()` returns `{}`
* `types.create.list()` returns `[]`
* and so on
* no implicit type coercion
* `types.create.quantity()` (for which see below) has default `{ value: 0, unit: null, }` which does
not satisfy the constraint `isa.nonempty.text x.unit`, so causes an error
* but `types.create.quantity { unit: 'km', }` works because `Object.assign { value: 0, unit: null, }, {
unit: 'km', }` gives `{ value: 0, unit: 'km', }` which does satisfy all constraints of `quantity`
# Related
```coffee
types.declare.quantity
test: [
( x ) -> @isa.object x
( x ) -> @isa.float x.value
( x ) -> @isa.nonempty.text x.unit
]
default:
value: 0
unit: null
```
* https://github.com/sindresorhus/ow
* https://github.com/sindresorhus/is
* Clojure `spec`
* https://github.com/lukeed/superstruct
* `create()` is of great help when writing functions with a configuration object (here always called `cfg`).
Where in earlier versions of this library one had to write:
```coffee
f = ( cfg ) ->
types.validate.foobar ( cfg = { defaults.foobar..., cfg..., } )
...
```
# To Do
now one can write more succinctly:
* [x] Allow to pass in target object at instantiation, so e.g. `new intertype @` will cause all InterType
methods to become available on target as `@isa()`, `@validate` and so on.
```coffee
f = ( cfg ) ->
cfg = types.create.foobar cfg
...
```
* [x] Rename `export_modules()` to `export()`, allow target object (e.g. `module.exports`) to be passed in.
and have reference to defaults, assignment from structured value and validation all wrapped up inside
one call to a single method.
* [ ] in the browser, `µ.types.types_of(document)` returns `["happy", "extensible", "immediate", "truthy",
"notunset"]`, missing out the (undeclared) value `htmldocument`; this is probably the case with all
undeclared types. Fix by adding result of `tyep_of x` to returned set.
## Intertype `equals()`
* [ ] implement 'fast mode' where validations are just `( x ) -> true` (?)
* a 'deep equals' implementation (see [`jseq`](https://github.com/loveencounterflow/jseq), gleaned from
[`jkroso/equals`](https://github.com/jkroso/equals))
* [ ] Add types `empty`, `nonempty`, ...
## To Do
* [ ] Implement method to iterate over type names, specs.
* **[–]** allow to filter out builtin types
* **[–]** implement sum types (a.k.a. tagged union, variant, variant record, choice type, discriminated
union, disjoint union, or coproduct :-O) as in `isa.integer.or.optional.nonempty.text`
* **[–]** implement hedges `odd`, `even`; valid for `float`s but do imply those numbers will be integer
* **[–]** implement diagnostic API, primarily to check for existence of hedged types; allow to distinguish
between standard types and user-defined types
* **[–]** special types:
* <del>groups</del>
* hedges
* existential / quantified:
* `anything`: `( x ) -> true`
* `something`: `( x ) -> x?`
* `nothing`: `( x ) -> not x?`
* **[–]** allow to derive types, including derivation of defaults
* **[–]** numeric types:
* **[–]** rename `number` to `real`? to avoid conflict with JS `Number` and to clarify that this does not
cover imaginary, complex numbers. Observe we now have `BigInt`s pre-generating literally hundreds of
hedgpath chains
* **[–]** consider `float` (includes `infinity`) vs `ffloat` ('**f**inite' float, excludes `infinity`)
(longer name, more restricted)
* **[–]** salvage
* from [farewell-commit of generated
hedgepaths](https://github.com/loveencounterflow/intertype/tree/c541c4a38bb047fd0cb65b4697c54028dffc2a4f)
solution how to make combinatorics work, write up in [Gaps &
Islands](https://github.com/loveencounterflow/gaps-and-islands)
* **[–]** implement `or` as in `types.isa.integer.or.text 'x'`
* **[–]** consider to turn all hedges into strict owners
* **[–]** can we generate random data based on a type declaration (like [Clojure `spec`]
does)[https://youtu.be/B_Farscj0hY?t=1562]
* **[–]** use sets not arrays when testing for extraneous keys in `Type_cfg.constructor()`
* **[–]** offer a way to collect all errors in validation ('slow fail') instead of bailing out on first
error ('fast fail') ([see HN post](https://news.ycombinator.com/item?id=32179856#32180458))
* **[–]** <del>make it so that type declarations can be queried / viewed / checked by user, especially
`defaults` must be retrievable so they can be referenced from new type declarations</del> <ins>offer API
to retrieve, review, print, document type declarations</ins>
* **[–]** try to find a way to treat hedges, types equally—there shouldn't be any (apparent at least)
difference since in a hedgerow like `isa.nonempty.text.or.optional.integer x` the types and hedges proper
both appear all over the place
* **[–]** in principle then, any combination of hedges proper and types becomes allowable; one could also
say: hedges become types and types are chainable, as in `validate.empty.text x` isnt categorically
different from `validate.text.integer x`, even if the latter reads non-sensically and can only ever fail
(because there's no overlap between text values and integer values). Could/should then rule out
non-sensical hedgerows by other means (i.e. a grammar that states what can go where)
* **[–]** make the name of the disjunction—by default, `'or'`—configurable
* **[–]** allow to configure that `optional` shall only applay to `null`; additionaly or alternatively,
offer `nullable` as a hedge for the same purpose
* **[–]** consider to change `list_of`, `set_of` into `list.of`, `set.of`, allow for all collections
(`text.of`, `object.of`, `map.of`)
* **[–]** implement `last_of()`, `first_of()`
* **[–]** try to centralize hedgerow validation; happens in several places now
* **[–]** implement aliases
* **[–]** implement `isa`, `validate`, `create` as functions that accept hedgerow, value (i.e. can say both
`isa.list.of.integer []` and `isa 'list', 'of', 'integer', []`, maybe `isa.list.of' 'integer', []`, too)
* **[–]** currently `isa` &c call instance method `_isa` &c; make it so that `isa` calls `super()` and
define effective `isa()` in base class `Intertype_xxxxx extends Intertype_abc`, `Intertype extends
Intertype_xxxxx`.
* **[–]** re-consider `seal`
* **[–]** implement type dependencies (both explicit and implicit), e.g. `codepoint` depends on `text` while
`codepointid` depends on `integer`
* **[–]** clarify distinction between `container` and `collection` or remove one of them
* **[–]** implement using the cfg directly for tests against object (struct) properties. Keys can be
anything but if they start with a `$` dollar sign the refer to the keys of the struct being described; `$`
refers to the struct itself; string values name an existing type. These additions make declarations highly
declarative and aid in providing automatic features (e.g. implicit type dependency):
* [ ] Catch errors that originate in type checking clauses
```coffee
declare.quantity
$: 'object' # this could be implicit, judging by the use of any `$`-prefixed key
$value: 'float'
$unit: 'nonempty.text'
default:
value: 0
unit: null
```
* [ ] make it illegal to re-declare an existing type
* **[–]** in addition to single-`$`-prefixed keys, allow double-`$`-prefixed keys to allow arbitrary names
for arbitrary conditions; these should probably always use functions as values:
* [ ] remove ANSI codes from error messages as they interfere with usage in non-terminal based
applications (e.g. in the browser)
```coffee
declare.foobar
$: 'object'
$number: 'optional.float'
$string: 'optional.nonempty.text'
$$either_number_or_string: ( x ) ->
( x.number? or x.string? ) and not ( x.number? and x.string? )
```
* [ ] Trace cause for failure in recursive type checks
* [ ] Allow to declare additional casts after type has been declared
* **[–]** implement 'checks', i.e. helpers to test for conditions like 'object has keys that conform to this
pattern' &c (?)
* **[–]** turn `Type_cfg` instances into functions
* **[–]** document that `isa.optional.t x` is just a convenient way to write `isa.null.or.undefined.or.t x`,
which explains why a hedgerow can be short-circuited as soon as `not x?` has been found to be `true`
* **[–]** implement `examine`, a non-throwing equivalent to `validate`, which returns the test clauses up to
the point of failure or `null`. Variant: call it `fails`, returns `false` where `isa` had returned `true`,
non-empty list of tests otherwise:
* [ ] Unify registration of checks and types; rename `declare()` to `declare_type()`
```coffee
if tests = fails.foobar x # lists are truthy in JS
log tests.at -1 # print info about failed test
```
* **[–]** based on the above, provide nicely formatted error reports so users don't have to
* **[–]** implement `create` with hedges such that one can write things like
`create.nonempty.list.of.integer size: 5`; in this case, the `create` method of type `integer` should be
called with argument `{ hedges: [ 'nonempty', 'integer', ], size: 5, }`
* **[–]** wrap all hedges and type testers to check for arity `1`; mabe this can be done in
`_get_hedge_base_proxy_cfg` once for all
* **[–]** rule out use of names with `cfg.sep` (`.`) (generally, check for name being a valid JS identifier;
likewise, `sep` should be restricted to non-identifier characters)
* [ ] disallow extra arguments to `isa()`: all typechecks must use exactly one argument (`x`)
* [ ] should `undefined` be an inherently sad (like errors) or happy (like `null`) value?
## Is Done
* [ ] implement generic checks like `equals()`
* [ ] all checks should be usable with `validate`, `isa`
* [ ] implement `panic()`-like function that throws on sad values (keeping exceptions as such, unwrapping
saddened values)
* [ ] consider whether to return type as intermediate happy value for type checks like `if is_happy ( type =
check.object x ) then ...`
* [ ] implement custom error messages for types and/or hints what context should be provided on failure in
validations, checks; this in an attempt to cut down on the amount of individual error messages one has to
write (ex.: `validate.number 42, { name, foo, bar }` could quote second argument in error messages to
provide contextual values `name`, `foo`, `bar`)
* [X] implement `validate.immediate x` to check `x` is anything but a promise; also offer as `nowait` method
(the counterpart to `await`)
* [ ] **v4.x.x** type declarations should have keys `isa` (single test or list or object with tests),
`default` (a value that represents initial value of a given type), `check` (like `isa` but for checks),
`sample` (generate random values from the type's domain as done in Clojure `spec`)
* [ ] implement hierarchical types, namespaces such that `isa.text.empty x` becomes possible; assign a
special namespace, call it `x`, for all custom userland namespaces, so one can always rely on
`isa.x.${npm_package_name}.foo()` to be available and free of naming conflicts.
* [ ] introduce `test` as superset of `isa/validate` and `check` such that `test.chk x, ...` returns `true`
or false depending on `check.chk x, ...` returns a happy or sad value (and `test.tp x` is equivalent to
`isa.tp x`). This is just to make it so that one can use available checks w/out being forced to add
`is_happy()` clauses in one's code.
* [ ] fix bug as commented in first version of `@[ "equality checks" ]` test case
* [ ] implement type `given` as `( x ) -> not [ null, undefined, NaN, '', ].includes x`
* [ ] include remark on `float` vs. `number`: "FTTB we are retaining `number` as a less-preferred synonym
for `float`; in the future, `number` may be removed because it conflicts with JS usage (where it includes
`NaN` and `+/-Infinity`) and, moreover, is not truthful (because it is a poor representation of what the
modern understanding of 'number' in the mathematical sense would imply)."
* [ ] include screenshot of `es6classes.test.coffee` `[ "es6classes type detection devices (prototype)" ]`
* [ ] idea:
* `validate()` is a (special) type test that throws unless its only argument is `true`; `isa()` is a
special test that either throws if its only argument is not either `true` or `false`, otherwise
returns its argument;
* type testers are proxies whose properties name refinement type testers, so `validate.text x`
really tests that the output of `text x` is `true`; `validate.text.empty x` throws unless both `text x`
and `empty x` hold; result is the same as `validate.empty.text x`. Both `isa.even.integer x` and
`isa.integer.even x` return the same result, but observe that `even` only makes sense with `integer`s,
so we would like to test for that condition only once, so
* we could use a `check()` as defined above; maybe all checks should return a standardized value that
can have a number of attributes, like `{ type, value, types, ..., }` where `type` is the return value
of `type_of x`, `value` (`probe`?) is `x` itself, `types` is a set of all types so far ascertained
(could be `set( 'float', 'integer', 'even' )` in this case).
* i.e. check objects acting as caches to prevent duplication of efforts;
* namespaces become union types of everything defined under them; there could be a namespace `Url` that
covers URLs in textual form and analyzed into an object, `Url.text` and `Url.object`, and `isa.Url x`
then tests for `( isa.Url.text ) or ( isa.Url.object x )`
* observe that `isa.Url.text x` is *not* the same as `isa.text.Url`, as the global `text` could be
totally unrelated from the one defined under `Url`
* namespaces do not inherit the names of the global namespace
* [X] rename `count` to `cardinal` (as Wirth did in Modula-2)
* [X] implement `isa_optional()`, `validate_optional()` (these will in a future version be rewritten such
that one can write `isa.optional.integer x` and so on, see above)
* [ ] **`TD:ONLYKEYS@1`**—provide an easy way to declare objects that should only have a given set of
attributes
* [ ] **`TD:ONLYKEYS@2`**—??? implement `has_only_keys()` to check for an object not to have any
undeclared key/value pairs ???
* [ ] **`TD:ETRACE@1`**—make a version of `_get_unsatisfied_aspect()` part of API, so users can probe values
for causes of type checking failure
* [ ] **`TD:ETRACE@2`**—consider to store trace of failed assertions in instance such that user may check
directly after type checking for causes; this is a safe operation as InterType works synchronously
* [ ] **`TD:ETRACE@3`**—in chained type declarations (e.g. where one type is an object whose fields are
declared to have some specific types, possibly through a longer chain of declarations), only the top
violated aspect makes it into the error message, obscuring the true underlying cause of failure. Fix that
by collecting the entire chain of failed aspects.
* **`TD:ETRACE@4`**—**implementation**: avoid to throw exceptions anywhere; instead, return a sad value
where an aspect has not been fulfilled. Exceptions always indicate a 'rogue' path: a buggy or incomplete
implementation; regular control flow should use 'blessed' happy/sad values (that can still be 'bogus').
* [ ] **`TD:SORRY@1`**—introduce a type `result`, an object with fields `?ok` for the happy field and
`?error` for the error, as the case may be
* [ ] **`TD:ERROR@1`**—introduce a type named `fault` or similar with fields being roughly `code`
(`integer`), `tag` (`text`), `message` (`text`) to give details on what went wrong with an attempted
computation (`code` is meant to hold a process exit code, but admittedly the name clashes with usage
in V8? / NodeJS? `Error` object's field `code`)
* [ ] **`TD:SORRY@2`**—introduce a type `sorry` as a generalized variant of `sad`; a `sorry` value is either
`sad` or is an object with an (existent/non-null) attribute `error`. Knowing one's data this makes
processing of `result`-type objects simpler and avoids using symbols; however, it may also match objects
that only accidentally have an attribute `error`.
* [ ] consider to use internal `WeakMap` to cache results of `validate()`, `isa()` (in conjunction w/
freezing the argument?)
* [ ] remove `index.*` as those files are no longer needed
* [ ] introduce `assert()`; `validate.type value` then becomes `assert isa.type value`
* [ ] while a type should be defined as a function that takes exactly one argument, there are cases where
types (or something akin to types) are not defined globally but only in reference to a given set of
givens. For example if my set of horses is `h = new Set [ 'Aladdin', 'Bespoke', 'Whizz', ]` then a
`horse_name` might be defined as a `nonempty_text` that also *is an element of the set of horse names*,
whatever that set may contain at the relevant point in time. IOW `isa.horse_name 'Whizz'` is `true` with
respect to `h` but after deleting `Whizz` from `h`, `isa.horse_name 'Whizz'` becomes `false`. Possible way
to model: pass in object containing context, so `isa.horse_name { x: 'Whizz', wrt: h, }`. May want to use
conventional prefix (`ctx_` maybe) for types that require contextual data.
* [ ] switch to compilation-based instantiation, i.e. all function chains (such as `isa.text()`,
`isa.optional.text()`, `validate.nonempty.list_of.nonempty.text()`) should be *prepared* (reified) at
instantion time instead of generated on-the-fly at method call time.
* [ ] type combinations include:
* `isa.list_of.my_type`
* `isa.nonempty.list_of.my_type`
* `isa.nonempty.list`
* `isa.optional.list_of.my_type`
* `isa.optional.my_type`
* `isa.my_type`
* `validate.list_of.my_type`
* `validate.nonempty.list_of.my_type`
* `validate.nonempty.list`
* `validate.optional.list_of.my_type`
* `validate.optional.my_type`
* `validate.my_type`
* **[+]** <del>use
[`Reflect.has()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)
to check for property availability in `size_of()`</del> <ins>reject</ins> because `Reflect.has()` balks on
primitive values like numbers, too, which further complicates the code instead of making it simpler.
⁂sigh⁂
* **[+]** in keeping with APIs for `isa[ typename ]` (i.e. `isa.integer &c`) and `validate[ typename ]`,
implement the same for `declare` as in `declare.my_type cfg`
* **[+]** use 'auto-vivification' for hedgepaths as outlined in
[`hengist/dev/intertype`](https://github.com/loveencounterflow/hengist/blob/40ec7b9cec3afc72c389a0d2889d4bab7babc893/dev/intertype/src/_ng.test.coffee#L813)
* <del>**[–]** how to finalize hedges?</del>
* <del>**[–]** demand to declare types with hedgepaths? `types.declare.empty.list`? `types.declare 'empty',
'list'`?</del>
* <del>**[–]** possible to 'auto-vivify' hedgepaths?</del>
* <del>**[–]** scrap hedgepaths, replace by `isa.$TYPE x, cfg` API? or `isa.$TYPE P..., x` where P may be any
number of modifiers as in `isa.list 'optional', 'empty', x`</del>
* **[+]** fix naming of type test functions (always `test`, should be name of type)
* **[+]** add `default` parameter to `declare`
* **[+]** implement `create()`
* **[+]** provide methods for the ubiquitous `validate.$TYPE ( cfg = { defaults.$TYPE..., cfg..., } )` as
`cfg = types.get_defaults.$TYPE cfg`
* **[+]** implement
* **[+]** declarative freezing
* <del>**[–]** declarative sealing</del>
* **[+]** declarative validation of absence of extraneous (enumerable) properties
* **[+]** declarative object creation with class declaration property `create` (must be function)
* **[+]** <del>make hedgepaths configurable—**hedges need an opt-in**</del>
* <del>using depth (length) of hedgepath; default depth is 0</del>
* <del>using *wildcard hedgepath pattern* (provided by [`picomatch`]()https://github.com/micromatch/picomatch)</del>
* <del>both at instantiation time for all builtins and declaration time for the type being declared</del>
* **[+]** <del>eliminate hedgepaths that end in a hedge instead of in a type (or group). So we don't allow to
test for `empty x`, only for `empty.collection x`, `empty.any x` &c</del>
* **[+]** flatten type entries in registry to be simple `Type_cfg` instances
* **[+]** <del>"a group is a set of types. A group's `groups` property is itself, so group `collection` is
groupmember of group `collection`, meaning there are tests for `isa.collection`, `isa.empty.collection`
and so on."</del>
* **[+]** <del>reconsider role of groups in type declarations</del> <ins>removed groups altogether, keeping
boolean property `collection`</ins>
* **[+]** <del>change `collection` to `iterable`, b/c their distinguishing mark is that they can be iterated
over by virtue of `x[ Symbol.iterator ]` returning a function</del> <ins>make `collection` a boolean
property of type configuration, implement type `iterable`</ins>
* **[+]** implement 'exception-guarding' where we catch exceptions thrown by type testers when so configured
(with `errors: false`) and return `false` instead, recording the error in `state`. When `errors: 'throw'`
is set, errors will be thrown as normally
* **[+]** allow users to access `Intertype_user_error` class so they can throw errors that are exempt from
exception-guarding

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc