@red-hat-developer-hub/cli
Version:
CLI for developing Backstage plugins and apps
183 lines (177 loc) • 6.04 kB
JavaScript
var configLoader = require('@backstage/config-loader');
var errors = require('@backstage/errors');
var fs = require('fs-extra');
var os = require('os');
var path = require('path');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
const filterPackages = (depName) => {
if (depName.startsWith("@backstage/")) {
if (depName.startsWith("@backstage/plugin-")) {
if (depName.startsWith("@backstage/plugin-catalog-") || depName.startsWith("@backstage/plugin-permission-") || depName.startsWith("@backstage/plugin-search-") || depName.startsWith("@backstage/plugin-scaffolder-")) {
return false;
}
return true;
}
return false;
} else if (depName === "@janus-idp/cli") {
return false;
}
return true;
};
const req = typeof __non_webpack_require__ === "undefined" ? require : __non_webpack_require__;
async function collectConfigSchemas(packageName) {
const schemas = new Array();
const tsSchemaPaths = new Array();
const visitedPackageVersions = /* @__PURE__ */ new Map();
const currentDir = await fs__default.default.realpath(process.cwd());
async function processItem(item) {
let pkgPath = item.packagePath;
if (pkgPath) {
const pkgExists = await fs__default.default.pathExists(pkgPath);
if (!pkgExists) {
return;
}
} else if (item.name) {
const { name, parentPath } = item;
try {
pkgPath = req.resolve(
`${name}/package.json`,
parentPath && {
paths: [parentPath]
}
);
} catch {
}
}
if (!pkgPath) {
return;
}
const pkg = await fs__default.default.readJson(pkgPath);
let versions = visitedPackageVersions.get(pkg.name);
if (versions?.has(pkg.version)) {
return;
}
if (!versions) {
versions = /* @__PURE__ */ new Set();
visitedPackageVersions.set(pkg.name, versions);
}
versions.add(pkg.version);
const depNames = [
...Object.keys(pkg.dependencies ?? {}),
...Object.keys(pkg.devDependencies ?? {}),
...Object.keys(pkg.optionalDependencies ?? {}),
...Object.keys(pkg.peerDependencies ?? {})
];
const hasSchema = "configSchema" in pkg;
if (hasSchema) {
if (typeof pkg.configSchema === "string") {
const isJson = pkg.configSchema.endsWith(".json");
const isDts = pkg.configSchema.endsWith(".d.ts");
if (!isJson && !isDts) {
throw new Error(
`Config schema files must be .json or .d.ts, got ${pkg.configSchema}`
);
}
if (isDts) {
tsSchemaPaths.push(
path.relative(
currentDir,
path.resolve(path.dirname(pkgPath), pkg.configSchema)
)
);
} else {
const path$1 = path.resolve(path.dirname(pkgPath), pkg.configSchema);
const value = await fs__default.default.readJson(path$1);
schemas.push({
value,
path: path.relative(currentDir, path$1)
});
}
} else {
schemas.push({
value: pkg.configSchema,
path: path.relative(currentDir, pkgPath)
});
}
}
await Promise.all(
depNames.filter(filterPackages).map((depName) => processItem({ name: depName, parentPath: pkgPath }))
);
}
await processItem({
name: packageName,
packagePath: `${currentDir}/package.json`
});
const tsSchemas = await compileTsSchemas(tsSchemaPaths);
return schemas.concat(tsSchemas);
}
async function compileTsSchemas(paths) {
if (paths.length === 0) {
return [];
}
const { getProgramFromFiles, buildGenerator } = await import('typescript-json-schema');
const program = getProgramFromFiles(paths, {
incremental: false,
isolatedModules: true,
lib: ["ES5"],
// Skipping most libs speeds processing up a lot, we just need the primitive types anyway
noEmit: true,
noResolve: true,
skipLibCheck: true,
// Skipping lib checks speeds things up
skipDefaultLibCheck: true,
strict: true,
typeRoots: [],
// Do not include any additional types
types: []
});
const tsSchemas = paths.map((path$1) => {
let value;
try {
const generator = buildGenerator(
program,
// This enables the use of these tags in TSDoc comments
{
required: true,
validationKeywords: ["visibility", "deepVisibility", "deprecated"]
},
[path$1.split(path.sep).join("/")]
// Unix paths are expected for all OSes here
);
value = generator?.getSchemaForSymbol("Config");
const userSymbols = new Set(generator?.getUserSymbols());
userSymbols.delete("Config");
if (userSymbols.size !== 0) {
const names = Array.from(userSymbols).join("', '");
throw new Error(
`Invalid configuration schema in ${path$1}, additional symbol definitions are not allowed, found '${names}'`
);
}
const reffedDefs = Object.keys(generator?.ReffedDefinitions ?? {});
if (reffedDefs.length !== 0) {
const lines = reffedDefs.join(`${os.EOL} `);
throw new Error(
`Invalid configuration schema in ${path$1}, the following definitions are not supported:${os.EOL}${os.EOL} ${lines}`
);
}
} catch (error) {
errors.assertError(error);
if (error.message !== "type Config not found") {
throw error;
}
}
if (!value) {
throw new Error(`Invalid schema in ${path$1}, missing Config export`);
}
return { path: path$1, value };
});
return tsSchemas;
}
const getConfigSchema = async (packageName) => {
const schemas = await collectConfigSchemas(packageName);
return configLoader.mergeConfigSchemas(schemas.map((_) => _.value));
};
exports.getConfigSchema = getConfigSchema;
//# sourceMappingURL=collect.cjs.js.map
;