@prismatic-io/spectral
Version:
Utility library for building Prismatic connectors and code-native integrations
827 lines (826 loc) • 31.7 kB
JavaScript
;
/**
* The `util` module provides a set of functions commonly needed to author custom components.
* Many functions in the `util` module are used to coerce data into a particular type, and can be accessed through `util.types`.
* For example, `util.types.toInt("5.5")` will return an integer, `5`.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.toObject = exports.lowerCaseHeaders = exports.isObjectWithTruthyKeys = exports.isObjectWithOneTruthyKey = void 0;
const fromUnixTime_1 = require("date-fns/fromUnixTime");
const isDate_1 = require("date-fns/isDate");
const isValid_1 = require("date-fns/isValid");
const parseISO_1 = require("date-fns/parseISO");
const omitBy_1 = __importDefault(require("lodash/omitBy"));
const safe_stable_stringify_1 = require("safe-stable-stringify");
const valid_url_1 = require("valid-url");
const isObjectWithOneTruthyKey = (value, keys) => {
return (value !== null &&
typeof value === "object" &&
keys.some((key) => key in value && Boolean(value === null || value === void 0 ? void 0 : value[key])));
};
exports.isObjectWithOneTruthyKey = isObjectWithOneTruthyKey;
const isObjectWithTruthyKeys = (value, keys) => {
return (value !== null &&
typeof value === "object" &&
keys.every((key) => key in value && Boolean(value === null || value === void 0 ? void 0 : value[key])));
};
exports.isObjectWithTruthyKeys = isObjectWithTruthyKeys;
/**
* This function checks if value is an Element.
*
* @param value The variable to test.
* @returns This function returns true or false, depending on if `value` is an Element.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isElement({ key: "foo" }); // true
* util.types.isElement({ key: "foo", label: "Foo" }); // true
* util.types.isElement("foo"); // false
* util.types.isElement({}); // false
*/
const isElement = (value) => (0, exports.isObjectWithTruthyKeys)(value, ["key"]);
/**
* Checks if a value is a valid ObjectSelection (an array of objects each with an `object` property).
*
* @param value The value to test
* @returns This function returns true if the type of `value` is an ObjectSelection, or false otherwise.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isObjectSelection([{ object: { key: "account" } }]); // true
* util.types.isObjectSelection("not an object selection"); // false
*/
const isObjectSelection = (value) => {
if (typeof value === "string" && isJSON(value)) {
return isObjectSelection(JSON.parse(value));
}
return Array.isArray(value) && value.every((item) => (0, exports.isObjectWithTruthyKeys)(item, ["object"]));
};
/**
* This function coerces a provided value into an ObjectSelection if possible.
* If the value is a JSON string it will be parsed first. Throws an error if
* the value cannot be coerced.
*
* @param value The value to coerce to ObjectSelection.
* @returns This function returns the value as an ObjectSelection if possible.
* @example
* import { util } from "@prismatic-io/spectral";
*
* const selection = util.types.toObjectSelection([
* { object: { key: "account", label: "Account" }, fields: [{ key: "name" }] },
* ]);
*
* // Also accepts a JSON string representation
* const fromString = util.types.toObjectSelection(
* '[{"object":{"key":"account"}}]'
* );
*/
const toObjectSelection = (value) => {
if (typeof value === "string" && isJSON(value)) {
return toObjectSelection(JSON.parse(value));
}
if (isObjectSelection(value)) {
return value;
}
throw new Error(`Value '${typeof value === "string" ? value : JSON.stringify(value)}' cannot be coerced to ObjectSelection.`);
};
/**
* Checks if a value is a valid ObjectFieldMap (an object with a `fields` array,
* where each field has a `field` property that is an Element).
*
* @param value The value to test
* @returns This function returns true if the type of `value` is an ObjectFieldMap, or false otherwise.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isObjectFieldMap({
* fields: [{ field: { key: "name", label: "Name" } }],
* }); // true
* util.types.isObjectFieldMap("not a field map"); // false
*/
const isObjectFieldMap = (value) => {
if (typeof value === "string" && isJSON(value)) {
return isObjectFieldMap(JSON.parse(value));
}
if (value && typeof value === "object") {
const { fields } = value;
return (Array.isArray(fields) &&
fields.every((item) => (0, exports.isObjectWithTruthyKeys)(item, ["field"]) &&
isElement(item === null || item === void 0 ? void 0 : item.field)));
}
return false;
};
/**
* This function coerces a provided value into an ObjectFieldMap if possible.
* If the value is a JSON string it will be parsed first. Throws an error if
* the value cannot be coerced.
*
* @param value The value to coerce to ObjectFieldMap.
* @returns This function returns the value as an ObjectFieldMap if possible.
* @example
* import { util } from "@prismatic-io/spectral";
*
* const fieldMap = util.types.toObjectFieldMap({
* fields: [
* { field: { key: "email", label: "Email" }, mappedField: { key: "contact_email" } },
* ],
* });
*/
const toObjectFieldMap = (value) => {
if (typeof value === "string" && isJSON(value)) {
return toObjectFieldMap(JSON.parse(value));
}
if (isObjectFieldMap(value)) {
return value;
}
throw new Error(`Value '${typeof value === "string" ? value : JSON.stringify(value)}' cannot be coerced to ObjectFieldMap.`);
};
/**
* Checks if a value is a valid JSONForm (an object with `schema`, `uiSchema`, and `data` properties).
*
* @param value The value to test
* @returns This function returns true if the type of `value` is a JSONForm, or false otherwise.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isJSONForm({
* schema: { type: "object", properties: { name: { type: "string" } } },
* uiSchema: { type: "VerticalLayout", elements: [] },
* data: { name: "Example" },
* }); // true
* util.types.isJSONForm({ schema: {} }); // false (missing uiSchema and data)
*/
const isJSONForm = (value) => {
if (typeof value === "string" && isJSON(value)) {
return isJSONForm(JSON.parse(value));
}
return (0, exports.isObjectWithTruthyKeys)(value, ["schema", "uiSchema", "data"]);
};
/**
* This function coerces a provided value into a JSONForm if possible.
* If the value is a JSON string it will be parsed first. Throws an error if
* the value cannot be coerced.
*
* @param value The value to coerce to JSONForm.
* @returns This function returns the value as a JSONForm if possible.
* @example
* import { util } from "@prismatic-io/spectral";
*
* const form = util.types.toJSONForm({
* schema: { type: "object", properties: { name: { type: "string" } } },
* uiSchema: { type: "VerticalLayout", elements: [] },
* data: { name: "Default Name" },
* });
*/
const toJSONForm = (value) => {
if (typeof value === "string" && isJSON(value)) {
return toJSONForm(JSON.parse(value));
}
if (isJSONForm(value)) {
return value;
}
throw new Error(`Value '${typeof value === "string" ? value : JSON.stringify(value)}' cannot be coerced to JSONForm.`);
};
/**
* Determine if a variable is a boolean (true or false).
*
* @param value The variable to test.
* @returns True if the value is a boolean, or false otherwise.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isBool(false); // true
* util.types.isBool(true); // true
* util.types.isBool("Hello"); // false
* util.types.isBool(0); // false
*/
const isBool = (value) => value === true || value === false;
/**
* Convert truthy (true, "t", "true", "y", "yes") values to boolean `true`,
* and falsy (false, "f", "false", "n", "no") values to boolean `false`.
* Truthy/falsy checks are case-insensitive.
*
* In the event that `value` is undefined or an empty string, a default value can be provided.
*
* @param value The value to convert to a boolean.
* @param defaultValue The value to return if `value` is undefined or an empty string.
* @returns The boolean equivalent of the truthy or falsy `value`.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.toBool("true"); // true
* util.types.toBool("YES"); // true
* util.types.toBool("f"); // false
* util.types.toBool("no"); // false
* util.types.toBool("", true); // true (uses default)
* util.types.toBool(undefined, false); // false (uses default)
*/
const toBool = (value, defaultValue) => {
if (isBool(value)) {
return value;
}
if (typeof value === "string") {
const lowerValue = value.toLowerCase();
if (["t", "true", "y", "yes"].includes(lowerValue)) {
return true;
}
else if (["f", "false", "n", "no"].includes(lowerValue)) {
return false;
}
}
return Boolean(value || defaultValue);
};
/**
* This function checks if value is an integer.
*
* @param value The variable to test.
* @returns This function returns true or false, depending on if `value` is an integer.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isInt(5); // true
* util.types.isInt(-3); // true
* util.types.isInt("5"); // false (string, not a number)
* util.types.isInt(5.5); // false (float, not an integer)
*/
const isInt = (value) => Number.isInteger(value);
/**
* This function converts a variable to an integer if possible.
* Floats are truncated (not rounded). Throws an error if `value`
* cannot be coerced and no `defaultValue` is provided.
*
* @param value The value to convert to an integer.
* @param defaultValue The value to return if `value` is undefined, an empty string, or not able to be coerced.
* @returns This function returns an integer if possible.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.toInt(5.5); // 5
* util.types.toInt("20.3"); // 20
* util.types.toInt("", 1); // 1 (uses default)
* util.types.toInt(undefined, 42); // 42 (uses default)
* util.types.toInt("abc"); // throws Error
*/
const toInt = (value, defaultValue) => {
if (isInt(value))
return value;
// Turn a float into an int
if (typeof value === "number") {
return ~~value;
}
if (typeof value === "string") {
const intValue = Number.parseInt(value, 10);
if (!Number.isNaN(intValue)) {
return intValue;
}
}
if (typeof value === "undefined" || value === "") {
return defaultValue || 0;
}
if (defaultValue) {
return defaultValue;
}
throw new Error(`Value '${value}' cannot be coerced to int.`);
};
/**
* Determine if a variable is a number, or can easily be coerced into a number.
*
* @param value The variable to test.
* @returns This function returns true if `value` can easily be coerced into a number, and false otherwise.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isNumber(3.21); // true
* util.types.isNumber("5.5"); // true (string is numeric)
* util.types.isNumber("Hello"); // false
*/
const isNumber = (value) => !Number.isNaN(Number(value));
/**
* This function coerces a value (number or string) into a number.
* In the event that `value` is undefined, null, or an empty string, a `defaultValue` can be provided, or zero will be returned.
* If `value` is not able to be coerced into a number but is defined, an error will be thrown.
*
* @param value The value to turn into a number.
* @param defaultValue The value to return if `value` is undefined, null, or an empty string.
* @returns This function returns the numerical version of `value` if possible, or the `defaultValue` if `value` is undefined or an empty string.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.toNumber("3.22"); // 3.22
* util.types.toNumber("", 5.5); // 5.5 (uses default)
* util.types.toNumber(null, 5.5); // 5.5 (uses default)
* util.types.toNumber(undefined); // 0 (no default given)
* util.types.toNumber("Hello"); // throws Error
*/
const toNumber = (value, defaultValue) => {
if (typeof value === "undefined" || value === "" || value === null) {
return defaultValue || 0;
}
if (isNumber(value)) {
return Number(value);
}
throw new Error(`Value '${value}' cannot be coerced to a number.`);
};
/**
* Checks if a value is a bigint.
*
* @param value The value to test
* @returns This function returns true if the type of `value` is a bigint, or false otherwise.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isBigInt(3n); // true
* util.types.isBigInt(3); // false (number, not bigint)
* util.types.isBigInt("3"); // false
*/
const isBigInt = (value) => typeof value === "bigint";
/**
* This function coerces a provided value into a bigint if possible.
* The provided `value` must be a bigint, integer, string representing an integer, or a boolean.
* Throws an error if the value cannot be coerced.
*
* @param value The value to coerce to bigint.
* @returns This function returns the bigint representation of `value`.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.toBigInt(3); // 3n
* util.types.toBigInt("-5"); // -5n
* util.types.toBigInt(true); // 1n
* util.types.toBigInt(false); // 0n
* util.types.toBigInt("5.5"); // throws Error (not an integer)
*/
const toBigInt = (value) => {
if (isBigInt(value)) {
return value;
}
try {
return BigInt(toString(value));
}
catch (_error) {
throw new Error(`Value '${value}' cannot be coerced to bigint.`);
}
};
/**
* This function returns true if `value` is a variable of type `Date`, and false otherwise.
*
* @param value The variable to test.
* @returns True if value is a Date object, false otherwise.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isDate(new Date()); // true
* util.types.isDate("2021-03-20"); // false (string, not Date)
* util.types.isDate(1616198400); // false (number, not Date)
*/
const isDate = (value) => (0, isDate_1.isDate)(value);
/**
* This function parses an ISO date string or UNIX epoch timestamp if possible,
* or throws an error if the value provided cannot be coerced into a Date object.
*
* @param value The value to turn into a date. Accepts a Date object, ISO date string, or UNIX epoch timestamp (seconds).
* @returns The date equivalent of `value`.
* @example
* import { util } from "@prismatic-io/spectral";
*
* // Pass through an existing Date object
* util.types.toDate(new Date("1995-12-17T03:24:00"));
*
* // Parse an ISO date string
* util.types.toDate("2021-03-20"); // Date object for 2021-03-20
*
* // Parse a UNIX epoch timestamp (in seconds)
* util.types.toDate(1616198400); // Date object for 2021-03-20
*
* // Invalid input throws an error
* util.types.toDate("not-a-date"); // throws Error
*/
const toDate = (value) => {
if (isDate(value)) {
return value;
}
if (isNumber(value) && toNumber(value)) {
return (0, fromUnixTime_1.fromUnixTime)(toNumber(value));
}
if (typeof value === "string") {
const dt = (0, parseISO_1.parseISO)(value);
if ((0, isValid_1.isValid)(dt)) {
return dt;
}
}
throw new Error(`Value '${value}' cannot be coerced to date.`);
};
/**
* This function tests if the string provided is a valid URL, and returns `true` if the URL is valid.
* Note: this function only tests that the string is a syntactically correct URL; it does not check
* if the URL is web accessible.
*
* @param value The URL to test.
* @returns This function returns true if `value` is a valid URL, and false otherwise.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isUrl("https://prismatic.io"); // true
* util.types.isUrl("http://example.com/path?q=1"); // true
* util.types.isUrl("https:://prismatic.io"); // false (malformed)
* util.types.isUrl("not a url"); // false
*/
const isUrl = (value) => (0, valid_url_1.isWebUri)(value) !== undefined;
/**
* This function checks if value is a valid picklist. A picklist is an array
* of strings or an array of Element objects (objects with a `key` property).
*
* @param value The variable to test.
* @returns This function returns true if `value` is a valid picklist.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isPicklist(["option1", "option2"]); // true
* util.types.isPicklist([{ key: "a", label: "Option A" }]); // true
* util.types.isPicklist("not a picklist"); // false
* util.types.isPicklist([1, 2, 3]); // false
*/
const isPicklist = (value) => Array.isArray(value) && (value.every(isString) || value.every(isElement));
/**
* This function checks if value is a valid schedule (an object with a truthy `value` property).
*
* @param value The variable to test.
* @returns This function returns true if `value` is a valid schedule.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isSchedule({ value: "00 00 * * 2,3" }); // true
* util.types.isSchedule({
* value: "00 00 * * 2,3",
* schedule_type: "week",
* time_zone: "America/Chicago",
* }); // true
* util.types.isSchedule("not a schedule"); // false
*/
const isSchedule = (value) => (0, exports.isObjectWithTruthyKeys)(value, ["value"]);
/**
* This function helps to transform key-value lists to objects.
* This is useful for transforming inputs that use the `keyvaluelist` collection type
* into plain objects.
*
* @param kvpList An array of objects with `key` and `value` properties.
* @param valueConverter Optional function to call for each `value`.
* @returns A plain object with keys and values from the input array.
* @example
* import { util } from "@prismatic-io/spectral";
*
* const headers = [
* { key: "Content-Type", value: "application/json" },
* { key: "Authorization", value: "Bearer abc123" },
* ];
* util.types.keyValPairListToObject(headers);
* // { "Content-Type": "application/json", "Authorization": "Bearer abc123" }
*
* @example
* import { util } from "@prismatic-io/spectral";
*
* // With a value converter
* const params = [
* { key: "limit", value: "10" },
* { key: "offset", value: "0" },
* ];
* util.types.keyValPairListToObject(params, (v) => Number(v));
* // { limit: 10, offset: 0 }
*/
const keyValPairListToObject = (kvpList, valueConverter) => {
return (kvpList || []).reduce((result, { key, value }) => (Object.assign(Object.assign({}, result), { [key]: valueConverter ? valueConverter(value) : value })), {});
};
/**
* This function tests if the object provided is a Prismatic `DataPayload` object.
* A `DataPayload` object is an object with a `data` attribute that is a Buffer, and optional `contentType` attribute.
*
* @param value The value to test
* @returns This function returns true if `value` is a DataPayload object, and false otherwise.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isBufferDataPayload({
* data: Buffer.from("hello"),
* contentType: "text/plain",
* }); // true
* util.types.isBufferDataPayload("hello"); // false
* util.types.isBufferDataPayload({ data: "not a buffer" }); // false
*/
const isBufferDataPayload = (value) => value instanceof Object && "data" in value && Buffer.isBuffer(value.data);
/**
* Many libraries for third-party APIs that handle binary files expect `Buffer` objects.
* This function helps to convert strings, Uint8Arrays, objects, and arrays to a
* `DataPayload` structure that has a Buffer and a string representing `contentType`.
*
* Throws an error if `value` cannot be converted to a Buffer.
*
* @param value The string, Buffer, Uint8Array, object, or Array to convert to a Buffer.
* @returns An object with two keys: `data` (a `Buffer`) and `contentType` (a string).
* @example
* import { util } from "@prismatic-io/spectral";
*
* // Convert a string (becomes text/plain)
* const { data, contentType } = util.types.toBufferDataPayload("Hello, world!");
* // data: Buffer, contentType: "text/plain"
*
* // Convert an object (becomes application/json)
* const jsonPayload = util.types.toBufferDataPayload({ key: "value" });
* // jsonPayload.contentType === "application/json"
*
* // Pass through an existing DataPayload
* const existing = { data: Buffer.from("binary"), contentType: "application/octet-stream" };
* util.types.toBufferDataPayload(existing); // returns as-is
*/
const toBufferDataPayload = (value) => {
if (isBufferDataPayload(value)) {
return value;
}
if (typeof value === "string") {
return {
data: Buffer.from(value, "utf-8"),
contentType: "text/plain",
};
}
if (value instanceof Buffer) {
return {
data: value,
contentType: "application/octet-stream",
};
}
if (value instanceof Uint8Array) {
return {
data: Buffer.from(value),
contentType: "application/octet-stream",
};
}
if (value instanceof Object || Array.isArray(value)) {
const json = JSON.stringify(value);
return {
data: Buffer.from(json, "utf-8"),
contentType: "application/json",
};
}
throw new Error(`Value '${value}' cannot be converted to a Buffer.`);
};
/**
* @deprecated This function tests if the object provided is a Prismatic `DataPayload` object.
* A `DataPayload` object is an object with a `data` attribute, and optional `contentType` attribute.
*
* @param value The value to test
* @returns This function returns true if `value` is a DataPayload object, and false otherwise.
*/
const isData = (value) => isBufferDataPayload(value);
/**
* @deprecated Many libraries for third-party API that handle binary files expect `Buffer` objects.
* This function helps to convert strings, Uint8Arrays, and Arrays to a data structure
* that has a Buffer and a string representing `contentType`.
*
* You can access the buffer like this:
* `const { data, contentType } = util.types.toData(someData);`
*
* If `value` cannot be converted to a Buffer, an error will be thrown.
* @param value The string, Buffer, Uint8Array, or Array to convert to a Buffer.
* @returns This function returns an object with two keys: `data`, which is a `Buffer`, and `contentType`, which is a string.
*/
const toData = (value) => toBufferDataPayload(value);
/**
* This function checks if value is a string.
*
* @param value The variable to test.
* @returns This function returns true or false, depending on if `value` is a string.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isString("value"); // true
* util.types.isString(new String("value")); // true
* util.types.isString(123); // false
* util.types.isString(null); // false
*/
const isString = (value) => typeof value === "string" || value instanceof String;
/**
* This function converts a `value` to a string.
* If `value` is undefined or null, an optional `defaultValue` is returned (defaults to `""`).
*
* @param value The value to convert to a string.
* @param defaultValue A default value to return if `value` is undefined or null. Defaults to `""`.
* @returns The stringified version of `value`, or `defaultValue` if `value` is undefined or null.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.toString("Hello"); // "Hello"
* util.types.toString(5.5); // "5.5"
* util.types.toString("", "Some default"); // ""
* util.types.toString(undefined); // ""
* util.types.toString(null, "fallback"); // "fallback"
*/
const toString = (value, defaultValue = "") => `${value !== null && value !== void 0 ? value : defaultValue}`;
/**
* This function checks if value is a valid connection object (has `key`, `label`,
* and `inputs` properties, with appropriate OAuth 2.0 fields if applicable).
*
* @param value The variable to test.
* @returns This function returns true or false, depending on if `value` is a valid connection.
* @see {@link https://prismatic.io/docs/custom-connectors/connections/ | Writing Custom Connections}
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isConnection({
* key: "apiKey",
* label: "API Key",
* inputs: { apiKey: { type: "password" } },
* }); // true
* util.types.isConnection("not a connection"); // false
*/
const isConnection = (value) => {
if (typeof value === "string" && isJSON(value)) {
return isConnection(JSON.parse(value));
}
if (value && typeof value === "object") {
const { inputs } = value;
if ((0, exports.isObjectWithTruthyKeys)(value, ["key", "label", "oauth2Type"])) {
return ((0, exports.isObjectWithTruthyKeys)(inputs, ["authorizeUrl", "tokenUrl", "clientId", "clientSecret"]) ||
(0, exports.isObjectWithTruthyKeys)(inputs, ["tokenUrl", "clientId", "clientSecret"]));
}
return (0, exports.isObjectWithTruthyKeys)(value, ["key", "label"]) && typeof inputs === "object";
}
return false;
};
/**
* This function returns true if `value` can be parsed as JSON, and false otherwise.
*
* @param value The value to test against.
* @returns True if `value` can be parsed by `JSON.parse()`, false otherwise.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.isJSON('{"name":"John","age":30}'); // true
* util.types.isJSON("5"); // true
* util.types.isJSON("true"); // true
* util.types.isJSON(""); // false
* util.types.isJSON("not json"); // false
*/
const isJSON = (value) => {
try {
JSON.parse(value);
return true;
}
catch (_a) {
return false;
}
};
/**
* This function accepts an arbitrary object/value and safely serializes it to JSON.
* Unlike `JSON.stringify`, it handles cyclic references without throwing.
*
* @param value Arbitrary object/value to serialize.
* @param prettyPrint When true, convert to pretty printed JSON with 2 spaces and newlines. When false, JSON is compact. Defaults to `true`.
* @param retainKeyOrder When true, the order of keys in the JSON output will be the same as the order in the input object. Defaults to `false`.
* @returns JSON serialized text that can be safely logged.
* @example
* import { util } from "@prismatic-io/spectral";
*
* // Pretty-printed (default)
* util.types.toJSON({ name: "Acme", count: 42 });
* // '{\n "count": 42,\n "name": "Acme"\n}'
*
* // Compact output
* util.types.toJSON({ name: "Acme", count: 42 }, false);
* // '{"count":42,"name":"Acme"}'
*
* // Retain original key order
* util.types.toJSON({ name: "Acme", count: 42 }, true, true);
* // '{\n "name": "Acme",\n "count": 42\n}'
*/
const toJSON = (value, prettyPrint = true, retainKeyOrder = false) => {
const stringify = (0, safe_stable_stringify_1.configure)({
circularValue: undefined,
deterministic: !retainKeyOrder,
});
const result = prettyPrint ? stringify(value, null, 2) : stringify(value);
return result !== null && result !== void 0 ? result : "";
};
/**
* This function returns a version of the headers object where all header
* names (keys) are lower-cased. Header values are left unchanged.
*
* @param headers The headers to convert to lower case.
* @returns A new header object with lower-cased keys.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.lowerCaseHeaders({ "Content-Type": "application/json" });
* // { "content-type": "application/json" }
*
* util.types.lowerCaseHeaders({
* "Cache-Control": "max-age=604800",
* "Accept-Language": "en-us",
* });
* // { "cache-control": "max-age=604800", "accept-language": "en-us" }
*/
const lowerCaseHeaders = (headers) => Object.entries(headers).reduce((result, [key, val]) => {
return Object.assign(Object.assign({}, result), { [key.toLowerCase()]: val });
}, {});
exports.lowerCaseHeaders = lowerCaseHeaders;
/**
* This function parses a JSON string and returns the resulting object,
* or returns the value as-is if it is already an object.
*
* @param value The JSON string or object to convert.
* @returns An object, parsing JSON as necessary.
* @example
* import { util } from "@prismatic-io/spectral";
*
* util.types.toObject('{"foo":"bar","baz":123}');
* // { foo: "bar", baz: 123 }
*
* util.types.toObject({ foo: "bar", baz: 123 });
* // { foo: "bar", baz: 123 } (returned as-is)
*/
const toObject = (value) => {
if (typeof value === "string" && isJSON(value)) {
return JSON.parse(value);
}
else {
return value;
}
};
exports.toObject = toObject;
/**
* This function removes any properties of an object that match a certain predicate.
* By default, properties with values of `undefined`, `null`, and `""` are removed.
* Useful for cleaning up request bodies before sending to an API.
*
* @param obj A key-value object to remove properties from.
* @param predicate A function that returns true for properties to remove. Defaults to removing properties with `undefined`, `null`, and `""` values.
* @returns A new object with matching properties removed.
* @example
* import { util } from "@prismatic-io/spectral";
*
* // Remove undefined, null, and empty string values (default)
* util.types.cleanObject({ foo: undefined, bar: "abc", baz: null, buz: "" });
* // { bar: "abc" }
*
* // Custom predicate: remove even numbers
* util.types.cleanObject({ foo: 1, bar: 2, baz: 3 }, (v) => v % 2 === 0);
* // { foo: 1, baz: 3 }
*/
const cleanObject = (obj, predicate) => {
const defaultPredicate = (v) => v === undefined || v === null || v === "";
return (0, omitBy_1.default)(obj, predicate || defaultPredicate);
};
__exportStar(require("./conditionalLogic"), exports);
__exportStar(require("./errors"), exports);
exports.default = {
types: {
isBool,
toBool,
isInt,
toInt,
isNumber,
toNumber,
isBigInt,
toBigInt,
isDate,
toDate,
isUrl,
isBufferDataPayload,
toBufferDataPayload,
isData,
toData,
isString,
toString,
keyValPairListToObject,
isJSON,
toJSON,
lowerCaseHeaders: exports.lowerCaseHeaders,
isObjectSelection,
toObjectSelection,
isObjectFieldMap,
toObjectFieldMap,
isJSONForm,
toJSONForm,
isPicklist,
isSchedule,
isConnection,
isElement,
toObject: exports.toObject,
cleanObject,
},
};