1
0
mirror of https://github.com/sasjs/adapter.git synced 2026-01-09 21:30:05 +00:00

feat(*): recreate package with new name

This commit is contained in:
Krishna Acondy
2020-07-07 19:53:35 +01:00
commit 066f953863
150 changed files with 48625 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
export async function asyncForEach(array: any[], callback: any) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}

View File

@@ -0,0 +1,9 @@
import { SASjsRequest } from "../types/SASjsRequest";
/**
* Comparator for SASjs request timestamps
*
*/
export const compareTimestamps = (a: SASjsRequest, b: SASjsRequest) => {
return b.timestamp.getTime() - a.timestamp.getTime();
};

133
src/utils/convertToCsv.ts Normal file
View File

@@ -0,0 +1,133 @@
/**
* Converts the given JSON object to a CSV string.
* @param data - the JSON object to convert.
*/
export const convertToCSV = (data: any) => {
const replacer = (key: any, value: any) => (value === null ? "" : value);
const headerFields = Object.keys(data[0]);
let csvTest;
let invalidString = false;
const headers = headerFields.map((field) => {
let firstFoundType: string | null = null;
let hasMixedTypes: boolean = false;
let rowNumError: number = -1;
const longestValueForField = data
.map((row: any, index: number) => {
if (row[field] || row[field] === "") {
if (firstFoundType) {
let currentFieldType =
row[field] === "" || typeof row[field] === "string"
? "chars"
: "number";
if (!hasMixedTypes) {
hasMixedTypes = currentFieldType !== firstFoundType;
rowNumError = hasMixedTypes ? index + 1 : -1;
}
} else {
if (row[field] === "") {
firstFoundType = "chars";
} else {
firstFoundType =
typeof row[field] === "string" ? "chars" : "number";
}
}
let byteSize;
if (typeof row[field] === "string") {
let doubleQuotesFound = row[field]
.split("")
.filter((char: any) => char === '"');
byteSize = getByteSize(row[field]);
if (doubleQuotesFound.length > 0) {
byteSize += doubleQuotesFound.length;
}
}
return byteSize;
}
})
.sort((a: number, b: number) => b - a)[0];
if (longestValueForField && longestValueForField > 32765) {
invalidString = true;
}
if (hasMixedTypes) {
console.error(
`Row (${rowNumError}), Column (${field}) has mixed types: ERROR`
);
}
return `${field}:${firstFoundType === "chars" ? "$" : ""}${
longestValueForField
? longestValueForField
: firstFoundType === "chars"
? "1"
: "best"
}.`;
});
if (invalidString) {
return "ERROR: LARGE STRING LENGTH";
}
csvTest = data.map((row: any) => {
const fields = Object.keys(row).map((fieldName, index) => {
let value;
let containsSpecialChar = false;
const currentCell = row[fieldName];
if (JSON.stringify(currentCell).search(/(\\t|\\n|\\r)/gm) > -1) {
value = currentCell.toString();
containsSpecialChar = true;
} else {
value = JSON.stringify(currentCell, replacer);
}
value = value.replace(/\\\\/gm, "\\");
if (containsSpecialChar) {
if (value.includes(",") || value.includes('"')) {
value = '"' + value + '"';
}
} else {
if (
!value.includes(",") &&
value.includes('"') &&
!value.includes('\\"')
) {
value = value.substring(1, value.length - 1);
}
value = value.replace(/\\"/gm, '""');
}
value = value.replace(/\r\n/gm, "\n");
if (value === "" && headers[index].includes("best")) {
value = ".";
}
return value;
});
return fields.join(",");
});
let finalCSV =
headers.join(",").replace(/,/g, " ") + "\r\n" + csvTest.join("\r\n");
return finalCSV;
};
const getByteSize = (str: string) => {
let byteSize = str.length;
for (let i = str.length - 1; i >= 0; i--) {
const code = str.charCodeAt(i);
if (code > 0x7f && code <= 0x7ff) byteSize++;
else if (code > 0x7ff && code <= 0xffff) byteSize += 2;
if (code >= 0xdc00 && code <= 0xdfff) i--; //trail surrogate
}
return byteSize;
};

14
src/utils/index.ts Normal file
View File

@@ -0,0 +1,14 @@
export * from "./asyncForEach";
export * from "./compareTimestamps";
export * from "./convertToCsv";
export * from "./isAuthorizeFormRequired";
export * from "./isLoginRequired";
export * from "./isLoginSuccess";
export * from "./makeRequest";
export * from "./needsRetry";
export * from "./parseAndSubmitAuthorizeForm";
export * from "./parseGeneratedCode";
export * from "./parseSourceCode";
export * from "./parseSasViyaLog";
export * from "./serialize";
export * from "./splitChunks";

View File

@@ -0,0 +1,3 @@
export const isAuthorizeFormRequired = (response: string): boolean => {
return /<form.+action="(.*Logon\/oauth\/authorize[^"]*).*>/gm.test(response);
};

View File

@@ -0,0 +1,5 @@
export const isLogInRequired = (response: string): boolean => {
const pattern: RegExp = /<form.+action="(.*Logon[^"]*).*>/gm;
const matches = pattern.test(response);
return matches;
};

View File

@@ -0,0 +1,2 @@
export const isLogInSuccess = (response: string): boolean =>
/You have signed in/gm.test(response);

37
src/utils/makeRequest.ts Normal file
View File

@@ -0,0 +1,37 @@
import { CsrfToken } from "../types";
export async function makeRequest<T>(
url: string,
request: RequestInit,
callback: (value: CsrfToken) => any,
contentType: "text" | "json" = "json"
): Promise<T> {
const responseTransform =
contentType === "json"
? (res: Response) => res.json()
: (res: Response) => res.text();
const result = await fetch(url, request).then((response) => {
if (!response.ok) {
if (response.status === 403) {
const tokenHeader = response.headers.get("X-CSRF-HEADER");
if (tokenHeader) {
const token = response.headers.get(tokenHeader);
callback({
headerName: tokenHeader,
value: token || "",
});
const retryRequest = {
...request,
headers: { ...request.headers, [tokenHeader]: token },
};
return fetch(url, retryRequest).then(responseTransform);
}
}
} else {
return responseTransform(response);
}
});
return result;
}

11
src/utils/needsRetry.ts Normal file
View File

@@ -0,0 +1,11 @@
export const needsRetry = (responseText: string): boolean => {
return (
(responseText.includes('"errorCode":403') &&
responseText.includes("_csrf") &&
responseText.includes("X-CSRF-TOKEN")) ||
(responseText.includes('"status":403') &&
responseText.includes('"error":"Forbidden"')) ||
(responseText.includes('"status":449') &&
responseText.includes("Authentication success, retry original request"))
);
};

View File

@@ -0,0 +1,49 @@
export const parseAndSubmitAuthorizeForm = async (
response: string,
serverUrl: string
) => {
let authUrl: string | null = null;
const params: any = {};
const responseBody = response.split("<body>")[1].split("</body>")[0];
const bodyElement = document.createElement("div");
bodyElement.innerHTML = responseBody;
const form = bodyElement.querySelector("#application_authorization");
authUrl = form ? serverUrl + form.getAttribute("action") : null;
const inputs: any = form?.querySelectorAll("input");
for (const input of inputs) {
if (input.name === "user_oauth_approval") {
input.value = "true";
}
params[input.name] = input.value;
}
const formData = new FormData();
for (const key in params) {
if (params.hasOwnProperty(key)) {
formData.append(key, params[key]);
}
}
return new Promise((resolve, reject) => {
if (authUrl) {
fetch(authUrl, {
method: "POST",
credentials: "include",
body: formData,
referrerPolicy: "same-origin",
})
.then((res) => res.text())
.then((res) => {
resolve(res);
});
} else {
reject("Auth form url is null");
}
});
};

View File

@@ -0,0 +1,7 @@
export const parseGeneratedCode = (log: string) => {
const startsWith = "MPRINT";
const isGeneratedCodeLine = (line: string) =>
line.trim().startsWith(startsWith);
const logLines = log.split("\n").filter(isGeneratedCodeLine);
return logLines.join("\r\n");
};

View File

@@ -0,0 +1,12 @@
export const parseSasViyaLog = (logResponse: { items: any[] }) => {
let log;
try {
log = logResponse.items
? logResponse.items.map((i) => i.line).join("\n")
: JSON.stringify(logResponse);
} catch (e) {
console.error("An error has occurred while parsing the log response", e);
log = logResponse;
}
return log;
};

View File

@@ -0,0 +1,6 @@
export const parseSourceCode = (log: string): string => {
const isSourceCodeLine = (line: string) =>
line.trim().substring(0, 10).trimStart().match(/^\d/);
const logLines = log.split("\n").filter(isSourceCodeLine);
return logLines.join("\r\n");
};

15
src/utils/serialize.ts Normal file
View File

@@ -0,0 +1,15 @@
export const serialize = (obj: any) => {
const str: any[] = [];
for (const p in obj) {
if (obj.hasOwnProperty(p)) {
if (obj[p] instanceof Array) {
for (let i = 0, n = obj[p].length; i < n; i++) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p][i]));
}
} else {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
}
}
return str.join("&");
};

12
src/utils/splitChunks.ts Normal file
View File

@@ -0,0 +1,12 @@
export const splitChunks = (content: string) => {
const size = 16000;
const numChunks = Math.ceil(content.length / size);
const chunks = new Array(numChunks);
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
chunks[i] = content.substr(o, size);
}
return chunks;
};