33
44import { AppConfigurationClient , ConfigurationSetting , ConfigurationSettingId , GetConfigurationSettingOptions , GetConfigurationSettingResponse , ListConfigurationSettingsOptions } from "@azure/app-configuration" ;
55import { RestError } from "@azure/core-rest-pipeline" ;
6- import { AzureAppConfiguration } from "./AzureAppConfiguration" ;
6+ import { AzureAppConfiguration , HierarchicalDataConversionOptions } from "./AzureAppConfiguration" ;
77import { AzureAppConfigurationOptions } from "./AzureAppConfigurationOptions" ;
88import { IKeyValueAdapter } from "./IKeyValueAdapter" ;
99import { JsonKeyValueAdapter } from "./JsonKeyValueAdapter" ;
@@ -16,16 +16,6 @@ import { createCorrelationContextHeader, requestTracingEnabled } from "./request
1616import { KeyFilter , LabelFilter , SettingSelector } from "./types" ;
1717
1818export class AzureAppConfigurationImpl implements AzureAppConfiguration {
19- /**
20- * App Configuration data
21- */
22- readonly data : { [ key : string ] : any } = { } ;
23-
24- /**
25- * Separator for hierarchical keys.
26- */
27- readonly #SEP: string = "." ;
28-
2919 /**
3020 * Hosting key-value pairs in the configuration store.
3121 */
@@ -178,8 +168,6 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
178168 for ( const [ k , v ] of keyValues ) {
179169 this . #configMap. set ( k , v ) ;
180170 }
181- // also construct hierarchical data object from map
182- this . #constructDataFromMap( ) ;
183171 }
184172
185173 /**
@@ -193,30 +181,52 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
193181
194182 /**
195183 * Construct hierarchical data object from map.
196- *
197- * @remarks
198- * This method is used to construct hierarchical data object from map, and it is called after the initial load and each refresh.
199184 */
200- #constructDataFromMap ( ) {
201- // clean data object in-place
202- for ( const key of Object . keys ( this . data ) ) {
203- delete this . data [ key ] ;
204- }
185+ toHierarchicalData ( options ?: HierarchicalDataConversionOptions ) : Record < string , any > {
186+ const separator = options ?. separator ?? "." ;
187+ const prefix = options ?. prefix ?? "" ;
188+ const onError = options ?. onError ?? "error" ;
189+
205190 // construct hierarchical data object from map
191+ const data : Record < string , any > = { } ;
206192 for ( const [ key , value ] of this . #configMap) {
207- const segments = key . split ( this . #SEP) ;
208- let current = this . data ;
209- // construct hierarchical data object along the path
210- for ( let i = 0 ; i < segments . length - 1 ; i ++ ) {
211- const segment = segments [ i ] ;
212- if ( typeof current [ segment ] !== "object" ) { // Note: it overwrites existing value if it's not an object
213- current [ segment ] = { } ;
193+ if ( key . startsWith ( prefix ) ) {
194+ const segments = key . slice ( prefix . length ) . split ( separator ) ;
195+ let current = data ;
196+ // construct hierarchical data object along the path
197+ for ( let i = 0 ; i < segments . length - 1 ; i ++ ) {
198+ const segment = segments [ i ] ;
199+ // undefined or empty string
200+ if ( ! segment ) {
201+ if ( onError === "error" ) {
202+ throw new Error ( `invalid key: ${ key } ` ) ;
203+ } else if ( onError === "ignore" ) {
204+ continue ;
205+ } else {
206+ throw new Error ( `The value of 'onError' is not supported: ${ onError } ` ) ;
207+ }
208+ }
209+ // create path if not exist
210+ if ( current [ segment ] === undefined ) {
211+ current [ segment ] = { } ;
212+ }
213+ // The path has been occupied by a non-object value, causing ambiguity.
214+ if ( typeof current [ segment ] !== "object" ) {
215+ if ( onError === "error" ) {
216+ throw new Error ( `The key '${ prefix } ${ segments . slice ( 0 , i + 1 ) . join ( separator ) } ' is not a valid path.` ) ;
217+ } else if ( onError === "ignore" ) {
218+ current [ segment ] = { } ; // overwrite the non-object value
219+ } else {
220+ throw new Error ( `The value of 'onError' is not supported: ${ onError } ` ) ;
221+ }
222+ }
223+ current = current [ segment ] ;
214224 }
215- current = current [ segment ] ;
225+ // set value to the last segment
226+ current [ segments [ segments . length - 1 ] ] = value ;
216227 }
217- // set value to the last segment
218- current [ segments [ segments . length - 1 ] ] = value ;
219228 }
229+ return data ;
220230 }
221231
222232 /**
0 commit comments