Newer
Older
import { CommandType, DecodeOptions } from "../types";
const digitRe = /^\d+$/;
export const isDigit = (v: any) => digitRe.test(v);
const firstIsIndex = (s: string) => digitDotRe.test(s);
// based on https://stackoverflow.com/questions/54733539/javascript-implementation-of-lodash-set-method
const set = (obj, path, value) => {
if (Object(obj) !== obj) return obj;
if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || [];
path
.slice(0, -1)
.reduce(
(a, c, i) =>
Object(a[c]) === a[c]
? a[c]
: (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {}),
obj
)[path[path.length - 1]] = value;
return obj;
};
// Based on: https://www.30secondsofcode.org/js/s/unflatten-object
export const unflatten = (obj: any) =>
Object.keys(obj).reduce(
(res, k) => {
k.split(".")
.map((v) => (isDigit(v) ? parseInt(v) - 1 : v))
.reduce(
(acc: any, e, i, keys) =>
acc[e] ||
(acc[e] = isNaN(Number(keys[i + 1]))
? keys.length - 1 === i
? obj[k]
: {}
: []),
res
);
return res;
},
firstIsIndex(Object.keys(obj)[0]) ? [] : {}
);
export const search = (obj: any, key: string): any => {
if (typeof obj !== "object") return null;
if (obj[key]) return obj[key];
for (const val of Object.values(obj)) {
const s = search(val, key);
if (s) return s;
}
};
export const searchParent = (
obj: any,
key: string
): Record<string, any> | undefined => {
if (typeof obj !== "object") return;
if (obj[key]) return obj;
for (const val of Object.values(obj)) {
const s = searchParent(val, key);
if (s) return s;
}
};
const fixPath = (s: string): string =>
s
.split(".")
.filter((it) => it !== "")
.map((it) => (isDigit(it) ? `[${parseInt(it) - 1}]` : it))
.join(".")
.split(".[")
.join("[");
export const convertToNestedObject = (arr: any[], retainPath?: boolean) => {
.map((it) =>
Object.entries(it.resultParams).map(([key, value]) => ({
path: fixPath(it.resolvedPath + key),
value,
}))
)
.flat(1)
.sort((a, b) => a.path.localeCompare(b.path))
.forEach(({ path, value }) => {
set(res, path, value);
});
return res;
};
export const hasMultipleIndexes = (
arr: string[],
pathSplit: string[]
): boolean =>
arr.some((it) => {
const spl = it.split(".");
return spl.length > pathSplit.length && isDigit(spl[pathSplit.length - 1]);
});
const _searchAll = (obj: any, key: string): any[] =>
typeof obj !== "object"
? []
: Object.entries(obj).reduce(
(acc, [k, v]) => [...acc, k === key ? v : _searchAll(v, key)],
[] as any[]
);
export const searchAll = (obj: any, key: string) =>
_searchAll(obj, key).flat(Infinity);
export const extractCommand = (msg: {
[key: string]: any;
}): CommandType | undefined => {
const msgType: string | undefined = search(msg, "msgType");
if (!msgType) {
const id: string | undefined = search(msg, "msgId");
const [frst] = id ? id.split("@") : [""];
return frst.toUpperCase().replace("_RESP", "") as CommandType;
return msgType.replace("_RESP", "") as CommandType;
export const unwrapObject = (data: any): any =>
!Array.isArray(data) &&
typeof data === "object" &&
Object.keys(data).length === 1
? Object.values(data)[0]
: data;
export const unwrapArray = (arr: any) =>
Array.isArray(arr) && arr.length === 1 ? arr[0] : arr;
const isObject = (val: any): boolean =>
typeof val === "object" && val !== null && !Array.isArray(val);
export const isEmptyObject = (obj: any): boolean =>
obj !== null &&
obj !== undefined &&
obj &&
typeof obj === "object" &&
Object.keys(obj).length === 0;
export const isEmpty = (v: any): boolean =>
v === undefined || v === null || isEmptyObject(v);
const clearObj = (obj) =>
isObject(obj) && Object.keys(obj).length === 1 ? Object.values(obj)[0] : obj;
const clearArray = (arr: Array<any>) =>
arr.length === 1 && Array.isArray(arr[0]) ? arr[0] : arr;
export const fullyUnwrapObject = (obj: any, shouldBeArray: boolean) => {
if (isObject(obj) && Object.keys(obj).length === 1)
return fullyUnwrapObject(Object.values(obj)[0], shouldBeArray);
const isArray = Array.isArray(obj);
if (isArray)
return clearArray(obj.filter((v) => !isEmptyObject(v)).map(clearObj));
else return isEmptyObject(obj) ? [] : [clearObj(obj)];
else if (isArray)
return fullyUnwrapObject(
export function makeBuffer(
payload: any,
options: Record<string, string>
) {
const NoSessionContextRecord = rootRecord.lookupType(
"usp_record.NoSessionContextRecord"
);
const noSessionContextRecordMsg = NoSessionContextRecord.create({
payload,
});
const record: any = rootRecord.lookupType("usp_record.Record");
const recordMsg = record.create({
version: "1.0",
PayloadSecurity: record.PayloadSecurity.PLAINTEXT,
noSessionContext: noSessionContextRecordMsg,
...options,
});
const buffer = record.encode(recordMsg).finish();
return buffer;
}
export const uniq = (initial?: string): string =>
(initial || "") +
(
Date.now().toString(36) + Math.random().toString(36).substr(2, 5)
).toUpperCase();
export const parseID = (msg: any) => {
const foundId = search(msg, "msgId");
// if id is formatted by me (command@) then use, otherwise check for sub id
const id = foundId.includes("@")
? foundId
: search(msg, "subscriptionId") || null;
return id;
};
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
const addPaths = (arr: any[]) =>
arr.map(({ resolvedPath, resultParams }) => ({
resolvedPath,
resultParams: { ...resultParams, query: resolvedPath },
}));
type RetainPathGetResult = {
query: string;
result: string | Record<string, string> | RetainPathGetResult[];
};
const getOther = (obj: Record<string, string>, skipKey: string) =>
obj[Object.keys(obj).find((key) => key !== skipKey) || ""];
const skipKey = (obj: Record<string, string>, keyToSkip: string) =>
Object.entries(obj).reduce(
(acc, [key, val]) => (key !== keyToSkip ? { ...acc, [key]: val } : acc),
{}
);
const isValue = (obj: Record<string, string>) => Object.keys(obj).length === 2;
const nestResult = (
result: any,
query?: string
): RetainPathGetResult => ({
query: query || result.query,
result: Array.isArray(result)
? result.map((v) => nestResult(v))
: isValue(result)
? getOther(result, "query")
: skipKey(result, "query"),
});
export const processGetResult = (
resolvedPathResultsArr: any[],
shouldBeArray: boolean,
requestedPath: string,
decodeOptions?: DecodeOptions,
) => {
const retainPath = decodeOptions?.retainPath === true;
const resolvedValues = retainPath
? addPaths(resolvedPathResultsArr)
: resolvedPathResultsArr;
const unflattened = convertToNestedObject(resolvedValues);
const unwrapped = fullyUnwrapObject(unflattened, shouldBeArray);
const result = isEmptyObject(unwrapped) ? [] : unwrapped;
const modifiedResult = retainPath
? nestResult(result, requestedPath)
: result;
return modifiedResult;
};