@backstage/config
Advanced tools
+25
-1
| # @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 @@ |
@@ -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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"} |
+113
-0
@@ -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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"} |
+2
-2
| { | ||
| "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": { |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
62494
11.06%689
21.3%Updated