mlld
Version:
mlld: a modular prompt scripting language
276 lines (273 loc) • 8.28 kB
JavaScript
import { logger } from './chunk-XGMRAGIT.mjs';
import { MlldResolutionError, MlldFileNotFoundError } from './chunk-YMCO2JI3.mjs';
import { __name, __publicField } from './chunk-OMKLS24H.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 lockFilePath = path.join(currentDir, "mlld.lock.json");
if (await fileSystem.exists(lockFilePath)) {
logger.debug(`Found mlld.lock.json 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 mlld.lock.json is missing`);
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");
__publicField(this, "description");
__publicField(this, "type");
__publicField(this, "capabilities");
this.fileSystem = fileSystem;
this.name = "base";
this.description = "Resolves @base references to project root files";
this.type = "io";
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
};
}
canResolve(ref, config) {
return ref.startsWith("@base") || !!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") {
return {
content: basePath,
contentType: "text",
metadata: {
source: "base",
timestamp: /* @__PURE__ */ new Date()
}
};
}
}
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 {
relativePath = ref;
}
if (relativePath.startsWith("/")) {
relativePath = relativePath.substring(1);
}
if (!relativePath) {
return {
content: basePath,
contentType: "text",
metadata: {
source: "base",
timestamp: /* @__PURE__ */ new Date()
}
};
}
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);
return {
content,
contentType,
metadata: {
source: withMld,
timestamp: /* @__PURE__ */ new Date(),
originalRef: ref
}
};
}
}
throw new MlldFileNotFoundError(`File not found: ${fullPath}`, {
path: fullPath
});
}
try {
const content = await this.fileSystem.readFile(fullPath);
const contentType = await this.detectContentType(fullPath, content);
return {
content,
contentType,
metadata: {
source: fullPath,
timestamp: /* @__PURE__ */ new Date(),
originalRef: ref
}
};
} 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") || filePath.endsWith(".mlld")) {
return "module";
}
if (filePath.endsWith(".json")) {
return "data";
}
try {
const { parse } = await import('./parser-X2XXTU6D.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-P46TIXQR.mjs.map
//# sourceMappingURL=chunk-P46TIXQR.mjs.map