'use strict';

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 _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

function _interopNamespace(e) {
  if (e && e.__esModule) return e;
  var n = Object.create(null);
  if (e) {
    Object.keys(e).forEach(function (k) {
      if (k !== 'default') {
        var d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: function () { return e[k]; }
        });
      }
    });
  }
  n["default"] = e;
  return Object.freeze(n);
}

var fs__default = /*#__PURE__*/_interopDefaultLegacy(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) {
    var _a, _b, _c, _d;
    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 == null ? void 0 : versions.has(pkg.version)) {
      return;
    }
    if (!versions) {
      versions = /* @__PURE__ */ new Set();
      visitedPackageVersions.set(pkg.name, versions);
    }
    versions.add(pkg.version);
    const depNames = [
      ...Object.keys((_a = pkg.dependencies) != null ? _a : {}),
      ...Object.keys((_b = pkg.devDependencies) != null ? _b : {}),
      ...Object.keys((_c = pkg.optionalDependencies) != null ? _c : {}),
      ...Object.keys((_d = pkg.peerDependencies) != null ? _d : {})
    ];
    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 Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('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) => {
    var _a;
    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 == null ? void 0 : generator.getSchemaForSymbol("Config");
      const userSymbols = new Set(generator == null ? void 0 : 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((_a = generator == null ? void 0 : generator.ReffedDefinitions) != null ? _a : {});
      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-c99ee3f5.cjs.js.map
