mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 13:21:55 +00:00
- Added `constants.mjs` defining `STORAGE_DIR` and `GRAPH_FILE`. - Replaced hard‑coded path strings in `agent.mjs`, `build_graph.mjs`, and `ingest.mjs` with imports from the new constants module. - Updated console log in `ingest.mjs` to reference `STORAGE_DIR`. - Adjusted `GRAPH_FILE` path to `./graphology/graph.json` via the constant.
100 lines
3.4 KiB
JavaScript
100 lines
3.4 KiB
JavaScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import { glob } from 'glob';
|
|
import * as cheerio from 'cheerio';
|
|
import { Graph } from 'graphology';
|
|
|
|
const SPEC_DIR = './spec-built/multipage';
|
|
const CODE_DIR = './engine262/src';
|
|
import { GRAPH_FILE } from './constants.mjs';
|
|
|
|
async function buildGraph() {
|
|
const graph = new Graph({ multi: true });
|
|
const htmlFiles = await glob(path.join(SPEC_DIR, '*.html'));
|
|
|
|
console.log("Processing specification for graph...");
|
|
for (const file of htmlFiles) {
|
|
const fileName = path.basename(file);
|
|
const content = fs.readFileSync(file, 'utf-8');
|
|
const $ = cheerio.load(content);
|
|
|
|
$('emu-clause').each((i, elem) => {
|
|
const id = $(elem).attr('id');
|
|
const title = $(elem).find('h1').first().text().trim();
|
|
|
|
if (id) {
|
|
if (!graph.hasNode(id)) {
|
|
graph.addNode(id, { title, type: 'SpecSection', file: fileName });
|
|
}
|
|
|
|
// Extract internal links
|
|
$(elem).find('a[href]').each((j, link) => {
|
|
const href = $(link).attr('href');
|
|
if (href && href.includes('#')) {
|
|
const [targetFile, targetId] = href.split('#');
|
|
// We only care about links to other sections for now
|
|
if (targetId && targetId.startsWith('sec-')) {
|
|
// Add relationship later if nodes exist
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Add edges for internal links
|
|
for (const file of htmlFiles) {
|
|
const content = fs.readFileSync(file, 'utf-8');
|
|
const $ = cheerio.load(content);
|
|
$('emu-clause').each((i, elem) => {
|
|
const sourceId = $(elem).attr('id');
|
|
if (sourceId && graph.hasNode(sourceId)) {
|
|
$(elem).find('a[href]').each((j, link) => {
|
|
const href = $(link).attr('href');
|
|
if (href && href.includes('#')) {
|
|
const [, targetId] = href.split('#');
|
|
if (targetId && graph.hasNode(targetId) && sourceId !== targetId) {
|
|
if (!graph.hasEdge(sourceId, targetId)) {
|
|
graph.addEdge(sourceId, targetId, { type: 'LINKS_TO' });
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
console.log("Processing code for graph...");
|
|
const jsFiles = await glob(path.join(CODE_DIR, '**/*.mts'));
|
|
|
|
for (const file of jsFiles) {
|
|
const fileName = path.basename(file);
|
|
const content = fs.readFileSync(file, 'utf-8');
|
|
|
|
// Simple heuristic: look for function names starting with Evaluate_
|
|
const functionMatches = content.matchAll(/export function\*? (Evaluate_([a-zA-Z0-9_]+))/g);
|
|
for (const match of functionMatches) {
|
|
const fullFuncName = match[1];
|
|
const shortName = match[2];
|
|
const funcNodeId = `func-${fullFuncName}`;
|
|
|
|
if (!graph.hasNode(funcNodeId)) {
|
|
graph.addNode(funcNodeId, { name: fullFuncName, type: 'JSFunction', file: fileName });
|
|
}
|
|
|
|
// Try to link to a spec section
|
|
// Heuristic: Evaluate_IfStatement -> sec-if-statement
|
|
const specId = `sec-${shortName.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()}`;
|
|
if (graph.hasNode(specId)) {
|
|
graph.addEdge(funcNodeId, specId, { type: 'IMPLEMENTS' });
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(`Graph built with ${graph.order} nodes and ${graph.size} edges.`);
|
|
fs.writeFileSync(GRAPH_FILE, JSON.stringify(graph.export(), null, 2));
|
|
console.log(`Graph saved to ${GRAPH_FILE}`);
|
|
}
|
|
|
|
buildGraph().catch(console.error);
|