autotel
Version:
Write Once, Observe Anywhere
151 lines (150 loc) • 6.15 kB
JavaScript
//#region src/values.ts
/** The value as an object, or undefined when it is anything else. */
function asRecord(value) {
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
}
/** The string the value carries, or undefined when it carries anything else. */
function asString(value) {
return typeof value === "string" ? value : void 0;
}
/**
* The value as a map of strings - a header bag, say - or undefined when it is
* not an object at all. Entries whose value is not a string are left out.
*/
function asStringRecord(value) {
const record = asRecord(value);
if (record === void 0) return void 0;
const strings = {};
for (const [key, entry] of Object.entries(record)) {
const text = asString(entry);
if (text !== void 0) strings[key] = text;
}
return strings;
}
/** The scalar the value carries - string, number or boolean - or undefined. */
function asScalar(value) {
return asString(value) ?? asNumber(value) ?? asBoolean(value);
}
/** The numbers the value carries as a list, or undefined when it is not one. */
function asNumberArray(value) {
return Array.isArray(value) && value.every((v) => asNumber(v) !== void 0) ? value.map(Number) : void 0;
}
/** The booleans the value carries as a list, or undefined when it is not one. */
function asBooleanArray(value) {
return Array.isArray(value) && value.every((v) => asBoolean(v) !== void 0) ? value.map(Boolean) : void 0;
}
/** The strings the value carries as a list, or undefined when it is not one. */
function asStringArray(value) {
return Array.isArray(value) && value.every((v) => asString(v) !== void 0) ? value.map(String) : void 0;
}
/** A string with something in it - a blank one counts as absent. */
function nonEmptyString(value) {
const text = asString(value);
return text !== void 0 && text.trim() !== "" ? text : void 0;
}
/** The number the value carries, or undefined when it carries anything else. */
function asNumber(value) {
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
}
/** The boolean the value carries, or undefined when it carries anything else. */
function asBoolean(value) {
return typeof value === "boolean" ? value : void 0;
}
/** Whether the value is callable. */
function isFunction(value) {
return typeof value === "function";
}
/**
* A config field that may be given as a value or as a function producing one,
* resolved to the value.
*/
function resolveValue(source) {
return typeof source === "function" ? source() : source;
}
/**
* An overloaded first argument that is either a name or an options object,
* split into the two.
*/
function splitNameOrOptions(value) {
return typeof value === "string" ? { name: value } : { options: value };
}
/** The value as a callable, or undefined when it is not one. */
function asFunction(value) {
if (typeof value !== "function") return void 0;
return value;
}
/**
* The value as a plain object - one built from a literal, not an instance of
* some class that has its own idea of what it is.
*/
function asPlainRecordOrMap(value) {
if (value instanceof Map) {
const entries = {};
for (const [key, entry] of value) entries[String(key)] = entry;
return entries;
}
return asPlainRecord(value);
}
function asPlainRecord(value) {
const record = asRecord(value);
return record !== void 0 && Object.getPrototypeOf(record) === Object.prototype ? record : void 0;
}
/** One field of a value, when the value is an object at all. */
function readProperty(source, key) {
return asRecord(source)?.[key];
}
/**
* What a value is, for a diagnostic message: the same words `typeof` uses,
* plus `null` and `array`, which are the two cases `typeof` answers uselessly.
*/
function describeValue(value) {
if (value === null) return "null";
return Array.isArray(value) ? "array" : typeof value;
}
/**
* The Error a caller's callback expects, wrapping whatever was actually
* thrown - a string, a number, an object with no stack.
*/
function toError(cause) {
return cause instanceof Error ? cause : new Error(String(cause));
}
/**
* A value as an OTel attribute, or undefined when it cannot be one.
*
* OTel accepts scalars and homogeneous arrays of scalars. Anything else - a
* nested object, a mixed array - is stringified rather than dropped, because
* a caller that attached it wanted to see it.
*/
function toAttributeValue(value) {
if (value === void 0 || value === null) return void 0;
const scalar = asString(value) ?? asNumber(value) ?? asBoolean(value);
if (scalar !== void 0) return scalar;
if (Array.isArray(value)) return toAttributeArray(value);
if (value instanceof Set) return toAttributeArray([...value]);
if (value instanceof Map) return JSON.stringify(Object.fromEntries(value));
return JSON.stringify(value);
}
/** The scalars in an array, dropping the entries OTel cannot carry. */
function toAttributeArray(values) {
const strings = values.filter((v) => typeof v === "string");
if (strings.length === values.length) return strings;
const numbers = values.filter((v) => typeof v === "number");
if (numbers.length === values.length) return numbers;
const booleans = values.filter((v) => typeof v === "boolean");
if (booleans.length === values.length) return booleans;
return values.length > 0 ? JSON.stringify(values) : void 0;
}
/** Whether a Node-style `process` global exists at all - edge runtimes have none. */
function hasProcess() {
return typeof process !== "undefined";
}
/**
* Whether this build is running outside production, for warnings meant to
* help during development. `process` is probed because the same code runs in
* edge runtimes that have no such global.
*/
function isDevelopment() {
return hasProcess() && process.env.NODE_ENV !== "production";
}
//#endregion
export { readProperty as _, asNumberArray as a, toAttributeValue as b, asScalar as c, asStringRecord as d, describeValue as f, nonEmptyString as g, isFunction as h, asNumber as i, asString as l, isDevelopment as m, asBooleanArray as n, asPlainRecordOrMap as o, hasProcess as p, asFunction as r, asRecord as s, asBoolean as t, asStringArray as u, resolveValue as v, toError as x, splitNameOrOptions as y };