UNPKG

mlld

Version:

mlld: llm scripting language

295 lines (292 loc) 8.96 kB
import { logger } from './chunk-M3R2H5KU.mjs'; import { MlldResolutionError, MlldFileNotFoundError } from './chunk-V5XE5YB5.mjs'; import { __name, __publicField } from './chunk-NJQT543K.mjs'; import * as path from 'path'; import * as os from 'os'; async function findProjectRoot(startPath, fileSystem) { let currentDir = path.resolve(startPath); const homeDir = os.homedir(); logger.debug(`Finding project root from: ${startPath}`); while (currentDir !== homeDir && currentDir !== path.dirname(currentDir)) { const configFiles = [ "mlld-config.json", "mlld-lock.json", "mlld.lock.json" // Backward compatibility ]; for (const configFile of configFiles) { const configPath = path.join(currentDir, configFile); if (await fileSystem.exists(configPath)) { logger.debug(`Found ${configFile} at: ${currentDir}`); return currentDir; } } const fallbackIndicators = [ "package.json", ".git", "pyproject.toml", "Cargo.toml" ]; for (const indicator of fallbackIndicators) { if (await fileSystem.exists(path.join(currentDir, indicator))) { logger.warn(`Found project root at ${currentDir} but no mlld config files found`); return currentDir; } } currentDir = path.dirname(currentDir); } logger.debug(`No project root found, using original path: ${startPath}`); return startPath; } __name(findProjectRoot, "findProjectRoot"); // core/resolvers/ProjectPathResolver.ts var _ProjectPathResolver = class _ProjectPathResolver { constructor(fileSystem) { __publicField(this, "fileSystem"); __publicField(this, "name", "base"); __publicField(this, "aliases", [ "root" ]); __publicField(this, "description", "Resolves @base and @root references to project root files"); __publicField(this, "type", "io"); __publicField(this, "capabilities", { io: { read: true, write: false, list: false }, contexts: { import: true, path: true, output: false }, supportedContentTypes: [ "text", "module" ], defaultContentType: "text", priority: 1, cache: { strategy: "none" } // Project path is static }); this.fileSystem = fileSystem; } canResolve(ref, config) { return ref.startsWith("@base") || ref.startsWith("@root") || !!config; } /** * Resolve a @base reference */ async resolve(ref, config) { let basePath = config?.basePath; if (!basePath || !await this.isProjectRoot(basePath)) { logger.debug(`Detecting project root (basePath: ${basePath})`); basePath = await this.findProjectRootFromCwd(); } if (!basePath) { throw new MlldResolutionError("ProjectPathResolver: Unable to determine project root. This usually means the resolver registry was not properly configured. Check that @base prefix is mapped to base resolver with basePath.", { reference: ref, availableConfig: Object.keys(config || {}) }); } if (!config || !config.context || config.context === "variable") { if (ref === "@base" || ref === "base" || ref === "@root" || ref === "root") { const metadata = { source: "base", timestamp: /* @__PURE__ */ new Date() }; return { content: basePath, contentType: "text", mx: metadata, metadata }; } } if (config.context === "path") { let relativePath; if (ref.startsWith("@base/")) { relativePath = ref.substring("@base/".length); } else if (ref.startsWith("@base")) { relativePath = ref.substring("@base".length); } else if (ref.startsWith("@root/")) { relativePath = ref.substring("@root/".length); } else if (ref.startsWith("@root")) { relativePath = ref.substring("@root".length); } else { relativePath = ref; } if (relativePath.startsWith("/")) { relativePath = relativePath.substring(1); } if (!relativePath) { const metadata = { source: "base", timestamp: /* @__PURE__ */ new Date() }; return { content: basePath, contentType: "text", mx: metadata, metadata }; } const fullPath = path.resolve(basePath, relativePath); const normalizedBasePath = path.resolve(basePath); const normalizedFullPath = path.resolve(fullPath); if (!normalizedFullPath.startsWith(normalizedBasePath)) { throw new MlldResolutionError(`Path outside project directory: ${relativePath}`, {}); } if (!await this.fileSystem.exists(fullPath)) { if (!path.extname(fullPath)) { const withMld = fullPath + ".mld"; if (await this.fileSystem.exists(withMld)) { const content = await this.fileSystem.readFile(withMld); const contentType = await this.detectContentType(withMld, content); const metadata = { source: withMld, timestamp: /* @__PURE__ */ new Date(), originalRef: ref }; return { content, contentType, mx: metadata, metadata }; } } throw new MlldFileNotFoundError(`File not found: ${fullPath}`, { path: fullPath }); } try { const content = await this.fileSystem.readFile(fullPath); const contentType = await this.detectContentType(fullPath, content); const metadata = { source: fullPath, timestamp: /* @__PURE__ */ new Date(), originalRef: ref }; return { content, contentType, mx: metadata, metadata }; } catch (error) { throw new MlldFileNotFoundError(`Failed to read file: ${fullPath}`, { path: fullPath }); } } if (config.context === "import") { const result = await this.resolve(ref, { ...config, context: "path" }); if (result.contentType !== "module") { throw new MlldResolutionError(`Import target is not a module: ${ref}`, {}); } return result; } throw new MlldResolutionError(`base resolver does not support context: ${config.context}`, {}); } /** * Validate resolver configuration */ validateConfig(config) { const errors = []; if (!config) { errors.push("Configuration is required"); return errors; } if (!config.basePath) { errors.push("basePath is required"); } else if (typeof config.basePath !== "string") { errors.push("basePath must be a string"); } return errors; } /** * Check if an operation is allowed */ async checkAccess(ref, operation, config) { if (operation === "write" && config?.readonly) { return false; } return operation === "read"; } /** * Detect content type based on file extension and content */ async detectContentType(filePath, content) { if (filePath.endsWith(".mld.md") || filePath.endsWith(".mld") || filePath.endsWith(".mlld.md") || filePath.endsWith(".mlld")) { return "module"; } if (filePath.endsWith(".json")) { return "data"; } try { const { parse } = await import('./parser-6HNWFG6W.mjs'); const result = await parse(content); if (result.success && this.hasModuleExports(result.ast)) { return "module"; } } catch { } try { JSON.parse(content); return "data"; } catch { } return "text"; } /** * Check if AST has module exports */ hasModuleExports(ast) { if (!ast || !Array.isArray(ast)) return false; return ast.some((node) => node && node.type === "Directive" && [ "var", "exe", "path" ].includes(node.kind)); } /** * Check if a path is likely a project root */ async isProjectRoot(path3) { const indicators = [ "package.json", ".git", "mlld.config.json", "mlld.lock.json" ]; for (const indicator of indicators) { if (await this.fileSystem.exists(path3 + "/" + indicator)) { return true; } } return false; } /** * Find project root from current working directory */ async findProjectRootFromCwd() { try { const projectRoot = await findProjectRoot(process.cwd(), this.fileSystem); return projectRoot; } catch (error) { logger.warn("Failed to find project root:", error); return null; } } }; __name(_ProjectPathResolver, "ProjectPathResolver"); var ProjectPathResolver = _ProjectPathResolver; export { ProjectPathResolver, findProjectRoot }; //# sourceMappingURL=chunk-2CD5MH5K.mjs.map //# sourceMappingURL=chunk-2CD5MH5K.mjs.map