mlld
Version:
mlld: llm scripting language
1 lines • 21.4 kB
Source Map (JSON)
{"version":3,"sources":["../core/utils/findProjectRoot.ts","../core/resolvers/ProjectPathResolver.ts"],"names":["findProjectRoot","startPath","fileSystem","currentDir","resolve","homeDir","homedir","logger","debug","dirname","configFiles","configFile","configPath","join","exists","fallbackIndicators","indicator","warn","ProjectPathResolver","name","aliases","description","type","capabilities","io","read","write","list","contexts","import","path","output","supportedContentTypes","defaultContentType","priority","cache","strategy","canResolve","ref","config","startsWith","basePath","isProjectRoot","findProjectRootFromCwd","MlldResolutionError","reference","availableConfig","Object","keys","context","metadata","source","timestamp","Date","content","contentType","mx","relativePath","substring","length","fullPath","normalizedBasePath","normalizedFullPath","extname","withMld","readFile","detectContentType","originalRef","MlldFileNotFoundError","error","result","validateConfig","errors","push","checkAccess","operation","readonly","filePath","endsWith","parse","success","hasModuleExports","ast","JSON","Array","isArray","some","node","includes","kind","indicators","projectRoot","process","cwd"],"mappings":"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","file":"chunk-2CD5MH5K.mjs","sourcesContent":["import * as path from 'path';\nimport * as os from 'os';\nimport type { IFileSystemService } from '@services/fs/IFileSystemService';\nimport { logger } from '@core/utils/logger';\n\n/**\n * Find the project root by searching up the directory tree for mlld config files\n * or other project indicators.\n *\n * @param startPath - The directory to start searching from\n * @param fileSystem - The filesystem service to use\n * @returns The project root path, or the original startPath if not found\n */\nexport async function findProjectRoot(\n startPath: string,\n fileSystem: IFileSystemService\n): Promise<string> {\n let currentDir = path.resolve(startPath);\n const homeDir = os.homedir();\n\n logger.debug(`Finding project root from: ${startPath}`);\n\n while (currentDir !== homeDir && currentDir !== path.dirname(currentDir)) {\n // Check for mlld config files (new names first, old name for backward compatibility)\n const configFiles = [\n 'mlld-config.json',\n 'mlld-lock.json',\n 'mlld.lock.json' // Backward compatibility\n ];\n\n for (const configFile of configFiles) {\n const configPath = path.join(currentDir, configFile);\n if (await fileSystem.exists(configPath)) {\n logger.debug(`Found ${configFile} at: ${currentDir}`);\n return currentDir;\n }\n }\n\n // Fallback indicators (if no mlld config files found)\n const fallbackIndicators = ['package.json', '.git', 'pyproject.toml', 'Cargo.toml'];\n for (const indicator of fallbackIndicators) {\n if (await fileSystem.exists(path.join(currentDir, indicator))) {\n // Found a project root, but warn that mlld config is missing\n logger.warn(`Found project root at ${currentDir} but no mlld config files found`);\n return currentDir;\n }\n }\n\n currentDir = path.dirname(currentDir);\n }\n\n // If no project root found, return original startPath\n logger.debug(`No project root found, using original path: ${startPath}`);\n return startPath;\n}","import * as path from 'path';\nimport { \n Resolver, \n ResolverContent, \n ResolverType,\n ContentInfo,\n ResolverCapabilities\n} from '@core/resolvers/types';\nimport { MlldResolutionError, MlldFileNotFoundError } from '@core/errors';\nimport { IFileSystemService } from '@services/fs/IFileSystemService';\nimport { findProjectRoot } from '@core/utils/findProjectRoot';\nimport { logger } from '@core/utils/logger';\n\n/**\n * Configuration for ProjectPathResolver\n */\nexport interface ProjectPathResolverConfig {\n /**\n * Base path for the project (typically project root)\n */\n basePath: string;\n\n /**\n * Whether this resolver is read-only\n */\n readonly?: boolean;\n}\n\n/**\n * Base Path Resolver - handles @base/ and @root/ references\n * Maps @base/@root to the project root directory\n */\nexport class ProjectPathResolver implements Resolver {\n name = 'base';\n aliases = ['root'];\n description = 'Resolves @base and @root references to project root files';\n type: ResolverType = 'io';\n \n capabilities: ResolverCapabilities = {\n io: { read: true, write: false, list: false },\n contexts: { import: true, path: true, output: false },\n supportedContentTypes: ['text', 'module'],\n defaultContentType: 'text',\n priority: 1,\n cache: { strategy: 'none' } // Project path is static\n };\n\n constructor(private fileSystem: IFileSystemService) {\n // No caching needed - project path is static\n }\n\n canResolve(ref: string, config?: ProjectPathResolverConfig): boolean {\n // Can resolve if reference starts with @base or @root\n // OR if we have a config (which means prefix was stripped)\n return ref.startsWith('@base') || ref.startsWith('@root') || !!config;\n }\n\n /**\n * Resolve a @base reference\n */\n async resolve(ref: string, config?: ProjectPathResolverConfig): Promise<ResolverContent> {\n // Try config basePath first\n let basePath = config?.basePath;\n \n // If not provided or seems incorrect, detect project root\n if (!basePath || !(await this.isProjectRoot(basePath))) {\n logger.debug(`Detecting project root (basePath: ${basePath})`);\n basePath = await this.findProjectRootFromCwd();\n }\n \n if (!basePath) {\n throw new MlldResolutionError(\n 'ProjectPathResolver: Unable to determine project root. ' +\n 'This usually means the resolver registry was not properly configured. ' +\n 'Check that @base prefix is mapped to base resolver with basePath.',\n { reference: ref, availableConfig: Object.keys(config || {}) }\n );\n }\n\n // Variable context - return the project path as text\n if (!config || !config.context || config.context === 'variable') {\n // If it's just @base or @root, return the base path\n if (ref === '@base' || ref === 'base' || ref === '@root' || ref === 'root') {\n const metadata = {\n source: 'base',\n timestamp: new Date()\n };\n return {\n content: basePath,\n contentType: 'text',\n mx: metadata,\n metadata\n };\n }\n }\n\n // Path context - read the file content\n if (config.context === 'path') {\n // Extract the path after @base or @root\n let relativePath: string;\n if (ref.startsWith('@base/')) {\n relativePath = ref.substring('@base/'.length);\n } else if (ref.startsWith('@base')) {\n relativePath = ref.substring('@base'.length);\n } else if (ref.startsWith('@root/')) {\n relativePath = ref.substring('@root/'.length);\n } else if (ref.startsWith('@root')) {\n relativePath = ref.substring('@root'.length);\n } else {\n // With prefix stripping, we might just get the path directly\n relativePath = ref;\n }\n\n // Remove leading slash if present\n if (relativePath.startsWith('/')) {\n relativePath = relativePath.substring(1);\n }\n\n // If no path specified, just return the project path\n if (!relativePath) {\n const metadata = {\n source: 'base',\n timestamp: new Date()\n };\n return {\n content: basePath,\n contentType: 'text',\n mx: metadata,\n metadata\n };\n }\n\n // Resolve full path relative to project root\n const fullPath = path.resolve(basePath, relativePath);\n\n // Security check: ensure the resolved path is within the project\n const normalizedBasePath = path.resolve(basePath);\n const normalizedFullPath = path.resolve(fullPath);\n if (!normalizedFullPath.startsWith(normalizedBasePath)) {\n throw new MlldResolutionError(\n `Path outside project directory: ${relativePath}`,\n {}\n );\n }\n\n // Check if file exists\n if (!await this.fileSystem.exists(fullPath)) {\n // Try with .mld extension if no extension provided\n if (!path.extname(fullPath)) {\n const withMld = fullPath + '.mld';\n if (await this.fileSystem.exists(withMld)) {\n const content = await this.fileSystem.readFile(withMld);\n const contentType = await this.detectContentType(withMld, content);\n \n const metadata = {\n source: withMld,\n timestamp: new Date(),\n originalRef: ref\n };\n return {\n content,\n contentType,\n mx: metadata,\n metadata\n };\n }\n }\n \n throw new MlldFileNotFoundError(\n `File not found: ${fullPath}`,\n { path: fullPath }\n );\n }\n\n try {\n // Read the file\n const content = await this.fileSystem.readFile(fullPath);\n const contentType = await this.detectContentType(fullPath, content);\n\n const metadata = {\n source: fullPath,\n timestamp: new Date(),\n originalRef: ref\n };\n return {\n content,\n contentType,\n mx: metadata,\n metadata\n };\n } catch (error) {\n throw new MlldFileNotFoundError(\n `Failed to read file: ${fullPath}`,\n { path: fullPath }\n );\n }\n }\n\n // Import context - similar to path but validates module content\n if (config.context === 'import') {\n // For imports, delegate to path logic but ensure module validation\n const result = await this.resolve(ref, { ...config, context: 'path' });\n \n // Validate that imported content is a module\n if (result.contentType !== 'module') {\n throw new MlldResolutionError(\n `Import target is not a module: ${ref}`,\n {}\n );\n }\n \n return result;\n }\n\n throw new MlldResolutionError(\n `base resolver does not support context: ${config.context}`,\n {}\n );\n }\n\n /**\n * Validate resolver configuration\n */\n validateConfig(config: any): string[] {\n const errors: string[] = [];\n \n if (!config) {\n errors.push('Configuration is required');\n return errors;\n }\n\n if (!config.basePath) {\n errors.push('basePath is required');\n } else if (typeof config.basePath !== 'string') {\n errors.push('basePath must be a string');\n }\n\n return errors;\n }\n\n /**\n * Check if an operation is allowed\n */\n async checkAccess(ref: string, operation: 'read' | 'write', config?: ProjectPathResolverConfig): Promise<boolean> {\n // For now, allow all read operations, deny write operations if readonly\n if (operation === 'write' && config?.readonly) {\n return false;\n }\n return operation === 'read';\n }\n\n /**\n * Detect content type based on file extension and content\n */\n private async detectContentType(filePath: string, content: string): Promise<'module' | 'data' | 'text'> {\n // Check file extension - support all mlld module extensions\n if (filePath.endsWith('.mld.md') || filePath.endsWith('.mld') ||\n filePath.endsWith('.mlld.md') || filePath.endsWith('.mlld')) {\n return 'module';\n }\n if (filePath.endsWith('.json')) {\n return 'data';\n }\n \n // Try to detect mlld module content\n try {\n const { parse } = await import('@grammar/parser');\n const result = await parse(content);\n if (result.success && this.hasModuleExports(result.ast)) {\n return 'module';\n }\n } catch {\n // Not valid mlld\n }\n \n // Try JSON\n try {\n JSON.parse(content);\n return 'data';\n } catch {\n // Not JSON\n }\n \n return 'text';\n }\n \n /**\n * Check if AST has module exports\n */\n private hasModuleExports(ast: any): boolean {\n // Check if there are any directive nodes (not just text/newlines)\n if (!ast || !Array.isArray(ast)) return false;\n \n return ast.some(node => \n node && node.type === 'Directive' && \n ['var', 'exe', 'path'].includes(node.kind)\n );\n }\n\n /**\n * Check if a path is likely a project root\n */\n private async isProjectRoot(path: string): Promise<boolean> {\n // Check for project indicators\n const indicators = ['package.json', '.git', 'mlld.config.json', 'mlld.lock.json'];\n for (const indicator of indicators) {\n if (await this.fileSystem.exists(path + '/' + indicator)) {\n return true;\n }\n }\n return false;\n }\n \n /**\n * Find project root from current working directory\n */\n private async findProjectRootFromCwd(): Promise<string | null> {\n try {\n const projectRoot = await findProjectRoot(process.cwd(), this.fileSystem);\n return projectRoot;\n } catch (error) {\n logger.warn('Failed to find project root:', error);\n return null;\n }\n }\n}\n"]}