autotel
Version:
Write Once, Observe Anywhere
277 lines (275 loc) • 8.32 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
Object.defineProperty(exports, 'asBoolean', {
enumerable: true,
get: function () {
return asBoolean;
}
});
Object.defineProperty(exports, 'asBooleanArray', {
enumerable: true,
get: function () {
return asBooleanArray;
}
});
Object.defineProperty(exports, 'asFunction', {
enumerable: true,
get: function () {
return asFunction;
}
});
Object.defineProperty(exports, 'asNumber', {
enumerable: true,
get: function () {
return asNumber;
}
});
Object.defineProperty(exports, 'asNumberArray', {
enumerable: true,
get: function () {
return asNumberArray;
}
});
Object.defineProperty(exports, 'asPlainRecordOrMap', {
enumerable: true,
get: function () {
return asPlainRecordOrMap;
}
});
Object.defineProperty(exports, 'asRecord', {
enumerable: true,
get: function () {
return asRecord;
}
});
Object.defineProperty(exports, 'asScalar', {
enumerable: true,
get: function () {
return asScalar;
}
});
Object.defineProperty(exports, 'asString', {
enumerable: true,
get: function () {
return asString;
}
});
Object.defineProperty(exports, 'asStringArray', {
enumerable: true,
get: function () {
return asStringArray;
}
});
Object.defineProperty(exports, 'asStringRecord', {
enumerable: true,
get: function () {
return asStringRecord;
}
});
Object.defineProperty(exports, 'describeValue', {
enumerable: true,
get: function () {
return describeValue;
}
});
Object.defineProperty(exports, 'hasProcess', {
enumerable: true,
get: function () {
return hasProcess;
}
});
Object.defineProperty(exports, 'isDevelopment', {
enumerable: true,
get: function () {
return isDevelopment;
}
});
Object.defineProperty(exports, 'isFunction', {
enumerable: true,
get: function () {
return isFunction;
}
});
Object.defineProperty(exports, 'nonEmptyString', {
enumerable: true,
get: function () {
return nonEmptyString;
}
});
Object.defineProperty(exports, 'readProperty', {
enumerable: true,
get: function () {
return readProperty;
}
});
Object.defineProperty(exports, 'resolveValue', {
enumerable: true,
get: function () {
return resolveValue;
}
});
Object.defineProperty(exports, 'splitNameOrOptions', {
enumerable: true,
get: function () {
return splitNameOrOptions;
}
});
Object.defineProperty(exports, 'toAttributeValue', {
enumerable: true,
get: function () {
return toAttributeValue;
}
});
Object.defineProperty(exports, 'toError', {
enumerable: true,
get: function () {
return toError;
}
});