smartling-api-sdk-nodejs 2.31.0 → 2.31.1
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/api/base/base-api.ts +1 -1
- package/api/base/merge.ts +15 -0
- package/built/api/base/base-api.js +3 -3
- package/built/api/base/base-api.js.map +1 -1
- package/built/api/base/merge.d.ts +1 -0
- package/built/api/base/merge.js +15 -0
- package/built/api/base/merge.js.map +1 -0
- package/built/package.json +7 -7
- package/built/test/base-api-merge.spec.d.ts +1 -0
- package/built/test/base-api-merge.spec.js +226 -0
- package/built/test/base-api-merge.spec.js.map +1 -0
- package/package.json +7 -7
- package/test/base-api-merge.spec.ts +296 -0
package/api/base/base-api.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import merge from "merge-deep";
|
|
2
1
|
import ua from "default-user-agent";
|
|
3
2
|
import FormData from "form-data";
|
|
4
3
|
import fetch from "cross-fetch";
|
|
@@ -7,6 +6,7 @@ import { Logger } from "../logger";
|
|
|
7
6
|
import { SmartlingException } from "../exception/index";
|
|
8
7
|
import { AccessTokenProvider } from "../auth/access-token-provider";
|
|
9
8
|
import { ResponseBodyType } from "./enum/response-body-type";
|
|
9
|
+
import { merge } from "./merge";
|
|
10
10
|
|
|
11
11
|
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
|
|
12
12
|
const packageJson = require("../../package.json");
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import deepmerge from "deepmerge";
|
|
2
|
+
|
|
3
|
+
// Deep-merge arrays as an ordered union: keep the target order, then append
|
|
4
|
+
// items from the source that aren't already present. Prevents header and
|
|
5
|
+
// option arrays from duplicating when a caller's values overlap the defaults.
|
|
6
|
+
const mergeOptions: deepmerge.Options = {
|
|
7
|
+
arrayMerge: (target, source) => source.reduce<unknown[]>(
|
|
8
|
+
(acc, item) => (acc.includes(item) ? acc : [...acc, item]),
|
|
9
|
+
[...target]
|
|
10
|
+
)
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function merge<T, U>(target: T, source: U): T & U {
|
|
14
|
+
return deepmerge<T, U>(target, source, mergeOptions);
|
|
15
|
+
}
|
|
@@ -13,12 +13,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.SmartlingBaseApi = void 0;
|
|
16
|
-
const merge_deep_1 = __importDefault(require("merge-deep"));
|
|
17
16
|
const default_user_agent_1 = __importDefault(require("default-user-agent"));
|
|
18
17
|
const cross_fetch_1 = __importDefault(require("cross-fetch"));
|
|
19
18
|
const querystring_1 = require("querystring");
|
|
20
19
|
const index_1 = require("../exception/index");
|
|
21
20
|
const response_body_type_1 = require("./enum/response-body-type");
|
|
21
|
+
const merge_1 = require("./merge");
|
|
22
22
|
const packageJson = require("../../package.json");
|
|
23
23
|
class SmartlingBaseApi {
|
|
24
24
|
constructor(logger) {
|
|
@@ -68,13 +68,13 @@ class SmartlingBaseApi {
|
|
|
68
68
|
}
|
|
69
69
|
defaultHeaders["Content-Type"] = "application/json";
|
|
70
70
|
defaultHeaders["User-Agent"] = this.ua(this.clientLibId, this.clientLibVersion);
|
|
71
|
-
return (0,
|
|
71
|
+
return (0, merge_1.merge)(defaultHeaders, headers);
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
makeRequest(verb, uri, payload = null, returnRawResponseBody = false, headers = {}) {
|
|
75
75
|
var _a, _b;
|
|
76
76
|
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
-
const opts = (0,
|
|
77
|
+
const opts = (0, merge_1.merge)({
|
|
78
78
|
method: verb,
|
|
79
79
|
headers: yield this.getDefaultHeaders(headers)
|
|
80
80
|
}, this.options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-api.js","sourceRoot":"","sources":["../../../api/base/base-api.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"base-api.js","sourceRoot":"","sources":["../../../api/base/base-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function merge<T, U>(target: T, source: U): T & U;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.merge = void 0;
|
|
7
|
+
const deepmerge_1 = __importDefault(require("deepmerge"));
|
|
8
|
+
const mergeOptions = {
|
|
9
|
+
arrayMerge: (target, source) => source.reduce((acc, item) => (acc.includes(item) ? acc : [...acc, item]), [...target])
|
|
10
|
+
};
|
|
11
|
+
function merge(target, source) {
|
|
12
|
+
return (0, deepmerge_1.default)(target, source, mergeOptions);
|
|
13
|
+
}
|
|
14
|
+
exports.merge = merge;
|
|
15
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../api/base/merge.ts"],"names":[],"mappings":";;;;;;AAAA,0DAAkC;AAKlC,MAAM,YAAY,GAAsB;IACpC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CACzC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,CAAC,CAAC,EAC1D,CAAC,GAAG,MAAM,CAAC,CACd;CACJ,CAAC;AAEF,SAAgB,KAAK,CAAO,MAAS,EAAE,MAAS;IAC5C,OAAO,IAAA,mBAAS,EAAO,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;AACzD,CAAC;AAFD,sBAEC"}
|
package/built/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smartling-api-sdk-nodejs",
|
|
3
|
-
"version": "2.31.
|
|
3
|
+
"version": "2.31.1",
|
|
4
4
|
"description": "Package for Smartling API",
|
|
5
5
|
"main": "built/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -31,19 +31,20 @@
|
|
|
31
31
|
"@types/mocha": "^9.0.0",
|
|
32
32
|
"@types/node": "^18.19.115",
|
|
33
33
|
"cross-fetch": "^3.1.4",
|
|
34
|
+
"deepmerge": "^4.3.1",
|
|
34
35
|
"default-user-agent": "^1.0.0",
|
|
35
36
|
"form-data": "^4.0.4",
|
|
36
|
-
"merge-deep": "^3.0.3",
|
|
37
37
|
"querystring": "^0.2.1",
|
|
38
|
+
"semver": "^5.7.2",
|
|
38
39
|
"string-to-file-stream": "^2.0.0",
|
|
39
|
-
"typescript": "^4.9.5"
|
|
40
|
-
"semver": "^5.7.2"
|
|
40
|
+
"typescript": "^4.9.5"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@typescript-eslint/eslint-plugin": "^4.29.0",
|
|
44
44
|
"@typescript-eslint/parser": "^4.29.0",
|
|
45
45
|
"ansi-regex": "^5.0.1",
|
|
46
46
|
"babel-eslint": "^10.1.0",
|
|
47
|
+
"braces": "^3.0.3",
|
|
47
48
|
"eslint": "^7.31.0",
|
|
48
49
|
"eslint-config-airbnb": "^19.0.4",
|
|
49
50
|
"eslint-plugin-flowtype": "^2.41.0",
|
|
@@ -52,13 +53,12 @@
|
|
|
52
53
|
"eslint-plugin-jsx-a11y": "^6.0.3",
|
|
53
54
|
"eslint-plugin-promise": "^3.6.0",
|
|
54
55
|
"eslint-plugin-react": "^7.10.0",
|
|
56
|
+
"json5": "^1.0.2",
|
|
55
57
|
"mocha": "^10.0.0",
|
|
56
58
|
"mocha-junit-reporter": "^2.0.2",
|
|
57
59
|
"nyc": "^17.1.0",
|
|
58
60
|
"sinon": "^11.1.2",
|
|
59
|
-
"ts-mocha": "^10.0.0"
|
|
60
|
-
"braces": "^3.0.3",
|
|
61
|
-
"json5": "^1.0.2"
|
|
61
|
+
"ts-mocha": "^10.0.0"
|
|
62
62
|
},
|
|
63
63
|
"nyc": {
|
|
64
64
|
"reporter": [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const assert_1 = __importDefault(require("assert"));
|
|
16
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
17
|
+
const index_1 = require("../api/base/index");
|
|
18
|
+
const merge_1 = require("../api/base/merge");
|
|
19
|
+
const mock_1 = require("./mock");
|
|
20
|
+
describe("SmartlingBaseApi deep merge", () => {
|
|
21
|
+
describe("Library-level behavior (direct merge calls)", () => {
|
|
22
|
+
it("overrides a target primitive with the source primitive at the same key", () => {
|
|
23
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ a: 1 }, { a: 2 }), { a: 2 });
|
|
24
|
+
});
|
|
25
|
+
it("combines disjoint keys from target and source", () => {
|
|
26
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ a: 1 }, { b: 2 }), { a: 1, b: 2 });
|
|
27
|
+
});
|
|
28
|
+
it("recursively merges one level of nested objects; source wins on conflicts", () => {
|
|
29
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ headers: { Authorization: "a", "Content-Type": "json" } }, { headers: { "Content-Type": "xml", "X-Custom": "x" } }), {
|
|
30
|
+
headers: {
|
|
31
|
+
Authorization: "a",
|
|
32
|
+
"Content-Type": "xml",
|
|
33
|
+
"X-Custom": "x"
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it("recursively merges multi-level nested objects", () => {
|
|
38
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ a: { b: { c: 1, d: 2 } } }, { a: { b: { d: 20, e: 3 } } }), { a: { b: { c: 1, d: 20, e: 3 } } });
|
|
39
|
+
});
|
|
40
|
+
it("replaces a target primitive with a source object at the same key", () => {
|
|
41
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ a: 1 }, { a: { b: 2 } }), { a: { b: 2 } });
|
|
42
|
+
});
|
|
43
|
+
it("does not mutate the target object", () => {
|
|
44
|
+
const target = { a: 1, b: { c: 2 } };
|
|
45
|
+
const snapshot = JSON.parse(JSON.stringify(target));
|
|
46
|
+
(0, merge_1.merge)(target, { b: { d: 3 } });
|
|
47
|
+
assert_1.default.deepEqual(target, snapshot);
|
|
48
|
+
});
|
|
49
|
+
it("does not mutate the source object", () => {
|
|
50
|
+
const source = { b: { d: 3 } };
|
|
51
|
+
const snapshot = JSON.parse(JSON.stringify(source));
|
|
52
|
+
(0, merge_1.merge)({ a: 1 }, source);
|
|
53
|
+
assert_1.default.deepEqual(source, snapshot);
|
|
54
|
+
});
|
|
55
|
+
it("returns a new object rather than a reference to either input", () => {
|
|
56
|
+
const target = { a: { b: 1 } };
|
|
57
|
+
const source = { c: 2 };
|
|
58
|
+
const result = (0, merge_1.merge)(target, source);
|
|
59
|
+
assert_1.default.notStrictEqual(result, target);
|
|
60
|
+
assert_1.default.notStrictEqual(result.a, target.a);
|
|
61
|
+
});
|
|
62
|
+
it("returns the source content when target is empty", () => {
|
|
63
|
+
assert_1.default.deepEqual((0, merge_1.merge)({}, { a: 1, b: { c: 2 } }), { a: 1, b: { c: 2 } });
|
|
64
|
+
});
|
|
65
|
+
it("returns the target content when source is empty", () => {
|
|
66
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ a: 1, b: { c: 2 } }, {}), { a: 1, b: { c: 2 } });
|
|
67
|
+
});
|
|
68
|
+
it("concatenates disjoint arrays at the same key in source order", () => {
|
|
69
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ items: ["a"] }, { items: ["b", "c"] }), { items: ["a", "b", "c"] });
|
|
70
|
+
});
|
|
71
|
+
it("de-duplicates overlapping array values while preserving order", () => {
|
|
72
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ items: [1, 2, 3] }, { items: [2, 3, 4] }), { items: [1, 2, 3, 4] });
|
|
73
|
+
});
|
|
74
|
+
it("applies the union semantics to arrays at nested paths", () => {
|
|
75
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ group: { items: [1, 2] } }, { group: { items: [2, 3] } }), { group: { items: [1, 2, 3] } });
|
|
76
|
+
});
|
|
77
|
+
it("does not dedupe object array elements by structural equality (reference-based)", () => {
|
|
78
|
+
const result = (0, merge_1.merge)({ x: [{ id: 1 }] }, { x: [{ id: 1 }] });
|
|
79
|
+
assert_1.default.deepEqual(result, { x: [{ id: 1 }, { id: 1 }] });
|
|
80
|
+
});
|
|
81
|
+
it("replaces a target array with a source object at the same key", () => {
|
|
82
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ a: [1, 2] }, { a: { b: 3 } }), { a: { b: 3 } });
|
|
83
|
+
});
|
|
84
|
+
it("replaces a target object with a source array at the same key", () => {
|
|
85
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ a: { b: 3 } }, { a: [1, 2] }), { a: [1, 2] });
|
|
86
|
+
});
|
|
87
|
+
it("keeps a null source value (null replaces target)", () => {
|
|
88
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ a: 1 }, { a: null }), { a: null });
|
|
89
|
+
});
|
|
90
|
+
it("keeps an undefined source value (undefined replaces target)", () => {
|
|
91
|
+
const result = (0, merge_1.merge)({ a: 1 }, { a: undefined });
|
|
92
|
+
assert_1.default.ok("a" in result);
|
|
93
|
+
assert_1.default.strictEqual(result.a, undefined);
|
|
94
|
+
});
|
|
95
|
+
it("replaces a nested target object with a null source", () => {
|
|
96
|
+
assert_1.default.deepEqual((0, merge_1.merge)({ a: { b: 1 } }, { a: null }), { a: null });
|
|
97
|
+
});
|
|
98
|
+
it("does not pollute Object.prototype via a __proto__ key in source", () => {
|
|
99
|
+
const malicious = JSON.parse("{\"__proto__\":{\"polluted\":\"yes\"}}");
|
|
100
|
+
const result = (0, merge_1.merge)({}, malicious);
|
|
101
|
+
assert_1.default.equal({}.polluted, undefined);
|
|
102
|
+
assert_1.default.equal(result.polluted, undefined);
|
|
103
|
+
});
|
|
104
|
+
it("does not pollute Object.prototype via a constructor.prototype key in source", () => {
|
|
105
|
+
const malicious = JSON.parse("{\"constructor\":{\"prototype\":{\"polluted\":\"yes\"}}}");
|
|
106
|
+
(0, merge_1.merge)({}, malicious);
|
|
107
|
+
assert_1.default.equal({}.polluted, undefined);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe("SmartlingBaseApi integration (pins the call-site behavior)", () => {
|
|
111
|
+
let base;
|
|
112
|
+
let uaStub;
|
|
113
|
+
beforeEach(() => {
|
|
114
|
+
base = new index_1.SmartlingBaseApi(mock_1.loggerMock);
|
|
115
|
+
base.authApi = mock_1.authMock;
|
|
116
|
+
uaStub = sinon_1.default.stub(base, "ua");
|
|
117
|
+
uaStub.returns("test_user_agent");
|
|
118
|
+
});
|
|
119
|
+
afterEach(() => {
|
|
120
|
+
uaStub.restore();
|
|
121
|
+
});
|
|
122
|
+
it("getDefaultHeaders: caller-supplied Content-Type overrides the default", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
123
|
+
const headers = yield base.getDefaultHeaders({
|
|
124
|
+
"Content-Type": "application/xml"
|
|
125
|
+
});
|
|
126
|
+
assert_1.default.deepEqual(headers, {
|
|
127
|
+
Authorization: "test_token_type test_access_token",
|
|
128
|
+
"Content-Type": "application/xml",
|
|
129
|
+
"User-Agent": "test_user_agent"
|
|
130
|
+
});
|
|
131
|
+
}));
|
|
132
|
+
it("getDefaultHeaders: caller-supplied Authorization overrides the default", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
133
|
+
const headers = yield base.getDefaultHeaders({ Authorization: "Bearer custom" });
|
|
134
|
+
assert_1.default.equal(headers.Authorization, "Bearer custom");
|
|
135
|
+
assert_1.default.equal(headers["Content-Type"], "application/json");
|
|
136
|
+
assert_1.default.equal(headers["User-Agent"], "test_user_agent");
|
|
137
|
+
}));
|
|
138
|
+
it("getDefaultHeaders: adds new caller-supplied keys while preserving defaults", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
139
|
+
const headers = yield base.getDefaultHeaders({
|
|
140
|
+
"X-SL-ServiceOrigin": "foo",
|
|
141
|
+
"X-Request-Id": "abc-123"
|
|
142
|
+
});
|
|
143
|
+
assert_1.default.deepEqual(headers, {
|
|
144
|
+
Authorization: "test_token_type test_access_token",
|
|
145
|
+
"Content-Type": "application/json",
|
|
146
|
+
"User-Agent": "test_user_agent",
|
|
147
|
+
"X-SL-ServiceOrigin": "foo",
|
|
148
|
+
"X-Request-Id": "abc-123"
|
|
149
|
+
});
|
|
150
|
+
}));
|
|
151
|
+
it("makeRequest: nested non-header option fields survive the options merge", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
152
|
+
const fetchStub = sinon_1.default.stub(base, "fetch").returns(mock_1.responseMock);
|
|
153
|
+
const textStub = sinon_1.default.stub(mock_1.responseMock, "text").returns("{\"response\": {\"data\": {}}}");
|
|
154
|
+
try {
|
|
155
|
+
base.setOptions({
|
|
156
|
+
timeout: 10000,
|
|
157
|
+
agent: { keepAlive: true, maxSockets: 50 }
|
|
158
|
+
});
|
|
159
|
+
yield base.makeRequest("POST", "https://test.com", { foo: "bar" });
|
|
160
|
+
const passedOpts = fetchStub.firstCall.args[1];
|
|
161
|
+
assert_1.default.equal(passedOpts.timeout, 10000);
|
|
162
|
+
assert_1.default.deepEqual(passedOpts.agent, { keepAlive: true, maxSockets: 50 });
|
|
163
|
+
assert_1.default.equal(passedOpts.method, "POST");
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
textStub.restore();
|
|
167
|
+
fetchStub.restore();
|
|
168
|
+
}
|
|
169
|
+
}));
|
|
170
|
+
it("makeRequest: options.headers deep-merge with the default headers (source wins on conflicts)", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
171
|
+
const fetchStub = sinon_1.default.stub(base, "fetch").returns(mock_1.responseMock);
|
|
172
|
+
const textStub = sinon_1.default.stub(mock_1.responseMock, "text").returns("{\"response\": {\"data\": {}}}");
|
|
173
|
+
try {
|
|
174
|
+
base.setOptions({
|
|
175
|
+
headers: {
|
|
176
|
+
"X-SL-ServiceOrigin": "foo-bar",
|
|
177
|
+
"Content-Type": "application/xml"
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
yield base.makeRequest("POST", "https://test.com", { foo: "bar" });
|
|
181
|
+
const passedOpts = fetchStub.firstCall.args[1];
|
|
182
|
+
assert_1.default.deepEqual(passedOpts.headers, {
|
|
183
|
+
Authorization: "test_token_type test_access_token",
|
|
184
|
+
"Content-Type": "application/xml",
|
|
185
|
+
"User-Agent": "test_user_agent",
|
|
186
|
+
"X-SL-ServiceOrigin": "foo-bar"
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
textStub.restore();
|
|
191
|
+
fetchStub.restore();
|
|
192
|
+
}
|
|
193
|
+
}));
|
|
194
|
+
it("makeRequest: array-valued header options are unioned, not duplicated", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
195
|
+
const fetchStub = sinon_1.default.stub(base, "fetch").returns(mock_1.responseMock);
|
|
196
|
+
const textStub = sinon_1.default.stub(mock_1.responseMock, "text").returns("{\"response\": {\"data\": {}}}");
|
|
197
|
+
try {
|
|
198
|
+
base.setOptions({
|
|
199
|
+
headers: { "Accept-Language": ["en", "fr"] }
|
|
200
|
+
});
|
|
201
|
+
yield base.makeRequest("POST", "https://test.com", { foo: "bar" }, false, { "Accept-Language": ["en", "de"] });
|
|
202
|
+
const passedOpts = fetchStub.firstCall.args[1];
|
|
203
|
+
assert_1.default.deepEqual(passedOpts.headers["Accept-Language"], ["en", "de", "fr"]);
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
textStub.restore();
|
|
207
|
+
fetchStub.restore();
|
|
208
|
+
}
|
|
209
|
+
}));
|
|
210
|
+
it("makeRequest: calling setOptions does not mutate the caller-provided object", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
211
|
+
const fetchStub = sinon_1.default.stub(base, "fetch").returns(mock_1.responseMock);
|
|
212
|
+
const textStub = sinon_1.default.stub(mock_1.responseMock, "text").returns("{\"response\": {\"data\": {}}}");
|
|
213
|
+
try {
|
|
214
|
+
const userOptions = { headers: { "X-Custom": "first" } };
|
|
215
|
+
base.setOptions(userOptions);
|
|
216
|
+
yield base.makeRequest("POST", "https://test.com", { foo: "bar" });
|
|
217
|
+
assert_1.default.deepEqual(userOptions, { headers: { "X-Custom": "first" } });
|
|
218
|
+
}
|
|
219
|
+
finally {
|
|
220
|
+
textStub.restore();
|
|
221
|
+
fetchStub.restore();
|
|
222
|
+
}
|
|
223
|
+
}));
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
//# sourceMappingURL=base-api-merge.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-api-merge.spec.js","sourceRoot":"","sources":["../../test/base-api-merge.spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smartling-api-sdk-nodejs",
|
|
3
|
-
"version": "2.31.
|
|
3
|
+
"version": "2.31.1",
|
|
4
4
|
"description": "Package for Smartling API",
|
|
5
5
|
"main": "built/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -31,19 +31,20 @@
|
|
|
31
31
|
"@types/mocha": "^9.0.0",
|
|
32
32
|
"@types/node": "^18.19.115",
|
|
33
33
|
"cross-fetch": "^3.1.4",
|
|
34
|
+
"deepmerge": "^4.3.1",
|
|
34
35
|
"default-user-agent": "^1.0.0",
|
|
35
36
|
"form-data": "^4.0.4",
|
|
36
|
-
"merge-deep": "^3.0.3",
|
|
37
37
|
"querystring": "^0.2.1",
|
|
38
|
+
"semver": "^5.7.2",
|
|
38
39
|
"string-to-file-stream": "^2.0.0",
|
|
39
|
-
"typescript": "^4.9.5"
|
|
40
|
-
"semver": "^5.7.2"
|
|
40
|
+
"typescript": "^4.9.5"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@typescript-eslint/eslint-plugin": "^4.29.0",
|
|
44
44
|
"@typescript-eslint/parser": "^4.29.0",
|
|
45
45
|
"ansi-regex": "^5.0.1",
|
|
46
46
|
"babel-eslint": "^10.1.0",
|
|
47
|
+
"braces": "^3.0.3",
|
|
47
48
|
"eslint": "^7.31.0",
|
|
48
49
|
"eslint-config-airbnb": "^19.0.4",
|
|
49
50
|
"eslint-plugin-flowtype": "^2.41.0",
|
|
@@ -52,13 +53,12 @@
|
|
|
52
53
|
"eslint-plugin-jsx-a11y": "^6.0.3",
|
|
53
54
|
"eslint-plugin-promise": "^3.6.0",
|
|
54
55
|
"eslint-plugin-react": "^7.10.0",
|
|
56
|
+
"json5": "^1.0.2",
|
|
55
57
|
"mocha": "^10.0.0",
|
|
56
58
|
"mocha-junit-reporter": "^2.0.2",
|
|
57
59
|
"nyc": "^17.1.0",
|
|
58
60
|
"sinon": "^11.1.2",
|
|
59
|
-
"ts-mocha": "^10.0.0"
|
|
60
|
-
"braces": "^3.0.3",
|
|
61
|
-
"json5": "^1.0.2"
|
|
61
|
+
"ts-mocha": "^10.0.0"
|
|
62
62
|
},
|
|
63
63
|
"nyc": {
|
|
64
64
|
"reporter": [
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import sinon from "sinon";
|
|
3
|
+
import { SmartlingBaseApi } from "../api/base/index";
|
|
4
|
+
import { merge } from "../api/base/merge";
|
|
5
|
+
import { loggerMock, responseMock, authMock } from "./mock";
|
|
6
|
+
|
|
7
|
+
describe("SmartlingBaseApi deep merge", () => {
|
|
8
|
+
describe("Library-level behavior (direct merge calls)", () => {
|
|
9
|
+
it("overrides a target primitive with the source primitive at the same key", () => {
|
|
10
|
+
assert.deepEqual(merge({ a: 1 }, { a: 2 }), { a: 2 });
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("combines disjoint keys from target and source", () => {
|
|
14
|
+
assert.deepEqual(merge({ a: 1 }, { b: 2 }), { a: 1, b: 2 });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("recursively merges one level of nested objects; source wins on conflicts", () => {
|
|
18
|
+
assert.deepEqual(
|
|
19
|
+
merge(
|
|
20
|
+
{ headers: { Authorization: "a", "Content-Type": "json" } },
|
|
21
|
+
{ headers: { "Content-Type": "xml", "X-Custom": "x" } }
|
|
22
|
+
),
|
|
23
|
+
{
|
|
24
|
+
headers: {
|
|
25
|
+
Authorization: "a",
|
|
26
|
+
"Content-Type": "xml",
|
|
27
|
+
"X-Custom": "x"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("recursively merges multi-level nested objects", () => {
|
|
34
|
+
assert.deepEqual(
|
|
35
|
+
merge({ a: { b: { c: 1, d: 2 } } }, { a: { b: { d: 20, e: 3 } } }),
|
|
36
|
+
{ a: { b: { c: 1, d: 20, e: 3 } } }
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("replaces a target primitive with a source object at the same key", () => {
|
|
41
|
+
assert.deepEqual(merge({ a: 1 }, { a: { b: 2 } }), { a: { b: 2 } });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("does not mutate the target object", () => {
|
|
45
|
+
const target = { a: 1, b: { c: 2 } };
|
|
46
|
+
const snapshot = JSON.parse(JSON.stringify(target));
|
|
47
|
+
merge(target, { b: { d: 3 } });
|
|
48
|
+
assert.deepEqual(target, snapshot);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("does not mutate the source object", () => {
|
|
52
|
+
const source = { b: { d: 3 } };
|
|
53
|
+
const snapshot = JSON.parse(JSON.stringify(source));
|
|
54
|
+
merge({ a: 1 }, source);
|
|
55
|
+
assert.deepEqual(source, snapshot);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("returns a new object rather than a reference to either input", () => {
|
|
59
|
+
const target = { a: { b: 1 } };
|
|
60
|
+
const source = { c: 2 };
|
|
61
|
+
const result = merge(target, source);
|
|
62
|
+
assert.notStrictEqual(result, target);
|
|
63
|
+
assert.notStrictEqual(result.a, target.a);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("returns the source content when target is empty", () => {
|
|
67
|
+
assert.deepEqual(merge({}, { a: 1, b: { c: 2 } }), { a: 1, b: { c: 2 } });
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("returns the target content when source is empty", () => {
|
|
71
|
+
assert.deepEqual(merge({ a: 1, b: { c: 2 } }, {}), { a: 1, b: { c: 2 } });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("concatenates disjoint arrays at the same key in source order", () => {
|
|
75
|
+
assert.deepEqual(
|
|
76
|
+
merge({ items: ["a"] }, { items: ["b", "c"] }),
|
|
77
|
+
{ items: ["a", "b", "c"] }
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("de-duplicates overlapping array values while preserving order", () => {
|
|
82
|
+
// Arrays at the same key are unioned (first occurrence wins, new
|
|
83
|
+
// items appended), so repeated values don't accumulate when a
|
|
84
|
+
// caller's option array overlaps the defaults.
|
|
85
|
+
assert.deepEqual(
|
|
86
|
+
merge({ items: [1, 2, 3] }, { items: [2, 3, 4] }),
|
|
87
|
+
{ items: [1, 2, 3, 4] }
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("applies the union semantics to arrays at nested paths", () => {
|
|
92
|
+
assert.deepEqual(
|
|
93
|
+
merge({ group: { items: [1, 2] } }, { group: { items: [2, 3] } }),
|
|
94
|
+
{ group: { items: [1, 2, 3] } }
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("does not dedupe object array elements by structural equality (reference-based)", () => {
|
|
99
|
+
// Array.prototype.includes uses reference equality, so two
|
|
100
|
+
// distinct objects with identical fields are both retained.
|
|
101
|
+
const result = merge({ x: [{ id: 1 }] }, { x: [{ id: 1 }] });
|
|
102
|
+
assert.deepEqual(result, { x: [{ id: 1 }, { id: 1 }] });
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("replaces a target array with a source object at the same key", () => {
|
|
106
|
+
assert.deepEqual(merge({ a: [1, 2] }, { a: { b: 3 } }), { a: { b: 3 } });
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("replaces a target object with a source array at the same key", () => {
|
|
110
|
+
assert.deepEqual(merge({ a: { b: 3 } }, { a: [1, 2] }), { a: [1, 2] });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("keeps a null source value (null replaces target)", () => {
|
|
114
|
+
assert.deepEqual(merge({ a: 1 }, { a: null }), { a: null });
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("keeps an undefined source value (undefined replaces target)", () => {
|
|
118
|
+
const result = merge<Record<string, unknown>, Record<string, unknown>>(
|
|
119
|
+
{ a: 1 },
|
|
120
|
+
{ a: undefined }
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
assert.ok("a" in result);
|
|
124
|
+
assert.strictEqual(result.a, undefined);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("replaces a nested target object with a null source", () => {
|
|
128
|
+
assert.deepEqual(merge({ a: { b: 1 } }, { a: null }), { a: null });
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("does not pollute Object.prototype via a __proto__ key in source", () => {
|
|
132
|
+
const malicious = JSON.parse("{\"__proto__\":{\"polluted\":\"yes\"}}");
|
|
133
|
+
const result = merge({}, malicious);
|
|
134
|
+
|
|
135
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
136
|
+
assert.equal(({} as any).polluted, undefined);
|
|
137
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
138
|
+
assert.equal((result as any).polluted, undefined);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("does not pollute Object.prototype via a constructor.prototype key in source", () => {
|
|
142
|
+
const malicious = JSON.parse(
|
|
143
|
+
"{\"constructor\":{\"prototype\":{\"polluted\":\"yes\"}}}"
|
|
144
|
+
);
|
|
145
|
+
merge({}, malicious);
|
|
146
|
+
|
|
147
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
148
|
+
assert.equal(({} as any).polluted, undefined);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe("SmartlingBaseApi integration (pins the call-site behavior)", () => {
|
|
153
|
+
let base;
|
|
154
|
+
let uaStub;
|
|
155
|
+
|
|
156
|
+
beforeEach(() => {
|
|
157
|
+
base = new SmartlingBaseApi(loggerMock);
|
|
158
|
+
base.authApi = authMock;
|
|
159
|
+
uaStub = sinon.stub(base, "ua");
|
|
160
|
+
uaStub.returns("test_user_agent");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
afterEach(() => {
|
|
164
|
+
uaStub.restore();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("getDefaultHeaders: caller-supplied Content-Type overrides the default", async () => {
|
|
168
|
+
const headers = await base.getDefaultHeaders({
|
|
169
|
+
"Content-Type": "application/xml"
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
assert.deepEqual(headers, {
|
|
173
|
+
Authorization: "test_token_type test_access_token",
|
|
174
|
+
"Content-Type": "application/xml",
|
|
175
|
+
"User-Agent": "test_user_agent"
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("getDefaultHeaders: caller-supplied Authorization overrides the default", async () => {
|
|
180
|
+
const headers = await base.getDefaultHeaders({ Authorization: "Bearer custom" });
|
|
181
|
+
|
|
182
|
+
assert.equal(headers.Authorization, "Bearer custom");
|
|
183
|
+
assert.equal(headers["Content-Type"], "application/json");
|
|
184
|
+
assert.equal(headers["User-Agent"], "test_user_agent");
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("getDefaultHeaders: adds new caller-supplied keys while preserving defaults", async () => {
|
|
188
|
+
const headers = await base.getDefaultHeaders({
|
|
189
|
+
"X-SL-ServiceOrigin": "foo",
|
|
190
|
+
"X-Request-Id": "abc-123"
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
assert.deepEqual(headers, {
|
|
194
|
+
Authorization: "test_token_type test_access_token",
|
|
195
|
+
"Content-Type": "application/json",
|
|
196
|
+
"User-Agent": "test_user_agent",
|
|
197
|
+
"X-SL-ServiceOrigin": "foo",
|
|
198
|
+
"X-Request-Id": "abc-123"
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("makeRequest: nested non-header option fields survive the options merge", async () => {
|
|
203
|
+
const fetchStub = sinon.stub(base, "fetch").returns(responseMock);
|
|
204
|
+
const textStub = sinon.stub(responseMock, "text").returns("{\"response\": {\"data\": {}}}");
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
base.setOptions({
|
|
208
|
+
timeout: 10000,
|
|
209
|
+
agent: { keepAlive: true, maxSockets: 50 }
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
await base.makeRequest("POST", "https://test.com", { foo: "bar" });
|
|
213
|
+
|
|
214
|
+
const passedOpts = fetchStub.firstCall.args[1];
|
|
215
|
+
assert.equal(passedOpts.timeout, 10000);
|
|
216
|
+
assert.deepEqual(passedOpts.agent, { keepAlive: true, maxSockets: 50 });
|
|
217
|
+
assert.equal(passedOpts.method, "POST");
|
|
218
|
+
} finally {
|
|
219
|
+
textStub.restore();
|
|
220
|
+
fetchStub.restore();
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("makeRequest: options.headers deep-merge with the default headers (source wins on conflicts)", async () => {
|
|
225
|
+
const fetchStub = sinon.stub(base, "fetch").returns(responseMock);
|
|
226
|
+
const textStub = sinon.stub(responseMock, "text").returns("{\"response\": {\"data\": {}}}");
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
base.setOptions({
|
|
230
|
+
headers: {
|
|
231
|
+
"X-SL-ServiceOrigin": "foo-bar",
|
|
232
|
+
"Content-Type": "application/xml"
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
await base.makeRequest("POST", "https://test.com", { foo: "bar" });
|
|
237
|
+
|
|
238
|
+
const passedOpts = fetchStub.firstCall.args[1];
|
|
239
|
+
assert.deepEqual(passedOpts.headers, {
|
|
240
|
+
Authorization: "test_token_type test_access_token",
|
|
241
|
+
"Content-Type": "application/xml",
|
|
242
|
+
"User-Agent": "test_user_agent",
|
|
243
|
+
"X-SL-ServiceOrigin": "foo-bar"
|
|
244
|
+
});
|
|
245
|
+
} finally {
|
|
246
|
+
textStub.restore();
|
|
247
|
+
fetchStub.restore();
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("makeRequest: array-valued header options are unioned, not duplicated", async () => {
|
|
252
|
+
const fetchStub = sinon.stub(base, "fetch").returns(responseMock);
|
|
253
|
+
const textStub = sinon.stub(responseMock, "text").returns("{\"response\": {\"data\": {}}}");
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
base.setOptions({
|
|
257
|
+
headers: { "Accept-Language": ["en", "fr"] }
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
await base.makeRequest(
|
|
261
|
+
"POST",
|
|
262
|
+
"https://test.com",
|
|
263
|
+
{ foo: "bar" },
|
|
264
|
+
false,
|
|
265
|
+
{ "Accept-Language": ["en", "de"] }
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
const passedOpts = fetchStub.firstCall.args[1];
|
|
269
|
+
assert.deepEqual(
|
|
270
|
+
passedOpts.headers["Accept-Language"],
|
|
271
|
+
["en", "de", "fr"]
|
|
272
|
+
);
|
|
273
|
+
} finally {
|
|
274
|
+
textStub.restore();
|
|
275
|
+
fetchStub.restore();
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("makeRequest: calling setOptions does not mutate the caller-provided object", async () => {
|
|
280
|
+
const fetchStub = sinon.stub(base, "fetch").returns(responseMock);
|
|
281
|
+
const textStub = sinon.stub(responseMock, "text").returns("{\"response\": {\"data\": {}}}");
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
const userOptions = { headers: { "X-Custom": "first" } };
|
|
285
|
+
base.setOptions(userOptions);
|
|
286
|
+
|
|
287
|
+
await base.makeRequest("POST", "https://test.com", { foo: "bar" });
|
|
288
|
+
|
|
289
|
+
assert.deepEqual(userOptions, { headers: { "X-Custom": "first" } });
|
|
290
|
+
} finally {
|
|
291
|
+
textStub.restore();
|
|
292
|
+
fetchStub.restore();
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
});
|