Socket
Socket
Sign inDemoInstall

@ui5/fs

Package Overview
Dependencies
Maintainers
3
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ui5/fs - npm Package Compare versions

Comparing version 1.0.2 to 1.1.0

9

CHANGELOG.md

@@ -5,4 +5,10 @@ # Changelog

A list of unreleased changes can be found [here](https://github.com/SAP/ui5-fs/compare/v1.0.2...HEAD).
A list of unreleased changes can be found [here](https://github.com/SAP/ui5-fs/compare/v1.1.0...HEAD).
<a name="v1.1.0"></a>
## [v1.1.0] - 2019-04-28
### Features
- **AbstractAdapter:** Add excludes option ([#140](https://github.com/SAP/ui5-fs/issues/140)) [`daef31f`](https://github.com/SAP/ui5-fs/commit/daef31f4fb22405e8fa889615b1f3545099eb186)
<a name="v1.0.2"></a>

@@ -52,2 +58,3 @@ ## [v1.0.2] - 2019-03-21

[v1.1.0]: https://github.com/SAP/ui5-fs/compare/v1.0.2...v1.1.0
[v1.0.2]: https://github.com/SAP/ui5-fs/compare/v1.0.1...v1.0.2

@@ -54,0 +61,0 @@ [v1.0.1]: https://github.com/SAP/ui5-fs/compare/v1.0.0...v1.0.1

const log = require("@ui5/logger").getLogger("resources:adapters:AbstractAdapter");
const minimatch = require("minimatch");
const micromatch = require("micromatch");
const AbstractReaderWriter = require("../AbstractReaderWriter");

@@ -21,4 +22,5 @@ const Resource = require("../Resource");

* @param {string} parameters.virBasePath Virtual base path
* @param {string[]} [parameters.excludes] List of glob patterns to exclude
*/
constructor({virBasePath, project}) {
constructor({virBasePath, excludes = [], project}) {
if (new.target === AbstractAdapter) {

@@ -30,5 +32,6 @@ throw new TypeError("Class 'AbstractAdapter' is abstract");

this._virBaseDir = virBasePath.slice(0, -1);
this._excludes = excludes;
this._excludesNegated = excludes.map((pattern) => `!${pattern}`);
this._project = project;
}
/**

@@ -47,10 +50,17 @@ * Locates resources by glob.

_byGlob(virPattern, options = {nodir: true}, trace) {
const excludes = this._excludesNegated;
if (!(virPattern instanceof Array)) {
virPattern = [virPattern];
}
// Append static exclude patterns
virPattern = Array.prototype.concat.apply(virPattern, excludes);
return Promise.all(virPattern.map(this._normalizePattern, this)).then((patterns) => {
patterns = Array.prototype.concat.apply([], patterns);
if (patterns.length === 0) {
return [];
}
patterns = Array.prototype.concat.apply([], patterns);
if (!options.nodir) {

@@ -80,2 +90,12 @@ for (let i = patterns.length - 1; i >= 0; i--) {

/**
* Validate if virtual path should be excluded
*
* @param {string} virPath Virtual Path
* @returns {boolean} True if path is excluded, otherwise false
*/
isPathExcluded(virPath) {
return micromatch(virPath, this._excludes).length > 0;
}
/**
* Normalizes virtual glob patterns.

@@ -82,0 +102,0 @@ *

129

lib/adapters/FileSystem.js
const log = require("@ui5/logger").getLogger("resources:adapters:FileSystem");
const path = require("path");
const fs = require("graceful-fs");
const glob = require("globby");
const globby = require("globby");
const makeDir = require("make-dir");

@@ -24,5 +24,6 @@ const {PassThrough} = require("stream");

* @param {string} parameters.fsBasePath (Physical) File system path
* @param {string[]} [parameters.excludes] List of glob patterns to exclude
*/
constructor({virBasePath, project, fsBasePath}) {
super({virBasePath, project});
constructor({virBasePath, project, fsBasePath, excludes}) {
super({virBasePath, project, excludes});
this._fsBasePath = fsBasePath;

@@ -41,65 +42,67 @@ }

*/
_runGlob(patterns, options = {nodir: true}, trace) {
return new Promise((resolve, reject) => {
const opt = {
cwd: this._fsBasePath,
dot: true,
nodir: options.nodir
};
async _runGlob(patterns, options = {nodir: true}, trace) {
const opt = {
cwd: this._fsBasePath,
dot: true,
onlyFiles: options.nodir,
followSymlinkedDirectories: false
};
trace.globCall();
trace.globCall();
glob(patterns, opt).then((matches) => {
const promises = [];
if (!opt.nodir && patterns[0] === "") { // Match physical root directory
promises.push(new Promise((resolve, reject) => {
fs.stat(this._fsBasePath, (err, stat) => {
if (err) {
reject(err);
} else {
resolve(new Resource({
project: this._project,
statInfo: stat,
path: this._virBaseDir,
createStream: () => {
return fs.createReadStream(this._fsBasePath);
}
}));
const promises = [];
if (!opt.onlyFiles && patterns.includes("")) { // Match physical root directory
promises.push(new Promise((resolve, reject) => {
fs.stat(this._fsBasePath, (err, stat) => {
if (err) {
reject(err);
} else {
resolve(new Resource({
project: this._project,
statInfo: stat,
path: this._virBaseDir,
createStream: () => {
return fs.createReadStream(this._fsBasePath);
}
});
}));
}
}));
}
});
}));
}
for (let i = matches.length - 1; i >= 0; i--) {
promises.push(new Promise((resolve, reject) => {
const fsPath = path.join(this._fsBasePath, matches[i]);
const virPath = (this._virBasePath + matches[i]);
// Remove empty string glob patterns
// Starting with globby v8 or v9 empty glob patterns "" act like "**"
// Micromatch throws on empty strings. We just ignore them since they are
// typically caused by our normalization in the AbstractAdapter
const globbyPatterns = patterns.filter((pattern) => {
return pattern !== "";
});
if (globbyPatterns.length > 0) {
const matches = await globby(globbyPatterns, opt);
for (let i = matches.length - 1; i >= 0; i--) {
promises.push(new Promise((resolve, reject) => {
const fsPath = path.join(this._fsBasePath, matches[i]);
const virPath = (this._virBasePath + matches[i]);
// Workaround for not getting the stat from the glob
fs.stat(fsPath, (err, stat) => {
if (err) {
reject(err);
} else {
resolve(new Resource({
project: this._project,
statInfo: stat,
path: virPath,
createStream: () => {
return fs.createReadStream(fsPath);
}
}));
}
});
}));
}
// Workaround for not getting the stat from the glob
fs.stat(fsPath, (err, stat) => {
if (err) {
reject(err);
} else {
resolve(new Resource({
project: this._project,
statInfo: stat,
path: virPath,
createStream: () => {
return fs.createReadStream(fsPath);
}
}));
}
});
}));
}
}
const results = await Promise.all(promises);
Promise.all(promises).then(function(results) {
const flat = Array.prototype.concat.apply([], results);
resolve(flat);
}, function(err) {
reject(err);
});
}).catch((err) => {
log.error(err);
});
});
// Flatten results
return Array.prototype.concat.apply([], results);
}

@@ -117,2 +120,6 @@

_byPath(virPath, options, trace) {
if (this.isPathExcluded(virPath)) {
return Promise.resolve(null);
}
return new Promise((resolve, reject) => {

@@ -119,0 +126,0 @@ if (!virPath.startsWith(this._virBasePath) && virPath !== this._virBaseDir) {

@@ -20,5 +20,6 @@ const log = require("@ui5/logger").getLogger("resources:adapters:Memory");

* @param {string} parameters.virBasePath Virtual base path
* @param {string[]} [parameters.excludes] List of glob patterns to exclude
*/
constructor({virBasePath, project}) {
super({virBasePath, project});
constructor({virBasePath, project, excludes}) {
super({virBasePath, project, excludes});
this._virFiles = {}; // map full of files

@@ -38,5 +39,5 @@ this._virDirs = {}; // map full of directories

*/
_runGlob(patterns, options = {nodir: true}, trace) {
async _runGlob(patterns, options = {nodir: true}, trace) {
if (patterns[0] === "" && !options.nodir) { // Match virtual root directory
return Promise.resolve([
return [
new Resource({

@@ -51,3 +52,3 @@ project: this.project,

})
]);
];
}

@@ -73,3 +74,3 @@

return Promise.resolve(matchedResources);
return matchedResources;
}

@@ -87,2 +88,5 @@

_byPath(virPath, options, trace) {
if (this.isPathExcluded(virPath)) {
return Promise.resolve(null);
}
return new Promise((resolve, reject) => {

@@ -89,0 +93,0 @@ if (!virPath.startsWith(this._virBasePath) && virPath !== this._virBaseDir) {

@@ -0,1 +1,2 @@

const log = require("@ui5/logger").getLogger("resources:resourceFactory");
const path = require("path");

@@ -18,2 +19,22 @@ const FsAdapter = require("./adapters/FileSystem");

/**
* Callback to retrieve excludes for a given project
*
* @public
* @callback module:@ui5/fs.resourceFactory~getProjectExcludes
* @param {Object} Project
* @returns {string[]} List of glob patterns to exclude
*/
/**
* Callback to retrieve a prefix to use for a given virtual base path of a project
*
* @public
* @callback module:@ui5/fs.resourceFactory~getVirtualBasePathPrefix
* @param {Object} parameters Parameters
* @param {Object} parameters.project Project
* @param {Object} parameters.virBasePath virtual base path to prefix
* @returns {string} Prefix for the virtual base path
*/
/**
* Creates resource reader collections for a (sub-)tree. Returns an object of resource readers:

@@ -31,6 +52,13 @@ * <pre>

* @param {boolean} [parameters.useNamespaces=false] Use project namespaces as path prefixes
* DEPRECATED: Use parameter <code>getVirtualBasePathPrefix</code> instead.
* @param {module:@ui5/fs.resourceFactory~getProjectExcludes} [parameters.getProjectExcludes]
* Callback to retrieve the exclude globs of a project
* @param {module:@ui5/fs.resourceFactory~getVirtualBasePathPrefix} [parameters.getVirtualBasePathPrefix]
* Callback to retrieve a prefix for a given virtual base path of a project if required
* @returns {Object} Object containing <code>source</code> and <code>dependencies</code> resource readers
*/
createCollectionsForTree(tree, {useNamespaces=false, virtualReaders={}} = {}) {
// TODO: virtualReaders is private API. The virtual reader of a project should be stored on the
createCollectionsForTree(tree, {
useNamespaces=false, getProjectExcludes, getVirtualBasePathPrefix, virtualReaders={}
} = {}) {
// TODO 2.0: virtualReaders is private API. The virtual reader of a project should be stored on the
// project itself. This requires projects to become objects independent from the dependency tree.

@@ -44,16 +72,22 @@ // Also see: https://github.com/SAP/ui5-project/issues/122

if (useNamespaces) {
// TODO 2.0: Remove deprecated "useNamespaces" parameter
log.warn(`resourceFactory.createCollectionsForTree called with deprecated parameter "useNamespaces". ` +
`This parameter will be removed in @ui5/fs version 2.0. ` +
`Use parameter "getVirtualBasePathPrefix" instead`);
}
if (useNamespaces && getVirtualBasePathPrefix) {
throw new Error(
`resourceFactory.createCollectionsForTree called with parameters "useNamespace" and ` +
`"getVirtualBasePathPrefix". Please provide only one of the two.`);
}
function processDependencies(project) {
if (project.resources && project.resources.pathMappings) {
const fsReaders = [];
for (let virBasePath in project.resources.pathMappings) {
// Create an fs reader for every path mapping
const fsAdapters = [];
for (const virBasePath in project.resources.pathMappings) {
if (project.resources.pathMappings.hasOwnProperty(virBasePath)) {
// Prevent duplicate dependency resource locators
const fsPath = project.resources.pathMappings[virBasePath];
const fsBasePath = path.join(project.path, fsPath);
if (useNamespaces && project.metadata.namespace) { // Prefix resource paths with namespace
virBasePath = "/resources/" + project.metadata.namespace + virBasePath;
}
// Prevent duplicate dependency resource locators
const key = virBasePath + fsBasePath;

@@ -65,4 +99,11 @@ if (dependencyPathIndex[key]) {

const fsReader = resourceFactory.createAdapter({fsBasePath, virBasePath, project});
fsReaders.push(fsReader);
// Create an fs adapter for every path mapping
const fsAdapter = resourceFactory._createFsAdapterForVirtualBasePath({
project,
virBasePath,
useNamespace: useNamespaces,
getProjectExcludes,
getVirtualBasePathPrefix
});
fsAdapters.push(fsAdapter);
}

@@ -77,7 +118,7 @@ }

name: `fs & vir reader collection for project ${project.metadata.name}`,
readers: [virtualReader, ...fsReaders]
readers: [virtualReader, ...fsAdapters]
});
dependencyCollection.push(readerCollection);
} else {
dependencyCollection.push(...fsReaders);
dependencyCollection.push(...fsAdapters);
}

@@ -92,12 +133,13 @@ }

if (tree.resources && tree.resources.pathMappings) {
for (let virBasePath in tree.resources.pathMappings) {
for (const virBasePath in tree.resources.pathMappings) {
if (tree.resources.pathMappings.hasOwnProperty(virBasePath)) {
const fsBasePath = path.join(tree.path, tree.resources.pathMappings[virBasePath]);
if (useNamespaces && tree.metadata.namespace) { // Prefix resource paths with namespace
virBasePath = "/resources/" + tree.metadata.namespace + virBasePath;
}
sourceResourceLocators.push(resourceFactory.createAdapter({
fsBasePath, virBasePath, project: tree
}));
// Create an fs adapter for every path mapping
const fsAdapter = resourceFactory._createFsAdapterForVirtualBasePath({
project: tree,
virBasePath,
useNamespace: useNamespaces,
getProjectExcludes,
getVirtualBasePathPrefix
});
sourceResourceLocators.push(fsAdapter);
}

@@ -126,2 +168,85 @@ }

/**
* Creates a FileSystem adapter mapping to the given virtual base path based on the given projects
* configuration.
*
* @param {Object} parameters Parameters
* @param {Project} parameters.project A project
* @param {string} parameters.virBasePath Virtual base path to create the adapter for
* @param {boolean} parameters.useNamespaces Use project namespace as path prefix
* @param {module:@ui5/fs.resourceFactory~getProjectExcludes} [parameters.getProjectExcludes]
* Callback to retrieve the exclude glob of a project
* @param {module:@ui5/fs.resourceFactory~getVirtualBasePathPrefix} [parameters.getVirtualBasePathPrefix]
* Callback to retrieve the exclude glob of a project
* @returns {Promise<string[]>} Promise resolving to list of normalized glob patterns
*/
_createFsAdapterForVirtualBasePath({
project, virBasePath, useNamespace, getProjectExcludes, getVirtualBasePathPrefix
}) {
const fsPath = project.resources.pathMappings[virBasePath];
const fsBasePath = path.join(project.path, fsPath);
let pathExcludes;
if (getProjectExcludes) {
pathExcludes = getProjectExcludes(project);
}
if (getVirtualBasePathPrefix) {
const virBasePathPrefix = getVirtualBasePathPrefix({project, virBasePath});
if (virBasePathPrefix) {
log.verbose(`Prefixing virtual base path ${virBasePath} of project ${project.metadata.name} ` +
`${virBasePathPrefix}...`);
virBasePath = virBasePathPrefix + virBasePath;
log.verbose(`New virtual base path: ${virBasePath}`);
if (pathExcludes) {
const normalizedPatterns = pathExcludes.map((pattern) => {
return resourceFactory._prefixGlobPattern(pattern, virBasePathPrefix);
});
pathExcludes = Array.prototype.concat.apply([], normalizedPatterns);
}
}
} else if (useNamespace && project.metadata.namespace) { // Prefix resource paths with namespace
const namespacedBasePath = "/resources/" + project.metadata.namespace;
virBasePath = namespacedBasePath + virBasePath;
if (pathExcludes) {
const normalizedPatterns = pathExcludes.map((pattern) => {
return resourceFactory._prefixGlobPattern(pattern, namespacedBasePath);
});
pathExcludes = Array.prototype.concat.apply([], normalizedPatterns);
}
}
return resourceFactory.createAdapter({
fsBasePath,
virBasePath,
excludes: pathExcludes,
project
});
},
/**
* Normalizes virtual glob patterns by prefixing them with
* a given virtual base directory path
*
* @param {string} virPattern glob pattern for virtual directory structure
* @param {string} virBaseDir virtual base directory path to prefix the given patterns with
* @returns {Promise<string[]>} Promise resolving to list of normalized glob patterns
*/
_prefixGlobPattern(virPattern, virBaseDir) {
const minimatch = require("minimatch");
const mm = new minimatch.Minimatch(virPattern);
const resultGlobs = [];
for (let i = 0; i < mm.globSet.length; i++) {
let resultPattern = path.posix.join(virBaseDir, mm.globSet[i]);
if (mm.negate) {
resultPattern = "!" + resultPattern;
}
resultGlobs.push(resultPattern);
}
return resultGlobs;
},
/**
* Creates a resource <code>ReaderWriter</code>.

@@ -136,9 +261,10 @@ *

* @param {string} [parameters.fsBasePath] File system base path
* @param {string[]} [parameters.excludes] List of glob patterns to exclude
* @returns {module:@ui5/fs.adapters.FileSystem|module:@ui5/fs.adapters.Memory} File System- or Virtual Adapter
*/
createAdapter({fsBasePath, virBasePath, project}) {
createAdapter({fsBasePath, virBasePath, project, excludes}) {
if (fsBasePath) {
return new FsAdapter({fsBasePath, virBasePath, project});
return new FsAdapter({fsBasePath, virBasePath, project, excludes});
} else {
return new MemAdapter({virBasePath, project});
return new MemAdapter({virBasePath, project, excludes});
}

@@ -145,0 +271,0 @@ },

{
"name": "@ui5/fs",
"version": "1.0.2",
"version": "1.1.0",
"description": "UI5 Tooling - File System Abstraction",

@@ -62,3 +62,4 @@ "author": "SAP SE (https://www.sap.com)",

"coverage/**",
"test/**"
"test/**",
".eslintrc.js"
],

@@ -98,11 +99,10 @@ "check-coverage": true,

"clone": "^2.1.0",
"dir-glob": "2.0.0",
"globby": "^7.1.1",
"globby": "^9.2.0",
"graceful-fs": "^4.1.15",
"make-dir": "^2.1.0",
"micromatch": "^3.1.4",
"make-dir": "^3.0.0",
"micromatch": "^4.0.2",
"minimatch": "^3.0.3",
"mock-require": "^3.0.3",
"pretty-hrtime": "^1.0.3",
"random-int": "^1.0.0"
"random-int": "^2.0.0"
},

@@ -115,11 +115,11 @@ "devDependencies": {

"cross-env": "^5.1.1",
"docdash": "^1.0.3",
"eslint": "^5.15.1",
"eslint-config-google": "^0.12.0",
"eslint-plugin-jsdoc": "^4.1.1",
"jsdoc": "^3.5.5",
"nyc": "^13.3.0",
"opn-cli": "^4.0.0",
"docdash": "^1.1.1",
"eslint": "^5.16.0",
"eslint-config-google": "^0.13.0",
"eslint-plugin-jsdoc": "^4.8.4",
"jsdoc": "^3.6.2",
"nyc": "^14.1.1",
"opn-cli": "^4.1.0",
"rimraf": "^2.6.3",
"sinon": "^7.2.7",
"sinon": "^7.3.2",
"tap-nyan": "^1.1.0"

@@ -126,0 +126,0 @@ },

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc