Skip to content

Commit e932db7

Browse files
authored
chore(mongodb-redact): remove lodash usage MONGOSH-1975 (#497)
Just ran into this while writing a test for mongosh that ensures that `shell-api` is really as runtime-independent as we expect.
1 parent 6283bab commit e932db7

File tree

4 files changed

+66
-12
lines changed

4 files changed

+66
-12
lines changed

package-lock.json

Lines changed: 0 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/mongodb-redact/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@
4545
"test-ci": "npm run test-cov",
4646
"reformat": "npm run prettier -- --write ."
4747
},
48-
"dependencies": {
49-
"lodash": "^4.17.21"
50-
},
5148
"devDependencies": {
5249
"@mongodb-js/eslint-config-devtools": "0.9.10",
5350
"@mongodb-js/mocha-config-devtools": "^1.0.4",

packages/mongodb-redact/src/index.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { expect } from 'chai';
22
import redact from './';
3+
import { runInNewContext } from 'vm';
34

45
/* eslint no-multi-str:0 */
56
const PRIVATE_KEY =
@@ -195,5 +196,44 @@ describe('mongodb-redact', function () {
195196
},
196197
});
197198
});
199+
200+
it('should work on objects with a null prototype', function () {
201+
const res = redact({
202+
obj: {
203+
path: '/Users/thomas/something.txt',
204+
__proto__: null,
205+
},
206+
});
207+
expect(res).to.deep.equal({
208+
obj: {
209+
path: '/Users/<user>/something.txt',
210+
},
211+
});
212+
});
213+
214+
it('should ignore class instances', function () {
215+
const obj = new (class Foo {
216+
path = '/Users/thomas/something.txt';
217+
})();
218+
const res = redact({
219+
obj,
220+
});
221+
expect(res.obj).to.equal(obj);
222+
});
223+
224+
it('should work on objects from another vm context', function () {
225+
const res = redact(
226+
runInNewContext(`({
227+
obj: {
228+
path: '/Users/thomas/something.txt',
229+
},
230+
})`)
231+
);
232+
expect(res).to.deep.equal({
233+
obj: {
234+
path: '/Users/<user>/something.txt',
235+
},
236+
});
237+
});
198238
});
199239
});

packages/mongodb-redact/src/index.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
1-
import _ from 'lodash';
21
import { regexes } from './regexes';
32

3+
const plainObjectTag = Object.prototype.toString.call({});
4+
function isPlainObject(val: unknown): val is object {
5+
if (
6+
typeof val !== 'object' ||
7+
!val ||
8+
Object.prototype.toString.call(val) !== plainObjectTag
9+
) {
10+
return false;
11+
}
12+
const proto = Object.getPrototypeOf(val);
13+
if (proto === null) return true;
14+
if (!Object.prototype.hasOwnProperty.call(proto, 'constructor')) return false;
15+
const ctor = proto.constructor;
16+
if (typeof ctor !== 'function') return ctor;
17+
// `ctor === Object` but this works across contexts
18+
// (Object is special because Object.__proto__.__proto__ === Object.prototype),
19+
const ctorPrototype = Object.getPrototypeOf(ctor);
20+
return Object.getPrototypeOf(ctorPrototype) === ctor.prototype;
21+
}
22+
423
export function redact<T>(message: T): T {
5-
if (_.isPlainObject(message)) {
24+
if (isPlainObject(message)) {
625
// recursively walk through all values of an object
7-
return _.mapValues(message as any, redact);
26+
return Object.fromEntries(
27+
Object.entries(message).map(([key, value]) => [key, redact(value)])
28+
) as T;
829
}
9-
if (_.isArray(message)) {
30+
if (Array.isArray(message)) {
1031
// walk through array and redact each value
11-
return _.map(message, redact) as T;
32+
return message.map(redact) as T;
1233
}
1334
if (typeof message !== 'string') {
1435
// all non-string types can be safely returned

0 commit comments

Comments
 (0)