(projectRoot, options = {})
| 297 | } |
| 298 | |
| 299 | function lintMemoryBlocks(projectRoot, options = {}) { |
| 300 | const blocks = loadMemoryBlocks(projectRoot); |
| 301 | const issues = []; |
| 302 | const seen = new Set(); |
| 303 | for (const entry of blocks) { |
| 304 | for (const issue of validateBlock(entry)) issues.push({ id: entry.id || null, type: 'schema', issue }); |
| 305 | if (seen.has(entry.id)) issues.push({ id: entry.id, type: 'duplicate', issue: `duplicate block id ${entry.id}` }); |
| 306 | seen.add(entry.id); |
| 307 | for (const item of entry.sources || []) { |
| 308 | if (!item.path) issues.push({ id: entry.id, type: 'source', issue: 'source missing path' }); |
| 309 | else if (!exists(projectRoot, item.path)) issues.push({ id: entry.id, type: 'source', issue: `source path not found: ${item.path}` }); |
| 310 | } |
| 311 | if (isOlderThan(entry.last_verified, options.staleDays || 60, options.now || new Date())) { |
| 312 | issues.push({ id: entry.id, type: 'stale', issue: `last_verified is stale: ${entry.last_verified}` }); |
| 313 | } |
| 314 | for (const issue of contradictionIssues(entry)) issues.push({ id: entry.id, type: 'contradiction', issue }); |
| 315 | } |
| 316 | for (const type of BLOCK_TYPES) { |
| 317 | if (!blocks.some((entry) => entry.type === type)) issues.push({ id: null, type: 'coverage', issue: `missing block type ${type}` }); |
| 318 | } |
| 319 | return { blocks, issues, pass: issues.length === 0 }; |
| 320 | } |
| 321 | |
| 322 | module.exports = { |
| 323 | BLOCK_TYPES, |
no test coverage detected