New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@algebraic/type

Package Overview
Dependencies
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@algebraic/type - npm Package Compare versions

Comparing version

to
1.0.0-alpha.21

cache.js

10

fail.js
const fail = Object.assign(
(...args) => { throw args.length > 1 ?
new (args[0])(args[1]) : Error(args[0]); },
(...args) => {
throw args[0] instanceof Error ?
args[0] :
typeof args[0] === "object" ?
Object.assign(Error(), args[0]) :
args.length > 1 ?
new (args[0])(args[1]) :
Error(args[0]); },
{ syntax: message => fail(SyntaxError, message) },

@@ -5,0 +11,0 @@ { type: message => fail(TypeError, message) });

279

field.js

@@ -1,233 +0,104 @@

const { is, fNamed } = require("./declaration");
const { parameterized } = require("./parameterized");
const { belongs, parameters } = parameterized;
const union = require("./union");
const maybe = require("./maybe");
const or = require("./or");
const { data } = require("./data");
const { ftype, string, boolean } = require("./primitive");
const { isArray } = Array;
const has = hasOwnProperty.call.bind(hasOwnProperty);
const any = require("./any");
const { IObject } = require("./intrinsics");
const { has } = IObject;
const f = require("./function-define");
//const type = require("./type");
const fail = require("./fail");
const of = require("./of");
const private = require("./private");
const { definition } = require("./type");
// data.fields are datas themselves, so creating them is a little tricky. You
// can quickly get into infinite recursion as data.fields have data.fields
// which have data.fields, etc. The solution is to have an internal non-data
// representation and only create the data.field representation as necessary
// (lazily).
//
// Here is our "official" representation. Technically this recurses forever,
// as data.field<T>'s init property is a data.field <data.field <T>.init>,
// which itself has an init field that is a
// data.field <data.field <data.field <T>.init >.init>, etc.
const field = parameterized(T =>
data `data.field <${T}>` (
name => string,
definition => field.definition(T) ) );
module.exports = field;
field.definition = parameterized(function (T)
function Field(options)
{
const suppliedT = field.definition.supplied(T);
const computedT = field.definition.computed(T);
return union `data.definition<${T}>` (
supplied => suppliedT,
computed => computedT );
});
field.definition.supplied = parameterized(T =>
data `field.definition<${T}>.supplied` (
fallback => maybe (T) ) );
field.definition.computed = parameterized(T =>
data `field.definition<${T}>.computed` (
compute => ftype,
dependencies => Array ) );
field.deferred = data `field.deferred` (
name => string,
computed => [boolean, false],
λdefinition => ftype );
field.declaration = union `field.declaration` (
field,
field.deferred );
field.error = union `field.error` (
data `missing` (
name => string ),
data `type` (
expected => any,
value => any ) );
field.compile = function (fieldDeclarations)
{
const partition = require("@climb/partition");
const compiled = fieldDeclarations.map(fromDeclaration);
const [computed, uncomputed] =
partition(([, [, computed]]) => computed, compiled);
return Object.assign(compiled, { computed, uncomputed });
return options instanceof Field ?
options :
options instanceof type ?
new Field({ type: options }) :
!(this instanceof Field) ?
new Field(options) :
IObject.assign(this,
{
default:
has("defaultValue", options) ?
new Default.Value(options.defaultValue) :
definition(options.type).toDefaultValue ?
new Default.Value(
definition(options.type)
.toDefaultValue(options.type)) :
Default.None,
constraint: new Constraint(options.type)
});
}
// field.declaration
// field.declaration.direct
// field.declaration.shorthand
//
// field.declaration { name, definition }
// property { name, definition: supplied }
// property { name, definition: computed }
module.exports = Field;
const parseShorthand = (function ()
Field.prototype.extract = function (forT, name, values)
{
const fShorthandRegExp = /(?:^\(\[([^\]]+)\]\))|([^=\s]+)\s*=>/;
const present = has(name, values);
return f =>
(([, computed, supplied]) => [!!computed, computed || supplied])
(fShorthandRegExp.exec(f + ""));
})();
if (!present && this.default === Default.None)
fail.type(
`${toTypeString(forT)} constructor requires field ` +
`${toValueString(name)}.`);
function fromDeclaration(declaration)
{
const isShorthand = !is (field.declaration, declaration);
const [computed, name, definition] =
isShorthand ?
[...parseShorthand(declaration), declaration([])] :
is (field.deferred, declaration) ?
[declaration.computed,
declaration.name,
declaration.λdefinition([])] :
[is (field.definition.computed, declaration.definition),
declaration.name,
declaration.definition];
const compiled = is (field.definition, definition) ?
fromDefinition(definition) :
fromShorthandDefinition(computed, definition);
// FIXME: Do computed correctly...
if (!present)
return this.default instanceof Default.Value ?
this.default.value :
this.default.computed();
return [name, compiled];
}
const value = values[name];
function fromDefinition(definition)
{
const type = parameters(definition)[0];
if (!this.constraint.has(value))
fail.type(
`${toTypeString(forT)} constructor passed invalid value` +
` for field ${toValueString(name)}:\n` +
` Expected: type ${toTypeString(this.constraint.type)}\n` +
` Found: ${toValueString(value)} ` +
`of type ${toTypeString(type.of(value))}`);
return is (field.definition.supplied, definition) ?
toSuppliedIC(type, definition) :
toComputedIC(type, definition);
return value;
}
function fromShorthandDefinition(computed, definition)
function Constraint(type)
{
const tuple = isArray(definition);
if (computed && tuple)
return fromComputedShorthand(...definition);
if (computed && !tuple)
return fail("Failed to parse computed property, you must pass an array");
/*
if (computed && !tuple)
return toComputedIC(
of(definition),
{ compute:() => definition, dependencies:[] });
*/
const type = tuple ? definition[0] : definition;
const fallback = tuple ?
maybe(type).just({ value: definition[1] }) :
maybe(type).nothing;
return toSuppliedIC(type, { fallback });
this.type = type;
}
const fromComputedShorthand = (function ()
Constraint.prototype.has = function (value)
{
const templateRegExp = require("./templated-regular-expression");
const { objectRegExp, listRegExp, emptyRegExp } = templateRegExp(
{
name: /[^,\}\s\)]+/g,
names: /${name}(?:\s*,\s*${name})*/,
objectRegExp: /^\(\s*\{\s*${names}\s*\}\)/,
listRegExp: /^\(?\s*(${names})\s*\)?/,
emptyRegExp: /^\(\s*(\{\s*\})?\s*\)/,
});
return function fromComputedShorthand(type, shorthand)
{
const fString = shorthand + "";
if (emptyRegExp.exec(fString))
return toComputedIC(type,
{ compute: () => shorthand(), dependencies:[] });
const object = objectRegExp.exec(fString);
const extracted = (object || listRegExp.exec(fString))[1];
const dependencies = extracted.split(/\s*,\s*/);
const deduped = Array.from(new Set(dependencies));
const compute = object ?
values => shorthand(values) :
values => shorthand(...dependencies.map(name => values[name]));
return toComputedIC(type, { compute, dependencies });
}
})();
function toSuppliedIC(type, definition)
{
const { fallback } = definition;
const initializer = fallback === maybe(type).none ?
(provided, name) => has(provided, name) ?
[true, provided[name]] :
[false, field.error.missing({ name })] :
(provided, name) => has(provided, name) ?
[true, provided[name]] :
[true, fallback.value];
return toIC(false, initializer, type, definition);
return type.has(this.type, value);
}
function toComputedIC(type, definition)
const Default =
{
const resulted = values => [true, definition.compute(values)];
None: Symbol("Default.None"),
Value: f.constructible `Default.Value`
(function (f, value) { this.value = value } ),
Computed: f.constructible `Default.Computed`
(function (f, computed) { this.computed = computed })
};
return toIC(true, resulted, type, definition);
}
Field.Default = Default;
function toIC(computed, initializer, type, definition)
{
return [typechecked(type, initializer), computed, type, definition];
}
const highlighted = ([color]) => string => `${color}${string}\x1b[0m`;
const toTypeString = T => highlighted `\x1b[36m` (type.typename(T));
const toValueString = value => highlighted `\x1b[35m` (
value === void(0) ? "undefined" :
value === null ? "null" :
typeof value === "function" ? `[function ${value.name}]` :
// typeof value !== "object" ? JSON.stringify(value, null, 2) :
// of(value) && getKind(of(value)) ? value + "" :
JSON.stringify(value, null, 2));
function typechecked(expected, initializer)
{
return (...args) => (([success, value]) =>
!success ? [success, value] :
is (expected, value) ? [true, value] :
[false, field.error.type({ expected, value })])
(initializer(...args));
}
module.exports.fromCompiled = function ([name, [_, computed, type, values]])
{
const definitionT = field.definition(type);
const definition = computed ?
definitionT.computed(values) :
definitionT.supplied(values);
const type = require("./type");
return field(type)({ name, definition });
}
// FIXME: UGH.
/* const MISSING = { };
const defaultValue = private(value, "defaultValue", () => MISSING);
module.exports.toFieldDeclaration = function toFieldDeclaration (declaration)
{
if (is (field.declaration, declaration))
return declaration;
this.default = defaultValue !== MISSING ?
new Default.Value(defaultValue) :
Default.None;*/
const [computed, name] = parseShorthand(declaration);
const λdefinition = declaration;
return field.deferred({ name, computed, λdefinition });
}
{
"name": "@algebraic/type",
"version": "1.0.0-alpha.20",
"version": "1.0.0-alpha.21",
"description": "",

@@ -5,0 +5,0 @@ "main": "type.js",

@@ -1,21 +0,361 @@

const type =
Error.stackTraceLimit = 10000;
const { IObject, IArray } = require("./intrinsics");
const { flat } = IArray.prototype;
const { f, constructible } = require("./function-define");
const { isTaggedCall, tagResolve } = require("./templating");
const fail = require("./fail");
const Definition = Symbol("Definition");
const definition = T => T[Definition];
const private = require("./private");
const UseFallbackForEverField = IObject.create(null);
const isObject = value => value && typeof value === "object";
const isFunction = value => typeof value === "function";
const type = constructible("type", (_, ...arguments) =>
// Case 0: type() -> ERROR
arguments.length < 1 ?
fail (`type() cannot be called with no arguments.`) :
// Case 1: type `[...]` -> ((...body) -> T)
isTaggedCall(arguments) ?
parseBody(tagResolve(...arguments)) :
// Case 2: type (...body) -> T
typeof arguments[0] !== "string" ?
declare("", arguments) :
// Case 3: type (string) -> ((...body) -> T)
arguments.length === 1 ?
parseBody(arguments[0]) :
// Case 4: type (string, ...body) -> T
declare(arguments[0], arguments.slice(1)),
(f, property) => property.inherits(Function.prototype));
IObject.defineProperty(type, "type", { value: type });
type.definition = definition;
// FIXME: Generalize this...
type.of = type.of = value =>
!value ? type[typeof value] :
IObject.getPrototypeOf(value).constructor instanceof type ?
IObject.getPrototypeOf(value).constructor :
type[typeof value];
const declare = (name, body, flatBody = flat.call(body)) =>
define(
isSumBody(flatBody) ? Sum (name, flatBody) :
isProductBody(flatBody) ? Product (name, flatBody) :
fail (`Could not recognize type declaration.`));
function parseBody(name)
{
always: value => [type.of(value), () => value],
any: require("./any"),
array: require("./array"),
of: require("./of"),
...require("./declaration"),
...require("./data"),
union: require("./union"),
...require("./primitive"),
...require("./serialize"),
...require("./deserialize"),
...require("./parameterized"),
maybe: require("./maybe"),
nullable: require("./nullable"),
or: require("./or"),
result: require("./result")
};
return IObject.assignNonenumerable(
(...body) => declare(name, body),
{ forall: (...rest) => forall(name, ...rest) });
}
const define = declaration =>
constructible(declaration.name, function (T, ...args)
{
const instantiating = args[0] === instantiate;
const instantiated = this instanceof T;
return instantiating && instantiated ?
this :
!instantiating && instantiated ?
failCannotBeInvokedWithNew(T) :
isTaggedCall(args) ?
annotate(tagResolve(...args), T) :
tryDefaultConstructor(T, args);
},
(T, property,
TDefinition = new TypeDefinition(T, declaration),
constructors = IObject.values(TDefinition.constructors)) =>
[
declaration.onPrototype &&
property.onPrototype(declaration.onPrototype),
property.prototypeOf (
constructors.length === 1 &&
definition(constructors[0]).isUnaryConstructor ?
IObject.setPrototypeOf(T.prototype, type.prototype) :
type.prototype),
declaration.inherits &&
property.inherits (declaration.inherits),
property({ name: Definition, value: TDefinition }),
...IObject
.entries(TDefinition.constructors)
.map(([name, constructor]) => property(
{
name,
enumerable: false,
value: definition(constructor).isUnaryConstructor ?
constructor() :
constructor
}))
]);
module.exports = type;
module.exports.type = type;
function instantiate(T, [public_, private_])
{
const instance =
T.prototype instanceof Array ?
IObject.setPrototypeOf([], T.prototype) :
new T(instantiate);
IObject
.entries(private_ || {})
.map(([name, value]) => private(instance, name, () => value));
return IObject.freeze(IObject.assign(instance, public_));
}
function TypeDefinition(T, declaration)
{
this.name = declaration.name || "";
this.invocation = declaration.invocation || false;
const constructorDeclarations = declaration.constructors || [];
const hasSingleConstructor = constructorDeclarations.length === 1;
const constructorEntries =
constructorDeclarations
.map((declaration, ID) =>
Constructor(hasSingleConstructor, T, ID, declaration))
.map(constructor => [constructor.name, constructor]);
this.constructors = IObject.fromEntries(constructorEntries);
const count = constructorEntries.length;
this.EveryCID = [(1 << count) - 1];
const typeKeyedConstructors =
constructorEntries
.filter(([name]) => name.startsWith("."));
// FIXME: What if *both* of these are present?
this.defaultConstructor =
IObject.has(this.name, this.constructors) ?
this.constructors[this.name] :
typeKeyedConstructors.length > 0 ?
toDefaultedTypeKeyedConstructor(typeKeyedConstructors) :
false;
this.has = declaration.has || ((T, value) => value instanceof T);
this.toDefaultValue = declaration.toDefaultValue;
return IObject.freeze(this);
}
function toDefaultedTypeKeyedConstructor(typeKeyedConstructors)
{
return function (value)
{
const T = type.of(value);
const constructor = typeKeyedConstructors
.map(([name, C]) => [name, C, getFields(C)])
.find(([name, C, fields]) =>
fields.length === 1 &&
fields[0][1].constraint.type === T);
if (!constructor)
fail (`No matching constructor found for ` + value);
return constructor[1](value);
}
}
function tryDefaultConstructor(T, args)
{
const { defaultConstructor, constructors, name } = definition(T);
return defaultConstructor ?
defaultConstructor(...args) :
fail(
`${name} has no default constructor.` +
(constructors.length <= 0 ?
"" :
`\nAvailable constructors are:${
IObject
.values(constructors)
.map(({ name }) => `\n ${name}`)}`));
}
// FIXME: Do something if constructors.length === 0
const failCannotBeInvokedWithNew = T =>
fail(
`${T.name} cannot be invoked with "new", ` +
`use ${T.name}(...) instead.`);
const primitive =
(name, has = (T, value) => typeof value === name) =>
define({ name, has });
type.bigint = primitive("bigint");
type.boolean = primitive("boolean");
type.function = primitive("function");
type.number = primitive("number");
type.null = primitive("null");
type.string = primitive("string");
type.symbol = primitive("symbol");
type.undefined = primitive("undefined");
type.object = primitive("object", (T, value) => value && typeof value === "object");
const has = (T, ...rest) =>
rest.length === 0 ?
value => has(T, value) :
definition(T).has(T, rest[0]);
type.has = has;
type.typename = T => definition(T).name;
function Constructor(hasSingleConstructor, T, ID, declaration)
{
const { name, preprocess, fields } = declaration;
const initialize = declaration.initialize || ((C, fields) => [fields]);
const hasNamedFields = fields.length === 1 && isObject(fields[0]);
const hasPositionalFields = !hasNamedFields && fields.every(isFunction);
if (!hasNamedFields && !hasPositionalFields)
fail (
`Unrecognized field declarations for constructor ${name}:` +
JSON.stringify(fields));
const isUnaryConstructor = hasPositionalFields && fields.length === 0;
const isUnaryType = hasSingleConstructor && isUnaryConstructor;
return f(name, (C, ...values) =>
{
if (isUnaryType)
return T;
const [result, preprocessed] = preprocess ?
preprocess(T, C, values) :
[false, values];
return result ||
instantiate(
T,
initialize(C, process(C, preprocessed)));
},
(_, property) =>
[
property.prototypeOf (Constructor.prototype),
property({ name: "ID", value: ID }),
property({ name: Definition, value:
{
name,
initialize,
hasPositionalFields,
isUnaryConstructor,
fieldDefinitions: IObject
.entries(hasNamedFields ? fields[0] : fields)
} })
]);
}
function process(C, preprocessed)
{
const { hasPositionalFields } = definition(C);
if (!hasPositionalFields && preprocessed.length > 1)
fail (
`Too many arguments passed to ${C.name}.\n` +
`${C.name} is a record constructor and thus expects ` +
`one object argument.`);
const fields = getFields(C);
if (hasPositionalFields && preprocessed.length > fields.length)
fail (
`Too many arguments passed to ${C.name}.\n` +
`${C.name} is a positional constructor that expects no more than` +
`${fields.length} arguments.`);
const flattened =
preprocessed.length <= 0 ?
UseFallbackForEverField :
hasPositionalFields ?
preprocessed :
preprocessed[0];
return IObject
.fromEntries(fields
.map(([name, field]) =>
[name, field.extract(C, name, flattened)]));
}
function getFields(C)
{
return private(C, "fields", () =>
C[Definition].fieldDefinitions
.map(([name, f]) => [name, Field(f())]));
}
function annotate(annotation, T)
{
if (annotation === "?")
return Optional.of(T);
if (annotation === "[]")
return List.of(T);
if (annotation === "=")
return defaultValue => Field({ type: T, defaultValue });
fail (`Unrecognized annotation: ${annotation} on type ${T}`);
}
type.fallback = function fallback(toDefaultValue)
{
return f `fallback` (
(f, ...args) => toDefaultValue(...args),
(_, property) => property.prototypeOf (fallback.prototype));
}
const { isProductBody, Product } = require("./types/product");
const { isSumBody, Sum, caseof } = require("./types/sum");
type.caseof = caseof;
const Field = require("./field");
const forall = require("./types/forall");
const Optional = require("./types/optional");
type.Optional = Optional;
const List = require("./types/list");
type.List = List;
/*
IObject.assign(type,
IObject.fromEntries(
require("./primitives")
.map(([name, has]) =>
type(new TypeDefinition({ name, has })))));
IObject.assign(
type,
IObject.fromEntries(...
["bigint", "boolean", "function", "number", "string", "symbol", "undefined"]
.map(name => [name, primitive])));
*/