Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BREAKING] Adapt to ui5-project changes. Add Link-reader, WriterCollection #381

Merged
merged 10 commits into from
Jun 13, 2022
14 changes: 14 additions & 0 deletions lib/AbstractReader.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,20 @@ class AbstractReader {
callback
});
}
/**
* Create a [Link-Reader]{@link module:@ui5/fs.readers.Link} from the current reader
*
* @public
* @param {module:@ui5/fs.reader.Link.PathMapping} pathMapping Link configuration
* @returns {module:@ui5/fs.reader.Link} Link instance
*/
link(pathMapping) {
const Link = require("./readers/Link");
return new Link({
reader: this,
pathMapping
});
}

/**
* Locates resources by one or more glob patterns.
Expand Down
77 changes: 55 additions & 22 deletions lib/Resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ class Resource {
* stream of the content of this resource (cannot be used in conjunction with parameters buffer,
* string or stream).
* In some cases this is the most memory-efficient way to supply resource content
* @param {module:@ui5/project.specifications.Project} [parameters.project] Project this resource is associated with
* @param {object} [parameters.source] Experimental, internal parameter. Do not use
* @param {object} [parameters.project] Experimental, internal parameter. Do not use
*/
constructor({path, statInfo, buffer, string, createStream, stream, source, project}) {
constructor({path, statInfo, buffer, string, createStream, stream, project, source}) {
if (!path) {
throw new Error("Cannot create Resource: path parameter missing");
}
Expand All @@ -53,12 +53,14 @@ class Resource {

this._path = path;
this._name = this._getNameFromPath(path);
this._project = project; // Experimental, internal parameter

this._source = source; // Experimental, internal parameter
if (this._source) {
// Indicator for adapters like FileSystem to detect whether a resource has been changed
this._source.modified = false;
}
this.__project = project; // Two underscores since "_project" was widely used in UI5 Tooling 2.0

this._statInfo = statInfo || { // TODO
isFile: fnTrue,
isDirectory: fnFalse,
Expand Down Expand Up @@ -292,30 +294,61 @@ class Resource {
* @public
* @returns {Promise<module:@ui5/fs.Resource>} Promise resolving with the clone
*/
clone() {
async clone() {
const options = await this._getCloneOptions();
return new Resource(options);
}

async _getCloneOptions() {
const options = {
path: this._path,
statInfo: clone(this._statInfo)
statInfo: clone(this._statInfo),
source: this._source
};

const addContentOption = () => {
if (this._stream) {
return this._getBufferFromStream().then(function(buffer) {
options.buffer = buffer;
});
} else {
if (this._createStream) {
options.createStream = this._createStream;
} else if (this._buffer) {
options.buffer = this._buffer;
}
return Promise.resolve();
}
};
if (this._stream) {
options.buffer = await this._getBufferFromStream();
} else if (this._createStream) {
options.createStream = this._createStream;
} else if (this._buffer) {
options.buffer = this._buffer;
}

return addContentOption().then(() => {
return new Resource(options);
});
return options;
}

/**
* Retrieve the project assigned to the resource
*
* @public
* @returns {module:@ui5/project.specifications.Project} Project this resource is associated with
*/
getProject() {
return this.__project;
}

/**
* Assign a project to the resource
*
* @public
* @param {module:@ui5/project.specifications.Project} project Project this resource is associated with
*/
setProject(project) {
if (this.__project) {
throw new Error(`Unable to assign project ${project.getName()} to resource ${this._path}: ` +
`Resource is already associated to project ${this.__project}`);
}
this.__project = project;
}

/**
* Check whether a project has been assigned to the resource
*
* @public
* @returns {boolean} True if the resource is associated with a project
*/
hasProject() {
return !!this.__project;
}

/**
Expand Down
191 changes: 191 additions & 0 deletions lib/ResourceFacade.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/**
* A [Resource]{module:@ui5/project.Resource} with a different path than it's original
*
* @public
* @memberof module:@ui5/fs
*/
class ResourceFacade {
/**
* The constructor.
*
* @public
* @param {object} parameters Parameters
* @param {string} parameters.path Virtual path
* @param {module:@ui5/fs.Resource} parameters.resource Resource to cover
*/
constructor({path, resource}) {
if (!path) {
throw new Error("Cannot create ResourceFacade: path parameter missing");
}
if (!resource) {
throw new Error("Cannot create ResourceFacade: resource parameter missing");
}
this._path = path;
this._resource = resource;
}

/**
* Gets the resources path
*
* @public
* @returns {string} (Virtual) path of the resource
*/
getPath() {
return this._path;
}

/**
* Sets the resources path
*
* @public
* @param {string} path (Virtual) path of the resource
*/
setPath(path) {
throw new Error(`The path of a ResourceFacade can't be changed at the moment`);
}

/**
* Returns a clone of the resource. The clones content is independent from that of the original resource.
* A ResourceFacade becomes a Resource
*
* @public
* @returns {Promise<module:@ui5/fs.Resource>} Promise resolving with the clone
*/
async clone() {
// Cloning resolves the facade
const resourceClone = await this._resource.clone();
resourceClone.setPath(this.getPath());
return resourceClone;
}

/**
* ======================================================================
* Call through functions to original resource
* ======================================================================
*/
/**
* Gets a buffer with the resource content.
*
* @public
* @returns {Promise<Buffer>} Promise resolving with a buffer of the resource content.
*/
async getBuffer() {
return this._resource.getBuffer();
}

/**
* Sets a Buffer as content.
*
* @public
* @param {Buffer} buffer Buffer instance
*/
setBuffer(buffer) {
return this._resource.setBuffer(buffer);
}

/**
* Gets a string with the resource content.
*
* @public
* @returns {Promise<string>} Promise resolving with the resource content.
*/
getString() {
return this._resource.getString();
}

/**
* Sets a String as content
*
* @public
* @param {string} string Resource content
*/
setString(string) {
return this._resource.setString(string);
}

/**
* Gets a readable stream for the resource content.
*
* Repetitive calls of this function are only possible if new content has been set in the meantime (through
* [setStream]{@link module:@ui5/fs.Resource#setStream}, [setBuffer]{@link module:@ui5/fs.Resource#setBuffer}
* or [setString]{@link module:@ui5/fs.Resource#setString}). This
* is to prevent consumers from accessing drained streams.
*
* @public
* @returns {stream.Readable} Readable stream for the resource content.
*/
getStream() {
return this._resource.getStream();
}

/**
* Sets a readable stream as content.
*
* @public
* @param {stream.Readable|module:@ui5/fs.Resource~createStream} stream Readable stream of the resource content or
callback for dynamic creation of a readable stream
*/
setStream(stream) {
return this._resource.setStream(stream);
}

/**
* Gets the resources stat info.
* Note that a resources stat information is not updated when the resource is being modified.
* Also, depending on the used adapter, some fields might be missing which would be present for a
* [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} instance.
*
* @public
* @returns {fs.Stats|object} Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats}
* or similar object
*/
getStatInfo() {
return this._resource.getStatInfo();
}

/**
* Size in bytes allocated by the underlying buffer.
*
* @see {TypedArray#byteLength}
* @returns {Promise<number>} size in bytes, <code>0</code> if there is no content yet
*/
async getSize() {
return this._resource.getSize();
}

/**
* Adds a resource collection name that was involved in locating this resource.
*
* @param {string} name Resource collection name
*/
pushCollection(name) {
return this._resource.pushCollection(name);
}

/**
* Tracing: Get tree for printing out trace
*
* @returns {object} Trace tree
*/
getPathTree() {
return this._resource.getPathTree();
}

getSource() {
return this._resource.getSource();
}

getProject() {
return this._resource.getProject();
}

hasProject() {
return this._resource.hasProject();
}

getConcealedResource() {
return this._resource;
}
}

module.exports = ResourceFacade;
Loading