Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

@backstage/config

Package Overview
Dependencies
Maintainers
4
Versions
418
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@backstage/config - npm Package Compare versions

Comparing version
0.0.0-nightly-20217521743
to
0.0.0-nightly-202181822218
+25
-1
CHANGELOG.md
# @backstage/config
## 0.0.0-nightly-20217521743
## 0.0.0-nightly-202181822218
### Patch Changes
- febddedcb2: Bump `lodash` to remediate `SNYK-JS-LODASH-590103` security vulnerability
## 0.1.9
### Patch Changes
- f88b2c7db: Documented `Config` interface and mark types as public.
## 0.1.8
### Patch Changes
- 47113f1f1: Only warn once per key when trying to read visibility-filtered values
## 0.1.7
### Patch Changes
- 90f25476a: Extended the `Config` interface to have an optional `subscribe` method that can be used be notified of updates to the configuration.
## 0.1.6
### Patch Changes
- e9d3983ee: Add warning when trying to access configuration values that have been filtered out by visibility.

@@ -8,0 +32,0 @@

+7
-3

@@ -49,2 +49,3 @@ 'use strict';

this.prefix = prefix;
this.notifiedFilteredKeys = new Set();
}

@@ -90,3 +91,4 @@ static fromConfigs(configs) {

const fullKey = this.fullKey(key);
if ((_b = this.filteredKeys) == null ? void 0 : _b.includes(fullKey)) {
if (((_b = this.filteredKeys) == null ? void 0 : _b.includes(fullKey)) && !this.notifiedFilteredKeys.has(fullKey)) {
this.notifiedFilteredKeys.add(fullKey);
console.warn(`Failed to read configuration value at '${fullKey}' as it is not visible. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.`);

@@ -144,3 +146,4 @@ }

const fullKey = this.fullKey(key);
if ((_a = this.filteredKeys) == null ? void 0 : _a.some((k) => k.startsWith(fullKey))) {
if (((_a = this.filteredKeys) == null ? void 0 : _a.some((k) => k.startsWith(fullKey))) && !this.notifiedFilteredKeys.has(key)) {
this.notifiedFilteredKeys.add(key);
console.warn(`Failed to read configuration array at '${key}' as it does not have any visible elements. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.`);

@@ -225,3 +228,4 @@ }

const fullKey = this.fullKey(key);
if ((_a = this.filteredKeys) == null ? void 0 : _a.includes(fullKey)) {
if (((_a = this.filteredKeys) == null ? void 0 : _a.includes(fullKey)) && !this.notifiedFilteredKeys.has(fullKey)) {
this.notifiedFilteredKeys.add(fullKey);
console.warn(`Failed to read configuration value at '${fullKey}' as it is not visible. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.`);

@@ -228,0 +232,0 @@ }

@@ -1,1 +0,1 @@

{"version":3,"file":"index.cjs.js","sources":["../src/reader.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, Config, JsonValue, JsonObject } from './types';\nimport cloneDeep from 'lodash/cloneDeep';\nimport mergeWith from 'lodash/mergeWith';\n\n// Update the same pattern in config-loader package if this is changed\nconst CONFIG_KEY_PART_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z][a-z0-9]*)*$/i;\n\nfunction isObject(value: JsonValue | undefined): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction typeOf(value: JsonValue | undefined): string {\n if (value === null) {\n return 'null';\n } else if (Array.isArray(value)) {\n return 'array';\n }\n const type = typeof value;\n if (type === 'number' && isNaN(value as number)) {\n return 'nan';\n }\n if (type === 'string' && value === '') {\n return 'empty-string';\n }\n return type;\n}\n\n// Separate out a couple of common error messages to reduce bundle size.\nconst errors = {\n type(key: string, context: string, typeName: string, expected: string) {\n return `Invalid type in config for key '${key}' in '${context}', got ${typeName}, wanted ${expected}`;\n },\n missing(key: string) {\n return `Missing required config value at '${key}'`;\n },\n convert(key: string, context: string, expected: string) {\n return `Unable to convert config value for key '${key}' in '${context}' to a ${expected}`;\n },\n};\n\nexport class ConfigReader implements Config {\n /**\n * A set of key paths that where removed from the config due to not being visible.\n *\n * This was added as a mutable private member to avoid changes to the public API.\n * Its only purpose of this is to warn users of missing visibility when running\n * the frontend in development mode.\n */\n private filteredKeys?: string[];\n\n static fromConfigs(configs: AppConfig[]): ConfigReader {\n if (configs.length === 0) {\n return new ConfigReader(undefined);\n }\n\n // Merge together all configs into a single config with recursive fallback\n // readers, giving the first config object in the array the lowest priority.\n return configs.reduce<ConfigReader>(\n (previousReader, { data, context, filteredKeys }) => {\n const reader = new ConfigReader(data, context, previousReader);\n reader.filteredKeys = filteredKeys;\n return reader;\n },\n undefined!,\n );\n }\n\n constructor(\n private readonly data: JsonObject | undefined,\n private readonly context: string = 'mock-config',\n private readonly fallback?: ConfigReader,\n private readonly prefix: string = '',\n ) {}\n\n has(key: string): boolean {\n const value = this.readValue(key);\n if (value !== undefined) {\n return true;\n }\n return this.fallback?.has(key) ?? false;\n }\n\n keys(): string[] {\n const localKeys = this.data ? Object.keys(this.data) : [];\n const fallbackKeys = this.fallback?.keys() ?? [];\n return [...new Set([...localKeys, ...fallbackKeys])];\n }\n\n get<T = JsonValue>(key?: string): T {\n const value = this.getOptional(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key ?? '')));\n }\n return value as T;\n }\n\n getOptional<T = JsonValue>(key?: string): T | undefined {\n const value = this.readValue(key);\n const fallbackValue = this.fallback?.getOptional<T>(key);\n\n if (value === undefined) {\n if (process.env.NODE_ENV === 'development') {\n if (fallbackValue === undefined && key) {\n const fullKey = this.fullKey(key);\n if (this.filteredKeys?.includes(fullKey)) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration value at '${fullKey}' as it is not visible. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n }\n return fallbackValue;\n } else if (fallbackValue === undefined) {\n return value as T;\n }\n\n // Avoid merging arrays and primitive values, since that's how merging works for other\n // methods for reading config.\n return mergeWith(\n {},\n { value: cloneDeep(fallbackValue) },\n { value },\n (into, from) => (!isObject(from) || !isObject(into) ? from : undefined),\n ).value as T;\n }\n\n getConfig(key: string): ConfigReader {\n const value = this.getOptionalConfig(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalConfig(key: string): ConfigReader | undefined {\n const value = this.readValue(key);\n const fallbackConfig = this.fallback?.getOptionalConfig(key);\n\n if (isObject(value)) {\n return this.copy(value, key, fallbackConfig);\n }\n if (value !== undefined) {\n throw new TypeError(\n errors.type(this.fullKey(key), this.context, typeOf(value), 'object'),\n );\n }\n return fallbackConfig;\n }\n\n getConfigArray(key: string): ConfigReader[] {\n const value = this.getOptionalConfigArray(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalConfigArray(key: string): ConfigReader[] | undefined {\n const configs = this.readConfigValue<JsonObject[]>(key, values => {\n if (!Array.isArray(values)) {\n return { expected: 'object-array' };\n }\n\n for (const [index, value] of values.entries()) {\n if (!isObject(value)) {\n return { expected: 'object-array', value, key: `${key}[${index}]` };\n }\n }\n return true;\n });\n\n if (!configs) {\n if (process.env.NODE_ENV === 'development') {\n const fullKey = this.fullKey(key);\n if (this.filteredKeys?.some(k => k.startsWith(fullKey))) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration array at '${key}' as it does not have any visible elements. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n return undefined;\n }\n\n return configs.map((obj, index) => this.copy(obj, `${key}[${index}]`));\n }\n\n getNumber(key: string): number {\n const value = this.getOptionalNumber(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalNumber(key: string): number | undefined {\n const value = this.readConfigValue<string | number>(\n key,\n val =>\n typeof val === 'number' ||\n typeof val === 'string' || { expected: 'number' },\n );\n if (typeof value === 'number' || value === undefined) {\n return value;\n }\n const number = Number(value);\n if (!Number.isFinite(number)) {\n throw new Error(\n errors.convert(this.fullKey(key), this.context, 'number'),\n );\n }\n return number;\n }\n\n getBoolean(key: string): boolean {\n const value = this.getOptionalBoolean(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalBoolean(key: string): boolean | undefined {\n return this.readConfigValue(\n key,\n value => typeof value === 'boolean' || { expected: 'boolean' },\n );\n }\n\n getString(key: string): string {\n const value = this.getOptionalString(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalString(key: string): string | undefined {\n return this.readConfigValue(\n key,\n value =>\n (typeof value === 'string' && value !== '') || { expected: 'string' },\n );\n }\n\n getStringArray(key: string): string[] {\n const value = this.getOptionalStringArray(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalStringArray(key: string): string[] | undefined {\n return this.readConfigValue(key, values => {\n if (!Array.isArray(values)) {\n return { expected: 'string-array' };\n }\n for (const [index, value] of values.entries()) {\n if (typeof value !== 'string' || value === '') {\n return { expected: 'string-array', value, key: `${key}[${index}]` };\n }\n }\n return true;\n });\n }\n\n private fullKey(key: string): string {\n return `${this.prefix}${this.prefix ? '.' : ''}${key}`;\n }\n\n private copy(data: JsonObject, key: string, fallback?: ConfigReader) {\n const reader = new ConfigReader(\n data,\n this.context,\n fallback,\n this.fullKey(key),\n );\n reader.filteredKeys = this.filteredKeys;\n return reader;\n }\n\n private readConfigValue<T extends JsonValue>(\n key: string,\n validate: (\n value: JsonValue,\n ) => { expected: string; value?: JsonValue; key?: string } | true,\n ): T | undefined {\n const value = this.readValue(key);\n\n if (value === undefined) {\n if (process.env.NODE_ENV === 'development') {\n const fullKey = this.fullKey(key);\n if (this.filteredKeys?.includes(fullKey)) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration value at '${fullKey}' as it is not visible. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n\n return this.fallback?.readConfigValue(key, validate);\n }\n const result = validate(value);\n if (result !== true) {\n const { key: keyName = key, value: theValue = value, expected } = result;\n throw new TypeError(\n errors.type(\n this.fullKey(keyName),\n this.context,\n typeOf(theValue),\n expected,\n ),\n );\n }\n\n return value as T;\n }\n\n private readValue(key?: string): JsonValue | undefined {\n const parts = key ? key.split('.') : [];\n for (const part of parts) {\n if (!CONFIG_KEY_PART_PATTERN.test(part)) {\n throw new TypeError(`Invalid config key '${key}'`);\n }\n }\n\n if (this.data === undefined) {\n return undefined;\n }\n\n let value: JsonValue | undefined = this.data;\n for (const [index, part] of parts.entries()) {\n if (isObject(value)) {\n value = value[part];\n } else if (value !== undefined) {\n const badKey = this.fullKey(parts.slice(0, index).join('.'));\n throw new TypeError(\n errors.type(badKey, this.context, typeOf(value), 'object'),\n );\n }\n }\n\n return value;\n }\n}\n"],"names":["mergeWith","cloneDeep"],"mappings":"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"}
{"version":3,"file":"index.cjs.js","sources":["../src/reader.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, Config, JsonValue, JsonObject } from './types';\nimport cloneDeep from 'lodash/cloneDeep';\nimport mergeWith from 'lodash/mergeWith';\n\n// Update the same pattern in config-loader package if this is changed\nconst CONFIG_KEY_PART_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z][a-z0-9]*)*$/i;\n\nfunction isObject(value: JsonValue | undefined): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction typeOf(value: JsonValue | undefined): string {\n if (value === null) {\n return 'null';\n } else if (Array.isArray(value)) {\n return 'array';\n }\n const type = typeof value;\n if (type === 'number' && isNaN(value as number)) {\n return 'nan';\n }\n if (type === 'string' && value === '') {\n return 'empty-string';\n }\n return type;\n}\n\n// Separate out a couple of common error messages to reduce bundle size.\nconst errors = {\n type(key: string, context: string, typeName: string, expected: string) {\n return `Invalid type in config for key '${key}' in '${context}', got ${typeName}, wanted ${expected}`;\n },\n missing(key: string) {\n return `Missing required config value at '${key}'`;\n },\n convert(key: string, context: string, expected: string) {\n return `Unable to convert config value for key '${key}' in '${context}' to a ${expected}`;\n },\n};\n\n/**\n * An implementation of the `Config` interface that uses a plain JavaScript object\n * for the backing data, with the ability of linking multiple readers together.\n *\n * @public\n */\nexport class ConfigReader implements Config {\n /**\n * A set of key paths that where removed from the config due to not being visible.\n *\n * This was added as a mutable private member to avoid changes to the public API.\n * Its only purpose of this is to warn users of missing visibility when running\n * the frontend in development mode.\n */\n private filteredKeys?: string[];\n private notifiedFilteredKeys = new Set<string>();\n\n static fromConfigs(configs: AppConfig[]): ConfigReader {\n if (configs.length === 0) {\n return new ConfigReader(undefined);\n }\n\n // Merge together all configs into a single config with recursive fallback\n // readers, giving the first config object in the array the lowest priority.\n return configs.reduce<ConfigReader>(\n (previousReader, { data, context, filteredKeys }) => {\n const reader = new ConfigReader(data, context, previousReader);\n reader.filteredKeys = filteredKeys;\n return reader;\n },\n undefined!,\n );\n }\n\n constructor(\n private readonly data: JsonObject | undefined,\n private readonly context: string = 'mock-config',\n private readonly fallback?: ConfigReader,\n private readonly prefix: string = '',\n ) {}\n\n has(key: string): boolean {\n const value = this.readValue(key);\n if (value !== undefined) {\n return true;\n }\n return this.fallback?.has(key) ?? false;\n }\n\n keys(): string[] {\n const localKeys = this.data ? Object.keys(this.data) : [];\n const fallbackKeys = this.fallback?.keys() ?? [];\n return [...new Set([...localKeys, ...fallbackKeys])];\n }\n\n get<T = JsonValue>(key?: string): T {\n const value = this.getOptional(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key ?? '')));\n }\n return value as T;\n }\n\n getOptional<T = JsonValue>(key?: string): T | undefined {\n const value = this.readValue(key);\n const fallbackValue = this.fallback?.getOptional<T>(key);\n\n if (value === undefined) {\n if (process.env.NODE_ENV === 'development') {\n if (fallbackValue === undefined && key) {\n const fullKey = this.fullKey(key);\n if (\n this.filteredKeys?.includes(fullKey) &&\n !this.notifiedFilteredKeys.has(fullKey)\n ) {\n this.notifiedFilteredKeys.add(fullKey);\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration value at '${fullKey}' as it is not visible. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n }\n return fallbackValue;\n } else if (fallbackValue === undefined) {\n return value as T;\n }\n\n // Avoid merging arrays and primitive values, since that's how merging works for other\n // methods for reading config.\n return mergeWith(\n {},\n { value: cloneDeep(fallbackValue) },\n { value },\n (into, from) => (!isObject(from) || !isObject(into) ? from : undefined),\n ).value as T;\n }\n\n getConfig(key: string): ConfigReader {\n const value = this.getOptionalConfig(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalConfig(key: string): ConfigReader | undefined {\n const value = this.readValue(key);\n const fallbackConfig = this.fallback?.getOptionalConfig(key);\n\n if (isObject(value)) {\n return this.copy(value, key, fallbackConfig);\n }\n if (value !== undefined) {\n throw new TypeError(\n errors.type(this.fullKey(key), this.context, typeOf(value), 'object'),\n );\n }\n return fallbackConfig;\n }\n\n getConfigArray(key: string): ConfigReader[] {\n const value = this.getOptionalConfigArray(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalConfigArray(key: string): ConfigReader[] | undefined {\n const configs = this.readConfigValue<JsonObject[]>(key, values => {\n if (!Array.isArray(values)) {\n return { expected: 'object-array' };\n }\n\n for (const [index, value] of values.entries()) {\n if (!isObject(value)) {\n return { expected: 'object-array', value, key: `${key}[${index}]` };\n }\n }\n return true;\n });\n\n if (!configs) {\n if (process.env.NODE_ENV === 'development') {\n const fullKey = this.fullKey(key);\n if (\n this.filteredKeys?.some(k => k.startsWith(fullKey)) &&\n !this.notifiedFilteredKeys.has(key)\n ) {\n this.notifiedFilteredKeys.add(key);\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration array at '${key}' as it does not have any visible elements. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n return undefined;\n }\n\n return configs.map((obj, index) => this.copy(obj, `${key}[${index}]`));\n }\n\n getNumber(key: string): number {\n const value = this.getOptionalNumber(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalNumber(key: string): number | undefined {\n const value = this.readConfigValue<string | number>(\n key,\n val =>\n typeof val === 'number' ||\n typeof val === 'string' || { expected: 'number' },\n );\n if (typeof value === 'number' || value === undefined) {\n return value;\n }\n const number = Number(value);\n if (!Number.isFinite(number)) {\n throw new Error(\n errors.convert(this.fullKey(key), this.context, 'number'),\n );\n }\n return number;\n }\n\n getBoolean(key: string): boolean {\n const value = this.getOptionalBoolean(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalBoolean(key: string): boolean | undefined {\n return this.readConfigValue(\n key,\n value => typeof value === 'boolean' || { expected: 'boolean' },\n );\n }\n\n getString(key: string): string {\n const value = this.getOptionalString(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalString(key: string): string | undefined {\n return this.readConfigValue(\n key,\n value =>\n (typeof value === 'string' && value !== '') || { expected: 'string' },\n );\n }\n\n getStringArray(key: string): string[] {\n const value = this.getOptionalStringArray(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalStringArray(key: string): string[] | undefined {\n return this.readConfigValue(key, values => {\n if (!Array.isArray(values)) {\n return { expected: 'string-array' };\n }\n for (const [index, value] of values.entries()) {\n if (typeof value !== 'string' || value === '') {\n return { expected: 'string-array', value, key: `${key}[${index}]` };\n }\n }\n return true;\n });\n }\n\n private fullKey(key: string): string {\n return `${this.prefix}${this.prefix ? '.' : ''}${key}`;\n }\n\n private copy(data: JsonObject, key: string, fallback?: ConfigReader) {\n const reader = new ConfigReader(\n data,\n this.context,\n fallback,\n this.fullKey(key),\n );\n reader.filteredKeys = this.filteredKeys;\n return reader;\n }\n\n private readConfigValue<T extends JsonValue>(\n key: string,\n validate: (\n value: JsonValue,\n ) => { expected: string; value?: JsonValue; key?: string } | true,\n ): T | undefined {\n const value = this.readValue(key);\n\n if (value === undefined) {\n if (process.env.NODE_ENV === 'development') {\n const fullKey = this.fullKey(key);\n if (\n this.filteredKeys?.includes(fullKey) &&\n !this.notifiedFilteredKeys.has(fullKey)\n ) {\n this.notifiedFilteredKeys.add(fullKey);\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration value at '${fullKey}' as it is not visible. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n\n return this.fallback?.readConfigValue(key, validate);\n }\n const result = validate(value);\n if (result !== true) {\n const { key: keyName = key, value: theValue = value, expected } = result;\n throw new TypeError(\n errors.type(\n this.fullKey(keyName),\n this.context,\n typeOf(theValue),\n expected,\n ),\n );\n }\n\n return value as T;\n }\n\n private readValue(key?: string): JsonValue | undefined {\n const parts = key ? key.split('.') : [];\n for (const part of parts) {\n if (!CONFIG_KEY_PART_PATTERN.test(part)) {\n throw new TypeError(`Invalid config key '${key}'`);\n }\n }\n\n if (this.data === undefined) {\n return undefined;\n }\n\n let value: JsonValue | undefined = this.data;\n for (const [index, part] of parts.entries()) {\n if (isObject(value)) {\n value = value[part];\n } else if (value !== undefined) {\n const badKey = this.fullKey(parts.slice(0, index).join('.'));\n throw new TypeError(\n errors.type(badKey, this.context, typeOf(value), 'object'),\n );\n }\n }\n\n return value;\n }\n}\n"],"names":["mergeWith","cloneDeep"],"mappings":"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"}

@@ -0,32 +1,144 @@

/**
* A type representing all allowed JSON primitive values.
*
* @public
*/
declare type JsonPrimitive = number | string | boolean | null;
/**
* A type representing all allowed JSON object values.
*
* @public
*/
declare type JsonObject = {
[key in string]?: JsonValue;
};
/**
* A type representing all allowed JSON array values.
*
* @public
*/
interface JsonArray extends Array<JsonValue> {
}
/**
* A type representing all allowed JSON values.
*
* @public
*/
declare type JsonValue = JsonObject | JsonArray | JsonPrimitive;
/**
* A serialized form of configuration data that carries additional context.
*
* @public
*/
declare type AppConfig = {
/**
* A string representing the source of this configuration data, for example a filepath.
*/
context: string;
/**
* The configuration data itself.
*/
data: JsonObject;
/**
* A list of keys that where filtered out from the configuration when it was loaded.
*
* This can be used to warn the user if they try to read any of these keys.
*/
filteredKeys?: string[];
};
/**
* The interface used to represent static configuration at runtime.
*
* @public
*/
declare type Config = {
/**
* Subscribes to the configuration object in order to receive a notification
* whenever any value within the configuration has changed.
*
* This method is optional to implement, and consumers need to check if it is
* implemented before invoking it.
*/
subscribe?(onChange: () => void): {
unsubscribe: () => void;
};
/**
* Checks whether the given key is present.
*/
has(key: string): boolean;
/**
* Lists all available configuration keys.
*/
keys(): string[];
/**
* Same as `getOptional`, but will throw an error if there's no value for the given key.
*/
get<T = JsonValue>(key?: string): T;
/**
* Read out all configuration data for the given key.
*
* Usage of this method should be avoided as the typed alternatives provide
* much better error reporting. The main use-case of this method is to determine
* the type of a configuration value in the case where there are multiple possible
* shapes of the configuration.
*/
getOptional<T = JsonValue>(key?: string): T | undefined;
/**
* Same as `getOptionalConfig`, but will throw an error if there's no value for the given key.
*/
getConfig(key: string): Config;
/**
* Creates a sub-view of the configuration object.
* The configuration value at the position of the provided key must be an object.
*/
getOptionalConfig(key: string): Config | undefined;
/**
* Same as `getOptionalConfigArray`, but will throw an error if there's no value for the given key.
*/
getConfigArray(key: string): Config[];
/**
* Creates a sub-view of an array of configuration objects.
* The configuration value at the position of the provided key must be an array of objects.
*/
getOptionalConfigArray(key: string): Config[] | undefined;
/**
* Same as `getOptionalNumber`, but will throw an error if there's no value for the given key.
*/
getNumber(key: string): number;
/**
* Reads a configuration value at the given key, expecting it to be a number.
*/
getOptionalNumber(key: string): number | undefined;
/**
* Same as `getOptionalBoolean`, but will throw an error if there's no value for the given key.
*/
getBoolean(key: string): boolean;
/**
* Reads a configuration value at the given key, expecting it to be a boolean.
*/
getOptionalBoolean(key: string): boolean | undefined;
/**
* Same as `getOptionalString`, but will throw an error if there's no value for the given key.
*/
getString(key: string): string;
/**
* Reads a configuration value at the given key, expecting it to be a string.
*/
getOptionalString(key: string): string | undefined;
/**
* Same as `getOptionalStringArray`, but will throw an error if there's no value for the given key.
*/
getStringArray(key: string): string[];
/**
* Reads a configuration value at the given key, expecting it to be an array of strings.
*/
getOptionalStringArray(key: string): string[] | undefined;
};
/**
* An implementation of the `Config` interface that uses a plain JavaScript object
* for the backing data, with the ability of linking multiple readers together.
*
* @public
*/
declare class ConfigReader implements Config {

@@ -45,2 +157,3 @@ private readonly data;

private filteredKeys?;
private notifiedFilteredKeys;
static fromConfigs(configs: AppConfig[]): ConfigReader;

@@ -47,0 +160,0 @@ constructor(data: JsonObject | undefined, context?: string, fallback?: ConfigReader | undefined, prefix?: string);

@@ -40,2 +40,3 @@ import cloneDeep from 'lodash/cloneDeep';

this.prefix = prefix;
this.notifiedFilteredKeys = new Set();
}

@@ -81,3 +82,4 @@ static fromConfigs(configs) {

const fullKey = this.fullKey(key);
if ((_b = this.filteredKeys) == null ? void 0 : _b.includes(fullKey)) {
if (((_b = this.filteredKeys) == null ? void 0 : _b.includes(fullKey)) && !this.notifiedFilteredKeys.has(fullKey)) {
this.notifiedFilteredKeys.add(fullKey);
console.warn(`Failed to read configuration value at '${fullKey}' as it is not visible. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.`);

@@ -135,3 +137,4 @@ }

const fullKey = this.fullKey(key);
if ((_a = this.filteredKeys) == null ? void 0 : _a.some((k) => k.startsWith(fullKey))) {
if (((_a = this.filteredKeys) == null ? void 0 : _a.some((k) => k.startsWith(fullKey))) && !this.notifiedFilteredKeys.has(key)) {
this.notifiedFilteredKeys.add(key);
console.warn(`Failed to read configuration array at '${key}' as it does not have any visible elements. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.`);

@@ -216,3 +219,4 @@ }

const fullKey = this.fullKey(key);
if ((_a = this.filteredKeys) == null ? void 0 : _a.includes(fullKey)) {
if (((_a = this.filteredKeys) == null ? void 0 : _a.includes(fullKey)) && !this.notifiedFilteredKeys.has(fullKey)) {
this.notifiedFilteredKeys.add(fullKey);
console.warn(`Failed to read configuration value at '${fullKey}' as it is not visible. See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.`);

@@ -219,0 +223,0 @@ }

@@ -1,1 +0,1 @@

{"version":3,"file":"index.esm.js","sources":["../src/reader.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, Config, JsonValue, JsonObject } from './types';\nimport cloneDeep from 'lodash/cloneDeep';\nimport mergeWith from 'lodash/mergeWith';\n\n// Update the same pattern in config-loader package if this is changed\nconst CONFIG_KEY_PART_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z][a-z0-9]*)*$/i;\n\nfunction isObject(value: JsonValue | undefined): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction typeOf(value: JsonValue | undefined): string {\n if (value === null) {\n return 'null';\n } else if (Array.isArray(value)) {\n return 'array';\n }\n const type = typeof value;\n if (type === 'number' && isNaN(value as number)) {\n return 'nan';\n }\n if (type === 'string' && value === '') {\n return 'empty-string';\n }\n return type;\n}\n\n// Separate out a couple of common error messages to reduce bundle size.\nconst errors = {\n type(key: string, context: string, typeName: string, expected: string) {\n return `Invalid type in config for key '${key}' in '${context}', got ${typeName}, wanted ${expected}`;\n },\n missing(key: string) {\n return `Missing required config value at '${key}'`;\n },\n convert(key: string, context: string, expected: string) {\n return `Unable to convert config value for key '${key}' in '${context}' to a ${expected}`;\n },\n};\n\nexport class ConfigReader implements Config {\n /**\n * A set of key paths that where removed from the config due to not being visible.\n *\n * This was added as a mutable private member to avoid changes to the public API.\n * Its only purpose of this is to warn users of missing visibility when running\n * the frontend in development mode.\n */\n private filteredKeys?: string[];\n\n static fromConfigs(configs: AppConfig[]): ConfigReader {\n if (configs.length === 0) {\n return new ConfigReader(undefined);\n }\n\n // Merge together all configs into a single config with recursive fallback\n // readers, giving the first config object in the array the lowest priority.\n return configs.reduce<ConfigReader>(\n (previousReader, { data, context, filteredKeys }) => {\n const reader = new ConfigReader(data, context, previousReader);\n reader.filteredKeys = filteredKeys;\n return reader;\n },\n undefined!,\n );\n }\n\n constructor(\n private readonly data: JsonObject | undefined,\n private readonly context: string = 'mock-config',\n private readonly fallback?: ConfigReader,\n private readonly prefix: string = '',\n ) {}\n\n has(key: string): boolean {\n const value = this.readValue(key);\n if (value !== undefined) {\n return true;\n }\n return this.fallback?.has(key) ?? false;\n }\n\n keys(): string[] {\n const localKeys = this.data ? Object.keys(this.data) : [];\n const fallbackKeys = this.fallback?.keys() ?? [];\n return [...new Set([...localKeys, ...fallbackKeys])];\n }\n\n get<T = JsonValue>(key?: string): T {\n const value = this.getOptional(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key ?? '')));\n }\n return value as T;\n }\n\n getOptional<T = JsonValue>(key?: string): T | undefined {\n const value = this.readValue(key);\n const fallbackValue = this.fallback?.getOptional<T>(key);\n\n if (value === undefined) {\n if (process.env.NODE_ENV === 'development') {\n if (fallbackValue === undefined && key) {\n const fullKey = this.fullKey(key);\n if (this.filteredKeys?.includes(fullKey)) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration value at '${fullKey}' as it is not visible. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n }\n return fallbackValue;\n } else if (fallbackValue === undefined) {\n return value as T;\n }\n\n // Avoid merging arrays and primitive values, since that's how merging works for other\n // methods for reading config.\n return mergeWith(\n {},\n { value: cloneDeep(fallbackValue) },\n { value },\n (into, from) => (!isObject(from) || !isObject(into) ? from : undefined),\n ).value as T;\n }\n\n getConfig(key: string): ConfigReader {\n const value = this.getOptionalConfig(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalConfig(key: string): ConfigReader | undefined {\n const value = this.readValue(key);\n const fallbackConfig = this.fallback?.getOptionalConfig(key);\n\n if (isObject(value)) {\n return this.copy(value, key, fallbackConfig);\n }\n if (value !== undefined) {\n throw new TypeError(\n errors.type(this.fullKey(key), this.context, typeOf(value), 'object'),\n );\n }\n return fallbackConfig;\n }\n\n getConfigArray(key: string): ConfigReader[] {\n const value = this.getOptionalConfigArray(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalConfigArray(key: string): ConfigReader[] | undefined {\n const configs = this.readConfigValue<JsonObject[]>(key, values => {\n if (!Array.isArray(values)) {\n return { expected: 'object-array' };\n }\n\n for (const [index, value] of values.entries()) {\n if (!isObject(value)) {\n return { expected: 'object-array', value, key: `${key}[${index}]` };\n }\n }\n return true;\n });\n\n if (!configs) {\n if (process.env.NODE_ENV === 'development') {\n const fullKey = this.fullKey(key);\n if (this.filteredKeys?.some(k => k.startsWith(fullKey))) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration array at '${key}' as it does not have any visible elements. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n return undefined;\n }\n\n return configs.map((obj, index) => this.copy(obj, `${key}[${index}]`));\n }\n\n getNumber(key: string): number {\n const value = this.getOptionalNumber(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalNumber(key: string): number | undefined {\n const value = this.readConfigValue<string | number>(\n key,\n val =>\n typeof val === 'number' ||\n typeof val === 'string' || { expected: 'number' },\n );\n if (typeof value === 'number' || value === undefined) {\n return value;\n }\n const number = Number(value);\n if (!Number.isFinite(number)) {\n throw new Error(\n errors.convert(this.fullKey(key), this.context, 'number'),\n );\n }\n return number;\n }\n\n getBoolean(key: string): boolean {\n const value = this.getOptionalBoolean(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalBoolean(key: string): boolean | undefined {\n return this.readConfigValue(\n key,\n value => typeof value === 'boolean' || { expected: 'boolean' },\n );\n }\n\n getString(key: string): string {\n const value = this.getOptionalString(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalString(key: string): string | undefined {\n return this.readConfigValue(\n key,\n value =>\n (typeof value === 'string' && value !== '') || { expected: 'string' },\n );\n }\n\n getStringArray(key: string): string[] {\n const value = this.getOptionalStringArray(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalStringArray(key: string): string[] | undefined {\n return this.readConfigValue(key, values => {\n if (!Array.isArray(values)) {\n return { expected: 'string-array' };\n }\n for (const [index, value] of values.entries()) {\n if (typeof value !== 'string' || value === '') {\n return { expected: 'string-array', value, key: `${key}[${index}]` };\n }\n }\n return true;\n });\n }\n\n private fullKey(key: string): string {\n return `${this.prefix}${this.prefix ? '.' : ''}${key}`;\n }\n\n private copy(data: JsonObject, key: string, fallback?: ConfigReader) {\n const reader = new ConfigReader(\n data,\n this.context,\n fallback,\n this.fullKey(key),\n );\n reader.filteredKeys = this.filteredKeys;\n return reader;\n }\n\n private readConfigValue<T extends JsonValue>(\n key: string,\n validate: (\n value: JsonValue,\n ) => { expected: string; value?: JsonValue; key?: string } | true,\n ): T | undefined {\n const value = this.readValue(key);\n\n if (value === undefined) {\n if (process.env.NODE_ENV === 'development') {\n const fullKey = this.fullKey(key);\n if (this.filteredKeys?.includes(fullKey)) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration value at '${fullKey}' as it is not visible. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n\n return this.fallback?.readConfigValue(key, validate);\n }\n const result = validate(value);\n if (result !== true) {\n const { key: keyName = key, value: theValue = value, expected } = result;\n throw new TypeError(\n errors.type(\n this.fullKey(keyName),\n this.context,\n typeOf(theValue),\n expected,\n ),\n );\n }\n\n return value as T;\n }\n\n private readValue(key?: string): JsonValue | undefined {\n const parts = key ? key.split('.') : [];\n for (const part of parts) {\n if (!CONFIG_KEY_PART_PATTERN.test(part)) {\n throw new TypeError(`Invalid config key '${key}'`);\n }\n }\n\n if (this.data === undefined) {\n return undefined;\n }\n\n let value: JsonValue | undefined = this.data;\n for (const [index, part] of parts.entries()) {\n if (isObject(value)) {\n value = value[part];\n } else if (value !== undefined) {\n const badKey = this.fullKey(parts.slice(0, index).join('.'));\n throw new TypeError(\n errors.type(badKey, this.context, typeOf(value), 'object'),\n );\n }\n }\n\n return value;\n }\n}\n"],"names":[],"mappings":"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"}
{"version":3,"file":"index.esm.js","sources":["../src/reader.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, Config, JsonValue, JsonObject } from './types';\nimport cloneDeep from 'lodash/cloneDeep';\nimport mergeWith from 'lodash/mergeWith';\n\n// Update the same pattern in config-loader package if this is changed\nconst CONFIG_KEY_PART_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z][a-z0-9]*)*$/i;\n\nfunction isObject(value: JsonValue | undefined): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction typeOf(value: JsonValue | undefined): string {\n if (value === null) {\n return 'null';\n } else if (Array.isArray(value)) {\n return 'array';\n }\n const type = typeof value;\n if (type === 'number' && isNaN(value as number)) {\n return 'nan';\n }\n if (type === 'string' && value === '') {\n return 'empty-string';\n }\n return type;\n}\n\n// Separate out a couple of common error messages to reduce bundle size.\nconst errors = {\n type(key: string, context: string, typeName: string, expected: string) {\n return `Invalid type in config for key '${key}' in '${context}', got ${typeName}, wanted ${expected}`;\n },\n missing(key: string) {\n return `Missing required config value at '${key}'`;\n },\n convert(key: string, context: string, expected: string) {\n return `Unable to convert config value for key '${key}' in '${context}' to a ${expected}`;\n },\n};\n\n/**\n * An implementation of the `Config` interface that uses a plain JavaScript object\n * for the backing data, with the ability of linking multiple readers together.\n *\n * @public\n */\nexport class ConfigReader implements Config {\n /**\n * A set of key paths that where removed from the config due to not being visible.\n *\n * This was added as a mutable private member to avoid changes to the public API.\n * Its only purpose of this is to warn users of missing visibility when running\n * the frontend in development mode.\n */\n private filteredKeys?: string[];\n private notifiedFilteredKeys = new Set<string>();\n\n static fromConfigs(configs: AppConfig[]): ConfigReader {\n if (configs.length === 0) {\n return new ConfigReader(undefined);\n }\n\n // Merge together all configs into a single config with recursive fallback\n // readers, giving the first config object in the array the lowest priority.\n return configs.reduce<ConfigReader>(\n (previousReader, { data, context, filteredKeys }) => {\n const reader = new ConfigReader(data, context, previousReader);\n reader.filteredKeys = filteredKeys;\n return reader;\n },\n undefined!,\n );\n }\n\n constructor(\n private readonly data: JsonObject | undefined,\n private readonly context: string = 'mock-config',\n private readonly fallback?: ConfigReader,\n private readonly prefix: string = '',\n ) {}\n\n has(key: string): boolean {\n const value = this.readValue(key);\n if (value !== undefined) {\n return true;\n }\n return this.fallback?.has(key) ?? false;\n }\n\n keys(): string[] {\n const localKeys = this.data ? Object.keys(this.data) : [];\n const fallbackKeys = this.fallback?.keys() ?? [];\n return [...new Set([...localKeys, ...fallbackKeys])];\n }\n\n get<T = JsonValue>(key?: string): T {\n const value = this.getOptional(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key ?? '')));\n }\n return value as T;\n }\n\n getOptional<T = JsonValue>(key?: string): T | undefined {\n const value = this.readValue(key);\n const fallbackValue = this.fallback?.getOptional<T>(key);\n\n if (value === undefined) {\n if (process.env.NODE_ENV === 'development') {\n if (fallbackValue === undefined && key) {\n const fullKey = this.fullKey(key);\n if (\n this.filteredKeys?.includes(fullKey) &&\n !this.notifiedFilteredKeys.has(fullKey)\n ) {\n this.notifiedFilteredKeys.add(fullKey);\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration value at '${fullKey}' as it is not visible. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n }\n return fallbackValue;\n } else if (fallbackValue === undefined) {\n return value as T;\n }\n\n // Avoid merging arrays and primitive values, since that's how merging works for other\n // methods for reading config.\n return mergeWith(\n {},\n { value: cloneDeep(fallbackValue) },\n { value },\n (into, from) => (!isObject(from) || !isObject(into) ? from : undefined),\n ).value as T;\n }\n\n getConfig(key: string): ConfigReader {\n const value = this.getOptionalConfig(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalConfig(key: string): ConfigReader | undefined {\n const value = this.readValue(key);\n const fallbackConfig = this.fallback?.getOptionalConfig(key);\n\n if (isObject(value)) {\n return this.copy(value, key, fallbackConfig);\n }\n if (value !== undefined) {\n throw new TypeError(\n errors.type(this.fullKey(key), this.context, typeOf(value), 'object'),\n );\n }\n return fallbackConfig;\n }\n\n getConfigArray(key: string): ConfigReader[] {\n const value = this.getOptionalConfigArray(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalConfigArray(key: string): ConfigReader[] | undefined {\n const configs = this.readConfigValue<JsonObject[]>(key, values => {\n if (!Array.isArray(values)) {\n return { expected: 'object-array' };\n }\n\n for (const [index, value] of values.entries()) {\n if (!isObject(value)) {\n return { expected: 'object-array', value, key: `${key}[${index}]` };\n }\n }\n return true;\n });\n\n if (!configs) {\n if (process.env.NODE_ENV === 'development') {\n const fullKey = this.fullKey(key);\n if (\n this.filteredKeys?.some(k => k.startsWith(fullKey)) &&\n !this.notifiedFilteredKeys.has(key)\n ) {\n this.notifiedFilteredKeys.add(key);\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration array at '${key}' as it does not have any visible elements. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n return undefined;\n }\n\n return configs.map((obj, index) => this.copy(obj, `${key}[${index}]`));\n }\n\n getNumber(key: string): number {\n const value = this.getOptionalNumber(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalNumber(key: string): number | undefined {\n const value = this.readConfigValue<string | number>(\n key,\n val =>\n typeof val === 'number' ||\n typeof val === 'string' || { expected: 'number' },\n );\n if (typeof value === 'number' || value === undefined) {\n return value;\n }\n const number = Number(value);\n if (!Number.isFinite(number)) {\n throw new Error(\n errors.convert(this.fullKey(key), this.context, 'number'),\n );\n }\n return number;\n }\n\n getBoolean(key: string): boolean {\n const value = this.getOptionalBoolean(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalBoolean(key: string): boolean | undefined {\n return this.readConfigValue(\n key,\n value => typeof value === 'boolean' || { expected: 'boolean' },\n );\n }\n\n getString(key: string): string {\n const value = this.getOptionalString(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalString(key: string): string | undefined {\n return this.readConfigValue(\n key,\n value =>\n (typeof value === 'string' && value !== '') || { expected: 'string' },\n );\n }\n\n getStringArray(key: string): string[] {\n const value = this.getOptionalStringArray(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n getOptionalStringArray(key: string): string[] | undefined {\n return this.readConfigValue(key, values => {\n if (!Array.isArray(values)) {\n return { expected: 'string-array' };\n }\n for (const [index, value] of values.entries()) {\n if (typeof value !== 'string' || value === '') {\n return { expected: 'string-array', value, key: `${key}[${index}]` };\n }\n }\n return true;\n });\n }\n\n private fullKey(key: string): string {\n return `${this.prefix}${this.prefix ? '.' : ''}${key}`;\n }\n\n private copy(data: JsonObject, key: string, fallback?: ConfigReader) {\n const reader = new ConfigReader(\n data,\n this.context,\n fallback,\n this.fullKey(key),\n );\n reader.filteredKeys = this.filteredKeys;\n return reader;\n }\n\n private readConfigValue<T extends JsonValue>(\n key: string,\n validate: (\n value: JsonValue,\n ) => { expected: string; value?: JsonValue; key?: string } | true,\n ): T | undefined {\n const value = this.readValue(key);\n\n if (value === undefined) {\n if (process.env.NODE_ENV === 'development') {\n const fullKey = this.fullKey(key);\n if (\n this.filteredKeys?.includes(fullKey) &&\n !this.notifiedFilteredKeys.has(fullKey)\n ) {\n this.notifiedFilteredKeys.add(fullKey);\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration value at '${fullKey}' as it is not visible. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n\n return this.fallback?.readConfigValue(key, validate);\n }\n const result = validate(value);\n if (result !== true) {\n const { key: keyName = key, value: theValue = value, expected } = result;\n throw new TypeError(\n errors.type(\n this.fullKey(keyName),\n this.context,\n typeOf(theValue),\n expected,\n ),\n );\n }\n\n return value as T;\n }\n\n private readValue(key?: string): JsonValue | undefined {\n const parts = key ? key.split('.') : [];\n for (const part of parts) {\n if (!CONFIG_KEY_PART_PATTERN.test(part)) {\n throw new TypeError(`Invalid config key '${key}'`);\n }\n }\n\n if (this.data === undefined) {\n return undefined;\n }\n\n let value: JsonValue | undefined = this.data;\n for (const [index, part] of parts.entries()) {\n if (isObject(value)) {\n value = value[part];\n } else if (value !== undefined) {\n const badKey = this.fullKey(parts.slice(0, index).join('.'));\n throw new TypeError(\n errors.type(badKey, this.context, typeOf(value), 'object'),\n );\n }\n }\n\n return value;\n }\n}\n"],"names":[],"mappings":"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"}
{
"name": "@backstage/config",
"description": "Config API used by Backstage core, backend, and CLI",
"version": "0.0.0-nightly-20217521743",
"version": "0.0.0-nightly-202181822218",
"private": false,

@@ -33,3 +33,3 @@ "publishConfig": {

"dependencies": {
"lodash": "^4.17.15"
"lodash": "^4.17.21"
},

@@ -36,0 +36,0 @@ "devDependencies": {