oracledb 5.5.0 → 6.0.0

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 (107) hide show
  1. package/CHANGELOG.md +1 -1875
  2. package/LICENSE.txt +8 -222
  3. package/NOTICE.txt +1 -1
  4. package/README.md +38 -30
  5. package/SECURITY.md +38 -0
  6. package/build/Release/oracledb-6.0.0-darwin-x64.node +0 -0
  7. package/build/Release/oracledb-6.0.0-darwin-x64.node-buildinfo.txt +1 -0
  8. package/build/Release/oracledb-6.0.0-js-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-6.0.0-linux-arm64.node +0 -0
  10. package/build/Release/oracledb-6.0.0-linux-arm64.node-buildinfo.txt +1 -0
  11. package/build/Release/oracledb-6.0.0-linux-x64.node +0 -0
  12. package/build/Release/oracledb-6.0.0-linux-x64.node-buildinfo.txt +1 -0
  13. package/build/Release/oracledb-6.0.0-win32-x64.node +0 -0
  14. package/build/Release/oracledb-6.0.0-win32-x64.node-buildinfo.txt +1 -0
  15. package/examples/README.md +113 -0
  16. package/examples/dbconfig.js +100 -0
  17. package/examples/example.js +156 -0
  18. package/index.js +26 -0
  19. package/lib/aqDeqOptions.js +146 -7
  20. package/lib/aqEnqOptions.js +59 -7
  21. package/lib/aqMessage.js +118 -7
  22. package/lib/aqQueue.js +242 -53
  23. package/lib/connection.js +1324 -465
  24. package/lib/constants.js +203 -0
  25. package/lib/dbObject.js +346 -32
  26. package/lib/errors.js +781 -0
  27. package/lib/impl/aqDeqOptions.js +197 -0
  28. package/lib/impl/aqEnqOptions.js +89 -0
  29. package/lib/impl/aqMessage.js +134 -0
  30. package/lib/impl/aqQueue.js +81 -0
  31. package/lib/impl/connection.js +529 -0
  32. package/lib/impl/dbObject.js +159 -0
  33. package/lib/impl/index.js +59 -0
  34. package/lib/impl/lob.js +85 -0
  35. package/lib/impl/pool.js +195 -0
  36. package/lib/impl/resultset.js +223 -0
  37. package/lib/impl/sodaCollection.js +174 -0
  38. package/lib/impl/sodaDatabase.js +81 -0
  39. package/lib/impl/sodaDocCursor.js +63 -0
  40. package/lib/impl/sodaDocument.js +98 -0
  41. package/lib/impl/sodaOperation.js +109 -0
  42. package/lib/lob.js +156 -68
  43. package/lib/oracledb.js +1047 -345
  44. package/lib/pool.js +654 -465
  45. package/lib/poolStatistics.js +23 -9
  46. package/lib/queryStream.js +14 -7
  47. package/lib/resultset.js +291 -183
  48. package/lib/settings.js +191 -0
  49. package/lib/sodaCollection.js +214 -201
  50. package/lib/sodaDatabase.js +107 -71
  51. package/lib/sodaDocCursor.js +44 -32
  52. package/lib/sodaDocument.js +76 -14
  53. package/lib/sodaOperation.js +131 -118
  54. package/lib/thin/connection.js +1038 -0
  55. package/lib/thin/dbObject.js +629 -0
  56. package/lib/thin/index.js +40 -0
  57. package/lib/thin/lob.js +188 -0
  58. package/lib/thin/pool.js +481 -0
  59. package/lib/thin/protocol/buffer.js +1040 -0
  60. package/lib/thin/protocol/capabilities.js +116 -0
  61. package/lib/thin/protocol/constants.js +764 -0
  62. package/lib/thin/protocol/encryptDecrypt.js +185 -0
  63. package/lib/thin/protocol/messages/auth.js +348 -0
  64. package/lib/thin/protocol/messages/base.js +475 -0
  65. package/lib/thin/protocol/messages/commit.js +56 -0
  66. package/lib/thin/protocol/messages/dataType.js +382 -0
  67. package/lib/thin/protocol/messages/execute.js +312 -0
  68. package/lib/thin/protocol/messages/fetch.js +60 -0
  69. package/lib/thin/protocol/messages/index.js +53 -0
  70. package/lib/thin/protocol/messages/lobOp.js +200 -0
  71. package/lib/thin/protocol/messages/logOff.js +53 -0
  72. package/lib/thin/protocol/messages/ping.js +56 -0
  73. package/lib/thin/protocol/messages/protocol.js +78 -0
  74. package/lib/thin/protocol/messages/rollback.js +56 -0
  75. package/lib/thin/protocol/messages/sessionRelease.js +60 -0
  76. package/lib/thin/protocol/messages/withData.js +811 -0
  77. package/lib/thin/protocol/oson.js +660 -0
  78. package/lib/thin/protocol/packet.js +520 -0
  79. package/lib/thin/protocol/protocol.js +202 -0
  80. package/lib/thin/protocol/utils.js +88 -0
  81. package/lib/thin/resultSet.js +122 -0
  82. package/lib/thin/sqlnet/connStrategy.js +175 -0
  83. package/lib/thin/sqlnet/constants.js +199 -0
  84. package/lib/thin/sqlnet/ezConnectResolver.js +488 -0
  85. package/lib/thin/sqlnet/navNodes.js +870 -0
  86. package/lib/thin/sqlnet/networkSession.js +620 -0
  87. package/lib/thin/sqlnet/ntTcp.js +525 -0
  88. package/lib/thin/sqlnet/nvStrToNvPair.js +783 -0
  89. package/lib/thin/sqlnet/packet.js +405 -0
  90. package/lib/thin/sqlnet/paramParser.js +205 -0
  91. package/lib/thin/sqlnet/sessionAtts.js +160 -0
  92. package/lib/thin/statement.js +301 -0
  93. package/lib/thin/util.js +289 -0
  94. package/lib/transformer.js +250 -0
  95. package/lib/types.js +357 -0
  96. package/lib/util.js +194 -110
  97. package/lib/version.js +36 -0
  98. package/package/README.md +33 -30
  99. package/package/install.js +89 -64
  100. package/package/prunebinaries.js +60 -12
  101. package/package.json +3 -3
  102. package/build/Release/oracledb-5.5.0-darwin-x64.node +0 -0
  103. package/build/Release/oracledb-5.5.0-darwin-x64.node-buildinfo.txt +0 -1
  104. package/build/Release/oracledb-5.5.0-linux-x64.node +0 -0
  105. package/build/Release/oracledb-5.5.0-linux-x64.node-buildinfo.txt +0 -1
  106. package/build/Release/oracledb-5.5.0-win32-x64.node +0 -0
  107. package/build/Release/oracledb-5.5.0-win32-x64.node-buildinfo.txt +0 -1
@@ -0,0 +1,783 @@
1
+ // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
2
+
3
+ //-----------------------------------------------------------------------------
4
+ //
5
+ // This software is dual-licensed to you under the Universal Permissive License
6
+ // (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
7
+ // 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
8
+ // either license.
9
+ //
10
+ // If you elect to accept the software under the Apache License, Version 2.0,
11
+ // the following applies:
12
+ //
13
+ // Licensed under the Apache License, Version 2.0 (the "License");
14
+ // you may not use this file except in compliance with the License.
15
+ // You may obtain a copy of the License at
16
+ //
17
+ // https://www.apache.org/licenses/LICENSE-2.0
18
+ //
19
+ // Unless required by applicable law or agreed to in writing, software
20
+ // distributed under the License is distributed on an "AS IS" BASIS,
21
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
+ // See the License for the specific language governing permissions and
23
+ // limitations under the License.
24
+ //
25
+ //-----------------------------------------------------------------------------
26
+
27
+ 'use strict';
28
+
29
+ const errors = require("../../errors.js");
30
+
31
+
32
+ /**
33
+ * Constant which implies that the VALUE has not been set to ATOM or LIST.
34
+ */
35
+ const RHS_NONE = 0;
36
+ /**
37
+ * Constant which implies that the VALUE of an NVPair is an ATOM.
38
+ */
39
+ const RHS_ATOM = 1;
40
+ /**
41
+ * Constant which indicates that the VALUE of an NVPair is a list of NVPairs.
42
+ */
43
+ const RHS_LIST = 2;
44
+ /**
45
+ * The List is in a regular format, i.e. (Name = Value) or (Name =
46
+ * (Name = Value)), and so on ..
47
+ */
48
+ const LIST_REGULAR = 3;
49
+ /**
50
+ * The List is comma separated and looks like ( Name = Value, Value, Value )
51
+ */
52
+ const LIST_COMMASEP = 4;
53
+
54
+ /**
55
+ * An NVPair, or Name-Value Pair, is the structure used by SQL*Net to store
56
+ * address information. An example of an NV-Pair is:
57
+ *
58
+ * CID = (ADDRESS = (PROTOCOL = TCP)(HOST = XYZ)(PORT = 1521))
59
+ *
60
+ * Here is a (brief) description of the syntax:
61
+ *
62
+ * NVPair -> ( name = value ) value = atom | NVList
63
+ */
64
+
65
+ class NVPair {
66
+ constructor(name) {
67
+ this.name = name;
68
+ this.listType = LIST_REGULAR;
69
+ this.rhsType = RHS_NONE;
70
+ }
71
+ set setAtom(atom) {
72
+ if (this._containsComment(atom)) {
73
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
74
+ }
75
+ this.rhsType = RHS_ATOM;
76
+ this.list = null;
77
+ this.atom = atom;
78
+ }
79
+ /**
80
+ * Checks if the input string contains comment.
81
+ * @param {string} str - input string
82
+ * @returns {boolean}
83
+ */
84
+ _containsComment(str) {
85
+ for (let i = 0; i < str.length; i++) {
86
+ if (str.charAt(i) == '#') {
87
+ if (i != 0) {
88
+ // Check if this character is escaped
89
+ if (str.charAt(i - 1) == '\\')
90
+ continue;
91
+ else
92
+ return true;
93
+ } else {
94
+ // Entire line is a comment
95
+ return true;
96
+ }
97
+ }
98
+ }
99
+ return false;
100
+ }
101
+
102
+ /**
103
+ * gets the size of the list.
104
+ * @returns {integer}
105
+ */
106
+ getListSize() {
107
+ if (this.list == null)
108
+ return 0;
109
+ else
110
+ return this.list.length;
111
+ }
112
+ /**
113
+ * gets the element at a given position in the list.
114
+ * @param {integer} pos
115
+ * @returns {string}
116
+ */
117
+ getListElement(pos) {
118
+ if (this.list == null)
119
+ return null;
120
+ else
121
+ return this.list[pos];
122
+ }
123
+ /**
124
+ * adds a nvpair to the existing one.
125
+ * @param {nvpair} pair
126
+ */
127
+ addListElement(pair) {
128
+ if (this.list == null) {
129
+ this.rhsType = RHS_LIST;
130
+ this.list = new Array();
131
+ this.atom = null;
132
+ }
133
+ this.list.push(pair);
134
+ pair.parent = this;
135
+ }
136
+ /**
137
+ * removes an element at a given position.
138
+ * @param {integer} pos
139
+ */
140
+ removeListElement(pos) {
141
+ if (this.list != null) {
142
+ this.list.splice(pos, 1);
143
+ if (this.getListSize == 0) {
144
+ this.list = null;
145
+ this.rhsType = RHS_NONE;
146
+ }
147
+ }
148
+ }
149
+ /**
150
+ * Returns an empty string with the number specified in the argument. Used for
151
+ * indentation of multi-level NVPairs as they are stored
152
+ *
153
+ * @param count
154
+ * Number of spaces required in the blank string.
155
+ */
156
+ _space(count) {
157
+ var blank_str = "";
158
+ for (let i = 0;i < count;i++) {
159
+ blank_str += " ";
160
+ }
161
+ return blank_str;
162
+ }
163
+
164
+ /**
165
+ * Returns the value of an NVPair (and all child NVPairs) as a readable
166
+ * String.
167
+ */
168
+ valueToString() {
169
+ let out = "";
170
+ if (this.rhsType == RHS_ATOM) {
171
+ out = out + this.atom;
172
+ } else if (this.rhsType == RHS_LIST) {
173
+ if (this.listType == LIST_REGULAR) {
174
+ for (let i = 0; i < this.getListSize(); i++) {
175
+ out = out + this.getListElement(i).toString();
176
+ }
177
+ } else if (this.listType == LIST_COMMASEP) {
178
+ for (let i = 0; i < this.getListSize(); i++) {
179
+ let listElem = this.getListElement(i);
180
+ out = out + listElem.name;
181
+ if (i != this.getListSize() - 1)
182
+ out = out + ", ";
183
+ }
184
+ }
185
+ }
186
+ return out;
187
+ }
188
+
189
+ /**
190
+ *
191
+ * @returns string representation of the nvpair
192
+ */
193
+ toString() {
194
+ let out = "(" + this.name + "=";
195
+ if (this.rhsType == RHS_ATOM) {
196
+ out = out + this.atom;
197
+ } else if (this.rhsType == RHS_LIST) {
198
+ if (this.listType == LIST_REGULAR) {
199
+ for (let i = 0; i < this.getListSize(); i++) {
200
+ out = out + this.getListElement(i).toString();
201
+ }
202
+ } else if (this.listType == LIST_COMMASEP) {
203
+ out = out + " (";
204
+ for (let i = 0; i < this.getListSize(); i++) {
205
+ let listElem = this.getListElement(i);
206
+ out = out + listElem.name;
207
+
208
+ if (i != this.getListSize() - 1)
209
+ out = out + ", ";
210
+ }
211
+ out = out + ")";
212
+ }
213
+ }
214
+ out = out + ")";
215
+ return out;
216
+ }
217
+
218
+
219
+ }
220
+ /**
221
+ * Constant which indicates that there are no more tokens left.
222
+ */
223
+ const TKN_NONE = 0;
224
+
225
+ /**
226
+ * Constant for left parenthesis '(' token.
227
+ */
228
+ const TKN_LPAREN = 1;
229
+
230
+ /**
231
+ * Constant for right parenthesis ')' token.
232
+ */
233
+ const TKN_RPAREN = 2;
234
+
235
+ /**
236
+ * Constant for comma token ',' token.
237
+ */
238
+ const TKN_COMMA = 3;
239
+
240
+ /**
241
+ * Constant for equal sign '=' token.
242
+ */
243
+ const TKN_EQUAL = 4;
244
+
245
+ /**
246
+ * Constant for literal token.
247
+ */
248
+ const TKN_LITERAL = 8;
249
+
250
+ /**
251
+ * Constant marking end of NVString.
252
+ */
253
+ const TKN_EOS = 9;
254
+
255
+ /*
256
+ * Characters used for comparison for tokens. When the analyzer hits and
257
+ * unescaped TKN_LPAREN_VALUE it interprets it as a TKN_LPAREN token.
258
+ */
259
+ const TKN_LPAREN_VALUE = '(';
260
+ const TKN_RPAREN_VALUE = ')';
261
+ const TKN_COMMA_VALUE = ',';
262
+ const TKN_EQUAL_VALUE = '=';
263
+ const TKN_BKSLASH_VALUE = '\\';
264
+ const TKN_DQUOTE_VALUE = "\"";
265
+ const TKN_SQUOTE_VALUE = '\'';
266
+ const TKN_EOS_VALUE = '%';
267
+
268
+ /*
269
+ * Characters which are considered whitespace.
270
+ */
271
+ const TKN_SPC_VALUE = ' ';
272
+ const TKN_TAB_VALUE = '\t';
273
+ const TKN_LF_VALUE = '\n';
274
+ const TKN_CR_VALUE = '\r';
275
+
276
+ /**
277
+ * The NVTokens class is used to help break NVStrings apart into tokens, such as
278
+ * TKN_LPAREN or TKN_LITERAL - this helps simplify the task of building NVPairs
279
+ * from an NVString.
280
+ */
281
+ class NVTokens {
282
+
283
+
284
+ /**
285
+ * Constructs NVTokens object for use.
286
+ */
287
+ constructor() {
288
+ this.tkType = null;
289
+ this.tkValue = null;
290
+ this.numTokens = 0;
291
+ this.tkPos = 0;
292
+ }
293
+
294
+ /*
295
+ * function to determine if a given character is whitespace. The
296
+ * following constitute whitespace: ' ' (SPACE), '\t' (TAB), '\n' (NEWLINE),
297
+ * '\r' (LINEFEED),
298
+ */
299
+ _isWhiteSpace(it) {
300
+ if ((it == TKN_SPC_VALUE) || (it == TKN_TAB_VALUE) || (it == TKN_LF_VALUE)
301
+ || (it == TKN_CR_VALUE)) {
302
+ return true;
303
+ }
304
+ return false;
305
+ }
306
+
307
+ /*
308
+ * function to trim leading and trailing spaces from a literal.
309
+ */
310
+ _trimWhiteSpace(it) {
311
+ let length = it.length;
312
+ let start = 0;
313
+ let end = length;
314
+
315
+ // Find first non-whitespace character
316
+ while ((start < length) && (this._isWhiteSpace(it.charAt(start)))) {
317
+ start++;
318
+ }
319
+ // From the back, find last non-whitespace character
320
+ while ((start < end) && (this._isWhiteSpace(it.charAt(end - 1)))) {
321
+ end--;
322
+ }
323
+ return it.substring(start, end);
324
+ }
325
+
326
+ /**
327
+ * Parses an NVString into a list of tokens which can be more easily
328
+ * interpreted. The list of tokens is stored within the class and must be
329
+ * accessed through getToken()/getLiteral() and eatToken().
330
+ *
331
+ * @param nvString
332
+ * NVString to be parsed.
333
+ */
334
+ parseTokens(nvString) {
335
+ this.numTokens = 0;
336
+ this.tkPos = 0;
337
+ this.tkType = new Array();
338
+ this.tkValue = new Array();
339
+
340
+ let len = nvString.length;
341
+ let eql_seen = false;
342
+ // convert NVString to character array for easier access
343
+ let input = new Array();
344
+ input = Array.from(nvString);
345
+ let pos = 0; // position in NVString
346
+
347
+ while (pos < len) {
348
+ // eat leading whitespace
349
+ while ((pos < len) && (this._isWhiteSpace(input[pos]))) {
350
+ pos++;
351
+ }
352
+ if (pos < len) {
353
+ switch (input[pos]) {
354
+ // For metacharacters (, ), and =, add to the token list, and
355
+ // advance the NVString position. (Save token, eat character)
356
+ case TKN_LPAREN_VALUE:
357
+ eql_seen = false;
358
+ this._addToken(TKN_LPAREN, TKN_LPAREN_VALUE);
359
+ pos++;
360
+ break;
361
+
362
+ case TKN_EQUAL_VALUE:
363
+ eql_seen = true;
364
+ this._addToken(TKN_EQUAL, TKN_EQUAL_VALUE);
365
+ pos++;
366
+ break;
367
+
368
+ case TKN_RPAREN_VALUE:
369
+ eql_seen = false;
370
+ this._addToken(TKN_RPAREN, TKN_RPAREN_VALUE);
371
+ pos++;
372
+ break;
373
+ case TKN_COMMA_VALUE:
374
+ eql_seen = false;
375
+ this._addToken(TKN_COMMA, TKN_COMMA_VALUE);
376
+ pos++;
377
+ break;
378
+
379
+ default: // Otherwise, treat it as a literal
380
+ {
381
+ let startPos = pos;
382
+ let endPos = -1; // substring position in input
383
+ let quoted_str = false; // is literal wrapped with quotes?
384
+ let quote_char = TKN_DQUOTE_VALUE;
385
+
386
+ // does it begin with a single or double quote?
387
+ if ((input[pos] == TKN_SQUOTE_VALUE)
388
+ || (input[pos] == TKN_DQUOTE_VALUE)) {
389
+ quoted_str = true;
390
+ quote_char = input[pos];
391
+ pos++;
392
+ startPos = pos;
393
+ }
394
+
395
+ while (pos < len) {
396
+ // On a backslash (escaped character), save the backslash and
397
+ // following character into the literal.
398
+ if (input[pos] == TKN_BKSLASH_VALUE) {
399
+ pos += 2;
400
+ continue;
401
+ }
402
+
403
+ if (quoted_str) { // literal wrapped with quotes
404
+ if (input[pos] == quote_char) {// quote terminator found
405
+ pos++;
406
+ endPos = pos - 1; // exclusive
407
+ break;
408
+ }
409
+ } else { // did we hit unescaped meta character ( ) or =
410
+ if ((input[pos] == TKN_LPAREN_VALUE)
411
+ || (input[pos] == TKN_RPAREN_VALUE)
412
+ || ((input[pos] == TKN_COMMA_VALUE) && !eql_seen)
413
+ || ((input[pos] == TKN_EQUAL_VALUE) && !eql_seen)) {
414
+ // terminate string - do NOT increment POS, or it will
415
+ // swallow the metacharacter into the literal
416
+ endPos = pos; // exclusive
417
+ break;
418
+ }
419
+ }
420
+ pos++; // accept character into literal
421
+ }
422
+
423
+ if (endPos == -1) { // reached end of NVString without terminator
424
+ endPos = pos; // exclusive
425
+ }
426
+ this._addToken(TKN_LITERAL,
427
+ nvString.substring(startPos, endPos).trim());
428
+ break;
429
+ }
430
+ }
431
+ }
432
+ }
433
+ // Add TKN_EOS as the last token in token list.
434
+ this._addToken(TKN_EOS, TKN_EOS_VALUE);
435
+ return true;
436
+ }
437
+ /**
438
+ * Returns current token. Throws Error if no string has
439
+ * been parsed, or if there are no tokens left. Does NOT advance
440
+ * the token position.
441
+ */
442
+ getToken() {
443
+ if (this.tkType == null) { // nothing parsed
444
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
445
+ }
446
+ if (this.tkPos < this.numTokens) {// are there tokens left?
447
+ return Number(this.tkType[this.tkPos]);
448
+ } else {
449
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
450
+ }
451
+ }
452
+
453
+ /**
454
+ * Returns current token. Throws Error if no string has
455
+ * been parsed, or if there are no tokens left. DOES advance the
456
+ * token position.
457
+ */
458
+ popToken() {
459
+ let token = TKN_NONE;
460
+
461
+ if (this.tkType == null) {
462
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
463
+ }
464
+ if (this.tkPos < this.numTokens) { // if parsed and tokens left
465
+ token = Number(this.tkType[this.tkPos++]);
466
+ } else {
467
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
468
+ }
469
+ return token;
470
+ }
471
+ /**
472
+ * Returns literal for current token. If current token is NOT a TKN_LITERAL,
473
+ * it returns a string representation of the current token. Throws
474
+ * Error if no string has been parsed, or
475
+ * if there are no tokens left.
476
+ *
477
+ * DOES NOT advance the token position.
478
+ */
479
+ getLiteral() {
480
+ let theLiteral = null;
481
+ if (this.tkValue == null) {
482
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
483
+ }
484
+ // If we have parsed an NV string AND we have tokens left
485
+ if (this.tkPos < this.numTokens) {
486
+ theLiteral = String(this.tkValue[this.tkPos]);
487
+ } else {
488
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
489
+ }
490
+ return theLiteral;
491
+ }
492
+
493
+ /**
494
+ * Returns literal for current token. If current token is NOT a TKN_LITERAL,
495
+ * it returns a string representation of the current token. Throws
496
+ * Error if no string has been parsed, or
497
+ * if there are no tokens left.
498
+ *
499
+ * DOES advance the token position.
500
+ */
501
+ popLiteral() {
502
+ let theLiteral = null;
503
+
504
+ if (this.tkValue == null) {
505
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
506
+ }
507
+ // If we have parsed an NV string AND we have tokens left.
508
+ if (this.tkPos < this.numTokens) {
509
+ theLiteral = String(this.tkValue[this.tkPos++]);
510
+ } else {
511
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
512
+ }
513
+ return theLiteral;
514
+ }
515
+
516
+ /**
517
+ * Advances the token position by one.
518
+ */
519
+ eatToken() {
520
+ if (this.tkPos < this.numTokens) {
521
+ this.tkPos++;
522
+ }
523
+ }
524
+
525
+ /**
526
+ * Returns NVTokens list as a readable String.
527
+ */
528
+ toString() {
529
+ if (this.tkType == null) {
530
+ return "*NO TOKENS*";
531
+ }
532
+ let out = "Tokens";
533
+ for (let i = 0; i < this.numTokens; i++) {
534
+ out = out + " : " + this.tkValue[i];
535
+ }
536
+ return out;
537
+ }
538
+ /*
539
+ * function to add a token and corresponding printable version (i.e.,
540
+ * TKN_LPAREN and TKN_LPAREN_VALUE) into the token list.
541
+ */
542
+ _addToken(tk, tk_val) {
543
+ this.tkType.push(Number(tk));
544
+ this.tkValue.push(String(tk_val));
545
+ this.numTokens++;
546
+ }
547
+ }
548
+
549
+
550
+
551
+
552
+ /**
553
+ * The NVFactory class is used to help interpret the tokens generated by
554
+ * NVTokens from an NVString.
555
+ */
556
+
557
+
558
+ /**
559
+ * Returns an NVPair which contains the broken-down form of nvString
560
+ * @param nvString the nvString to parse
561
+ */
562
+ function createNVPair(nvString) {
563
+ let nvt = new NVTokens();
564
+ nvt.parseTokens(nvString);
565
+ return readTopLevelNVPair(nvt);
566
+ }
567
+
568
+ /*
569
+ * function which returns a top-level NVPair from NVTokens.
570
+ * NVPair: (name=value)
571
+ * value: atom | NVList
572
+ */
573
+ function readTopLevelNVPair(nvt) {
574
+ //check for opening (
575
+ let tk = nvt.getToken();
576
+ nvt.eatToken();
577
+ if (tk != TKN_LPAREN) {
578
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
579
+ }
580
+
581
+ let name = readNVLiteral(nvt);
582
+ let nvp = new NVPair(name);
583
+
584
+ if ((tk = nvt.getToken()) == TKN_COMMA) {
585
+ // read comma'ed names as one name
586
+ while (tk == TKN_LITERAL || tk == TKN_COMMA) {
587
+ name += nvt.popLiteral();
588
+ tk = nvt.getToken();
589
+ }
590
+ nvp.name = name;
591
+
592
+ return readRightHandSide(nvp, nvt);
593
+ }
594
+
595
+ return readRightHandSide(nvp, nvt);
596
+ }
597
+ /*
598
+ * function which returns the next NVPair from NVTokens.
599
+ * NVPair: (name=value) | (name, | ,name) | ,name,
600
+ * value: atom | NVList
601
+ */
602
+ function readNVPair(nvt) {
603
+ // Opening ( or , for NVPair
604
+ let tk = nvt.getToken();
605
+ nvt.eatToken();
606
+ if (!((tk == TKN_LPAREN) || (tk == TKN_COMMA))) {
607
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
608
+ }
609
+
610
+ let name = readNVLiteral(nvt);
611
+ let nvp = new NVPair(name);
612
+
613
+ return readRightHandSide(nvp, nvt);
614
+ }
615
+
616
+ /*
617
+ * function which reads rhs and returns NVPair from NVTokens.
618
+ * NVPair: (name=value)
619
+ * value: atom | NVList
620
+ */
621
+ function readRightHandSide(nvp, nvt) {
622
+ let tk = nvt.getToken();
623
+ switch (tk) {
624
+ case TKN_EQUAL:
625
+ nvt.eatToken();
626
+
627
+ // If the next token after "=" is a LITERAL, then read an atom,
628
+ // otherwise read an NVList.
629
+ tk = nvt.getToken();
630
+ if (tk == TKN_LITERAL) {
631
+ let value = readNVLiteral(nvt);
632
+ nvp.setAtom = value;
633
+ } else {
634
+ // NVList is responsible for adding child NVPairs to this parent
635
+ // NVPair.
636
+ readNVList(nvt, nvp);
637
+ }
638
+ break;
639
+
640
+ case TKN_COMMA:
641
+ case TKN_RPAREN:
642
+
643
+ // If we get a "comma" or ")", then we need to parse a list of values.
644
+ // eg, "(x=(value1, value2,...))" or "(x=(value))"
645
+ nvp.setAtom = nvp.name;
646
+ break;
647
+
648
+ default:
649
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
650
+ }
651
+
652
+ // terminating ")" or "," for NVPair
653
+ tk = nvt.getToken();
654
+ if (tk == TKN_RPAREN) {
655
+ nvt.eatToken();
656
+ } else if (tk != TKN_COMMA) {
657
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
658
+ }
659
+
660
+ return nvp;
661
+ }
662
+ /*
663
+ * function which returns the next literal from NVTokens.
664
+ */
665
+ function readNVLiteral(nvt) {
666
+ let tk = nvt.getToken();
667
+ if (tk != TKN_LITERAL) {
668
+ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
669
+ }
670
+ return nvt.popLiteral();
671
+ }
672
+
673
+ /*
674
+ * function which adds a list of NVPairs to a parent NVPair.
675
+ * NVList: NVPair NVList | epsilon
676
+ */
677
+ function readNVList(nvt, parent) {
678
+ // if next token is "(" or ",", then read an NVPair
679
+ // otherwise, assume epsilon
680
+ let tk = nvt.getToken();
681
+ if (!(tk == TKN_LPAREN || tk == TKN_COMMA)) {
682
+ return; // didn't read an nvpair
683
+ }
684
+
685
+ let child = readNVPair(nvt);
686
+
687
+ // read a good NVPair
688
+ parent.addListElement(child);
689
+ if ((tk == TKN_COMMA) || (child.name == child.atom)) {
690
+ if (parent.getListType != LIST_COMMASEP) // if not already set
691
+ parent.setListType = LIST_COMMASEP; // set it
692
+ }
693
+
694
+ readNVList(nvt, parent); // next iteration of NVList()
695
+ }
696
+
697
+ /**
698
+ * Returns a NVPair whose name matches (ignoring case) the specified
699
+ * name. This function does search recursively through all descendents
700
+ * of the specified NVPair.
701
+ * @param nvp NVPair to search through
702
+ * @param name name to match (ignoring case)
703
+ */
704
+ function findNVPairRecurse(nvp, name) {
705
+ /* Is the base NV Pair the name we are looking for? */
706
+ if (!nvp) {
707
+ return null;
708
+ }
709
+ if ((name.toUpperCase() == (nvp.name).toUpperCase()))
710
+ return nvp;
711
+
712
+ /* Do we have anywhere else to search (ie, is nvp a list)? */
713
+ if (nvp.getRHSType == RHS_ATOM)
714
+ return null;
715
+
716
+ /* Loop thru the list of children and searching each child for name. */
717
+ for (let i = 0; i < nvp.getListSize(); i++) {
718
+ let child = findNVPairRecurse(nvp.getListElement(i), name);
719
+
720
+ /* Did we find "name"? */
721
+ if (child !== null)
722
+ return child;
723
+ }
724
+
725
+ return null;
726
+ }
727
+
728
+ /**
729
+ * Returns a NVPair whose name matches (ignoring case) the specified
730
+ * name. This functions only searches the direct descendants of specified NVPair
731
+ * @param nvp NVPair to search through
732
+ * @param name name to match (ignoring case)
733
+ */
734
+ function findNVPair(nvp, name) {
735
+ if (!nvp) {
736
+ return null;
737
+ }
738
+
739
+ /* Do we have anywhere else to search (ie, is nvp a list)? */
740
+ if (nvp.getRHSType == RHS_ATOM)
741
+ return null;
742
+
743
+ /* Loop thru the list of children and searching each child for name. */
744
+ for (let i = 0; i < nvp.getListSize(); i++) {
745
+ let child = nvp.getListElement(i);
746
+ if (name.toUpperCase() == (child.name).toUpperCase())
747
+ return child;
748
+ }
749
+ return null;
750
+ }
751
+
752
+ /**
753
+ * Returns a value which matches the specified path
754
+ * @param nvp NVPair to search through
755
+ * @param name array of names to match (ignoring case)
756
+ */
757
+ function findValue(nvp, names) {
758
+ if (!nvp) {
759
+ return null;
760
+ }
761
+
762
+ /* Is the base NV Pair the first name in path */
763
+ if ((names[0].toUpperCase() != (nvp.name).toUpperCase()))
764
+ return null;
765
+
766
+ let output = nvp;
767
+ let sze = names.length;
768
+
769
+ for (let i = 1; i < sze; i++) {
770
+ output = findNVPair(output, names[i]);
771
+ if (!output)
772
+ return null;
773
+ }
774
+ if (output.atom == null) {
775
+ if (output.list == null)
776
+ return null;
777
+ else
778
+ return (output.list).toString();
779
+ } else {
780
+ return (output.atom).toString();
781
+ }
782
+ }
783
+ module.exports = {findNVPairRecurse, createNVPair, findNVPair, findValue};