@theia/core 1.74.0-next.68 → 1.74.0-next.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/common/preferences/preference-provider.d.ts +15 -0
- package/lib/common/preferences/preference-provider.d.ts.map +1 -1
- package/lib/common/preferences/preference-provider.js +21 -1
- package/lib/common/preferences/preference-provider.js.map +1 -1
- package/lib/common/preferences/preference-provider.spec.js +17 -0
- package/lib/common/preferences/preference-provider.spec.js.map +1 -1
- package/package.json +4 -4
- package/src/common/preferences/preference-provider.spec.ts +17 -0
- package/src/common/preferences/preference-provider.ts +22 -1
|
@@ -103,6 +103,21 @@ export interface PreferenceProvider extends Disposable {
|
|
|
103
103
|
getPreferences(resourceUri?: string): JSONObject;
|
|
104
104
|
}
|
|
105
105
|
export declare namespace PreferenceUtils {
|
|
106
|
+
/**
|
|
107
|
+
* Recursively merges the values of `target` into `source` and returns the merged result.
|
|
108
|
+
*
|
|
109
|
+
* Note the direction: `source` is the accumulator that is mutated and returned, while the
|
|
110
|
+
* values of `target` take precedence for conflicting primitive values. Nested objects are
|
|
111
|
+
* merged recursively and arrays are concatenated (`source` entries first, then `target`).
|
|
112
|
+
* If `source` is not a JSON object, a deep copy of `target` is returned instead.
|
|
113
|
+
*
|
|
114
|
+
* Only own properties are considered and reserved keys are ignored, so merged results are
|
|
115
|
+
* always plain data objects.
|
|
116
|
+
*
|
|
117
|
+
* @param source the accumulator to merge into; mutated and returned unless it is not an object
|
|
118
|
+
* @param target the values that are merged into `source` and take precedence on conflicts
|
|
119
|
+
* @returns the merged result (the mutated `source`, or a deep copy of `target`)
|
|
120
|
+
*/
|
|
106
121
|
function merge(source: JSONValue | undefined, target: JSONValue): JSONValue;
|
|
107
122
|
/**
|
|
108
123
|
* Handles deep equality with the possibility of `undefined`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preference-provider.d.ts","sourceRoot":"","sources":["../../../src/common/preferences/preference-provider.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAW,UAAU,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAE5D,MAAM,WAAW,4BAA4B;IACzC;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,yBAAiB,4BAA4B,CAAC;IAC1C,SAAgB,OAAO,CAAC,MAAM,EAAE,4BAA4B,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAI3F;CACJ;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACtC,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,KAAK,CAAC,EAAE,CAAC,CAAA;CACZ;AAED,MAAM,WAAW,6BAA6B;IAC1C,CAAC,cAAc,EAAE,MAAM,GAAG,4BAA4B,CAAC;CAC1D;AACD,eAAO,MAAM,kBAAkB,eAA+B,CAAC;AAE/D,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IAClD,QAAQ,CAAC,uBAAuB,EAAE,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACvE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAEpB;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC;IAEhD;;;;;;;;OAQG;IACH,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IACpE;;;;;;;;;;OAUG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACpF;;;;;;;;;OASG;IACH,OAAO,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,uBAAuB,CAAC,CAAC,CAAC,CAAC;IAErF;;;;;;OAMG;IACH,YAAY,CAAC,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;IAC3E;;;;;;OAMG;IACH,sBAAsB,CAAC,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;IAErF;;OAEG;IACH,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;CACpD;AAED,yBAAiB,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"preference-provider.d.ts","sourceRoot":"","sources":["../../../src/common/preferences/preference-provider.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAW,UAAU,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAE5D,MAAM,WAAW,4BAA4B;IACzC;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,yBAAiB,4BAA4B,CAAC;IAC1C,SAAgB,OAAO,CAAC,MAAM,EAAE,4BAA4B,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAI3F;CACJ;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACtC,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,KAAK,CAAC,EAAE,CAAC,CAAA;CACZ;AAED,MAAM,WAAW,6BAA6B;IAC1C,CAAC,cAAc,EAAE,MAAM,GAAG,4BAA4B,CAAC;CAC1D;AACD,eAAO,MAAM,kBAAkB,eAA+B,CAAC;AAE/D,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IAClD,QAAQ,CAAC,uBAAuB,EAAE,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACvE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAEpB;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC;IAEhD;;;;;;;;OAQG;IACH,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IACpE;;;;;;;;;;OAUG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACpF;;;;;;;;;OASG;IACH,OAAO,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,uBAAuB,CAAC,CAAC,CAAC,CAAC;IAErF;;;;;;OAMG;IACH,YAAY,CAAC,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;IAC3E;;;;;;OAMG;IACH,sBAAsB,CAAC,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;IAErF;;OAEG;IACH,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;CACpD;AAED,yBAAiB,eAAe,CAAC;IAG7B;;;;;;;;;;;;;;OAcG;IACH,SAAgB,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,SAAS,CAyBjF;IAED;;OAEG;IACH,SAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAIrF;CAEJ"}
|
|
@@ -30,6 +30,22 @@ var PreferenceProviderDataChange;
|
|
|
30
30
|
exports.PreferenceProvider = Symbol('PreferenceProvider');
|
|
31
31
|
var PreferenceUtils;
|
|
32
32
|
(function (PreferenceUtils) {
|
|
33
|
+
const RESERVED_MERGE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
34
|
+
/**
|
|
35
|
+
* Recursively merges the values of `target` into `source` and returns the merged result.
|
|
36
|
+
*
|
|
37
|
+
* Note the direction: `source` is the accumulator that is mutated and returned, while the
|
|
38
|
+
* values of `target` take precedence for conflicting primitive values. Nested objects are
|
|
39
|
+
* merged recursively and arrays are concatenated (`source` entries first, then `target`).
|
|
40
|
+
* If `source` is not a JSON object, a deep copy of `target` is returned instead.
|
|
41
|
+
*
|
|
42
|
+
* Only own properties are considered and reserved keys are ignored, so merged results are
|
|
43
|
+
* always plain data objects.
|
|
44
|
+
*
|
|
45
|
+
* @param source the accumulator to merge into; mutated and returned unless it is not an object
|
|
46
|
+
* @param target the values that are merged into `source` and take precedence on conflicts
|
|
47
|
+
* @returns the merged result (the mutated `source`, or a deep copy of `target`)
|
|
48
|
+
*/
|
|
33
49
|
function merge(source, target) {
|
|
34
50
|
if (source === undefined || !coreutils_1.JSONExt.isObject(source)) {
|
|
35
51
|
return coreutils_1.JSONExt.deepCopy(target);
|
|
@@ -38,7 +54,11 @@ var PreferenceUtils;
|
|
|
38
54
|
return {};
|
|
39
55
|
}
|
|
40
56
|
for (const [key, value] of Object.entries(target)) {
|
|
41
|
-
if (key
|
|
57
|
+
if (RESERVED_MERGE_KEYS.has(key)) {
|
|
58
|
+
// Skip reserved object keys so merged results stay plain data objects.
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
42
62
|
const sourceValue = source[key];
|
|
43
63
|
if (coreutils_1.JSONExt.isObject(sourceValue) && coreutils_1.JSONExt.isObject(value)) {
|
|
44
64
|
merge(sourceValue, value);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preference-provider.js","sourceRoot":"","sources":["../../../src/common/preferences/preference-provider.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;AAEhF,iDAAmE;AAGnE,gCAA6B;AA8B7B,IAAiB,4BAA4B,CAM5C;AAND,WAAiB,4BAA4B;IACzC,SAAgB,OAAO,CAAC,MAAoC,EAAE,WAAoB;QAC9E,MAAM,YAAY,GAAG,WAAW,IAAI,IAAI,SAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC;QAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC7B,OAAO,CAAC,YAAY,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,SAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3G,CAAC;IAJe,oCAAO,UAItB,CAAA;AACL,CAAC,EANgB,4BAA4B,4CAA5B,4BAA4B,QAM5C;AAUY,QAAA,kBAAkB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAqE/D,IAAiB,eAAe,
|
|
1
|
+
{"version":3,"file":"preference-provider.js","sourceRoot":"","sources":["../../../src/common/preferences/preference-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,5 +30,22 @@ describe('PreferenceProviderImpl', () => {
|
|
|
30
30
|
const result = preference_provider_1.PreferenceUtils.merge({ 'configurations': [{ 'name': 'test1', 'request': 'launch' }], 'compounds': [] }, { 'configurations': [{ 'name': 'test2' }] });
|
|
31
31
|
expect(result).deep.equals({ 'configurations': [{ 'name': 'test1', 'request': 'launch' }, { 'name': 'test2' }], 'compounds': [] });
|
|
32
32
|
});
|
|
33
|
+
it('should ignore reserved keys when merging', () => {
|
|
34
|
+
const payload = JSON.parse('{"__proto__":{"injected":"yes"}}');
|
|
35
|
+
const result = preference_provider_1.PreferenceUtils.merge({ 'safe': true }, payload);
|
|
36
|
+
// A modified Object.prototype leaks onto every object, so a freshly created `{}`
|
|
37
|
+
// must not inherit the injected key and the result must stay a plain object.
|
|
38
|
+
expect({}.injected).to.equal(undefined);
|
|
39
|
+
expect(Object.getPrototypeOf(result)).to.equal(Object.prototype);
|
|
40
|
+
expect(result).deep.equals({ 'safe': true });
|
|
41
|
+
});
|
|
42
|
+
it('should ignore nested reserved keys when merging', () => {
|
|
43
|
+
const payload = JSON.parse('{"parent":{"__proto__":{"injected":"yes"},"valid":"true"}}');
|
|
44
|
+
const result = preference_provider_1.PreferenceUtils.merge({ 'parent': { 'existing': true } }, payload);
|
|
45
|
+
// The nested reserved key is dropped while the sibling `valid` is still merged, and a
|
|
46
|
+
// freshly created `{}` must not inherit the injected key.
|
|
47
|
+
expect({}.injected).to.equal(undefined);
|
|
48
|
+
expect(result).deep.equals({ 'parent': { 'existing': true, 'valid': 'true' } });
|
|
49
|
+
});
|
|
33
50
|
});
|
|
34
51
|
//# sourceMappingURL=preference-provider.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preference-provider.spec.js","sourceRoot":"","sources":["../../../src/common/preferences/preference-provider.spec.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,+CAA+C;AAC/C,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;AAEhF,+DAAwD;AAExD,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAEnC,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACpD,MAAM,MAAM,GAAG,qCAAe,CAAC,KAAK,CAAC,EAAE,gBAAgB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1G,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACpD,MAAM,MAAM,GAAG,qCAAe,CAAC,KAAK,CAAC,EAAE,gBAAgB,EAAE,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1G,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACjC,MAAM,MAAM,GAAG,qCAAe,CAAC,KAAK,CAChC,EAAE,gBAAgB,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,EACjF,EAAE,gBAAgB,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,CAC9C,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IACvI,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"preference-provider.spec.js","sourceRoot":"","sources":["../../../src/common/preferences/preference-provider.spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/core",
|
|
3
|
-
"version": "1.74.0-next.
|
|
3
|
+
"version": "1.74.0-next.70+d3cad42d4",
|
|
4
4
|
"description": "Theia is a cloud & desktop IDE framework implemented in TypeScript.",
|
|
5
5
|
"main": "lib/common/index.js",
|
|
6
6
|
"typings": "lib/common/index.d.ts",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"@lumino/virtualdom": "^2.0.4",
|
|
18
18
|
"@lumino/widgets": "2.7.5",
|
|
19
19
|
"@parcel/watcher": "^2.5.6",
|
|
20
|
-
"@theia/application-package": "1.74.0-next.
|
|
21
|
-
"@theia/request": "1.74.0-next.
|
|
20
|
+
"@theia/application-package": "1.74.0-next.70+d3cad42d4",
|
|
21
|
+
"@theia/request": "1.74.0-next.70+d3cad42d4",
|
|
22
22
|
"@types/body-parser": "^1.19.6",
|
|
23
23
|
"@types/express": "^4.17.25",
|
|
24
24
|
"@types/fs-extra": "^4.0.15",
|
|
@@ -230,5 +230,5 @@
|
|
|
230
230
|
"nyc": {
|
|
231
231
|
"extends": "../../configs/nyc.json"
|
|
232
232
|
},
|
|
233
|
-
"gitHead": "
|
|
233
|
+
"gitHead": "d3cad42d4e3220b8b6796d6b40a4441bbe25a0bc"
|
|
234
234
|
}
|
|
@@ -34,4 +34,21 @@ describe('PreferenceProviderImpl', () => {
|
|
|
34
34
|
);
|
|
35
35
|
expect(result).deep.equals({ 'configurations': [{ 'name': 'test1', 'request': 'launch' }, { 'name': 'test2' }], 'compounds': [] });
|
|
36
36
|
});
|
|
37
|
+
it('should ignore reserved keys when merging', () => {
|
|
38
|
+
const payload = JSON.parse('{"__proto__":{"injected":"yes"}}');
|
|
39
|
+
const result = PreferenceUtils.merge({ 'safe': true }, payload);
|
|
40
|
+
// A modified Object.prototype leaks onto every object, so a freshly created `{}`
|
|
41
|
+
// must not inherit the injected key and the result must stay a plain object.
|
|
42
|
+
expect(({} as Record<string, unknown>).injected).to.equal(undefined);
|
|
43
|
+
expect(Object.getPrototypeOf(result)).to.equal(Object.prototype);
|
|
44
|
+
expect(result).deep.equals({ 'safe': true });
|
|
45
|
+
});
|
|
46
|
+
it('should ignore nested reserved keys when merging', () => {
|
|
47
|
+
const payload = JSON.parse('{"parent":{"__proto__":{"injected":"yes"},"valid":"true"}}');
|
|
48
|
+
const result = PreferenceUtils.merge({ 'parent': { 'existing': true } }, payload);
|
|
49
|
+
// The nested reserved key is dropped while the sibling `valid` is still merged, and a
|
|
50
|
+
// freshly created `{}` must not inherit the injected key.
|
|
51
|
+
expect(({} as Record<string, unknown>).injected).to.equal(undefined);
|
|
52
|
+
expect(result).deep.equals({ 'parent': { 'existing': true, 'valid': 'true' } });
|
|
53
|
+
});
|
|
37
54
|
});
|
|
@@ -133,6 +133,23 @@ export interface PreferenceProvider extends Disposable {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
export namespace PreferenceUtils {
|
|
136
|
+
const RESERVED_MERGE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Recursively merges the values of `target` into `source` and returns the merged result.
|
|
140
|
+
*
|
|
141
|
+
* Note the direction: `source` is the accumulator that is mutated and returned, while the
|
|
142
|
+
* values of `target` take precedence for conflicting primitive values. Nested objects are
|
|
143
|
+
* merged recursively and arrays are concatenated (`source` entries first, then `target`).
|
|
144
|
+
* If `source` is not a JSON object, a deep copy of `target` is returned instead.
|
|
145
|
+
*
|
|
146
|
+
* Only own properties are considered and reserved keys are ignored, so merged results are
|
|
147
|
+
* always plain data objects.
|
|
148
|
+
*
|
|
149
|
+
* @param source the accumulator to merge into; mutated and returned unless it is not an object
|
|
150
|
+
* @param target the values that are merged into `source` and take precedence on conflicts
|
|
151
|
+
* @returns the merged result (the mutated `source`, or a deep copy of `target`)
|
|
152
|
+
*/
|
|
136
153
|
export function merge(source: JSONValue | undefined, target: JSONValue): JSONValue {
|
|
137
154
|
if (source === undefined || !JSONExt.isObject(source)) {
|
|
138
155
|
return JSONExt.deepCopy(target);
|
|
@@ -141,7 +158,11 @@ export namespace PreferenceUtils {
|
|
|
141
158
|
return {};
|
|
142
159
|
}
|
|
143
160
|
for (const [key, value] of Object.entries(target)) {
|
|
144
|
-
if (key
|
|
161
|
+
if (RESERVED_MERGE_KEYS.has(key)) {
|
|
162
|
+
// Skip reserved object keys so merged results stay plain data objects.
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
145
166
|
const sourceValue = source[key];
|
|
146
167
|
if (JSONExt.isObject(sourceValue) && JSONExt.isObject(value)) {
|
|
147
168
|
merge(sourceValue, value);
|