alinea
Version:
[](https://npmjs.org/package/alinea) [](https://packagephobia.com/result?p=alinea)
237 lines (235 loc) • 5.93 kB
JavaScript
// node_modules/cito/dist/index.js
var { assign, entries, keys, values, setPrototypeOf } = Object;
var { stringify } = JSON;
var Context = class {
value = void 0;
path = [];
expected = "";
at(name) {
this.path.push(this.path.length > 0 ? `.${name}` : name);
}
index(index) {
this.path.push(`[${index}]`);
}
back() {
this.path.pop();
}
expect(e, v) {
this.expected = e;
this.value = v;
}
err() {
let at = this.path.length ? `@ ${this.path.join("")} ` : "";
return `Expected ${this.expected} ${at}(got: ${stringify(this.value)})`;
}
};
var arg = "v";
var ctx = new Context();
var Type = class {
narrow() {
return this;
}
new(value) {
return value;
}
check(input) {
ctx = new Context();
return this.validate(input, ctx);
}
assert(input) {
if (!this.check(input))
throw new TypeError(ctx.err());
}
and(that) {
return type(
(value) => this.validate(value, ctx) && that.validate(value, ctx),
(path) => `${this.gen(path)} && ${that.gen(path)}`
);
}
or(that) {
return type(
(value) => this.validate(value, ctx) || that.validate(value, ctx),
(path) => `(${this.gen(path)} || ${that.gen(path)})`
);
}
get nullable() {
return nullable(this);
}
get optional() {
return optional(this);
}
};
var noGen = () => {
throw new Error(`This type cannot be generated`);
};
var type = (validate, gen = noGen) => {
const inst = assign(
setPrototypeOf((value) => {
inst.assert(value);
return value;
}, Type.prototype),
{ validate, gen }
);
return inst;
};
var literal = (literal2) => type(
(value) => (ctx.expect(stringify(literal2), value), literal2 === value),
(path) => `${path} === ${stringify(literal2)}`
);
var nullable = (inner) => literal(null).or(inner);
var optional = (inner) => literal(void 0).or(inner);
var primitive = (primitive2) => type(
(value) => (ctx.expect(primitive2, value), typeof value === primitive2),
(path) => `typeof ${path} === '${primitive2}'`
);
var instance = (constructor) => type(
(value, ctx2) => (ctx2.expect(constructor.name, value), value instanceof constructor),
(path) => `${path} instanceof ${constructor.name}`
);
var string = primitive("string");
var number = primitive("number").and(
type(
(value) => !isNaN(value),
(path) => `!isNaN(${path})`
)
);
var bigint = primitive("bigint");
var boolean = primitive("boolean");
var symbol = primitive("symbol");
var any = type(
(value) => true,
() => `!0`
);
var date = instance(Date).and(
type(
(value) => !isNaN(value.getTime()),
(path) => `!isNaN(${path}.getTime())`
)
);
var isFunction = (f) => typeof f === "function";
var isObject = type(
(value) => (ctx.expect("object", value), typeof value === "object" && value != null),
(path) => `typeof ${path} === 'object' && ${path} !== null`
);
var isArray = type(
(value) => (ctx.expect("array", value), Array.isArray(value)),
(path) => `Array.isArray(${path})`
);
var tuple = (...types) => isArray.and(
type(
(value) => {
if (value.length !== types.length)
return false;
for (let i = 0; i < types.length; i++) {
ctx.index(i);
if (!types[i].validate(value[i], ctx))
return false;
ctx.back();
}
return true;
},
(path) => `${path}.length === ${types.length} && ${types.map((type2, i) => type2.gen(`${path}[${i}]`)).join(" && ")}`
)
);
var record = (inner) => isObject.and(
type(
(value) => {
for (let [key, item] of entries(value)) {
ctx.at(key);
if (!inner.validate(item, ctx))
return false;
ctx.back();
}
return true;
},
(path) => `Object.values(${path}).every(${arg} => ${inner.gen(arg)})`
)
);
var object = (definition) => {
let inst = definition;
return isObject.and(
type(
(value) => {
if (isFunction(inst))
inst = new inst();
for (let key in inst) {
ctx.at(key);
if (!inst[key].validate(value[key], ctx))
return false;
ctx.back();
}
return true;
},
(path) => {
if (isFunction(inst))
inst = new inst();
const types = keys(inst).map((key) => [key, inst[key]]);
return types.map(([key, inner]) => inner.gen(`${path}.${key}`)).join(" && ");
}
)
);
};
var union = (...types) => {
let definitions = types.map(
(type2) => type2 instanceof Type ? type2 : object(type2)
);
return type(
(value) => {
let current = ctx.path.length;
let relevancy = 0;
let expectation = void 0;
for (let type2 of definitions) {
ctx.path.splice(current, Infinity);
if (type2.validate(value, ctx))
return true;
if (ctx.path.length >= relevancy) {
relevancy = ctx.path.length;
expectation = [ctx.path.slice(), ctx.expected, ctx.value];
}
}
if (expectation) {
ctx.path = expectation[0];
ctx.expected = expectation[1];
ctx.value = expectation[2];
}
return false;
},
(path) => `(${definitions.map((type2) => `${type2.gen(path)}`).join(" || ")})`
);
};
var array = (inner) => isArray.and(
type(
(value, ctx2) => {
for (let i = 0; i < value.length; i++) {
ctx2.index(i);
if (!inner.validate(value[i], ctx2))
return false;
ctx2.back();
}
return true;
},
(path) => `${path}.every(${arg} => ${inner.gen(arg)})`
)
);
var enums = (types) => {
const options = values(types);
const desc = options.join(" | ");
return type(
(value) => (ctx.expect(desc, value), options.includes(value)),
(path) => `${stringify(options)}.includes(${path})`
);
};
export {
type,
literal,
string,
number,
boolean,
any,
tuple,
record,
object,
union,
array,
enums
};