UNPKG

fastman

Version:

快速api测试及文档生成

228 lines (203 loc) 7.74 kB
/** * @license * Copyright 2017 Red Hat * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import {OasNode} from "./node.model"; import {OasDocument} from "./document.model"; import {IOasIndexedNode} from "./inode.model"; import {IOasNodeVisitor} from "../visitors/visitor.iface"; /** * Represents a canonical path to a node within a OAS document model. The node path * can be used to identify and locate a single model in the document tree. */ export class OasNodePath { private _segments: OasNodePathSegment[] = []; constructor(path?: string) { if (path && path.indexOf("/") === 0 && path !== "/") { let currentScanType: string = "path"; let currentIdx: number = 1; while (currentIdx < path.length) { let segStart: number = currentIdx; let segEnd: number; if (currentScanType === "path") { let nextPathSep: number = path.indexOf("/", segStart); let nextBrace: number = path.indexOf("[", segStart); if (nextPathSep === -1) { nextPathSep = path.length; } if (nextBrace === -1) { nextBrace = path.length; } if (nextPathSep <= nextBrace) { segEnd = nextPathSep; } else { segEnd = nextBrace; } } else { let nextCloseBrace: number = path.indexOf("]", segStart); if (nextCloseBrace === -1) { nextCloseBrace = path.length; } segEnd = nextCloseBrace + 1; } let seg: string = path.substring(segStart, segEnd); let segment: OasNodePathSegment = OasNodePathSegment.fromString(seg); this._segments.push(segment); // Default next values. currentScanType = "path"; currentIdx = segEnd + 1; // Find real next values. if (path.charAt(segEnd) === '/') { currentScanType = "path"; currentIdx = segEnd + 1; } else if (path.charAt(segEnd) === '[') { currentScanType = "index"; currentIdx = segEnd; } else if (path.charAt(segEnd) === ']') { if (path.charAt(segEnd+1) === '[') { currentScanType = "index"; currentIdx = segEnd + 1; } else if (path.charAt(segEnd+1) === '/') { currentScanType = "path"; currentIdx = segEnd + 1; } } } } } /** * Adds a segment to the beginning of the path. * @param value * @param index */ public prependSegment(value: string|number, index?: boolean): void { this._segments.unshift(new OasNodePathSegment(value, index)); } /** * Adds a segment to the end of the path. * @param value * @param index */ public appendSegment(value: string | number, index?: boolean): void { this._segments.push(new OasNodePathSegment(value, index)); } /** * Resolves a path to its target node within the document model. This basically * walks the tree according to the path segments until it reaches the node being * referenced. If the path does not point to a valid node, then this method * returns undefined. * @param document the document to resolve the path relative to * @param visitor an optional visitor to invoke for each node in the path * @return {OasNode} */ public resolve(document: OasDocument, visitor?: IOasNodeVisitor): OasNode { let node: OasNode = document; if (visitor) { node.accept(visitor); } for (let segment of this._segments) { node = segment.resolve(node); if (visitor && node && node["accept"]) { node.accept(visitor); } } return node; } /** * Returns true if this path "contains" the given node. The path is said to contain * a node if the node is visited while resolving it. In other words, if one of the * segments of the path represents the node, then this will return true, otherwise it * will return false. * @param {OasNode} node * @return {boolean} */ public contains(node: OasNode): boolean { let tnode: OasNode = node.ownerDocument(); // Of course the root document is always a match. if (tnode === node) { return true; } for (let segment of this._segments) { tnode = segment.resolve(tnode); if (tnode === node) { return true; } } return false; } /** * Converts the path to a string. */ public toString(): string { if (this._segments.length === 0) { return "/"; } let rval: string = ""; for (let segment of this._segments) { if (segment.isIndex()) { rval += '[' + segment.value() + ']'; } else { rval += '/' + segment.value(); } } return rval; } } /** * Represents a single segment in a model node path. */ export class OasNodePathSegment { private _value: string | number; private _index: boolean = false; constructor(value: string | number, index?: boolean) { this._value = value; if (index) { this._index = true; } } public value(): string | number { return this._value; } public isIndex(): boolean { return this._index; } public resolve(node: OasNode): OasNode { if (node === null) { return null; } let childNode: any = null; if (this.isIndex() && node["__instanceof_IOasIndexedNode"]) { childNode = (<any>node as IOasIndexedNode<OasNode>).getItem(<string>this.value()); } else { childNode = node[this.value()]; if (childNode === undefined) { childNode = null; } } return <OasNode>childNode; } /** * Creates a new segment from a string. * @param segment * @return {OasNodePathSegment} */ public static fromString(segment: string): OasNodePathSegment { if (!segment) { return new OasNodePathSegment(null); } if (segment.indexOf("[") !== 0) { return new OasNodePathSegment(segment); } else { let bStart: number = segment.indexOf("["); let bEnd: number = segment.indexOf("]", bStart); let value: string = segment.substring(bStart + 1, bEnd); return new OasNodePathSegment(value, true); } } }