llm-md
Version:
Convert JSON to Markdown optimized for LLM consumption
198 lines (197 loc) • 5.61 kB
JavaScript
;
/**
* Utility functions for JSON to Markdown conversion
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getMaxDepth = getMaxDepth;
exports.escapePipes = escapePipes;
exports.escapeMarkdown = escapeMarkdown;
exports.formatValue = formatValue;
exports.formatCellValue = formatCellValue;
exports.estimateTokens = estimateTokens;
exports.calculateKeySimilarity = calculateKeySimilarity;
exports.getAverageKeyCount = getAverageKeyCount;
exports.getAllKeys = getAllKeys;
/**
* Calculate the maximum depth of a data structure
* @param data The data to analyze
* @param current Current depth level
* @param maxDepth Maximum depth to prevent infinite recursion
* @param visited Set to track circular references
* @returns Maximum depth found
*/
function getMaxDepth(data, current = 0, maxDepth = 10, visited = new WeakSet()) {
// Prevent infinite recursion
if (current >= maxDepth) {
return maxDepth;
}
// Primitive values have no additional depth
if (data === null || typeof data !== 'object') {
return current;
}
// Check for circular references
if (visited.has(data)) {
return current;
}
visited.add(data);
// Arrays
if (Array.isArray(data)) {
if (data.length === 0) {
return current;
}
return Math.max(current, ...data.map((item) => getMaxDepth(item, current + 1, maxDepth, visited)));
}
// Objects
const values = Object.values(data);
if (values.length === 0) {
return current;
}
return Math.max(current, ...values.map((val) => getMaxDepth(val, current + 1, maxDepth, visited)));
}
/**
* Escape pipe characters in strings for Markdown tables
* @param str String to escape
* @returns Escaped string
*/
function escapePipes(str) {
return str.replace(/\|/g, '\\|');
}
/**
* Escape special Markdown characters
* @param str String to escape
* @returns Escaped string
*/
function escapeMarkdown(str) {
return str
.replace(/\\/g, '\\\\')
.replace(/\*/g, '\\*')
.replace(/_/g, '\\_')
.replace(/\[/g, '\\[')
.replace(/\]/g, '\\]')
.replace(/`/g, '\\`');
}
/**
* Format a value for display in Markdown
* @param value Value to format
* @returns Formatted string
*/
function formatValue(value) {
if (value === null) {
return '`null`';
}
if (value === undefined) {
return '`undefined`';
}
if (typeof value === 'boolean') {
return value.toString();
}
if (typeof value === 'number') {
return String(value);
}
if (typeof value === 'string') {
return value;
}
if (typeof value === 'object') {
return '`' + JSON.stringify(value) + '`';
}
return String(value);
}
/**
* Format a value for table cells
* @param value Value to format
* @returns Formatted string safe for table cells
*/
function formatCellValue(value) {
if (value === null) {
return '`null`';
}
if (value === undefined) {
return '';
}
if (typeof value === 'boolean') {
return value ? '✓' : '✗';
}
if (typeof value === 'number') {
return String(value);
}
if (typeof value === 'string') {
// Escape pipes and remove newlines
return escapePipes(value.replace(/\n/g, ' '));
}
if (typeof value === 'object') {
return '`' + JSON.stringify(value) + '`';
}
return String(value);
}
/**
* Estimate token count for a string (rough approximation)
* Uses a simple heuristic: ~4 characters per token
* @param str String to estimate
* @returns Estimated token count
*/
function estimateTokens(str) {
return Math.ceil(str.length / 4);
}
/**
* Check if all objects in an array have similar keys
* @param arr Array of objects to check
* @returns Similarity score (0-1)
*/
function calculateKeySimilarity(arr) {
if (!Array.isArray(arr) || arr.length === 0) {
return 0;
}
// Filter to only objects
const objects = arr.filter((item) => item !== null && typeof item === 'object' && !Array.isArray(item));
if (objects.length === 0) {
return 0;
}
// Get key sets for each object
const keySets = objects.map((obj) => Object.keys(obj)
.sort()
.join(','));
// Calculate uniqueness
const uniqueKeySets = new Set(keySets);
return 1 / uniqueKeySets.size;
}
/**
* Get average number of keys in array of objects
* @param arr Array to analyze
* @returns Average key count
*/
function getAverageKeyCount(arr) {
if (!Array.isArray(arr) || arr.length === 0) {
return 0;
}
const objects = arr.filter((item) => item !== null && typeof item === 'object' && !Array.isArray(item));
if (objects.length === 0) {
return 0;
}
const totalKeys = objects.reduce((sum, obj) => {
return sum + Object.keys(obj).length;
}, 0);
return totalKeys / objects.length;
}
/**
* Get all unique keys from an array of objects
* @param arr Array of objects
* @returns Array of unique keys in order of first appearance
*/
function getAllKeys(arr) {
if (!Array.isArray(arr)) {
return [];
}
const keySet = new Set();
const keyOrder = [];
arr.forEach((item) => {
if (item !== null && typeof item === 'object' && !Array.isArray(item)) {
Object.keys(item).forEach((key) => {
if (!keySet.has(key)) {
keySet.add(key);
keyOrder.push(key);
}
});
}
});
return keyOrder;
}