@apistudio/apim-cli
Version:
CLI for API Management Products
179 lines (164 loc) • 5.01 kB
text/typescript
import path from "path";
import fs from "fs";
import { BaseAsset } from "../../model/assets-model.js";
import { isValidAsset } from "./asset-helper.js";
import { readMultiYaml } from "../common/yaml-helper.js";
import {
readFile,
isYamlFile,
isDirectory,
isDirOrFileExists,
getSubDirectory,
normalizePath,
} from "../common/fs-helper.js";
import { showWarning, showError } from "../common/message-helper.js";
import {
DIRECTORY_DOESNT_EXIST,
ERROR_IN_SEARCH_OF_ASSET,
NO_ENTRIES_FOUND_FOR_KIND,
NO_ASSET_METADATA,
IS_FOUND_IN,
INVALID_DIRECTORY,
} from "../../constants/message-constants.js";
import { COMMA } from "../../constants/app-constants.js";
import { equalsIgnoreCase } from "../common/data-helper.js";
const searchAssetByKind = async (
kindToSearch: string,
rootDirPath: string,
projectNames: string
): Promise<Record<string, string>> => {
const projectAssetMetadata: Record<string, string[]> = {};
try {
const projects = projectNames.split(COMMA);
for (const project of projects) {
const projectDirPath = getSubDirectory(rootDirPath, project);
if (!isDirOrFileExists(projectDirPath) || !isDirectory(projectDirPath)) {
showWarning(`${DIRECTORY_DOESNT_EXIST} ${projectDirPath}`);
continue;
}
const matchingEntries = searchAssetByKindInDirectory(
kindToSearch,
projectDirPath
);
if (matchingEntries.length > 0) {
for (const entry of matchingEntries) {
const filePath = path.join(entry.parentPath, entry.name);
extractKindMetadata(
filePath,
project,
kindToSearch,
projectAssetMetadata
);
}
} else {
showWarning(
`${NO_ENTRIES_FOUND_FOR_KIND} - '${kindToSearch}' ${IS_FOUND_IN} '${projectDirPath}'`
);
}
}
return formatMetadataResult(projectAssetMetadata);
} catch (error) {
showError(
`${ERROR_IN_SEARCH_OF_ASSET} ${kindToSearch}: ${(error as Error).message}`
);
throw error;
}
};
const searchAssetByKindInDirectory = (
kindToSearch: string,
projectDirPath: string
): fs.Dirent[] => {
if (!isDirOrFileExists(projectDirPath) || !isDirectory(projectDirPath)) {
throw new Error(`${INVALID_DIRECTORY} ${projectDirPath}`);
}
try {
const entries: fs.Dirent[] = fs.readdirSync(projectDirPath, {
withFileTypes: true,
recursive: true,
});
return entries.filter((entry) => {
if (entry.isDirectory()) {
return false;
}
if (!isYamlFile(entry.name)) {
return false;
}
const assets = readMultiYaml<BaseAsset>(
normalizePath(`${entry.parentPath}/${entry.name}`),
readFile(entry.parentPath, entry.name)
);
return containsMatchingKind(assets, kindToSearch);
});
} catch (error) {
showError(
`${ERROR_IN_SEARCH_OF_ASSET} ${kindToSearch}: ${(error as Error).message}`
);
throw error;
}
};
const containsMatchingKind = (
assets: BaseAsset[],
kindToSearch: string
): boolean => {
for (const asset of assets) {
if (isValidAsset(asset) && equalsIgnoreCase(kindToSearch, asset.kind)) {
return true;
}
}
return false;
};
const extractKindMetadata = (
filePath: string,
project: string,
kindToSearch: string,
projectAssetMetadata: Record<string, string[]>
): boolean => {
try {
const fileContent = readFile(
path.dirname(filePath),
path.basename(filePath)
);
const yamlContents = readMultiYaml<BaseAsset>(filePath, fileContent);
const assetMetadata: string[] = [];
yamlContents.forEach((yamlContent) => {
if (isValidAsset(yamlContent)) {
const kind = yamlContent.kind ? yamlContent.kind.toLowerCase() : "";
if (kind === kindToSearch.toLowerCase()) {
const metadata = getMetadata(yamlContent);
assetMetadata.push(metadata);
}
}
});
if (assetMetadata.length > 0) {
if (!projectAssetMetadata[project]) {
projectAssetMetadata[project] = [];
}
projectAssetMetadata[project].push(...assetMetadata);
}
return assetMetadata.length > 0;
} catch (error) {
showError(
`${error instanceof Error ? error.message : "Unknown error"}`
);
return false;
}
};
const formatMetadataResult = (
projectAssetMetadata: Record<string, string[]>
): Record<string, string> => {
if (Object.keys(projectAssetMetadata).length === 0) {
showError(NO_ASSET_METADATA);
}
const result: Record<string, string> = {};
for (const [project, metadataArray] of Object.entries(projectAssetMetadata)) {
result[project] = metadataArray.join(COMMA);
}
return result;
};
const getMetadata = (asset: BaseAsset): string => {
const namespace = asset.metadata?.namespace || "";
const name = asset.metadata?.name || "";
const version = asset.metadata?.version || "";
return `${namespace}:${name}:${version}`;
};
export { searchAssetByKind };