meta-log-db
Version:
Native database package for Meta-Log (ProLog, DataLog, R5RS)
201 lines • 6.07 kB
JavaScript
;
/**
* Org Mode R5RS Functions
*
* R5RS functions for parsing and processing Org Mode documents
* Uses orga package for parsing
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseOrgDocument = parseOrgDocument;
exports.extractHeadings = extractHeadings;
exports.extractSourceBlocks = extractSourceBlocks;
exports.extractPropertyDrawers = extractPropertyDrawers;
exports.expandNoweb = expandNoweb;
// Dynamic import to handle optional dependency
let orgaParse = null;
async function loadOrga() {
if (orgaParse)
return orgaParse;
try {
// Use require for CommonJS module (works in Node.js)
// eslint-disable-next-line @typescript-eslint/no-require-imports
const orga = require('orga');
orgaParse = orga.parse;
if (!orgaParse) {
throw new Error('orga.parse not found');
}
return orgaParse;
}
catch (error) {
throw new Error('orga package not available. Install with: npm install orga');
}
}
/**
* Parse Org Mode document
*
* @param content - Org Mode document content
* @returns Parsed AST structure
*/
async function parseOrgDocument(content) {
if (!content || typeof content !== 'string') {
throw new Error('Org Mode content must be a non-empty string');
}
const parse = await loadOrga();
return parse(content);
}
/**
* Extract headings from Org Mode document
*
* @param content - Org Mode document content
* @returns Array of headings with hierarchy
*/
async function extractHeadings(content) {
const ast = await parseOrgDocument(content);
const headings = [];
function traverse(node, level = 0, parentId = null) {
if (!node || typeof node !== 'object')
return;
if (node.type === 'headline' || node.type === 'heading') {
const title = extractTitle(node);
const id = slugify(title);
const heading = {
id,
level: node.level || level,
title,
children: [],
sourceBlocks: [],
parentId
};
headings.push(heading);
if (node.children) {
for (const child of node.children) {
traverse(child, level + 1, id);
}
}
}
else if (node.children) {
for (const child of node.children) {
traverse(child, level, parentId);
}
}
}
traverse(ast);
return headings;
}
/**
* Extract source blocks from Org Mode document
*
* @param content - Org Mode document content
* @returns Array of source blocks
*/
async function extractSourceBlocks(content) {
const ast = await parseOrgDocument(content);
const sourceBlocks = [];
function traverse(node) {
if (!node || typeof node !== 'object')
return;
if (node.type === 'src-block' || node.type === 'block' && node.name === 'SRC') {
const block = {
name: node.name || '',
type: node.params?.[0] || 'text',
content: node.value || '',
headerArgs: node.properties || {},
tangle: extractTangle(node),
noweb: node.noweb || false
};
sourceBlocks.push(block);
}
if (node.children) {
for (const child of node.children) {
traverse(child);
}
}
}
traverse(ast);
return sourceBlocks;
}
/**
* Extract property drawers from Org Mode document
*
* @param content - Org Mode document content
* @returns Array of property drawers
*/
async function extractPropertyDrawers(content) {
const ast = await parseOrgDocument(content);
const drawers = [];
function traverse(node) {
if (!node || typeof node !== 'object')
return;
if (node.type === 'drawer' && node.name === 'PROPERTIES') {
const properties = {};
if (node.children) {
for (const child of node.children) {
if (child.type === 'property') {
properties[child.key] = child.value;
}
}
}
drawers.push(properties);
}
if (node.children) {
for (const child of node.children) {
traverse(child);
}
}
}
traverse(ast);
return drawers;
}
/**
* Expand Noweb references in source block
*
* @param content - Source block content with Noweb references
* @param namedBlocks - Map of named source blocks
* @returns Expanded content
*/
async function expandNoweb(content, namedBlocks) {
if (!content || typeof content !== 'string') {
return content;
}
// Noweb syntax: <<block-name>> or <<block-name()>>
const nowebPattern = /<<([^>]+)>>/g;
return content.replace(nowebPattern, (match, blockName) => {
const name = blockName.trim();
const blockContent = namedBlocks.get(name);
if (blockContent) {
return blockContent;
}
// Return original if not found (could throw error instead)
return match;
});
}
// Helper functions
function extractTitle(node) {
if (node.title)
return node.title;
if (node.children) {
const titleNode = node.children.find((c) => c.type === 'text' || c.type === 'plain-text');
if (titleNode)
return titleNode.value || '';
}
return '';
}
function slugify(text) {
return text
.toLowerCase()
.replace(/[^\w\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.trim();
}
function extractTangle(node) {
if (node.properties) {
for (const [key, value] of Object.entries(node.properties)) {
if (key.toLowerCase() === 'tangle') {
return value;
}
}
}
return undefined;
}
//# sourceMappingURL=r5rs-functions.js.map