ag-charts-core
Version:
Advanced Charting / Charts supporting Javascript / Typescript / React / Angular / Vue
1,628 lines (1,601 loc) • 278 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result)
__defProp(target, key, result);
return result;
};
// packages/ag-charts-core/src/globals/debug-logger.ts
var debug_logger_exports = {};
__export(debug_logger_exports, {
Time: () => Time,
check: () => check,
create: () => create,
inDevelopmentMode: () => inDevelopmentMode
});
// packages/ag-charts-core/src/utils/arrays.ts
function toArray(value) {
if (value === void 0) {
return [];
}
return Array.isArray(value) ? value : [value];
}
function unique(array2) {
return Array.from(new Set(array2));
}
function groupBy(array2, iteratee) {
return array2.reduce((result, item) => {
const groupKey = iteratee(item);
result[groupKey] ?? (result[groupKey] = []);
result[groupKey].push(item);
return result;
}, {});
}
function arraysEqual(a, b) {
if (a == null || b == null || a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (Array.isArray(a[i]) && Array.isArray(b[i])) {
if (!arraysEqual(a[i], b[i])) {
return false;
}
} else if (a[i] !== b[i]) {
return false;
}
}
return true;
}
function circularSliceArray(data, size, offset = 0) {
if (data.length === 0) {
return [];
}
const result = [];
for (let i = 0; i < size; i++) {
result.push(data.at((i + offset) % data.length));
}
return result;
}
function sortBasedOnArray(baseArray, orderArray) {
const orderMap = /* @__PURE__ */ new Map();
for (const [index, item] of orderArray.entries()) {
orderMap.set(item, index);
}
return baseArray.sort((a, b) => {
const indexA = orderMap.get(a) ?? Infinity;
const indexB = orderMap.get(b) ?? Infinity;
return indexA - indexB;
});
}
function dropFirstWhile(array2, cond) {
let i = 0;
while (i < array2.length && cond(array2[i])) {
i += 1;
}
const deleteCount = i;
if (deleteCount !== 0)
array2.splice(0, deleteCount);
}
function dropLastWhile(array2, cond) {
let i = array2.length - 1;
while (i >= 0 && cond(array2[i])) {
i -= 1;
}
const deleteCount = array2.length - 1 - i;
if (deleteCount !== 0)
array2.splice(array2.length - deleteCount, deleteCount);
}
function distribute(min, max, maxCount) {
const values = [min];
const step = Math.round((max - min) / (maxCount - 1));
if (step > 0) {
for (let i = min + step; i < max; i += step) {
const length2 = values.push(i);
if (length2 >= maxCount - 1)
break;
}
}
values.push(max);
return values;
}
// packages/ag-charts-core/src/utils/dom/globalsProxy.ts
var verifiedGlobals = {};
if (typeof globalThis.window !== "undefined") {
verifiedGlobals.window = globalThis.window;
}
if (typeof document !== "undefined") {
verifiedGlobals.document = document;
} else if (typeof globalThis.global !== "undefined") {
verifiedGlobals.document = globalThis.document;
}
function getDocument(propertyName) {
return propertyName ? verifiedGlobals.document?.[propertyName] : verifiedGlobals.document;
}
function getWindow(propertyName) {
return propertyName ? verifiedGlobals.window?.[propertyName] : verifiedGlobals.window;
}
function setDocument(document2) {
verifiedGlobals.document = document2;
}
function setWindow(window) {
verifiedGlobals.window = window;
}
// packages/ag-charts-core/src/utils/dom/domElements.ts
function createElement(tagName, className, style2) {
const element = getDocument().createElement(tagName);
if (typeof className === "object") {
style2 = className;
className = void 0;
}
if (className) {
for (const name of className.split(" ")) {
element.classList.add(name);
}
}
if (style2) {
Object.assign(element.style, style2);
}
return element;
}
function createSvgElement(elementName) {
return getDocument().createElementNS("http://www.w3.org/2000/svg", elementName);
}
// packages/ag-charts-core/src/utils/dom/domDownload.ts
function downloadUrl(dataUrl, fileName) {
const body = getDocument("body");
const element = createElement("a", { display: "none" });
element.href = dataUrl;
element.download = fileName;
body.appendChild(element);
element.click();
setTimeout(() => element.remove());
}
// packages/ag-charts-core/src/utils/dom/domEvents.ts
function attachListener(element, eventName, handler, options) {
element.addEventListener(eventName, handler, options);
return () => element.removeEventListener(eventName, handler, options);
}
// packages/ag-charts-core/src/utils/dom/domUtils.ts
var style;
function parseColor(color2) {
if (style == null) {
const OptionConstructor = getWindow("Option");
style = new OptionConstructor().style;
}
style.color = color2;
const result = style.color || null;
style.color = "";
return result;
}
// packages/ag-charts-core/src/globals/logger.ts
var logger_exports = {};
__export(logger_exports, {
error: () => error,
errorOnce: () => errorOnce,
log: () => log,
logGroup: () => logGroup,
reset: () => reset,
table: () => table,
warn: () => warn,
warnOnce: () => warnOnce
});
var doOnceCache = /* @__PURE__ */ new Set();
function log(...logContent) {
console.log(...logContent);
}
function warn(message, ...logContent) {
console.warn(`AG Charts - ${message}`, ...logContent);
}
function error(message, ...logContent) {
if (typeof message === "object") {
console.error(`AG Charts error`, message, ...logContent);
} else {
console.error(`AG Charts - ${message}`, ...logContent);
}
}
function table(...logContent) {
console.table(...logContent);
}
function guardOnce(messageOrError, prefix, cb) {
let message;
if (messageOrError instanceof Error) {
message = messageOrError.message;
} else if (typeof messageOrError === "string") {
message = messageOrError;
} else if (typeof messageOrError === "object") {
message = JSON.stringify(messageOrError);
} else {
message = String(messageOrError);
}
const cacheKey = `${prefix}: ${message}`;
if (doOnceCache.has(cacheKey))
return;
cb(messageOrError);
doOnceCache.add(cacheKey);
}
function warnOnce(messageOrError, ...logContent) {
guardOnce(messageOrError, "Logger.warn", (message) => warn(message, ...logContent));
}
function errorOnce(messageOrError, ...logContent) {
guardOnce(messageOrError, "Logger.error", (message) => error(message, ...logContent));
}
function reset() {
doOnceCache.clear();
}
function logGroup(name, cb) {
console.groupCollapsed(name);
try {
return cb();
} finally {
console.groupEnd();
}
}
// packages/ag-charts-core/src/globals/debug-logger.ts
var LongTimePeriodThreshold = 2e3;
var timeOfLastLog = Date.now();
function logTimeGap() {
const timeSinceLastLog = Date.now() - timeOfLastLog;
if (timeSinceLastLog > LongTimePeriodThreshold) {
const prettyDuration = (Math.floor(timeSinceLastLog / 100) / 10).toFixed(1);
log(`**** ${prettyDuration}s since last log message ****`);
}
timeOfLastLog = Date.now();
}
function create(...debugSelectors) {
const resultFn = (...logContent) => {
if (check(...debugSelectors)) {
if (typeof logContent[0] === "function") {
logContent = toArray(logContent[0]());
}
logTimeGap();
log(...logContent);
}
};
return Object.assign(resultFn, {
check: () => check(...debugSelectors),
group: (name, cb) => {
if (check(...debugSelectors)) {
return logGroup(name, cb);
}
return cb();
}
});
}
function check(...debugSelectors) {
if (debugSelectors.length === 0) {
debugSelectors.push(true);
}
const chartDebug = toArray(getWindow("agChartsDebug"));
return chartDebug.some((selector) => debugSelectors.includes(selector));
}
function inDevelopmentMode(fn) {
if (check("dev")) {
return fn();
}
}
function Time(name, opts = {}) {
const { logResult = true, logStack = false, logArgs = false, logData } = opts;
return function(_target, _propertyKey, descriptor) {
const method = descriptor.value;
descriptor.value = function(...args) {
const start2 = performance.now();
const result = method.apply(this, args);
const duration = performance.now() - start2;
const logMessage = { duration };
if (logResult)
logMessage.result = result;
if (logArgs)
logMessage.args = args;
if (logStack)
logMessage.stack = new Error("Stack trace for timing debug").stack;
if (logData)
logMessage.logData = logData(this);
log(name, logMessage);
return result;
};
};
}
// packages/ag-charts-core/src/globals/debug-metrics.ts
var debug_metrics_exports = {};
__export(debug_metrics_exports, {
flush: () => flush,
record: () => record
});
var metrics = /* @__PURE__ */ new Map();
function record(key, value) {
if (!check("scene:stats:verbose"))
return;
metrics.set(key, value);
}
function flush() {
const result = Object.fromEntries(metrics);
metrics.clear();
return result;
}
// packages/ag-charts-core/src/globals/enterpriseRegistry.ts
var enterpriseRegistry = {};
// packages/ag-charts-core/src/globals/moduleRegistry.ts
var moduleRegistry_exports = {};
__export(moduleRegistry_exports, {
RegistryMode: () => RegistryMode,
getAxisModule: () => getAxisModule,
getChartModule: () => getChartModule,
getPresetModule: () => getPresetModule,
getSeriesModule: () => getSeriesModule,
hasModule: () => hasModule,
isEnterprise: () => isEnterprise,
isIntegrated: () => isIntegrated,
isModuleType: () => isModuleType,
isUmd: () => isUmd,
listModules: () => listModules,
listModulesByType: () => listModulesByType,
register: () => register,
registerModules: () => registerModules,
reset: () => reset2,
setRegistryMode: () => setRegistryMode
});
// packages/ag-charts-core/src/interfaces/moduleDefinition.ts
var ModuleType = /* @__PURE__ */ ((ModuleType2) => {
ModuleType2["Chart"] = "chart";
ModuleType2["Axis"] = "axis";
ModuleType2["Series"] = "series";
ModuleType2["Plugin"] = "plugin";
ModuleType2["AxisPlugin"] = "axis:plugin";
ModuleType2["SeriesPlugin"] = "series:plugin";
ModuleType2["Preset"] = "preset";
return ModuleType2;
})(ModuleType || {});
// packages/ag-charts-core/src/globals/moduleRegistry.ts
var RegistryMode = /* @__PURE__ */ ((RegistryMode2) => {
RegistryMode2["Enterprise"] = "enterprise";
RegistryMode2["Integrated"] = "integrated";
RegistryMode2["UMD"] = "umd";
return RegistryMode2;
})(RegistryMode || {});
var registeredModes = /* @__PURE__ */ new Set();
var registeredModules = /* @__PURE__ */ new Map();
function registerModuleDefinition(def) {
registeredModules.set(def.name, def);
if (def.dependencies) {
for (const dependency of def.dependencies) {
register(dependency);
}
}
}
function register(def) {
const existingDefinition = registeredModules.get(def.name);
if (!existingDefinition) {
registerModuleDefinition(def);
return;
}
if (existingDefinition.version === def.version) {
if (!existingDefinition.enterprise && def.enterprise) {
registerModuleDefinition(def);
}
return;
}
throw new Error(
[
`AG Charts - Module '${def.name}' already registered with different version:`,
`${existingDefinition.version} vs ${def.version}`,
``,
`Check your package.json for conflicting dependencies - depending on your package manager`,
`one of these commands may help:`,
`- npm ls ag-charts-community`,
`- yarn why ag-charts-community`
].join("\n")
);
}
function registerModules(definitions) {
for (const definition of definitions.flat()) {
register(definition);
}
}
function reset2() {
registeredModes.clear();
registeredModules.clear();
}
function hasModule(moduleName) {
return registeredModules.has(moduleName);
}
function* listModules() {
for (const definition of registeredModules.values()) {
yield definition;
}
}
function* listModulesByType(moduleType) {
for (const definition of registeredModules.values()) {
if (isModuleType(moduleType, definition)) {
yield definition;
}
}
}
function getAxisModule(moduleName) {
const definition = registeredModules.get(moduleName);
if (isModuleType("axis" /* Axis */, definition)) {
return definition;
}
}
function getChartModule(moduleName) {
const definition = registeredModules.get(moduleName);
if (isModuleType("chart" /* Chart */, definition)) {
return definition;
}
throw new Error(
`AG Charts - Unknown chart type; Check options are correctly structured and series types are specified`
);
}
function getPresetModule(moduleName) {
const definition = registeredModules.get(moduleName);
if (isModuleType("preset" /* Preset */, definition)) {
return definition;
}
}
function getSeriesModule(moduleName) {
const definition = registeredModules.get(moduleName);
if (isModuleType("series" /* Series */, definition)) {
return definition;
}
}
function setRegistryMode(registryFlag) {
registeredModes.add(registryFlag);
}
function isEnterprise() {
return registeredModes.has("enterprise" /* Enterprise */);
}
function isIntegrated() {
return registeredModes.has("integrated" /* Integrated */);
}
function isUmd() {
return registeredModes.has("umd" /* UMD */);
}
function isModuleType(moduleType, definition) {
return definition?.type === moduleType;
}
// packages/ag-charts-core/src/utils/cleanupRegistry.ts
var CleanupRegistry = class {
constructor() {
this.callbacks = /* @__PURE__ */ new Set();
}
flush() {
for (const cb of this.callbacks) {
cb();
}
this.callbacks.clear();
}
merge(registry) {
for (const cb of registry.callbacks) {
this.callbacks.add(cb);
}
}
register(...callbacks) {
for (const cb of callbacks) {
if (!cb)
continue;
this.callbacks.add(cb);
}
}
};
// packages/ag-charts-core/src/globals/moduleInstance.ts
var AbstractModuleInstance = class {
constructor() {
this.cleanup = new CleanupRegistry();
}
destroy() {
this.cleanup.flush();
}
};
// packages/ag-charts-core/src/interfaces/scaleTypes.ts
function extractDomain(value) {
return value.domain;
}
var ScaleAlignment = /* @__PURE__ */ ((ScaleAlignment2) => {
ScaleAlignment2[ScaleAlignment2["Leading"] = 0] = "Leading";
ScaleAlignment2[ScaleAlignment2["Trailing"] = 1] = "Trailing";
ScaleAlignment2[ScaleAlignment2["Interpolate"] = 2] = "Interpolate";
return ScaleAlignment2;
})(ScaleAlignment || {});
// packages/ag-charts-core/src/classes/eventEmitter.ts
var EventEmitter = class {
constructor() {
this.events = /* @__PURE__ */ new Map();
}
/**
* Registers an event listener.
* @param eventName The event name to listen for.
* @param listener The callback to be invoked on the event.
* @returns A function to unregister the listener.
*/
on(eventName, listener) {
if (!this.events.has(eventName)) {
this.events.set(eventName, /* @__PURE__ */ new Set());
}
this.events.get(eventName)?.add(listener);
return () => this.off(eventName, listener);
}
/**
* Unregisters an event listener.
* @param eventName The event name to stop listening for.
* @param listener The callback to be removed.
*/
off(eventName, listener) {
const eventListeners = this.events.get(eventName);
if (eventListeners) {
eventListeners.delete(listener);
if (eventListeners.size === 0) {
this.events.delete(eventName);
}
}
}
/**
* Emits an event to all registered listeners.
* @param eventName The name of the event to emit.
* @param event The event payload.
*/
emit(eventName, event) {
const listeners = this.events.get(eventName);
if (listeners) {
for (const callback2 of listeners) {
callback2(event);
}
}
}
/**
* Clears all listeners for a specific event or all events if no event name is provided.
* @param eventName (Optional) The name of the event to clear listeners for. If not provided, all listeners for all events are cleared.
*/
clear(eventName) {
if (eventName) {
this.events.delete(eventName);
} else {
this.events.clear();
}
}
};
// packages/ag-charts-core/src/classes/lruCache.ts
var LRUCache = class {
constructor(maxCacheSize) {
this.maxCacheSize = maxCacheSize;
this.store = /* @__PURE__ */ new Map();
if (maxCacheSize <= 0) {
throw new Error("LRUCache size must be greater than 0");
}
}
get(key) {
if (!this.store.has(key))
return;
const value = this.store.get(key);
this.store.delete(key);
this.store.set(key, value);
return value;
}
has(key) {
return this.store.has(key);
}
set(key, value) {
this.store.set(key, value);
if (this.store.size > this.maxCacheSize) {
this.store.delete(this.store.keys().next().value);
}
return value;
}
clear() {
this.store.clear();
}
};
// packages/ag-charts-core/src/utils/numbers.ts
function clamp(min, value, max) {
return Math.min(max, Math.max(min, value));
}
function inRange(value, range2, epsilon = 1e-10) {
return value >= range2[0] - epsilon && value <= range2[1] + epsilon;
}
function isNumberEqual(a, b, epsilon = 1e-10) {
return a === b || Math.abs(a - b) < epsilon;
}
function isNegative(value) {
return Math.sign(value) === -1 || Object.is(value, -0);
}
function isInteger(value) {
return value % 1 === 0;
}
function roundTo(value, decimals = 2) {
const base = 10 ** decimals;
return Math.round(value * base) / base;
}
function modulus(n, m) {
return Math.floor(n % m + (n < 0 ? Math.abs(m) : 0));
}
function countFractionDigits(value) {
if (Math.floor(value) === value) {
return 0;
}
let valueString = String(value);
let exponent = 0;
if (value < 1e-6 || value >= 1e21) {
let exponentString;
[valueString, exponentString] = valueString.split("e");
if (exponentString != null) {
exponent = Number(exponentString);
}
}
const decimalPlaces2 = valueString.split(".")[1]?.length ?? 0;
return Math.max(decimalPlaces2 - exponent, 0);
}
// packages/ag-charts-core/src/utils/typeGuards.ts
function isDefined(val) {
return val != null;
}
function isArray(value) {
return Array.isArray(value);
}
function isBoolean(value) {
return typeof value === "boolean";
}
function isDate(value) {
return value instanceof Date;
}
function isValidDate(value) {
return isDate(value) && !Number.isNaN(Number(value));
}
function isRegExp(value) {
return value instanceof RegExp;
}
function isFunction(value) {
return typeof value === "function";
}
function isObject(value) {
return typeof value === "object" && value !== null && !isArray(value);
}
function isObjectLike(value) {
return isArray(value) || isPlainObject(value);
}
function isPlainObject(value) {
return typeof value === "object" && value !== null && value.constructor?.name === "Object";
}
function isEmptyObject(value) {
if (typeof value !== "object" || value === null)
return false;
for (const _ in value) {
return false;
}
return true;
}
function isString(value) {
return typeof value === "string";
}
function isNumber(value) {
return typeof value === "number";
}
function isFiniteNumber(value) {
return Number.isFinite(value);
}
function isHtmlElement(value) {
return typeof globalThis.window !== "undefined" && value instanceof HTMLElement;
}
function isEnumKey(enumObject, enumKey) {
return isString(enumKey) && Object.keys(enumObject).includes(enumKey);
}
function isEnumValue(enumObject, enumValue) {
return Object.values(enumObject).includes(enumValue);
}
function isSymbol(value) {
return typeof value === "symbol";
}
function isColor(value) {
return isString(value) && (value === "none" || parseColor(value) != null);
}
function isKeyOf(value, container) {
return value in container;
}
// packages/ag-charts-core/src/modules/format/numberFormat.ts
var formatRegEx = /^(?:(.)?([<>=^]))?([+\-( ])?([$€£¥₣₹#])?(0)?(\d+)?(,)?(?:\.(\d+))?(~)?([%a-z])?$/i;
var surroundedRegEx = /^((?:[^#]|#[^{])*)#{([^}]+)}(.*)$/;
function isValidNumberFormat(value) {
if (!isString(value))
return false;
const match = surroundedRegEx.exec(value);
return formatRegEx.test(match ? match[2] : value);
}
function parseNumberFormat(format) {
let prefix;
let suffix;
const surrounded = surroundedRegEx.exec(format);
if (surrounded) {
[, prefix, format, suffix] = surrounded;
}
const match = formatRegEx.exec(format);
if (!match) {
logger_exports.warnOnce(`The number formatter is invalid: ${format}`);
return;
}
const [, fill, align, sign, symbol, zero, width2, comma, precision, trim, type] = match;
return {
fill,
align,
sign,
symbol,
zero,
width: Number.parseInt(width2),
comma,
precision: Number.parseInt(precision),
trim: Boolean(trim),
type,
prefix,
suffix
};
}
function createNumberFormatter(format) {
const options = typeof format === "string" ? parseNumberFormat(format) : format;
if (options == null)
return;
const { fill, align, sign = "-", symbol, zero, width: width2, comma, type, prefix = "", suffix = "", precision } = options;
let { trim } = options;
const precisionIsNaN = precision == null || Number.isNaN(precision);
let formatBody;
if (!type) {
formatBody = decimalTypes["g"];
trim = true;
} else if (type in decimalTypes && type in integerTypes) {
formatBody = precisionIsNaN ? integerTypes[type] : decimalTypes[type];
} else if (type in decimalTypes) {
formatBody = decimalTypes[type];
} else if (type in integerTypes) {
formatBody = integerTypes[type];
} else {
throw new Error(`The number formatter type is invalid: ${type}`);
}
const defaultFormatterPrecision = type ? 6 : 12;
let formatterPrecision;
if (!precisionIsNaN) {
formatterPrecision = precision;
}
let padAlign = align;
let padFill = fill;
if (zero) {
padFill ?? (padFill = "0");
padAlign ?? (padAlign = "=");
}
return (n, fractionDigits) => {
let effectivePrecision;
if (formatterPrecision != null) {
effectivePrecision = formatterPrecision;
} else if (type === "f" || type === "%") {
effectivePrecision = fractionDigits ?? defaultFormatterPrecision;
} else if (type) {
effectivePrecision = defaultFormatterPrecision;
} else {
effectivePrecision = fractionDigits ?? defaultFormatterPrecision;
}
let result = formatBody(n, effectivePrecision);
if (trim) {
result = removeTrailingZeros(result);
}
if (comma) {
result = insertSeparator(result, comma);
}
const symbolPrefix = getSymbolPrefix(symbol, type);
const symbolPrefixLength = symbolPrefix?.length ?? 0;
if (symbolPrefix) {
result = `${symbolPrefix}${result}`;
}
if (type === "s") {
result = `${result}${getSIPrefix(n)}`;
}
if (type === "%" || type === "p") {
result = `${result}%`;
}
const { value: signedResult, prefixLength: signPrefixLength } = addSign(n, result, sign);
const totalPrefixLength = signPrefixLength + symbolPrefixLength;
let output = signedResult;
if (width2 != null && !Number.isNaN(width2)) {
output = addPadding(output, width2, padFill ?? " ", padAlign, totalPrefixLength);
}
output = `${prefix}${output}${suffix}`;
return output;
};
}
var integerTypes = {
b: (n) => absFloor(n).toString(2),
c: (n) => String.fromCodePoint(n),
d: (n) => Math.round(Math.abs(n)).toFixed(0),
o: (n) => absFloor(n).toString(8),
x: (n) => absFloor(n).toString(16),
X: (n) => integerTypes.x(n).toUpperCase(),
n: (n) => integerTypes.d(n),
"%": (n) => `${absFloor(n * 100).toFixed(0)}`
};
var decimalTypes = {
e: (n, f) => Math.abs(n).toExponential(f),
E: (n, f) => decimalTypes.e(n, f).toUpperCase(),
f: (n, f) => Math.abs(n).toFixed(f),
F: (n, f) => decimalTypes.f(n, f).toUpperCase(),
g: (n, f) => {
if (n === 0) {
return "0";
}
const a = Math.abs(n);
const p = Math.floor(Math.log10(a));
if (p >= -4 && p < f) {
return a.toFixed(f - 1 - p);
}
return a.toExponential(f - 1);
},
G: (n, f) => decimalTypes.g(n, f).toUpperCase(),
n: (n, f) => decimalTypes.g(n, f),
p: (n, f) => decimalTypes.r(n * 100, f),
r: (n, f) => {
if (n === 0) {
return "0";
}
const a = Math.abs(n);
const p = Math.floor(Math.log10(a));
const q = p - (f - 1);
if (q <= 0) {
return a.toFixed(-q);
}
const x = 10 ** q;
return (Math.round(a / x) * x).toFixed();
},
s: (n, f) => {
const p = getSIPrefixPower(n);
return decimalTypes.r(n / 10 ** p, f);
},
"%": (n, f) => decimalTypes.f(n * 100, f)
};
var minSIPrefix = -24;
var maxSIPrefix = 24;
var siPrefixes = {
[minSIPrefix]: "y",
[-21]: "z",
[-18]: "a",
[-15]: "f",
[-12]: "p",
[-9]: "n",
[-6]: "\xB5",
[-3]: "m",
[0]: "",
[3]: "k",
[6]: "M",
[9]: "G",
[12]: "T",
[15]: "P",
[18]: "E",
[21]: "Z",
[maxSIPrefix]: "Y"
};
var minusSign = "\u2212";
function absFloor(n) {
return Math.floor(Math.abs(n));
}
function removeTrailingZeros(numString) {
if (!numString.endsWith("0") || !numString.includes("."))
return numString;
let endIndex = numString.length - 1;
while (endIndex > 0) {
if (numString[endIndex] == "0") {
endIndex -= 1;
} else if (numString[endIndex] == ".") {
endIndex -= 1;
break;
} else {
break;
}
}
return numString.substring(0, endIndex + 1);
}
function insertSeparator(numString, separator) {
let dotIndex = numString.indexOf(".");
if (dotIndex < 0) {
dotIndex = numString.length;
}
const integerChars = numString.substring(0, dotIndex).split("");
const fractionalPart = numString.substring(dotIndex);
for (let i = integerChars.length - 3; i > 0; i -= 3) {
integerChars.splice(i, 0, separator);
}
return `${integerChars.join("")}${fractionalPart}`;
}
function getSIPrefix(n) {
return siPrefixes[getSIPrefixPower(n)];
}
function getSIPrefixPower(n) {
return clamp(minSIPrefix, n ? Math.floor(Math.log10(Math.abs(n)) / 3) * 3 : 0, maxSIPrefix);
}
function addSign(num, numString, signType = "") {
if (signType === "(") {
if (num >= 0) {
return { value: numString, prefixLength: 0 };
}
return { value: `(${numString})`, prefixLength: 1 };
}
let signPrefix = "";
if (num < 0) {
signPrefix = minusSign;
} else if (signType === "+") {
signPrefix = "+";
} else if (signType === " ") {
signPrefix = " ";
}
return { value: `${signPrefix}${numString}`, prefixLength: signPrefix.length };
}
function addPadding(numString, width2, fill = " ", align = ">", prefixLength = 0) {
const padSize = width2 - numString.length;
if (padSize <= 0) {
return numString;
}
const padding2 = fill.repeat(padSize);
if (align === "=") {
const clampedPrefix = Math.min(Math.max(prefixLength, 0), numString.length);
const start2 = numString.slice(0, clampedPrefix);
const rest = numString.slice(clampedPrefix);
return `${start2}${padding2}${rest}`;
}
if (align === ">" || !align) {
return padding2 + numString;
} else if (align === "<") {
return `${numString}${padding2}`;
} else if (align === "^") {
const padLeft = Math.ceil(padSize / 2);
const padRight = Math.floor(padSize / 2);
return `${fill.repeat(padLeft)}${numString}${fill.repeat(padRight)}`;
}
return padding2 + numString;
}
function getSymbolPrefix(symbol, type) {
if (symbol === "#") {
switch (type) {
case "b":
return "0b";
case "o":
return "0o";
case "x":
return "0x";
case "X":
return "0X";
default:
return "";
}
}
return symbol ?? "";
}
// packages/ag-charts-core/src/modules/format/timeFormat.ts
var CONSTANTS = {
periods: ["AM", "PM"],
days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
months: [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
],
shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
};
function dayOfYear(date2, startOfYear = new Date(date2.getFullYear(), 0, 1)) {
const startOffset = date2.getTimezoneOffset() - startOfYear.getTimezoneOffset();
const timeDiff = date2.getTime() - startOfYear.getTime() + startOffset * 6e4;
const timeOneDay = 36e5 * 24;
return Math.floor(timeDiff / timeOneDay);
}
function weekOfYear(date2, startDay) {
const startOfYear = new Date(date2.getFullYear(), 0, 1);
const startOfYearDay = startOfYear.getDay();
const firstWeekStartOffset = (startDay - startOfYearDay + 7) % 7;
const startOffset = new Date(date2.getFullYear(), 0, firstWeekStartOffset + 1);
if (startOffset <= date2) {
return Math.floor(dayOfYear(date2, startOffset) / 7) + 1;
}
return 0;
}
var SUNDAY = 0;
var MONDAY = 1;
var THURSDAY = 4;
function isoWeekOfYear(date2, year = date2.getFullYear()) {
const firstOfYear = new Date(year, 0, 1);
const firstOfYearDay = firstOfYear.getDay();
const firstThursdayOffset = (THURSDAY - firstOfYearDay + 7) % 7;
const startOffset = new Date(year, 0, firstThursdayOffset - (THURSDAY - MONDAY) + 1);
if (startOffset <= date2) {
return Math.floor(dayOfYear(date2, startOffset) / 7) + 1;
}
return isoWeekOfYear(date2, year - 1);
}
function timezone(date2) {
const offset = date2.getTimezoneOffset();
const unsignedOffset = Math.abs(offset);
const sign = offset > 0 ? "-" : "+";
return `${sign}${pad(Math.floor(unsignedOffset / 60), 2, "0")}${pad(Math.floor(unsignedOffset % 60), 2, "0")}`;
}
var FORMATTERS = {
a: (d) => CONSTANTS.shortDays[d.getDay()],
A: (d) => CONSTANTS.days[d.getDay()],
b: (d) => CONSTANTS.shortMonths[d.getMonth()],
B: (d) => CONSTANTS.months[d.getMonth()],
c: "%x, %X",
d: (d, p) => pad(d.getDate(), 2, p ?? "0"),
e: "%_d",
f: (d, p) => pad(d.getMilliseconds() * 1e3, 6, p ?? "0"),
H: (d, p) => pad(d.getHours(), 2, p ?? "0"),
I: (d, p) => {
const hours = d.getHours() % 12;
return hours === 0 ? "12" : pad(hours, 2, p ?? "0");
},
j: (d, p) => pad(dayOfYear(d) + 1, 3, p ?? "0"),
m: (d, p) => pad(d.getMonth() + 1, 2, p ?? "0"),
M: (d, p) => pad(d.getMinutes(), 2, p ?? "0"),
L: (d, p) => pad(d.getMilliseconds(), 3, p ?? "0"),
p: (d) => d.getHours() < 12 ? "AM" : "PM",
Q: (d) => String(d.getTime()),
s: (d) => String(Math.floor(d.getTime() / 1e3)),
S: (d, p) => pad(d.getSeconds(), 2, p ?? "0"),
u: (d) => {
let day = d.getDay();
if (day < 1)
day += 7;
return String(day % 7);
},
U: (d, p) => pad(weekOfYear(d, SUNDAY), 2, p ?? "0"),
V: (d, p) => pad(isoWeekOfYear(d), 2, p ?? "0"),
w: (d, p) => pad(d.getDay(), 2, p ?? "0"),
W: (d, p) => pad(weekOfYear(d, MONDAY), 2, p ?? "0"),
x: "%-m/%-d/%Y",
X: "%-I:%M:%S %p",
y: (d, p) => pad(d.getFullYear() % 100, 2, p ?? "0"),
Y: (d, p) => pad(d.getFullYear(), 4, p ?? "0"),
Z: (d) => timezone(d),
"%": () => "%"
};
var PADS = {
_: " ",
"0": "0",
"-": ""
};
function pad(value, size, padChar) {
const output = String(Math.floor(value));
if (output.length >= size) {
return output;
}
return `${padChar.repeat(size - output.length)}${output}`;
}
function buildDateFormatter(formatString) {
const formatParts = [];
while (formatString.length > 0) {
let nextEscapeIdx = formatString.indexOf("%");
if (nextEscapeIdx !== 0) {
const literalPart = nextEscapeIdx > 0 ? formatString.substring(0, nextEscapeIdx) : formatString;
formatParts.push(literalPart);
}
if (nextEscapeIdx < 0)
break;
const maybePadSpecifier = formatString[nextEscapeIdx + 1];
const maybePad = PADS[maybePadSpecifier];
if (maybePad != null) {
nextEscapeIdx++;
}
const maybeFormatterSpecifier = formatString[nextEscapeIdx + 1];
const maybeFormatter = FORMATTERS[maybeFormatterSpecifier];
if (typeof maybeFormatter === "function") {
formatParts.push([maybeFormatter, maybePad]);
} else if (typeof maybeFormatter === "string") {
const formatter2 = buildDateFormatter(maybeFormatter);
formatParts.push([formatter2, maybePad]);
} else {
formatParts.push(`${maybePad ?? ""}${maybeFormatterSpecifier}`);
}
formatString = formatString.substring(nextEscapeIdx + 2);
}
return (dateTime) => {
const dateTimeAsDate = typeof dateTime === "number" ? new Date(dateTime) : dateTime;
return formatParts.map((c) => typeof c === "string" ? c : c[0](dateTimeAsDate, c[1])).join("");
};
}
// packages/ag-charts-core/src/utils/functions.ts
function debounce(callback2, waitMs = 0, options) {
const { leading = false, trailing = true, maxWait = Infinity } = options ?? {};
let timerId;
let startTime;
if (maxWait < waitMs) {
throw new Error("Value of maxWait cannot be lower than waitMs.");
}
function debounceCallback(...args) {
if (leading && !startTime) {
startTime = Date.now();
timerId = setTimeout(() => startTime = null, waitMs);
callback2(...args);
return;
}
let adjustedWaitMs = waitMs;
if (maxWait !== Infinity && startTime) {
const elapsedTime = Date.now() - startTime;
if (waitMs > maxWait - elapsedTime) {
adjustedWaitMs = maxWait - elapsedTime;
}
}
clearTimeout(timerId);
startTime ?? (startTime = Date.now());
timerId = setTimeout(() => {
startTime = null;
if (trailing) {
callback2(...args);
}
}, adjustedWaitMs);
}
return Object.assign(debounceCallback, {
cancel() {
clearTimeout(timerId);
startTime = null;
}
});
}
function throttle(callback2, waitMs, options) {
const { leading = true, trailing = true } = options ?? {};
let timerId;
let lastArgs;
let shouldWait = false;
function timeoutHandler() {
if (trailing && lastArgs) {
timerId = setTimeout(timeoutHandler, waitMs);
callback2(...lastArgs);
} else {
shouldWait = false;
}
lastArgs = null;
}
function throttleCallback(...args) {
if (shouldWait) {
lastArgs = args;
} else {
shouldWait = true;
timerId = setTimeout(timeoutHandler, waitMs);
if (leading) {
callback2(...args);
} else {
lastArgs = args;
}
}
}
return Object.assign(throttleCallback, {
cancel() {
clearTimeout(timerId);
shouldWait = false;
lastArgs = null;
}
});
}
function safeCall(callback2, args, errorPath = "") {
try {
return callback2(...args);
} catch (error2) {
const postfix = errorPath ? ` \`${errorPath}\`` : "";
warnOnce(`Uncaught exception in user callback${postfix}`, error2);
}
}
// packages/ag-charts-core/src/utils/textUtils.ts
var EllipsisChar = "\u2026";
var LineSplitter = /\r?\n/g;
var TrimEdgeGuard = "\u200B";
function toFontString({ fontSize, fontStyle, fontWeight, fontFamily }) {
let fontString = "";
if (fontStyle && fontStyle !== "normal") {
fontString += `${fontStyle} `;
}
if (fontWeight && fontWeight !== "normal" && fontWeight !== 400) {
fontString += `${fontWeight} `;
}
fontString += `${fontSize}px`;
fontString += ` ${fontFamily}`;
return fontString;
}
function calcLineHeight(fontSize, lineHeightRatio = 1.15) {
return Math.round(fontSize * lineHeightRatio);
}
function toTextString(value) {
return String(value ?? "");
}
var TrimCharsRegex = /[\s.,;:-]{1,5}$/;
function appendEllipsis(text) {
return text.replace(TrimCharsRegex, "") + EllipsisChar;
}
function guardTextEdges(str) {
return TrimEdgeGuard + str + TrimEdgeGuard;
}
function unguardTextEdges(str) {
return str.replaceAll(TrimEdgeGuard, "");
}
function isTruncated(value) {
return isArray(value) ? isSegmentTruncated(value.at(-1)) : isTextTruncated(toTextString(value));
}
function isTextTruncated(str) {
return str.endsWith(EllipsisChar);
}
function isSegmentTruncated(segment) {
return toTextString(segment?.text).endsWith(EllipsisChar);
}
// packages/ag-charts-core/src/utils/strings.ts
function joinFormatted(values, conjunction = "and", format = String, maxItems = Infinity) {
if (values.length === 0) {
return "";
} else if (values.length === 1) {
return format(values[0]);
}
values = values.map(format);
const lastValue = values.pop();
if (values.length >= maxItems) {
const remainingCount = values.length - (maxItems - 1);
return `${values.slice(0, maxItems - 1).join(", ")}, and ${remainingCount} more ${conjunction} ${lastValue}`;
}
return `${values.join(", ")} ${conjunction} ${lastValue}`;
}
function stringifyValue(value, maxLength = Infinity) {
if (typeof value === "number") {
if (Number.isNaN(value)) {
return "NaN";
} else if (value === Infinity) {
return "Infinity";
} else if (value === -Infinity) {
return "-Infinity";
}
}
const strValue = JSON.stringify(value) ?? typeof value;
if (strValue.length > maxLength) {
return `${strValue.slice(0, maxLength)}... (+${strValue.length - maxLength} characters)`;
}
return strValue;
}
function countLines(text) {
let count = 1;
for (let i = 0; i < text.length; i++) {
if (text.codePointAt(i) === 10) {
count++;
}
}
return count;
}
function levenshteinDistance(a, b) {
if (a === b)
return 0;
const [shorter, longer] = a.length < b.length ? [a, b] : [b, a];
const m = shorter.length;
const n = longer.length;
let prevRow = new Array(m + 1).fill(0).map((_, i) => i);
let currRow = new Array(m + 1);
for (let i = 1; i <= n; i++) {
currRow[0] = i;
for (let j = 1; j <= m; j++) {
const cost = longer[i - 1] === shorter[j - 1] ? 0 : 1;
currRow[j] = Math.min(
prevRow[j] + 1,
// Deletion
currRow[j - 1] + 1,
// Insertion
prevRow[j - 1] + cost
// Substitution
);
}
[prevRow, currRow] = [currRow, prevRow];
}
return prevRow[m];
}
function kebabCase(a) {
return a.replaceAll(KEBAB_CASE_REGEX, (match, offset) => (offset > 0 ? "-" : "") + match.toLowerCase());
}
var KEBAB_CASE_REGEX = /[A-Z]+(?![a-z])|[A-Z]/g;
function toPlainText(text, fallback = "") {
if (text == null) {
return fallback;
} else if (isArray(text)) {
return text.map((segment) => toTextString(segment.text)).join("");
} else if (isString(text)) {
return text;
} else {
return String(text);
}
}
// packages/ag-charts-core/src/utils/validation.ts
var descriptionSymbol = Symbol("description");
var requiredSymbol = Symbol("required");
var markedSymbol = Symbol("marked");
var undocumentedSymbol = Symbol("undocumented");
var unionSymbol = Symbol("union");
var similarOptionsMap = [
["placement", "position"],
["padding", "spacing", "gap"],
["color", "fill", "stroke"],
["whisker", "wick"],
["nodeClick", "seriesNodeClick"],
["nodeDoubleClick", "seriesNodeDoubleClick"],
["src", "url"]
].reduce((map, words) => {
for (const word of words) {
map.set(word.toLowerCase(), new Set(words.filter((w) => w !== word)));
}
return map;
}, /* @__PURE__ */ new Map());
var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
ErrorType2["Invalid"] = "invalid";
ErrorType2["Required"] = "required";
ErrorType2["Unknown"] = "unknown";
return ErrorType2;
})(ErrorType || {});
function extendPath(path, key) {
if (isFiniteNumber(key)) {
return `${path}[${key}]`;
}
return path ? `${path}.${key}` : key;
}
var ValidationError = class {
constructor(type, description, value, path, key) {
this.type = type;
this.description = description;
this.value = value;
this.path = path;
this.key = key;
}
setUnionType(unionType, path) {
if (this.path.startsWith(path)) {
const suffix = this.path.slice(path.length);
this.altPath = `${path}[type=${unionType}]${suffix}`;
}
}
getPrefix() {
const { altPath: path = this.path, key } = this;
if (!path && !key)
return "Value";
return `Option \`${key ? extendPath(path, key) : path}\``;
}
toString() {
const { description = "unknown", type, value } = this;
if (type === "required" /* Required */ && value == null) {
return `${this.getPrefix()} is required and has not been provided; expecting ${description}, ignoring.`;
}
return `${this.getPrefix()} cannot be set to \`${stringifyValue(value, 50)}\`; expecting ${description}, ignoring.`;
}
};
var UnknownError = class extends ValidationError {
constructor(suggestions, value, path, key) {
super("unknown" /* Unknown */, void 0, value, path, key);
this.suggestions = suggestions;
this.key = key;
}
getPrefix() {
return `Unknown option \`${extendPath(this.altPath ?? this.path, this.key)}\``;
}
getPostfix() {
const suggestions = joinFormatted(findSuggestions(this.key, this.suggestions), "or", (val) => `\`${val}\``);
return suggestions ? `; Did you mean ${suggestions}? Ignoring.` : ", ignoring.";
}
toString() {
return `${this.getPrefix()}${this.getPostfix()}`;
}
};
function validate(options, optionsDefs2, path = "") {
if (!isObject(options)) {
return { cleared: null, invalid: [new ValidationError("required" /* Required */, "an object", options, path)] };
}
const cleared = {};
const invalid = [];
const optionsKeys = new Set(Object.keys(options));
const unusedKeys = [];
if (unionSymbol in optionsDefs2) {
const validTypes = Object.keys(optionsDefs2);
const defaultType = optionsDefs2[unionSymbol];
if (options.type != null && validTypes.includes(options.type) || options.type == null && defaultType != null) {
const { type = defaultType, ...rest } = options;
const nestedResult = validate(rest, optionsDefs2[type], path);
Object.assign(cleared, { type }, nestedResult.cleared);
for (const error2 of nestedResult.invalid) {
error2.setUnionType(type, path);
}
invalid.push(...nestedResult.invalid);
} else {
const keywords = joinFormatted(validTypes, "or", (val) => `'${val}'`);
invalid.push(
new ValidationError("required" /* Required */, `a keyword such as ${keywords}`, options.type, path, "type")
);
}
return { cleared, invalid };
}
for (const key of Object.keys(optionsDefs2)) {
const validatorOrDefs = optionsDefs2[key];
const required3 = validatorOrDefs[requiredSymbol];
const value = options[key];
optionsKeys.delete(key);
if (value === void 0) {
if (!validatorOrDefs[undocumentedSymbol]) {
unusedKeys.push(key);
}
if (!required3)
continue;
}
const keyPath = extendPath(path, key);
if (isFunction(validatorOrDefs)) {
const context = { options, path: keyPath };
const validatorResult = validatorOrDefs(value, context);
const objectResult = typeof validatorResult === "object";
if (objectResult) {
invalid.push(...validatorResult.invalid);
if (validatorResult.valid) {
cleared[key] = validatorResult.cleared;
continue;
} else if (hasRequiredInPath(validatorResult.invalid, keyPath)) {
continue;
}
} else if (validatorResult) {
cleared[key] = value;
continue;
}
invalid.push(
new ValidationError(
required3 ? "required" /* Required */ : "invalid" /* Invalid */,
validatorOrDefs[descriptionSymbol],
value,
path,
key
)
);
} else {
const nestedResult = validate(value, validatorOrDefs, keyPath);
if (nestedResult.cleared != null) {
cleared[key] = nestedResult.cleared;
}
invalid.push(...nestedResult.invalid);
}
}
for (const key of optionsKeys) {
const value = options[key];
if (value === void 0)
continue;
invalid.push(new UnknownError(unusedKeys, value, path, key));
}
return { cleared, invalid };
}
function findSuggestions(value, suggestions, maxDistance = 2) {
const lowerCaseValue = value.toLowerCase();
const similarValues = similarOptionsMap.get(lowerCaseValue);
return suggestions.filter((key) => {
const lowerCaseKey = key.toLowerCase();
return similarValues?.has(key) === true || lowerCaseKey.includes(lowerCaseValue) || levenshteinDistance(lowerCaseValue, lowerCaseKey) <= maxDistance;
});
}
function attachDescription(validatorOrDefs, description) {
if (isFunction(validatorOrDefs)) {
let clonedValidator2 = function(value, context) {
return validatorOrDefs(value, context);
};
var clonedValidator = clonedValidator2;
clonedValidator2[descriptionSymbol] = description;
return clonedValidator2;
} else {
return { ...validatorOrDefs, [descriptionSymbol]: description };
}
}
function required(validatorOrDefs) {
return Object.assign(
isFunction(validatorOrDefs) ? (value, context) => validatorOrDefs(value, context) : optionsDefs(validatorOrDefs),
{ [requiredSymbol]: true, [descriptionSymbol]: validatorOrDefs[descriptionSymbol] }
);
}
function undocumented(validatorOrDefs) {
return Object.assign(
isFunction(validatorOrDefs) ? (value, context) => validatorOrDefs(value, context) : optionsDefs(validatorOrDefs),
{ [undocumentedSymbol]: true, [descriptionSymbol]: validatorOrDefs[descriptionSymbol] }
);
}
var optionsDefs = (defs, description = "an object", failAll = false) => attachDescription((value, context) => {
const result = validate(value, defs, context.path);
const valid = !hasRequiredInPath(result.invalid, context.path);
return { valid, cleared: valid || !failAll ? result.cleared : null, invalid: result.invalid };
}, description);
var typeUnion = (defs, description, defaultType) => ({
...defs,
[descriptionSymbol]: description,
[unionSymbol]: defaultType
});
var and = (...validators) => attachDescription(
(value, context) => {
const invalid = [];
for (const validator of validators) {
const result = validator(value, context);
if (typeof result === "object") {
invalid.push(...result.invalid);
if (!result.valid) {
return { valid: false, cleared: value, invalid };
}
value = result.cleared;
} else if (!result) {
return false;
}
}
return { valid: true, cleared: value, invalid };
},
joinFormatted(
validators.filter((v) => !v[undocumentedSymbol]).map((v) => v[descriptionSymbol]).filter(isDefined),
"and"
)
);
var or = (...validators) => attachDescription(
(value, context) => {
for (const validator of validators) {
const result = validator(value, context);
if (typeof result === "object" ? result.valid : result) {
return result;
}
}
return false;
},
joinFormatted(
validators.filter((v) => !v[undocumentedSymbol]).map((v) => v[descriptionSymbol]).filter(isDefined),
"or"
)
);
var isComparable = (value) => isFiniteNumber(value) || isValidDate(value);
var isValidDateValue = (value) => isDate(value) || (isFiniteNumber(value) || isString(value)) && isValidDate(new Date(value));
var array = attachDescription(isArray, "an array");
var boolean = attachDescription(isBoolean, "a boolean");
var callback = attachDescription(isFunction, "a function");
var color = attachDescription(isColor, "a color string");
var date = attachDescription(isValidDateValue, "a date");
var defined = attachDescription(isDefined, "a defined value");
var number = attachDescription(isFiniteNumber, "a number");
var object = attachDescription(isObject, "an object");
var string = attachDescription(isString, "a string");
var htmlElement = attachDescription(
(value) => typeof HTMLElement === "undefined" || value instanceof HTMLElement,
"an html element"
);
var arrayLength = (minLength, maxLength = Infinity) => {
let message;
if (maxLength === Infinity) {
message = `an array of at least ${minLength} items`;
} else if (minLength === maxLength) {
message = `an array of exactly ${minLength} items`;
} else if (minLength === 0) {
message = `an array of no more than ${maxLength} items`;
} else {
message = `an array of at least ${minLength} and no more than ${maxLength} items`;
}
return attachDescription(
(value) => isArray(value) && value.length >= minLength && value.length <= maxLength,
message
);
};
var stringLength = (minLength, maxLength = Infinity) => {
let message;
if (maxLength === Infinity) {
message = `a string of at least ${minLength} characters`;
} else if (minLength === maxLength) {
message = `an string of exactly ${minLength} characters`;
} else if (minLength === 0) {
message = `an string of no more than ${maxLength} characters`;
} else {
message = `an string of at least ${minLength} and no more than ${maxLength} characters`;
}
return attachDescription(
(value) => isString(value) && value.length >= minLength && value.length <= maxLength,
message
);
};
var numberMin = (min, inclusive = true) => attachDescription(
(value) => isFiniteNumber(value) && (value > min || inclusive && value === min),
`a number greater than ${inclusive ? "or equal to " : ""}${min}`
);
var numberRange = (min, max) => attachDescription(
(value) => isFiniteNumber(value) && value >= min && value <= max,
`a number betwe