@daitanjs/manipulation
Version:
A library to manipulate JSON, strings, and dates.
364 lines (358 loc) • 13.2 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/manipulation/src/index.js
var src_exports = {};
__export(src_exports, {
addEscapes: () => addEscapes,
cleanJSONString: () => cleanJSONString,
convertUSDateToUKDate: () => convertUSDateToUKDate,
deepCleanJSON: () => deepCleanJSON,
escapeObjectStrings: () => escapeObjectStrings,
isAlpha: () => isAlpha,
isAlphanumeric: () => isAlphanumeric,
isNumeric: () => isNumeric,
reverseString: () => reverseString,
safeParseJSON: () => safeParseJSON,
toTitleCase: () => toTitleCase,
truncate: () => truncate,
validateJSON: () => validateJSON
});
module.exports = __toCommonJS(src_exports);
var import_development4 = require("@daitanjs/development");
// src/manipulation/src/dates.js
var import_development = require("@daitanjs/development");
var import_error = require("@daitanjs/error");
var logger = (0, import_development.getLogger)("daitan-manipulation-dates");
function convertUSDateToUKDate(usDate) {
const callId = `usToUkDate-${Date.now().toString(36)}`;
logger.debug(
`[${callId}] convertUSDateToUKDate: Attempting to convert date "${usDate}".`
);
if (typeof usDate !== "string" || !usDate.trim()) {
const errMsg = "Input date string cannot be empty.";
logger.error(`[${callId}] ${errMsg}`, { input: usDate });
throw new import_error.DaitanInvalidInputError(errMsg, { inputDate: usDate });
}
const parts = usDate.trim().split("/");
if (parts.length !== 3) {
const errMsg = `Invalid US date format: "${usDate}". Expected MM/DD/YYYY.`;
logger.error(`[${callId}] ${errMsg}`);
throw new import_error.DaitanInvalidInputError(errMsg, { inputDate: usDate });
}
const [monthStr, dayStr, yearStr] = parts;
if (monthStr.length < 1 || monthStr.length > 2 || dayStr.length < 1 || dayStr.length > 2 || yearStr.length !== 4) {
const errMsg = `Invalid US date component lengths in "${usDate}". Ensure MM (1-2 digits), DD (1-2 digits), YYYY (4 digits).`;
logger.error(`[${callId}] ${errMsg}`);
throw new import_error.DaitanInvalidInputError(errMsg, {
inputDate: usDate,
parsedParts: { monthStr, dayStr, yearStr }
});
}
const monthNum = parseInt(monthStr, 10);
const dayNum = parseInt(dayStr, 10);
const yearNum = parseInt(yearStr, 10);
if (isNaN(monthNum) || isNaN(dayNum) || isNaN(yearNum)) {
const errMsg = `Invalid numeric components in US date "${usDate}". Ensure MM, DD, YYYY are numbers.`;
logger.error(`[${callId}] ${errMsg}`);
throw new import_error.DaitanInvalidInputError(errMsg, {
inputDate: usDate,
parsedParts: { monthStr, dayStr, yearStr }
});
}
if (monthNum < 1 || monthNum > 12 || dayNum < 1 || dayNum > 31) {
const errMsg = `Month or day out of valid range in US date "${usDate}". Month: ${monthNum}, Day: ${dayNum}.`;
logger.error(`[${callId}] ${errMsg}`);
throw new import_error.DaitanInvalidInputError(errMsg, {
inputDate: usDate,
month: monthNum,
day: dayNum
});
}
const testDate = new Date(yearNum, monthNum - 1, dayNum);
if (testDate.getFullYear() !== yearNum || testDate.getMonth() !== monthNum - 1 || testDate.getDate() !== dayNum) {
const errMsg = `The date "${usDate}" is not a valid calendar date (e.g., Feb 30).`;
logger.error(`[${callId}] ${errMsg}`);
throw new import_error.DaitanInvalidInputError(errMsg, { inputDate: usDate });
}
const ukDay = dayStr.padStart(2, "0");
const ukMonth = monthStr.padStart(2, "0");
const ukDate = `${ukDay}/${ukMonth}/${yearStr}`;
logger.info(
`[${callId}] Successfully converted "${usDate}" (US) to "${ukDate}" (UK).`
);
return ukDate;
}
// src/manipulation/src/json.js
var import_development2 = require("@daitanjs/development");
var import_error2 = require("@daitanjs/error");
var logger2 = (0, import_development2.getLogger)("daitan-manipulation-json");
function generateJSONErrorDetails(error, jsonString) {
const positionMatch = error.message.match(/position (\d+)/i);
let enhancedError = `JSON Error: ${error.message}`;
if (positionMatch && positionMatch[1]) {
const position = parseInt(positionMatch[1], 10);
if (!isNaN(position)) {
const contextChars = 25;
const start = Math.max(0, position - contextChars);
const end = Math.min(jsonString.length, position + 1 + contextChars);
let nearText = jsonString.substring(start, end);
nearText = nearText.replace(/\n/g, "\\n").replace(/\r/g, "\\r");
const pointerOffset = position - start;
const pointerLine = " ".repeat(pointerOffset) + "^";
enhancedError += `
Context: "${nearText}"
${pointerLine}`;
}
}
return enhancedError;
}
function cleanJSONString(input) {
if (typeof input !== "string" || !input.trim()) {
if (typeof input === "string" && input.length > 0 && !input.trim()) {
logger2.debug(
"cleanJSONString: Input string is whitespace only. Returning empty string."
);
return "";
}
logger2.debug(
"cleanJSONString: Input is not a string or is effectively empty. Returning as is.",
{ inputType: typeof input }
);
return input;
}
let cleaned = input;
const originalLength = cleaned.length;
const firstBracket = cleaned.indexOf("{");
const firstSquareBracket = cleaned.indexOf("[");
let startIndex = -1;
if (firstBracket !== -1 && firstSquareBracket !== -1) {
startIndex = Math.min(firstBracket, firstSquareBracket);
} else {
startIndex = Math.max(firstBracket, firstSquareBracket);
}
if (startIndex !== -1) {
const lastBracket = cleaned.lastIndexOf("}");
const lastSquareBracket = cleaned.lastIndexOf("]");
const endIndex = Math.max(lastBracket, lastSquareBracket);
if (endIndex > startIndex) {
cleaned = cleaned.substring(startIndex, endIndex + 1);
}
}
cleaned = cleaned.replace(/[\u200B-\u200D\uFEFF]/g, "");
cleaned = cleaned.replace(/\/\/[^\n]*\n?/g, "");
cleaned = cleaned.replace(/,\s*([}\]])/g, "$1");
cleaned = cleaned.trim();
if (cleaned.length !== originalLength && logger2.isLevelEnabled("debug")) {
logger2.debug(
"cleanJSONString: String was modified by cleaning heuristics.",
{
originalLength,
cleanedLength: cleaned.length,
originalPreview: input.substring(0, 100) + (input.length > 100 ? "..." : ""),
cleanedPreview: cleaned.substring(0, 100) + (cleaned.length > 100 ? "..." : "")
}
);
}
return cleaned;
}
function deepCleanJSON(data) {
if (typeof data === "string") {
return cleanJSONString(data);
} else if (Array.isArray(data)) {
return data.map((item) => deepCleanJSON(item));
} else if (data && typeof data === "object") {
const cleanedObject = {};
for (const [key, value] of Object.entries(data)) {
cleanedObject[key] = deepCleanJSON(value);
}
return cleanedObject;
} else if (data === null || typeof data === "number" || typeof data === "boolean" || data === void 0) {
return data;
}
logger2.warn(
`deepCleanJSON: Unsupported data type encountered: ${typeof data}. Returning as is.`
);
return data;
}
function safeParseJSON(jsonString, options = {}) {
const { attemptClean = true } = options;
if (typeof jsonString !== "string") {
const errMsg = "Input to safeParseJSON must be a string.";
logger2.error(errMsg, { inputType: typeof jsonString });
throw new import_error2.DaitanInvalidInputError(errMsg, { input: jsonString });
}
let stringToParse = attemptClean ? cleanJSONString(jsonString) : jsonString;
try {
return JSON.parse(stringToParse);
} catch (error) {
const detailedMessage = generateJSONErrorDetails(error, stringToParse);
logger2.error(
`safeParseJSON: Failed to parse JSON string. ${detailedMessage}`
);
throw new import_error2.DaitanOperationError(
`JSON parsing failed: ${error.message}`,
{
inputStringPreview: stringToParse.substring(0, 200) + (stringToParse.length > 200 ? "..." : ""),
attemptedClean
},
error
);
}
}
function validateJSON(jsonString, options = {}) {
const { attemptClean = true } = options;
if (typeof jsonString !== "string") {
return {
isValid: false,
parsedJson: null,
error: "Input must be a string to validate as JSON."
};
}
if (!jsonString.trim()) {
return {
isValid: false,
parsedJson: null,
error: "Input JSON string is empty or contains only whitespace."
};
}
const stringToValidate = attemptClean ? cleanJSONString(jsonString) : jsonString;
try {
const parsed = JSON.parse(stringToValidate);
return { isValid: true, parsedJson: parsed, error: null };
} catch (e) {
return {
isValid: false,
parsedJson: null,
error: generateJSONErrorDetails(e, stringToValidate)
};
}
}
// src/manipulation/src/strings.js
var import_development3 = require("@daitanjs/development");
var import_error3 = require("@daitanjs/error");
var logger3 = (0, import_development3.getLogger)("daitan-manipulation-strings");
var addEscapes = (str) => {
if (typeof str !== "string") {
throw new import_error3.DaitanInvalidInputError("Input to addEscapes must be a string.");
}
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/\f/g, "\\f").replace(/\b/g, "\\b");
};
var escapeObjectStrings = (data) => {
if (typeof data === "string") {
return addEscapes(data);
} else if (Array.isArray(data)) {
return data.map((item) => escapeObjectStrings(item));
} else if (data && typeof data === "object") {
const escapedObject = {};
for (const key in data) {
if (Object.prototype.hasOwnProperty.call(data, key)) {
escapedObject[key] = escapeObjectStrings(data[key]);
}
}
return escapedObject;
}
return data;
};
var truncate = (str, maxLength = 100, ellipsis = "...") => {
if (typeof str !== "string") {
throw new import_error3.DaitanInvalidInputError(
"Input `str` to truncate must be a string."
);
}
if (typeof maxLength !== "number" || isNaN(maxLength) || maxLength <= 0) {
throw new import_error3.DaitanInvalidInputError(
"maxLength for truncate must be a positive number."
);
}
if (typeof ellipsis !== "string") {
throw new import_error3.DaitanInvalidInputError(
"ellipsis for truncate must be a string."
);
}
if (str.length <= maxLength) {
return str;
}
if (maxLength <= ellipsis.length) {
return ellipsis.substring(0, maxLength);
}
return str.substring(0, maxLength - ellipsis.length) + ellipsis;
};
var toTitleCase = (str) => {
if (typeof str !== "string") {
throw new import_error3.DaitanInvalidInputError(
"Input `str` to toTitleCase must be a string."
);
}
if (!str.trim()) return "";
return str.toLowerCase().replace(/\b\w/g, (char) => char.toUpperCase());
};
var isAlpha = (str) => {
if (typeof str !== "string") {
throw new import_error3.DaitanInvalidInputError(
"Input `str` to isAlpha must be a string."
);
}
return /^[a-zA-Z]+$/.test(str);
};
var isAlphanumeric = (str) => {
if (typeof str !== "string") {
throw new import_error3.DaitanInvalidInputError(
"Input `str` to isAlphanumeric must be a string."
);
}
return /^[a-zA-Z0-9]+$/.test(str);
};
var isNumeric = (str) => {
if (typeof str !== "string") {
throw new import_error3.DaitanInvalidInputError(
"Input `str` to isNumeric must be a string."
);
}
return /^[0-9]+$/.test(str);
};
var reverseString = (str) => {
if (typeof str !== "string") {
throw new import_error3.DaitanInvalidInputError(
"Input `str` to reverseString must be a string."
);
}
return str.split("").reverse().join("");
};
// src/manipulation/src/index.js
var manipulationIndexLogger = (0, import_development4.getLogger)("daitan-manipulation-index");
manipulationIndexLogger.debug("Exporting DaitanJS Manipulation utilities...");
manipulationIndexLogger.info(
"DaitanJS Manipulation module exports configured and ready."
);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
addEscapes,
cleanJSONString,
convertUSDateToUKDate,
deepCleanJSON,
escapeObjectStrings,
isAlpha,
isAlphanumeric,
isNumeric,
reverseString,
safeParseJSON,
toTitleCase,
truncate,
validateJSON
});
//# sourceMappingURL=index.cjs.map