Skip to content

Commit d9b0a6f

Browse files
authored
fix bug on parsing specicial JSON values (#15)
1 parent 3b7ec10 commit d9b0a6f

File tree

3 files changed

+62
-19
lines changed

3 files changed

+62
-19
lines changed

src/JsonKeyValueAdapter.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@ export class JsonKeyValueAdapter implements IKeyValueAdapter {
2222
}
2323

2424
public async processKeyValue(setting: ConfigurationSetting): Promise<[string, unknown]> {
25-
if (!setting.value) {
26-
throw new Error("Unexpected empty value for application/json content type.");
27-
}
2825
let parsedValue: unknown;
29-
try {
30-
parsedValue = JSON.parse(setting.value);
31-
} catch (error) {
26+
if (setting.value !== undefined) {
27+
try {
28+
parsedValue = JSON.parse(setting.value);
29+
} catch (error) {
30+
parsedValue = setting.value;
31+
}
32+
} else {
3233
parsedValue = setting.value;
3334
}
3435
return [setting.key, parsedValue];

test/json.test.js

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,15 @@ const {
1010
mockAppConfigurationClientListConfigurationSettings,
1111
restoreMocks,
1212
createMockedConnectionString,
13-
createMockedKeyVaultReference
13+
createMockedKeyVaultReference,
14+
createMockedJsonKeyValue
1415
} = require("./utils/testHelper");
1516

16-
const jsonKeyValue = {
17-
value: '{"Test":{"Level":"Debug"},"Prod":{"Level":"Warning"}}',
18-
key: "json.settings.logging",
19-
label: null,
20-
contentType: "application/json",
21-
lastModified: "2023-05-04T04:32:56.000Z",
22-
tags: {},
23-
etag: "GdmsLWq3mFjFodVEXUYRmvFr3l_qRiKAW_KdpFbxZKk",
24-
isReadOnly: false
25-
};
17+
const jsonKeyValue = createMockedJsonKeyValue("json.settings.logging", '{"Test":{"Level":"Debug"},"Prod":{"Level":"Warning"}}');
2618
const keyVaultKeyValue = createMockedKeyVaultReference("TestKey", "https://fake-vault-name.vault.azure.net/secrets/fakeSecretName");
2719

2820
describe("json", function () {
29-
beforeEach(() => {
21+
beforeEach(() => {
3022
});
3123

3224
afterEach(() => {
@@ -49,7 +41,7 @@ describe("json", function () {
4941

5042
it("should not parse key-vault reference", async () => {
5143
mockAppConfigurationClientListConfigurationSettings([jsonKeyValue, keyVaultKeyValue]);
52-
44+
5345
const connectionString = createMockedConnectionString();
5446
const settings = await load(connectionString, {
5547
keyVaultOptions: {
@@ -62,4 +54,42 @@ describe("json", function () {
6254
expect(resolvedSecret.uri).undefined;
6355
expect(typeof resolvedSecret).eq("string");
6456
});
57+
58+
it("should parse different kinds of legal values", async () => {
59+
mockAppConfigurationClientListConfigurationSettings([
60+
/**
61+
* A JSON value MUST be an object, array, number, or string, false, null, true
62+
* See https://www.ietf.org/rfc/rfc4627.txt
63+
*/
64+
createMockedJsonKeyValue("json.settings.object", "{}"),
65+
createMockedJsonKeyValue("json.settings.array", "[]"),
66+
createMockedJsonKeyValue("json.settings.number", "8"),
67+
createMockedJsonKeyValue("json.settings.string", "string"),
68+
createMockedJsonKeyValue("json.settings.false", "false"),
69+
createMockedJsonKeyValue("json.settings.true", "true"),
70+
createMockedJsonKeyValue("json.settings.null", "null"),
71+
createMockedJsonKeyValue("json.settings.literalNull", null), // possible value via Portal's advanced edit.
72+
// Special tricky values related to JavaScript
73+
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean#boolean_coercion
74+
createMockedJsonKeyValue("json.settings.zero", 0),
75+
createMockedJsonKeyValue("json.settings.emptyString", ""), // should fail JSON.parse and use string value as fallback
76+
createMockedJsonKeyValue("json.settings.illegalString", "[unclosed"), // should fail JSON.parse
77+
78+
]);
79+
const connectionString = createMockedConnectionString();
80+
const settings = await load(connectionString);
81+
expect(settings).not.undefined;
82+
expect(typeof settings.get("json.settings.object")).eq("object", "is object");
83+
expect(Object.keys(settings.get("json.settings.object")).length).eq(0, "is empty object");
84+
expect(Array.isArray(settings.get("json.settings.array"))).eq(true, "is array");
85+
expect(settings.get("json.settings.number")).eq(8, "is number");
86+
expect(settings.get("json.settings.string")).eq("string", "is string");
87+
expect(settings.get("json.settings.false")).eq(false, "is false");
88+
expect(settings.get("json.settings.true")).eq(true, "is true");
89+
expect(settings.get("json.settings.null")).eq(null, "is null");
90+
expect(settings.get("json.settings.literalNull")).eq(null, "is literal null");
91+
expect(settings.get("json.settings.zero")).eq(0, "is zero");
92+
expect(settings.get("json.settings.emptyString")).eq("", "is empty string");
93+
expect(settings.get("json.settings.illegalString")).eq("[unclosed", "is illegal string");
94+
});
6595
})

test/utils/testHelper.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ const createMockedKeyVaultReference = (key, vaultUri) => ({
6363
isReadOnly: false,
6464
});
6565

66+
const createMockedJsonKeyValue = (key, value) => ({
67+
value: value,
68+
key: key,
69+
label: null,
70+
contentType: "application/json",
71+
lastModified: "2023-05-04T04:32:56.000Z",
72+
tags: {},
73+
etag: "GdmsLWq3mFjFodVEXUYRmvFr3l_qRiKAW_KdpFbxZKk",
74+
isReadOnly: false
75+
});
76+
6677
module.exports = {
6778
sinon,
6879
mockAppConfigurationClientListConfigurationSettings,
@@ -73,4 +84,5 @@ module.exports = {
7384
createMockedConnectionString,
7485
createMockedTokenCredential,
7586
createMockedKeyVaultReference,
87+
createMockedJsonKeyValue
7688
}

0 commit comments

Comments
 (0)