UNPKG

concept-lang

Version:

A semantic network system for defining concepts, relationships, and building knowledge graphs with automatic inference

468 lines 20.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StdPlugin = exports.createStdPlugin = void 0; const block_1 = require("../../core/block"); /** * Standard library plugin for common Concept language functionality */ const createStdPlugin = (getBlock) => ({ say: (params) => { if (params.length < 2) { throw new Error('Invalid "say" usage: say <message>'); } // Add all concepts to the block params.forEach(concept => getBlock().addConcept(concept)); // Extract the message (everything after 'say') const message = params .slice(1) .map(p => p.name) .join(' '); console.log(message); return []; }, is: (params) => { const block = getBlock(); // Handle "is <statement>" - evaluate whatever comes after 'is' if (params[0]?.name === 'is') { // Handle "is <statement>" - evaluate whatever comes after 'is' if (params.length < 2) { throw new Error('Invalid "is" usage: is <statement>'); } // Extract everything after 'is' and evaluate it as a concept statement const statement = params.slice(1); // Check if this is a query (is A B) or (is A B action) if (statement.length >= 2) { const [a, relation, b] = statement; // Handle relationship queries: is A B if (relation?.name === 'is' && b && a) { // Check if the relationship exists (for future use if needed) block.chain.some(data => data.pair.conceptA.name === a.name && data.pair.conceptB.name === b.name && data.value === true && data.relationshipType === 'is'); // If there are more parameters after the relationship, execute them as a command if (statement.length > 3) { const actionParams = statement.slice(3); const actionCommand = actionParams[0]; if (actionCommand && block['_hookMap'] && block['_hookMap'][actionCommand.name]) { const hook = block['_hookMap'][actionCommand.name]; if (hook) { // Execute the action with the relationship result const actionResult = hook(actionParams); return actionResult; } } } // If no action, just add the concepts (the query was processed) // Note: relationshipExists is available for future use if needed statement.forEach(concept => { block.addConcept(concept); }); return; } // Handle negative relationship queries: isnt A B if (relation?.name === 'isnt' && b && a) { // Check if the negative relationship exists (for future use if needed) block.chain.some(data => data.pair.conceptA.name === a.name && data.pair.conceptB.name === b.name && data.value === false); // If there are more parameters after the relationship, execute them as a command if (statement.length > 3) { const actionParams = statement.slice(3); const actionCommand = actionParams[0]; if (actionCommand && block['_hookMap'] && block['_hookMap'][actionCommand.name]) { const hook = block['_hookMap'][actionCommand.name]; if (hook) { // Execute the action with the relationship result const actionResult = hook(actionParams); return actionResult; } } } // If no action, just add the concepts (the query was processed) // Note: relationshipExists is available for future use if needed statement.forEach(concept => { block.addConcept(concept); }); return; } } // Check if the first concept is a command (has a hook) const firstConcept = statement[0]; if (firstConcept && block['_hookMap'] && block['_hookMap'][firstConcept.name]) { // Execute the command with the remaining parameters const hook = block['_hookMap'][firstConcept.name]; if (hook) { return hook(statement); } } // Otherwise, just add the concepts statement.forEach(concept => { block.addConcept(concept); }); } // Handle "A is B" relationships if (params.length === 3) { const [a, isToken, b] = params; if (a && isToken?.name === 'is' && b) { // Add all concepts to the block params.forEach(concept => block.addConcept(concept)); // Create the relationship block.addToChain(a, b, true); return; } } // Handle incomplete relationships (just add concepts) if (params.length < 3) { params.forEach(concept => { block.addConcept(concept); }); return; } }, isnt: (params) => { const block = getBlock(); // Handle "isnt <statement>" - evaluate whatever comes after 'isnt' if (params[0]?.name === 'isnt') { // Handle "isnt <statement>" - evaluate whatever comes after 'isnt' if (params.length < 2) { throw new Error('Invalid "isnt" usage: isnt <statement>'); } // Extract everything after 'isnt' and evaluate it as a concept statement const statement = params.slice(1); if (statement.length >= 2) { // If it looks like a relationship (A isnt B), create it const [a, relation, b] = statement; if (relation?.name === 'is' && b && a) { block.addToChain(a, b, true, 'is'); return; } if (relation?.name === 'isnt' && b && a) { block.addToChain(a, b, false, 'isnt'); return; } } // Check if the first concept is a command (has a hook) const firstConcept = statement[0]; if (firstConcept && block['_hookMap'] && block['_hookMap'][firstConcept.name]) { // Execute the command with the remaining parameters const hook = block['_hookMap'][firstConcept.name]; if (hook) { return hook(statement); } } // Otherwise, just add the concepts statement.forEach(concept => { block.addConcept(concept); }); } // Handle "A isnt B" relationships if (params.length === 3) { const [a, isntToken, b] = params; if (a && isntToken?.name === 'isnt' && b) { // Add all concepts to the block params.forEach(concept => block.addConcept(concept)); // Create the relationship block.addToChain(a, b, false); return; } } // Handle incomplete relationships (just add concepts) if (params.length < 3) { params.forEach(concept => { block.addConcept(concept); }); return; } }, has: (params) => { const block = getBlock(); // Handle "has A B" query - check if A has B if (params.length >= 3 && params[0]?.name === 'has') { const [query, a, b] = params; if (query?.name === 'has' && a && b) { // Check if the relationship exists const hasRelationship = block.chain.find(data => data.pair.conceptA.name === a.name && data.pair.conceptB.name === b.name && data.relationshipType === 'has' && data.value === true); if (hasRelationship) { console.log(`✅ ${a.name} has ${b.name}`); return []; } else { console.log(`❌ ${a.name} does not have ${b.name}`); return []; } } } // Handle "A has B" relationship - creates a property relationship if (params.length >= 3 && params[1]?.name === 'has') { const [a, relation, b] = params; if (relation?.name === 'has' && b && a) { // Create the has relationship: A has B block.addToChain(a, b, true, 'has'); // Add the property concept to the block so it can be referenced block.addConcept(b); // Automatically create property instance: property_of_object const propertyInstanceName = `${b.name}_of_${a.name}`; block.addConcept({ name: propertyInstanceName }); // Create relationship: instance is property block.addPair({ conceptA: { name: propertyInstanceName }, conceptB: { name: b.name }, }); block.addData({ pair: { conceptA: { name: propertyInstanceName }, conceptB: { name: b.name }, }, value: true, relationshipType: 'is', }); // Create relationship: main concept has instance block.addPair({ conceptA: { name: a.name }, conceptB: { name: propertyInstanceName }, }); block.addData({ pair: { conceptA: { name: a.name }, conceptB: { name: propertyInstanceName }, }, value: true, relationshipType: 'has', }); return; } } // Handle "has <statement>" - evaluate whatever comes after 'has' if (params[0]?.name === 'has') { // Handle "has <statement>" - evaluate whatever comes after 'has' if (params.length < 2) { throw new Error('Invalid "has" usage: has <statement>'); } // Extract everything after 'has' and evaluate it as a concept statement const statement = params.slice(1); if (statement.length >= 2) { // If it looks like a relationship (A has B), create it const [a, relation, b] = statement; if (relation?.name === 'has' && b && a) { block.addToChain(a, b, true, 'has'); return; } if (relation?.name === 'is' && b && a) { block.addToChain(a, b, true, 'is'); return; } } // Check if the first concept is a command (has a hook) const firstConcept = statement[0]; if (firstConcept && block['_hookMap'] && block['_hookMap'][firstConcept.name]) { // Execute the command with the remaining parameters const hook = block['_hookMap'][firstConcept.name]; if (hook) { return hook(statement); } } // Otherwise, just add the concepts statement.forEach(concept => { block.addConcept(concept); }); return; } // Handle incomplete relationships (just add concepts) if (params.length < 3) { params.forEach(concept => { block.addConcept(concept); }); return; } }, hasnt: (params) => { const block = getBlock(); // Handle "hasnt A B" query - check if A does not have B if (params.length >= 3 && params[0]?.name === 'hasnt') { const [query, a, b] = params; if (query?.name === 'hasnt' && a && b) { // Check if the relationship exists const hasRelationship = block.chain.find(data => data.pair.conceptA.name === a.name && data.pair.conceptB.name === b.name && data.relationshipType === 'has' && data.value === true); if (hasRelationship) { console.log(`❌ ${a.name} has ${b.name} (expected not to have)`); return []; } else { console.log(`✅ ${a.name} does not have ${b.name}`); return []; } } } // Handle "A hasnt B" relationship - creates a negative property relationship if (params.length >= 3 && params[1]?.name === 'hasnt') { const [a, relation, b] = params; if (relation?.name === 'hasnt' && b && a) { // Create the negative has relationship: A hasnt B block.addToChain(a, b, false, 'has'); // Add the property concept to the block so it can be referenced block.addConcept(b); return; } } // Handle "hasnt <statement>" - evaluate whatever comes after 'hasnt' if (params[0]?.name === 'hasnt') { if (params.length < 2) { throw new Error('Invalid "hasnt" usage: hasnt <statement>'); } // Extract everything after 'hasnt' and evaluate it as a concept statement const statement = params.slice(1); // Check if the first concept is a command (has a hook) const firstConcept = statement[0]; if (firstConcept && block['_hookMap'] && block['_hookMap'][firstConcept.name]) { // Execute the command with the remaining parameters const hook = block['_hookMap'][firstConcept.name]; if (hook) { return hook(statement); } } // Otherwise, just add the concepts statement.forEach(concept => { block.addConcept(concept); }); return; } // Handle incomplete relationships (just add concepts) if (params.length < 3) { params.forEach(concept => { block.addConcept(concept); }); return; } }, inspect: (params) => { const block = getBlock(); if (params.length < 2) { throw new Error('Invalid "inspect" usage: inspect <concept_name>'); } // Add all concepts to the block params.forEach(concept => block.addConcept(concept)); const conceptName = params[1]?.name; if (!conceptName) { throw new Error('Invalid "inspect" usage: inspect <concept_name>'); } const concept = block.getConcept(conceptName); if (!concept) { console.log(`❌ Concept '${conceptName}' not found`); return; } console.log(`\n=== Concept: \x1b[34m${conceptName}\x1b[0m ===`); // Check if this is a boxed concept if (concept.block && concept.block.length > 0) { console.log('\nBoxed Content:'); concept.block.forEach(blockConcept => { console.log(` - \x1b[32m${blockConcept.name}\x1b[0m`); }); } // Get all relationships involving this concept using the block explorer // This gives us the complete, deduplicated view of all relationships const allConcepts = block.concepts; const allRelationships = []; for (const otherConcept of allConcepts) { if (otherConcept.name === conceptName) continue; // Find the actual relationship data to get the relationship type const relationshipData = block.chain.find(data => data.pair.conceptA.name === concept.name && data.pair.conceptB.name === otherConcept.name); if (relationshipData) { allRelationships.push({ concept: conceptName, relation: relationshipData.relationshipType || 'is', target: otherConcept.name, isInferred: false, }); } } // Also check reverse relationships (where this concept is the target) for (const otherConcept of allConcepts) { if (otherConcept.name === conceptName) continue; // Find the actual relationship data to get the relationship type const relationshipData = block.chain.find(data => data.pair.conceptA.name === otherConcept.name && data.pair.conceptB.name === concept.name); if (relationshipData) { allRelationships.push({ concept: otherConcept.name, relation: relationshipData.relationshipType || 'is', target: conceptName, isInferred: false, }); } } console.log(`Relationships: ${allRelationships.length}`); if (allRelationships.length > 0) { console.log('\nRelationships:'); allRelationships.forEach(rel => { let relationColor = '\x1b[32m'; // Default green if (rel.relation === 'isnt') { relationColor = '\x1b[31m'; // Red for 'isnt' } else if (rel.relation === 'has') { relationColor = '\x1b[33m'; // Yellow for 'has' } console.log(` \x1b[34m${rel.concept}\x1b[0m ${relationColor}${rel.relation}\x1b[0m \x1b[34m${rel.target}\x1b[0m`); }); } // Check if concept has any references const references = block.getReferences(conceptName); if (references.length > 0) { console.log('\nReferences:'); references.forEach(ref => { console.log(` -> ${ref}`); }); } console.log(''); }, }); exports.createStdPlugin = createStdPlugin; /** * Standard library plugin implementation */ class StdPlugin { constructor() { this.config = { name: 'std', version: '3.0.0', description: 'Standard library plugin with basic commands', main: 'index.js', }; } async initialize() { // No initialization needed } registerListeners() { // Return empty map since we use hooks instead of listeners return new Map(); } getHooks(block) { // Return the hooks for the compiler return (0, exports.createStdPlugin)(() => block || new block_1.Block()); } } exports.StdPlugin = StdPlugin; // Export as default for plugin loading exports.default = StdPlugin; //# sourceMappingURL=index.js.map