UNPKG

@ui5/fs

Version:

UI5 CLI - File System Abstraction

140 lines (130 loc) 4.4 kB
import AbstractReader from "../AbstractReader.js"; import ResourceFacade from "../ResourceFacade.js"; import {prefixGlobPattern} from "../resourceFactory.js"; import {getLogger} from "@ui5/logger"; const log = getLogger("resources:readers:Link"); /** * A reader that allows for rewriting paths segments of all resources passed through it. * * @example * import Link from "@ui5/fs/readers/Link"; * const linkedReader = new Link({ * reader: sourceReader, * pathMapping: { * linkPath: `/app`, * targetPath: `/resources/my-app-name/` * } * }); * * // The following resolves with a @ui5/fs/ResourceFacade of the resource * // located at "/resources/my-app-name/Component.js" in the sourceReader * const resource = await linkedReader.byPath("/app/Component.js"); * * @public * @class * @alias @ui5/fs/readers/Link * @extends @ui5/fs/AbstractReader */ class Link extends AbstractReader { /** * Path mapping for a [Link]{@link @ui5/fs/readers/Link} * * @public * @typedef {object} @ui5/fs/readers/Link/PathMapping * @property {string} linkPath Path to match and replace in the requested path or pattern * @property {string} targetPath Path to use as a replacement in the request for the source reader */ /** * Constructor * * @public * @param {object} parameters Parameters * @param {@ui5/fs/AbstractReader} parameters.reader The resource reader or collection to wrap * @param {@ui5/fs/readers/Link/PathMapping} parameters.pathMapping */ constructor({reader, pathMapping}) { super(); if (!reader) { throw new Error(`Missing parameter "reader"`); } if (!pathMapping) { throw new Error(`Missing parameter "pathMapping"`); } this._reader = reader; this._pathMapping = pathMapping; Link._validatePathMapping(pathMapping); } /** * Locates resources by glob. * * @private * @param {string|string[]} patterns glob pattern as string or an array of * glob patterns for virtual directory structure * @param {object} options glob options * @param {@ui5/fs/tracing/Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ async _byGlob(patterns, options, trace) { if (!(patterns instanceof Array)) { patterns = [patterns]; } patterns = patterns.map((pattern) => { if (pattern.startsWith(this._pathMapping.linkPath)) { pattern = pattern.substr(this._pathMapping.linkPath.length); } return prefixGlobPattern(pattern, this._pathMapping.targetPath); }); // Flatten prefixed patterns patterns = Array.prototype.concat.apply([], patterns); // Keep resource's internal path unchanged for now const resources = await this._reader._byGlob(patterns, options, trace); return resources.map((resource) => { const resourcePath = resource.getPath(); if (resourcePath.startsWith(this._pathMapping.targetPath)) { return new ResourceFacade({ resource, path: this._pathMapping.linkPath + resourcePath.substr(this._pathMapping.targetPath.length) }); } }); } /** * Locates resources by path. * * @private * @param {string} virPath Virtual path * @param {object} options Options * @param {@ui5/fs/tracing/Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ async _byPath(virPath, options, trace) { if (!virPath.startsWith(this._pathMapping.linkPath)) { return null; } const targetPath = this._pathMapping.targetPath + virPath.substr(this._pathMapping.linkPath.length); log.silly(`byPath: Rewriting virtual path ${virPath} to ${targetPath}`); const resource = await this._reader._byPath(targetPath, options, trace); if (resource) { return new ResourceFacade({ resource, path: this._pathMapping.linkPath + resource.getPath().substr(this._pathMapping.targetPath.length) }); } return null; } static _validatePathMapping({linkPath, targetPath}) { if (!linkPath) { throw new Error(`Path mapping is missing attribute "linkPath"`); } if (!targetPath) { throw new Error(`Path mapping is missing attribute "targetPath"`); } if (!linkPath.endsWith("/")) { throw new Error(`Link path must end with a slash: ${linkPath}`); } if (!targetPath.endsWith("/")) { throw new Error(`Target path must end with a slash: ${targetPath}`); } } } export default Link;