/**
* schema.js — Atom naming conventions and Scheme expression builders
*
* All atoms use prefixed ConceptNode names:
* mod: — modules (package.json boundaries)
* file: — source files (relative paths)
* fn: — exported functions/classes
* loop: — correction loops (by fingerprint)
* rule: — learned rules (by id)
*
* All edges use EdgeLink + BondNode (learn-pipeline compatible):
* (EdgeLink (BondNode "TYPE") (ListLink SRC DST))
*
* Bond types:
* contains — module contains file
* imports — file imports from file
* depends-on — module depends on module
* exports — file exports function/class
* loop-in-file — loop involved this file
* resolved-by — loop was resolved by editing this file
* rule-for-file — learned rule applies to this file
*/
// Escape strings for Scheme (double quotes, backslashes)
function esc (str) {
if (!str) return ''
return str
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\n/g, '\\n')
}
// --- Node builders ---
function modNode (name) {
return `(ConceptNode "mod:${esc(name)}")`
}
function fileNode (path) {
return `(ConceptNode "file:${esc(path)}")`
}
function fnNode (name) {
return `(ConceptNode "fn:${esc(name)}")`
}
function loopNode (fingerprint) {
return `(ConceptNode "loop:${esc(fingerprint)}")`
}
function ruleNode (id) {
return `(ConceptNode "rule:${esc(id)}")`
}
// --- Edge builder ---
function edge (bondType, src, dst) {
return `(EdgeLink (BondNode "${esc(bondType)}") (ListLink ${src} ${dst}))`
}
// --- Value setters ---
function setStringValue (node, key, value) {
return `(cog-set-value! ${node} (Predicate "${esc(key)}") (StringValue "${esc(value)}"))`
}
function setFloatValue (node, key, value) {
return `(cog-set-value! ${node} (Predicate "${esc(key)}") (FloatValue ${value}))`
}
// --- Query builders ---
function meetQuery (varName, varType, body) {
return `(cog-execute! (Meet (TypedVariable (Variable "${varName}") (Type '${varType})) (Present ${body})))`
}
// Find all files that import from a given file
function queryImporters (filePath) {
const target = fileNode(filePath)
return meetQuery('$consumer', 'ConceptNode',
`(EdgeLink (BondNode "imports") (ListLink (Variable "$consumer") ${target}))`)
}
// Find all files that a given file imports from
function queryDependencies (filePath) {
const source = fileNode(filePath)
return meetQuery('$dep', 'ConceptNode',
`(EdgeLink (BondNode "imports") (ListLink ${source} (Variable "$dep")))`)
}
// Find all loops involving a file
function queryLoopsForFile (filePath) {
const target = fileNode(filePath)
return meetQuery('$loop', 'ConceptNode',
`(EdgeLink (BondNode "loop-in-file") (ListLink (Variable "$loop") ${target}))`)
}
// Find all rules applying to a file
function queryRulesForFile (filePath) {
const target = fileNode(filePath)
return meetQuery('$rule', 'ConceptNode',
`(EdgeLink (BondNode "rule-for-file") (ListLink (Variable "$rule") ${target}))`)
}
// Find all files in a module
function queryModuleFiles (modName) {
const mod = modNode(modName)
return meetQuery('$file', 'ConceptNode',
`(EdgeLink (BondNode "contains") (ListLink ${mod} (Variable "$file")))`)
}
// Get a string value from an atom
function getStringValue (node, key) {
return `(let ((v (cog-value ${node} (Predicate "${esc(key)}")))) (if v (cog-value-ref v 0) ""))`
}
// Get a float value from an atom
function getFloatValue (node, key) {
return `(let ((v (cog-value ${node} (Predicate "${esc(key)}")))) (if v (cog-value-ref v 0) 0))`
}
// Count atoms in AtomSpace
function reportCounts () {
return '(cog-report-counts)'
}
module.exports = {
esc,
modNode, fileNode, fnNode, loopNode, ruleNode,
edge,
setStringValue, setFloatValue,
meetQuery,
queryImporters, queryDependencies,
queryLoopsForFile, queryRulesForFile,
queryModuleFiles,
getStringValue, getFloatValue,
reportCounts
}