Comparing version 3.0.0-rc.4 to 3.0.0-rc.5
@@ -5,4 +5,7 @@ # Changelog | ||
A list of unreleased changes can be found [here](https://github.com/SAP/ui5-fs/compare/v3.0.0-rc.4...HEAD). | ||
A list of unreleased changes can be found [here](https://github.com/SAP/ui5-fs/compare/v3.0.0-rc.5...HEAD). | ||
<a name="v3.0.0-rc.5"></a> | ||
## [v3.0.0-rc.5] - 2023-02-03 | ||
<a name="v3.0.0-rc.4"></a> | ||
@@ -235,2 +238,3 @@ ## [v3.0.0-rc.4] - 2023-01-24 | ||
[v3.0.0-rc.5]: https://github.com/SAP/ui5-fs/compare/v3.0.0-rc.4...v3.0.0-rc.5 | ||
[v3.0.0-rc.4]: https://github.com/SAP/ui5-fs/compare/v3.0.0-rc.3...v3.0.0-rc.4 | ||
@@ -237,0 +241,0 @@ [v3.0.0-rc.3]: https://github.com/SAP/ui5-fs/compare/v3.0.0-rc.2...v3.0.0-rc.3 |
@@ -0,1 +1,2 @@ | ||
import path from "node:path/posix"; | ||
import {getLogger} from "@ui5/logger"; | ||
@@ -23,3 +24,4 @@ const log = getLogger("resources:adapters:AbstractAdapter"); | ||
* @param {object} parameters Parameters | ||
* @param {string} parameters.virBasePath Virtual base path | ||
* @param {string} parameters.virBasePath | ||
* Virtual base path. Must be absolute, POSIX-style, and must end with a slash | ||
* @param {string[]} [parameters.excludes] List of glob patterns to exclude | ||
@@ -33,4 +35,12 @@ * @param {object} [parameters.project] Experimental, internal parameter. Do not use | ||
super(); | ||
if (!virBasePath) { | ||
throw new Error(`Unable to create adapter: Missing parameter 'virBasePath'`); | ||
} | ||
if (!path.isAbsolute(virBasePath)) { | ||
throw new Error(`Unable to create adapter: Virtual base path must be absolute but is '${virBasePath}'`); | ||
} | ||
if (!virBasePath.endsWith("/")) { | ||
throw new Error(`Virtual base path must end with a slash: ${virBasePath}`); | ||
throw new Error( | ||
`Unable to create adapter: Virtual base path must end with a slash but is '${virBasePath}'`); | ||
} | ||
@@ -102,3 +112,3 @@ this._virBasePath = virBasePath; | ||
*/ | ||
isPathExcluded(virPath) { | ||
_isPathExcluded(virPath) { | ||
return micromatch(virPath, this._excludes).length > 0; | ||
@@ -108,2 +118,15 @@ } | ||
/** | ||
* Validate if virtual path should be handled by the adapter. | ||
* This means that it either starts with the virtual base path of the adapter | ||
* or equals the base directory (base path without a trailing slash) | ||
* | ||
* @param {string} virPath Virtual Path | ||
* @returns {boolean} True if path should be handled | ||
*/ | ||
_isPathHandled(virPath) { | ||
// Check whether path starts with base path, or equals base directory | ||
return virPath.startsWith(this._virBasePath) || virPath === this._virBaseDir; | ||
} | ||
/** | ||
* Normalizes virtual glob patterns. | ||
@@ -222,8 +245,3 @@ * | ||
_write(resource) { | ||
if (!resource.getPath().startsWith(this._virBasePath)) { | ||
throw new Error(`The path of the resource '${resource.getPath()}' does not start with ` + | ||
`the configured virtual base path of the adapter '${this._virBasePath}'`); | ||
} | ||
_assignProjectToResource(resource) { | ||
if (this._project) { | ||
@@ -244,4 +262,43 @@ // Assign project to resource if necessary | ||
} | ||
_resolveVirtualPathToBase(inputVirPath, writeMode = false) { | ||
if (!path.isAbsolute(inputVirPath)) { | ||
throw new Error(`Failed to resolve virtual path '${inputVirPath}': Path must be absolute`); | ||
} | ||
// Resolve any ".." segments to make sure we compare the effective start of the path | ||
// with the virBasePath | ||
const virPath = path.normalize(inputVirPath); | ||
if (!writeMode) { | ||
// When reading resources, validate against path excludes and return null if the given path | ||
// does not match this adapters base path | ||
if (!this._isPathHandled(virPath)) { | ||
if (log.isLevelEnabled("silly")) { | ||
log.silly(`Failed to resolve virtual path '${inputVirPath}': ` + | ||
`Resolved path does not start with adapter base path '${this._virBasePath}' or equals ` + | ||
`base dir: ${this._virBaseDir}`); | ||
} | ||
return null; | ||
} | ||
if (this._isPathExcluded(virPath)) { | ||
if (log.isLevelEnabled("silly")) { | ||
log.silly(`Failed to resolve virtual path '${inputVirPath}': ` + | ||
`Resolved path is excluded by configuration of adapter with base path '${this._virBasePath}'`); | ||
} | ||
return null; | ||
} | ||
} else if (!this._isPathHandled(virPath)) { | ||
// Resolved path is not within the configured base path and does | ||
// not equal the virtual base directory. | ||
// Since we don't want to write resources to foreign locations, we throw an error | ||
throw new Error( | ||
`Failed to write resource with virtual path '${inputVirPath}': Path must start with ` + | ||
`the configured virtual base path of the adapter. Base path: '${this._virBasePath}'`); | ||
} | ||
const relPath = virPath.substr(this._virBasePath.length); | ||
return relPath; | ||
} | ||
} | ||
export default AbstractAdapter; |
@@ -29,4 +29,6 @@ import {getLogger} from "@ui5/logger"; | ||
* @param {object} parameters Parameters | ||
* @param {string} parameters.virBasePath Virtual base path | ||
* @param {string} parameters.fsBasePath (Physical) File system path | ||
* @param {string} parameters.virBasePath | ||
* Virtual base path. Must be absolute, POSIX-style, and must end with a slash | ||
* @param {string} parameters.fsBasePath | ||
* File System base path. Must be absolute and must use platform-specific path segment separators | ||
* @param {string[]} [parameters.excludes] List of glob patterns to exclude | ||
@@ -39,3 +41,10 @@ * @param {object} [parameters.useGitignore=false] | ||
super({virBasePath, project, excludes}); | ||
this._fsBasePath = path.resolve(fsBasePath); | ||
if (!fsBasePath) { | ||
throw new Error(`Unable to create adapter: Missing parameter 'fsBasePath'`); | ||
} | ||
// Ensure path is resolved to an absolute path, ending with a slash (or backslash on Windows) | ||
// path.resolve will always remove any trailing segment separator | ||
this._fsBasePath = path.join(path.resolve(fsBasePath), path.sep); | ||
this._useGitignore = !!useGitignore; | ||
@@ -99,4 +108,12 @@ } | ||
promises.push(new Promise((resolve, reject) => { | ||
const fsPath = path.join(this._fsBasePath, matches[i]); | ||
const virPath = (this._virBasePath + matches[i]); | ||
const relPath = this._resolveVirtualPathToBase(virPath); | ||
if (!relPath) { | ||
// Match is likely outside adapter base path | ||
log.verbose( | ||
`Failed to resolve virtual path of glob match '${virPath}': Path must start with ` + | ||
`the configured virtual base path of the adapter. Base path: '${this._virBasePath}'`); | ||
resolve(null); | ||
} | ||
const fsPath = this._resolveToFileSystem(relPath); | ||
@@ -128,3 +145,3 @@ // Workaround for not getting the stat from the glob | ||
// Flatten results | ||
return Array.prototype.concat.apply([], results); | ||
return Array.prototype.concat.apply([], results).filter(($) => $); | ||
} | ||
@@ -136,3 +153,3 @@ | ||
* @private | ||
* @param {string} virPath Virtual path | ||
* @param {string} virPath Absolute virtual path | ||
* @param {object} options Options | ||
@@ -143,7 +160,5 @@ * @param {@ui5/fs/tracing.Trace} trace Trace instance | ||
async _byPath(virPath, options, trace) { | ||
if (this.isPathExcluded(virPath)) { | ||
return null; | ||
} | ||
const relPath = this._resolveVirtualPathToBase(virPath); | ||
if (!virPath.startsWith(this._virBasePath) && virPath !== this._virBaseDir) { | ||
if (!relPath) { | ||
// Neither starts with basePath, nor equals baseDirectory | ||
@@ -164,5 +179,5 @@ if (!options.nodir && this._virBasePath.startsWith(virPath)) { | ||
} | ||
const relPath = virPath.substr(this._virBasePath.length); | ||
const fsPath = path.join(this._fsBasePath, relPath); | ||
const fsPath = this._resolveToFileSystem(relPath); | ||
trace.pathCall(); | ||
@@ -240,3 +255,3 @@ | ||
} | ||
super._write(resource); | ||
this._assignProjectToResource(resource); | ||
if (drain && readOnly) { | ||
@@ -247,4 +262,4 @@ throw new Error(`Error while writing resource ${resource.getPath()}: ` + | ||
const relPath = resource.getPath().substr(this._virBasePath.length); | ||
const fsPath = path.join(this._fsBasePath, relPath); | ||
const relPath = this._resolveVirtualPathToBase(resource.getPath(), true); | ||
const fsPath = this._resolveToFileSystem(relPath); | ||
const dirPath = path.dirname(fsPath); | ||
@@ -347,4 +362,18 @@ | ||
} | ||
_resolveToFileSystem(relPath) { | ||
const fsPath = path.join(this._fsBasePath, relPath); | ||
if (!fsPath.startsWith(this._fsBasePath)) { | ||
log.verbose(`Failed to resolve virtual path internally: ${relPath}`); | ||
log.verbose(` Adapter base path: ${this._fsBasePath}`); | ||
log.verbose(` Resulting path: ${fsPath}`); | ||
throw new Error( | ||
`Error while resolving internal virtual path: '${relPath}' resolves ` + | ||
`to a directory not accessible by this File System adapter instance`); | ||
} | ||
return fsPath; | ||
} | ||
} | ||
export default FileSystem; |
@@ -22,3 +22,4 @@ import {getLogger} from "@ui5/logger"; | ||
* @param {object} parameters Parameters | ||
* @param {string} parameters.virBasePath Virtual base path | ||
* @param {string} parameters.virBasePath | ||
* Virtual base path. Must be absolute, POSIX-style, and must end with a slash | ||
* @param {string[]} [parameters.excludes] List of glob patterns to exclude | ||
@@ -110,11 +111,7 @@ * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) | ||
async _byPath(virPath, options, trace) { | ||
if (this.isPathExcluded(virPath)) { | ||
const relPath = this._resolveVirtualPathToBase(virPath); | ||
if (!relPath) { | ||
return null; | ||
} | ||
if (!virPath.startsWith(this._virBasePath) && virPath !== this._virBaseDir) { | ||
// Neither starts with basePath, nor equals baseDirectory | ||
return null; | ||
} | ||
const relPath = virPath.substr(this._virBasePath.length); | ||
trace.pathCall(); | ||
@@ -145,4 +142,4 @@ | ||
} | ||
super._write(resource); | ||
const relPath = resource.getPath().substr(this._virBasePath.length); | ||
this._assignProjectToResource(resource); | ||
const relPath = this._resolveVirtualPathToBase(resource.getPath(), true); | ||
log.silly(`Writing to virtual path ${resource.getPath()}`); | ||
@@ -149,0 +146,0 @@ this._virFiles[relPath] = await resource.clone(); |
import stream from "node:stream"; | ||
import clone from "clone"; | ||
import path from "node:path"; | ||
import posixPath from "node:path/posix"; | ||
@@ -42,3 +42,3 @@ const fnTrue = () => true; | ||
* @param {object} parameters Parameters | ||
* @param {string} parameters.path Virtual path | ||
* @param {string} parameters.path Absolute virtual path of the resource | ||
* @param {fs.Stats|object} [parameters.statInfo] File information. Instance of | ||
@@ -62,12 +62,11 @@ * [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} or similar object | ||
if (!path) { | ||
throw new Error("Cannot create Resource: path parameter missing"); | ||
throw new Error("Unable to create Resource: Missing parameter 'path'"); | ||
} | ||
if (buffer && createStream || buffer && string || string && createStream || buffer && stream || | ||
string && stream || createStream && stream) { | ||
throw new Error("Cannot create Resource: Please set only one content parameter. " + | ||
"Buffer, string, stream or createStream"); | ||
throw new Error("Unable to create Resource: Please set only one content parameter. " + | ||
"'buffer', 'string', 'stream' or 'createStream'"); | ||
} | ||
this.#path = path; | ||
this.#name = Resource._getNameFromPath(path); | ||
this.setPath(path); | ||
@@ -120,6 +119,2 @@ this.#sourceMetadata = sourceMetadata; | ||
static _getNameFromPath(virPath) { | ||
return path.posix.basename(virPath); | ||
} | ||
/** | ||
@@ -265,6 +260,6 @@ * Gets a buffer with the resource content. | ||
/** | ||
* Gets the resources path | ||
* Gets the virtual resources path | ||
* | ||
* @public | ||
* @returns {string} (Virtual) path of the resource | ||
* @returns {string} Virtual path of the resource | ||
*/ | ||
@@ -276,10 +271,14 @@ getPath() { | ||
/** | ||
* Sets the resources path | ||
* Sets the virtual resources path | ||
* | ||
* @public | ||
* @param {string} path (Virtual) path of the resource | ||
* @param {string} path Absolute virtual path of the resource | ||
*/ | ||
setPath(path) { | ||
path = posixPath.normalize(path); | ||
if (!posixPath.isAbsolute(path)) { | ||
throw new Error(`Unable to set resource path: Path must be absolute: ${path}`); | ||
} | ||
this.#path = path; | ||
this.#name = Resource._getNameFromPath(path); | ||
this.#name = posixPath.basename(path); | ||
} | ||
@@ -286,0 +285,0 @@ |
@@ -1,2 +0,2 @@ | ||
import Resource from "./Resource.js"; | ||
import posixPath from "node:path/posix"; | ||
@@ -24,9 +24,13 @@ /** | ||
if (!path) { | ||
throw new Error("Cannot create ResourceFacade: path parameter missing"); | ||
throw new Error("Unable to create ResourceFacade: Missing parameter 'path'"); | ||
} | ||
if (!resource) { | ||
throw new Error("Cannot create ResourceFacade: resource parameter missing"); | ||
throw new Error("Unable to create ResourceFacade: Missing parameter 'resource'"); | ||
} | ||
path = posixPath.normalize(path); | ||
if (!posixPath.isAbsolute(path)) { | ||
throw new Error(`Unable to create ResourceFacade: Parameter 'path' must be absolute: ${path}`); | ||
} | ||
this.#path = path; | ||
this.#name = Resource._getNameFromPath(path); | ||
this.#name = posixPath.basename(path); | ||
this.#resource = resource; | ||
@@ -33,0 +37,0 @@ } |
import path from "node:path"; | ||
import minimatch from "minimatch"; | ||
import DuplexCollection from "./DuplexCollection.js"; | ||
import FileSystem from "./adapters/FileSystem.js"; | ||
import FsAdapter from "./adapters/FileSystem.js"; | ||
import MemAdapter from "./adapters/Memory.js"; | ||
@@ -27,4 +27,7 @@ import ReaderCollection from "./ReaderCollection.js"; | ||
* @param {object} parameters Parameters | ||
* @param {string} parameters.virBasePath Virtual base path | ||
* @param {string} [parameters.fsBasePath] File system base path | ||
* @param {string} parameters.virBasePath Virtual base path. Must be absolute, POSIX-style, and must end with a slash | ||
* @param {string} [parameters.fsBasePath] | ||
* File System base path. | ||
* If this parameter is supplied, a File System adapter will be created instead of a Memory adapter. | ||
* The provided path must be absolute and must use platform-specific path segment separators. | ||
* @param {string[]} [parameters.excludes] List of glob patterns to exclude | ||
@@ -39,3 +42,2 @@ * @param {object} [parameters.useGitignore=false] | ||
if (fsBasePath) { | ||
const FsAdapter = FileSystem; | ||
return new FsAdapter({fsBasePath, virBasePath, project, excludes, useGitignore}); | ||
@@ -48,8 +50,9 @@ } else { | ||
/** | ||
* Creates an adapter and wraps it in a ReaderCollection | ||
* Creates a File System adapter and wraps it in a ReaderCollection | ||
* | ||
* @public | ||
* @param {object} parameters Parameters | ||
* @param {string} parameters.virBasePath Virtual base path | ||
* @param {string} parameters.fsBasePath File system base path | ||
* @param {string} parameters.virBasePath Virtual base path. Must be absolute, POSIX-style, and must end with a slash | ||
* @param {string} parameters.fsBasePath | ||
* File System base path. Must be absolute and must use platform-specific path segment separators | ||
* @param {object} [parameters.project] Experimental, internal parameter. Do not use | ||
@@ -67,3 +70,3 @@ * @param {string[]} [parameters.excludes] List of glob patterns to exclude | ||
// since there would be no way to fill the adapter with resources | ||
throw new Error(`Missing parameter "fsBasePath"`); | ||
throw new Error(`Unable to create reader: Missing parameter "fsBasePath"`); | ||
} | ||
@@ -155,7 +158,7 @@ return new ReaderCollection({ | ||
* only used for writing files. If not supplied, a Memory adapter will be created. | ||
* @param {string} [parameters.name="vir & fs source"] Name of the collection | ||
* @param {string} [parameters.name="workspace"] Name of the collection | ||
* @param {string} [parameters.virBasePath="/"] Virtual base path | ||
* @returns {@ui5/fs/DuplexCollection} DuplexCollection which wraps the provided resource locators | ||
*/ | ||
export function createWorkspace({reader, writer, virBasePath = "/", name = "vir & fs source"}) { | ||
export function createWorkspace({reader, writer, virBasePath = "/", name = "workspace"}) { | ||
if (!writer) { | ||
@@ -162,0 +165,0 @@ writer = new MemAdapter({ |
{ | ||
"name": "@ui5/fs", | ||
"version": "3.0.0-rc.4", | ||
"version": "3.0.0-rc.5", | ||
"description": "UI5 Tooling - File System Abstraction", | ||
@@ -35,3 +35,3 @@ "author": { | ||
"engines": { | ||
"node": "^16.18.0 || >=18.0.0", | ||
"node": "^16.18.0 || >=18.12.0", | ||
"npm": ">= 8" | ||
@@ -124,3 +124,3 @@ }, | ||
"dependencies": { | ||
"@ui5/logger": "^3.0.1-rc.2", | ||
"@ui5/logger": "^3.0.1-rc.3", | ||
"clone": "^2.1.2", | ||
@@ -131,3 +131,3 @@ "escape-string-regexp": "^5.0.0", | ||
"micromatch": "^4.0.5", | ||
"minimatch": "^6.1.5", | ||
"minimatch": "^6.1.6", | ||
"pretty-hrtime": "^1.0.3", | ||
@@ -145,6 +145,6 @@ "random-int": "^3.0.0" | ||
"docdash": "^2.0.1", | ||
"eslint": "^8.32.0", | ||
"eslint": "^8.33.0", | ||
"eslint-config-google": "^0.14.0", | ||
"eslint-plugin-ava": "^14.0.0", | ||
"eslint-plugin-jsdoc": "^39.6.7", | ||
"eslint-plugin-jsdoc": "^39.7.4", | ||
"esmock": "^2.1.0", | ||
@@ -154,3 +154,3 @@ "jsdoc": "^3.6.11", | ||
"open-cli": "^7.1.0", | ||
"rimraf": "^4.1.1", | ||
"rimraf": "^4.1.2", | ||
"sinon": "^15.0.1", | ||
@@ -157,0 +157,0 @@ "tap-xunit": "^2.4.1" |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
136205
2902
Updated@ui5/logger@^3.0.1-rc.3
Updatedminimatch@^6.1.6