UNPKG

@sap-ux/project-access

Version:

Library to access SAP Fiori tools projects

198 lines 8.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getSpecification = getSpecification; exports.refreshSpecificationDistTags = refreshSpecificationDistTags; exports.getSpecificationPath = getSpecificationPath; const fs_1 = require("fs"); const promises_1 = require("fs/promises"); const path_1 = require("path"); const semver_1 = require("semver"); const module_loader_1 = require("./module-loader"); const ui5_config_1 = require("./ui5-config"); const info_1 = require("./info"); const constants_1 = require("../constants"); const file_1 = require("../file"); const command_1 = require("../command"); const specificationDistTagPath = (0, path_1.join)(constants_1.fioriToolsDirectory, constants_1.FileName.SpecificationDistTags); /** * Gets the dist-tag for the provided project/app and returns it. * * @param root - root path of the project/app * @param [options] - optional options * @param [options.logger] - logger instance * @returns - specification instance */ async function getProjectDistTag(root, options) { let distTag = 'latest'; try { const webappPath = await (0, ui5_config_1.getWebappPath)(root); const manifest = await (0, file_1.readJSON)((0, path_1.join)(webappPath, constants_1.FileName.Manifest)); const minUI5Version = (0, info_1.getMinimumUI5Version)(manifest); if (minUI5Version && (0, semver_1.valid)(minUI5Version)) { const [mayor, minor] = minUI5Version.split('.'); distTag = `UI5-${mayor}.${minor}`; } } catch (error) { options?.logger?.error(`Failed to get minimum UI5 version from manifest: ${error} using 'latest'`); } return distTag; } /** * Checks if package.json contains dev dependency to specification. * * @param root - root path of the project/app * @returns If dev dependency to specification is found in package.json */ async function hasSpecificationDevDependency(root) { const packageJson = await (0, file_1.readJSON)((0, path_1.join)(root, constants_1.FileName.Package)); return !!packageJson.devDependencies?.['@sap/ux-specification']; } /** * Loads the specification module from cache and returns it. * * @param root - root path of the project/app * @param [options] - optional options * @param [options.logger] - logger instance * @returns - specification instance */ async function getSpecificationModule(root, options) { const logger = options?.logger; let specification; const version = await getSpecificationVersion(root, { logger }); try { specification = await getSpecificationByVersion(version, { logger }); logger?.debug(`Specification loaded from cache using version '${version}'`); } catch (error) { logger?.error(`Failed to load specification: ${error}`); throw new Error(`Failed to load specification: ${error}`); } return specification; } /** * Loads and return specification from project or cache. * 1. if package.json contains devDependency to specification, attempts to load from project. * 2. if not in package.json of project, attempts to load from cache. * * @param root - root path of the project/app * @param [options] - optional options * @param [options.logger] - logger instance * @returns - specification instance */ async function getSpecification(root, options) { const logger = options?.logger; try { if (await hasSpecificationDevDependency(root)) { logger?.debug(`Specification found in devDependencies of project '${root}', trying to load`); // Early return with load module from project. If it throws an error it is not handled here. return (0, module_loader_1.loadModuleFromProject)(root, '@sap/ux-specification'); } } catch { logger?.debug(`Specification not found in project '${root}', trying to load from cache`); } return await getSpecificationModule(root, { logger }); } /** * Refreshes the specification dist-tags cache. Also cleans specification modules in cache that are not required anymore. * * @param [options] - optional options, like logger * @param [options.logger] - logger instance */ async function refreshSpecificationDistTags(options) { const logger = options?.logger; try { const distTagsString = await (0, command_1.execNpmCommand)(['view', '@sap/ux-specification', 'dist-tags', '--json'], { logger }); const distTags = JSON.parse(distTagsString); await (0, file_1.writeFile)(specificationDistTagPath, JSON.stringify(distTags, null, 4)); const uniqueVersions = new Set(Object.values(distTags)); // Check if we have cached versions that are not required anymore const specificationCachePath = (0, path_1.join)(constants_1.moduleCacheRoot, '@sap/ux-specification'); const removeExistingVersions = (0, fs_1.existsSync)(specificationCachePath) ? (await (0, promises_1.readdir)(specificationCachePath, { withFileTypes: true })) .filter((d) => d.isDirectory()) .filter((d) => !uniqueVersions.has(d.name)) .map((d) => d.name) : []; // Delete cached versions that are not required anymore for (const version of removeExistingVersions) { await (0, module_loader_1.deleteModule)('@sap/ux-specification', version); logger?.debug(`Deleted unused specification module '@sap/ux-specification@${version}' from cache`); } } catch (error) { logger?.error(`Error refreshing specification dist-tags: ${error}`); } } /** * Loads and return specification from cache by version. * * @param version - version of the specification * @param [options] - optional options * @param [options.logger] - optional logger instance * @returns - specification instance */ async function getSpecificationByVersion(version, options) { const logger = options?.logger; const specification = await (0, module_loader_1.getModule)('@sap/ux-specification', version, { logger }); return specification; } /** * Converts dist-tag to version. * * @param distTag - dist-tag of the specification, like 'latest' or 'UI5-1.71' * @param [options] - optional options * @param [options.logger] - optional logger instance * @returns - version for given dist-tag */ async function convertDistTagToVersion(distTag, options) { const logger = options?.logger; if (!(0, fs_1.existsSync)(specificationDistTagPath)) { logger?.debug(`Specification dist-tags not found at '${specificationDistTagPath}'. Trying to refresh.`); await refreshSpecificationDistTags({ logger }); } const specificationDistTags = await (0, file_1.readJSON)(specificationDistTagPath); const version = specificationDistTags[distTag] ?? specificationDistTags.latest; return version; } /** * Gets the dist-tag of a project specification and returns the version from it. * * @param root - root path of the project/app * @param [options] - optional options * @param [options.logger] - optional logger instance * @returns - version of specification */ async function getSpecificationVersion(root, options) { const logger = options?.logger; const distTag = await getProjectDistTag(root, { logger }); return await convertDistTagToVersion(distTag, { logger }); } /** * Returns the path to the specification used. * Can be path to node_modules in project, or cache. * * @param root - root path of the project/app * @param [options] - optional options * @param [options.logger] - optional logger instance * @returns - path to specification */ async function getSpecificationPath(root, options) { const logger = options?.logger; const moduleName = '@sap/ux-specification'; if (await hasSpecificationDevDependency(root)) { const modulePath = await (0, module_loader_1.getModulePath)(root, moduleName); logger?.debug(`Specification root found in project '${root}'`); return modulePath.slice(0, modulePath.lastIndexOf((0, path_1.join)(moduleName)) + (0, path_1.join)(moduleName).length); } await getSpecificationModule(root, { logger }); const version = await getSpecificationVersion(root, { logger }); logger?.debug(`Specification not found in project '${root}', using path from cache with version '${version}'`); const moduleRoot = (0, path_1.join)(constants_1.moduleCacheRoot, moduleName, version); const modulePath = await (0, module_loader_1.getModulePath)(moduleRoot, moduleName); return modulePath.slice(0, modulePath.lastIndexOf((0, path_1.join)(moduleName)) + (0, path_1.join)(moduleName).length); } //# sourceMappingURL=specification.js.map