Skip to content

Commit fca2c16

Browse files
committed
Fix ambiguity check in configuration object construction
1 parent 0a9e02d commit fca2c16

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed

src/AzureAppConfigurationImpl.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,17 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
203203
}
204204
// The path has been occupied by a non-object value, causing ambiguity.
205205
if (typeof current[segment] !== "object") {
206-
throw new Error(`The key '${segments.slice(0, i + 1).join(separator)}' is not a valid path.`);
206+
throw new Error(`Ambiguity occurs when constructing configuration object from key '${key}', value '${value}'. The path '${segments.slice(0, i + 1).join(separator)}' has been occupied.`);
207207
}
208208
current = current[segment];
209209
}
210+
211+
const lastSegment = segments[segments.length - 1];
212+
if (current[lastSegment] !== undefined) {
213+
throw new Error(`Ambiguity occurs when constructing configuration object from key '${key}', value '${value}'. The key should not be part of another key.`);
214+
}
210215
// set value to the last segment
211-
current[segments[segments.length - 1]] = value;
216+
current[lastSegment] = value;
212217
}
213218
return data;
214219
}

test/load.test.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ const mockedKVs = [{
4444
}, {
4545
key: "app4.excludedFolders.1",
4646
value: "dist"
47-
}
47+
}, {
48+
key: "app5.settings.fontColor",
49+
value: "yellow"
50+
}, {
51+
key: "app5.settings",
52+
value: "placeholder"
53+
},
4854
].map(createMockedKeyValue);
4955

5056
describe("load", function () {
@@ -233,7 +239,7 @@ describe("load", function () {
233239
* get() will return "placeholder" for "app3.settings" and "yellow" for "app3.settings.fontColor", as expected.
234240
* data.app3.settings will return "placeholder" as a whole JSON object, which is not guarenteed to be correct.
235241
*/
236-
it("Edge case: Hierarchical key-value pairs with overlapped key prefix.", async () => {
242+
it("Edge case 1: Hierarchical key-value pairs with overlapped key prefix.", async () => {
237243
const connectionString = createMockedConnectionString();
238244
const settings = await load(connectionString, {
239245
selectors: [{
@@ -243,7 +249,28 @@ describe("load", function () {
243249
expect(settings).not.undefined;
244250
expect(() => {
245251
settings.constructConfigurationObject();
246-
}).to.throw("The key 'app3.settings' is not a valid path.");
252+
}).to.throw("Ambiguity occurs when constructing configuration object from key 'app3.settings.fontColor', value 'yellow'. The path 'app3.settings' has been occupied.");
253+
});
254+
255+
/**
256+
* Edge case: Hierarchical key-value pairs with overlapped key prefix.
257+
* key: "app5.settings.fontColor" => value: "yellow"
258+
* key: "app5.settings" => value: "placeholder"
259+
*
260+
* When ocnstructConfigurationObject() is called, it first constructs from key "app5.settings.fontColor" and then from key "app5.settings".
261+
* An error will be thrown when constructing from key "app5.settings" because there is ambiguity between the two keys.
262+
*/
263+
it("Edge case 1: Hierarchical key-value pairs with overlapped key prefix.", async () => {
264+
const connectionString = createMockedConnectionString();
265+
const settings = await load(connectionString, {
266+
selectors: [{
267+
keyFilter: "app5.settings*"
268+
}]
269+
});
270+
expect(settings).not.undefined;
271+
expect(() => {
272+
settings.constructConfigurationObject();
273+
}).to.throw("Ambiguity occurs when constructing configuration object from key 'app5.settings', value 'placeholder'. The key should not be part of another key.");
247274
});
248275

249276
it("should construct configuration object with array", async () => {

0 commit comments

Comments
 (0)