schemas/libraries/decoders/download_compiled/index/unminified.js
schemas/libraries/decoders/download_compiled/index/unminified.js
schemas/libraries/decoders/download_compiled/index/unminified.js
schemas/libraries/decoders/download_compiled/index/unminified.js
var MAX_ERRORS = 3;
function qty(n, unit) {
return n === 1
? `${n} ${unit}`
: `${n} ${unit}s`;
}
function isNumber(value) {
return typeof value === "number";
}
function isString(value) {
return typeof value === "string";
}
function isDate(value) {
return (
!!value &&
Object.prototype.toString.call(
value,
) === "[object Date]" &&
!isNaN(value)
);
}
function isPromiseLike(value) {
return (
typeof value === "object" &&
value !== null &&
"then" in value &&
typeof value.then === "function"
);
}
function isPlainObject(value) {
return (
value !== null &&
typeof value === "object" &&
Object.prototype.toString.call(
value,
) === "[object Object]"
);
}
function assertNever(
_value,
msg = "Unhandled case",
) {
throw new Error(msg);
}
var kAnnotationRegistry =
Symbol.for(
"decoders.kAnnotationRegistry",
);
var _stamped = (globalThis[
kAnnotationRegistry
] ??= new WeakSet());
function stamp(ann) {
_stamped.add(ann);
return ann;
}
function makeObjectAnn(
getFields,
text,
) {
let fields;
return stamp({
type: "object",
get fields() {
return (fields ??= getFields());
},
text,
});
}
function makeArrayAnn(getItems, text) {
let items;
return stamp({
type: "array",
get items() {
return (items ??= getItems());
},
text,
});
}
function makeOpaqueAnn(value, text) {
return stamp({
type: "opaque",
value,
text,
});
}
function makeScalarAnn(value, text) {
return stamp({
type: "scalar",
value,
text,
});
}
function updateText(annotation, text) {
if (text === void 0)
return annotation;
switch (annotation.type) {
case "object":
return makeObjectAnn(
() => annotation.fields,
text,
);
case "array":
return makeArrayAnn(
() => annotation.items,
text,
);
case "scalar":
return makeScalarAnn(
annotation.value,
text,
);
case "opaque":
return makeOpaqueAnn(
annotation.value,
text,
);
default:
return assertNever(
annotation,
"Unknown annotation type",
);
}
}
function merge(objAnnotation, fields) {
return makeObjectAnn(
() =>
new Map([
...objAnnotation.fields,
...fields,
]),
objAnnotation.text,
);
}
function isAnnotation(thing) {
return _stamped.has(thing);
}
function annotateArray(
arr,
text,
seen,
) {
seen.add(arr);
return makeArrayAnn(
() =>
Array.from(arr, (value) =>
__annotate(value, void 0, seen),
),
text,
);
}
function annotateObject(
obj,
text,
seen,
) {
seen.add(obj);
return makeObjectAnn(() => {
const fields =
new Map();
for (const key of Object.keys(
obj,
)) {
const value = obj[key];
fields.set(
key,
__annotate(value, void 0, seen),
);
}
return fields;
}, text);
}
function __annotate(value, text, seen) {
if (
value === null ||
value === void 0 ||
typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean" ||
typeof value === "symbol" ||
typeof value === "bigint" ||
typeof value.getMonth === "function"
)
return makeScalarAnn(value, text);
if (isAnnotation(value))
return updateText(value, text);
if (Array.isArray(value)) {
if (seen.has(value))
return makeOpaqueAnn(
"<circular ref>",
text,
);
else
return annotateArray(
value,
text,
seen,
);
}
if (
isPlainObject(value)
) {
if (seen.has(value))
return makeOpaqueAnn(
"<circular ref>",
text,
);
else
return annotateObject(
value,
text,
seen,
);
}
if (typeof value === "function")
return makeOpaqueAnn(
"<function>",
text,
);
if (
isPromiseLike(value)
)
return makeOpaqueAnn(
"<Promise>",
text,
);
if (value?.constructor?.name)
return makeOpaqueAnn(
`<${value.constructor.name}>`,
text,
);
else
return makeOpaqueAnn("???", text);
}
function public_annotate(value, text) {
return __annotate(
value,
text,
new WeakSet(),
);
}
function public_annotateObject(
obj,
text,
) {
return annotateObject(
obj,
text,
new WeakSet(),
);
}
var INDENT = " ";
function isMultiline(s) {
return s.includes("\n");
}
function indent(s, prefix = INDENT) {
if ( isMultiline(s))
return s
.split("\n")
.map((line) => `${prefix}${line}`)
.join("\n");
else return `${prefix}${s}`;
}
var quotePattern = /'/g;
function quote(value) {
return typeof value === "string"
? "'" +
value.replace(
quotePattern,
"\\'",
) +
"'"
: value === void 0
? "undefined"
: JSON.stringify(value);
}
function summarize(ann, keypath = []) {
const result = [];
if (ann.type === "array") {
const items = ann.items;
let index = 0;
for (const ann2 of items)
for (const item of summarize(
ann2,
[...keypath, index++],
))
result.push(item);
} else if (ann.type === "object") {
const fields = ann.fields;
for (const [key, value] of fields)
for (const item of summarize(
value,
[...keypath, key],
))
result.push(item);
}
const text = ann.text;
if (!text) return result;
let prefix;
if (keypath.length === 0) prefix = "";
else if (keypath.length === 1)
prefix =
typeof keypath[0] === "number"
? `Value at index ${keypath[0]}: `
: `Value at key ${/* @__PURE__ */ quote(keypath[0])}: `;
else
prefix = `Value at keypath ${/* @__PURE__ */ quote(keypath.map(String).join("."))}: `;
return [
...result,
`${prefix}${text}`,
];
}
function serializeString(
s,
width = 80,
) {
let ser = JSON.stringify(s);
if (ser.length <= width) return ser;
const truncated = `${s.substring(0, width - 15)}...`;
ser = `${JSON.stringify(truncated)} [truncated]`;
return ser;
}
function serializeArray(
annotation,
prefix,
) {
const { items } = annotation;
if (items.length === 0) return "[]";
const result = [];
for (
let i = 0;
i < items.length;
++i
) {
const [ser, ann] =
serializeAnnotation(
items[i],
`${prefix}${INDENT}`,
`(at index ${i})`,
);
result.push(
`${prefix}${INDENT}${ser},`,
);
if (ann !== void 0)
result.push(
indent(
ann,
`${prefix}${INDENT}`,
),
);
}
return [
"[",
...result,
`${prefix}]`,
].join("\n");
}
function serializeObject(
annotation,
prefix,
) {
const { fields } = annotation;
if (fields.size === 0) return "{}";
const result = [];
for (const [
key,
valueAnnotation,
] of fields) {
const kser = serializeValue(key);
const valPrefix = `${prefix}${INDENT}${" ".repeat(kser.length + 2)}`;
const [vser, vann] =
serializeAnnotation(
valueAnnotation,
`${prefix}${INDENT}`,
);
result.push(
`${prefix}${INDENT}${kser}: ${vser},`,
);
if (vann !== void 0)
result.push(
indent(
vann,
valPrefix,
),
);
}
return [
"{",
...result,
`${prefix}}`,
].join("\n");
}
function serializeValue(value) {
if (typeof value === "string")
return serializeString(value);
else if (
typeof value === "number" ||
typeof value === "boolean" ||
typeof value === "symbol"
)
return value.toString();
else if (value === null)
return "null";
else if (value === void 0)
return "undefined";
else if (typeof value === "bigint")
return `${value.toString()}n`;
else if (
isDate(value)
)
return `new Date(${/* @__PURE__ */ quote(value.toISOString())})`;
else if (value instanceof Date)
return "(Invalid Date)";
else return "(unserializable)";
}
function serializeAnnotation(
ann,
prefix = "",
location,
) {
let serialized;
if (ann.type === "array")
serialized = serializeArray(
ann,
prefix,
);
else if (ann.type === "object")
serialized = serializeObject(
ann,
prefix,
);
else if (ann.type === "scalar")
serialized = serializeValue(
ann.value,
);
else serialized = ann.value;
const text = ann.text;
if (text !== void 0) {
const sep = "^".repeat(
isMultiline(
serialized,
)
? 1
: serialized.length,
);
const annotation =
isMultiline(text)
? [
location
? `${sep} ${location}`
: sep,
text,
].join("\n")
: [sep, text, location]
.filter(Boolean)
.join(" ");
return [serialized, annotation];
} else return [serialized, void 0];
}
function formatInline(ann) {
const [serialized, annotation] =
serializeAnnotation(ann);
if (annotation !== void 0)
return `${serialized}
${annotation}`;
else return serialized;
}
function* iterAnnotation(ann, stack) {
if (ann.text) {
if (stack.length > 0)
yield {
message: ann.text,
path: [...stack],
};
else yield { message: ann.text };
}
switch (ann.type) {
case "array": {
let index = 0;
for (const item of ann.items) {
stack.push(index++);
yield* iterAnnotation(
item,
stack,
);
stack.pop();
}
break;
}
case "object":
for (const [
key,
value,
] of ann.fields) {
stack.push(key);
yield* iterAnnotation(
value,
stack,
);
stack.pop();
}
break;
case "scalar":
case "opaque":
break;
default:
assertNever(
ann,
"Unknown annotation type",
);
}
}
function formatAsIssues(ann) {
return Array.from(
iterAnnotation(ann, []),
);
}
function ok(value) {
return {
ok: true,
value,
error: void 0,
};
}
function err(error) {
return {
ok: false,
value: void 0,
error,
};
}
function noThrow(fn) {
return (t) => {
try {
return ok(fn(t));
} catch (e) {
return err(
public_annotate(
t,
e instanceof Error
? e.message
: String(e),
),
);
}
};
}
function format(err2, formatter) {
const formatted = formatter(err2);
if (typeof formatted === "string") {
const err3 =
new Error(`
${formatted}`);
err3.name = "Decoding error";
return err3;
} else return formatted;
}
var DecoderImpl = class {
decode;
verify;
value;
#standard;
constructor(fn) {
const decode = (blob) => {
const makeFlexErr = (msg) =>
err(
isAnnotation(msg)
? msg
: public_annotate(
blob,
msg,
),
);
return fn(blob, ok, makeFlexErr);
};
const verify = (
blob,
formatter = formatInline,
) => {
const result = decode(blob);
if (result.ok)
return result.value;
else
throw format(
result.error,
formatter,
);
};
const value = (blob) =>
decode(blob).value;
this.decode = decode;
this.verify = verify;
this.value = value;
}
transform(transformFn) {
return this.chain(
noThrow(transformFn),
);
}
refine(predicateFn, errmsg) {
return this.reject((value) =>
predicateFn(value)
? null
: errmsg,
);
}
refineType() {
return this;
}
chain(next) {
const decode = this.decode;
return define(
(blob, ok2, err2) => {
const r1 = decode(blob);
if (!r1.ok) return r1;
const r2 =
isDecoder(
next,
)
? next
: next(r1.value, ok2, err2);
return isDecoder(
r2,
)
? r2.decode(r1.value)
: r2;
},
);
}
pipe(next) {
return this.chain(next);
}
reject(rejectFn) {
return this.chain(
(blob, ok2, err2) => {
const errmsg = rejectFn(blob);
return errmsg === null
? ok2(blob)
: err2(
typeof errmsg === "string"
? public_annotate(
blob,
errmsg,
)
: errmsg,
);
},
);
}
describe(message) {
const decode = this.decode;
return define(
(blob, _, err2) => {
const result = decode(blob);
if (result.ok) return result;
else
return err2(
public_annotate(
result.error,
message,
),
);
},
);
}
get "~standard"() {
const decode = this.decode;
return (this.#standard ??= {
version: 1,
vendor: "decoders",
validate: (blob) => {
const result = decode(blob);
if (result.ok)
return {
value: result.value,
};
else
return {
issues: formatAsIssues(
result.error,
),
};
},
});
}
};
Object.defineProperty(
DecoderImpl,
"name",
{ value: "Decoder" },
);
function define(fn) {
return stamp2(new DecoderImpl(fn));
}
var kDecoderRegistry =
Symbol.for(
"decoders.kDecoderRegistry",
);
var _stamped2 = (globalThis[
kDecoderRegistry
] ??= new WeakSet());
function stamp2(decoder) {
_stamped2.add(decoder);
return decoder;
}
function isDecoder(value) {
return _stamped2.has(value);
}
function bySizeOptions(options) {
const size = options.size;
const min2 = size ?? options.min;
const max2 = size ?? options.max;
const atLeast =
min2 === max2 ? "" : "at least ";
const atMost =
min2 === max2 ? "" : "at most ";
return (value) => {
const len =
value.length ?? value.size;
if (typeof value === "string") {
if (min2 !== void 0 && len < min2)
return `Too short, must be ${atLeast}${/* @__PURE__ */ qty(min2, "char")}`;
if (max2 !== void 0 && len > max2)
return `Too long, must be ${atMost}${/* @__PURE__ */ qty(max2, "char")}`;
} else {
if (min2 !== void 0 && len < min2)
return `Must have ${atLeast}${/* @__PURE__ */ qty(min2, "item")}`;
if (max2 !== void 0 && len > max2)
return `Must have ${atMost}${/* @__PURE__ */ qty(max2, "item")}`;
}
return null;
};
}
function sized(decoder, options) {
return decoder.reject(
bySizeOptions(
options,
),
);
}
var poja = define(
(blob, ok2, err2) => {
if (!Array.isArray(blob))
return err2("Must be an array");
return ok2(blob);
},
);
function array(decoder, options) {
const decodeFn = decoder.decode;
return (
options !== void 0
? sized(
poja,
options,
)
: poja
).chain((inputs, ok2, err2) => {
const results = [];
let clone = null;
let errorCount = 0;
for (
let i = 0;
i < inputs.length;
++i
) {
const blob = inputs[i];
const result = decodeFn(blob);
if (result.ok) {
if (clone === null)
results.push(result.value);
} else {
results.length = 0;
clone ??= inputs.slice();
clone[i] = result.error;
if (++errorCount >= MAX_ERRORS)
break;
}
}
return clone !== null
? err2(public_annotate(clone))
: ok2(results);
});
}
var pojo = define(
(blob, ok2, err2) =>
isPlainObject(blob)
? ok2(blob)
: err2("Must be an object"),
);
function buildObject(decoders) {
const knownKeys =
Object.keys(decoders);
return pojo.chain(
(plainObj, ok2, err2) => {
const record2 = {};
let errors = null;
let missingKeys = null;
for (const key of knownKeys) {
const decoder = decoders[key];
const rawValue = plainObj[key];
const result =
decoder.decode(rawValue);
if (result.ok) {
const value = result.value;
if (value !== void 0)
record2[key] = value;
} else {
const ann = result.error;
if (rawValue === void 0)
(missingKeys ??= []).push(
key,
);
else
(errors ??=
new Map()).set(
key,
ann,
);
}
}
if (errors || missingKeys) {
let objAnn =
public_annotateObject(
plainObj,
);
if (errors)
objAnn = merge(
objAnn,
errors,
);
if (missingKeys) {
const errMsg = missingKeys
.map(quote)
.join(", ");
const pluralized =
missingKeys.length > 1
? "keys"
: "key";
objAnn = updateText(
objAnn,
`Missing ${pluralized}: ${errMsg}`,
);
}
return err2(objAnn);
}
return ok2(record2);
},
);
}
function object(decoders) {
return buildObject(
decoders,
);
}
var EITHER_PREFIX = "Either:\n";
function itemize(s) {
return `-${/* @__PURE__ */ indent(s).substring(1)}`;
}
function nest(errText) {
return errText.startsWith(
EITHER_PREFIX,
)
? errText.substring(
EITHER_PREFIX.length,
)
: itemize(errText);
}
function either(...decoders) {
if (decoders.length === 0)
throw new Error(
"Pass at least one decoder to either()",
);
return define(
(blob, _, err2) => {
const errors = [];
for (const decoder of decoders) {
const result =
decoder.decode(blob);
if (result.ok) return result;
else errors.push(result.error);
}
return err2(
EITHER_PREFIX +
errors
.map((err3) =>
nest(
summarize(
err3,
).join("\n"),
),
)
.join("\n"),
);
},
);
}
function oneOf(constants) {
return define(
(blob, ok2, err2) => {
const index =
constants.indexOf(blob);
if (index !== -1)
return ok2(constants[index]);
return err2(
`Must be one of ${constants.map((value) => quote(value)).join(", ")}`,
);
},
);
}
function lazyval(value) {
return typeof value === "function"
? value()
: value;
}
var null_ =
constant(null);
function nullable(
decoder,
defaultValue,
) {
const rv = either(
null_,
decoder,
);
return arguments.length >= 2
? rv.transform(
(value) =>
value ??
lazyval(defaultValue),
)
: rv;
}
function constant(value) {
return define(
(blob, ok2, err2) =>
blob === value
? ok2(value)
: err2(
`Must be ${typeof value === "symbol" ? String(value) : quote(value)}`,
),
);
}
var url_re =
/^[A-Za-z]{2,12}(?:[+][A-Za-z]{2,12})?:\/\/(?:[^@]*@)?[A-Za-z0-9.-]+(?::[0-9]{2,5})?(?:\/[-+~%/.,!$&'()*:;=@\w]*(?:\?[-+~%/.,!$&'()*:;=@?\w]*)?)?(?:#[^\s#]*)?$/;
var string = define(
(blob, ok2, err2) =>
isString(blob)
? ok2(blob)
: err2("Must be string"),
);
function regex(regex2, msg) {
return string.refine(
(s) => regex2.test(s),
msg,
);
}
var urlString = regex(
url_re,
"Must be URL",
);
var date = define(
(blob, ok2, err2) => {
return isDate(blob)
? ok2(blob)
: err2("Must be a Date");
},
);
var number =
define(
(blob, ok2, err2) =>
isNumber(blob)
? ok2(blob)
: err2("Must be number"),
).refine(
(n) => Number.isFinite(n),
"Number must be finite",
);
function between(
min2,
max2,
decoder = number,
) {
return decoder.reject((value) =>
value < min2
? `Too low, must be between ${min2} and ${max2}`
: value > max2
? `Too high, must be between ${min2} and ${max2}`
: null,
);
}
const imageDecoder =
object({
id: number,
created: date,
title: sized(
string,
{
min: 1,
max: 100,
},
),
type: oneOf([
"jpg",
"png",
]),
size: number,
url: urlString,
});
object({
id: number,
created: date,
title: sized(string, {
min: 1,
max: 100,
}),
brand: sized(string, {
min: 1,
max: 30,
}),
description: sized(
string,
{
min: 1,
max: 500,
},
),
price: between(
1,
1e4,
),
discount: nullable(
between(1, 100),
),
quantity: between(
0,
10,
),
tags: array(
sized(string, {
min: 1,
max: 30,
}),
),
images: array(
imageDecoder,
),
ratings: array(
object({
id: number,
stars: between(
1,
5,
),
title: sized(
string,
{
min: 1,
max: 100,
},
),
text: sized(
string,
{
min: 1,
max: 1e3,
},
),
images: array(
imageDecoder,
),
}),
),
}).verify({});
var MAX_ERRORS = 3;
function qty(n, unit) {
return n === 1 ? `${n} ${unit}` : `${n} ${unit}s`;
}
function isNumber(value) {
return typeof value === "number";
}
function isString(value) {
return typeof value === "string";
}
function isDate(value) {
return (
!!value &&
Object.prototype.toString.call(value) ===
"[object Date]" &&
!isNaN(value)
);
}
function isPromiseLike(value) {
return (
typeof value === "object" &&
value !== null &&
"then" in value &&
typeof value.then === "function"
);
}
function isPlainObject(value) {
return (
value !== null &&
typeof value === "object" &&
Object.prototype.toString.call(value) ===
"[object Object]"
);
}
function assertNever(_value, msg = "Unhandled case") {
throw new Error(msg);
}
var kAnnotationRegistry = Symbol.for(
"decoders.kAnnotationRegistry",
);
var _stamped = (globalThis[kAnnotationRegistry] ??=
new WeakSet());
function stamp(ann) {
_stamped.add(ann);
return ann;
}
function makeObjectAnn(getFields, text) {
let fields;
return stamp({
type: "object",
get fields() {
return (fields ??= getFields());
},
text,
});
}
function makeArrayAnn(getItems, text) {
let items;
return stamp({
type: "array",
get items() {
return (items ??= getItems());
},
text,
});
}
function makeOpaqueAnn(value, text) {
return stamp({
type: "opaque",
value,
text,
});
}
function makeScalarAnn(value, text) {
return stamp({
type: "scalar",
value,
text,
});
}
function updateText(annotation, text) {
if (text === void 0) return annotation;
switch (annotation.type) {
case "object":
return makeObjectAnn(() => annotation.fields, text);
case "array":
return makeArrayAnn(() => annotation.items, text);
case "scalar":
return makeScalarAnn(annotation.value, text);
case "opaque":
return makeOpaqueAnn(annotation.value, text);
default:
return assertNever(
annotation,
"Unknown annotation type",
);
}
}
function merge(objAnnotation, fields) {
return makeObjectAnn(
() => new Map([...objAnnotation.fields, ...fields]),
objAnnotation.text,
);
}
function isAnnotation(thing) {
return _stamped.has(thing);
}
function annotateArray(arr, text, seen) {
seen.add(arr);
return makeArrayAnn(
() =>
Array.from(arr, (value) =>
__annotate(value, void 0, seen),
),
text,
);
}
function annotateObject(obj, text, seen) {
seen.add(obj);
return makeObjectAnn(() => {
const fields = new Map();
for (const key of Object.keys(obj)) {
const value = obj[key];
fields.set(key, __annotate(value, void 0, seen));
}
return fields;
}, text);
}
function __annotate(value, text, seen) {
if (
value === null ||
value === void 0 ||
typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean" ||
typeof value === "symbol" ||
typeof value === "bigint" ||
typeof value.getMonth === "function"
)
return makeScalarAnn(value, text);
if (isAnnotation(value)) return updateText(value, text);
if (Array.isArray(value)) {
if (seen.has(value))
return makeOpaqueAnn("<circular ref>", text);
else return annotateArray(value, text, seen);
}
if ( isPlainObject(value)) {
if (seen.has(value))
return makeOpaqueAnn("<circular ref>", text);
else return annotateObject(value, text, seen);
}
if (typeof value === "function")
return makeOpaqueAnn("<function>", text);
if ( isPromiseLike(value))
return makeOpaqueAnn("<Promise>", text);
if (value?.constructor?.name)
return makeOpaqueAnn(
`<${value.constructor.name}>`,
text,
);
else return makeOpaqueAnn("???", text);
}
function public_annotate(value, text) {
return __annotate(
value,
text,
new WeakSet(),
);
}
function public_annotateObject(obj, text) {
return annotateObject(
obj,
text,
new WeakSet(),
);
}
var INDENT = " ";
function isMultiline(s) {
return s.includes("\n");
}
function indent(s, prefix = INDENT) {
if ( isMultiline(s))
return s
.split("\n")
.map((line) => `${prefix}${line}`)
.join("\n");
else return `${prefix}${s}`;
}
var quotePattern = /'/g;
function quote(value) {
return typeof value === "string"
? "'" + value.replace(quotePattern, "\\'") + "'"
: value === void 0
? "undefined"
: JSON.stringify(value);
}
function summarize(ann, keypath = []) {
const result = [];
if (ann.type === "array") {
const items = ann.items;
let index = 0;
for (const ann2 of items)
for (const item of summarize(ann2, [
...keypath,
index++,
]))
result.push(item);
} else if (ann.type === "object") {
const fields = ann.fields;
for (const [key, value] of fields)
for (const item of summarize(value, [
...keypath,
key,
]))
result.push(item);
}
const text = ann.text;
if (!text) return result;
let prefix;
if (keypath.length === 0) prefix = "";
else if (keypath.length === 1)
prefix =
typeof keypath[0] === "number"
? `Value at index ${keypath[0]}: `
: `Value at key ${/* @__PURE__ */ quote(keypath[0])}: `;
else
prefix = `Value at keypath ${/* @__PURE__ */ quote(keypath.map(String).join("."))}: `;
return [...result, `${prefix}${text}`];
}
function serializeString(s, width = 80) {
let ser = JSON.stringify(s);
if (ser.length <= width) return ser;
const truncated = `${s.substring(0, width - 15)}...`;
ser = `${JSON.stringify(truncated)} [truncated]`;
return ser;
}
function serializeArray(annotation, prefix) {
const { items } = annotation;
if (items.length === 0) return "[]";
const result = [];
for (let i = 0; i < items.length; ++i) {
const [ser, ann] = serializeAnnotation(
items[i],
`${prefix}${INDENT}`,
`(at index ${i})`,
);
result.push(`${prefix}${INDENT}${ser},`);
if (ann !== void 0)
result.push(
indent(ann, `${prefix}${INDENT}`),
);
}
return ["[", ...result, `${prefix}]`].join("\n");
}
function serializeObject(annotation, prefix) {
const { fields } = annotation;
if (fields.size === 0) return "{}";
const result = [];
for (const [key, valueAnnotation] of fields) {
const kser = serializeValue(key);
const valPrefix = `${prefix}${INDENT}${" ".repeat(kser.length + 2)}`;
const [vser, vann] = serializeAnnotation(
valueAnnotation,
`${prefix}${INDENT}`,
);
result.push(`${prefix}${INDENT}${kser}: ${vser},`);
if (vann !== void 0)
result.push( indent(vann, valPrefix));
}
return ["{", ...result, `${prefix}}`].join("\n");
}
function serializeValue(value) {
if (typeof value === "string")
return serializeString(value);
else if (
typeof value === "number" ||
typeof value === "boolean" ||
typeof value === "symbol"
)
return value.toString();
else if (value === null) return "null";
else if (value === void 0) return "undefined";
else if (typeof value === "bigint")
return `${value.toString()}n`;
else if ( isDate(value))
return `new Date(${/* @__PURE__ */ quote(value.toISOString())})`;
else if (value instanceof Date) return "(Invalid Date)";
else return "(unserializable)";
}
function serializeAnnotation(ann, prefix = "", location) {
let serialized;
if (ann.type === "array")
serialized = serializeArray(ann, prefix);
else if (ann.type === "object")
serialized = serializeObject(ann, prefix);
else if (ann.type === "scalar")
serialized = serializeValue(ann.value);
else serialized = ann.value;
const text = ann.text;
if (text !== void 0) {
const sep = "^".repeat(
isMultiline(serialized)
? 1
: serialized.length,
);
const annotation = isMultiline(text)
? [location ? `${sep} ${location}` : sep, text].join(
"\n",
)
: [sep, text, location].filter(Boolean).join(" ");
return [serialized, annotation];
} else return [serialized, void 0];
}
function formatInline(ann) {
const [serialized, annotation] = serializeAnnotation(ann);
if (annotation !== void 0)
return `${serialized}
${annotation}`;
else return serialized;
}
function* iterAnnotation(ann, stack) {
if (ann.text) {
if (stack.length > 0)
yield {
message: ann.text,
path: [...stack],
};
else yield { message: ann.text };
}
switch (ann.type) {
case "array": {
let index = 0;
for (const item of ann.items) {
stack.push(index++);
yield* iterAnnotation(item, stack);
stack.pop();
}
break;
}
case "object":
for (const [key, value] of ann.fields) {
stack.push(key);
yield* iterAnnotation(value, stack);
stack.pop();
}
break;
case "scalar":
case "opaque":
break;
default:
assertNever(ann, "Unknown annotation type");
}
}
function formatAsIssues(ann) {
return Array.from(iterAnnotation(ann, []));
}
function ok(value) {
return {
ok: true,
value,
error: void 0,
};
}
function err(error) {
return {
ok: false,
value: void 0,
error,
};
}
function noThrow(fn) {
return (t) => {
try {
return ok(fn(t));
} catch (e) {
return err(
public_annotate(
t,
e instanceof Error ? e.message : String(e),
),
);
}
};
}
function format(err2, formatter) {
const formatted = formatter(err2);
if (typeof formatted === "string") {
const err3 = new Error(`
${formatted}`);
err3.name = "Decoding error";
return err3;
} else return formatted;
}
var DecoderImpl = class {
decode;
verify;
value;
#standard;
constructor(fn) {
const decode = (blob) => {
const makeFlexErr = (msg) =>
err(
isAnnotation(msg)
? msg
: public_annotate(blob, msg),
);
return fn(blob, ok, makeFlexErr);
};
const verify = (blob, formatter = formatInline) => {
const result = decode(blob);
if (result.ok) return result.value;
else throw format(result.error, formatter);
};
const value = (blob) => decode(blob).value;
this.decode = decode;
this.verify = verify;
this.value = value;
}
transform(transformFn) {
return this.chain(noThrow(transformFn));
}
refine(predicateFn, errmsg) {
return this.reject((value) =>
predicateFn(value) ? null : errmsg,
);
}
refineType() {
return this;
}
chain(next) {
const decode = this.decode;
return define((blob, ok2, err2) => {
const r1 = decode(blob);
if (!r1.ok) return r1;
const r2 = isDecoder(next)
? next
: next(r1.value, ok2, err2);
return isDecoder(r2)
? r2.decode(r1.value)
: r2;
});
}
pipe(next) {
return this.chain(next);
}
reject(rejectFn) {
return this.chain((blob, ok2, err2) => {
const errmsg = rejectFn(blob);
return errmsg === null
? ok2(blob)
: err2(
typeof errmsg === "string"
? public_annotate(blob, errmsg)
: errmsg,
);
});
}
describe(message) {
const decode = this.decode;
return define((blob, _, err2) => {
const result = decode(blob);
if (result.ok) return result;
else
return err2(public_annotate(result.error, message));
});
}
get "~standard"() {
const decode = this.decode;
return (this.#standard ??= {
version: 1,
vendor: "decoders",
validate: (blob) => {
const result = decode(blob);
if (result.ok) return { value: result.value };
else
return { issues: formatAsIssues(result.error) };
},
});
}
};
Object.defineProperty(DecoderImpl, "name", {
value: "Decoder",
});
function define(fn) {
return stamp2(new DecoderImpl(fn));
}
var kDecoderRegistry = Symbol.for(
"decoders.kDecoderRegistry",
);
var _stamped2 = (globalThis[kDecoderRegistry] ??=
new WeakSet());
function stamp2(decoder) {
_stamped2.add(decoder);
return decoder;
}
function isDecoder(value) {
return _stamped2.has(value);
}
function bySizeOptions(options) {
const size = options.size;
const min2 = size ?? options.min;
const max2 = size ?? options.max;
const atLeast = min2 === max2 ? "" : "at least ";
const atMost = min2 === max2 ? "" : "at most ";
return (value) => {
const len = value.length ?? value.size;
if (typeof value === "string") {
if (min2 !== void 0 && len < min2)
return `Too short, must be ${atLeast}${/* @__PURE__ */ qty(min2, "char")}`;
if (max2 !== void 0 && len > max2)
return `Too long, must be ${atMost}${/* @__PURE__ */ qty(max2, "char")}`;
} else {
if (min2 !== void 0 && len < min2)
return `Must have ${atLeast}${/* @__PURE__ */ qty(min2, "item")}`;
if (max2 !== void 0 && len > max2)
return `Must have ${atMost}${/* @__PURE__ */ qty(max2, "item")}`;
}
return null;
};
}
function sized(decoder, options) {
return decoder.reject(
bySizeOptions(options),
);
}
var poja = define((blob, ok2, err2) => {
if (!Array.isArray(blob)) return err2("Must be an array");
return ok2(blob);
});
function array(decoder, options) {
const decodeFn = decoder.decode;
return (
options !== void 0
? sized(poja, options)
: poja
).chain((inputs, ok2, err2) => {
const results = [];
let clone = null;
let errorCount = 0;
for (let i = 0; i < inputs.length; ++i) {
const blob = inputs[i];
const result = decodeFn(blob);
if (result.ok) {
if (clone === null) results.push(result.value);
} else {
results.length = 0;
clone ??= inputs.slice();
clone[i] = result.error;
if (++errorCount >= MAX_ERRORS) break;
}
}
return clone !== null
? err2(public_annotate(clone))
: ok2(results);
});
}
var pojo = define((blob, ok2, err2) =>
isPlainObject(blob)
? ok2(blob)
: err2("Must be an object"),
);
function buildObject(decoders) {
const knownKeys = Object.keys(decoders);
return pojo.chain((plainObj, ok2, err2) => {
const record2 = {};
let errors = null;
let missingKeys = null;
for (const key of knownKeys) {
const decoder = decoders[key];
const rawValue = plainObj[key];
const result = decoder.decode(rawValue);
if (result.ok) {
const value = result.value;
if (value !== void 0) record2[key] = value;
} else {
const ann = result.error;
if (rawValue === void 0)
(missingKeys ??= []).push(key);
else
(errors ??= new Map()).set(
key,
ann,
);
}
}
if (errors || missingKeys) {
let objAnn = public_annotateObject(plainObj);
if (errors) objAnn = merge(objAnn, errors);
if (missingKeys) {
const errMsg = missingKeys.map(quote).join(", ");
const pluralized =
missingKeys.length > 1 ? "keys" : "key";
objAnn = updateText(
objAnn,
`Missing ${pluralized}: ${errMsg}`,
);
}
return err2(objAnn);
}
return ok2(record2);
});
}
function object(decoders) {
return buildObject(decoders);
}
var EITHER_PREFIX = "Either:\n";
function itemize(s) {
return `-${/* @__PURE__ */ indent(s).substring(1)}`;
}
function nest(errText) {
return errText.startsWith(EITHER_PREFIX)
? errText.substring(EITHER_PREFIX.length)
: itemize(errText);
}
function either(...decoders) {
if (decoders.length === 0)
throw new Error(
"Pass at least one decoder to either()",
);
return define((blob, _, err2) => {
const errors = [];
for (const decoder of decoders) {
const result = decoder.decode(blob);
if (result.ok) return result;
else errors.push(result.error);
}
return err2(
EITHER_PREFIX +
errors
.map((err3) =>
nest(
summarize(err3).join("\n"),
),
)
.join("\n"),
);
});
}
function oneOf(constants) {
return define((blob, ok2, err2) => {
const index = constants.indexOf(blob);
if (index !== -1) return ok2(constants[index]);
return err2(
`Must be one of ${constants.map((value) => quote(value)).join(", ")}`,
);
});
}
function lazyval(value) {
return typeof value === "function" ? value() : value;
}
var null_ = constant(null);
function nullable(decoder, defaultValue) {
const rv = either(null_, decoder);
return arguments.length >= 2
? rv.transform(
(value) => value ?? lazyval(defaultValue),
)
: rv;
}
function constant(value) {
return define((blob, ok2, err2) =>
blob === value
? ok2(value)
: err2(
`Must be ${typeof value === "symbol" ? String(value) : quote(value)}`,
),
);
}
var url_re =
/^[A-Za-z]{2,12}(?:[+][A-Za-z]{2,12})?:\/\/(?:[^@]*@)?[A-Za-z0-9.-]+(?::[0-9]{2,5})?(?:\/[-+~%/.,!$&'()*:;=@\w]*(?:\?[-+~%/.,!$&'()*:;=@?\w]*)?)?(?:#[^\s#]*)?$/;
var string = define((blob, ok2, err2) =>
isString(blob)
? ok2(blob)
: err2("Must be string"),
);
function regex(regex2, msg) {
return string.refine((s) => regex2.test(s), msg);
}
var urlString = regex(
url_re,
"Must be URL",
);
var date = define((blob, ok2, err2) => {
return isDate(blob)
? ok2(blob)
: err2("Must be a Date");
});
var number = define(
(blob, ok2, err2) =>
isNumber(blob)
? ok2(blob)
: err2("Must be number"),
).refine(
(n) => Number.isFinite(n),
"Number must be finite",
);
function between(min2, max2, decoder = number) {
return decoder.reject((value) =>
value < min2
? `Too low, must be between ${min2} and ${max2}`
: value > max2
? `Too high, must be between ${min2} and ${max2}`
: null,
);
}
const imageDecoder = object({
id: number,
created: date,
title: sized(string, {
min: 1,
max: 100,
}),
type: oneOf(["jpg", "png"]),
size: number,
url: urlString,
});
object({
id: number,
created: date,
title: sized(string, {
min: 1,
max: 100,
}),
brand: sized(string, {
min: 1,
max: 30,
}),
description: sized(string, {
min: 1,
max: 500,
}),
price: between(1, 1e4),
discount: nullable(
between(1, 100),
),
quantity: between(0, 10),
tags: array(
sized(string, {
min: 1,
max: 30,
}),
),
images: array(imageDecoder),
ratings: array(
object({
id: number,
stars: between(1, 5),
title: sized(string, {
min: 1,
max: 100,
}),
text: sized(string, {
min: 1,
max: 1e3,
}),
images: array(imageDecoder),
}),
),
}).verify({});
var MAX_ERRORS = 3;
function qty(n, unit) {
return n === 1 ? `${n} ${unit}` : `${n} ${unit}s`;
}
function isNumber(value) {
return typeof value === "number";
}
function isString(value) {
return typeof value === "string";
}
function isDate(value) {
return (
!!value &&
Object.prototype.toString.call(value) === "[object Date]" &&
!isNaN(value)
);
}
function isPromiseLike(value) {
return (
typeof value === "object" &&
value !== null &&
"then" in value &&
typeof value.then === "function"
);
}
function isPlainObject(value) {
return (
value !== null &&
typeof value === "object" &&
Object.prototype.toString.call(value) === "[object Object]"
);
}
function assertNever(_value, msg = "Unhandled case") {
throw new Error(msg);
}
var kAnnotationRegistry = Symbol.for(
"decoders.kAnnotationRegistry",
);
var _stamped = (globalThis[kAnnotationRegistry] ??=
new WeakSet());
function stamp(ann) {
_stamped.add(ann);
return ann;
}
function makeObjectAnn(getFields, text) {
let fields;
return stamp({
type: "object",
get fields() {
return (fields ??= getFields());
},
text,
});
}
function makeArrayAnn(getItems, text) {
let items;
return stamp({
type: "array",
get items() {
return (items ??= getItems());
},
text,
});
}
function makeOpaqueAnn(value, text) {
return stamp({
type: "opaque",
value,
text,
});
}
function makeScalarAnn(value, text) {
return stamp({
type: "scalar",
value,
text,
});
}
function updateText(annotation, text) {
if (text === void 0) return annotation;
switch (annotation.type) {
case "object":
return makeObjectAnn(() => annotation.fields, text);
case "array":
return makeArrayAnn(() => annotation.items, text);
case "scalar":
return makeScalarAnn(annotation.value, text);
case "opaque":
return makeOpaqueAnn(annotation.value, text);
default:
return assertNever(annotation, "Unknown annotation type");
}
}
function merge(objAnnotation, fields) {
return makeObjectAnn(
() => new Map([...objAnnotation.fields, ...fields]),
objAnnotation.text,
);
}
function isAnnotation(thing) {
return _stamped.has(thing);
}
function annotateArray(arr, text, seen) {
seen.add(arr);
return makeArrayAnn(
() => Array.from(arr, (value) => __annotate(value, void 0, seen)),
text,
);
}
function annotateObject(obj, text, seen) {
seen.add(obj);
return makeObjectAnn(() => {
const fields = new Map();
for (const key of Object.keys(obj)) {
const value = obj[key];
fields.set(key, __annotate(value, void 0, seen));
}
return fields;
}, text);
}
function __annotate(value, text, seen) {
if (
value === null ||
value === void 0 ||
typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean" ||
typeof value === "symbol" ||
typeof value === "bigint" ||
typeof value.getMonth === "function"
)
return makeScalarAnn(value, text);
if (isAnnotation(value)) return updateText(value, text);
if (Array.isArray(value)) {
if (seen.has(value)) return makeOpaqueAnn("<circular ref>", text);
else return annotateArray(value, text, seen);
}
if ( isPlainObject(value)) {
if (seen.has(value)) return makeOpaqueAnn("<circular ref>", text);
else return annotateObject(value, text, seen);
}
if (typeof value === "function") return makeOpaqueAnn("<function>", text);
if ( isPromiseLike(value))
return makeOpaqueAnn("<Promise>", text);
if (value?.constructor?.name)
return makeOpaqueAnn(`<${value.constructor.name}>`, text);
else return makeOpaqueAnn("???", text);
}
function public_annotate(value, text) {
return __annotate(value, text, new WeakSet());
}
function public_annotateObject(obj, text) {
return annotateObject(obj, text, new WeakSet());
}
var INDENT = " ";
function isMultiline(s) {
return s.includes("\n");
}
function indent(s, prefix = INDENT) {
if ( isMultiline(s))
return s
.split("\n")
.map((line) => `${prefix}${line}`)
.join("\n");
else return `${prefix}${s}`;
}
var quotePattern = /'/g;
function quote(value) {
return typeof value === "string"
? "'" + value.replace(quotePattern, "\\'") + "'"
: value === void 0
? "undefined"
: JSON.stringify(value);
}
function summarize(ann, keypath = []) {
const result = [];
if (ann.type === "array") {
const items = ann.items;
let index = 0;
for (const ann2 of items)
for (const item of summarize(ann2, [...keypath, index++]))
result.push(item);
} else if (ann.type === "object") {
const fields = ann.fields;
for (const [key, value] of fields)
for (const item of summarize(value, [...keypath, key]))
result.push(item);
}
const text = ann.text;
if (!text) return result;
let prefix;
if (keypath.length === 0) prefix = "";
else if (keypath.length === 1)
prefix =
typeof keypath[0] === "number"
? `Value at index ${keypath[0]}: `
: `Value at key ${/* @__PURE__ */ quote(keypath[0])}: `;
else
prefix = `Value at keypath ${/* @__PURE__ */ quote(keypath.map(String).join("."))}: `;
return [...result, `${prefix}${text}`];
}
function serializeString(s, width = 80) {
let ser = JSON.stringify(s);
if (ser.length <= width) return ser;
const truncated = `${s.substring(0, width - 15)}...`;
ser = `${JSON.stringify(truncated)} [truncated]`;
return ser;
}
function serializeArray(annotation, prefix) {
const { items } = annotation;
if (items.length === 0) return "[]";
const result = [];
for (let i = 0; i < items.length; ++i) {
const [ser, ann] = serializeAnnotation(
items[i],
`${prefix}${INDENT}`,
`(at index ${i})`,
);
result.push(`${prefix}${INDENT}${ser},`);
if (ann !== void 0)
result.push( indent(ann, `${prefix}${INDENT}`));
}
return ["[", ...result, `${prefix}]`].join("\n");
}
function serializeObject(annotation, prefix) {
const { fields } = annotation;
if (fields.size === 0) return "{}";
const result = [];
for (const [key, valueAnnotation] of fields) {
const kser = serializeValue(key);
const valPrefix = `${prefix}${INDENT}${" ".repeat(kser.length + 2)}`;
const [vser, vann] = serializeAnnotation(
valueAnnotation,
`${prefix}${INDENT}`,
);
result.push(`${prefix}${INDENT}${kser}: ${vser},`);
if (vann !== void 0) result.push( indent(vann, valPrefix));
}
return ["{", ...result, `${prefix}}`].join("\n");
}
function serializeValue(value) {
if (typeof value === "string") return serializeString(value);
else if (
typeof value === "number" ||
typeof value === "boolean" ||
typeof value === "symbol"
)
return value.toString();
else if (value === null) return "null";
else if (value === void 0) return "undefined";
else if (typeof value === "bigint") return `${value.toString()}n`;
else if ( isDate(value))
return `new Date(${/* @__PURE__ */ quote(value.toISOString())})`;
else if (value instanceof Date) return "(Invalid Date)";
else return "(unserializable)";
}
function serializeAnnotation(ann, prefix = "", location) {
let serialized;
if (ann.type === "array") serialized = serializeArray(ann, prefix);
else if (ann.type === "object") serialized = serializeObject(ann, prefix);
else if (ann.type === "scalar") serialized = serializeValue(ann.value);
else serialized = ann.value;
const text = ann.text;
if (text !== void 0) {
const sep = "^".repeat(
isMultiline(serialized) ? 1 : serialized.length,
);
const annotation = isMultiline(text)
? [location ? `${sep} ${location}` : sep, text].join("\n")
: [sep, text, location].filter(Boolean).join(" ");
return [serialized, annotation];
} else return [serialized, void 0];
}
function formatInline(ann) {
const [serialized, annotation] = serializeAnnotation(ann);
if (annotation !== void 0)
return `${serialized}
${annotation}`;
else return serialized;
}
function* iterAnnotation(ann, stack) {
if (ann.text) {
if (stack.length > 0)
yield {
message: ann.text,
path: [...stack],
};
else yield { message: ann.text };
}
switch (ann.type) {
case "array": {
let index = 0;
for (const item of ann.items) {
stack.push(index++);
yield* iterAnnotation(item, stack);
stack.pop();
}
break;
}
case "object":
for (const [key, value] of ann.fields) {
stack.push(key);
yield* iterAnnotation(value, stack);
stack.pop();
}
break;
case "scalar":
case "opaque":
break;
default:
assertNever(ann, "Unknown annotation type");
}
}
function formatAsIssues(ann) {
return Array.from(iterAnnotation(ann, []));
}
function ok(value) {
return {
ok: true,
value,
error: void 0,
};
}
function err(error) {
return {
ok: false,
value: void 0,
error,
};
}
function noThrow(fn) {
return (t) => {
try {
return ok(fn(t));
} catch (e) {
return err(
public_annotate(t, e instanceof Error ? e.message : String(e)),
);
}
};
}
function format(err2, formatter) {
const formatted = formatter(err2);
if (typeof formatted === "string") {
const err3 = new Error(`
${formatted}`);
err3.name = "Decoding error";
return err3;
} else return formatted;
}
var DecoderImpl = class {
decode;
verify;
value;
#standard;
constructor(fn) {
const decode = (blob) => {
const makeFlexErr = (msg) =>
err(
isAnnotation(msg) ? msg : public_annotate(blob, msg),
);
return fn(blob, ok, makeFlexErr);
};
const verify = (blob, formatter = formatInline) => {
const result = decode(blob);
if (result.ok) return result.value;
else throw format(result.error, formatter);
};
const value = (blob) => decode(blob).value;
this.decode = decode;
this.verify = verify;
this.value = value;
}
transform(transformFn) {
return this.chain(noThrow(transformFn));
}
refine(predicateFn, errmsg) {
return this.reject((value) => (predicateFn(value) ? null : errmsg));
}
refineType() {
return this;
}
chain(next) {
const decode = this.decode;
return define((blob, ok2, err2) => {
const r1 = decode(blob);
if (!r1.ok) return r1;
const r2 = isDecoder(next)
? next
: next(r1.value, ok2, err2);
return isDecoder(r2) ? r2.decode(r1.value) : r2;
});
}
pipe(next) {
return this.chain(next);
}
reject(rejectFn) {
return this.chain((blob, ok2, err2) => {
const errmsg = rejectFn(blob);
return errmsg === null
? ok2(blob)
: err2(
typeof errmsg === "string" ? public_annotate(blob, errmsg) : errmsg,
);
});
}
describe(message) {
const decode = this.decode;
return define((blob, _, err2) => {
const result = decode(blob);
if (result.ok) return result;
else return err2(public_annotate(result.error, message));
});
}
get "~standard"() {
const decode = this.decode;
return (this.#standard ??= {
version: 1,
vendor: "decoders",
validate: (blob) => {
const result = decode(blob);
if (result.ok) return { value: result.value };
else return { issues: formatAsIssues(result.error) };
},
});
}
};
Object.defineProperty(DecoderImpl, "name", { value: "Decoder" });
function define(fn) {
return stamp2(new DecoderImpl(fn));
}
var kDecoderRegistry = Symbol.for("decoders.kDecoderRegistry");
var _stamped2 = (globalThis[kDecoderRegistry] ??=
new WeakSet());
function stamp2(decoder) {
_stamped2.add(decoder);
return decoder;
}
function isDecoder(value) {
return _stamped2.has(value);
}
function bySizeOptions(options) {
const size = options.size;
const min2 = size ?? options.min;
const max2 = size ?? options.max;
const atLeast = min2 === max2 ? "" : "at least ";
const atMost = min2 === max2 ? "" : "at most ";
return (value) => {
const len = value.length ?? value.size;
if (typeof value === "string") {
if (min2 !== void 0 && len < min2)
return `Too short, must be ${atLeast}${/* @__PURE__ */ qty(min2, "char")}`;
if (max2 !== void 0 && len > max2)
return `Too long, must be ${atMost}${/* @__PURE__ */ qty(max2, "char")}`;
} else {
if (min2 !== void 0 && len < min2)
return `Must have ${atLeast}${/* @__PURE__ */ qty(min2, "item")}`;
if (max2 !== void 0 && len > max2)
return `Must have ${atMost}${/* @__PURE__ */ qty(max2, "item")}`;
}
return null;
};
}
function sized(decoder, options) {
return decoder.reject( bySizeOptions(options));
}
var poja = define((blob, ok2, err2) => {
if (!Array.isArray(blob)) return err2("Must be an array");
return ok2(blob);
});
function array(decoder, options) {
const decodeFn = decoder.decode;
return (
options !== void 0 ? sized(poja, options) : poja
).chain((inputs, ok2, err2) => {
const results = [];
let clone = null;
let errorCount = 0;
for (let i = 0; i < inputs.length; ++i) {
const blob = inputs[i];
const result = decodeFn(blob);
if (result.ok) {
if (clone === null) results.push(result.value);
} else {
results.length = 0;
clone ??= inputs.slice();
clone[i] = result.error;
if (++errorCount >= MAX_ERRORS) break;
}
}
return clone !== null ? err2(public_annotate(clone)) : ok2(results);
});
}
var pojo = define((blob, ok2, err2) =>
isPlainObject(blob) ? ok2(blob) : err2("Must be an object"),
);
function buildObject(decoders) {
const knownKeys = Object.keys(decoders);
return pojo.chain((plainObj, ok2, err2) => {
const record2 = {};
let errors = null;
let missingKeys = null;
for (const key of knownKeys) {
const decoder = decoders[key];
const rawValue = plainObj[key];
const result = decoder.decode(rawValue);
if (result.ok) {
const value = result.value;
if (value !== void 0) record2[key] = value;
} else {
const ann = result.error;
if (rawValue === void 0) (missingKeys ??= []).push(key);
else (errors ??= new Map()).set(key, ann);
}
}
if (errors || missingKeys) {
let objAnn = public_annotateObject(plainObj);
if (errors) objAnn = merge(objAnn, errors);
if (missingKeys) {
const errMsg = missingKeys.map(quote).join(", ");
const pluralized = missingKeys.length > 1 ? "keys" : "key";
objAnn = updateText(objAnn, `Missing ${pluralized}: ${errMsg}`);
}
return err2(objAnn);
}
return ok2(record2);
});
}
function object(decoders) {
return buildObject(decoders);
}
var EITHER_PREFIX = "Either:\n";
function itemize(s) {
return `-${/* @__PURE__ */ indent(s).substring(1)}`;
}
function nest(errText) {
return errText.startsWith(EITHER_PREFIX)
? errText.substring(EITHER_PREFIX.length)
: itemize(errText);
}
function either(...decoders) {
if (decoders.length === 0)
throw new Error("Pass at least one decoder to either()");
return define((blob, _, err2) => {
const errors = [];
for (const decoder of decoders) {
const result = decoder.decode(blob);
if (result.ok) return result;
else errors.push(result.error);
}
return err2(
EITHER_PREFIX +
errors
.map((err3) => nest( summarize(err3).join("\n")))
.join("\n"),
);
});
}
function oneOf(constants) {
return define((blob, ok2, err2) => {
const index = constants.indexOf(blob);
if (index !== -1) return ok2(constants[index]);
return err2(
`Must be one of ${constants.map((value) => quote(value)).join(", ")}`,
);
});
}
function lazyval(value) {
return typeof value === "function" ? value() : value;
}
var null_ = constant(null);
function nullable(decoder, defaultValue) {
const rv = either(null_, decoder);
return arguments.length >= 2
? rv.transform((value) => value ?? lazyval(defaultValue))
: rv;
}
function constant(value) {
return define((blob, ok2, err2) =>
blob === value
? ok2(value)
: err2(
`Must be ${typeof value === "symbol" ? String(value) : quote(value)}`,
),
);
}
var url_re =
/^[A-Za-z]{2,12}(?:[+][A-Za-z]{2,12})?:\/\/(?:[^@]*@)?[A-Za-z0-9.-]+(?::[0-9]{2,5})?(?:\/[-+~%/.,!$&'()*:;=@\w]*(?:\?[-+~%/.,!$&'()*:;=@?\w]*)?)?(?:#[^\s#]*)?$/;
var string = define((blob, ok2, err2) =>
isString(blob) ? ok2(blob) : err2("Must be string"),
);
function regex(regex2, msg) {
return string.refine((s) => regex2.test(s), msg);
}
var urlString = regex(url_re, "Must be URL");
var date = define((blob, ok2, err2) => {
return isDate(blob) ? ok2(blob) : err2("Must be a Date");
});
var number = define((blob, ok2, err2) =>
isNumber(blob) ? ok2(blob) : err2("Must be number"),
).refine((n) => Number.isFinite(n), "Number must be finite");
function between(min2, max2, decoder = number) {
return decoder.reject((value) =>
value < min2
? `Too low, must be between ${min2} and ${max2}`
: value > max2
? `Too high, must be between ${min2} and ${max2}`
: null,
);
}
const imageDecoder = object({
id: number,
created: date,
title: sized(string, {
min: 1,
max: 100,
}),
type: oneOf(["jpg", "png"]),
size: number,
url: urlString,
});
object({
id: number,
created: date,
title: sized(string, {
min: 1,
max: 100,
}),
brand: sized(string, {
min: 1,
max: 30,
}),
description: sized(string, {
min: 1,
max: 500,
}),
price: between(1, 1e4),
discount: nullable( between(1, 100)),
quantity: between(0, 10),
tags: array(
sized(string, {
min: 1,
max: 30,
}),
),
images: array(imageDecoder),
ratings: array(
object({
id: number,
stars: between(1, 5),
title: sized(string, {
min: 1,
max: 100,
}),
text: sized(string, {
min: 1,
max: 1e3,
}),
images: array(imageDecoder),
}),
),
}).verify({});
var MAX_ERRORS = 3;
function qty(n, unit) {
return n === 1 ? `${n} ${unit}` : `${n} ${unit}s`;
}
function isNumber(value) {
return typeof value === "number";
}
function isString(value) {
return typeof value === "string";
}
function isDate(value) {
return !!value && Object.prototype.toString.call(value) === "[object Date]" && !isNaN(value);
}
function isPromiseLike(value) {
return (
typeof value === "object" &&
value !== null &&
"then" in value &&
typeof value.then === "function"
);
}
function isPlainObject(value) {
return (
value !== null &&
typeof value === "object" &&
Object.prototype.toString.call(value) === "[object Object]"
);
}
function assertNever(_value, msg = "Unhandled case") {
throw new Error(msg);
}
var kAnnotationRegistry = Symbol.for("decoders.kAnnotationRegistry");
var _stamped = (globalThis[kAnnotationRegistry] ??= new WeakSet());
function stamp(ann) {
_stamped.add(ann);
return ann;
}
function makeObjectAnn(getFields, text) {
let fields;
return stamp({
type: "object",
get fields() {
return (fields ??= getFields());
},
text,
});
}
function makeArrayAnn(getItems, text) {
let items;
return stamp({
type: "array",
get items() {
return (items ??= getItems());
},
text,
});
}
function makeOpaqueAnn(value, text) {
return stamp({
type: "opaque",
value,
text,
});
}
function makeScalarAnn(value, text) {
return stamp({
type: "scalar",
value,
text,
});
}
function updateText(annotation, text) {
if (text === void 0) return annotation;
switch (annotation.type) {
case "object":
return makeObjectAnn(() => annotation.fields, text);
case "array":
return makeArrayAnn(() => annotation.items, text);
case "scalar":
return makeScalarAnn(annotation.value, text);
case "opaque":
return makeOpaqueAnn(annotation.value, text);
default:
return assertNever(annotation, "Unknown annotation type");
}
}
function merge(objAnnotation, fields) {
return makeObjectAnn(() => new Map([...objAnnotation.fields, ...fields]), objAnnotation.text);
}
function isAnnotation(thing) {
return _stamped.has(thing);
}
function annotateArray(arr, text, seen) {
seen.add(arr);
return makeArrayAnn(() => Array.from(arr, (value) => __annotate(value, void 0, seen)), text);
}
function annotateObject(obj, text, seen) {
seen.add(obj);
return makeObjectAnn(() => {
const fields = new Map();
for (const key of Object.keys(obj)) {
const value = obj[key];
fields.set(key, __annotate(value, void 0, seen));
}
return fields;
}, text);
}
function __annotate(value, text, seen) {
if (
value === null ||
value === void 0 ||
typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean" ||
typeof value === "symbol" ||
typeof value === "bigint" ||
typeof value.getMonth === "function"
)
return makeScalarAnn(value, text);
if (isAnnotation(value)) return updateText(value, text);
if (Array.isArray(value)) {
if (seen.has(value)) return makeOpaqueAnn("<circular ref>", text);
else return annotateArray(value, text, seen);
}
if ( isPlainObject(value)) {
if (seen.has(value)) return makeOpaqueAnn("<circular ref>", text);
else return annotateObject(value, text, seen);
}
if (typeof value === "function") return makeOpaqueAnn("<function>", text);
if ( isPromiseLike(value)) return makeOpaqueAnn("<Promise>", text);
if (value?.constructor?.name) return makeOpaqueAnn(`<${value.constructor.name}>`, text);
else return makeOpaqueAnn("???", text);
}
function public_annotate(value, text) {
return __annotate(value, text, new WeakSet());
}
function public_annotateObject(obj, text) {
return annotateObject(obj, text, new WeakSet());
}
var INDENT = " ";
function isMultiline(s) {
return s.includes("\n");
}
function indent(s, prefix = INDENT) {
if ( isMultiline(s))
return s
.split("\n")
.map((line) => `${prefix}${line}`)
.join("\n");
else return `${prefix}${s}`;
}
var quotePattern = /'/g;
function quote(value) {
return typeof value === "string"
? "'" + value.replace(quotePattern, "\\'") + "'"
: value === void 0
? "undefined"
: JSON.stringify(value);
}
function summarize(ann, keypath = []) {
const result = [];
if (ann.type === "array") {
const items = ann.items;
let index = 0;
for (const ann2 of items)
for (const item of summarize(ann2, [...keypath, index++])) result.push(item);
} else if (ann.type === "object") {
const fields = ann.fields;
for (const [key, value] of fields)
for (const item of summarize(value, [...keypath, key])) result.push(item);
}
const text = ann.text;
if (!text) return result;
let prefix;
if (keypath.length === 0) prefix = "";
else if (keypath.length === 1)
prefix =
typeof keypath[0] === "number"
? `Value at index ${keypath[0]}: `
: `Value at key ${/* @__PURE__ */ quote(keypath[0])}: `;
else prefix = `Value at keypath ${/* @__PURE__ */ quote(keypath.map(String).join("."))}: `;
return [...result, `${prefix}${text}`];
}
function serializeString(s, width = 80) {
let ser = JSON.stringify(s);
if (ser.length <= width) return ser;
const truncated = `${s.substring(0, width - 15)}...`;
ser = `${JSON.stringify(truncated)} [truncated]`;
return ser;
}
function serializeArray(annotation, prefix) {
const { items } = annotation;
if (items.length === 0) return "[]";
const result = [];
for (let i = 0; i < items.length; ++i) {
const [ser, ann] = serializeAnnotation(items[i], `${prefix}${INDENT}`, `(at index ${i})`);
result.push(`${prefix}${INDENT}${ser},`);
if (ann !== void 0) result.push( indent(ann, `${prefix}${INDENT}`));
}
return ["[", ...result, `${prefix}]`].join("\n");
}
function serializeObject(annotation, prefix) {
const { fields } = annotation;
if (fields.size === 0) return "{}";
const result = [];
for (const [key, valueAnnotation] of fields) {
const kser = serializeValue(key);
const valPrefix = `${prefix}${INDENT}${" ".repeat(kser.length + 2)}`;
const [vser, vann] = serializeAnnotation(valueAnnotation, `${prefix}${INDENT}`);
result.push(`${prefix}${INDENT}${kser}: ${vser},`);
if (vann !== void 0) result.push( indent(vann, valPrefix));
}
return ["{", ...result, `${prefix}}`].join("\n");
}
function serializeValue(value) {
if (typeof value === "string") return serializeString(value);
else if (typeof value === "number" || typeof value === "boolean" || typeof value === "symbol")
return value.toString();
else if (value === null) return "null";
else if (value === void 0) return "undefined";
else if (typeof value === "bigint") return `${value.toString()}n`;
else if ( isDate(value))
return `new Date(${/* @__PURE__ */ quote(value.toISOString())})`;
else if (value instanceof Date) return "(Invalid Date)";
else return "(unserializable)";
}
function serializeAnnotation(ann, prefix = "", location) {
let serialized;
if (ann.type === "array") serialized = serializeArray(ann, prefix);
else if (ann.type === "object") serialized = serializeObject(ann, prefix);
else if (ann.type === "scalar") serialized = serializeValue(ann.value);
else serialized = ann.value;
const text = ann.text;
if (text !== void 0) {
const sep = "^".repeat( isMultiline(serialized) ? 1 : serialized.length);
const annotation = isMultiline(text)
? [location ? `${sep} ${location}` : sep, text].join("\n")
: [sep, text, location].filter(Boolean).join(" ");
return [serialized, annotation];
} else return [serialized, void 0];
}
function formatInline(ann) {
const [serialized, annotation] = serializeAnnotation(ann);
if (annotation !== void 0)
return `${serialized}
${annotation}`;
else return serialized;
}
function* iterAnnotation(ann, stack) {
if (ann.text) {
if (stack.length > 0)
yield {
message: ann.text,
path: [...stack],
};
else yield { message: ann.text };
}
switch (ann.type) {
case "array": {
let index = 0;
for (const item of ann.items) {
stack.push(index++);
yield* iterAnnotation(item, stack);
stack.pop();
}
break;
}
case "object":
for (const [key, value] of ann.fields) {
stack.push(key);
yield* iterAnnotation(value, stack);
stack.pop();
}
break;
case "scalar":
case "opaque":
break;
default:
assertNever(ann, "Unknown annotation type");
}
}
function formatAsIssues(ann) {
return Array.from(iterAnnotation(ann, []));
}
function ok(value) {
return {
ok: true,
value,
error: void 0,
};
}
function err(error) {
return {
ok: false,
value: void 0,
error,
};
}
function noThrow(fn) {
return (t) => {
try {
return ok(fn(t));
} catch (e) {
return err(public_annotate(t, e instanceof Error ? e.message : String(e)));
}
};
}
function format(err2, formatter) {
const formatted = formatter(err2);
if (typeof formatted === "string") {
const err3 = new Error(`
${formatted}`);
err3.name = "Decoding error";
return err3;
} else return formatted;
}
var DecoderImpl = class {
decode;
verify;
value;
#standard;
constructor(fn) {
const decode = (blob) => {
const makeFlexErr = (msg) =>
err(isAnnotation(msg) ? msg : public_annotate(blob, msg));
return fn(blob, ok, makeFlexErr);
};
const verify = (blob, formatter = formatInline) => {
const result = decode(blob);
if (result.ok) return result.value;
else throw format(result.error, formatter);
};
const value = (blob) => decode(blob).value;
this.decode = decode;
this.verify = verify;
this.value = value;
}
transform(transformFn) {
return this.chain(noThrow(transformFn));
}
refine(predicateFn, errmsg) {
return this.reject((value) => (predicateFn(value) ? null : errmsg));
}
refineType() {
return this;
}
chain(next) {
const decode = this.decode;
return define((blob, ok2, err2) => {
const r1 = decode(blob);
if (!r1.ok) return r1;
const r2 = isDecoder(next) ? next : next(r1.value, ok2, err2);
return isDecoder(r2) ? r2.decode(r1.value) : r2;
});
}
pipe(next) {
return this.chain(next);
}
reject(rejectFn) {
return this.chain((blob, ok2, err2) => {
const errmsg = rejectFn(blob);
return errmsg === null
? ok2(blob)
: err2(typeof errmsg === "string" ? public_annotate(blob, errmsg) : errmsg);
});
}
describe(message) {
const decode = this.decode;
return define((blob, _, err2) => {
const result = decode(blob);
if (result.ok) return result;
else return err2(public_annotate(result.error, message));
});
}
get "~standard"() {
const decode = this.decode;
return (this.#standard ??= {
version: 1,
vendor: "decoders",
validate: (blob) => {
const result = decode(blob);
if (result.ok) return { value: result.value };
else return { issues: formatAsIssues(result.error) };
},
});
}
};
Object.defineProperty(DecoderImpl, "name", { value: "Decoder" });
function define(fn) {
return stamp2(new DecoderImpl(fn));
}
var kDecoderRegistry = Symbol.for("decoders.kDecoderRegistry");
var _stamped2 = (globalThis[kDecoderRegistry] ??= new WeakSet());
function stamp2(decoder) {
_stamped2.add(decoder);
return decoder;
}
function isDecoder(value) {
return _stamped2.has(value);
}
function bySizeOptions(options) {
const size = options.size;
const min2 = size ?? options.min;
const max2 = size ?? options.max;
const atLeast = min2 === max2 ? "" : "at least ";
const atMost = min2 === max2 ? "" : "at most ";
return (value) => {
const len = value.length ?? value.size;
if (typeof value === "string") {
if (min2 !== void 0 && len < min2)
return `Too short, must be ${atLeast}${/* @__PURE__ */ qty(min2, "char")}`;
if (max2 !== void 0 && len > max2)
return `Too long, must be ${atMost}${/* @__PURE__ */ qty(max2, "char")}`;
} else {
if (min2 !== void 0 && len < min2)
return `Must have ${atLeast}${/* @__PURE__ */ qty(min2, "item")}`;
if (max2 !== void 0 && len > max2)
return `Must have ${atMost}${/* @__PURE__ */ qty(max2, "item")}`;
}
return null;
};
}
function sized(decoder, options) {
return decoder.reject( bySizeOptions(options));
}
var poja = define((blob, ok2, err2) => {
if (!Array.isArray(blob)) return err2("Must be an array");
return ok2(blob);
});
function array(decoder, options) {
const decodeFn = decoder.decode;
return (options !== void 0 ? sized(poja, options) : poja).chain(
(inputs, ok2, err2) => {
const results = [];
let clone = null;
let errorCount = 0;
for (let i = 0; i < inputs.length; ++i) {
const blob = inputs[i];
const result = decodeFn(blob);
if (result.ok) {
if (clone === null) results.push(result.value);
} else {
results.length = 0;
clone ??= inputs.slice();
clone[i] = result.error;
if (++errorCount >= MAX_ERRORS) break;
}
}
return clone !== null ? err2(public_annotate(clone)) : ok2(results);
},
);
}
var pojo = define((blob, ok2, err2) =>
isPlainObject(blob) ? ok2(blob) : err2("Must be an object"),
);
function buildObject(decoders) {
const knownKeys = Object.keys(decoders);
return pojo.chain((plainObj, ok2, err2) => {
const record2 = {};
let errors = null;
let missingKeys = null;
for (const key of knownKeys) {
const decoder = decoders[key];
const rawValue = plainObj[key];
const result = decoder.decode(rawValue);
if (result.ok) {
const value = result.value;
if (value !== void 0) record2[key] = value;
} else {
const ann = result.error;
if (rawValue === void 0) (missingKeys ??= []).push(key);
else (errors ??= new Map()).set(key, ann);
}
}
if (errors || missingKeys) {
let objAnn = public_annotateObject(plainObj);
if (errors) objAnn = merge(objAnn, errors);
if (missingKeys) {
const errMsg = missingKeys.map(quote).join(", ");
const pluralized = missingKeys.length > 1 ? "keys" : "key";
objAnn = updateText(objAnn, `Missing ${pluralized}: ${errMsg}`);
}
return err2(objAnn);
}
return ok2(record2);
});
}
function object(decoders) {
return buildObject(decoders);
}
var EITHER_PREFIX = "Either:\n";
function itemize(s) {
return `-${/* @__PURE__ */ indent(s).substring(1)}`;
}
function nest(errText) {
return errText.startsWith(EITHER_PREFIX)
? errText.substring(EITHER_PREFIX.length)
: itemize(errText);
}
function either(...decoders) {
if (decoders.length === 0) throw new Error("Pass at least one decoder to either()");
return define((blob, _, err2) => {
const errors = [];
for (const decoder of decoders) {
const result = decoder.decode(blob);
if (result.ok) return result;
else errors.push(result.error);
}
return err2(
EITHER_PREFIX +
errors.map((err3) => nest( summarize(err3).join("\n"))).join("\n"),
);
});
}
function oneOf(constants) {
return define((blob, ok2, err2) => {
const index = constants.indexOf(blob);
if (index !== -1) return ok2(constants[index]);
return err2(
`Must be one of ${constants.map((value) => quote(value)).join(", ")}`,
);
});
}
function lazyval(value) {
return typeof value === "function" ? value() : value;
}
var null_ = constant(null);
function nullable(decoder, defaultValue) {
const rv = either(null_, decoder);
return arguments.length >= 2 ? rv.transform((value) => value ?? lazyval(defaultValue)) : rv;
}
function constant(value) {
return define((blob, ok2, err2) =>
blob === value
? ok2(value)
: err2(`Must be ${typeof value === "symbol" ? String(value) : quote(value)}`),
);
}
var url_re =
/^[A-Za-z]{2,12}(?:[+][A-Za-z]{2,12})?:\/\/(?:[^@]*@)?[A-Za-z0-9.-]+(?::[0-9]{2,5})?(?:\/[-+~%/.,!$&'()*:;=@\w]*(?:\?[-+~%/.,!$&'()*:;=@?\w]*)?)?(?:#[^\s#]*)?$/;
var string = define((blob, ok2, err2) =>
isString(blob) ? ok2(blob) : err2("Must be string"),
);
function regex(regex2, msg) {
return string.refine((s) => regex2.test(s), msg);
}
var urlString = regex(url_re, "Must be URL");
var date = define((blob, ok2, err2) => {
return isDate(blob) ? ok2(blob) : err2("Must be a Date");
});
var number = define((blob, ok2, err2) =>
isNumber(blob) ? ok2(blob) : err2("Must be number"),
).refine((n) => Number.isFinite(n), "Number must be finite");
function between(min2, max2, decoder = number) {
return decoder.reject((value) =>
value < min2
? `Too low, must be between ${min2} and ${max2}`
: value > max2
? `Too high, must be between ${min2} and ${max2}`
: null,
);
}
const imageDecoder = object({
id: number,
created: date,
title: sized(string, {
min: 1,
max: 100,
}),
type: oneOf(["jpg", "png"]),
size: number,
url: urlString,
});
object({
id: number,
created: date,
title: sized(string, {
min: 1,
max: 100,
}),
brand: sized(string, {
min: 1,
max: 30,
}),
description: sized(string, {
min: 1,
max: 500,
}),
price: between(1, 1e4),
discount: nullable( between(1, 100)),
quantity: between(0, 10),
tags: array(
sized(string, {
min: 1,
max: 30,
}),
),
images: array(imageDecoder),
ratings: array(
object({
id: number,
stars: between(1, 5),
title: sized(string, {
min: 1,
max: 100,
}),
text: sized(string, {
min: 1,
max: 1e3,
}),
images: array(imageDecoder),
}),
),
}).verify({});