refactor(8.0): remove dead, unreachable, and unwired modules
Pre-GA dead-code sweep. A deterministic import-reachability walk from the
package's real entry points (the exports map, the CLI bin, the conversation
surface) found 34 source modules that nothing reachable imports — they
compile and ship as dist output that no consumer or internal path can ever
reach. All were superseded duplicates, abandoned parallel implementations,
or built-but-never-wired features:
- superseded duplicates of live modules: an older "unified" entry, a
standalone neural-import variant, a static NLP processor + its matcher,
a parallel API-types module, a duplicate progress-types module
- an abandoned import path (orchestrator + entity deduplicator + barrels)
left behind when ingestion moved to the coordinator
- unwired feature modules (instance pool, import presets, cached
embeddings, relationship-confidence scorer) reachable only from tests
- dead leaf utilities (write buffer, deleted-items index, bounded
registry, two crypto shims, a cache manager, a structured logger, a
stale v5 type-migration helper, a browser-only FS type shim) and
several dead re-export barrels
- a CLI catalog command wired into no command
Also removed two tests that only exercised deleted modules, repointed two
VFS tests off a deleted barrel onto the implementation module, and deleted
one example that demoed removed features.
Verified: clean build (both tsc passes), unit 1505 + integration 607 green,
and a re-run of the reachability walk reports zero remaining orphans.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
03d654061f
commit
bf0afe8563
39 changed files with 2 additions and 10497 deletions
|
|
@ -1,326 +0,0 @@
|
|||
/**
|
||||
* Consistent API Types for Brainy
|
||||
*
|
||||
* These types provide a uniform interface for all public methods,
|
||||
* using object parameters for consistency and extensibility.
|
||||
*/
|
||||
|
||||
import type { Vector } from '../coreTypes.js'
|
||||
import type { NounType, VerbType } from './graphTypes.js'
|
||||
|
||||
// ============= NOUN OPERATIONS =============
|
||||
|
||||
/**
|
||||
* Parameters for adding a noun
|
||||
*/
|
||||
export interface AddNounParams {
|
||||
data: any | Vector // Content or pre-computed vector
|
||||
type: NounType | string // Noun type (required)
|
||||
metadata?: any // Optional metadata
|
||||
id?: string // Optional custom ID
|
||||
service?: string // Optional service identifier
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for updating a noun
|
||||
*/
|
||||
export interface UpdateNounParams {
|
||||
id: string // Noun ID to update
|
||||
data?: any // New data
|
||||
metadata?: any // New metadata
|
||||
type?: NounType | string // New type
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for getting nouns
|
||||
*/
|
||||
export interface GetNounsParams {
|
||||
ids?: string[] // Specific IDs to fetch
|
||||
type?: NounType | string | string[] // Filter by type(s)
|
||||
limit?: number // Maximum results
|
||||
offset?: number // Pagination offset
|
||||
cursor?: string // Pagination cursor
|
||||
filter?: Record<string, any> // Metadata filters
|
||||
service?: string // Service filter
|
||||
}
|
||||
|
||||
// ============= VERB OPERATIONS =============
|
||||
|
||||
/**
|
||||
* Parameters for adding a verb (relationship)
|
||||
*/
|
||||
export interface AddVerbParams {
|
||||
source: string // Source noun ID
|
||||
target: string // Target noun ID
|
||||
type: VerbType | string // Verb type (required)
|
||||
weight?: number // Relationship weight (0-1)
|
||||
metadata?: any // Optional metadata
|
||||
service?: string // Optional service identifier
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for getting verbs
|
||||
*/
|
||||
export interface GetVerbsParams {
|
||||
source?: string // Filter by source
|
||||
target?: string // Filter by target
|
||||
type?: VerbType | string | string[] // Filter by type(s)
|
||||
limit?: number // Maximum results
|
||||
offset?: number // Pagination offset
|
||||
cursor?: string // Pagination cursor
|
||||
filter?: Record<string, any> // Metadata filters
|
||||
service?: string // Service filter
|
||||
}
|
||||
|
||||
// ============= SEARCH OPERATIONS =============
|
||||
|
||||
/**
|
||||
* Unified search parameters
|
||||
*/
|
||||
export interface SearchParams {
|
||||
query: string | Vector // Text query or vector
|
||||
limit?: number // Maximum results (default: 10)
|
||||
threshold?: number // Similarity threshold (0-1)
|
||||
filter?: {
|
||||
type?: NounType | string | string[] // Filter by noun type(s)
|
||||
metadata?: Record<string, any> // Metadata filters
|
||||
service?: string // Service filter
|
||||
}
|
||||
includeMetadata?: boolean // Include metadata in results
|
||||
includeVectors?: boolean // Include vectors in results
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for similarity search
|
||||
*/
|
||||
export interface SimilarityParams {
|
||||
id?: string // Find similar to this ID
|
||||
data?: any | Vector // Or find similar to this data
|
||||
limit?: number // Maximum results (default: 10)
|
||||
threshold?: number // Similarity threshold (0-1)
|
||||
filter?: {
|
||||
type?: NounType | string | string[]
|
||||
metadata?: Record<string, any>
|
||||
service?: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for related items search
|
||||
*/
|
||||
export interface RelatedParams {
|
||||
id: string // Starting noun ID
|
||||
depth?: number // Traversal depth (default: 1)
|
||||
limit?: number // Max results per level
|
||||
types?: VerbType[] | string[] // Relationship types to follow
|
||||
direction?: 'outgoing' | 'incoming' | 'both'
|
||||
}
|
||||
|
||||
// ============= BATCH OPERATIONS =============
|
||||
|
||||
/**
|
||||
* Parameters for batch noun operations
|
||||
*/
|
||||
export interface BatchNounsParams {
|
||||
items: AddNounParams[] // Array of nouns to add
|
||||
parallel?: boolean // Process in parallel
|
||||
chunkSize?: number // Batch size for processing
|
||||
onProgress?: (completed: number, total: number) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for batch verb operations
|
||||
*/
|
||||
export interface BatchVerbsParams {
|
||||
items: AddVerbParams[] // Array of verbs to add
|
||||
parallel?: boolean // Process in parallel
|
||||
chunkSize?: number // Batch size for processing
|
||||
onProgress?: (completed: number, total: number) => void
|
||||
}
|
||||
|
||||
// ============= STATISTICS & METADATA =============
|
||||
|
||||
/**
|
||||
* Parameters for statistics queries
|
||||
*/
|
||||
export interface StatisticsParams {
|
||||
detailed?: boolean // Include detailed breakdown
|
||||
includeAugmentations?: boolean // Include augmentation stats
|
||||
includeMemory?: boolean // Include memory usage
|
||||
service?: string // Filter by service
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for metadata operations
|
||||
*/
|
||||
export interface MetadataParams {
|
||||
id: string // Entity ID
|
||||
metadata: any // Metadata to set/update
|
||||
merge?: boolean // Merge with existing (vs replace)
|
||||
}
|
||||
|
||||
// ============= CONFIGURATION =============
|
||||
|
||||
/**
|
||||
* Dynamic configuration update parameters
|
||||
*/
|
||||
export interface ConfigUpdateParams {
|
||||
embeddings?: {
|
||||
model?: string
|
||||
precision?: 'q8'
|
||||
cache?: boolean
|
||||
}
|
||||
augmentations?: {
|
||||
[name: string]: boolean | Record<string, any>
|
||||
}
|
||||
storage?: {
|
||||
type?: string
|
||||
config?: any
|
||||
}
|
||||
performance?: {
|
||||
batchSize?: number
|
||||
maxConcurrency?: number
|
||||
cacheSize?: number
|
||||
}
|
||||
}
|
||||
|
||||
// ============= TRIPLE INTELLIGENCE API =============
|
||||
|
||||
/**
|
||||
* API for Triple Intelligence Engine to access Brainy internals
|
||||
* This provides type-safe access without unchecked casts
|
||||
*/
|
||||
export interface TripleIntelligenceAPI {
|
||||
// Vector operations
|
||||
vectorSearch(vector: Vector | string, limit: number): Promise<Array<{id: string, score: number, entity?: any}>>
|
||||
|
||||
// Graph operations
|
||||
graphTraversal(options: {
|
||||
start: string | string[]
|
||||
type?: string | string[]
|
||||
direction?: 'in' | 'out' | 'both'
|
||||
maxDepth?: number
|
||||
}): Promise<Array<{id: string, score: number, depth: number}>>
|
||||
|
||||
// Metadata operations
|
||||
metadataQuery(where: Record<string, any>): Promise<Set<string>>
|
||||
getEntity(id: string): Promise<any>
|
||||
|
||||
// Storage operations
|
||||
getVerbsBySource(sourceId: string): Promise<any[]>
|
||||
getVerbsByTarget(targetId: string): Promise<any[]>
|
||||
|
||||
// Statistics
|
||||
getStatistics(): Promise<{
|
||||
totalCount: number
|
||||
fieldStats: Record<string, {
|
||||
min: number
|
||||
max: number
|
||||
cardinality: number
|
||||
type: string
|
||||
}>
|
||||
}>
|
||||
|
||||
// Index access
|
||||
getAllNouns(): Map<string, any>
|
||||
hasMetadataIndex(): boolean
|
||||
}
|
||||
|
||||
// ============= RESULTS =============
|
||||
|
||||
/**
|
||||
* Unified search result
|
||||
*/
|
||||
export interface SearchResult<T = any> {
|
||||
id: string
|
||||
score: number // Similarity score (0-1)
|
||||
data?: T // Original data
|
||||
metadata?: any // Metadata if requested
|
||||
vector?: Vector // Vector if requested
|
||||
type?: string // Noun type
|
||||
distance?: number // Raw distance metric
|
||||
}
|
||||
|
||||
/**
|
||||
* Paginated result wrapper
|
||||
*/
|
||||
export interface PaginatedResult<T> {
|
||||
items: T[]
|
||||
total?: number
|
||||
hasMore: boolean
|
||||
nextCursor?: string
|
||||
previousCursor?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch operation result
|
||||
*/
|
||||
export interface BatchResult {
|
||||
successful: string[] // Successfully processed IDs
|
||||
failed: Array<{
|
||||
index: number
|
||||
error: string
|
||||
item?: any
|
||||
}>
|
||||
total: number
|
||||
duration: number // Total time in ms
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistics result
|
||||
*/
|
||||
export interface StatisticsResult {
|
||||
nouns: {
|
||||
total: number
|
||||
byType: Record<string, number>
|
||||
}
|
||||
verbs: {
|
||||
total: number
|
||||
byType: Record<string, number>
|
||||
}
|
||||
storage: {
|
||||
used: number
|
||||
type: string
|
||||
}
|
||||
performance?: {
|
||||
avgLatency: number
|
||||
throughput: number
|
||||
cacheHitRate?: number
|
||||
}
|
||||
augmentations?: Record<string, any>
|
||||
memory?: {
|
||||
used: number
|
||||
limit: number
|
||||
}
|
||||
}
|
||||
|
||||
// ============= ERRORS =============
|
||||
|
||||
/**
|
||||
* Structured error for API operations
|
||||
*/
|
||||
export class BrainyAPIError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public code: string,
|
||||
public statusCode: number = 400,
|
||||
public details?: any
|
||||
) {
|
||||
super(message)
|
||||
this.name = 'BrainyAPIError'
|
||||
}
|
||||
}
|
||||
|
||||
// Error codes
|
||||
export const ErrorCodes = {
|
||||
INVALID_TYPE: 'INVALID_TYPE',
|
||||
NOT_FOUND: 'NOT_FOUND',
|
||||
DUPLICATE_ID: 'DUPLICATE_ID',
|
||||
INVALID_VECTOR: 'INVALID_VECTOR',
|
||||
STORAGE_ERROR: 'STORAGE_ERROR',
|
||||
EMBEDDING_ERROR: 'EMBEDDING_ERROR',
|
||||
AUGMENTATION_ERROR: 'AUGMENTATION_ERROR',
|
||||
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
||||
QUOTA_EXCEEDED: 'QUOTA_EXCEEDED',
|
||||
UNAUTHORIZED: 'UNAUTHORIZED'
|
||||
} as const
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/**
|
||||
* Type declarations for the File System Access API
|
||||
* Extends the FileSystemDirectoryHandle interface to include the [Symbol.asyncIterator] method
|
||||
* and FileSystemHandle to include getFile() method for TypeScript compatibility
|
||||
*/
|
||||
|
||||
// Extend the FileSystemDirectoryHandle interface
|
||||
interface FileSystemDirectoryHandle {
|
||||
[Symbol.asyncIterator](): AsyncIterableIterator<[string, FileSystemHandle]>;
|
||||
|
||||
keys(): AsyncIterableIterator<string>;
|
||||
|
||||
entries(): AsyncIterableIterator<[string, FileSystemHandle]>;
|
||||
}
|
||||
|
||||
// Extend the FileSystemHandle interface to include getFile method
|
||||
// This is needed because TypeScript doesn't recognize that a FileSystemHandle
|
||||
// can be a FileSystemFileHandle which has the getFile method
|
||||
interface FileSystemHandle {
|
||||
getFile?(): Promise<File>;
|
||||
}
|
||||
|
||||
// Export something to make this a module
|
||||
export const fileSystemTypesLoaded = true
|
||||
|
|
@ -1,288 +0,0 @@
|
|||
/**
|
||||
* Standardized Progress Reporting
|
||||
*
|
||||
* Provides unified progress tracking across all long-running operations
|
||||
* in Brainy (imports, clustering, large searches, etc.)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Progress status states
|
||||
*/
|
||||
export type ProgressStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'
|
||||
|
||||
/**
|
||||
* Standardized progress report
|
||||
*/
|
||||
export interface BrainyProgress<T = any> {
|
||||
// Core status
|
||||
status: ProgressStatus
|
||||
|
||||
// Progress percentage (0-100)
|
||||
progress: number
|
||||
|
||||
// Human-readable message
|
||||
message: string
|
||||
|
||||
// Detailed metadata
|
||||
metadata: {
|
||||
itemsProcessed: number
|
||||
itemsTotal: number
|
||||
currentItem?: string
|
||||
estimatedTimeRemaining?: number // milliseconds
|
||||
startedAt: number
|
||||
completedAt?: number
|
||||
throughput?: number // items per second
|
||||
}
|
||||
|
||||
// Result when completed
|
||||
result?: T
|
||||
|
||||
// Error when failed
|
||||
error?: Error
|
||||
}
|
||||
|
||||
/**
|
||||
* Progress tracker with automatic time estimation
|
||||
*/
|
||||
export class ProgressTracker<T = any> {
|
||||
private status: ProgressStatus = 'pending'
|
||||
private processed = 0
|
||||
private total: number
|
||||
private startedAt?: number
|
||||
private completedAt?: number
|
||||
private currentItem?: string
|
||||
private result?: T
|
||||
private error?: Error
|
||||
private processingTimes: number[] = [] // Track last N processing times for estimation
|
||||
|
||||
constructor(total: number) {
|
||||
if (total < 0) {
|
||||
throw new Error('Total must be non-negative')
|
||||
}
|
||||
this.total = total
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating progress trackers
|
||||
*/
|
||||
static create<T>(total: number): ProgressTracker<T> {
|
||||
return new ProgressTracker<T>(total)
|
||||
}
|
||||
|
||||
/**
|
||||
* Start tracking progress
|
||||
*/
|
||||
start(): BrainyProgress<T> {
|
||||
this.status = 'running'
|
||||
this.startedAt = Date.now()
|
||||
return this.current()
|
||||
}
|
||||
|
||||
/**
|
||||
* Update progress
|
||||
*/
|
||||
update(processed: number, currentItem?: string): BrainyProgress<T> {
|
||||
if (processed < 0) {
|
||||
throw new Error('Processed count must be non-negative')
|
||||
}
|
||||
if (processed > this.total) {
|
||||
throw new Error(`Processed count (${processed}) exceeds total (${this.total})`)
|
||||
}
|
||||
|
||||
const previousProcessed = this.processed
|
||||
this.processed = processed
|
||||
this.currentItem = currentItem
|
||||
|
||||
// Track processing time for estimation
|
||||
if (this.startedAt && previousProcessed < processed) {
|
||||
const itemsProcessed = processed - previousProcessed
|
||||
const timeTaken = Date.now() - this.startedAt
|
||||
const avgTimePerItem = timeTaken / processed
|
||||
this.processingTimes.push(avgTimePerItem)
|
||||
|
||||
// Keep only last 100 measurements for rolling average
|
||||
if (this.processingTimes.length > 100) {
|
||||
this.processingTimes.shift()
|
||||
}
|
||||
}
|
||||
|
||||
return this.current()
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment progress by 1
|
||||
*/
|
||||
increment(currentItem?: string): BrainyProgress<T> {
|
||||
return this.update(this.processed + 1, currentItem)
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark as completed
|
||||
*/
|
||||
complete(result: T): BrainyProgress<T> {
|
||||
this.status = 'completed'
|
||||
this.completedAt = Date.now()
|
||||
this.processed = this.total
|
||||
this.result = result
|
||||
return this.current()
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark as failed
|
||||
*/
|
||||
fail(error: Error): BrainyProgress<T> {
|
||||
this.status = 'failed'
|
||||
this.completedAt = Date.now()
|
||||
this.error = error
|
||||
return this.current()
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark as cancelled
|
||||
*/
|
||||
cancel(): BrainyProgress<T> {
|
||||
this.status = 'cancelled'
|
||||
this.completedAt = Date.now()
|
||||
return this.current()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current progress state
|
||||
*/
|
||||
current(): BrainyProgress<T> {
|
||||
const progress = this.total > 0 ? Math.round((this.processed / this.total) * 100) : 0
|
||||
|
||||
// Generate message based on status
|
||||
let message: string
|
||||
switch (this.status) {
|
||||
case 'pending':
|
||||
message = `Ready to process ${this.total} items`
|
||||
break
|
||||
case 'running':
|
||||
message = this.currentItem
|
||||
? `Processing: ${this.currentItem} (${this.processed}/${this.total})`
|
||||
: `Processing ${this.processed}/${this.total} items`
|
||||
break
|
||||
case 'completed':
|
||||
message = `Completed ${this.total} items`
|
||||
break
|
||||
case 'failed':
|
||||
message = `Failed after ${this.processed} items: ${this.error?.message || 'Unknown error'}`
|
||||
break
|
||||
case 'cancelled':
|
||||
message = `Cancelled after ${this.processed} items`
|
||||
break
|
||||
}
|
||||
|
||||
return {
|
||||
status: this.status,
|
||||
progress,
|
||||
message,
|
||||
metadata: {
|
||||
itemsProcessed: this.processed,
|
||||
itemsTotal: this.total,
|
||||
currentItem: this.currentItem,
|
||||
estimatedTimeRemaining: this.estimateTimeRemaining(),
|
||||
startedAt: this.startedAt || Date.now(),
|
||||
completedAt: this.completedAt,
|
||||
throughput: this.calculateThroughput()
|
||||
},
|
||||
result: this.result,
|
||||
error: this.error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate time remaining based on processing history
|
||||
*/
|
||||
private estimateTimeRemaining(): number | undefined {
|
||||
if (this.status !== 'running' || !this.startedAt || this.processed === 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const remaining = this.total - this.processed
|
||||
if (remaining === 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Use rolling average if we have enough samples
|
||||
if (this.processingTimes.length > 0) {
|
||||
const avgTimePerItem = this.processingTimes.reduce((a, b) => a + b, 0) / this.processingTimes.length
|
||||
return Math.round(avgTimePerItem * remaining)
|
||||
}
|
||||
|
||||
// Fallback to simple calculation
|
||||
const elapsed = Date.now() - this.startedAt
|
||||
const avgTimePerItem = elapsed / this.processed
|
||||
return Math.round(avgTimePerItem * remaining)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate current throughput (items/second)
|
||||
*/
|
||||
private calculateThroughput(): number | undefined {
|
||||
if (!this.startedAt || this.processed === 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const elapsed = Date.now() - this.startedAt
|
||||
const seconds = elapsed / 1000
|
||||
return seconds > 0 ? Math.round((this.processed / seconds) * 100) / 100 : undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Get progress statistics
|
||||
*/
|
||||
getStats() {
|
||||
const elapsed = this.startedAt ? Date.now() - this.startedAt : 0
|
||||
return {
|
||||
status: this.status,
|
||||
processed: this.processed,
|
||||
total: this.total,
|
||||
remaining: this.total - this.processed,
|
||||
progress: this.total > 0 ? this.processed / this.total : 0,
|
||||
elapsed,
|
||||
estimatedTotal: elapsed > 0 && this.processed > 0
|
||||
? Math.round((elapsed / this.processed) * this.total)
|
||||
: undefined,
|
||||
throughput: this.calculateThroughput()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to format time duration
|
||||
*/
|
||||
export function formatDuration(ms: number): string {
|
||||
const seconds = Math.floor(ms / 1000)
|
||||
const minutes = Math.floor(seconds / 60)
|
||||
const hours = Math.floor(minutes / 60)
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes % 60}m`
|
||||
} else if (minutes > 0) {
|
||||
return `${minutes}m ${seconds % 60}s`
|
||||
} else {
|
||||
return `${seconds}s`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to format progress percentage
|
||||
*/
|
||||
export function formatProgress(progress: BrainyProgress): string {
|
||||
const { status, progress: pct, metadata } = progress
|
||||
const remaining = metadata.estimatedTimeRemaining
|
||||
|
||||
let str = `[${status.toUpperCase()}] ${pct}% (${metadata.itemsProcessed}/${metadata.itemsTotal})`
|
||||
|
||||
if (metadata.throughput) {
|
||||
str += ` - ${metadata.throughput} items/s`
|
||||
}
|
||||
|
||||
if (remaining && remaining > 0) {
|
||||
str += ` - ${formatDuration(remaining)} remaining`
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
/**
|
||||
* Type Migration Utilities for Stage 3 Taxonomy
|
||||
*
|
||||
* Provides migration helpers for code using removed types from v5.x
|
||||
*
|
||||
* ## Removed Types
|
||||
*
|
||||
* ### Nouns (2 removed):
|
||||
* - `user` → merged into `person`
|
||||
* - `topic` → merged into `concept`
|
||||
*
|
||||
* ### Verbs (4 removed):
|
||||
* - `succeeds` → use inverse of `precedes`
|
||||
* - `belongsTo` → use inverse of `owns`
|
||||
* - `createdBy` → use inverse of `creates`
|
||||
* - `supervises` → use inverse of `reportsTo`
|
||||
*/
|
||||
|
||||
import { NounType, VerbType } from './graphTypes.js'
|
||||
|
||||
/**
|
||||
* Migration mapping for removed noun types
|
||||
*/
|
||||
export const REMOVED_NOUN_TYPES = {
|
||||
user: NounType.Person,
|
||||
topic: NounType.Concept
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Migration mapping for removed verb types
|
||||
* Note: Some verbs should use inverse relationships in Stage 3
|
||||
*/
|
||||
export const REMOVED_VERB_TYPES = {
|
||||
succeeds: VerbType.Precedes, // Use with inverted source/target
|
||||
belongsTo: VerbType.Owns, // Use with inverted source/target
|
||||
createdBy: VerbType.Creates, // Use with inverted source/target
|
||||
supervises: VerbType.ReportsTo // Use with inverted source/target
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Check if a type was removed in Stage 3
|
||||
*/
|
||||
export function isRemovedNounType(type: string): type is keyof typeof REMOVED_NOUN_TYPES {
|
||||
return type in REMOVED_NOUN_TYPES
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a verb type was removed in Stage 3
|
||||
*/
|
||||
export function isRemovedVerbType(type: string): type is keyof typeof REMOVED_VERB_TYPES {
|
||||
return type in REMOVED_VERB_TYPES
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate a noun type (Stage 3)
|
||||
* Returns the migrated type or the original if no migration needed
|
||||
*/
|
||||
export function migrateNounType(type: string): NounType {
|
||||
if (isRemovedNounType(type)) {
|
||||
console.warn(`⚠️ NounType "${type}" was removed in v6.0. Migrating to "${REMOVED_NOUN_TYPES[type]}"`)
|
||||
return REMOVED_NOUN_TYPES[type]
|
||||
}
|
||||
return type as NounType
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate a verb type (Stage 3)
|
||||
* Returns the migrated type or the original if no migration needed
|
||||
*
|
||||
* WARNING: Some verbs require inverting source/target relationships!
|
||||
* See VERB_REQUIRES_INVERSION for details.
|
||||
*/
|
||||
export function migrateVerbType(type: string): VerbType {
|
||||
if (isRemovedVerbType(type)) {
|
||||
console.warn(`⚠️ VerbType "${type}" was removed in v6.0. Migrating to "${REMOVED_VERB_TYPES[type]}" (may require source/target inversion)`)
|
||||
return REMOVED_VERB_TYPES[type]
|
||||
}
|
||||
return type as VerbType
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbs that require inverting source/target when migrating
|
||||
*
|
||||
* Example:
|
||||
* - Old: `A createdBy B` → New: `B creates A`
|
||||
* - Old: `A belongsTo B` → New: `B owns A`
|
||||
* - Old: `A supervises B` → New: `B reportsTo A`
|
||||
* - Old: `A succeeds B` → New: `B precedes A`
|
||||
*/
|
||||
export const VERB_REQUIRES_INVERSION = new Set([
|
||||
'succeeds',
|
||||
'belongsTo',
|
||||
'createdBy',
|
||||
'supervises'
|
||||
])
|
||||
|
||||
/**
|
||||
* Check if a verb type requires inverting source/target during migration
|
||||
*/
|
||||
export function requiresInversion(oldVerbType: string): boolean {
|
||||
return VERB_REQUIRES_INVERSION.has(oldVerbType)
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate a relationship, handling source/target inversion if needed
|
||||
*
|
||||
* @returns Object with migrated verb and potentially inverted source/target
|
||||
*/
|
||||
export function migrateRelationship(params: {
|
||||
verb: string
|
||||
source: string
|
||||
target: string
|
||||
}): {
|
||||
verb: VerbType
|
||||
source: string
|
||||
target: string
|
||||
inverted: boolean
|
||||
} {
|
||||
const verb = migrateVerbType(params.verb)
|
||||
const inverted = requiresInversion(params.verb)
|
||||
|
||||
if (inverted) {
|
||||
return {
|
||||
verb,
|
||||
source: params.target, // Swap source and target
|
||||
target: params.source,
|
||||
inverted: true
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
verb,
|
||||
source: params.source,
|
||||
target: params.target,
|
||||
inverted: false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stage 3 Type Compatibility Check
|
||||
* Helps developers identify code that needs updating
|
||||
*/
|
||||
export function checkTypeCompatibility(nounTypes: string[], verbTypes: string[]): {
|
||||
valid: boolean
|
||||
removedNouns: string[]
|
||||
removedVerbs: string[]
|
||||
warnings: string[]
|
||||
} {
|
||||
const removedNouns = nounTypes.filter(isRemovedNounType)
|
||||
const removedVerbs = verbTypes.filter(isRemovedVerbType)
|
||||
const warnings: string[] = []
|
||||
|
||||
if (removedNouns.length > 0) {
|
||||
warnings.push(
|
||||
`Found ${removedNouns.length} removed noun type(s): ${removedNouns.join(', ')}. ` +
|
||||
`These were merged in Stage 3. Use Person instead of User, Concept instead of Topic.`
|
||||
)
|
||||
}
|
||||
|
||||
if (removedVerbs.length > 0) {
|
||||
warnings.push(
|
||||
`Found ${removedVerbs.length} removed verb type(s): ${removedVerbs.join(', ')}. ` +
|
||||
`These require using inverse relationships in Stage 3. ` +
|
||||
`Example: "A createdBy B" becomes "B creates A".`
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
valid: removedNouns.length === 0 && removedVerbs.length === 0,
|
||||
removedNouns,
|
||||
removedVerbs,
|
||||
warnings
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue