UNPKG

@memory-bank/mcp

Version:

Memory-enabled Co-Pilot (MCP) server for managing project documentation and context

184 lines 5.96 kB
import { DomainError, DomainErrorCodes } from '../../shared/errors/DomainError.js'; /** * Class encapsulating the path representation used in JSON Patch * Implementation of JSON Pointer compliant with RFC 6901 */ export class JsonPath { _path; _segments; /** * Constructor - Do not use directly, use the static factory method instead */ constructor(path, segments) { this._path = path; this._segments = segments; } /** * Create a JsonPath object from a path string * @param path JSON Pointer path string (e.g., '/a/b/c') * @returns New JsonPath instance * @throws DomainError if the path is invalid */ static parse(path) { // Handle root path represented by an empty string if (path === '') { return new JsonPath('', []); } // All non-empty paths must start with '/' if (!path.startsWith('/')) { throw new DomainError(DomainErrorCodes.INVALID_JSON_PATH, 'JSON Pointer must start with "/" or be an empty string' // エラーメッセージ修正 ); } // Remove leading slash and split // Handle root path represented by "/" if (path === '/') { return new JsonPath('/', []); // ルートパス '/' のセグメントは空配列 } // Remove leading slash and split for non-root paths const rawSegments = path.substring(1).split('/'); const segments = []; // Process escape sequences in each segment for (const segment of rawSegments) { let i = 0; let result = ''; while (i < segment.length) { if (segment[i] === '~') { if (i + 1 >= segment.length) { throw new DomainError(DomainErrorCodes.INVALID_JSON_PATH, 'Invalid JSON path: incomplete escape sequence'); } if (segment[i + 1] === '0') { result += '~'; } else if (segment[i + 1] === '1') { result += '/'; } else { throw new DomainError(DomainErrorCodes.INVALID_JSON_PATH, 'Invalid JSON Pointer escape sequence' // エラーメッセージ修正 ); } i += 2; } else { result += segment[i]; i += 1; } } segments.push(result); } return new JsonPath(path, segments); } /** * Generate the root path * @returns JsonPath instance representing the root path */ static root() { return new JsonPath('/', []); // ルートパス '/' のセグメントは空配列 } /** * Create a JsonPath object from an array of segments * @param segments Array of path segments * @returns New JsonPath instance */ static fromSegments(segments) { if (segments.length === 0) { return new JsonPath('', []); // 空セグメントの場合はルートパス "" を返す } const escapedSegments = segments.map(segment => JsonPath.escapeSegment(segment)); const path = '/' + escapedSegments.join('/'); return new JsonPath(path, [...segments]); } /** * Escape a path segment * @param segment Segment to escape * @returns Escaped segment */ static escapeSegment(segment) { return segment.replace(/~/g, '~0').replace(/\//g, '~1'); } /** * Unescape an escaped path segment * @param segment Escaped segment * @returns Original segment */ static unescapeSegment(segment) { return segment.replace(/~1/g, '/').replace(/~0/g, '~'); } /** * Get the path string */ get path() { return this._path; } /** * Get the array of path segments */ get segments() { return this._segments; } /** * Check if the path is the root path * @returns true if it is the root path */ isRoot() { return this._path === '/'; } /** * Get the parent path * @returns JsonPath instance representing the parent path * @throws DomainError if called on the root path */ parent() { if (this.isRoot()) { throw new DomainError(DomainErrorCodes.INVALID_JSON_PATH, 'Root path has no parent'); } const parentSegments = this._segments.slice(0, -1); return JsonPath.fromSegments(parentSegments); } /** * Get the last segment of the path * @returns The last segment */ lastSegment() { return this._segments[this._segments.length - 1]; } /** * Generate a child path * @param childSegment Child segment * @returns New JsonPath instance */ child(childSegment) { const newSegments = [...this._segments, childSegment]; return JsonPath.fromSegments(newSegments); } /** * Check if the path points to an array element * @returns true if the path points to an array element */ isArrayElement() { const lastSegment = this.lastSegment(); return lastSegment === '-' || /^\d+$/.test(lastSegment); } /** * Check if the path points to the end of an array for appending * @returns true if the path points to the end of an array */ isArrayAppend() { return this.lastSegment() === '-'; } /** * Check path equality * @param other JsonPath to compare against * @returns true if equal */ equals(other) { return this._path === other._path; } /** * Get the string representation * @returns Path string */ toString() { return this._path; } } //# sourceMappingURL=JsonPath.js.map