@backstage/config-loader 1.11.0 → 1.11.2-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @backstage/config-loader
2
2
 
3
+ ## 1.11.2-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 0c67dbc: Fix issue where `backstage-cli config:check --strict` would incorrectly reject valid configuration for open-ended object schemas, such as plain objects or map-like structures.
8
+ - bb98419: Added an `onSchemaError` callback that allows callers to report TypeScript configuration schema errors and continue loading. The callback receives a `ConfigSchemaError` containing the source package and underlying cause. Without a handler, schema errors are thrown.
9
+
3
10
  ## 1.11.0
4
11
 
5
12
  ### Minor Changes
package/dist/index.cjs.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var compile = require('./schema/compile.cjs.js');
4
4
  var load = require('./schema/load.cjs.js');
5
+ var ConfigSchemaError = require('./schema/ConfigSchemaError.cjs.js');
5
6
  var loader = require('./loader.cjs.js');
6
7
  var ConfigSources = require('./sources/ConfigSources.cjs.js');
7
8
  var EnvConfigSource = require('./sources/EnvConfigSource.cjs.js');
@@ -14,6 +15,7 @@ var StaticConfigSource = require('./sources/StaticConfigSource.cjs.js');
14
15
 
15
16
  exports.mergeConfigSchemas = compile.mergeConfigSchemas;
16
17
  exports.loadConfigSchema = load.loadConfigSchema;
18
+ exports.ConfigSchemaError = ConfigSchemaError.ConfigSchemaError;
17
19
  exports.loadConfig = loader.loadConfig;
18
20
  exports.ConfigSources = ConfigSources.ConfigSources;
19
21
  exports.EnvConfigSource = EnvConfigSource.EnvConfigSource;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -81,12 +81,29 @@ type ConfigSchema = {
81
81
  */
82
82
  declare function mergeConfigSchemas(schemas: JSONSchema7[]): JSONSchema7;
83
83
 
84
+ /**
85
+ * An error encountered while loading a TypeScript configuration schema.
86
+ *
87
+ * @public
88
+ */
89
+ declare class ConfigSchemaError extends Error {
90
+ name: "ConfigSchemaError";
91
+ /** The package that provided the configuration schema. */
92
+ readonly source: string;
93
+ /** The underlying error that caused schema loading to fail. */
94
+ readonly cause: Error;
95
+ constructor(options: {
96
+ source: string;
97
+ cause: Error;
98
+ });
99
+ }
100
+
84
101
  /**
85
102
  * Options that control the loading of configuration schema files in the backend.
86
103
  *
87
104
  * @public
88
105
  */
89
- type LoadConfigSchemaOptions = ({
106
+ type LoadConfigSchemaOptions = (({
90
107
  dependencies: string[];
91
108
  packagePaths?: string[];
92
109
  /**
@@ -95,11 +112,20 @@ type LoadConfigSchemaOptions = ({
95
112
  * Defaults to `false`.
96
113
  */
97
114
  excludePackageDependencies?: boolean;
115
+ /**
116
+ * Receives `ConfigSchemaError` instances and allows TypeScript schema
117
+ * loading to continue. Unresolved types are treated as unconstrained
118
+ * values, while schemas that cannot be generated are omitted.
119
+ *
120
+ * Without this callback, TypeScript configuration schema errors are
121
+ * thrown.
122
+ */
123
+ onSchemaError?: (error: ConfigSchemaError) => void;
98
124
  } | {
99
125
  serialized: JsonObject;
100
126
  }) & {
101
127
  noUndeclaredProperties?: boolean;
102
- };
128
+ });
103
129
  /**
104
130
  * Loads config schema for a Backstage instance.
105
131
  *
@@ -641,5 +667,5 @@ declare class StaticConfigSource implements ConfigSource {
641
667
  toString(): string;
642
668
  }
643
669
 
644
- export { ConfigSources, EnvConfigSource, FileConfigSource, MutableConfigSource, RemoteConfigSource, StaticConfigSource, loadConfig, loadConfigSchema, mergeConfigSchemas, readEnvConfig };
670
+ export { ConfigSchemaError, ConfigSources, EnvConfigSource, FileConfigSource, MutableConfigSource, RemoteConfigSource, StaticConfigSource, loadConfig, loadConfigSchema, mergeConfigSchemas, readEnvConfig };
645
671
  export type { AsyncConfigSourceGenerator, BaseConfigSourcesOptions, ClosableConfig, ConfigSchema, ConfigSchemaProcessingOptions, ConfigSource, ConfigSourceData, ConfigSourceTarget, ConfigSourcesDefaultForTargetsOptions, ConfigSourcesDefaultOptions, ConfigTarget, ConfigVisibility, EnvConfigSourceOptions, SubstitutionFunc as EnvFunc, FileConfigSourceOptions, LoadConfigOptions, LoadConfigOptionsRemote, LoadConfigOptionsWatch, LoadConfigResult, LoadConfigSchemaOptions, MutableConfigSourceOptions, Parser, ReadConfigDataOptions, RemoteConfigSourceOptions, StaticConfigSourceOptions, TransformFunc };
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ class ConfigSchemaError extends Error {
4
+ name = "ConfigSchemaError";
5
+ /** The package that provided the configuration schema. */
6
+ source;
7
+ constructor(options) {
8
+ const { source, cause } = options;
9
+ const causeMessage = cause.message.replace(/\s*\r?\n\s*/g, " ").trim();
10
+ super(
11
+ `The TypeScript configuration schema for package '${source}' contains an error - ${causeMessage}`,
12
+ { cause }
13
+ );
14
+ this.source = source;
15
+ this.cause = cause;
16
+ Error.captureStackTrace?.(this, this.constructor);
17
+ }
18
+ }
19
+
20
+ exports.ConfigSchemaError = ConfigSchemaError;
21
+ //# sourceMappingURL=ConfigSchemaError.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigSchemaError.cjs.js","sources":["../../src/schema/ConfigSchemaError.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * An error encountered while loading a TypeScript configuration schema.\n *\n * @public\n */\nexport class ConfigSchemaError extends Error {\n name = 'ConfigSchemaError' as const;\n\n /** The package that provided the configuration schema. */\n readonly source: string;\n\n /** The underlying error that caused schema loading to fail. */\n declare readonly cause: Error;\n\n constructor(options: { source: string; cause: Error }) {\n const { source, cause } = options;\n const causeMessage = cause.message.replace(/\\s*\\r?\\n\\s*/g, ' ').trim();\n super(\n `The TypeScript configuration schema for package '${source}' contains an error - ${causeMessage}`,\n { cause },\n );\n\n this.source = source;\n this.cause = cause;\n Error.captureStackTrace?.(this, this.constructor);\n }\n}\n"],"names":[],"mappings":";;AAqBO,MAAM,0BAA0B,KAAA,CAAM;AAAA,EAC3C,IAAA,GAAO,mBAAA;AAAA;AAAA,EAGE,MAAA;AAAA,EAKT,YAAY,OAAA,EAA2C;AACrD,IAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAM,GAAI,OAAA;AAC1B,IAAA,MAAM,eAAe,KAAA,CAAM,OAAA,CAAQ,QAAQ,cAAA,EAAgB,GAAG,EAAE,IAAA,EAAK;AACrE,IAAA,KAAA;AAAA,MACE,CAAA,iDAAA,EAAoD,MAAM,CAAA,sBAAA,EAAyB,YAAY,CAAA,CAAA;AAAA,MAC/F,EAAE,KAAA;AAAM,KACV;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,KAAA,CAAM,iBAAA,GAAoB,IAAA,EAAM,IAAA,CAAK,WAAW,CAAA;AAAA,EAClD;AACF;;;;"}
@@ -1,8 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var fs = require('fs-extra');
4
+ var errors = require('@backstage/errors');
4
5
  var node_crypto = require('node:crypto');
5
6
  var node_path = require('node:path');
7
+ var ConfigSchemaError = require('./ConfigSchemaError.cjs.js');
6
8
 
7
9
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
8
10
 
@@ -106,7 +108,7 @@ async function collectConfigSchemas(packageNames, packagePaths, options) {
106
108
  ...packageNames.map((name) => processItem({ name, parentPath: currentDir })),
107
109
  ...packagePaths.map((path) => processItem({ name: path, packagePath: path }))
108
110
  ]);
109
- const tsSchemas = await compileTsSchemas(tsSchemaPaths);
111
+ const tsSchemas = await compileTsSchemas(tsSchemaPaths, options);
110
112
  const allSchemas = schemas.concat(tsSchemas);
111
113
  const hasBackendDefaults = allSchemas.some(
112
114
  ({ packageName }) => packageName === "@backstage/backend-defaults"
@@ -173,13 +175,20 @@ function parseNestedSchemaAnnotation(annotation) {
173
175
  }
174
176
  return { key, value };
175
177
  }
176
- async function compileTsSchemas(entries) {
178
+ function handleSchemaError(options, error) {
179
+ if (!options?.onSchemaError) {
180
+ throw error;
181
+ }
182
+ options.onSchemaError(error);
183
+ }
184
+ async function compileTsSchemas(entries, options) {
177
185
  if (entries.length === 0) {
178
186
  return [];
179
187
  }
180
188
  const ts = require("typescript");
181
189
  const {
182
190
  AnnotatedTypeFormatter,
191
+ AnyType,
183
192
  createFormatter,
184
193
  createParser,
185
194
  DEFAULT_CONFIG,
@@ -201,26 +210,36 @@ async function compileTsSchemas(entries) {
201
210
  types: []
202
211
  };
203
212
  const program = ts.createProgram(rootNames, compilerOptions);
204
- const diagnostics = [
213
+ const sharedDiagnostics = [
205
214
  ...program.getOptionsDiagnostics(),
206
- ...program.getGlobalDiagnostics(),
207
- ...rootNames.flatMap((rootName) => {
208
- const sourceFile = program.getSourceFile(rootName);
209
- return sourceFile ? [
215
+ ...program.getGlobalDiagnostics()
216
+ ];
217
+ entries.forEach(({ packageName }, index) => {
218
+ const sourceFile = program.getSourceFile(rootNames[index]);
219
+ const diagnostics = [
220
+ ...index === 0 ? sharedDiagnostics : [],
221
+ ...sourceFile ? [
210
222
  ...program.getSyntacticDiagnostics(sourceFile),
211
223
  ...program.getSemanticDiagnostics(sourceFile)
212
- ] : [];
213
- })
214
- ];
215
- if (diagnostics.length > 0) {
216
- const message = ts.formatDiagnostics(diagnostics, {
217
- getCanonicalFileName: (fileName) => fileName,
218
- getCurrentDirectory: () => currentDir,
219
- getNewLine: () => "\n"
220
- });
221
- throw new Error(`Invalid TypeScript configuration schema:
222
- ${message}`);
223
- }
224
+ ] : []
225
+ ];
226
+ if (diagnostics.length === 0) {
227
+ return;
228
+ }
229
+ for (const diagnostic of diagnostics) {
230
+ const cause = new Error(
231
+ ts.formatDiagnostics([diagnostic], {
232
+ getCanonicalFileName: (fileName) => fileName,
233
+ getCurrentDirectory: () => currentDir,
234
+ getNewLine: () => "\n"
235
+ }).trimEnd()
236
+ );
237
+ handleSchemaError(
238
+ options,
239
+ new ConfigSchemaError.ConfigSchemaError({ source: packageName, cause })
240
+ );
241
+ }
242
+ });
224
243
  const generatorConfig = {
225
244
  ...DEFAULT_CONFIG,
226
245
  additionalProperties: true,
@@ -231,7 +250,24 @@ ${message}`);
231
250
  topRef: false,
232
251
  tsProgram: program
233
252
  };
234
- const parser = createParser(program, generatorConfig);
253
+ const typeChecker = program.getTypeChecker();
254
+ const parser = createParser(program, generatorConfig, (mutableParser) => {
255
+ if (!options?.onSchemaError) {
256
+ return;
257
+ }
258
+ mutableParser.addNodeParser({
259
+ supportsNode(node) {
260
+ if (!ts.isTypeReferenceNode(node)) {
261
+ return false;
262
+ }
263
+ const symbol = typeChecker.getSymbolAtLocation(node.typeName);
264
+ return !symbol?.declarations?.length;
265
+ },
266
+ createType() {
267
+ return new AnyType();
268
+ }
269
+ });
270
+ });
235
271
  class NestedAnnotationsFormatter extends AnnotatedTypeFormatter {
236
272
  getDefinition(type) {
237
273
  const annotations = type.getAnnotations();
@@ -267,25 +303,40 @@ ${message}`);
267
303
  formatter,
268
304
  generatorConfig
269
305
  );
270
- const tsSchemas = entries.map(({ path, packageName }, index) => {
306
+ const tsSchemas = entries.flatMap(({ path, packageName }, index) => {
271
307
  const sourceFile = program.getSourceFile(rootNames[index]);
272
308
  if (!sourceFile) {
273
- throw new Error(`Invalid schema in ${path}, missing Config export`);
309
+ throw new ConfigSchemaError.ConfigSchemaError({
310
+ source: packageName,
311
+ cause: new Error("The schema source file could not be loaded")
312
+ });
274
313
  }
275
314
  const configNode = sourceFile.statements.find(
276
315
  (statement) => (ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement)) && statement.name.text === "Config"
277
316
  );
278
317
  if (!configNode) {
279
- throw new Error(`Invalid schema in ${path}, missing Config export`);
318
+ throw new ConfigSchemaError.ConfigSchemaError({
319
+ source: packageName,
320
+ cause: new Error("The schema does not export a Config type")
321
+ });
280
322
  }
281
323
  const namespace = node_crypto.createHash("sha256").update(packageName).update("\0").update(path.split(node_path.sep).join("/")).digest("hex");
282
- const value = namespaceSchemaDefinitions(
283
- structuredClone(
284
- generator.createSchemaFromNodes([configNode])
285
- ),
286
- namespace
287
- );
288
- return { path, value, packageName };
324
+ try {
325
+ const value = namespaceSchemaDefinitions(
326
+ structuredClone(
327
+ generator.createSchemaFromNodes([configNode])
328
+ ),
329
+ namespace
330
+ );
331
+ return [{ path, value, packageName }];
332
+ } catch (error) {
333
+ const cause = errors.toError(error);
334
+ handleSchemaError(
335
+ options,
336
+ new ConfigSchemaError.ConfigSchemaError({ source: packageName, cause })
337
+ );
338
+ return [];
339
+ }
289
340
  });
290
341
  return tsSchemas;
291
342
  }
@@ -1 +1 @@
1
- {"version":3,"file":"collect.cjs.js","sources":["../../src/schema/collect.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport type * as TsJsonSchemaGenerator from 'ts-json-schema-generator';\nimport type * as TypeScript from 'typescript';\nimport { createHash } from 'node:crypto';\nimport {\n resolve as resolvePath,\n relative as relativePath,\n dirname,\n sep,\n} from 'node:path';\nimport { ConfigSchemaPackageEntry } from './types';\nimport type { JsonObject } from '@backstage/types';\n\ntype Item = {\n name?: string;\n parentPath?: string;\n packagePath?: string;\n};\n\nconst req =\n typeof __non_webpack_require__ === 'undefined'\n ? require\n : __non_webpack_require__;\n\n/**\n * Exported for test mocking. Jest 30's module resolver has issues with\n * nested node_modules, requiring tests to use an alternative resolution strategy.\n * @internal\n */\nexport const internal = {\n resolvePackagePath(name: string, options?: { paths: string[] }): string {\n return req.resolve(name, options);\n },\n};\n\n/**\n * This collects all known config schemas across all dependencies of the app.\n */\nexport async function collectConfigSchemas(\n packageNames: string[],\n packagePaths: string[],\n options?: { excludePackageDependencies?: boolean },\n): Promise<ConfigSchemaPackageEntry[]> {\n const schemas = new Array<ConfigSchemaPackageEntry>();\n const tsSchemaPaths = new Array<{ packageName: string; path: string }>();\n const visitedPackageVersions = new Map<string, Set<string>>(); // pkgName: [versions...]\n\n const currentDir = await fs.realpath(process.cwd());\n\n async function processItem(item: Item) {\n let pkgPath = item.packagePath;\n\n if (pkgPath) {\n const pkgExists = await fs.pathExists(pkgPath);\n if (!pkgExists) {\n return;\n }\n } else if (item.name) {\n const { name, parentPath } = item;\n\n try {\n pkgPath = internal.resolvePackagePath(\n `${name}/package.json`,\n parentPath ? { paths: [parentPath] } : undefined,\n );\n } catch {\n // We can somewhat safely ignore packages that don't export package.json,\n // as they are likely not part of the Backstage ecosystem anyway.\n }\n }\n if (!pkgPath) {\n return;\n }\n\n const pkg = await fs.readJson(pkgPath);\n\n // Ensures that we only process the same version of each package once.\n let versions = visitedPackageVersions.get(pkg.name);\n if (versions?.has(pkg.version)) {\n return;\n }\n if (!versions) {\n versions = new Set();\n visitedPackageVersions.set(pkg.name, versions);\n }\n versions.add(pkg.version);\n\n const depNames = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ...Object.keys(pkg.optionalDependencies ?? {}),\n ...Object.keys(pkg.peerDependencies ?? {}),\n ];\n\n // TODO(Rugvip): Trying this out to avoid having to traverse the full dependency graph,\n // since that's pretty slow. We probably need a better way to determine when\n // we've left the Backstage ecosystem, but this will do for now.\n const hasSchema = 'configSchema' in pkg;\n const hasBackstageDep = depNames.some(_ => _.startsWith('@backstage/'));\n if (!hasSchema && !hasBackstageDep) {\n return;\n }\n if (hasSchema) {\n if (typeof pkg.configSchema === 'string') {\n const isJson = pkg.configSchema.endsWith('.json');\n const isDts = pkg.configSchema.endsWith('.d.ts');\n if (!isJson && !isDts) {\n throw new Error(\n `Config schema files must be .json or .d.ts, got ${pkg.configSchema}`,\n );\n }\n if (isDts) {\n tsSchemaPaths.push({\n path: relativePath(\n currentDir,\n resolvePath(dirname(pkgPath), pkg.configSchema),\n ),\n packageName: pkg.name,\n });\n } else {\n const path = resolvePath(dirname(pkgPath), pkg.configSchema);\n const value = await fs.readJson(path);\n schemas.push({\n packageName: pkg.name,\n value,\n path: relativePath(currentDir, path),\n });\n }\n } else {\n schemas.push({\n packageName: pkg.name,\n value: pkg.configSchema,\n path: relativePath(currentDir, pkgPath),\n });\n }\n }\n\n if (!options?.excludePackageDependencies) {\n await Promise.all(\n depNames.map(depName =>\n processItem({ name: depName, parentPath: pkgPath }),\n ),\n );\n }\n }\n\n await Promise.all([\n ...packageNames.map(name => processItem({ name, parentPath: currentDir })),\n ...packagePaths.map(path => processItem({ name: path, packagePath: path })),\n ]);\n\n const tsSchemas = await compileTsSchemas(tsSchemaPaths);\n const allSchemas = schemas.concat(tsSchemas);\n\n const hasBackendDefaults = allSchemas.some(\n ({ packageName }) => packageName === '@backstage/backend-defaults',\n );\n\n if (hasBackendDefaults) {\n // We filter out backend-common schemas here to avoid issues with\n // schema merging over different versions of the same schema.\n // led to issues such as https://github.com/backstage/backstage/issues/28170\n return allSchemas.filter(\n ({ packageName }) => packageName !== '@backstage/backend-common',\n );\n }\n\n return allSchemas;\n}\n\nfunction namespaceSchemaDefinitions(\n schema: JsonObject,\n namespace: string,\n): JsonObject {\n const definitions = schema.definitions;\n if (\n !definitions ||\n typeof definitions !== 'object' ||\n Array.isArray(definitions) ||\n Object.keys(definitions).length === 0\n ) {\n delete schema.definitions;\n return schema;\n }\n\n const renamedDefinitions = Object.fromEntries(\n Object.entries(definitions).map(([name, definition]) => [\n `${namespace}-${name}`,\n definition,\n ]),\n );\n const renamedRefs = new Map<string, string>();\n for (const name of Object.keys(definitions)) {\n const renamed = `${namespace}-${name}`;\n renamedRefs.set(`#/definitions/${name}`, `#/definitions/${renamed}`);\n renamedRefs.set(\n `#/definitions/${encodeURIComponent(name)}`,\n `#/definitions/${encodeURIComponent(renamed)}`,\n );\n }\n\n function rewriteRefs(value: unknown): void {\n if (Array.isArray(value)) {\n value.forEach(rewriteRefs);\n return;\n }\n if (!value || typeof value !== 'object') {\n return;\n }\n\n const object = value as Record<string, unknown>;\n if (typeof object.$ref === 'string') {\n object.$ref = renamedRefs.get(object.$ref) ?? object.$ref;\n }\n Object.values(object).forEach(rewriteRefs);\n }\n\n schema.definitions = renamedDefinitions;\n rewriteRefs(schema);\n return schema;\n}\n\nfunction parseNestedSchemaAnnotation(annotation: unknown) {\n if (typeof annotation !== 'string') {\n return undefined;\n }\n\n const match = annotation.match(/^\\.([\\w-]+)\\s+([\\s\\S]+)$/);\n if (!match) {\n return undefined;\n }\n\n const [, key, text] = match;\n let value: unknown = text.trim();\n try {\n value = JSON.parse(value as string);\n } catch {\n // Plain strings such as visibility values are not JSON encoded.\n }\n return { key, value };\n}\n\n// This handles the support of TypeScript .d.ts config schema declarations.\n// We collect all TypeScript schema definitions and compile them in one shared\n// program, which avoids repeatedly resolving and parsing imported types.\nasync function compileTsSchemas(\n entries: { path: string; packageName: string }[],\n) {\n if (entries.length === 0) {\n return [];\n }\n\n // Lazy loaded, because these bring up all of TypeScript and we don't want\n // that eagerly loaded when collecting JSON schemas.\n const ts: typeof TypeScript = require('typescript');\n const {\n AnnotatedTypeFormatter,\n createFormatter,\n createParser,\n DEFAULT_CONFIG,\n SchemaGenerator,\n }: typeof TsJsonSchemaGenerator = require('ts-json-schema-generator');\n\n const currentDir = process.cwd();\n const rootNames = entries.map(({ path }) => resolvePath(currentDir, path));\n const compilerOptions: TypeScript.CompilerOptions = {\n incremental: false,\n jsx: ts.JsxEmit.Preserve,\n module: ts.ModuleKind.ESNext,\n moduleResolution: ts.ModuleResolutionKind.Bundler,\n noEmit: true,\n noResolve: false,\n skipDefaultLibCheck: true,\n skipLibCheck: false,\n strict: true,\n target: ts.ScriptTarget.ES2022,\n types: [],\n };\n\n const program = ts.createProgram(rootNames, compilerOptions);\n const diagnostics = [\n ...program.getOptionsDiagnostics(),\n ...program.getGlobalDiagnostics(),\n ...rootNames.flatMap(rootName => {\n const sourceFile = program.getSourceFile(rootName);\n return sourceFile\n ? [\n ...program.getSyntacticDiagnostics(sourceFile),\n ...program.getSemanticDiagnostics(sourceFile),\n ]\n : [];\n }),\n ];\n if (diagnostics.length > 0) {\n const message = ts.formatDiagnostics(diagnostics, {\n getCanonicalFileName: fileName => fileName,\n getCurrentDirectory: () => currentDir,\n getNewLine: () => '\\n',\n });\n throw new Error(`Invalid TypeScript configuration schema:\\n${message}`);\n }\n\n const generatorConfig = {\n ...DEFAULT_CONFIG,\n additionalProperties: true,\n expose: 'none' as const,\n extraTags: ['visibility', 'deepVisibility', 'deprecated', 'items'],\n jsDoc: 'extended' as const,\n skipTypeCheck: true,\n topRef: false,\n tsProgram: program,\n };\n const parser = createParser(program, generatorConfig);\n class NestedAnnotationsFormatter extends AnnotatedTypeFormatter {\n override getDefinition(type: TsJsonSchemaGenerator.AnnotatedType) {\n const annotations = type.getAnnotations();\n const itemsAnnotation = annotations.items;\n const nestedItems = parseNestedSchemaAnnotation(itemsAnnotation);\n if (!nestedItems) {\n return super.getDefinition(type);\n }\n\n delete annotations.items;\n try {\n const definition = super.getDefinition(type);\n const items = definition.items;\n if (items && typeof items === 'object' && !Array.isArray(items)) {\n Object.assign(items, { [nestedItems.key]: nestedItems.value });\n }\n return definition;\n } finally {\n annotations.items = itemsAnnotation;\n }\n }\n }\n const formatter = createFormatter(\n generatorConfig,\n (chainFormatter, circularReferenceFormatter) => {\n chainFormatter.addTypeFormatter(\n new NestedAnnotationsFormatter(circularReferenceFormatter),\n );\n },\n );\n const generator = new SchemaGenerator(\n program,\n parser,\n formatter,\n generatorConfig,\n );\n\n const tsSchemas = entries.map(({ path, packageName }, index) => {\n const sourceFile = program.getSourceFile(rootNames[index]);\n if (!sourceFile) {\n throw new Error(`Invalid schema in ${path}, missing Config export`);\n }\n const configNode = sourceFile.statements.find(\n statement =>\n (ts.isInterfaceDeclaration(statement) ||\n ts.isTypeAliasDeclaration(statement)) &&\n statement.name.text === 'Config',\n );\n if (!configNode) {\n throw new Error(`Invalid schema in ${path}, missing Config export`);\n }\n\n const namespace = createHash('sha256')\n .update(packageName)\n .update('\\0')\n .update(path.split(sep).join('/'))\n .digest('hex');\n const value = namespaceSchemaDefinitions(\n structuredClone(\n generator.createSchemaFromNodes([configNode]),\n ) as JsonObject,\n namespace,\n );\n\n return { path, value, packageName };\n });\n\n return tsSchemas;\n}\n"],"names":["fs","relativePath","resolvePath","dirname","createHash","sep"],"mappings":"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"}
1
+ {"version":3,"file":"collect.cjs.js","sources":["../../src/schema/collect.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { toError } from '@backstage/errors';\nimport type * as TsJsonSchemaGenerator from 'ts-json-schema-generator';\nimport type * as TypeScript from 'typescript';\nimport { createHash } from 'node:crypto';\nimport {\n resolve as resolvePath,\n relative as relativePath,\n dirname,\n sep,\n} from 'node:path';\nimport { ConfigSchemaPackageEntry } from './types';\nimport type { JsonObject } from '@backstage/types';\nimport { ConfigSchemaError } from './ConfigSchemaError';\n\ntype Item = {\n name?: string;\n parentPath?: string;\n packagePath?: string;\n};\n\ntype CollectConfigSchemasOptions = {\n excludePackageDependencies?: boolean;\n onSchemaError?: (error: ConfigSchemaError) => void;\n};\n\nconst req =\n typeof __non_webpack_require__ === 'undefined'\n ? require\n : __non_webpack_require__;\n\n/**\n * Exported for test mocking. Jest 30's module resolver has issues with\n * nested node_modules, requiring tests to use an alternative resolution strategy.\n * @internal\n */\nexport const internal = {\n resolvePackagePath(name: string, options?: { paths: string[] }): string {\n return req.resolve(name, options);\n },\n};\n\n/**\n * This collects all known config schemas across all dependencies of the app.\n */\nexport async function collectConfigSchemas(\n packageNames: string[],\n packagePaths: string[],\n options?: CollectConfigSchemasOptions,\n): Promise<ConfigSchemaPackageEntry[]> {\n const schemas = new Array<ConfigSchemaPackageEntry>();\n const tsSchemaPaths = new Array<{ packageName: string; path: string }>();\n const visitedPackageVersions = new Map<string, Set<string>>(); // pkgName: [versions...]\n\n const currentDir = await fs.realpath(process.cwd());\n\n async function processItem(item: Item) {\n let pkgPath = item.packagePath;\n\n if (pkgPath) {\n const pkgExists = await fs.pathExists(pkgPath);\n if (!pkgExists) {\n return;\n }\n } else if (item.name) {\n const { name, parentPath } = item;\n\n try {\n pkgPath = internal.resolvePackagePath(\n `${name}/package.json`,\n parentPath ? { paths: [parentPath] } : undefined,\n );\n } catch {\n // We can somewhat safely ignore packages that don't export package.json,\n // as they are likely not part of the Backstage ecosystem anyway.\n }\n }\n if (!pkgPath) {\n return;\n }\n\n const pkg = await fs.readJson(pkgPath);\n\n // Ensures that we only process the same version of each package once.\n let versions = visitedPackageVersions.get(pkg.name);\n if (versions?.has(pkg.version)) {\n return;\n }\n if (!versions) {\n versions = new Set();\n visitedPackageVersions.set(pkg.name, versions);\n }\n versions.add(pkg.version);\n\n const depNames = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ...Object.keys(pkg.optionalDependencies ?? {}),\n ...Object.keys(pkg.peerDependencies ?? {}),\n ];\n\n // TODO(Rugvip): Trying this out to avoid having to traverse the full dependency graph,\n // since that's pretty slow. We probably need a better way to determine when\n // we've left the Backstage ecosystem, but this will do for now.\n const hasSchema = 'configSchema' in pkg;\n const hasBackstageDep = depNames.some(_ => _.startsWith('@backstage/'));\n if (!hasSchema && !hasBackstageDep) {\n return;\n }\n if (hasSchema) {\n if (typeof pkg.configSchema === 'string') {\n const isJson = pkg.configSchema.endsWith('.json');\n const isDts = pkg.configSchema.endsWith('.d.ts');\n if (!isJson && !isDts) {\n throw new Error(\n `Config schema files must be .json or .d.ts, got ${pkg.configSchema}`,\n );\n }\n if (isDts) {\n tsSchemaPaths.push({\n path: relativePath(\n currentDir,\n resolvePath(dirname(pkgPath), pkg.configSchema),\n ),\n packageName: pkg.name,\n });\n } else {\n const path = resolvePath(dirname(pkgPath), pkg.configSchema);\n const value = await fs.readJson(path);\n schemas.push({\n packageName: pkg.name,\n value,\n path: relativePath(currentDir, path),\n });\n }\n } else {\n schemas.push({\n packageName: pkg.name,\n value: pkg.configSchema,\n path: relativePath(currentDir, pkgPath),\n });\n }\n }\n\n if (!options?.excludePackageDependencies) {\n await Promise.all(\n depNames.map(depName =>\n processItem({ name: depName, parentPath: pkgPath }),\n ),\n );\n }\n }\n\n await Promise.all([\n ...packageNames.map(name => processItem({ name, parentPath: currentDir })),\n ...packagePaths.map(path => processItem({ name: path, packagePath: path })),\n ]);\n\n const tsSchemas = await compileTsSchemas(tsSchemaPaths, options);\n const allSchemas = schemas.concat(tsSchemas);\n\n const hasBackendDefaults = allSchemas.some(\n ({ packageName }) => packageName === '@backstage/backend-defaults',\n );\n\n if (hasBackendDefaults) {\n // We filter out backend-common schemas here to avoid issues with\n // schema merging over different versions of the same schema.\n // led to issues such as https://github.com/backstage/backstage/issues/28170\n return allSchemas.filter(\n ({ packageName }) => packageName !== '@backstage/backend-common',\n );\n }\n\n return allSchemas;\n}\n\nfunction namespaceSchemaDefinitions(\n schema: JsonObject,\n namespace: string,\n): JsonObject {\n const definitions = schema.definitions;\n if (\n !definitions ||\n typeof definitions !== 'object' ||\n Array.isArray(definitions) ||\n Object.keys(definitions).length === 0\n ) {\n delete schema.definitions;\n return schema;\n }\n\n const renamedDefinitions = Object.fromEntries(\n Object.entries(definitions).map(([name, definition]) => [\n `${namespace}-${name}`,\n definition,\n ]),\n );\n const renamedRefs = new Map<string, string>();\n for (const name of Object.keys(definitions)) {\n const renamed = `${namespace}-${name}`;\n renamedRefs.set(`#/definitions/${name}`, `#/definitions/${renamed}`);\n renamedRefs.set(\n `#/definitions/${encodeURIComponent(name)}`,\n `#/definitions/${encodeURIComponent(renamed)}`,\n );\n }\n\n function rewriteRefs(value: unknown): void {\n if (Array.isArray(value)) {\n value.forEach(rewriteRefs);\n return;\n }\n if (!value || typeof value !== 'object') {\n return;\n }\n\n const object = value as Record<string, unknown>;\n if (typeof object.$ref === 'string') {\n object.$ref = renamedRefs.get(object.$ref) ?? object.$ref;\n }\n Object.values(object).forEach(rewriteRefs);\n }\n\n schema.definitions = renamedDefinitions;\n rewriteRefs(schema);\n return schema;\n}\n\nfunction parseNestedSchemaAnnotation(annotation: unknown) {\n if (typeof annotation !== 'string') {\n return undefined;\n }\n\n const match = annotation.match(/^\\.([\\w-]+)\\s+([\\s\\S]+)$/);\n if (!match) {\n return undefined;\n }\n\n const [, key, text] = match;\n let value: unknown = text.trim();\n try {\n value = JSON.parse(value as string);\n } catch {\n // Plain strings such as visibility values are not JSON encoded.\n }\n return { key, value };\n}\n\nfunction handleSchemaError(\n options: CollectConfigSchemasOptions | undefined,\n error: ConfigSchemaError,\n) {\n if (!options?.onSchemaError) {\n throw error;\n }\n options.onSchemaError(error);\n}\n\n// This handles the support of TypeScript .d.ts config schema declarations.\n// We collect all TypeScript schema definitions and compile them in one shared\n// program, which avoids repeatedly resolving and parsing imported types.\nasync function compileTsSchemas(\n entries: { path: string; packageName: string }[],\n options?: CollectConfigSchemasOptions,\n) {\n if (entries.length === 0) {\n return [];\n }\n\n // Lazy loaded, because these bring up all of TypeScript and we don't want\n // that eagerly loaded when collecting JSON schemas.\n const ts: typeof TypeScript = require('typescript');\n const {\n AnnotatedTypeFormatter,\n AnyType,\n createFormatter,\n createParser,\n DEFAULT_CONFIG,\n SchemaGenerator,\n }: typeof TsJsonSchemaGenerator = require('ts-json-schema-generator');\n\n const currentDir = process.cwd();\n const rootNames = entries.map(({ path }) => resolvePath(currentDir, path));\n const compilerOptions: TypeScript.CompilerOptions = {\n incremental: false,\n jsx: ts.JsxEmit.Preserve,\n module: ts.ModuleKind.ESNext,\n moduleResolution: ts.ModuleResolutionKind.Bundler,\n noEmit: true,\n noResolve: false,\n skipDefaultLibCheck: true,\n skipLibCheck: false,\n strict: true,\n target: ts.ScriptTarget.ES2022,\n types: [],\n };\n\n const program = ts.createProgram(rootNames, compilerOptions);\n const sharedDiagnostics = [\n ...program.getOptionsDiagnostics(),\n ...program.getGlobalDiagnostics(),\n ];\n entries.forEach(({ packageName }, index) => {\n const sourceFile = program.getSourceFile(rootNames[index]);\n const diagnostics = [\n ...(index === 0 ? sharedDiagnostics : []),\n ...(sourceFile\n ? [\n ...program.getSyntacticDiagnostics(sourceFile),\n ...program.getSemanticDiagnostics(sourceFile),\n ]\n : []),\n ];\n if (diagnostics.length === 0) {\n return;\n }\n\n for (const diagnostic of diagnostics) {\n const cause = new Error(\n ts\n .formatDiagnostics([diagnostic], {\n getCanonicalFileName: fileName => fileName,\n getCurrentDirectory: () => currentDir,\n getNewLine: () => '\\n',\n })\n .trimEnd(),\n );\n handleSchemaError(\n options,\n new ConfigSchemaError({ source: packageName, cause }),\n );\n }\n });\n\n const generatorConfig = {\n ...DEFAULT_CONFIG,\n additionalProperties: true,\n expose: 'none' as const,\n extraTags: ['visibility', 'deepVisibility', 'deprecated', 'items'],\n jsDoc: 'extended' as const,\n skipTypeCheck: true,\n topRef: false,\n tsProgram: program,\n };\n const typeChecker = program.getTypeChecker();\n const parser = createParser(program, generatorConfig, mutableParser => {\n if (!options?.onSchemaError) {\n return;\n }\n\n // Preserve the rest of a schema by treating unresolved references as unconstrained values.\n mutableParser.addNodeParser({\n supportsNode(node) {\n if (!ts.isTypeReferenceNode(node)) {\n return false;\n }\n const symbol = typeChecker.getSymbolAtLocation(node.typeName);\n return !symbol?.declarations?.length;\n },\n createType() {\n return new AnyType();\n },\n });\n });\n class NestedAnnotationsFormatter extends AnnotatedTypeFormatter {\n override getDefinition(type: TsJsonSchemaGenerator.AnnotatedType) {\n const annotations = type.getAnnotations();\n const itemsAnnotation = annotations.items;\n const nestedItems = parseNestedSchemaAnnotation(itemsAnnotation);\n if (!nestedItems) {\n return super.getDefinition(type);\n }\n\n delete annotations.items;\n try {\n const definition = super.getDefinition(type);\n const items = definition.items;\n if (items && typeof items === 'object' && !Array.isArray(items)) {\n Object.assign(items, { [nestedItems.key]: nestedItems.value });\n }\n return definition;\n } finally {\n annotations.items = itemsAnnotation;\n }\n }\n }\n const formatter = createFormatter(\n generatorConfig,\n (chainFormatter, circularReferenceFormatter) => {\n chainFormatter.addTypeFormatter(\n new NestedAnnotationsFormatter(circularReferenceFormatter),\n );\n },\n );\n const generator = new SchemaGenerator(\n program,\n parser,\n formatter,\n generatorConfig,\n );\n\n const tsSchemas = entries.flatMap(({ path, packageName }, index) => {\n const sourceFile = program.getSourceFile(rootNames[index]);\n if (!sourceFile) {\n throw new ConfigSchemaError({\n source: packageName,\n cause: new Error('The schema source file could not be loaded'),\n });\n }\n const configNode = sourceFile.statements.find(\n statement =>\n (ts.isInterfaceDeclaration(statement) ||\n ts.isTypeAliasDeclaration(statement)) &&\n statement.name.text === 'Config',\n );\n if (!configNode) {\n throw new ConfigSchemaError({\n source: packageName,\n cause: new Error('The schema does not export a Config type'),\n });\n }\n\n const namespace = createHash('sha256')\n .update(packageName)\n .update('\\0')\n .update(path.split(sep).join('/'))\n .digest('hex');\n try {\n const value = namespaceSchemaDefinitions(\n structuredClone(\n generator.createSchemaFromNodes([configNode]),\n ) as JsonObject,\n namespace,\n );\n\n return [{ path, value, packageName }];\n } catch (error) {\n const cause = toError(error);\n handleSchemaError(\n options,\n new ConfigSchemaError({ source: packageName, cause }),\n );\n return [];\n }\n });\n\n return tsSchemas;\n}\n"],"names":["fs","relativePath","resolvePath","dirname","ConfigSchemaError","createHash","sep","toError"],"mappings":"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"}
@@ -6,12 +6,14 @@ var traverse = require('json-schema-traverse');
6
6
  var config = require('@backstage/config');
7
7
  var types = require('./types.cjs.js');
8
8
  var utils = require('./utils.cjs.js');
9
+ var cloneDeep = require('lodash/cloneDeep');
9
10
 
10
11
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
11
12
 
12
13
  var Ajv__default = /*#__PURE__*/_interopDefaultCompat(Ajv);
13
14
  var mergeAllOf__default = /*#__PURE__*/_interopDefaultCompat(mergeAllOf);
14
15
  var traverse__default = /*#__PURE__*/_interopDefaultCompat(traverse);
16
+ var cloneDeep__default = /*#__PURE__*/_interopDefaultCompat(cloneDeep);
15
17
 
16
18
  const inheritedVisibility = /* @__PURE__ */ Symbol("inherited-visibility");
17
19
  function compileConfigSchemas(schemas, options) {
@@ -89,7 +91,17 @@ function compileConfigSchemas(schemas, options) {
89
91
  throw new Error(`Schema at ${schema.path} is invalid, ${error}`);
90
92
  }
91
93
  }
92
- const merged = mergeConfigSchemas(schemas.map((_) => _.value));
94
+ const merged = mergeConfigSchemas(
95
+ schemas.map((_) => {
96
+ const copy = cloneDeep__default.default(_.value);
97
+ traverse__default.default(copy, (s) => {
98
+ if (typeof s.additionalProperties === "object" && s.additionalProperties !== null && Object.keys(s.additionalProperties).length === 0) {
99
+ s.additionalProperties = true;
100
+ }
101
+ });
102
+ return copy;
103
+ })
104
+ );
93
105
  traverse__default.default(
94
106
  merged,
95
107
  (schema, jsonPtr, _1, _2, _3, parentSchema) => {
@@ -109,7 +121,8 @@ function compileConfigSchemas(schemas, options) {
109
121
  }
110
122
  }
111
123
  if (options?.noUndeclaredProperties) {
112
- if (schema?.type === "object") {
124
+ const hasPropertyWithKey = (key) => typeof schema[key] === "object" && schema[key] !== null && Object.keys(schema[key]).length > 0;
125
+ if (schema?.type === "object" && (hasPropertyWithKey("properties") || hasPropertyWithKey("patternProperties"))) {
113
126
  schema.additionalProperties ||= false;
114
127
  }
115
128
  }
@@ -1 +1 @@
1
- {"version":3,"file":"compile.cjs.js","sources":["../../src/schema/compile.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Ajv from 'ajv';\nimport type { JSONSchema7 as JSONSchema } from 'json-schema';\nimport mergeAllOf, { Resolvers } from 'json-schema-merge-allof';\nimport traverse from 'json-schema-traverse';\nimport { ConfigReader } from '@backstage/config';\nimport {\n ConfigSchemaPackageEntry,\n ValidationFunc,\n CONFIG_VISIBILITIES,\n ConfigVisibility,\n} from './types';\nimport { SchemaObject } from 'json-schema-traverse';\nimport { normalizeAjvPath } from './utils';\n\n// Used to keep track of the internal deepVisibility inherited through the schema.\nconst inheritedVisibility = Symbol('inherited-visibility');\n\n/**\n * This takes a collection of Backstage configuration schemas from various\n * sources and compiles them down into a single schema validation function.\n *\n * It also handles the implementation of the custom \"visibility\" keyword used\n * to specify the scope of different config paths.\n */\nexport function compileConfigSchemas(\n schemas: ConfigSchemaPackageEntry[],\n options?: {\n noUndeclaredProperties?: boolean;\n },\n): ValidationFunc {\n // The ajv instance below is stateful and doesn't really allow for additional\n // output during validation. We work around this by having this extra piece\n // of state that we reset before each validation.\n const visibilityByDataPath = new Map<string, ConfigVisibility>();\n const deepVisibilityByDataPath = new Map<string, ConfigVisibility>();\n const deprecationByDataPath = new Map<string, string>();\n\n const ajv = new Ajv({\n allErrors: true,\n allowUnionTypes: true,\n coerceTypes: true,\n schemas: {\n 'https://backstage.io/schema/config-v1': true,\n },\n })\n .addKeyword({\n keyword: 'visibility',\n metaSchema: {\n type: 'string',\n enum: CONFIG_VISIBILITIES,\n },\n compile(visibility: ConfigVisibility) {\n return (_data, context) => {\n if (context?.instancePath === undefined) {\n return false;\n }\n if (visibility && visibility !== 'backend') {\n const normalizedPath = normalizeAjvPath(context.instancePath);\n visibilityByDataPath.set(normalizedPath, visibility);\n }\n return true;\n };\n },\n })\n .addKeyword({\n keyword: 'deepVisibility',\n metaSchema: {\n type: 'string',\n /**\n * Disallow 'backend' deepVisibility to prevent cases of permission escaping.\n *\n * Something like:\n * - deepVisibility secret -> backend -> frontend.\n * - deepVisibility secret -> backend -> visibility frontend.\n */\n enum: ['frontend', 'secret'],\n },\n compile(visibility: 'frontend' | 'secret') {\n return (_data, context) => {\n if (context?.instancePath === undefined) {\n return false;\n }\n if (visibility) {\n const normalizedPath = normalizeAjvPath(context.instancePath);\n deepVisibilityByDataPath.set(normalizedPath, visibility);\n }\n return true;\n };\n },\n })\n .removeKeyword('deprecated') // remove `deprecated` keyword so that we can implement our own compiler\n .addKeyword({\n keyword: 'deprecated',\n metaSchema: { type: 'string' },\n compile(deprecationDescription: string) {\n return (_data, context) => {\n if (context?.instancePath === undefined) {\n return false;\n }\n const normalizedPath = normalizeAjvPath(context.instancePath);\n // create mapping of deprecation description and data path of property\n deprecationByDataPath.set(normalizedPath, deprecationDescription);\n return true;\n };\n },\n });\n\n for (const schema of schemas) {\n try {\n ajv.compile(schema.value);\n } catch (error) {\n throw new Error(`Schema at ${schema.path} is invalid, ${error}`);\n }\n }\n\n const merged = mergeConfigSchemas(schemas.map(_ => _.value));\n\n traverse(\n merged,\n (\n schema: SchemaObject & { [inheritedVisibility]?: ConfigVisibility },\n jsonPtr: string,\n _1: any,\n _2: any,\n _3?: any,\n parentSchema?: SchemaObject & {\n [inheritedVisibility]?: ConfigVisibility;\n },\n ) => {\n // Inherit parent deepVisibility if we don't define one ourselves.\n // This is used to detect situations where conflicting deep visibilities are set.\n schema[inheritedVisibility] ??=\n schema?.deepVisibility ?? parentSchema?.[inheritedVisibility];\n\n if (schema[inheritedVisibility]) {\n // Validate that we're not trying to set a conflicting visibility. This can be done\n // either by setting a conflicting visibility directly or deep visibility\n const values = [\n schema.visibility,\n schema[inheritedVisibility],\n parentSchema?.[inheritedVisibility],\n ];\n const hasFrontend = values.some(e => e === 'frontend');\n const hasSecret = values.some(e => e === 'secret');\n if (hasFrontend && hasSecret) {\n throw new Error(\n `Config schema visibility is both 'frontend' and 'secret' for ${jsonPtr}`,\n );\n }\n }\n\n if (options?.noUndeclaredProperties) {\n /**\n * The `additionalProperties` key can only be applied to `type: object` in the JSON\n * schema.\n */\n if (schema?.type === 'object') {\n schema.additionalProperties ||= false;\n }\n }\n },\n );\n\n const validate = ajv.compile(merged);\n\n const visibilityBySchemaPath = new Map<string, ConfigVisibility>();\n traverse(merged, (schema, path) => {\n if (schema.visibility && schema.visibility !== 'backend') {\n visibilityBySchemaPath.set(normalizeAjvPath(path), schema.visibility);\n }\n if (schema.deepVisibility) {\n visibilityBySchemaPath.set(normalizeAjvPath(path), schema.deepVisibility);\n }\n });\n\n return configs => {\n const config = ConfigReader.fromConfigs(configs).getOptional();\n\n visibilityByDataPath.clear();\n deepVisibilityByDataPath.clear();\n\n const valid = validate(config);\n\n if (!valid) {\n return {\n errors: validate.errors ?? [],\n visibilityByDataPath: new Map(visibilityByDataPath),\n deepVisibilityByDataPath: new Map(deepVisibilityByDataPath),\n visibilityBySchemaPath,\n deprecationByDataPath,\n };\n }\n\n return {\n visibilityByDataPath: new Map(visibilityByDataPath),\n deepVisibilityByDataPath: new Map(deepVisibilityByDataPath),\n visibilityBySchemaPath,\n deprecationByDataPath,\n };\n };\n}\n\n/**\n * Given a list of configuration schemas from packages, merge them\n * into a single json schema.\n *\n * @public\n */\nexport function mergeConfigSchemas(schemas: JSONSchema[]): JSONSchema {\n const merged = mergeAllOf(\n { allOf: schemas },\n {\n // JSONSchema is typically subtractive, as in it always reduces the set of allowed\n // inputs through constraints. This changes the object property merging to be additive\n // rather than subtractive.\n ignoreAdditionalProperties: true,\n resolvers: {\n // This ensures that the visibilities across different schemas are sound, and\n // selects the most specific visibility for each path.\n visibility(values: string[], path: string[]) {\n const hasFrontend = values.some(_ => _ === 'frontend');\n const hasSecret = values.some(_ => _ === 'secret');\n if (hasFrontend && hasSecret) {\n throw new Error(\n `Config schema visibility is both 'frontend' and 'secret' for ${path.join(\n '/',\n )}`,\n );\n } else if (hasFrontend) {\n return 'frontend';\n } else if (hasSecret) {\n return 'secret';\n }\n\n return 'backend';\n },\n } as Partial<Resolvers<JSONSchema>>,\n },\n );\n return merged;\n}\n"],"names":["Ajv","CONFIG_VISIBILITIES","normalizeAjvPath","traverse","config","ConfigReader","mergeAllOf"],"mappings":"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"}
1
+ {"version":3,"file":"compile.cjs.js","sources":["../../src/schema/compile.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Ajv from 'ajv';\nimport type { JSONSchema7 as JSONSchema } from 'json-schema';\nimport mergeAllOf, { Resolvers } from 'json-schema-merge-allof';\nimport traverse from 'json-schema-traverse';\nimport { ConfigReader } from '@backstage/config';\nimport {\n ConfigSchemaPackageEntry,\n ValidationFunc,\n CONFIG_VISIBILITIES,\n ConfigVisibility,\n} from './types';\nimport { SchemaObject } from 'json-schema-traverse';\nimport { normalizeAjvPath } from './utils';\nimport cloneDeep from 'lodash/cloneDeep';\n\n// Used to keep track of the internal deepVisibility inherited through the schema.\nconst inheritedVisibility = Symbol('inherited-visibility');\n\n/**\n * This takes a collection of Backstage configuration schemas from various\n * sources and compiles them down into a single schema validation function.\n *\n * It also handles the implementation of the custom \"visibility\" keyword used\n * to specify the scope of different config paths.\n */\nexport function compileConfigSchemas(\n schemas: ConfigSchemaPackageEntry[],\n options?: {\n noUndeclaredProperties?: boolean;\n },\n): ValidationFunc {\n // The ajv instance below is stateful and doesn't really allow for additional\n // output during validation. We work around this by having this extra piece\n // of state that we reset before each validation.\n const visibilityByDataPath = new Map<string, ConfigVisibility>();\n const deepVisibilityByDataPath = new Map<string, ConfigVisibility>();\n const deprecationByDataPath = new Map<string, string>();\n\n const ajv = new Ajv({\n allErrors: true,\n allowUnionTypes: true,\n coerceTypes: true,\n schemas: {\n 'https://backstage.io/schema/config-v1': true,\n },\n })\n .addKeyword({\n keyword: 'visibility',\n metaSchema: {\n type: 'string',\n enum: CONFIG_VISIBILITIES,\n },\n compile(visibility: ConfigVisibility) {\n return (_data, context) => {\n if (context?.instancePath === undefined) {\n return false;\n }\n if (visibility && visibility !== 'backend') {\n const normalizedPath = normalizeAjvPath(context.instancePath);\n visibilityByDataPath.set(normalizedPath, visibility);\n }\n return true;\n };\n },\n })\n .addKeyword({\n keyword: 'deepVisibility',\n metaSchema: {\n type: 'string',\n /**\n * Disallow 'backend' deepVisibility to prevent cases of permission escaping.\n *\n * Something like:\n * - deepVisibility secret -> backend -> frontend.\n * - deepVisibility secret -> backend -> visibility frontend.\n */\n enum: ['frontend', 'secret'],\n },\n compile(visibility: 'frontend' | 'secret') {\n return (_data, context) => {\n if (context?.instancePath === undefined) {\n return false;\n }\n if (visibility) {\n const normalizedPath = normalizeAjvPath(context.instancePath);\n deepVisibilityByDataPath.set(normalizedPath, visibility);\n }\n return true;\n };\n },\n })\n .removeKeyword('deprecated') // remove `deprecated` keyword so that we can implement our own compiler\n .addKeyword({\n keyword: 'deprecated',\n metaSchema: { type: 'string' },\n compile(deprecationDescription: string) {\n return (_data, context) => {\n if (context?.instancePath === undefined) {\n return false;\n }\n const normalizedPath = normalizeAjvPath(context.instancePath);\n // create mapping of deprecation description and data path of property\n deprecationByDataPath.set(normalizedPath, deprecationDescription);\n return true;\n };\n },\n });\n\n for (const schema of schemas) {\n try {\n ajv.compile(schema.value);\n } catch (error) {\n throw new Error(`Schema at ${schema.path} is invalid, ${error}`);\n }\n }\n\n const merged = mergeConfigSchemas(\n schemas.map(_ => {\n const copy = cloneDeep(_.value as JSONSchema);\n traverse(copy, s => {\n // We convert `additionalProperties: {}` to `additionalProperties: true`\n // because `mergeAllOf` drops `additionalProperties: {}` during merging.\n // According to JSON Schema, these two forms are equivalent. Without this\n // conversion, the dropped value is treated as unset, which causes\n // `noUndeclaredProperties` to incorrectly add `additionalProperties: false`\n // and reject valid configuration.\n if (\n typeof s.additionalProperties === 'object' &&\n s.additionalProperties !== null &&\n Object.keys(s.additionalProperties).length === 0\n ) {\n s.additionalProperties = true;\n }\n });\n return copy;\n }),\n );\n\n traverse(\n merged,\n (\n schema: SchemaObject & { [inheritedVisibility]?: ConfigVisibility },\n jsonPtr: string,\n _1: any,\n _2: any,\n _3?: any,\n parentSchema?: SchemaObject & {\n [inheritedVisibility]?: ConfigVisibility;\n },\n ) => {\n // Inherit parent deepVisibility if we don't define one ourselves.\n // This is used to detect situations where conflicting deep visibilities are set.\n schema[inheritedVisibility] ??=\n schema?.deepVisibility ?? parentSchema?.[inheritedVisibility];\n\n if (schema[inheritedVisibility]) {\n // Validate that we're not trying to set a conflicting visibility. This can be done\n // either by setting a conflicting visibility directly or deep visibility\n const values = [\n schema.visibility,\n schema[inheritedVisibility],\n parentSchema?.[inheritedVisibility],\n ];\n const hasFrontend = values.some(e => e === 'frontend');\n const hasSecret = values.some(e => e === 'secret');\n if (hasFrontend && hasSecret) {\n throw new Error(\n `Config schema visibility is both 'frontend' and 'secret' for ${jsonPtr}`,\n );\n }\n }\n\n if (options?.noUndeclaredProperties) {\n const hasPropertyWithKey = (key: string) =>\n typeof schema[key] === 'object' &&\n schema[key] !== null &&\n Object.keys(schema[key]).length > 0;\n /**\n * The `additionalProperties` key can only be applied to `type: object`\n * in the JSON schema. It's only applied to objects that specify\n * properties. Otherwise, we end up with nonsensical schemas that don't\n * allow any properties at all.\n */\n if (\n schema?.type === 'object' &&\n (hasPropertyWithKey('properties') ||\n hasPropertyWithKey('patternProperties'))\n ) {\n schema.additionalProperties ||= false;\n }\n }\n },\n );\n\n const validate = ajv.compile(merged);\n\n const visibilityBySchemaPath = new Map<string, ConfigVisibility>();\n traverse(merged, (schema, path) => {\n if (schema.visibility && schema.visibility !== 'backend') {\n visibilityBySchemaPath.set(normalizeAjvPath(path), schema.visibility);\n }\n if (schema.deepVisibility) {\n visibilityBySchemaPath.set(normalizeAjvPath(path), schema.deepVisibility);\n }\n });\n\n return configs => {\n const config = ConfigReader.fromConfigs(configs).getOptional();\n\n visibilityByDataPath.clear();\n deepVisibilityByDataPath.clear();\n\n const valid = validate(config);\n\n if (!valid) {\n return {\n errors: validate.errors ?? [],\n visibilityByDataPath: new Map(visibilityByDataPath),\n deepVisibilityByDataPath: new Map(deepVisibilityByDataPath),\n visibilityBySchemaPath,\n deprecationByDataPath,\n };\n }\n\n return {\n visibilityByDataPath: new Map(visibilityByDataPath),\n deepVisibilityByDataPath: new Map(deepVisibilityByDataPath),\n visibilityBySchemaPath,\n deprecationByDataPath,\n };\n };\n}\n\n/**\n * Given a list of configuration schemas from packages, merge them\n * into a single json schema.\n *\n * @public\n */\nexport function mergeConfigSchemas(schemas: JSONSchema[]): JSONSchema {\n const merged = mergeAllOf(\n { allOf: schemas },\n {\n // JSONSchema is typically subtractive, as in it always reduces the set of allowed\n // inputs through constraints. This changes the object property merging to be additive\n // rather than subtractive.\n ignoreAdditionalProperties: true,\n resolvers: {\n // This ensures that the visibilities across different schemas are sound, and\n // selects the most specific visibility for each path.\n visibility(values: string[], path: string[]) {\n const hasFrontend = values.some(_ => _ === 'frontend');\n const hasSecret = values.some(_ => _ === 'secret');\n if (hasFrontend && hasSecret) {\n throw new Error(\n `Config schema visibility is both 'frontend' and 'secret' for ${path.join(\n '/',\n )}`,\n );\n } else if (hasFrontend) {\n return 'frontend';\n } else if (hasSecret) {\n return 'secret';\n }\n\n return 'backend';\n },\n } as Partial<Resolvers<JSONSchema>>,\n },\n );\n return merged;\n}\n"],"names":["Ajv","CONFIG_VISIBILITIES","normalizeAjvPath","cloneDeep","traverse","config","ConfigReader","mergeAllOf"],"mappings":"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"}
@@ -24,7 +24,8 @@ async function loadConfigSchema(options) {
24
24
  options.dependencies,
25
25
  options.packagePaths ?? [],
26
26
  {
27
- excludePackageDependencies: options.excludePackageDependencies
27
+ excludePackageDependencies: options.excludePackageDependencies,
28
+ onSchemaError: options.onSchemaError
28
29
  }
29
30
  );
30
31
  } else {
@@ -1 +1 @@
1
- {"version":3,"file":"load.cjs.js","sources":["../../src/schema/load.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AppConfig } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport { compileConfigSchemas } from './compile';\nimport { collectConfigSchemas } from './collect';\nimport { filterByVisibility, filterErrorsByVisibility } from './filtering';\nimport {\n ValidationError,\n ConfigSchema,\n ConfigSchemaPackageEntry,\n CONFIG_VISIBILITIES,\n} from './types';\nimport { normalizeAjvPath } from './utils';\n\n/**\n * Options that control the loading of configuration schema files in the backend.\n *\n * @public\n */\nexport type LoadConfigSchemaOptions =\n | (\n | {\n dependencies: string[];\n packagePaths?: string[];\n /**\n * Whether to exclude schemas from package dependencies.\n *\n * Defaults to `false`.\n */\n excludePackageDependencies?: boolean;\n }\n | {\n serialized: JsonObject;\n }\n ) & {\n noUndeclaredProperties?: boolean;\n };\n\nfunction errorsToError(errors: ValidationError[]): Error {\n const messages = errors.map(({ instancePath, message, params }) => {\n const paramStr = Object.entries(params)\n .map(([name, value]) => `${name}=${value}`)\n .join(' ');\n return `Config ${message || ''} { ${paramStr} } at ${normalizeAjvPath(\n instancePath,\n )}`;\n });\n const error = new Error(`Config validation failed, ${messages.join('; ')}`);\n (error as any).messages = messages;\n return error;\n}\n\n/**\n * Loads config schema for a Backstage instance.\n *\n * @public\n */\nexport async function loadConfigSchema(\n options: LoadConfigSchemaOptions,\n): Promise<ConfigSchema> {\n let schemas: ConfigSchemaPackageEntry[];\n\n if ('dependencies' in options) {\n schemas = await collectConfigSchemas(\n options.dependencies,\n options.packagePaths ?? [],\n {\n excludePackageDependencies: options.excludePackageDependencies,\n },\n );\n } else {\n const { serialized } = options;\n if (serialized?.backstageConfigSchemaVersion !== 1) {\n throw new Error(\n 'Serialized configuration schema is invalid or has an invalid version number',\n );\n }\n schemas = serialized.schemas as ConfigSchemaPackageEntry[];\n }\n\n const validate = compileConfigSchemas(schemas, {\n noUndeclaredProperties: options.noUndeclaredProperties,\n });\n\n return {\n process(\n configs: AppConfig[],\n {\n visibility,\n valueTransform,\n withFilteredKeys,\n withDeprecatedKeys,\n ignoreSchemaErrors,\n } = {},\n ): AppConfig[] {\n const result = validate(configs);\n\n if (!ignoreSchemaErrors) {\n const visibleErrors = filterErrorsByVisibility(\n result.errors,\n visibility,\n result.visibilityByDataPath,\n result.visibilityBySchemaPath,\n );\n if (visibleErrors.length > 0) {\n throw errorsToError(visibleErrors);\n }\n }\n\n let processedConfigs = configs;\n\n if (visibility) {\n processedConfigs = processedConfigs.map(({ data, context }) => ({\n context,\n ...filterByVisibility(\n data,\n visibility,\n result.visibilityByDataPath,\n result.deepVisibilityByDataPath,\n result.deprecationByDataPath,\n valueTransform,\n withFilteredKeys,\n withDeprecatedKeys,\n ),\n }));\n } else if (valueTransform) {\n processedConfigs = processedConfigs.map(({ data, context }) => ({\n context,\n ...filterByVisibility(\n data,\n Array.from(CONFIG_VISIBILITIES),\n result.visibilityByDataPath,\n result.deepVisibilityByDataPath,\n result.deprecationByDataPath,\n valueTransform,\n withFilteredKeys,\n withDeprecatedKeys,\n ),\n }));\n }\n\n return processedConfigs;\n },\n serialize(): JsonObject {\n return {\n schemas,\n backstageConfigSchemaVersion: 1,\n };\n },\n };\n}\n"],"names":["normalizeAjvPath","collectConfigSchemas","compileConfigSchemas","filterErrorsByVisibility","filterByVisibility","CONFIG_VISIBILITIES"],"mappings":"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"}
1
+ {"version":3,"file":"load.cjs.js","sources":["../../src/schema/load.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AppConfig } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport { compileConfigSchemas } from './compile';\nimport { collectConfigSchemas } from './collect';\nimport { filterByVisibility, filterErrorsByVisibility } from './filtering';\nimport {\n ValidationError,\n ConfigSchema,\n ConfigSchemaPackageEntry,\n CONFIG_VISIBILITIES,\n} from './types';\nimport { normalizeAjvPath } from './utils';\nimport type { ConfigSchemaError } from './ConfigSchemaError';\n\n/**\n * Options that control the loading of configuration schema files in the backend.\n *\n * @public\n */\nexport type LoadConfigSchemaOptions =\n | (\n | {\n dependencies: string[];\n packagePaths?: string[];\n /**\n * Whether to exclude schemas from package dependencies.\n *\n * Defaults to `false`.\n */\n excludePackageDependencies?: boolean;\n /**\n * Receives `ConfigSchemaError` instances and allows TypeScript schema\n * loading to continue. Unresolved types are treated as unconstrained\n * values, while schemas that cannot be generated are omitted.\n *\n * Without this callback, TypeScript configuration schema errors are\n * thrown.\n */\n onSchemaError?: (error: ConfigSchemaError) => void;\n }\n | {\n serialized: JsonObject;\n }\n ) & {\n noUndeclaredProperties?: boolean;\n };\n\nfunction errorsToError(errors: ValidationError[]): Error {\n const messages = errors.map(({ instancePath, message, params }) => {\n const paramStr = Object.entries(params)\n .map(([name, value]) => `${name}=${value}`)\n .join(' ');\n return `Config ${message || ''} { ${paramStr} } at ${normalizeAjvPath(\n instancePath,\n )}`;\n });\n const error = new Error(`Config validation failed, ${messages.join('; ')}`);\n (error as any).messages = messages;\n return error;\n}\n\n/**\n * Loads config schema for a Backstage instance.\n *\n * @public\n */\nexport async function loadConfigSchema(\n options: LoadConfigSchemaOptions,\n): Promise<ConfigSchema> {\n let schemas: ConfigSchemaPackageEntry[];\n\n if ('dependencies' in options) {\n schemas = await collectConfigSchemas(\n options.dependencies,\n options.packagePaths ?? [],\n {\n excludePackageDependencies: options.excludePackageDependencies,\n onSchemaError: options.onSchemaError,\n },\n );\n } else {\n const { serialized } = options;\n if (serialized?.backstageConfigSchemaVersion !== 1) {\n throw new Error(\n 'Serialized configuration schema is invalid or has an invalid version number',\n );\n }\n schemas = serialized.schemas as ConfigSchemaPackageEntry[];\n }\n\n const validate = compileConfigSchemas(schemas, {\n noUndeclaredProperties: options.noUndeclaredProperties,\n });\n\n return {\n process(\n configs: AppConfig[],\n {\n visibility,\n valueTransform,\n withFilteredKeys,\n withDeprecatedKeys,\n ignoreSchemaErrors,\n } = {},\n ): AppConfig[] {\n const result = validate(configs);\n\n if (!ignoreSchemaErrors) {\n const visibleErrors = filterErrorsByVisibility(\n result.errors,\n visibility,\n result.visibilityByDataPath,\n result.visibilityBySchemaPath,\n );\n if (visibleErrors.length > 0) {\n throw errorsToError(visibleErrors);\n }\n }\n\n let processedConfigs = configs;\n\n if (visibility) {\n processedConfigs = processedConfigs.map(({ data, context }) => ({\n context,\n ...filterByVisibility(\n data,\n visibility,\n result.visibilityByDataPath,\n result.deepVisibilityByDataPath,\n result.deprecationByDataPath,\n valueTransform,\n withFilteredKeys,\n withDeprecatedKeys,\n ),\n }));\n } else if (valueTransform) {\n processedConfigs = processedConfigs.map(({ data, context }) => ({\n context,\n ...filterByVisibility(\n data,\n Array.from(CONFIG_VISIBILITIES),\n result.visibilityByDataPath,\n result.deepVisibilityByDataPath,\n result.deprecationByDataPath,\n valueTransform,\n withFilteredKeys,\n withDeprecatedKeys,\n ),\n }));\n }\n\n return processedConfigs;\n },\n serialize(): JsonObject {\n return {\n schemas,\n backstageConfigSchemaVersion: 1,\n };\n },\n };\n}\n"],"names":["normalizeAjvPath","collectConfigSchemas","compileConfigSchemas","filterErrorsByVisibility","filterByVisibility","CONFIG_VISIBILITIES"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/config-loader",
3
- "version": "1.11.0",
3
+ "version": "1.11.2-next.0",
4
4
  "description": "Config loading functionality used by Backstage backend, and CLI",
5
5
  "backstage": {
6
6
  "role": "node-library"
@@ -36,10 +36,10 @@
36
36
  "test": "backstage-cli package test"
37
37
  },
38
38
  "dependencies": {
39
- "@backstage/cli-common": "^0.3.0",
40
- "@backstage/config": "^1.3.8",
41
- "@backstage/errors": "^1.3.1",
42
- "@backstage/types": "^1.2.2",
39
+ "@backstage/cli-common": "0.3.0",
40
+ "@backstage/config": "1.3.8",
41
+ "@backstage/errors": "1.3.1",
42
+ "@backstage/types": "1.2.2",
43
43
  "@types/json-schema": "^7.0.6",
44
44
  "ajv": "^8.10.0",
45
45
  "chokidar": "^3.5.2",
@@ -53,8 +53,8 @@
53
53
  "yaml": "^2.0.0"
54
54
  },
55
55
  "devDependencies": {
56
- "@backstage/backend-test-utils": "^1.11.5",
57
- "@backstage/cli": "^0.36.4",
56
+ "@backstage/backend-test-utils": "1.11.6-next.1",
57
+ "@backstage/cli": "0.36.5-next.1",
58
58
  "@types/json-schema-merge-allof": "^0.6.0",
59
59
  "@types/minimist": "^1.2.5",
60
60
  "msw": "^2.0.0",