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 0.0.4 to 0.101.4

build-npmignore

18

lib/errors.js

@@ -15,2 +15,6 @@ (function() {

super();
if (ref === null) {
this.message = message;
return void 0;
}
this.message = `${ref} (${this.constructor.name}) ${message}`;

@@ -80,2 +84,16 @@ this.ref = ref;

this.Intertype_user_error = class Intertype_user_error extends this.Intertype_error {
constructor(message) {
super(null, message);
}
};
this.Intertype_validation_error = class Intertype_validation_error extends this.Intertype_error {
constructor(ref, state, report) {
super(ref, `not a valid ${state.hedgerow}; failing tests: ${report}`);
}
};
//-----------------------------------------------------------------------------------------------------------

@@ -82,0 +100,0 @@ this.Intertype_ETEMPTBD = class Intertype_ETEMPTBD extends this.Intertype_error {};

181

lib/hedges.js
(function() {
'use strict';
var E, GUY, H, L, PMATCH, debug, ref, rpr,
boundMethodCheck = function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } },
indexOf = [].indexOf;
var E, GUY, H, L, debug, rpr;

@@ -21,4 +19,2 @@ //###########################################################################################################

PMATCH = require('picomatch');
//===========================================================================================================

@@ -32,3 +28,3 @@ this.defaults = {

//===========================================================================================================
ref = this.Intertype_hedges = (function() {
this.Intertype_hedges = (function() {
class Intertype_hedges extends GUY.props.Strict_owner {

@@ -38,65 +34,10 @@ //---------------------------------------------------------------------------------------------------------

super();
//---------------------------------------------------------------------------------------------------------
this._combine = this._combine.bind(this);
this.cfg = {...L.defaults.combinator_cfg, ...cfg};
// @hedgepaths = new GUY.props.Strict_owner()
// for groupname from @_get_groupnames()
// compiled_hedges = @_compile_hedges groupname, @constructor.hedges
// hedgepaths = @get_hedgepaths compiled_hedges
// @hedgepaths[ groupname ] = @_reduce_hedgepaths hedgepaths
return void 0;
}
_combine(terms) {
var _, i, len, ref1, results, v, x;
boundMethodCheck(this, ref);
ref1 = combinate(terms);
results = [];
for (i = 0, len = ref1.length; i < len; i++) {
x = ref1[i];
results.push((function() {
var results1;
results1 = [];
for (_ in x) {
v = x[_];
results1.push(v);
}
return results1;
})());
}
return results;
}
//---------------------------------------------------------------------------------------------------------
_compile_hedges(groupname, hedges) {
var R, catchall_group, hedge, i, j, len, len1, ref1, target, termgroup;
R = [];
catchall_group = this.constructor.catchall_group;
for (i = 0, len = hedges.length; i < len; i++) {
hedge = hedges[i];
if (indexOf.call(hedge.groups, catchall_group) < 0) {
if (indexOf.call(hedge.groups, groupname) < 0) {
continue;
}
}
target = [];
R.push(target);
ref1 = hedge.terms;
for (j = 0, len1 = ref1.length; j < len1; j++) {
termgroup = ref1[j];
// continue if termgroup? and @_has_conflicting_hedge_matchers
if (Array.isArray(termgroup)) {
target.splice(target.length - 1, 0, ...(this.get_hedgepaths(termgroup)));
} else {
target.push(termgroup);
}
}
}
return R;
}
//---------------------------------------------------------------------------------------------------------
get_hedgepaths(compiled_hedges) {
var R, hedgematch, i, idx, ref1, x;
throw new Error("not implemented: get_hedgepaths()");
var R, hedgematch, i, idx, ref, x;
throw new E.Intertype_ETEMPTBD('^intertype.hedges@1^', "not implemented: get_hedgepaths()");
if ((hedgematch = this.cfg.hedgematch) == null) {

@@ -106,7 +47,7 @@ return [];

R = (function() {
var i, len, ref1, results;
ref1 = this._combine(compiled_hedges);
var i, len, ref, results;
ref = this._combine(compiled_hedges);
results = [];
for (i = 0, len = ref1.length; i < len; i++) {
x = ref1[i];
for (i = 0, len = ref.length; i < len; i++) {
x = ref[i];
results.push(x.flat());

@@ -117,3 +58,3 @@ }

if (hedgematch !== '*') {
for (idx = i = ref1 = R.length - 1; i >= 0; idx = i += -1) {
for (idx = i = ref = R.length - 1; i >= 0; idx = i += -1) {
if (!this._match_hedgepath(R[idx], hedgematch)) {

@@ -133,109 +74,47 @@ delete R[idx];

_get_groupnames() {
var h;
return GUY.lft.freeze(new Set(((function() {
var i, len, ref1, results;
ref1 = this.constructor.hedges;
results = [];
for (i = 0, len = ref1.length; i < len; i++) {
h = ref1[i];
results.push(h.groups);
}
return results;
}).call(this)).flat()));
}
};
//---------------------------------------------------------------------------------------------------------
Intertype_hedges.catchall_group = 'other';
Intertype_hedges.hedges = GUY.lft.freeze([]);
//---------------------------------------------------------------------------------------------------------
Intertype_hedges.hedges = GUY.lft.freeze([
{
terms: [null,
'optional'],
groups: ['other']
},
{
terms: [null,
[[null,
'empty',
'nonempty'],
['list_of',
'set_of'],
[null,
'optional']]],
groups: ['other']
},
{
terms: [null,
'empty',
'nonempty'],
groups: ['collection']
},
{
terms: [null,
'positive0',
'positive1',
'negative0',
'negative1'],
groups: ['number']
}
]);
// #---------------------------------------------------------------------------------------------------------
// @groups_of_groups:
// collection: [ ]
//---------------------------------------------------------------------------------------------------------
/* TAINT tack onto prototype as hidden */
Intertype_hedges.prototype._hedgemethods = GUY.lft.freeze(new GUY.props.Strict_owner({
Intertype_hedges.prototype._hedgemethods = new GUY.props.Strict_owner({
freeze: true,
target: {
optional: function(x) {
if (x == null) {
// debug GUY.trm.reverse GUY.trm.yellow '^optional@453^', rpr x, @
return H.signals.true_and_break;
if (x != null) {
return true;
} else {
return H.signals.return_true;
}
return true;
},
//.......................................................................................................
/* TAINT use `length` or `size` or custom method */
empty: function(x) {
return (H.size_of(x, null)) === 0;
or: function(x) {
return x === true;
},
nonempty: function(x) {
return (H.size_of(x, null)) !== 0;
of: function(x) {
return H.signals.element_mode;
},
//.......................................................................................................
list_of: function(x) {
if (!Array.isArray(x)) {
return H.signals.false_and_break;
}
return H.signals.process_list_elements;
empty: function(x) {
var R;
return ((R = H.size_of(x, null)) != null) && R === 0;
},
set_of: function(x) {
if (!(x instanceof Set)) {
return H.signals.false_and_break;
}
return H.signals.process_set_elements;
nonempty: function(x) {
var R;
return ((R = H.size_of(x, null)) != null) && R !== 0;
},
//.......................................................................................................
positive0: function(x) {
// debug GUY.trm.reverse GUY.trm.yellow '^positive0@453^', rpr x
return x >= 0;
return (x === +2e308) || ((Number.isFinite(x)) && (x >= 0));
},
positive1: function(x) {
return x > 0;
return (x === +2e308) || ((Number.isFinite(x)) && (x > 0));
},
negative0: function(x) {
return x <= 0;
return (x === -2e308) || ((Number.isFinite(x)) && (x <= 0));
},
negative1: function(x) {
return x < 0;
return (x === -2e308) || ((Number.isFinite(x)) && (x < 0));
}
}
}));
});

@@ -242,0 +121,0 @@ return Intertype_hedges;

(function() {
'use strict';
var E, GUY, misfit, notavalue,
var E, GUY, Intertype_abc, debug, help, idf, info, misfit, notavalue, rpr, to_width, urge, warn, width_of,
indexOf = [].indexOf;

@@ -9,2 +9,6 @@

({debug, info, warn, urge, help} = GUY.trm.get_loggers('INTERTYPE'));
({rpr} = GUY.trm);
misfit = Symbol('misfit');

@@ -16,5 +20,30 @@

/*
js_type_of = ( x ) => ( ( Object::toString.call x ).slice 8, -1 ).toLowerCase().replace /\s+/g, ''
*/
({to_width, width_of} = require('to-width'));
/* TAINT unify with symbols in `hedges` */
this.misfit = Symbol('misfit');
//...........................................................................................................
this.constructor_of_generators = ((function*() {
return (yield 42);
})()).constructor;
/* see https://github.com/davidmarkclements/rfdc */
this.deep_copy = (require('rfdc'))({
proto: true,
circles: false
});
this.nameit = function(name, f) {
return Object.defineProperty(f, 'name', {
value: name
});
};
idf = function(x) {
return x/* IDentity Function */;
};
this.equals = this.nameit('equals', require('../deps/jkroso-equals'));
//===========================================================================================================

@@ -24,4 +53,4 @@ // TYPE_OF FLAVORS

this.domenic_denicola_device = (x) => {
var ref, ref1;
return (ref = x != null ? (ref1 = x.constructor) != null ? ref1.name : void 0 : void 0) != null ? ref : './.';
var ref1, ref2;
return (ref1 = x != null ? (ref2 = x.constructor) != null ? ref2.name : void 0 : void 0) != null ? ref1 : './.';
};

@@ -38,3 +67,3 @@

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

@@ -105,6 +134,5 @@

target: {
true_and_break: Symbol('true_and_break'),
false_and_break: Symbol('false_and_break'),
process_list_elements: Symbol('process_list_elements'),
process_set_elements: Symbol('process_set_elements'),
return_true: Symbol('return_true'),
advance: Symbol('advance'),
// element_mode: Symbol 'element_mode'
nothing: Symbol('nothing')

@@ -183,9 +211,457 @@ }

//===========================================================================================================
// INTERNAL TYPES
//-----------------------------------------------------------------------------------------------------------
this.constructor_of_generators = ((function*() {
return (yield 42);
})()).constructor;
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);
},
"@isa.boolean x.errors": function(x) {
return this.isa.boolean(x.errors);
}
}
});
//...........................................................................................................
this.defaults.Intertype_constructor_cfg = {
sep: '.',
errors: true
};
//-----------------------------------------------------------------------------------------------------------
this.types.declare('intertype_color', function(x) {
if (this.isa.function(x)) {
return true;
}
if (this.isa.boolean(x)) {
return true;
}
if (!this.isa.nonempty_text(x)) {
return false;
}
if (!this.isa.function(GUY.trm[x])) {
return false;
}
return true;
});
//-----------------------------------------------------------------------------------------------------------
this.types.declare('intertype_state_report_colors', {
tests: {
"@isa.object x": function(x) {
return this.isa.object(x);
},
"@isa.intertype_color x.ref": function(x) {
return this.isa.intertype_color(x.ref);
},
"@isa.intertype_color x.value": function(x) {
return this.isa.intertype_color(x.value);
},
"@isa.intertype_color x.true": function(x) {
return this.isa.intertype_color(x.true);
},
"@isa.intertype_color x.false": function(x) {
return this.isa.intertype_color(x.false);
},
"@isa.intertype_color x.hedge": function(x) {
return this.isa.intertype_color(x.hedge);
},
"@isa.intertype_color x.verb": function(x) {
return this.isa.intertype_color(x.verb);
},
"@isa.intertype_color x.arrow": function(x) {
return this.isa.intertype_color(x.arrow);
},
"@isa.intertype_color x.error": function(x) {
return this.isa.intertype_color(x.error);
},
"@isa.intertype_color x.reverse": function(x) {
return this.isa.intertype_color(x.reverse);
}
}
});
//...........................................................................................................
this.defaults.intertype_state_report_colors = GUY.lft.freeze({
ref: 'grey',
value: 'lime',
true: 'green',
false: 'red',
hedge: 'blue',
verb: 'gold',
arrow: 'white',
error: 'red',
reverse: 'reverse'
});
//...........................................................................................................
this.defaults.intertype_state_report_no_colors = GUY.lft.freeze({
ref: idf,
value: idf,
true: idf,
false: idf,
hedge: idf,
verb: idf,
arrow: idf,
error: idf,
reverse: idf
});
//-----------------------------------------------------------------------------------------------------------
this.types.declare('intertype_get_state_report_cfg', {
tests: {
"@isa.object x": function(x) {
return this.isa.object(x);
},
"x.format in [ 'all', 'failing', 'short' ]": function(x) {
var ref1;
return (ref1 = x.format) === 'all' || ref1 === 'failing' || ref1 === 'short';
},
"@isa.boolean x.refs": function(x) {
return this.isa.boolean(x.refs);
},
"@isa_optional.positive_integer x.width": function(x) {
return this.isa_optional.positive_integer(x.width);
},
"( @isa.boolean x.colors ) or ( @isa.intertype_state_report_colors )": function(x) {
return (this.isa.boolean(x.colors)) || this.isa.intertype_state_report_colors;
}
}
});
//...........................................................................................................
this.defaults.intertype_get_state_report_cfg = {
colors: this.defaults.intertype_state_report_colors,
format: 'failing',
width: null,
refs: false
};
//-----------------------------------------------------------------------------------------------------------
this.defaults.Intertype_state = {
method: null,
verb: null,
isa_depth: 0,
hedgerow: null,
hedges: null,
hedgeresults: null,
x: misfit,
result: null,
error: null,
extra_keys: null,
data: null
};
//===========================================================================================================
//-----------------------------------------------------------------------------------------------------------
Intertype_abc = class Intertype_abc extends GUY.props.Strict_owner {};
//===========================================================================================================
//-----------------------------------------------------------------------------------------------------------
// @defaults = GUY.lft.freeze @defaults
this.Intertype_abc = Intertype_abc;
//===========================================================================================================
//-----------------------------------------------------------------------------------------------------------
this._get_state_report_colors = function(colors) {
var R, color, purpose;
if (colors === true) {
return this.defaults.intertype_state_report_colors;
}
if (colors === false) {
return this.defaults.intertype_state_report_no_colors;
}
R = {};
for (purpose in colors) {
color = colors[purpose];
if (this.types.isa.function(color)) {
continue;
}
switch (color) {
case true:
R[purpose] = GUY.trm[this.defaults.intertype_state_report_colors[color]].bind(GUY.trm);
break;
case false:
R[purpose] = idf;
break;
default:
R[purpose] = GUY.trm[color].bind(GUY.trm);
}
}
return R;
};
//-----------------------------------------------------------------------------------------------------------
this.get_state_report = function(hub, cfg) {
var C, R, TTY, arrow_field, first_hidx, hedge, hidx, i, j, last_hidx, level, push_error_row, push_value_row, r, ref, ref1, ref2, ref3, ref4, sep, truth, value, value_r, verb_field, widths;
this.types.validate.intertype_get_state_report_cfg((cfg = {...this.defaults.intertype_get_state_report_cfg, ...cfg}));
C = this._get_state_report_colors(cfg.colors);
//.........................................................................................................
TTY = require('node:tty');
truth = function(b, r) {
return C.reverse(b ? C.true(" T ") : C.false(" F "));
};
first_hidx = 0;
last_hidx = hub.state.hedgeresults.length - 1;
//.........................................................................................................
R = [];
sep = '';
widths = (function() {
var lw, ref1;
lw = (ref1 = cfg.width) != null ? ref1 : (TTY.isatty(process.stdout.fd)) ? process.stdout.columns : 100;
widths = {};
widths.line = lw;
lw -= widths.ref = cfg.refs ? 5 : 0;
lw -= widths.verb = 10;
lw -= widths.truth = 3;
lw -= widths.hedgerow = Math.floor(lw / 3);
lw -= widths.value = lw;
return widths;
})();
//.........................................................................................................
switch (cfg.format) {
case 'all':
null;
break;
case 'failing':
case 'short':
if (hub.state.result === true) {
return null;
}
first_hidx = last_hidx;
while (first_hidx > 0) {
if ((hub.state.hedgeresults[first_hidx - 1].at(-1)) !== false) {
break;
}
first_hidx--;
}
first_hidx = Math.min(first_hidx, last_hidx);
break;
default:
throw new E.Intertype_internal_error('^intertype.get_state_report@1^', `unknown format ${rpr(format)}`);
}
//.........................................................................................................
switch (cfg.format) {
case 'short':
verb_field = C.reverse(C.verb(` ${hub.state.verb} `));
arrow_field = C.reverse(C.arrow(" ◀ "));
break;
default:
verb_field = C.reverse(C.verb(to_width(hub.state.verb, widths.verb, {
align: 'center'
})));
arrow_field = null;
}
//.........................................................................................................
push_value_row = function(ref, level, hedge, value, r) {
var dent;
dent = ' '.repeat(level);
if (cfg.refs) {
R.push(C.reverse(C.ref(to_width(ref != null ? ref : '', widths.ref))));
}
R.push(truth(r, r != null ? r.toString() : void 0));
R.push(verb_field);
R.push(C.reverse(C.hedge(to_width(' ' + dent + hedge, widths.hedgerow))));
R.push(C.reverse(C.value(to_width(' ' + rpr(value), widths.value))));
R.push('\n');
return null;
};
//.........................................................................................................
push_error_row = function(error = null) {
var error_r;
if (error == null) {
return null;
}
if (error instanceof Error) {
error_r = ` Error: ${error.message.trim()}`;
} else {
error_r = ` Error: ${error.toString()}`;
}
R.push(C.reverse(C.error(to_width(error_r, widths.line))));
return R.push('\n');
};
//.........................................................................................................
switch (cfg.format) {
//.......................................................................................................
case 'all':
case 'failing':
for (hidx = i = ref1 = first_hidx, ref2 = last_hidx; (ref1 <= ref2 ? i <= ref2 : i >= ref2); hidx = ref1 <= ref2 ? ++i : --i) {
[ref, level, hedge, value, r] = hub.state.hedgeresults[hidx];
push_value_row(ref, level, hedge, value, r);
}
//.....................................................................................................
if (hub.state.hedgeresults.length > 1) {
push_value_row(null, 0, hub.state.hedgerow, hub.state.x, hub.state.result);
}
push_error_row(hub.state.error);
break;
//.......................................................................................................
case 'short':
for (hidx = j = ref3 = first_hidx, ref4 = last_hidx; (ref3 <= ref4 ? j <= ref4 : j >= ref4); hidx = ref3 <= ref4 ? ++j : --j) {
[ref, level, hedge, value, r] = hub.state.hedgeresults[hidx];
value_r = rpr(value);
if ((width_of(value_r)) > 50) {
value_r = to_width(value_r, 50);
}
R.push('' + (truth(r)) + verb_field + (C.reverse(C.hedge(` ${hedge} `))) + (C.reverse(C.value(` ${value_r} `))));
}
sep = arrow_field;
break;
default:
throw new E.Intertype_internal_error('^intertype.get_state_report@2^', `unknown format ${rpr(format)}`);
}
//.........................................................................................................
R = R.join(sep);
if ((cfg.format === 'short') && (cfg.colors === false)) {
R = R.trim();
R = R.replace(/\x20{2,}/g, ' ');
}
return R;
};
}).call(this);
//# sourceMappingURL=helpers.js.map
(function() {
'use strict';
var E, GUY, H, HEDGES, ITYP, Intertype_abc, debug, rpr, to_width, types, warn,
var DECLARATIONS, E, GUY, H, HEDGES, Intertype, Type_factory, debug, help, info, rpr, to_width, urge, warn,
splice = [].splice;

@@ -9,3 +9,3 @@

({debug, warn} = GUY.trm.get_loggers('INTERTYPE'));
({debug, info, warn, urge, help} = GUY.trm.get_loggers('INTERTYPE'));

@@ -21,143 +21,76 @@ ({rpr} = GUY.trm);

ITYP = this;
DECLARATIONS = require('./declarations');
types = new (require('intertype-legacy')).Intertype();
({Type_factory} = require('./type-factory'));
this.defaults = {};
({to_width} = require('to-width'));
//-----------------------------------------------------------------------------------------------------------
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.function x.test ) or ( @isa_list_of.function x.test )": function(x) {
return (this.isa.function(x.test)) || (this.isa_list_of.function(x.test));
},
"x.groups is a nonempty text or a nonempty list of nonempty texts": function(x) {
if (this.isa.nonempty_text(x.groups)) {
return true;
}
if (!this.isa.list(x.groups)) {
return false;
}
return x.groups.every((e) => {
return (this.isa.nonempty_text(e)) && !/[\s,]/.test(e);
});
Intertype = (function() {
//===========================================================================================================
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', GUY.props.Strict_owner.create({
oneshot: true
}));
// GUY.props.hide @, 'types', H.types
this._initialize_state();
//.......................................................................................................
this._register_hedges();
DECLARATIONS._provisional_declare_basic_types(this);
return void 0;
}
}
});
//...........................................................................................................
this.defaults.Type_cfg_constructor_cfg = {
groups: 'other',
name: null,
test: null
};
//-----------------------------------------------------------------------------------------------------------
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);
//---------------------------------------------------------------------------------------------------------
_initialize_state(cfg) {
/* TAINT should use deep copy of default object */
return this.state = {
...H.defaults.Intertype_state,
hedgeresults: [],
...cfg
};
}
}
});
//...........................................................................................................
this.defaults.Intertype_constructor_cfg = {
sep: '.'
};
// #-----------------------------------------------------------------------------------------------------------
// 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.Type_cfg = class Type_cfg extends Intertype_abc {
//---------------------------------------------------------------------------------------------------------
constructor(hub, cfg) {
var _test, f, k, v;
/* TAINT ensure type_cfg does not contain `type`, `name` */
super();
GUY.props.hide(this, 'hub', hub);
cfg = {...ITYP.defaults.Type_cfg_constructor_cfg, ...cfg};
cfg.groups = this._compile_groups(cfg.groups);
types.validate.Type_cfg_constructor_cfg(cfg);
if (types.isa.list(cfg.test)) {
_test = (function() {
var i, len, ref, results;
ref = cfg.test;
results = [];
for (i = 0, len = ref.length; i < len; i++) {
f = ref[i];
results.push(f.bind(hub));
}
return results;
})();
cfg.test = (x) => {
return _test.every(function(f) {
return f(x);
});
};
} else {
cfg.test = cfg.test.bind(hub);
//---------------------------------------------------------------------------------------------------------
_register_hedges() {
var hedge, isa, ref1;
ref1 = this._hedges._hedgemethods;
for (hedge in ref1) {
isa = ref1[hedge];
((hedge, isa) => {
return this.declare(hedge, {isa});
})(hedge, isa);
}
return null;
}
if (cfg.isa_collection && (cfg.size == null)) {
cfg.size = 'length';
}
if (cfg.size == null) {
cfg.size = null;
}
for (k in cfg) {
v = cfg[k];
this[k] = v;
}
return GUY.lft.freeze(this);
}
//---------------------------------------------------------------------------------------------------------
_compile_groups(groups) {
var R;
warn(GUY.trm.reverse("^_compile_groups@1^ should validate groups"));
R = (types.isa.text(groups)) ? groups.split(/\s*,\s*/) : groups;
// for group in R
// continue if GUY.props.has @hub._hedges.hedgepaths, group
// throw new E.Intertype_ETEMPTBD '^intertype/Type_cfg^', "unknown hedge group #{rpr group}"
return R;
}
};
//===========================================================================================================
this.Intertype = (function() {
class Intertype extends Intertype_abc {
//---------------------------------------------------------------------------------------------------------
constructor(cfg) {
var _hedgebuffer, base_proxy_cfg, count, group, ref, sub_proxy_cfg;
super();
//.......................................................................................................
/* TAINT ideally would put this stuff elsewhere */
base_proxy_cfg = {
/* 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) => {

@@ -168,107 +101,104 @@ var R, f;

}
_hedgebuffer.length = 0;
_hedgebuffer.push('_isa');
_hedgebuffer.push(key);
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.verb = method_name.slice(1);
self.state.hedges = [key];
self.state.hedgerow = 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;
}
f = {
[`${key}`]: (function(x) {
praise('^878-1^', rpr(x));
return 'something';
})
}[key];
return target[key] = new Proxy(f, sub_proxy_cfg);
//...................................................................................................
/* TAINT code below never used? */
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;
}
};
//.......................................................................................................
count = 0;
sub_proxy_cfg = {
}
//---------------------------------------------------------------------------------------------------------
_get_hedge_sub_proxy_cfg(self) {
return {
get: (target, key) => {
var R, f;
var R, f, type_dsc;
if (key === Symbol.toStringTag) {
// debug '^878-2^', target, rpr key
// process.exit 111 if count++ > 100
return void 0;
}
_hedgebuffer.push(key);
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);
self.state.hedgerow = self.state.hedges.join(self.cfg.sep);
if ((R = GUY.props.get(target, key, H.signals.nothing)) !== H.signals.nothing) {
return R;
}
f = {
[`${key}`]: function(x) {
var method_name;
method_name = _hedgebuffer.shift();
debug('^878-3^', {method_name, _hedgebuffer});
return this[method_name](..._hedgebuffer, x);
}
}[key];
debug('^878-4^', f);
return target[key] = new Proxy(f, sub_proxy_cfg);
//...................................................................................................
if ((type_dsc = 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;
}
};
//.......................................................................................................
GUY.props.hide(this, 'cfg', {...ITYP.defaults.Intertype_constructor_cfg, ...cfg});
GUY.props.hide(this, '_hedges', new HEDGES.Intertype_hedges());
// GUY.props.hide @, 'isa', new GUY.props.Strict_owner { reset: false, }
GUY.props.hide(this, 'isa', new Proxy({}, base_proxy_cfg));
GUY.props.hide(this, 'validate', new GUY.props.Strict_owner({
reset: false
}));
GUY.props.hide(this, 'declare', new Proxy(this._declare.bind(this), {
get: (_, type) => {
return (cfg) => {
return this._declare.call(this, type, cfg);
};
}
}));
GUY.props.hide(this, 'registry', new GUY.props.Strict_owner({
reset: false
}));
GUY.props.hide(this, 'types', types);
GUY.props.hide(this, 'groups', {});
// GUY.props.hide @, '_hedgebuffer', []
_hedgebuffer = [];
ref = this._hedges._get_groupnames();
//.......................................................................................................
for (group of ref) {
this.groups[group] = new Set();
((group) => {
return this.declare(group, {
groups: group,
test: (x) => {
var R;
R = this.groups[group].has(this.type_of(x));
return this._protocol_isa({
term: group,
x,
value: H.signals.nothing,
verdict: R
});
}
});
})(group);
}
GUY.lft.freeze(this.groups);
//.......................................................................................................
return void 0;
}
//---------------------------------------------------------------------------------------------------------
_declare(type, type_cfg) {
var group, i, len, ref;
type_cfg = {
...type_cfg,
name: type
};
type_cfg = new ITYP.Type_cfg(this, type_cfg);
this.registry[type] = type_cfg;
this.isa[type] = type_cfg.test;
this.validate[type] = (x) => {
return this._validate(type, x);
};
ref = type_cfg.groups;
for (i = 0, len = ref.length; i < len; i++) {
group = ref[i];
this._add_type_to_group(group, type);
_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(dsc, this._get_hedge_sub_proxy_cfg(this));
if (dsc.collection) {
this._collections.add(dsc.typename);
}

@@ -279,4 +209,8 @@ return null;

//---------------------------------------------------------------------------------------------------------
_add_type_to_group(group, type) {
this.groups[group].add(type);
_validate_hedgerow(hedgerow) {
var ref1, ref2, xr;
if (((ref1 = hedgerow[0]) === 'of' || ref1 === 'or') || ((ref2 = hedgerow[hedgerow.length - 1]) === 'of' || ref2 === '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}`);
}
return null;

@@ -287,130 +221,161 @@ }

_isa(...hedges) {
var R, e, hedge, hedge_idx, i, len, ref, tail_hedges, type, typetest, verdict, x;
ref = hedges, [...hedges] = ref, [type, x] = splice.call(hedges, -2);
for (hedge_idx = i = 0, len = hedges.length; i < len; hedge_idx = ++i) {
var R, error, ref1, x;
ref1 = hedges, [...hedges] = ref1, [x] = splice.call(hedges, -1);
this.state.isa_depth++;
R = false;
try {
R = this.state.result = this._inner_isa(...hedges, x);
} catch (error1) {
error = error1;
if (this.cfg.errors || error instanceof E.Intertype_error) {
throw error;
}
this.state.error = error;
}
this.state.isa_depth--;
return this.state.result = R;
}
//---------------------------------------------------------------------------------------------------------
_inner_isa(...hedges) {
var R, advance, element, error, hedge, hedge_idx, is_terminal, last_hedge_idx, ref1, result, tail_hedges, type_dsc, x;
ref1 = hedges, [...hedges] = ref1, [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) {
//.......................................................................................................
hedge_idx++;
if (hedge_idx > last_hedge_idx) {
return R; // exit point
}
hedge = hedges[hedge_idx];
switch (R = this._test_hedge(hedge, x)) {
case true:
null;
break;
case H.signals.true_and_break:
return true;
case H.signals.false_and_break:
is_terminal = (hedges[hedge_idx + 1] === 'or') || (hedge_idx === last_hedge_idx);
//.....................................................................................................
if (advance) {
if (is_terminal) { // exit point
return false;
case false:
return false;
case H.signals.process_list_elements:
case H.signals.process_set_elements:
}
if (hedge !== 'or') {
continue;
}
}
advance = false;
//.....................................................................................................
switch (hedge) {
//...................................................................................................
case 'of':
this.push_hedgeresult(['▲ii1', this.state.isa_depth, 'of', x, true]);
tail_hedges = hedges.slice(hedge_idx + 1);
for (e of x) {
if (!this._isa(...tail_hedges, type, e)) {
return false;
try {
for (element of x) {
if ((this._isa(...tail_hedges, element)) === false) { // exit point
// return ( false ) if ( @_inner_isa tail_hedges..., element ) is false # exit point
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; // exit point
//...................................................................................................
case 'or':
this.push_hedgeresult(['▲ii2', this.state.isa_depth, 'or', x, true]);
R = true;
continue;
}
//.....................................................................................................
if ((type_dsc = GUY.props.get(this.registry, hedge, null)) == null) {
throw new E.Intertype_ETEMPTBD('^intertype.isa@8^', `unknown hedge or type ${rpr(hedge)}`);
}
//.....................................................................................................
// @push_hedgeresult hedgeresult = [ '▲ii3', @state.isa_depth, type_dsc.name, x, ]
result = type_dsc.call(this, x);
// hedgeresult.push result
switch (result) {
case H.signals.return_true:
return true;
default:
throw new E.Intertype_ETEMPTBD('^intertype@1^', `illegal return value from \`_test_hedge()\`: ${rpr(type)}`);
case false:
advance = true;
R = false;
continue;
case 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)}`);
}
//.......................................................................................................
if ((typetest = GUY.props.get(this.isa, type, null)) == null) {
throw new E.Intertype_ETEMPTBD('^intertype@1^', `unknown type ${rpr(type)}`);
return R; // exit point
}
//---------------------------------------------------------------------------------------------------------
_validate(...hedges) {
var ref1, state_report, x;
ref1 = hedges, [...hedges] = ref1, [x] = splice.call(hedges, -1);
if (this._isa(...hedges, x)) {
return x;
}
verdict = typetest(x);
return this._protocol_isa({
term: type,
x,
value: H.signals.nothing,
verdict
console.log(GUY.trm.reverse(GUY.trm.red("\n Validation Failure ")));
console.log((this.get_state_report({
format: 'failing'
})).trim());
console.log(GUY.trm.reverse(GUY.trm.red(" Validation Failure \n")));
state_report = this.get_state_report({
format: 'short',
colors: false,
width: 500
});
throw new E.Intertype_validation_error('^intertype.validate@3^', this.state, state_report);
}
//---------------------------------------------------------------------------------------------------------
_test_hedge(hedge, x) {
var R, hedgetest;
if ((hedgetest = GUY.props.get(this._hedges._hedgemethods, hedge, null)) == null) {
throw new E.Intertype_ETEMPTBD('^intertype@1^', `unknown hedge ${rpr(hedge)}`);
_create(type, cfg) {
var R, create, t, type_dsc;
create = null;
//.......................................................................................................
if ((type_dsc = GUY.props.get(this.registry, type, null)) == null) {
throw new E.Intertype_ETEMPTBD('^intertype.create@11^', `unknown type ${rpr(type)}`);
}
//.......................................................................................................
switch (R = hedgetest.call(this, x)) {
case H.signals.true_and_break:
return this._protocol_isa({
term: hedge,
x,
value: H.signals.nothing,
verdict: R
});
case H.signals.false_and_break:
return this._protocol_isa({
term: hedge,
x,
value: H.signals.nothing,
verdict: R
});
case false:
return this._protocol_isa({
term: hedge,
x,
value: H.signals.nothing,
verdict: false
});
case true:
return this._protocol_isa({
term: hedge,
x,
value: H.signals.nothing,
verdict: true
});
case H.signals.process_list_elements:
return this._protocol_isa({
term: hedge,
x,
value: H.signals.nothing,
verdict: R
});
case H.signals.process_set_elements:
return this._protocol_isa({
term: hedge,
x,
value: H.signals.nothing,
verdict: R
});
/* 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_dsc, 'create', null)) === null) {
if ((R = GUY.props.get(type_dsc, '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);
}
//.......................................................................................................
throw new E.Intertype_internal_error('^intertype@1^', `unexpected return value from hedgemethod for hedge ${rpr(hedge)}: ${rpr(R)}`);
}
//---------------------------------------------------------------------------------------------------------
_protocol_isa({term, x, value, verdict}) {
var groups, ref, src, test, type_cfg;
if ((type_cfg = GUY.props.get(this.registry, term, null)) != null) {
groups = (ref = type_cfg.groups) != null ? ref : null;
if ((test = GUY.props.get(type_cfg, 'test', null)) != null) {
src = GUY.src.slug_from_simple_function({
function: test,
fallback: '???'
});
if ((create == null) && (cfg != null)) {
if ((t = H.js_type_of(R)) === '[object Object]' || t === '[object Array]') {
R = Object.assign(H.deep_copy(R), cfg);
} else {
src = null;
R = cfg;
}
} else {
groups = null;
src = null;
R = H.deep_copy(R);
}
debug(GUY.trm.gold('^_protocol_isa@1^', {term, groups, x, value, verdict, src}));
return verdict;
}
//---------------------------------------------------------------------------------------------------------
_validate(...hedges) {
var qtype, ref, type, x, xr;
ref = hedges, [...hedges] = ref, [type, x] = splice.call(hedges, -2);
debug('^4534^', {hedges, type, x});
debug('^4534^', this._isa(...hedges, type, x));
if (this._isa(...hedges, type, x)) {
return true;
//.......................................................................................................
if (type_dsc.freeze === true) {
R = Object.freeze(R);
} else if (type_dsc.freeze === 'deep') {
R = GUY.lft.freeze(H.deep_copy(R));
}
qtype = [...hedges, type].join(this.cfg.sep);
xr = to_width(rpr(x), 100);
throw new E.Intertype_ETEMPTBD('^intertype@1^', `not a valid ${qtype}`);
//.......................................................................................................
return this._validate(type, R);
}

@@ -422,10 +387,29 @@

//-----------------------------------------------------------------------------------------------------------
_walk_hedgepaths(cfg) {
throw new Error("^_walk_hedgepaths@1^ not implemented");
_split_hedgerow_text(hedgerow) {
return hedgerow.split(this.cfg.sep);
}
//---------------------------------------------------------------------------------------------------------
get_state_report(cfg) {
return H.get_state_report(this, cfg);
}
//---------------------------------------------------------------------------------------------------------
push_hedgeresult(hedgeresult) {
/* [ ref, level, hedge, value, r, ] = hedgeresult */
var hedge, level, r, ref, value;
[ref, level, hedge, value, r] = hedgeresult;
H.types.validate.nonempty_text(ref);
// H.types.validate.cardinal level
H.types.validate.nonempty_text(hedge);
H.types.validate.boolean(r);
this.state.hedgeresults.push(hedgeresult);
return hedgeresult.at(-1);
}
};
//---------------------------------------------------------------------------------------------------------
Intertype.prototype.equals = H.equals;
Intertype.prototype.type_of = H.type_of;

@@ -439,11 +423,18 @@

// cfg = { ITYP.defaults.Intertype_walk_hedgepaths_cfg..., cfg..., }
// yield from GUY.props.walk_tree @isa, cfg
// return null
// #-----------------------------------------------------------------------------------------------------------
// _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.defaults = GUY.lft.freeze(this.defaults);
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": "0.0.4",
"version": "0.101.4",
"description": "A JavaScript typechecker",

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

"dependencies": {
"acorn": "^8.7.1",
"acorn-loose": "^8.3.0",
"acorn-walk": "^8.2.0",
"astring": "^1.8.3",
"guy": "10.0.0",
"guy": "11.6.0",
"intertype-legacy": "^7.7.1",
"picomatch": "^2.3.1",
"rfdc": "^1.3.0",
"to-width": "^1.2.0"

@@ -26,0 +22,0 @@ },

# InterType
# ▞ InterType

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

- [InterType](#intertype)
- [Hedges](#hedges)
- [Type Declarations](#type-declarations)
- [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)

@@ -20,8 +30,289 @@ - [Is Done](#is-done)

## Quick Links
# InterType
* [Type Declarations](README-declare.md)
## Hedges
# ▞ InterType
## Motivation
* 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
## Contracts of Type Tests and the Verbs `isa`, `validate`
### Type Tests
* 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:
```coffee
{ Intertype
Intertype_user_error } = require 'intertype'
types = new Intertype { errors: false, }
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), exception-guarding is an opt-in (as shown above, use
`errors: false`)
* Users may always construct type testers whose intentional errors will not be silently caught by deriving
their errors from `Intertype_user_error`
* A type test must be *idempotent* and is therefore only allowed to look at, but not to touch (modify)
values; IOW, it must be a pure method in the sense of functional programming. Yes, in theory one could
write an `isa` method that 'fixes' a list by transforming, adding or deleting some elements (conveniently
so, while one has to iterate over list elements anyway), but that would most certainly violate most user's
basic assumptions—a type check is not supposed to return with a triumphant 'does the value have the proper
shape? Well yes, now it does!'. A type check is not a repair order. InterType does not check for `isa`
method being pure because that is deemed (far) too computationally expensive.
### `isa`
* 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.
## `validate`
* `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`.
## Hedgerows
* 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`)
* these accessors are called 'hedges'
* hedges can be combined in so-called 'hedgerows', e.g. `isa.positive0.integer x` tests whether `x >= 0`
* hedgerows can be arbitrarily long, e.g. `isa.optional.nonempty.list_of.optional.negative1.integer x`
* 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:
```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
```
* 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).
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:
```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
```
* 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 )`).
* 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.
### Diagram
```
isa.text
text is text isnt text
return true ATOERF¹
⊙ return true return false
¹ATOERF: Advance To OR, Else Return False
```
```
isa.text.or.optional.list_of.positive1.integer
text is text isnt text
return true ATOERF¹
or ————————————————————————
integer is integer isnt integer
next ATOERF¹
⊙ return true return false
¹ATOERF: Advance To OR, Else Return False
```
```
isa.text.or.optional.list_of.positive1.integer
text is text isnt text
return true ATOERF¹
or ————————————————————————
optional not x? x?
return true next
list_of: list is list isnt list
switch to EM² ATOERF¹
positive1 e > 0 not ( e > 0 )
next ATOERF¹
integer is integer isnt integer
next ATOERF¹
⊙ return true return false
¹ATOERF: Advance To OR, Else Return False
²EM: Elements Mode
```
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`:
| FALSE | isa | TRUE |
| ------: | :-------: | :----- |
| | negative1 | ▼ |
| | integer | ▼ |
| ───────── | OR | ▼▼▼────── |
| | optional | |
| | empty | |
| | text | |
| ═════════ | ═════════ | ═════════ |
| | -42 | TRUE |
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`:
| FALSE | isa | TRUE |
| ------: | :-------: | :----- |
| ▼▼ | negative1 | |
| | integer | |
| ────────▼ | OR | ───────── |
| | optional | ▼ |
| ▼▼ | empty | |
| | text | |
| ═════════ | ═════════ | ═════════ |
| FALSE | 'meep' | |
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:
| 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.
**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.
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:
| FALSE | isa | TRUE |
| ------: | :-------: | :----- |
| | nonempty | ▼ |
| ▼▼ | text | |
| ────────▼ | OR | ───────── |
| | list_of | ▼ |
| | ∈ nonempty | ▼ |
| | ∈ text | ▼ |
| ═════════ | ═════════ | ═════════ |
| | [ 'helo', 'world', ] | TRUE |
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
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
```
### xxx
```
types.isa.integer 42

@@ -66,40 +357,115 @@ types.isa.even.integer -42

## Intertype `state` Property
## Type Declarations
* `Intertype` instances have a `state` property
* the shape and initial value of `types.state` is:
```coffee
'use strict'
```coffee
types.state = {
method: null
hedges: []
extra_keys: null
error: null
data: null }
```
types = new ( require '../../../apps/intertype' ).Intertype()
{ isa
declare } = types
log = console.log
* The initial value of `types.state` is resumed right before a top-level `isa` or `validate` test is
performed.
declare 'xy_quantity', test: [
( x ) -> @isa.object x
( x ) -> @isa.float x.value
( x ) -> @isa.nonempty.text x.unit
]
* The fields of `types.state` are used as follows:
# can use simplified form:
* When chained methods on `isa` and `validate` are called (as in `isa.integer x`, `validate.integer x`),
`method` will be set to the name of method to be invoked (here `'_isa'` or `'_validate'`).
declare.xy_quantity,
* As each hedge in a hedgerow is encountered, its name is pushed into the `types.state.hedges` list and
its associated test is performed.
* 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. Errors that are thrown instead of being silenced are *not* recorded in
`state.error`.
* `state.data` is a place for the user's type-checking methods to store intermediate data in. It is never
touched by InterType methods except for being reset each time a top-level `isa` or `validate` is
performed. It can be used to store expensive computational results that are necessitated by
type-checking procedures; for example, one might have a type that is a potentially long list of either
functions or names identifying functions. When checking that the list validates, one has to iterate over
the list and check for all elements being either a function or a name. Knowing that names will have to
be replaced by functions later on, on could have the `isa` method cache all those to-be-postprocessed
items:
```coffee
( x ) ->
@state.data ?= {}
@state.data.name_indexes ?= []
for idx, element in x
switch @type_of element
when 'function'
continue
when 'text'
@state.data.name_indexes.push { idx, element, }
else
return false
...
...
```
## 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`
```coffee
types.declare.quantity
test: [
( x ) -> @isa.object x
( x ) -> @isa.float x.value
( x ) -> @isa.nonempty.text x.unit
( x ) -> @isa.object x
( x ) -> @isa.float x.value
( x ) -> @isa.nonempty.text x.unit
]
default:
value: 0
unit: null
```
* `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:
log '^1-1^', isa.xy_quantity null
log '^1-1^', isa.xy_quantity 42
log '^1-1^', isa.xy_quantity { value: 42, unit: 'm', }
```
```coffee
f = ( cfg ) ->
types.validate.foobar ( cfg = { defaults.foobar..., cfg..., } )
...
```
now one can write more succinctly:
```coffee
f = ( cfg ) ->
cfg = types.create.foobar cfg
...
```
and have reference to defaults, assignment from structured value and validation all wrapped up inside
one call to a single method.
## Intertype `equals()`
* a 'deep equals' implementation (see [`jseq`](https://github.com/loveencounterflow/jseq), gleaned from
[`jkroso/equals`](https://github.com/jkroso/equals))
## To Do
* **[–]** make hedgepaths configurable—**hedges need an opt-in**
* using depth (length) of hedgepath; default depth is 0
* using *wildcard hedgepath pattern* (provided by [`picomatch`]()https://github.com/micromatch/picomatch)
* both at instantiation time for all builtins and declaration time for the type being declared
* **[–]** allow to filter out builtin types

@@ -111,9 +477,4 @@ * **[–]** implement sum types (a.k.a. tagged union, variant, variant record, choice type, discriminated

between standard types and user-defined types
* **[–]** "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."
* **[–]** 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
* **[–]** special types:
* groups
* <del>groups</del>
* hedges

@@ -125,19 +486,8 @@ * existential / quantified:

* **[–]** allow to derive types, including derivation of defaults
* **[–]** provide methods for the ubiquitous `validate.$TYPE ( cfg = { defaults.$TYPE..., cfg..., } )` as
`cfg = types.get_defaults.$TYPE cfg`
* **[–]** add `defaults` parameter to `declare`
* **[–]** 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
* **[–]** rename group `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
* **[–]** fix naming of type test functions (always `test`, should be name of type)
* **[–]** 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>
* **[–]** 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

@@ -148,3 +498,122 @@ * from [farewell-commit of generated

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
* **[–]** `helpers.dep_copy()` should allow circular objects where necessary
* **[–]** `structuredClone()` throws an exception when encountering a function (and other things)
* **[–]** fix (probably) related bug [metteur#1867d3a6535c4d1f12ccc55d359fc6ff681a16e6](https://github.com/loveencounterflow/metteur/tree/1867d3a6535c4d1f12ccc55d359fc6ff681a16e6)
```
Validation Failure
F create mtr_new_template.rpr:optional.function { template: 'the answers are ❰...answer❱.', open: '❰', close: '❱', rpr: null }
F create mtr_new_template Symbol(misfit)
Error: ^intertype/validate@1567^ not a valid boolean (violates 'x is true or false'): Symbol(return_true)
Validation Failure
```
* **[–]** 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:
```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? )
```
* **[–]** 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:
```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)
* **[–]** consider to offer faster mode where all hegerows must get pre-declared instead of being
auto-vivified on-the-fly
* **[–]** rename `extras` in type descriptions to `open`? Or indeed create type `noxtra` similar to `empty`,
`nonempty`: `isa.noxtra.foo x` (or `isa.foo.noxtra x`?) is `true` when `isa.foo x` is `true`, the
declaration of type `foo` enumerates fieldnames, and no fields except these are found in `Object.keys x`.
* **[–]** <del>allow `validate` to take an extra parameter: either string (with placeholders for data?) or
function to be called in case of validation failure; this to make throwing more meaningful errors than
standard validation errors easier</del> <ins>probably not possible due to existence of rest parameter in
`_validate: ( hedges..., type, x ) ->`; instead, recommend these patterns:</ins>
```coffee
### provide custom value in case of postcondition failure: ###
plus_1 = ( a, b ) ->
R = a + b
return try validate.float.or.bigint R catch error
0
### throw custom error in case of postcondition failure: ###
plus_2 = ( a, b ) ->
R = a + b
return try validate.float.or.bigint R catch error
throw new Error "these values can not be added: a: #{rpr a}, b: #{rpr b}"
```
* **[–]** implement configuration to specifiy whether validation errors should output tracing message and
whether to include tracing in `stderr` or print to console or both
* **[–]** must use deep copies when deriving values from defaults in `create()`
* **[–]** `get_state_report()` may report single line even with `format: 'failing'` when test has succeeded,
should return `null`
* **[–]** change `default` to `defaults` (as in, 'field defaults') to avoid clash with JS reserved word.
Alternative: <del>`paragon`</del> <ins>`template`</ins>
* **[–]** do not use `$`-prefixed fieldnames, define fields in `fields` sub-object
* **[–]** allow list as enumeration of allowed values as in `color: [ 'red', 'green', 'blue', ]`
* **[–]** Implement a demo type `quantity` that allows inputs like `ms: 42`, `km: 3, m: 800` with
normalization
* **[–]** make sure key properties of `Intertype` instances are hidden to avoid terminal flooding on output
## Is Done

@@ -159,1 +628,53 @@

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
* **[+]** 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;
<del>`$` refers to the struct itself;</del> string values name an existing type. These additions make
declarations highly declarative and aid in providing automatic features (e.g. implicit type dependency):
```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
```

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

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