@mongosh/shell-bson 1.0.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.
@@ -0,0 +1,147 @@
1
+ import type { BSON } from './';
2
+ import type { InspectOptionsStylized, CustomInspectFunction } from 'util';
3
+ import { inspect as utilInspect } from 'util';
4
+ const inspectCustom = Symbol.for('nodejs.util.inspect.custom');
5
+ type BSONClassKey = BSON[Exclude<
6
+ keyof BSON,
7
+ 'EJSON' | 'calculateObjectSize'
8
+ >]['prototype']['_bsontype'];
9
+
10
+ // Turn e.g. 'new Double(...)' into 'Double(...)' but preserve possible leading whitespace
11
+ function removeNewFromInspectResult(str: string): string {
12
+ return str.replace(/^(\s*)(new )/, '$1');
13
+ }
14
+
15
+ /** Typed array such as Int8Array have a format like 'Int8Array(3) [1, 2, 3]'
16
+ * and we want to remove the prefix and keep just the array contents. */
17
+ function removeTypedArrayPrefixFromInspectResult(str: string): string {
18
+ return str.replace(/^\s*\S+\s*\(\d+\)\s*/, '');
19
+ }
20
+
21
+ // Create a Node.js-util-inspect() style custom inspect function that
22
+ // strips 'new ' from inspect results but otherwise uses the Node.js
23
+ // driver's bson library's inspect functions.
24
+ function makeClasslessInspect<K extends BSONClassKey>(
25
+ cls: BSON[K]
26
+ ): CustomInspectFunction {
27
+ const originalInspect = cls.prototype.inspect;
28
+ return function (
29
+ this: BSON[K]['prototype'],
30
+ ...args: Parameters<typeof originalInspect>
31
+ ) {
32
+ return removeNewFromInspectResult(originalInspect.apply(this, args));
33
+ } satisfies CustomInspectFunction;
34
+ }
35
+
36
+ const makeBinaryVectorInspect = (bsonLibrary: BSON): CustomInspectFunction => {
37
+ return function (
38
+ this: BSON['Binary']['prototype'],
39
+ depth: number,
40
+ options: InspectOptionsStylized
41
+ ): string {
42
+ const binaryInspect = makeClasslessInspect(bsonLibrary.Binary);
43
+ switch (this.buffer[0]) {
44
+ case bsonLibrary.Binary.VECTOR_TYPE.Int8:
45
+ return `Binary.fromInt8Array(new Int8Array(${removeTypedArrayPrefixFromInspectResult(
46
+ utilInspect(this.toInt8Array(), {
47
+ depth,
48
+ ...options,
49
+ // These arrays can be very large, so would prefer to use the default options instead.
50
+ maxArrayLength: utilInspect.defaultOptions.maxArrayLength,
51
+ })
52
+ )}))`;
53
+ case bsonLibrary.Binary.VECTOR_TYPE.Float32:
54
+ return `Binary.fromFloat32Array(new Float32Array(${removeTypedArrayPrefixFromInspectResult(
55
+ utilInspect(this.toFloat32Array(), {
56
+ depth,
57
+ ...options,
58
+ // These arrays can be very large, so would prefer to use the default options instead.
59
+ maxArrayLength: utilInspect.defaultOptions.maxArrayLength,
60
+ })
61
+ )}))`;
62
+ case bsonLibrary.Binary.VECTOR_TYPE.PackedBit: {
63
+ const paddingInfo = this.buffer[1] === 0 ? '' : `, ${this.buffer[1]}`;
64
+ return `Binary.fromPackedBits(new Uint8Array(${removeTypedArrayPrefixFromInspectResult(
65
+ utilInspect(this.toPackedBits(), {
66
+ depth,
67
+ ...options,
68
+ // These arrays can be very large, so would prefer to use the default options instead.
69
+ maxArrayLength: utilInspect.defaultOptions.maxArrayLength,
70
+ })
71
+ )})${paddingInfo})`;
72
+ }
73
+ default:
74
+ return binaryInspect.call(this, depth, options);
75
+ }
76
+ } satisfies CustomInspectFunction;
77
+ };
78
+
79
+ export const makeBsonStringifiers: (
80
+ bsonLibrary: BSON
81
+ ) => Record<BSONClassKey | 'ObjectID', CustomInspectFunction> = (
82
+ bsonLibrary
83
+ ) => {
84
+ const binaryVectorInspect = makeBinaryVectorInspect(bsonLibrary);
85
+ const binaryInspect = makeClasslessInspect(bsonLibrary.Binary);
86
+ return {
87
+ ObjectId: makeClasslessInspect(bsonLibrary.ObjectId),
88
+ ObjectID: makeClasslessInspect(bsonLibrary.ObjectId),
89
+ DBRef: makeClasslessInspect(bsonLibrary.DBRef),
90
+ MaxKey: makeClasslessInspect(bsonLibrary.MaxKey),
91
+ MinKey: makeClasslessInspect(bsonLibrary.MinKey),
92
+ Timestamp: makeClasslessInspect(bsonLibrary.Timestamp),
93
+ BSONSymbol: makeClasslessInspect(bsonLibrary.BSONSymbol),
94
+ Code: makeClasslessInspect(bsonLibrary.Code),
95
+ Decimal128: makeClasslessInspect(bsonLibrary.Decimal128),
96
+ Int32: makeClasslessInspect(bsonLibrary.Int32),
97
+ Long: makeClasslessInspect(bsonLibrary.Long),
98
+ Double: makeClasslessInspect(bsonLibrary.Double),
99
+ BSONRegExp: makeClasslessInspect(bsonLibrary.BSONRegExp),
100
+ Binary: function (
101
+ this: BSON['Binary']['prototype'],
102
+ ...args: Parameters<CustomInspectFunction>
103
+ ): string {
104
+ const hexString = this.toString('hex');
105
+
106
+ switch (this.sub_type) {
107
+ case bsonLibrary.Binary.SUBTYPE_VECTOR:
108
+ return binaryVectorInspect.apply(this, args);
109
+ case bsonLibrary.Binary.SUBTYPE_MD5:
110
+ return `MD5('${hexString}')`;
111
+ case bsonLibrary.Binary.SUBTYPE_UUID:
112
+ if (hexString.length === 32) {
113
+ // Format '0123456789abcdef0123456789abcdef' into
114
+ // '01234567-89ab-cdef-0123-456789abcdef'.
115
+ const asUUID = /^(.{8})(.{4})(.{4})(.{4})(.{12})$/
116
+ .exec(hexString)!
117
+ .slice(1, 6)
118
+ .join('-');
119
+ return `UUID('${asUUID}')`;
120
+ }
121
+ // In case somebody did something weird and used an UUID with a
122
+ // non-standard length, fall through.
123
+ default:
124
+ return binaryInspect.apply(this, args);
125
+ }
126
+ } satisfies CustomInspectFunction,
127
+ };
128
+ };
129
+
130
+ /**
131
+ * This method modifies the BSON class passed in as argument. This is required so that
132
+ * we can have the driver return our BSON classes without having to write our own serializer.
133
+ * @param {Object} bson
134
+ */
135
+ export function makePrintableBson(bsonLibrary: BSON): void {
136
+ for (const [key, stringifier] of Object.entries(
137
+ makeBsonStringifiers(bsonLibrary)
138
+ )) {
139
+ if (!(key in bsonLibrary)) {
140
+ continue;
141
+ }
142
+ const cls = bsonLibrary[key as keyof BSON];
143
+ for (const key of [inspectCustom, 'inspect']) {
144
+ (cls as any).prototype[key] = stringifier;
145
+ }
146
+ }
147
+ }