@sap-ux/project-access
Version:
Library to access SAP Fiori tools projects
164 lines • 6.51 kB
JavaScript
import { basename, dirname, join } from 'node:path';
import { UI5Config } from '@sap-ux/ui5-config';
import { DirName, FileName } from '../constants.js';
import { fileExists, findFilesByExtension, findFileUp, readFile } from '../file/index.js';
/**
* Default path mappings for each UI5 project type.
*
*/
const PATH_MAPPING_DEFAULTS = {
application: { webapp: DirName.Webapp },
library: { src: 'src', test: 'test' },
'theme-library': { src: 'src', test: 'test' },
module: {}
};
/**
* Get base directory of the project where package.json is located.
*
* @param appRoot - root to the application
* @param memFs - optional mem-fs editor instance
* @returns - base directory of the project
*/
async function getBaseDir(appRoot, memFs) {
const packageJsonPath = await findFileUp(FileName.Package, appRoot, memFs);
return packageJsonPath ? dirname(packageJsonPath) : appRoot;
}
/**
* Get path to webapp.
*
* @param appRoot - root to the application
* @param [memFs] - optional mem-fs editor instance
* @returns - path to webapp folder
*/
export async function getWebappPath(appRoot, memFs) {
let pathMappings;
try {
pathMappings = await getPathMappings(appRoot, memFs);
}
catch {
// For backward compatibility ignore errors and use default
pathMappings = {};
}
return 'webapp' in pathMappings ? pathMappings.webapp : join(appRoot, DirName.Webapp);
}
/**
* Get path mappings defined in 'ui5.yaml' depending on the project type defined in 'ui5.yaml'.
*
* @param appRoot - root to the application
* @param memFs - optional mem-fs editor instance
* @param fileName - optional name of yaml file to be read. Defaults to 'ui5.yaml'.
* @returns - path mappings
* @throws {Error} if ui5.yaml or 'type' cannot be read
* @throws {Error} if project type is not 'application', 'library', 'theme-library' or 'module'
*/
export async function getPathMappings(appRoot, memFs, fileName = FileName.Ui5Yaml) {
let ui5Config;
let configuration;
let type;
try {
ui5Config = await readUi5Yaml(appRoot, fileName, memFs);
configuration = ui5Config.getConfiguration();
type = ui5Config.getType();
}
catch {
throw new Error(`Could not read 'type' from ${fileName} in project root: ${appRoot}`);
}
if (!(type in PATH_MAPPING_DEFAULTS)) {
throw new Error(`Unsupported project type for path mappings: ${type}`);
}
const baseDir = await getBaseDir(appRoot, memFs);
// Use Record<string, string> to permit index access during the merge loop
const result = {};
const configPaths = (configuration?.paths || {});
const defaults = PATH_MAPPING_DEFAULTS[type];
for (const key in defaults) {
const value = configPaths[key] ?? defaults[key];
result[key] = join(baseDir, value);
}
// Cast the merged result to PathMappings to re-enforce strict union keys for the caller
return result;
}
/**
* Checks if UI5 config yaml file exists and returns its content.
*
* @param projectRoot - path to project root
* @param fileName - name of yaml file to be read
* @param [memFs] - optional mem-fs editor instance
* @param options - options
* @param [options.validateSchema] - optional flag to validate the schema of the yaml file
* @returns {UI5Config} UI5 config file in yaml format
* @throws {Error} if file is not found
*/
export async function readUi5Yaml(projectRoot, fileName, memFs, options) {
const ui5YamlPath = join(projectRoot, fileName);
if (await fileExists(ui5YamlPath, memFs)) {
const yamlString = await readFile(ui5YamlPath, memFs);
return await UI5Config.newInstance(yamlString, { validateSchema: options?.validateSchema });
}
throw Error(`File '${fileName}' not found in project '${projectRoot}'`);
}
/**
* Scans the project directory for ui5 configuration yaml files.
*
* @param projectRoot - path to project root, where ui5 configuration y*ml files are located
* @param [memFs] - optional mem-fs editor instance
* @returns list of valid and invalid UI5 configuration yaml file names
* @throws {Error} if an error occurs while reading files from projectRoot
*/
export async function getAllUi5YamlFileNames(projectRoot, memFs) {
try {
const yamlFilePaths = await findFilesByExtension('.yaml', projectRoot, [], memFs, true);
return yamlFilePaths.map((path) => basename(path));
}
catch (error) {
throw new Error(`There was an error reading files from the directory '${projectRoot}': ${error}`);
}
}
/**
* Retrieves the mock server configuration from the UI5 mock YAML file.
*
* @param projectRoot - Path to the project root.
* @param fileName - Name of the YAML file to read. Defaults to FileName.Ui5MockYaml.
* @returns The mock server configuration or null if not found.
* @throws {Error} If the sap-fe-mockserver middleware is not found.
*/
export async function getMockServerConfig(projectRoot, fileName = FileName.Ui5MockYaml) {
const ui5MockYamlFile = await readUi5Yaml(projectRoot, fileName);
const mockserverMiddleware = ui5MockYamlFile.findCustomMiddleware('sap-fe-mockserver');
if (!mockserverMiddleware) {
throw new Error('Could not find sap-fe-mockserver');
}
return mockserverMiddleware.configuration;
}
/**
* Retrieves the mock data path from the mock server configuration.
*
* @param projectRoot - Path to the project root.
* @param fileName - Name of the YAML file to read. Defaults to FileName.Ui5MockYaml.
* @returns The mock data path as a string. Returns an empty string if not found.
*/
export async function getMockDataPath(projectRoot, fileName = FileName.Ui5MockYaml) {
const mockServerConfig = await getMockServerConfig(projectRoot, fileName);
if (!mockServerConfig) {
return '';
}
const services = extractServices(mockServerConfig);
if (!services) {
return '';
}
const found = services.find((service) => !!service.mockdataPath);
return found?.mockdataPath ?? '';
}
/**
* Helper to extract the services array from a MockServerConfiguration.
*
* @param config - The mock server configuration object.
* @returns An array of MockServerService objects, or undefined if not found.
*/
function extractServices(config) {
if ('services' in config && config.services) {
return Array.isArray(config.services) ? config.services : [config.services];
}
return undefined;
}
//# sourceMappingURL=ui5-config.js.map