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

[FEATURE] Workspace: Add getModules method / Specification: Add getId method #592

Merged
merged 3 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions lib/graph/Workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@ class Workspace {
return this.#configuration.metadata.name;
}

/**
* Returns an array of [Module]{@ui5/project/graph/Module} instances found in the configured
* dependency-management resolution paths of this workspace, sorted by module ID.
*
* @public
* @returns {Promise<@ui5/project/graph/Module[]>}
* Array of Module instances sorted by module ID
*/
async getModules() {
const {moduleIdMap} = await this._getResolvedModules();
const sortedMap = new Map([...moduleIdMap].sort((a, b) => String(a[0]).localeCompare(b[0])));
flovogt marked this conversation as resolved.
Show resolved Hide resolved
return Array.from(sortedMap.values());
}

/**
* For a given project name (e.g. the value of the <code>metadata.name</code> property in a ui5.yaml),
* returns a [Module]{@ui5/project/graph/Module} instance or <code>undefined</code> depending on whether the project
Expand All @@ -82,7 +96,7 @@ class Workspace {
* @public
* @param {string} projectName Name of the project
* @returns {Promise<@ui5/project/graph/Module|undefined>}
* Module instance of <code>undefined</code> if none is found
* Module instance, or <code>undefined</code> if none is found
*/
async getModuleByProjectName(projectName) {
const {projectNameMap} = await this._getResolvedModules();
Expand All @@ -98,7 +112,7 @@ class Workspace {
* @public
* @param {string} nodeId Node ID of the module
* @returns {Promise<@ui5/project/graph/Module|undefined>}
* Module instance of <code>undefined</code> if none is found
* Module instance, or <code>undefined</code> if none is found
*/
async getModuleByNodeId(nodeId) {
const {moduleIdMap} = await this._getResolvedModules();
Expand Down
3 changes: 2 additions & 1 deletion lib/specifications/Project.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ class Project extends Specification {
* @returns {boolean} True if the project is a framework project
*/
isFrameworkProject() {
return this.__id.startsWith("@openui5/") || this.__id.startsWith("@sapui5/");
const id = this.getId();
return id.startsWith("@openui5/") || id.startsWith("@sapui5/");
}

/**
Expand Down
34 changes: 26 additions & 8 deletions lib/specifications/Specification.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,10 @@ class Specification {
this._version = version;
this._modulePath = modulePath;

// The configured name (metadata.name) should be the unique identifier
// The ID property as supplied by the translators is only here for debugging and potential tracing purposes
// The ID property is filled from the provider (e.g. package.json "name") and might differ between providers.
// It is mainly used to detect framework libraries marked by @openui5 / @sapui5 scopes of npm package.
// (see Project#isFrameworkProject)
// In general, the configured name (metadata.name) should be used instead as the unique identifier of a project.
this.__id = id;

// Deep clone config to prevent changes by reference
Expand Down Expand Up @@ -157,7 +159,23 @@ class Specification {

/* === Attributes === */
/**
* Get the name of this specification
* Gets the ID of this specification.
*
* <p><b>Note: </b>Only to be used for special occasions as it is specific to the provider that was used and does
* not necessarily represent something defined by the project.</p>
*
* For general purposes of a unique identifier use
* {@link @ui5/project/specifications/Specification#getName getName} instead.
*
* @public
* @returns {string} Specification ID
*/
getId() {
return this.__id;
}

/**
* Gets the name of this specification. Represents a unique identifier.
*
* @public
* @returns {string} Specification name
Expand All @@ -167,7 +185,7 @@ class Specification {
}

/**
* Get the kind of this specification, for example <code>project</code> or <code>extension</code>
* Gets the kind of this specification, for example <code>project</code> or <code>extension</code>
*
* @public
* @returns {string} Specification kind
Expand All @@ -177,7 +195,7 @@ class Specification {
}

/**
* Get the type of this specification,
* Gets the type of this specification,
* for example <code>application</code> or <code>library</code> in case of projects,
* and <code>task</code> or <code>server-middleware</code> in case of extensions
*
Expand All @@ -199,7 +217,7 @@ class Specification {
}

/**
* Get the specification's generic version, as typically defined in a <code>package.json</code>
* Gets the specification's generic version, as typically defined in a <code>package.json</code>
*
* @public
* @returns {string} Project version
Expand All @@ -209,7 +227,7 @@ class Specification {
}

/**
* Get the specification's file system path. This might not be POSIX-style on some platforms
* Gets the specification's file system path. This might not be POSIX-style on some platforms
*
* @public
* @returns {string} Project root path
Expand All @@ -220,7 +238,7 @@ class Specification {

/* === Resource Access === */
/**
* Get a [ReaderCollection]{@link @ui5/fs/ReaderCollection} for the root directory of the specification.
* Gets a [ReaderCollection]{@link @ui5/fs/ReaderCollection} for the root directory of the specification.
* Resource readers always use POSIX-style
*
* @public
Expand Down
3 changes: 3 additions & 0 deletions test/lib/graph/Workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ test("Basic resolution", async (t) => {
t.is(await workspace.getModuleByNodeId("library.d"), libD,
"getModuleByNodeId returns correct module for library.d");

const modules = await workspace.getModules();
t.deepEqual(modules, [libD, libE], "getModules returns modules sorted by module ID");

t.deepEqual(Array.from(moduleIdMap.keys()).sort(), ["library.d", "library.e"], "Correct module ID keys");
moduleIdMap.forEach((value, key) => {
t.is(value, projectNameMap.get(key), `Same instance of module ${key} in both maps`);
Expand Down
1 change: 1 addition & 0 deletions test/lib/specifications/Specification.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ test("Specification can't be instantiated", (t) => {

test("Instantiate a basic project", async (t) => {
const project = await Specification.create(t.context.basicProjectInput);
t.is(project.getId(), "application.a.id", "Returned correct ID");
t.is(project.getName(), "application.a", "Returned correct name");
t.is(project.getVersion(), "1.0.0", "Returned correct version");
t.is(project.getRootPath(), applicationAPath, "Returned correct project path");
Expand Down