UNPKG

@apistudio/apim-cli

Version:

CLI for API Management Products

131 lines (113 loc) 4.51 kB
import { BaseAsset } from "@apic/studio-client-model"; import { checkForNullOrUndefined } from "../common/data-helper.js"; import AdmZip from "adm-zip"; import path from "node:path"; import fs from "node:fs"; import { showError, showInfo, showWarning } from "../common/message-helper.js"; import { AssetCacheModel } from "../../model/asset-cache-model.js"; import { APIAsset } from "../../model/assets-model.js"; const bundleApiDependency = ( asset: BaseAsset, searchResult: fs.Dirent<string>, cachedUnProcessedAsset: AssetCacheModel, rootDirPath: string, project: string, zipFile: AdmZip ) => { const sourceProjectName = cachedUnProcessedAsset.sourceProject; if (!sourceProjectName) { showError(`Source project not found for API dependency ${cachedUnProcessedAsset.ref}`); return; } // Pass the timestamp as the unique value that gets appended to project name const timeStamp = Date.now(); // Add API with project folder structure const apiRelativePath = addApiDependencyAsset( searchResult, zipFile, project, // target project name sourceProjectName, rootDirPath, timeStamp ); showInfo(`API added: ${project}/${apiRelativePath}`); // Also add the API specification resolveAndAddApiSpec( asset, zipFile, apiRelativePath, project, // target project name sourceProjectName, rootDirPath, timeStamp ); } const addApiDependencyAsset = ( file: fs.Dirent, zip: AdmZip, targetProjectName: string, sourceProjectName: string, rootDirPath: string, timeStamp: number ) => { // Calculate relative path from target project root const targetProjectPath = path.join(rootDirPath, targetProjectName); const relativePath = path.relative(targetProjectPath, path.join(file.parentPath, file.name)); // Add to zip with project folder structure nested inside source project // Result: sourceProject/targetProject/api-assets/api.yml const zipPath = path.join(sourceProjectName, `${targetProjectName}_${timeStamp}`, relativePath); zip.addLocalFile( path.join(file.parentPath, file.name), path.dirname(zipPath) ); return relativePath; }; const resolveAndAddApiSpec = ( asset: BaseAsset, zip: AdmZip, apiFileRelativePath: string, targetProjectName: string, sourceProjectName: string, rootDirPath: string, timeStamp: number ) => { const apiAsset = asset as unknown as APIAsset; const spec = checkForNullOrUndefined( apiAsset.spec, `Spec is not defined for the asset with kind 'API' and name '${apiAsset.metadata?.name}'` ); const apiSpec = checkForNullOrUndefined( spec["api-spec"], `Attribute 'api-spec' is not defined for kind 'API' and name '${apiAsset.metadata?.name}'` ); const apiSpecPath = checkForNullOrUndefined( apiSpec.$path, `API Definition Path is not found for ${asset}` ); // Get the directory where the API file is located const apiFileDir = path.dirname(apiFileRelativePath); // Resolve api spec path relative to project folder by default let resolvedSpecPath = apiSpecPath; if (apiSpecPath.startsWith('../') || apiSpecPath.startsWith('./')) { // Resolve relative path from API file's directory // Example: apiFileDir = "api-assets", apiSpecPath = "../specs/petstore.yaml" // Result: "specs/petstore.yaml" const specPathFromProjectRoot = path.join(apiFileDir, apiSpecPath); resolvedSpecPath = path.normalize(specPathFromProjectRoot); } // Build absolute file system path for reading the spec const absoluteSpecPath = path.join(rootDirPath, targetProjectName, resolvedSpecPath); if (!fs.existsSync(absoluteSpecPath)) { showWarning( `API spec not found: ${absoluteSpecPath} for API ${apiAsset.metadata?.namespace}:${apiAsset.metadata?.name}:${apiAsset.metadata.version}` ); return; } // Build zip path using the relative spec path from API // apiSpecPath is already relative (e.g., "specs/petstore.yaml") const zipSpecPath = path.join(sourceProjectName, `${targetProjectName}_${timeStamp}`, resolvedSpecPath); zip.addLocalFile(absoluteSpecPath, path.dirname(zipSpecPath)); showInfo(`Spec added: ${zipSpecPath}`); }; export { bundleApiDependency, addApiDependencyAsset, resolveAndAddApiSpec }