@backstage/backend-defaults
Version:
Backend defaults used by Backstage backend apps
120 lines (114 loc) • 3.92 kB
JavaScript
;
var fs = require('fs-extra');
var platformPath = require('path');
var errors = require('@backstage/errors');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
const DETECTED_PACKAGE_ROLES = [
"node-library",
"backend",
"backend-plugin",
"backend-plugin-module"
];
function isBackendFeature(value) {
return !!value && ["object", "function"].includes(typeof value) && value.$$type === "@backstage/BackendFeature";
}
function isBackendFeatureFactory(value) {
return !!value && typeof value === "function" && value.$$type === "@backstage/BackendFeatureFactory";
}
async function findClosestPackageDir(searchDir) {
let path = searchDir;
for (let i = 0; i < 1e3; i++) {
const packagePath = platformPath.resolve(path, "package.json");
const exists = await fs__default.default.pathExists(packagePath);
if (exists) {
return path;
}
const newPath = platformPath.dirname(path);
if (newPath === path) {
return void 0;
}
path = newPath;
}
throw new Error(
`Iteration limit reached when searching for root package.json at ${searchDir}`
);
}
class PackageDiscoveryService {
constructor(config, logger) {
this.config = config;
this.logger = logger;
}
getDependencyNames(path) {
const { dependencies } = require(path);
const packagesConfig = this.config.getOptional("backend.packages");
const dependencyNames = Object.keys(dependencies || {});
if (packagesConfig === "all") {
return dependencyNames;
}
const includedPackagesConfig = this.config.getOptionalStringArray(
"backend.packages.include"
);
const includedPackages = includedPackagesConfig ? new Set(includedPackagesConfig) : dependencyNames;
const excludedPackagesSet = new Set(
this.config.getOptionalStringArray("backend.packages.exclude")
);
return [...includedPackages].filter((name) => !excludedPackagesSet.has(name));
}
async getBackendFeatures() {
const packagesConfig = this.config.getOptional("backend.packages");
if (!packagesConfig || Object.keys(packagesConfig).length === 0) {
return { features: [] };
}
const packageDir = await findClosestPackageDir(process.argv[1]);
if (!packageDir) {
throw new Error("Package discovery failed to find package.json");
}
const dependencyNames = this.getDependencyNames(
platformPath.resolve(packageDir, "package.json")
);
const features = [];
for (const name of dependencyNames) {
let depPkg;
try {
const packageJsonPath = require.resolve(`${name}/package.json`, {
paths: [packageDir]
});
depPkg = require(packageJsonPath);
} catch (error) {
if (errors.isError(error) && error.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
continue;
}
throw error;
}
if (!depPkg?.backstage?.role || !DETECTED_PACKAGE_ROLES.includes(depPkg.backstage.role)) {
continue;
}
const exportedModulePaths = [
require.resolve(name, {
paths: [packageDir]
})
];
try {
exportedModulePaths.push(
require.resolve(`${name}/alpha`, { paths: [packageDir] })
);
} catch {
}
for (const modulePath of exportedModulePaths) {
const mod = require(modulePath);
if (isBackendFeature(mod.default)) {
this.logger.info(`Detected: ${name}`);
features.push(mod.default);
}
if (isBackendFeatureFactory(mod.default)) {
this.logger.info(`Detected: ${name}`);
features.push(mod.default());
}
}
}
return { features };
}
}
exports.PackageDiscoveryService = PackageDiscoveryService;
//# sourceMappingURL=PackageDiscoveryService.cjs.js.map