Repository: microsoft/vscode (TypeScript)
Date: 2021-07-17 11:41:45+00:00
Task type: Bug Fix

Issue:
workspace.getConfiguration() fails to retrieve empty string keys in configuration variables
Issue Type: <b>Bug</b>

I currently store some arbitrary JSON-serializable object using `workspace.getConfiguration()` and updating keys. At the top level, my configuration variable is an array, and each element is a dictionary that contains some keys. 

One of those keys map to a value like this:
```
                    "A": {
                        "B": {
                            "C": [
                                "a",
                                "b",
                                "c",
                                "d"
                            ],
                            "": [
                                "e"
                            ]
                        }
                    }
```

This sets fine, and I can look in my workspace's `settings.json` to see all keys and values there as expected. However, when I try to get the value from the workspace configuration again, the empty string key `""` and its value are missing, meaning I unable to retrieve the array with `"e"` in it.  So it seems VSCode filters out keys which are blank strings when reading workspace configurations, although it will set/save them. 

This is currently blocking a project I'm working on and should be a trivial fix.

VS Code version: Code 1.57.1 (507ce72a4466fbb27b715c3722558bb15afa9f48, 2021-06-17T13:28:07.755Z)
OS version: Windows_NT x64 10.0.19041
Restricted Mode: No

<!-- generated by issue reporter -->


Issue discussion:
I am sorry that I do not understand the usage of the API here and what is being done. Can you please provide a sample code snippet to reproduce the issue? 
Here's a round trip example of me saving an object to the workspace configuration, and retrieving it. It shows all data is stored appropriately, but data is lost when reading it back if a blank string key exists.
```typescript
	// Obtain the workspace configuration
        let workspaceConfiguration = vscode.workspace.getConfiguration("testConfig");

	// Store an object with a blank key in our workspace configuration
	let obj = {
		A: "FIRST",
		B: "SECOND",
		"": "THIRD" // this is the culprit, it will be stored but not retrieved back
	};
	workspaceConfiguration.update('testObject', obj);

	// This results in the following settings.json (note all key-value pairs are stored appropriately):
	/*
		{
			"testConfig.testObject": {
				"A": "FIRST",
				"B": "SECOND",
				"": "THIRD"
			}
		}
	*/

	// Now read the test object back.
	workspaceConfiguration = vscode.workspace.getConfiguration("testConfig");
	let obj2 = workspaceConfiguration.get('testObject');

	// obj2 contents are as follows (note the missing key with the value "THIRD"):
	/*
		{A: 'FIRST', B: 'SECOND'}
	*/

	if (JSON.stringify(obj) === JSON.stringify(obj2)) {
		vscode.window.showInformationMessage('getConfiguration() has no bug');
	}
	else {
		vscode.window.showInformationMessage('getConfiguration() has a bug');
	}
```

@sandy081 The message `getConfiguration() has a bug` will be shown. If you comment out/remove the key-value pair `"": "THIRD"` in `obj`, it will instead say `getConfiguration() has no bug`. So VSCode is losing data when obtaining data from the workspace configuration if you store an object which has a blank key somewhere (at any level of depth).
There was a fairly quick initial response here, but since then a good amount of time has elapsed. Has there been any progress updates or planning related to this issue? Can you confirm you now understand the issue given the above proof-of-concept? It should be very clear. @sandy081 
Thanks for the info. It is in my list of issues to investigate, I will try it out and get back to you.

Solution patch:
diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts
--- a/src/vs/platform/configuration/common/configurationModels.ts
+++ b/src/vs/platform/configuration/common/configurationModels.ts
@@ -270,7 +270,7 @@ export class ConfigurationModelParser {
 		function onValue(value: any) {
 			if (Array.isArray(currentParent)) {
 				(<any[]>currentParent).push(value);
-			} else if (currentProperty) {
+			} else if (currentProperty !== null) {
 				currentParent[currentProperty] = value;
 			}
 		}


Test patch:
diff --git a/src/vs/platform/configuration/test/common/configurationModels.test.ts b/src/vs/platform/configuration/test/common/configurationModels.test.ts
--- a/src/vs/platform/configuration/test/common/configurationModels.test.ts
+++ b/src/vs/platform/configuration/test/common/configurationModels.test.ts
@@ -334,6 +334,16 @@ suite('CustomConfigurationModel', () => {
 		assert.deepStrictEqual(testObject.configurationModel.keys, []);
 	});
 
+	test('Test empty property is not ignored', () => {
+		const testObject = new ConfigurationModelParser('test');
+		testObject.parse(JSON.stringify({ '': 1 }));
+
+		// deepStrictEqual seems to ignore empty properties, fall back
+		// to comparing the output of JSON.stringify
+		assert.strictEqual(JSON.stringify(testObject.configurationModel.contents), JSON.stringify({ '': 1 }));
+		assert.deepStrictEqual(testObject.configurationModel.keys, ['']);
+	});
+
 	test('Test registering the same property again', () => {
 		Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
 			'id': 'a',