@qp-mongosh/service-provider-core 0.0.0-dev.3 → 0.0.0-dev.8

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.
Files changed (71) hide show
  1. package/.eslintignore +2 -2
  2. package/.eslintrc.js +1 -1
  3. package/AUTHORS +11 -11
  4. package/LICENSE +200 -200
  5. package/package.json +54 -54
  6. package/src/admin.ts +119 -119
  7. package/src/all-fle-types.ts +17 -17
  8. package/src/all-transport-types.ts +80 -80
  9. package/src/cli-options.ts +49 -49
  10. package/src/closable.ts +14 -14
  11. package/src/connect-info.spec.ts +192 -192
  12. package/src/connect-info.ts +57 -57
  13. package/src/index.ts +62 -62
  14. package/src/platform.ts +6 -6
  15. package/src/printable-bson.spec.ts +75 -75
  16. package/src/printable-bson.ts +103 -103
  17. package/src/readable.ts +242 -242
  18. package/src/service-provider.ts +23 -23
  19. package/src/shell-auth-options.ts +7 -7
  20. package/src/textencoder-polyfill.spec.ts +11 -11
  21. package/src/textencoder-polyfill.ts +30 -30
  22. package/src/uri-generator.spec.ts +481 -481
  23. package/src/uri-generator.ts +265 -265
  24. package/src/writable.ts +367 -367
  25. package/tsconfig.json +12 -12
  26. package/tsconfig.lint.json +8 -8
  27. package/lib/admin.d.ts +0 -28
  28. package/lib/admin.js +0 -3
  29. package/lib/admin.js.map +0 -1
  30. package/lib/all-fle-types.d.ts +0 -2
  31. package/lib/all-fle-types.js +0 -3
  32. package/lib/all-fle-types.js.map +0 -1
  33. package/lib/all-transport-types.d.ts +0 -1
  34. package/lib/all-transport-types.js +0 -3
  35. package/lib/all-transport-types.js.map +0 -1
  36. package/lib/cli-options.d.ts +0 -43
  37. package/lib/cli-options.js +0 -3
  38. package/lib/cli-options.js.map +0 -1
  39. package/lib/closable.d.ts +0 -4
  40. package/lib/closable.js +0 -3
  41. package/lib/closable.js.map +0 -1
  42. package/lib/connect-info.d.ts +0 -19
  43. package/lib/connect-info.js +0 -35
  44. package/lib/connect-info.js.map +0 -1
  45. package/lib/index.d.ts +0 -31
  46. package/lib/index.js +0 -56
  47. package/lib/index.js.map +0 -1
  48. package/lib/platform.d.ts +0 -6
  49. package/lib/platform.js +0 -11
  50. package/lib/platform.js.map +0 -1
  51. package/lib/printable-bson.d.ts +0 -3
  52. package/lib/printable-bson.js +0 -82
  53. package/lib/printable-bson.js.map +0 -1
  54. package/lib/readable.d.ts +0 -18
  55. package/lib/readable.js +0 -3
  56. package/lib/readable.js.map +0 -1
  57. package/lib/service-provider.d.ts +0 -11
  58. package/lib/service-provider.js +0 -19
  59. package/lib/service-provider.js.map +0 -1
  60. package/lib/shell-auth-options.d.ts +0 -7
  61. package/lib/shell-auth-options.js +0 -3
  62. package/lib/shell-auth-options.js.map +0 -1
  63. package/lib/textencoder-polyfill.d.ts +0 -2
  64. package/lib/textencoder-polyfill.js +0 -22
  65. package/lib/textencoder-polyfill.js.map +0 -1
  66. package/lib/uri-generator.d.ts +0 -8
  67. package/lib/uri-generator.js +0 -176
  68. package/lib/uri-generator.js.map +0 -1
  69. package/lib/writable.d.ts +0 -22
  70. package/lib/writable.js +0 -3
  71. package/lib/writable.js.map +0 -1
@@ -1,265 +1,265 @@
1
- /* eslint complexity: 0*/
2
-
3
- import { CommonErrors, MongoshInvalidInputError } from '@qp-mongosh/errors';
4
- import i18n from '@qp-mongosh/i18n';
5
- import CliOptions from './cli-options';
6
- import ConnectionString, { CommaAndColonSeparatedRecord } from 'mongodb-connection-string-url';
7
- import { DEFAULT_DB } from './index';
8
-
9
- /**
10
- * URI schemes.
11
- */
12
- enum Scheme {
13
- Mongo = 'mongodb://',
14
- MongoSrv = 'mongodb+srv://'
15
- }
16
-
17
- /**
18
- * The default host.
19
- */
20
- const DEFAULT_HOST = '127.0.0.1';
21
-
22
- /**
23
- * The default port.
24
- */
25
- const DEFAULT_PORT = '27017';
26
-
27
- /**
28
- * Conflicting host/port message.
29
- */
30
- const CONFLICT = 'cli-repl.uri-generator.no-host-port';
31
-
32
- /**
33
- * Invalid host message.
34
- */
35
- const INVALID_HOST = 'cli-repl.uri-generator.invalid-host';
36
-
37
- /**
38
- * Host seed list contains a port that mismatches an explicit --port.
39
- */
40
- const HOST_LIST_PORT_MISMATCH = 'cli-repl.uri-generator.host-list-port-mismatch';
41
-
42
- /**
43
- * Diverging gssapiServiceName and SERVICE_NAME mechanism property
44
- */
45
- const DIVERGING_SERVICE_NAME = 'cli-repl.uri-generator.diverging-service-name';
46
-
47
- /**
48
- * Usage of unsupported gssapiServiceName query parameter
49
- */
50
- const GSSAPI_SERVICE_NAME_UNSUPPORTED = 'cli-repl.uri-generator.gssapi-service-name-unsupported';
51
-
52
- /**
53
- * Validate conflicts in the options.
54
- */
55
- function validateConflicts(options: CliOptions, connectionString?: ConnectionString): void {
56
- if (options.host || options.port) {
57
- throw new MongoshInvalidInputError(i18n.__(CONFLICT), CommonErrors.InvalidArgument);
58
- }
59
-
60
- if (options.gssapiServiceName && connectionString?.searchParams.has('authMechanismProperties')) {
61
- const authProperties = new CommaAndColonSeparatedRecord(
62
- connectionString.searchParams.get('authMechanismProperties'));
63
- const serviceName = authProperties.get('SERVICE_NAME');
64
- if (serviceName !== undefined && options.gssapiServiceName !== serviceName) {
65
- throw new MongoshInvalidInputError(i18n.__(DIVERGING_SERVICE_NAME), CommonErrors.InvalidArgument);
66
- }
67
- }
68
-
69
- if (connectionString?.searchParams.has('gssapiServiceName')) {
70
- throw new MongoshInvalidInputError(i18n.__(GSSAPI_SERVICE_NAME_UNSUPPORTED), CommonErrors.InvalidArgument);
71
- }
72
- }
73
-
74
- /**
75
- * Perform basic validation of the --host option.
76
- *
77
- * @param {string} host - The value of the --host option.
78
- */
79
- function validateHost(host: string): void {
80
- const invalidCharacter = host.match(/[^a-zA-Z0-9.:\[\]_-]/);
81
- if (invalidCharacter) {
82
- throw new MongoshInvalidInputError(
83
- i18n.__(INVALID_HOST) + ': ' + invalidCharacter[0],
84
- CommonErrors.InvalidArgument);
85
- }
86
- }
87
-
88
- /**
89
- * Validates a host seed list against a specified fixed port and
90
- * returns an individual `<host>:<port>` array.
91
- */
92
- function validateHostSeedList(hosts: string, fixedPort: string | undefined): string[] {
93
- const trimmedHosts = hosts.split(',').map(h => h.trim()).filter(h => !!h);
94
- const hostList: string[] = [];
95
- trimmedHosts.forEach(h => {
96
- const [host, port] = h.split(':');
97
- if (fixedPort && port !== undefined && port !== fixedPort) {
98
- throw new MongoshInvalidInputError(
99
- i18n.__(HOST_LIST_PORT_MISMATCH),
100
- CommonErrors.InvalidArgument
101
- );
102
- }
103
- hostList.push(`${host}${(port || fixedPort) ? ':' + (port || fixedPort) : ''}`);
104
- });
105
- return hostList;
106
- }
107
-
108
- /**
109
- * Generate the host from the options or default.
110
- *
111
- * @param {CliOptions} options - The options.
112
- *
113
- * @returns {string} The host.
114
- */
115
- function generateHost(options: CliOptions): string {
116
- if (options.host) {
117
- validateHost(options.host);
118
- if (options.host.includes(':')) {
119
- return options.host.split(':')[0];
120
- }
121
- return options.host;
122
- }
123
- return DEFAULT_HOST;
124
- }
125
-
126
- /**
127
- * Generate the port from the options or default.
128
- *
129
- * @param {CliOptions} options - The options.
130
- *
131
- * @returns {string} The port.
132
- */
133
- function generatePort(options: CliOptions): string {
134
- if (options.host && options.host.includes(':')) {
135
- validateHost(options.host);
136
- const port = options.host.split(':')[1];
137
- if (!options.port || options.port === port) {
138
- return port;
139
- }
140
- throw new MongoshInvalidInputError(i18n.__(CONFLICT), CommonErrors.InvalidArgument);
141
- }
142
- return options.port ? options.port : DEFAULT_PORT;
143
- }
144
-
145
- /**
146
- * Generate a URI from the provided CLI options.
147
- *
148
- * If a full URI is provided, you cannot also specify --host or --port
149
- *
150
- * Rules from the existing Shell code:
151
- *
152
- * if nodb is set then all positional parameters are files
153
- * otherwise the first positional parameter might be a dbaddress, but
154
- * only if one of these conditions is met:
155
- * - it contains no '.' after the last appearance of '\' or '/'
156
- * - it doesn't end in '.js' and it doesn't specify a path to an existing file
157
- */
158
- function generateUri(options: CliOptions): string {
159
- if (options.nodb) {
160
- return '';
161
- }
162
- const connectionString = generateUriNormalized(options);
163
- if (connectionString.hosts.every(host =>
164
- ['localhost', '127.0.0.1'].includes(host.split(':')[0]))) {
165
- const params = connectionString.searchParams;
166
- if (!params.has('serverSelectionTimeoutMS')) {
167
- params.set('serverSelectionTimeoutMS', '2000');
168
- }
169
- }
170
- return connectionString.toString();
171
- }
172
- function generateUriNormalized(options: CliOptions): ConnectionString {
173
- const uri = options.connectionSpecifier;
174
-
175
- // If the --host argument contains /, it has the format
176
- // <replSetName>/<hostname1><:port>,<hostname2><:port>,<...>
177
- const replSetHostMatch = (options.host ?? '').match(
178
- /^(?<replSetName>[^/]+)\/(?<hosts>([A-Za-z0-9._-]+(:\d+)?,?)+)$/
179
- );
180
- if (replSetHostMatch) {
181
- const { replSetName, hosts } = replSetHostMatch.groups as { replSetName: string, hosts: string };
182
- const connectionString = new ConnectionString(`${Scheme.Mongo}replacemeHost/${encodeURIComponent(uri || '')}`);
183
- connectionString.hosts = validateHostSeedList(hosts, options.port);
184
- connectionString.searchParams.set('replicaSet', replSetName);
185
- return addShellConnectionStringParameters(connectionString);
186
- }
187
-
188
- // If the --host argument contains multiple hosts as a seed list
189
- // we directly do not do additional host/port parsing
190
- const seedList = (options.host ?? '').match(
191
- /^(?<hosts>([A-Za-z0-9._-]+(:\d+)?,?)+)$/
192
- );
193
- if (seedList && options.host?.includes(',')) {
194
- const { hosts } = seedList.groups as { hosts: string };
195
- const connectionString = new ConnectionString(`${Scheme.Mongo}replacemeHost/${encodeURIComponent(uri || '')}`);
196
- connectionString.hosts = validateHostSeedList(hosts, options.port);
197
- return addShellConnectionStringParameters(connectionString);
198
- }
199
-
200
- // There is no URI provided, use default 127.0.0.1:27017
201
- if (!uri) {
202
- return new ConnectionString(`${Scheme.Mongo}${generateHost(options)}:${generatePort(options)}/?directConnection=true`);
203
- }
204
-
205
- // mongodb+srv:// URI is provided, treat as correct and immediately return
206
- if (uri.startsWith(Scheme.MongoSrv)) {
207
- const connectionString = new ConnectionString(uri);
208
- validateConflicts(options, connectionString);
209
- return connectionString;
210
- } else if (uri.startsWith(Scheme.Mongo)) {
211
- // we need to figure out if we have to add the directConnection query parameter
212
- const connectionString = new ConnectionString(uri);
213
- validateConflicts(options, connectionString);
214
- return addShellConnectionStringParameters(connectionString);
215
- }
216
-
217
- // Capture host, port and db from the string and generate a URI from
218
- // the parts. If there is a db part, it *must* start with /.
219
- const uriMatch = /^([A-Za-z0-9][A-Za-z0-9._-]+):?(\d+)?(?:\/(\S*))?$/gi;
220
- let parts: string[] | null = uriMatch.exec(uri);
221
-
222
- if (parts === null) {
223
- if (/[/\\. "$]/.test(uri)) {
224
- // This cannot be a database name because 'uri' contains characters invalid in a database.
225
- throw new MongoshInvalidInputError(`Invalid URI: ${uri}`, CommonErrors.InvalidArgument);
226
- } else {
227
- parts = [ uri, uri ];
228
- }
229
- }
230
-
231
- let host: string | undefined = parts?.[1];
232
- const port = parts?.[2];
233
- let dbAndQueryString = parts?.[3];
234
-
235
- // If there is no port and db, host becomes db if there is no
236
- // '.' in the string. (legacy shell behaviour)
237
- if (!port && !dbAndQueryString && host.indexOf('.') < 0) {
238
- dbAndQueryString = host;
239
- host = undefined;
240
- }
241
-
242
- // If we have a host or port, validate that the options don't also
243
- // have a host or port in them.
244
- if (host || port) {
245
- validateConflicts(options);
246
- }
247
- return addShellConnectionStringParameters(new ConnectionString(
248
- `${Scheme.Mongo}${host || generateHost(options)}:${port || generatePort(options)}/${encodeURIComponent(dbAndQueryString || DEFAULT_DB)}`));
249
- }
250
-
251
- /**
252
- * Adds the `directConnection=true` query parameter if required.
253
- * @param uri mongodb:// connection string
254
- */
255
- function addShellConnectionStringParameters(uri: ConnectionString): ConnectionString {
256
- uri = uri.clone();
257
- const params = uri.searchParams;
258
- if (!params.has('replicaSet') && !params.has('directConnection') && !params.has('loadBalanced') && uri.hosts.length === 1) {
259
- params.set('directConnection', 'true');
260
- }
261
- return uri;
262
- }
263
-
264
- export default generateUri;
265
- export { Scheme };
1
+ /* eslint complexity: 0*/
2
+
3
+ import { CommonErrors, MongoshInvalidInputError } from '@qp-mongosh/errors';
4
+ import i18n from '@qp-mongosh/i18n';
5
+ import CliOptions from './cli-options';
6
+ import ConnectionString, { CommaAndColonSeparatedRecord } from 'mongodb-connection-string-url';
7
+ import { DEFAULT_DB } from './index';
8
+
9
+ /**
10
+ * URI schemes.
11
+ */
12
+ enum Scheme {
13
+ Mongo = 'mongodb://',
14
+ MongoSrv = 'mongodb+srv://'
15
+ }
16
+
17
+ /**
18
+ * The default host.
19
+ */
20
+ const DEFAULT_HOST = '127.0.0.1';
21
+
22
+ /**
23
+ * The default port.
24
+ */
25
+ const DEFAULT_PORT = '27017';
26
+
27
+ /**
28
+ * Conflicting host/port message.
29
+ */
30
+ const CONFLICT = 'cli-repl.uri-generator.no-host-port';
31
+
32
+ /**
33
+ * Invalid host message.
34
+ */
35
+ const INVALID_HOST = 'cli-repl.uri-generator.invalid-host';
36
+
37
+ /**
38
+ * Host seed list contains a port that mismatches an explicit --port.
39
+ */
40
+ const HOST_LIST_PORT_MISMATCH = 'cli-repl.uri-generator.host-list-port-mismatch';
41
+
42
+ /**
43
+ * Diverging gssapiServiceName and SERVICE_NAME mechanism property
44
+ */
45
+ const DIVERGING_SERVICE_NAME = 'cli-repl.uri-generator.diverging-service-name';
46
+
47
+ /**
48
+ * Usage of unsupported gssapiServiceName query parameter
49
+ */
50
+ const GSSAPI_SERVICE_NAME_UNSUPPORTED = 'cli-repl.uri-generator.gssapi-service-name-unsupported';
51
+
52
+ /**
53
+ * Validate conflicts in the options.
54
+ */
55
+ function validateConflicts(options: CliOptions, connectionString?: ConnectionString): void {
56
+ if (options.host || options.port) {
57
+ throw new MongoshInvalidInputError(i18n.__(CONFLICT), CommonErrors.InvalidArgument);
58
+ }
59
+
60
+ if (options.gssapiServiceName && connectionString?.searchParams.has('authMechanismProperties')) {
61
+ const authProperties = new CommaAndColonSeparatedRecord(
62
+ connectionString.searchParams.get('authMechanismProperties'));
63
+ const serviceName = authProperties.get('SERVICE_NAME');
64
+ if (serviceName !== undefined && options.gssapiServiceName !== serviceName) {
65
+ throw new MongoshInvalidInputError(i18n.__(DIVERGING_SERVICE_NAME), CommonErrors.InvalidArgument);
66
+ }
67
+ }
68
+
69
+ if (connectionString?.searchParams.has('gssapiServiceName')) {
70
+ throw new MongoshInvalidInputError(i18n.__(GSSAPI_SERVICE_NAME_UNSUPPORTED), CommonErrors.InvalidArgument);
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Perform basic validation of the --host option.
76
+ *
77
+ * @param {string} host - The value of the --host option.
78
+ */
79
+ function validateHost(host: string): void {
80
+ const invalidCharacter = host.match(/[^a-zA-Z0-9.:\[\]_-]/);
81
+ if (invalidCharacter) {
82
+ throw new MongoshInvalidInputError(
83
+ i18n.__(INVALID_HOST) + ': ' + invalidCharacter[0],
84
+ CommonErrors.InvalidArgument);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Validates a host seed list against a specified fixed port and
90
+ * returns an individual `<host>:<port>` array.
91
+ */
92
+ function validateHostSeedList(hosts: string, fixedPort: string | undefined): string[] {
93
+ const trimmedHosts = hosts.split(',').map(h => h.trim()).filter(h => !!h);
94
+ const hostList: string[] = [];
95
+ trimmedHosts.forEach(h => {
96
+ const [host, port] = h.split(':');
97
+ if (fixedPort && port !== undefined && port !== fixedPort) {
98
+ throw new MongoshInvalidInputError(
99
+ i18n.__(HOST_LIST_PORT_MISMATCH),
100
+ CommonErrors.InvalidArgument
101
+ );
102
+ }
103
+ hostList.push(`${host}${(port || fixedPort) ? ':' + (port || fixedPort) : ''}`);
104
+ });
105
+ return hostList;
106
+ }
107
+
108
+ /**
109
+ * Generate the host from the options or default.
110
+ *
111
+ * @param {CliOptions} options - The options.
112
+ *
113
+ * @returns {string} The host.
114
+ */
115
+ function generateHost(options: CliOptions): string {
116
+ if (options.host) {
117
+ validateHost(options.host);
118
+ if (options.host.includes(':')) {
119
+ return options.host.split(':')[0];
120
+ }
121
+ return options.host;
122
+ }
123
+ return DEFAULT_HOST;
124
+ }
125
+
126
+ /**
127
+ * Generate the port from the options or default.
128
+ *
129
+ * @param {CliOptions} options - The options.
130
+ *
131
+ * @returns {string} The port.
132
+ */
133
+ function generatePort(options: CliOptions): string {
134
+ if (options.host && options.host.includes(':')) {
135
+ validateHost(options.host);
136
+ const port = options.host.split(':')[1];
137
+ if (!options.port || options.port === port) {
138
+ return port;
139
+ }
140
+ throw new MongoshInvalidInputError(i18n.__(CONFLICT), CommonErrors.InvalidArgument);
141
+ }
142
+ return options.port ? options.port : DEFAULT_PORT;
143
+ }
144
+
145
+ /**
146
+ * Generate a URI from the provided CLI options.
147
+ *
148
+ * If a full URI is provided, you cannot also specify --host or --port
149
+ *
150
+ * Rules from the existing Shell code:
151
+ *
152
+ * if nodb is set then all positional parameters are files
153
+ * otherwise the first positional parameter might be a dbaddress, but
154
+ * only if one of these conditions is met:
155
+ * - it contains no '.' after the last appearance of '\' or '/'
156
+ * - it doesn't end in '.js' and it doesn't specify a path to an existing file
157
+ */
158
+ function generateUri(options: CliOptions): string {
159
+ if (options.nodb) {
160
+ return '';
161
+ }
162
+ const connectionString = generateUriNormalized(options);
163
+ if (connectionString.hosts.every(host =>
164
+ ['localhost', '127.0.0.1'].includes(host.split(':')[0]))) {
165
+ const params = connectionString.searchParams;
166
+ if (!params.has('serverSelectionTimeoutMS')) {
167
+ params.set('serverSelectionTimeoutMS', '2000');
168
+ }
169
+ }
170
+ return connectionString.toString();
171
+ }
172
+ function generateUriNormalized(options: CliOptions): ConnectionString {
173
+ const uri = options.connectionSpecifier;
174
+
175
+ // If the --host argument contains /, it has the format
176
+ // <replSetName>/<hostname1><:port>,<hostname2><:port>,<...>
177
+ const replSetHostMatch = (options.host ?? '').match(
178
+ /^(?<replSetName>[^/]+)\/(?<hosts>([A-Za-z0-9._-]+(:\d+)?,?)+)$/
179
+ );
180
+ if (replSetHostMatch) {
181
+ const { replSetName, hosts } = replSetHostMatch.groups as { replSetName: string, hosts: string };
182
+ const connectionString = new ConnectionString(`${Scheme.Mongo}replacemeHost/${encodeURIComponent(uri || '')}`);
183
+ connectionString.hosts = validateHostSeedList(hosts, options.port);
184
+ connectionString.searchParams.set('replicaSet', replSetName);
185
+ return addShellConnectionStringParameters(connectionString);
186
+ }
187
+
188
+ // If the --host argument contains multiple hosts as a seed list
189
+ // we directly do not do additional host/port parsing
190
+ const seedList = (options.host ?? '').match(
191
+ /^(?<hosts>([A-Za-z0-9._-]+(:\d+)?,?)+)$/
192
+ );
193
+ if (seedList && options.host?.includes(',')) {
194
+ const { hosts } = seedList.groups as { hosts: string };
195
+ const connectionString = new ConnectionString(`${Scheme.Mongo}replacemeHost/${encodeURIComponent(uri || '')}`);
196
+ connectionString.hosts = validateHostSeedList(hosts, options.port);
197
+ return addShellConnectionStringParameters(connectionString);
198
+ }
199
+
200
+ // There is no URI provided, use default 127.0.0.1:27017
201
+ if (!uri) {
202
+ return new ConnectionString(`${Scheme.Mongo}${generateHost(options)}:${generatePort(options)}/?directConnection=true`);
203
+ }
204
+
205
+ // mongodb+srv:// URI is provided, treat as correct and immediately return
206
+ if (uri.startsWith(Scheme.MongoSrv)) {
207
+ const connectionString = new ConnectionString(uri);
208
+ validateConflicts(options, connectionString);
209
+ return connectionString;
210
+ } else if (uri.startsWith(Scheme.Mongo)) {
211
+ // we need to figure out if we have to add the directConnection query parameter
212
+ const connectionString = new ConnectionString(uri);
213
+ validateConflicts(options, connectionString);
214
+ return addShellConnectionStringParameters(connectionString);
215
+ }
216
+
217
+ // Capture host, port and db from the string and generate a URI from
218
+ // the parts. If there is a db part, it *must* start with /.
219
+ const uriMatch = /^([A-Za-z0-9][A-Za-z0-9._-]+):?(\d+)?(?:\/(\S*))?$/gi;
220
+ let parts: string[] | null = uriMatch.exec(uri);
221
+
222
+ if (parts === null) {
223
+ if (/[/\\. "$]/.test(uri)) {
224
+ // This cannot be a database name because 'uri' contains characters invalid in a database.
225
+ throw new MongoshInvalidInputError(`Invalid URI: ${uri}`, CommonErrors.InvalidArgument);
226
+ } else {
227
+ parts = [ uri, uri ];
228
+ }
229
+ }
230
+
231
+ let host: string | undefined = parts?.[1];
232
+ const port = parts?.[2];
233
+ let dbAndQueryString = parts?.[3];
234
+
235
+ // If there is no port and db, host becomes db if there is no
236
+ // '.' in the string. (legacy shell behaviour)
237
+ if (!port && !dbAndQueryString && host.indexOf('.') < 0) {
238
+ dbAndQueryString = host;
239
+ host = undefined;
240
+ }
241
+
242
+ // If we have a host or port, validate that the options don't also
243
+ // have a host or port in them.
244
+ if (host || port) {
245
+ validateConflicts(options);
246
+ }
247
+ return addShellConnectionStringParameters(new ConnectionString(
248
+ `${Scheme.Mongo}${host || generateHost(options)}:${port || generatePort(options)}/${encodeURIComponent(dbAndQueryString || DEFAULT_DB)}`));
249
+ }
250
+
251
+ /**
252
+ * Adds the `directConnection=true` query parameter if required.
253
+ * @param uri mongodb:// connection string
254
+ */
255
+ function addShellConnectionStringParameters(uri: ConnectionString): ConnectionString {
256
+ uri = uri.clone();
257
+ const params = uri.searchParams;
258
+ if (!params.has('replicaSet') && !params.has('directConnection') && !params.has('loadBalanced') && uri.hosts.length === 1) {
259
+ params.set('directConnection', 'true');
260
+ }
261
+ return uri;
262
+ }
263
+
264
+ export default generateUri;
265
+ export { Scheme };