@aigne/afs-mapping 1.11.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +26 -0
- package/README.md +286 -0
- package/dist/index.d.mts +912 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +828 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["parseYaml"],"sources":["../src/binder.ts","../src/schema.ts","../src/parser.ts","../src/projector.ts","../src/resolver.ts","../src/compiler.ts"],"sourcesContent":["/**\n * Parameter Binder\n *\n * Evaluates binding expressions like \"path.owner\", \"query.state | default('open')\".\n * Supports pipe operators for transformations.\n */\n\n/**\n * Context for evaluating binding expressions\n */\nexport interface BindingContext {\n /** Path parameters extracted from route matching */\n path: Record<string, string>;\n /** Query parameters from URL */\n query: Record<string, string>;\n /** Input data (for write operations) */\n input: Record<string, unknown>;\n /** API response data (for JSONPath expressions) */\n data: unknown;\n}\n\n/**\n * A pipe operator in an expression\n */\nexport interface Pipe {\n name: string;\n args: unknown[];\n}\n\n/**\n * Parsed binding expression\n */\nexport interface ParsedExpression {\n /** Source type: path, query, input, jsonpath, or literal */\n source: \"path\" | \"query\" | \"input\" | \"jsonpath\" | \"literal\";\n /** Key to access (or JSONPath expression, or literal value) */\n key: string;\n /** Pipe operators to apply */\n pipes: Pipe[];\n}\n\n/**\n * Expression binder for evaluating binding expressions\n */\nexport class ExpressionBinder {\n /**\n * Parse a binding expression string\n */\n parseExpression(expr: string): ParsedExpression {\n const trimmed = expr.trim();\n\n // Split by pipe, respecting parentheses\n const parts = this.splitByPipe(trimmed);\n const sourcePart = parts[0]?.trim() ?? \"\";\n const pipes = parts.slice(1).map((p) => this.parsePipe(p.trim()));\n\n // Determine source type\n if (sourcePart.startsWith(\"$\")) {\n // JSONPath expression\n return {\n source: \"jsonpath\",\n key: sourcePart,\n pipes,\n };\n }\n\n // Parse source.key format\n const dotIndex = sourcePart.indexOf(\".\");\n if (dotIndex === -1) {\n // No dot - treat as literal value\n return {\n source: \"literal\",\n key: sourcePart,\n pipes,\n };\n }\n\n const source = sourcePart.slice(0, dotIndex);\n const key = sourcePart.slice(dotIndex + 1);\n\n if (source !== \"path\" && source !== \"query\" && source !== \"input\") {\n // Unknown source type - treat as literal value\n return {\n source: \"literal\",\n key: sourcePart,\n pipes,\n };\n }\n\n return {\n source,\n key,\n pipes,\n };\n }\n\n /**\n * Split expression by pipe operator, respecting parentheses\n */\n private splitByPipe(expr: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n let parenDepth = 0;\n\n for (let i = 0; i < expr.length; i++) {\n const char = expr[i];\n\n if (char === \"(\") {\n parenDepth++;\n current += char;\n } else if (char === \")\") {\n parenDepth--;\n current += char;\n } else if (char === \"|\" && parenDepth === 0) {\n parts.push(current);\n current = \"\";\n } else {\n current += char;\n }\n }\n\n if (current) {\n parts.push(current);\n }\n\n return parts;\n }\n\n /**\n * Parse a pipe operator string like \"default('open')\" or \"int\"\n */\n private parsePipe(pipeStr: string): Pipe {\n const parenIndex = pipeStr.indexOf(\"(\");\n\n if (parenIndex === -1) {\n // No arguments\n return { name: pipeStr, args: [] };\n }\n\n const name = pipeStr.slice(0, parenIndex);\n const argsStr = pipeStr.slice(parenIndex + 1, -1); // Remove ( and )\n\n if (!argsStr) {\n return { name, args: [] };\n }\n\n // Parse arguments\n const args = this.parseArgs(argsStr);\n return { name, args };\n }\n\n /**\n * Parse comma-separated arguments, handling quoted strings and numbers\n */\n private parseArgs(argsStr: string): unknown[] {\n const args: unknown[] = [];\n let current = \"\";\n let inString = false;\n let stringChar = \"\";\n\n for (let i = 0; i < argsStr.length; i++) {\n const char = argsStr[i];\n\n if (!inString && (char === '\"' || char === \"'\")) {\n inString = true;\n stringChar = char;\n } else if (inString && char === stringChar) {\n inString = false;\n args.push(current);\n current = \"\";\n // Skip comma after closing quote\n if (argsStr[i + 1] === \",\") i++;\n } else if (!inString && char === \",\") {\n if (current.trim()) {\n args.push(this.parseValue(current.trim()));\n }\n current = \"\";\n } else {\n current += char;\n }\n }\n\n if (current.trim() && !inString) {\n args.push(this.parseValue(current.trim()));\n }\n\n return args;\n }\n\n /**\n * Parse a value (number or string)\n */\n private parseValue(value: string): unknown {\n // Try number\n const num = Number(value);\n if (!Number.isNaN(num)) {\n return num;\n }\n\n // Return as string\n return value;\n }\n\n /**\n * Evaluate a binding expression against a context\n */\n evaluate(expr: string, context: BindingContext): unknown {\n const parsed = this.parseExpression(expr);\n let value: unknown;\n\n // Get initial value based on source\n switch (parsed.source) {\n case \"path\":\n value = this.getNestedValue(context.path, parsed.key);\n break;\n case \"query\":\n value = this.getNestedValue(context.query, parsed.key);\n break;\n case \"input\":\n value = this.getNestedValue(context.input, parsed.key);\n break;\n case \"jsonpath\":\n value = this.evaluateJsonPath(parsed.key, context.data);\n break;\n case \"literal\":\n value = parsed.key;\n break;\n }\n\n // Apply pipes\n for (const pipe of parsed.pipes) {\n value = this.applyPipe(value, pipe);\n }\n\n return value;\n }\n\n /**\n * Get a nested value from an object using dot notation\n */\n private getNestedValue(obj: unknown, key: string): unknown {\n const parts = key.split(\".\");\n let current: unknown = obj;\n\n for (const part of parts) {\n if (current === null || current === undefined) {\n return undefined;\n }\n if (typeof current !== \"object\") {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n }\n\n /**\n * Evaluate a simple JSONPath expression\n * Note: This is a simplified implementation supporting basic paths\n */\n private evaluateJsonPath(jsonPath: string, data: unknown): unknown {\n if (!jsonPath.startsWith(\"$\")) {\n throw new Error(`Invalid JSONPath: ${jsonPath}`);\n }\n\n // Remove leading $\n const path = jsonPath.slice(1);\n\n if (!path || path === \".\") {\n return data;\n }\n\n // Parse the path\n const parts = this.parseJsonPathParts(path);\n let current: unknown = data;\n\n for (const part of parts) {\n if (current === null || current === undefined) {\n return undefined;\n }\n\n if (part === \"[*]\") {\n // Array wildcard - not supported in simple evaluation\n // Return as-is for now, projector handles this\n continue;\n }\n\n if (typeof current !== \"object\") {\n return undefined;\n }\n\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n }\n\n /**\n * Parse JSONPath parts like \".user.login\" or \"[0].name\"\n */\n private parseJsonPathParts(path: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n\n for (let i = 0; i < path.length; i++) {\n const char = path[i];\n\n if (char === \".\") {\n if (current) parts.push(current);\n current = \"\";\n } else if (char === \"[\") {\n if (current) parts.push(current);\n current = \"\";\n // Find matching ]\n const endBracket = path.indexOf(\"]\", i);\n if (endBracket === -1) {\n throw new Error(`Unmatched bracket in JSONPath: ${path}`);\n }\n const bracketContent = path.slice(i, endBracket + 1);\n parts.push(bracketContent);\n i = endBracket;\n } else {\n current += char;\n }\n }\n\n if (current) parts.push(current);\n return parts;\n }\n\n /**\n * Apply a pipe operator to a value\n */\n private applyPipe(value: unknown, pipe: Pipe): unknown {\n switch (pipe.name) {\n case \"default\":\n return value === undefined || value === null ? pipe.args[0] : value;\n\n case \"int\":\n if (value === undefined || value === null) return undefined;\n return parseInt(String(value), 10);\n\n case \"string\":\n if (value === undefined || value === null) return undefined;\n return String(value);\n\n case \"bool\":\n return Boolean(value);\n\n case \"json\":\n return JSON.stringify(value);\n\n default:\n // Unknown pipe - return value as-is\n return value;\n }\n }\n\n /**\n * Bind multiple expressions and return result object\n */\n bindAll(bindings: Record<string, string>, context: BindingContext): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, expr] of Object.entries(bindings)) {\n result[key] = this.evaluate(expr, context);\n }\n\n return result;\n }\n}\n","/**\n * Mapping DSL Schema Definitions\n *\n * Zod schemas for validating mapping configuration files.\n * The DSL allows declarative mapping of AFS paths to external API calls.\n */\n\nimport { z } from \"zod\";\n\n/**\n * Transform entry mapping - how to convert API response fields to AFS entry fields\n */\nexport const transformEntrySchema = z\n .object({\n /** Entry ID (usually from API item identifier) */\n id: z.string().optional(),\n /** AFS path for this entry */\n path: z.string().optional(),\n /** Entry summary (e.g., title) */\n summary: z.string().optional(),\n /** Entry description */\n description: z.string().optional(),\n /** Entry content (e.g., body) */\n content: z.string().optional(),\n /** Additional metadata (nested object supported) */\n meta: z.record(z.string(), z.any()).optional(),\n })\n .passthrough();\n\nexport type TransformEntry = z.infer<typeof transformEntrySchema>;\n\n/**\n * Transform configuration - how to convert API response to AFS entries\n */\nexport const transformSchema = z.object({\n /** JSONPath to items array (e.g., \"$\" for root, \"$.data\" for nested) */\n items: z.string().optional(),\n /** Mapping for each entry */\n entry: transformEntrySchema.optional(),\n});\n\nexport type Transform = z.infer<typeof transformSchema>;\n\n/**\n * Operation schema - a single API operation (list, read, write, etc.)\n */\nexport const operationSchema = z.object({\n /** Operation type (default: http) */\n type: z.enum([\"http\", \"graphql\", \"mcp-tool\"]).optional(),\n\n // HTTP operation fields\n /** HTTP method */\n method: z.enum([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"]).optional(),\n /** API path template */\n path: z.string().optional(),\n /** Parameter bindings (e.g., { owner: \"path.owner\", state: \"query.state | default('open')\" }) */\n params: z.record(z.string(), z.string()).optional(),\n /** Request body bindings (for POST/PUT/PATCH) */\n body: z.record(z.string(), z.string()).optional(),\n /** Custom headers */\n headers: z.record(z.string(), z.string()).optional(),\n\n // GraphQL operation fields\n /** GraphQL query string */\n query: z.string().optional(),\n /** GraphQL variables bindings */\n variables: z.record(z.string(), z.string()).optional(),\n\n // MCP operation fields\n /** MCP tool name */\n tool: z.string().optional(),\n\n // Common fields\n /** Response transform configuration */\n transform: transformSchema.optional(),\n});\n\nexport type Operation = z.infer<typeof operationSchema>;\n\n/**\n * Route definition - operations for a specific path pattern\n */\nexport const routeDefinitionSchema = z.object({\n /** List operation (returns multiple entries) */\n list: operationSchema.optional(),\n /** Read operation (returns single entry) */\n read: operationSchema.optional(),\n /** Write/update operation */\n write: operationSchema.optional(),\n /** Create operation */\n create: operationSchema.optional(),\n /** Delete operation */\n delete: operationSchema.optional(),\n});\n\nexport type RouteDefinition = z.infer<typeof routeDefinitionSchema>;\n\n/**\n * Default configuration applied to all operations\n */\nexport const defaultsSchema = z.object({\n /** Base URL for all API calls */\n baseUrl: z.string().optional(),\n /** Default headers */\n headers: z.record(z.string(), z.string()).optional(),\n /** Default timeout in milliseconds */\n timeout: z.number().optional(),\n});\n\nexport type Defaults = z.infer<typeof defaultsSchema>;\n\n/**\n * Root mapping configuration schema\n */\nexport const mappingConfigSchema = z.object({\n /** Mapping name (e.g., \"github\") */\n name: z.string(),\n /** Version string */\n version: z.string(),\n /** Human-readable description */\n description: z.string().optional(),\n /** Default configuration */\n defaults: defaultsSchema.optional(),\n /** Paths to include (relative to this file) */\n include: z.array(z.string()).optional(),\n /** Route definitions keyed by path template */\n routes: z.record(z.string(), routeDefinitionSchema),\n});\n\nexport type MappingConfig = z.infer<typeof mappingConfigSchema>;\n\n/**\n * Partial mapping config for included files (no name/version required)\n */\nexport const partialMappingConfigSchema = z.object({\n /** Route definitions keyed by path template */\n routes: z.record(z.string(), routeDefinitionSchema).optional(),\n /** Default configuration (merged with parent) */\n defaults: defaultsSchema.optional(),\n});\n\nexport type PartialMappingConfig = z.infer<typeof partialMappingConfigSchema>;\n","/**\n * YAML Parser for Mapping Configuration\n *\n * Parses YAML mapping files, handles includes, and validates against schema.\n */\n\nimport { readFile, stat } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { fromError } from \"zod-validation-error\";\nimport {\n type MappingConfig,\n mappingConfigSchema,\n type PartialMappingConfig,\n partialMappingConfigSchema,\n} from \"./schema.js\";\n\n/**\n * Error thrown when parsing fails\n */\nexport class MappingParseError extends Error {\n constructor(\n message: string,\n public readonly filePath?: string,\n public readonly cause?: Error,\n ) {\n super(filePath ? `${message} (in ${filePath})` : message);\n this.name = \"MappingParseError\";\n }\n}\n\n/**\n * Parser for mapping configuration files\n */\nexport class MappingParser {\n /**\n * Parse a YAML string into a validated mapping config\n */\n parseString(yaml: string, filePath?: string): MappingConfig {\n let parsed: unknown;\n try {\n parsed = parseYaml(yaml);\n } catch (e) {\n throw new MappingParseError(\n `Invalid YAML: ${e instanceof Error ? e.message : String(e)}`,\n filePath,\n );\n }\n\n const result = mappingConfigSchema.safeParse(parsed);\n if (!result.success) {\n const validationError = fromError(result.error);\n throw new MappingParseError(`Schema validation failed: ${validationError.message}`, filePath);\n }\n\n return result.data;\n }\n\n /**\n * Parse a partial config string (for included files)\n */\n parsePartialString(yaml: string, filePath?: string): PartialMappingConfig {\n let parsed: unknown;\n try {\n parsed = parseYaml(yaml);\n } catch (e) {\n throw new MappingParseError(\n `Invalid YAML: ${e instanceof Error ? e.message : String(e)}`,\n filePath,\n );\n }\n\n const result = partialMappingConfigSchema.safeParse(parsed);\n if (!result.success) {\n const validationError = fromError(result.error);\n throw new MappingParseError(`Schema validation failed: ${validationError.message}`, filePath);\n }\n\n return result.data;\n }\n\n /**\n * Parse a mapping file and resolve includes\n */\n async parseFile(filePath: string, visitedPaths: Set<string> = new Set()): Promise<MappingConfig> {\n const absolutePath = resolve(filePath);\n\n // Check for circular includes\n if (visitedPaths.has(absolutePath)) {\n throw new MappingParseError(`Circular include detected: ${absolutePath}`, filePath);\n }\n visitedPaths.add(absolutePath);\n\n // Read file\n let content: string;\n try {\n content = await readFile(absolutePath, \"utf-8\");\n } catch (e) {\n throw new MappingParseError(\n `Failed to read file: ${e instanceof Error ? e.message : String(e)}`,\n absolutePath,\n );\n }\n\n // Parse as full config\n const config = this.parseString(content, absolutePath);\n\n // Resolve includes\n if (config.include && config.include.length > 0) {\n const baseDir = dirname(absolutePath);\n\n for (const includePath of config.include) {\n const includeAbsPath = resolve(baseDir, includePath);\n\n // Check circular\n if (visitedPaths.has(includeAbsPath)) {\n throw new MappingParseError(`Circular include detected: ${includeAbsPath}`, filePath);\n }\n\n // Parse included file as partial\n const partial = await this.parsePartialFile(includeAbsPath, visitedPaths);\n\n // Merge routes\n if (partial.routes) {\n config.routes = { ...config.routes, ...partial.routes };\n }\n\n // Merge defaults (included file's defaults are lower priority)\n if (partial.defaults) {\n config.defaults = {\n ...partial.defaults,\n ...config.defaults,\n headers: {\n ...partial.defaults.headers,\n ...config.defaults?.headers,\n },\n };\n }\n }\n }\n\n return config;\n }\n\n /**\n * Parse a partial mapping file (for includes)\n */\n async parsePartialFile(\n filePath: string,\n visitedPaths: Set<string> = new Set(),\n ): Promise<PartialMappingConfig> {\n const absolutePath = resolve(filePath);\n\n // Check for circular includes\n if (visitedPaths.has(absolutePath)) {\n throw new MappingParseError(`Circular include detected: ${absolutePath}`, filePath);\n }\n visitedPaths.add(absolutePath);\n\n // Read file\n let content: string;\n try {\n content = await readFile(absolutePath, \"utf-8\");\n } catch (e) {\n throw new MappingParseError(\n `Failed to read file: ${e instanceof Error ? e.message : String(e)}`,\n absolutePath,\n );\n }\n\n // Parse as partial config\n const partial = this.parsePartialString(content, absolutePath);\n\n // Recursively resolve includes in partial file\n const parsed = parseYaml(content) as { include?: string[] };\n if (parsed.include && parsed.include.length > 0) {\n const baseDir = dirname(absolutePath);\n\n for (const includePath of parsed.include) {\n const includeAbsPath = resolve(baseDir, includePath);\n\n // Check circular\n if (visitedPaths.has(includeAbsPath)) {\n throw new MappingParseError(`Circular include detected: ${includeAbsPath}`, filePath);\n }\n\n const nestedPartial = await this.parsePartialFile(includeAbsPath, visitedPaths);\n\n // Merge routes\n if (nestedPartial.routes) {\n partial.routes = { ...partial.routes, ...nestedPartial.routes };\n }\n }\n }\n\n return partial;\n }\n\n /**\n * Parse a directory containing index.yaml and potentially included files\n */\n async parseDirectory(dirPath: string): Promise<MappingConfig> {\n const absoluteDir = resolve(dirPath);\n const indexPath = join(absoluteDir, \"index.yaml\");\n\n // Check if index.yaml exists\n try {\n const stats = await stat(indexPath);\n if (!stats.isFile()) {\n throw new MappingParseError(`index.yaml is not a file`, indexPath);\n }\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new MappingParseError(`Directory does not contain index.yaml`, absoluteDir);\n }\n throw e;\n }\n\n return this.parseFile(indexPath);\n }\n}\n","/**\n * JSONPath Projector\n *\n * Transforms API responses to AFS entries using JSONPath expressions.\n */\n\nimport type { AFSEntry } from \"@aigne/afs\";\nimport { ExpressionBinder } from \"./binder.js\";\nimport type { Transform } from \"./schema.js\";\n\n// Re-export Transform for convenience\nexport type { Transform } from \"./schema.js\";\n\n/**\n * Projects API response data to AFS entries\n */\nexport class Projector {\n private binder = new ExpressionBinder();\n\n /**\n * Project data to AFS entries based on transform config\n */\n project(data: unknown, transform: Transform, pathParams: Record<string, string>): AFSEntry[] {\n // If items path is specified, treat as list\n if (transform.items) {\n return this.projectList(data, transform, pathParams);\n }\n\n // Otherwise, treat as single item\n if (transform.entry) {\n return [this.projectItem(data, transform, pathParams)];\n }\n\n return [];\n }\n\n /**\n * Project a list of items\n */\n projectList(data: unknown, transform: Transform, pathParams: Record<string, string>): AFSEntry[] {\n if (!transform.entry) {\n return [];\n }\n\n // Get items array using items path\n let items: unknown[];\n\n if (transform.items === \"$\") {\n // Root array\n if (!Array.isArray(data)) {\n return [];\n }\n items = data;\n } else {\n // Nested path\n const itemsPath = transform.items;\n const itemsData = this.evaluateJsonPath(itemsPath, data);\n\n if (itemsData === undefined || itemsData === null) {\n return [];\n }\n\n if (Array.isArray(itemsData)) {\n items = itemsData;\n } else {\n // Single item - wrap in array\n items = [itemsData];\n }\n }\n\n // Project each item\n return items.map((item) => this.projectItem(item, { entry: transform.entry }, pathParams));\n }\n\n /**\n * Project a single item to an AFS entry\n */\n projectItem(data: unknown, transform: Transform, pathParams: Record<string, string>): AFSEntry {\n if (!transform.entry) {\n throw new Error(\"Transform must have entry configuration\");\n }\n\n const entryConfig = transform.entry;\n\n // Build the entry\n const entry: AFSEntry = {\n id: this.evaluateField(entryConfig.id, data, pathParams) ?? \"\",\n path: this.interpolatePath(entryConfig.path ?? \"\", data, pathParams),\n };\n\n // Optional fields\n if (entryConfig.summary) {\n const summary = this.evaluateField(entryConfig.summary, data, pathParams);\n if (summary !== undefined) {\n entry.summary = summary;\n }\n }\n\n if (entryConfig.content) {\n const content = this.evaluateField(entryConfig.content, data, pathParams);\n if (content !== undefined) {\n entry.content = content;\n }\n }\n\n // Metadata\n if (entryConfig.meta) {\n entry.meta = this.projectMetadata(entryConfig.meta, data, pathParams);\n }\n\n // description goes into metadata\n if (entryConfig.description) {\n const description = this.evaluateField(entryConfig.description, data, pathParams);\n if (description !== undefined) {\n entry.meta = entry.meta || {};\n entry.meta.description = description;\n }\n }\n\n return entry;\n }\n\n /**\n * Evaluate a single field expression\n */\n private evaluateField(\n expr: string | undefined,\n data: unknown,\n pathParams: Record<string, string>,\n ): string | undefined {\n if (!expr) return undefined;\n\n const context = {\n path: pathParams,\n query: {},\n input: {},\n data,\n };\n\n const result = this.binder.evaluate(expr, context);\n return result === undefined || result === null ? undefined : String(result);\n }\n\n /**\n * Interpolate a path template with data and path params\n * Handles both {name} for path params and {$.path} for JSONPath\n */\n private interpolatePath(\n template: string,\n data: unknown,\n pathParams: Record<string, string>,\n ): string {\n // Find all {xxx} patterns\n return template.replace(/\\{([^}]+)\\}/g, (match, expr) => {\n // Check if it's a JSONPath expression\n if (expr.startsWith(\"$.\")) {\n const value = this.evaluateJsonPath(expr, data);\n return value !== undefined && value !== null ? String(value) : match;\n }\n\n // Otherwise, it's a path param\n return pathParams[expr] ?? match;\n });\n }\n\n /**\n * Project metadata object recursively\n */\n private projectMetadata(\n config: Record<string, unknown>,\n data: unknown,\n pathParams: Record<string, string>,\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(config)) {\n if (typeof value === \"string\") {\n // It's an expression\n const context = {\n path: pathParams,\n query: {},\n input: {},\n data,\n };\n result[key] = this.binder.evaluate(value, context);\n } else if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n // Nested metadata object\n result[key] = this.projectMetadata(value as Record<string, unknown>, data, pathParams);\n } else {\n // Other values (arrays, etc.) - pass through\n result[key] = value;\n }\n }\n\n return result;\n }\n\n /**\n * Evaluate a JSONPath expression\n */\n private evaluateJsonPath(jsonPath: string | undefined, data: unknown): unknown {\n if (!jsonPath) return undefined;\n\n const context = {\n path: {},\n query: {},\n input: {},\n data,\n };\n\n return this.binder.evaluate(jsonPath, context);\n }\n}\n","/**\n * Path Resolver\n *\n * Efficient path template matching using a Trie structure.\n * Supports parameterized path segments like /{owner}/{repo}/issues/{number}.\n */\n\n/**\n * Result of a path match\n */\nexport interface PathMatchResult<T> {\n /** The matched template string */\n template: string;\n /** Extracted path parameters */\n params: Record<string, string>;\n /** Associated data */\n data: T;\n}\n\n/**\n * Represents a parsed path template\n */\nexport class PathTemplate {\n /** Original template string */\n readonly template: string;\n /** Parsed segments */\n readonly segments: string[];\n /** Parameter names in order */\n readonly params: string[];\n\n private constructor(template: string, segments: string[], params: string[]) {\n this.template = template;\n this.segments = segments;\n this.params = params;\n }\n\n /**\n * Parse a path template string\n */\n static parse(template: string): PathTemplate {\n // Normalize: remove trailing slash, split by /\n const normalized =\n template.endsWith(\"/\") && template !== \"/\" ? template.slice(0, -1) : template;\n\n const segments = normalized.split(\"/\").filter(Boolean);\n const params: string[] = [];\n\n for (const segment of segments) {\n if (segment.startsWith(\"{\") && segment.endsWith(\"}\")) {\n const paramName = segment.slice(1, -1);\n params.push(paramName);\n }\n }\n\n return new PathTemplate(template, segments, params);\n }\n\n /**\n * Try to match a path against this template\n */\n match(path: string): { params: Record<string, string> } | null {\n // Normalize input path\n const normalizedPath = path.endsWith(\"/\") && path !== \"/\" ? path.slice(0, -1) : path;\n\n const pathSegments = normalizedPath.split(\"/\").filter(Boolean);\n\n // Must have same number of segments\n if (pathSegments.length !== this.segments.length) {\n return null;\n }\n\n const params: Record<string, string> = {};\n\n for (let i = 0; i < this.segments.length; i++) {\n const templateSeg = this.segments[i]!;\n const pathSeg = decodeURIComponent(pathSegments[i]!);\n\n if (templateSeg.startsWith(\"{\") && templateSeg.endsWith(\"}\")) {\n // Parameter segment - extract value\n const paramName = templateSeg.slice(1, -1);\n params[paramName] = pathSeg;\n } else {\n // Static segment - must match exactly\n if (templateSeg !== pathSeg) {\n return null;\n }\n }\n }\n\n return { params };\n }\n}\n\n/**\n * Trie node for path resolution\n */\ninterface TrieNode<T> {\n /** Children keyed by segment (static segments and \"{param}\" for parameters) */\n children: Map<string, TrieNode<T>>;\n /** Data stored at this node (if this is a route endpoint) */\n data?: T;\n /** Template string (if this is a route endpoint) */\n template?: string;\n /** Is this a parameter node */\n isParam: boolean;\n /** Parameter name (if isParam) */\n paramName?: string;\n}\n\n/**\n * Path resolver using Trie for O(k) lookup where k = path depth\n */\nexport class PathResolver<T> {\n private root: TrieNode<T>;\n\n constructor() {\n this.root = this.createNode(false);\n }\n\n private createNode(isParam: boolean, paramName?: string): TrieNode<T> {\n return {\n children: new Map(),\n isParam,\n paramName,\n };\n }\n\n /**\n * Add a route template with associated data\n */\n addRoute(template: string, data: T): void {\n const parsed = PathTemplate.parse(template);\n let current = this.root;\n\n for (const segment of parsed.segments) {\n const isParam = segment.startsWith(\"{\") && segment.endsWith(\"}\");\n const key = isParam ? \"{param}\" : segment;\n\n if (!current.children.has(key)) {\n const paramName = isParam ? segment.slice(1, -1) : undefined;\n current.children.set(key, this.createNode(isParam, paramName));\n }\n\n current = current.children.get(key)!;\n }\n\n current.data = data;\n current.template = template;\n }\n\n /**\n * Resolve a path to a route\n */\n resolve(path: string): PathMatchResult<T> | null {\n const normalizedPath = path.endsWith(\"/\") && path !== \"/\" ? path.slice(0, -1) : path;\n\n const segments = normalizedPath.split(\"/\").filter(Boolean);\n const params: Record<string, string> = {};\n\n let current = this.root;\n\n for (const segment of segments) {\n const decodedSegment = decodeURIComponent(segment);\n\n // Try static match first (more specific)\n if (current.children.has(decodedSegment)) {\n current = current.children.get(decodedSegment)!;\n }\n // Then try parameter match\n else if (current.children.has(\"{param}\")) {\n const paramNode = current.children.get(\"{param}\")!;\n if (paramNode.paramName) {\n params[paramNode.paramName] = decodedSegment;\n }\n current = paramNode;\n }\n // No match\n else {\n return null;\n }\n }\n\n // Check if we reached a valid endpoint\n if (current.data === undefined || current.template === undefined) {\n return null;\n }\n\n return {\n template: current.template,\n params,\n data: current.data,\n };\n }\n\n /**\n * Get all registered routes\n */\n getAllRoutes(): Array<{ template: string; data: T }> {\n const routes: Array<{ template: string; data: T }> = [];\n this.collectRoutes(this.root, routes);\n return routes;\n }\n\n private collectRoutes(node: TrieNode<T>, routes: Array<{ template: string; data: T }>): void {\n if (node.data !== undefined && node.template !== undefined) {\n routes.push({ template: node.template, data: node.data });\n }\n\n for (const child of node.children.values()) {\n this.collectRoutes(child, routes);\n }\n }\n}\n","/**\n * Mapping Compiler\n *\n * Compiles mapping configuration to internal IR for efficient path matching.\n * Integrates parser, resolver, binder, and projector.\n */\n\nimport type { AFSEntry } from \"@aigne/afs\";\nimport { type BindingContext, ExpressionBinder } from \"./binder.js\";\nimport { MappingParser } from \"./parser.js\";\nimport { Projector } from \"./projector.js\";\nimport { PathResolver } from \"./resolver.js\";\nimport type { Defaults, MappingConfig, Operation, RouteDefinition } from \"./schema.js\";\n\n/**\n * Operation types supported by routes\n */\nexport type OperationType = \"list\" | \"read\" | \"write\" | \"create\" | \"delete\";\n\n/**\n * Resolved route information\n */\nexport interface ResolvedRoute {\n /** Original template */\n template: string;\n /** Extracted path parameters */\n params: Record<string, string>;\n /** Available operations */\n operations: Partial<Record<OperationType, Operation>>;\n}\n\n/**\n * HTTP request built from route and operation\n */\nexport interface HttpRequest {\n /** HTTP method */\n method: string;\n /** Request path (with params interpolated) */\n path: string;\n /** Query/path parameters */\n params: Record<string, unknown>;\n /** Request headers */\n headers?: Record<string, string>;\n /** Request body (for POST/PUT/PATCH) */\n body?: Record<string, unknown>;\n}\n\n/**\n * Compiled mapping ready for runtime use\n */\nexport class CompiledMapping {\n readonly name: string;\n readonly version: string;\n readonly description?: string;\n readonly defaults?: Defaults;\n\n private resolver: PathResolver<RouteDefinition>;\n private binder = new ExpressionBinder();\n private projector = new Projector();\n private routes: Map<string, RouteDefinition> = new Map();\n\n constructor(config: MappingConfig) {\n this.name = config.name;\n this.version = config.version;\n this.description = config.description;\n this.defaults = config.defaults;\n\n // Build path resolver\n this.resolver = new PathResolver<RouteDefinition>();\n\n for (const [template, routeDef] of Object.entries(config.routes) as [\n string,\n RouteDefinition,\n ][]) {\n this.resolver.addRoute(template, routeDef);\n this.routes.set(template, routeDef);\n }\n }\n\n /**\n * Get number of routes\n */\n get routeCount(): number {\n return this.routes.size;\n }\n\n /**\n * Get total number of operations\n */\n get operationCount(): number {\n let count = 0;\n for (const route of this.routes.values()) {\n if (route.list) count++;\n if (route.read) count++;\n if (route.write) count++;\n if (route.create) count++;\n if (route.delete) count++;\n }\n return count;\n }\n\n /**\n * Resolve a path to route information\n */\n resolve(path: string): ResolvedRoute | null {\n const result = this.resolver.resolve(path);\n if (!result) return null;\n\n return {\n template: result.template,\n params: result.params,\n operations: {\n list: result.data.list,\n read: result.data.read,\n write: result.data.write,\n create: result.data.create,\n delete: result.data.delete,\n },\n };\n }\n\n /**\n * Build an HTTP request for a given path and operation\n */\n buildRequest(\n afsPath: string,\n operationType: OperationType,\n options: {\n query?: Record<string, string>;\n input?: Record<string, unknown>;\n },\n ): HttpRequest | null {\n const resolved = this.resolve(afsPath);\n if (!resolved) return null;\n\n const operation = resolved.operations[operationType];\n if (!operation) return null;\n\n // Build binding context\n const context: BindingContext = {\n path: resolved.params,\n query: options.query ?? {},\n input: options.input ?? {},\n data: {},\n };\n\n // Bind parameters\n const boundParams = operation.params ? this.binder.bindAll(operation.params, context) : {};\n\n // Interpolate API path\n const apiPath = this.interpolatePath(operation.path ?? \"\", context);\n\n // Build headers\n const headers = {\n ...this.defaults?.headers,\n ...operation.headers,\n };\n\n // Build body for write operations\n let body: Record<string, unknown> | undefined;\n if (operation.body) {\n body = this.binder.bindAll(operation.body, context);\n }\n\n return {\n method: operation.method ?? \"GET\",\n path: apiPath,\n params: boundParams,\n headers: Object.keys(headers).length > 0 ? headers : undefined,\n body,\n };\n }\n\n /**\n * Project API response to AFS entries\n */\n projectResponse(afsPath: string, operationType: OperationType, apiResponse: unknown): AFSEntry[] {\n const resolved = this.resolve(afsPath);\n if (!resolved) return [];\n\n const operation = resolved.operations[operationType];\n if (!operation?.transform) return [];\n\n return this.projector.project(apiResponse, operation.transform, resolved.params);\n }\n\n /**\n * Interpolate path template with context values\n */\n private interpolatePath(template: string, context: BindingContext): string {\n return template.replace(/\\{([^}]+)\\}/g, (match, key) => {\n const value = context.path[key];\n return value !== undefined ? value : match;\n });\n }\n}\n\n/**\n * Compiler for mapping configurations\n */\nexport class MappingCompiler {\n private parser = new MappingParser();\n\n /**\n * Compile a mapping file\n */\n async compileFile(filePath: string): Promise<CompiledMapping> {\n const config = await this.parser.parseFile(filePath);\n return new CompiledMapping(config);\n }\n\n /**\n * Compile a mapping directory\n */\n async compileDirectory(dirPath: string): Promise<CompiledMapping> {\n const config = await this.parser.parseDirectory(dirPath);\n return new CompiledMapping(config);\n }\n\n /**\n * Compile from a config object (for testing)\n */\n compileConfig(config: MappingConfig): CompiledMapping {\n return new CompiledMapping(config);\n }\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aigne/afs-mapping",
|
|
3
|
+
"version": "1.11.0-beta.10",
|
|
4
|
+
"description": "AFS Mapping DSL compiler for declarative path-to-API mapping",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"author": "Arcblock <blocklet@arcblock.io> https://github.com/arcblock",
|
|
10
|
+
"homepage": "https://github.com/arcblock/afs",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/arcblock/afs"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/arcblock/afs/issues"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "./dist/index.cjs",
|
|
20
|
+
"module": "./dist/index.mjs",
|
|
21
|
+
"types": "./dist/index.d.cts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"require": "./dist/index.cjs",
|
|
25
|
+
"import": "./dist/index.mjs"
|
|
26
|
+
},
|
|
27
|
+
"./*": "./*"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"LICENSE",
|
|
32
|
+
"README.md",
|
|
33
|
+
"CHANGELOG.md"
|
|
34
|
+
],
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"yaml": "^2.8.1",
|
|
37
|
+
"zod": "^4.0.0",
|
|
38
|
+
"zod-validation-error": "^4.0.0",
|
|
39
|
+
"@aigne/afs": "^1.11.0-beta.10"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/bun": "^1.3.6",
|
|
43
|
+
"npm-run-all": "^4.1.5",
|
|
44
|
+
"rimraf": "^6.1.2",
|
|
45
|
+
"tsdown": "0.20.0-beta.3",
|
|
46
|
+
"typescript": "5.9.2",
|
|
47
|
+
"@aigne/scripts": "0.0.0",
|
|
48
|
+
"@aigne/typescript-config": "0.0.0"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsdown",
|
|
52
|
+
"check-types": "tsc --noEmit",
|
|
53
|
+
"clean": "rimraf dist coverage",
|
|
54
|
+
"test": "bun test",
|
|
55
|
+
"test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text"
|
|
56
|
+
}
|
|
57
|
+
}
|