@readme/syntax-highlighter 15.0.2 → 16.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.
@@ -1,605 +0,0 @@
1
- // oxlint-disable react/no-this-in-sfc
2
- // oxlint-disable unicorn/consistent-function-scoping
3
- // oxlint-disable curly
4
- // oxlint-disable no-param-reassign
5
- // oxlint-disable typescript/no-require-imports
6
- // oxlint-disable func-names
7
- // oxlint-disable operator-assignment
8
- // oxlint-disable prefer-arrow-callback
9
- // oxlint-disable prefer-template
10
- // oxlint-disable no-return-assign
11
- // oxlint-disable no-unused-expressions
12
- // oxlint-disable no-prototype-builtins
13
- // oxlint-disable no-useless-escape
14
- // oxlint-disable eqeqeq
15
- // oxlint-disable global-require
16
-
17
- /**
18
- * This mode has been adapted from the source of `codemirror-solidity` as the way that library is
19
- * structured makes it impossible for us load as an isolated mode for our Codemirror needs. The
20
- * source is mostly presented as-is with the exception of a few areas adapted into to our coding
21
- * standards (such as using `const` instead of `let` for immutable data).
22
- *
23
- * @license MIT
24
- * @see {@link https://github.com/alincode/codemirror-solidity}
25
- */
26
- (function (mod) {
27
- if (typeof exports === 'object' && typeof module === 'object') {
28
- // CommonJS
29
- mod(require('codemirror/lib/codemirror'));
30
-
31
- // oxlint-disable-next-line no-undef
32
- } else if (typeof define === 'function' && define.amd) {
33
- // AMD
34
- // oxlint-disable-next-line no-undef
35
- define(['codemirror/lib/codemirror'], mod);
36
- } else {
37
- // Plain browser env
38
- // oxlint-disable-next-line no-undef
39
- mod(CodeMirror);
40
- }
41
- })(function (CodeMirror) {
42
- CodeMirror.defineMode('solidity', function (config) {
43
- const indentUnit = config.indentUnit;
44
-
45
- // let functionKeyword = 'function'
46
- // let functionNameKeyword = 'Name'
47
- // let leftBracketSign = '('
48
- // let rightBracketSign = ')'
49
- // let functionVariableName = 'variable'
50
- // let keyWordContract = 'contract'
51
-
52
- const keywords = {
53
- pragma: true,
54
- solidity: true,
55
- import: true,
56
- as: true,
57
- from: true,
58
- contract: true,
59
- constructor: true,
60
- is: true,
61
- function: true,
62
- modifier: true,
63
- // modifiers
64
- pure: true,
65
- view: true,
66
- payable: true,
67
- constant: true,
68
- anonymous: true,
69
- indexed: true,
70
- returns: true,
71
- return: true,
72
- event: true,
73
- struct: true,
74
- mapping: true,
75
- interface: true,
76
- using: true,
77
- library: true,
78
- storage: true,
79
- memory: true,
80
- calldata: true,
81
- public: true,
82
- private: true,
83
- external: true,
84
- internal: true,
85
- emit: true,
86
- assembly: true,
87
- abstract: true,
88
- after: true,
89
- catch: true,
90
- final: true,
91
- in: true,
92
- inline: true,
93
- let: true,
94
- match: true,
95
- null: true,
96
- of: true,
97
- relocatable: true,
98
- static: true,
99
- try: true,
100
- typeof: true,
101
- var: true,
102
- };
103
-
104
- const keywordsSpecial = {
105
- pragma: true,
106
- returns: true,
107
- address: true,
108
- contract: true,
109
- function: true,
110
- struct: true,
111
- };
112
-
113
- const keywordsEtherUnit = {
114
- wei: true,
115
- szabo: true,
116
- finney: true,
117
- ether: true,
118
- };
119
- const keywordsTimeUnit = {
120
- seconds: true,
121
- minutes: true,
122
- hours: true,
123
- days: true,
124
- weeks: true,
125
- };
126
- const keywordsBlockAndTransactionProperties = {
127
- block: ['coinbase', 'difficulty', 'gaslimit', 'number', 'timestamp'],
128
- msg: ['data', 'sender', 'sig', 'value'],
129
- tx: ['gasprice', 'origin'],
130
- };
131
- const keywordsMoreBlockAndTransactionProperties = {
132
- now: true,
133
- gasleft: true,
134
- blockhash: true,
135
- };
136
- const keywordsErrorHandling = {
137
- assert: true,
138
- require: true,
139
- revert: true,
140
- throw: true,
141
- };
142
- const keywordsMathematicalAndCryptographicFuctions = {
143
- addmod: true,
144
- mulmod: true,
145
- keccak256: true,
146
- sha256: true,
147
- ripemd160: true,
148
- ecrecover: true,
149
- };
150
- const keywordsContractRelated = {
151
- this: true,
152
- selfdestruct: true,
153
- super: true,
154
- };
155
- const keywordsTypeInformation = { type: true };
156
- const keywordsContractList = {};
157
-
158
- const keywordsControlStructures = {
159
- if: true,
160
- else: true,
161
- while: true,
162
- do: true,
163
- for: true,
164
- break: true,
165
- continue: true,
166
- switch: true,
167
- case: true,
168
- default: true,
169
- };
170
-
171
- const keywordsValueTypes = {
172
- bool: true,
173
- byte: true,
174
- string: true,
175
- enum: true,
176
- address: true,
177
- };
178
-
179
- const keywordsV0505NewReserve = {
180
- alias: true,
181
- apply: true,
182
- auto: true,
183
- copyof: true,
184
- define: true,
185
- immutable: true,
186
- implements: true,
187
- macro: true,
188
- mutable: true,
189
- override: true,
190
- partial: true,
191
- promise: true,
192
- reference: true,
193
- sealed: true,
194
- sizeof: true,
195
- supports: true,
196
- typedef: true,
197
- unchecked: true,
198
- };
199
-
200
- const keywordsAbiEncodeDecodeFunctions = {
201
- abi: ['decode', 'encodePacked', 'encodeWithSelector', 'encodeWithSignature', 'encode'],
202
- };
203
-
204
- const keywordsMembersOfAddressType = ['transfer', 'send', 'balance', 'call', 'delegatecall', 'staticcall'];
205
-
206
- const natSpecTags = ['title', 'author', 'notice', 'dev', 'param', 'return'];
207
-
208
- // let functionStructureStage = [{
209
- // function: ['function', 'returns']
210
- // },
211
- // leftBracketSign,
212
- // parameterName,
213
- // parameterValue,
214
- // rightBracketSign,
215
- // ];
216
-
217
- const atoms = {
218
- delete: true,
219
- new: true,
220
- true: true,
221
- false: true,
222
- // "iota": true, "nil": true, "append": true,
223
- // "cap": true, "close": true, "complex": true, "copy": true, "imag": true,
224
- // "make": true, "panic": true, "print": true,
225
- // "println": true, "real": true, "recover": true
226
- };
227
-
228
- const isOperatorChar = /[+\-*&^%:=<>!|\/~]/;
229
- const isNegativeChar = /[-]/;
230
-
231
- let curPunc;
232
-
233
- function tokenBase(stream, state) {
234
- let ch = stream.next();
235
-
236
- if (ch == '"' || ch == "'" || ch == '`') {
237
- state.tokenize = tokenString(ch);
238
- return state.tokenize(stream, state);
239
- }
240
-
241
- if (isVersion(stream, state)) return 'version';
242
-
243
- if (
244
- ch == '.' &&
245
- keywordsMembersOfAddressType.some(function (item) {
246
- return stream.match(`${item}`);
247
- })
248
- )
249
- return 'addressFunction';
250
-
251
- if (isNumber(ch, stream)) return 'number';
252
-
253
- if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
254
- return updateGarmmer(ch, state);
255
- }
256
-
257
- if (ch == '/') {
258
- if (stream.eat('*')) {
259
- state.tokenize = tokenComment;
260
- return tokenComment(stream, state);
261
- }
262
- if (stream.match(/\/{2}/)) {
263
- while ((ch = stream.next())) {
264
- if (ch == '@') {
265
- stream.backUp(1);
266
- state.grammar = 'doc';
267
- break;
268
- }
269
- }
270
- return 'doc';
271
- }
272
-
273
- if (stream.eat('/')) {
274
- stream.skipToEnd();
275
- return 'comment';
276
- }
277
- }
278
-
279
- if (isNegativeChar.test(ch)) {
280
- if (isNumber(stream.peek(), stream)) return 'number';
281
- return 'operator';
282
- }
283
-
284
- if (isOperatorChar.test(ch)) {
285
- stream.eatWhile(isOperatorChar);
286
- return 'operator';
287
- }
288
- stream.eatWhile(/[\w\$_\xa1-\uffff]/);
289
-
290
- const cur = stream.current();
291
-
292
- if (state.grammar == 'doc') {
293
- if (
294
- natSpecTags.some(function (item) {
295
- return cur == `@${item}`;
296
- })
297
- )
298
- return 'docReserve';
299
- return 'doc';
300
- }
301
-
302
- if (cur === 'solidity' && state.lastToken == 'pragma') {
303
- state.lastToken = state.lastToken + ' ' + cur;
304
- }
305
-
306
- if (keywords.propertyIsEnumerable(cur)) {
307
- if (cur == 'case' || cur == 'default') curPunc = 'case';
308
- if (keywordsSpecial.propertyIsEnumerable(cur)) state.lastToken = cur;
309
- // if (cur == 'function' && state.para == 'parameterMode')
310
- return 'keyword';
311
- }
312
-
313
- if (keywordsEtherUnit.propertyIsEnumerable(cur)) return 'etherUnit';
314
- if (keywordsContractRelated.propertyIsEnumerable(cur)) return 'contractRelated';
315
- if (
316
- keywordsControlStructures.propertyIsEnumerable(cur) ||
317
- keywordsTypeInformation.propertyIsEnumerable(cur) ||
318
- keywordsV0505NewReserve.propertyIsEnumerable(cur)
319
- )
320
- return 'keyword';
321
- if (
322
- keywordsValueTypes.propertyIsEnumerable(cur) ||
323
- keywordsTimeUnit.propertyIsEnumerable(cur) ||
324
- isValidInteger(cur) ||
325
- isValidBytes(cur) ||
326
- isValidFixed(cur)
327
- ) {
328
- state.lastToken = state.lastToken + 'variable';
329
- return 'keyword';
330
- }
331
-
332
- if (atoms.propertyIsEnumerable(cur)) return 'atom';
333
- if (keywordsErrorHandling.propertyIsEnumerable(cur)) return 'errorHandling';
334
- if (keywordsMathematicalAndCryptographicFuctions.propertyIsEnumerable(cur)) return 'mathematicalAndCryptographic';
335
-
336
- if (
337
- keywordsMoreBlockAndTransactionProperties.propertyIsEnumerable(cur) ||
338
- (keywordsBlockAndTransactionProperties.hasOwnProperty(cur) &&
339
- keywordsBlockAndTransactionProperties[cur].some(function (item) {
340
- return stream.match(`.${item}`);
341
- }))
342
- )
343
- return 'variable-2';
344
-
345
- if (
346
- keywordsAbiEncodeDecodeFunctions.hasOwnProperty(cur) &&
347
- keywordsAbiEncodeDecodeFunctions[cur].some(function (item) {
348
- return stream.match(`.${item}`);
349
- })
350
- )
351
- return 'abi';
352
-
353
- const style = updateHexLiterals(cur, stream);
354
- if (style != null) return style;
355
-
356
- if (
357
- (state.lastToken == 'functionName(' || state.lastToken == 'returns(') &&
358
- keywordsContractList.propertyIsEnumerable(cur)
359
- ) {
360
- state.lastToken += 'variable';
361
- return 'variable';
362
- }
363
- if (state.lastToken == 'function') {
364
- state.lastToken = 'functionName';
365
- if (state.para == null) {
366
- state.grammar = 'function';
367
- state.para = '';
368
- }
369
- // state.parasMode = isNaN(state.parasMode) ? 1 : state.functionLayerCount++;
370
- state.para += 'functionName';
371
- return 'functionName';
372
- }
373
-
374
- if (state.lastToken == 'functionName(variable') {
375
- state.lastToken = 'functionName(';
376
- return 'parameterValue';
377
- }
378
-
379
- if (state.lastToken == 'returns(variable') {
380
- state.lastToken = 'returns(';
381
- return 'parameterValue';
382
- }
383
-
384
- if (state.lastToken == 'address' && cur == 'payable') {
385
- state.lastToken = 'address payable';
386
- }
387
- if (state.lastToken == 'contract' || state.lastToken == 'struct') {
388
- keywordsContractList[cur] = true;
389
- state.lastToken = null;
390
- }
391
- if (state.grammar == 'function') {
392
- return 'parameterValue';
393
- }
394
-
395
- return 'variable';
396
- }
397
-
398
- function tokenString(quote) {
399
- return function (stream, state) {
400
- let escaped = false;
401
- let next;
402
- let end = false;
403
- while ((next = stream.next()) != null) {
404
- if (next == quote && !escaped) {
405
- end = true;
406
- break;
407
- }
408
- escaped = !escaped && quote != '`' && next == '\\';
409
- }
410
- if (end || !(escaped || quote == '`')) state.tokenize = tokenBase;
411
- return 'string';
412
- };
413
- }
414
-
415
- function tokenComment(stream, state) {
416
- let maybeEnd = false;
417
- let ch;
418
- while ((ch = stream.next())) {
419
- if (ch == '/' && maybeEnd) {
420
- state.tokenize = tokenBase;
421
- break;
422
- }
423
- maybeEnd = ch == '*';
424
- }
425
- return 'comment';
426
- }
427
-
428
- function isVersion(stream, state) {
429
- if (state.lastToken == 'pragma solidity') {
430
- state.lastToken = null;
431
- return (
432
- !state.startOfLine &&
433
- (stream.match(/[\^{0}][0-9\.]+/) || stream.match(/[\>\=]+?[\s]*[0-9\.]+[\s]*[\<]?[\s]*[0-9\.]+/))
434
- );
435
- }
436
- }
437
-
438
- function isNumber(ch, stream) {
439
- if (/[\d\.]/.test(ch)) {
440
- if (ch == '.') {
441
- stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/);
442
- } else if (ch == '0') {
443
- stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);
444
- } else {
445
- stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/);
446
- }
447
- return true;
448
- }
449
- }
450
-
451
- function isValidInteger(token) {
452
- if (token.match(/^[u]?int/)) {
453
- if (token.indexOf('t') + 1 == token.length) return true;
454
- const numberPart = token.substr(token.indexOf('t') + 1, token.length);
455
- return numberPart % 8 === 0 && numberPart <= 256;
456
- }
457
- }
458
-
459
- function isValidBytes(token) {
460
- if (token.match(/^bytes/)) {
461
- if (token.indexOf('s') + 1 == token.length) return true;
462
- const bytesPart = token.substr(token.indexOf('s') + 1, token.length);
463
- return bytesPart <= 32;
464
- }
465
- }
466
-
467
- function isValidFixed(token) {
468
- if (token.match(/^[u]?fixed([0-9]+x[0-9]+)?/)) {
469
- if (token.indexOf('d') + 1 == token.length) return true;
470
- const numberPart = token.substr(token.indexOf('d') + 1, token.length).split('x');
471
- return numberPart[0] % 8 === 0 && numberPart[0] <= 256 && numberPart[1] <= 80;
472
- }
473
- }
474
-
475
- function updateHexLiterals(token, stream) {
476
- if (token.match(/^hex/) && stream.peek() == '"') {
477
- let maybeEnd = false;
478
- let ch;
479
- let hexValue = '';
480
- let stringAfterHex = '';
481
- while ((ch = stream.next())) {
482
- stringAfterHex += ch;
483
- if (ch == '"' && maybeEnd) {
484
- hexValue = stringAfterHex.substring(1, stringAfterHex.length - 1);
485
- if (hexValue.match(/^[0-9a-fA-F]+$/)) {
486
- return 'number';
487
- }
488
-
489
- stream.backUp(stringAfterHex.length);
490
- break;
491
- }
492
- maybeEnd = maybeEnd || ch == '"';
493
- }
494
- }
495
- }
496
-
497
- function updateGarmmer(ch, state) {
498
- if (ch == ',' && state.para == 'functionName(variable') {
499
- state.para = 'functionName(';
500
- }
501
- if (state.para != null && state.para.startsWith('functionName')) {
502
- if (ch == ')') {
503
- if (state.para.endsWith('(')) {
504
- state.para = state.para.substr(0, state.para.length - 1);
505
- if (state.para == 'functionName') state.grammar = '';
506
- }
507
- } else if (ch == '(') {
508
- state.para += ch;
509
- }
510
- }
511
-
512
- if (ch == '(' && state.lastToken == 'functionName') {
513
- state.lastToken += ch;
514
- } else if (ch == ')' && state.lastToken == 'functionName(') {
515
- state.lastToken = null;
516
- } else if (ch == '(' && state.lastToken == 'returns') {
517
- state.lastToken += ch;
518
- } else if (ch == ')' && (state.lastToken == 'returns(' || state.lastToken == 'returns(variable')) {
519
- state.lastToken = null;
520
- }
521
- if (ch == '(' && state.lastToken == 'address') {
522
- state.lastToken += ch;
523
- }
524
- curPunc = ch;
525
- return null;
526
- }
527
-
528
- function Context(indented, column, type, align, prev) {
529
- this.indented = indented;
530
- this.column = column;
531
- this.type = type;
532
- this.align = align;
533
- this.prev = prev;
534
- }
535
- function pushContext(state, col, type) {
536
- return (state.context = new Context(state.indented, col, type, null, state.context));
537
- }
538
- function popContext(state) {
539
- if (!state.context.prev) return;
540
- const t = state.context.type;
541
- if (t == ')' || t == ']' || t == '}') state.indented = state.context.indented;
542
- return (state.context = state.context.prev);
543
- }
544
-
545
- // Interface
546
- return {
547
- startState(basecolumn) {
548
- return {
549
- tokenize: null,
550
- context: new Context((basecolumn || 0) - indentUnit, 0, 'top', false),
551
- indented: 0,
552
- startOfLine: true,
553
- };
554
- },
555
-
556
- token(stream, state) {
557
- const ctx = state.context;
558
- if (stream.sol()) {
559
- if (ctx.align == null) ctx.align = false;
560
- state.indented = stream.indentation();
561
- state.startOfLine = true;
562
- if (ctx.type == 'case') ctx.type = '}';
563
- if (state.grammar == 'doc') state.grammar = null;
564
- }
565
- if (stream.eatSpace()) return null;
566
- curPunc = null;
567
- const style = (state.tokenize || tokenBase)(stream, state);
568
-
569
- if (style == 'comment') return style;
570
- if (ctx.align == null) ctx.align = true;
571
-
572
- if (curPunc == '{') pushContext(state, stream.column(), '}');
573
- else if (curPunc == '[') pushContext(state, stream.column(), ']');
574
- else if (curPunc == '(') pushContext(state, stream.column(), ')');
575
- else if (curPunc == 'case') ctx.type = 'case';
576
- else if (curPunc == '}' && ctx.type == '}') popContext(state);
577
- else if (curPunc == ctx.type) popContext(state);
578
- state.startOfLine = false;
579
- return style;
580
- },
581
-
582
- indent(state, textAfter) {
583
- if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
584
- const ctx = state.context;
585
- const firstChar = textAfter && textAfter.charAt(0);
586
- if (ctx.type == 'case' && /^(?:case|default)\b/.test(textAfter)) {
587
- state.context.type = '}';
588
- return ctx.indented;
589
- }
590
- const closing = firstChar == ctx.type;
591
- if (ctx.align) return ctx.column + (closing ? 0 : 1);
592
- return ctx.indented + (closing ? 0 : indentUnit);
593
- },
594
-
595
- electricChars: '{}):',
596
- closeBrackets: '()[]{}\'\'""``',
597
- fold: 'brace',
598
- blockCommentStart: '/*',
599
- blockCommentEnd: '*/',
600
- lineComment: '//',
601
- };
602
- });
603
-
604
- CodeMirror.defineMIME('text/x-solidity', 'solidity');
605
- });
@@ -1,104 +0,0 @@
1
- // This is a mapping of languages that we support, but aren't directly loading the mode extension
2
- // Within `/src/codeMirror/index.jsx` and /src/codeEditor.index.jsx
3
- //
4
- // This list also includes a number of language aliases, as because of the way we're using
5
- // `CodeMirror.runMode` we can't take advantage of its known aliases in the mode extensions that
6
- // we're loading.
7
- //
8
- // There are 2 types of lookup, single and array. e.g. `html` needs to be rendered using
9
- // `htmlmixed`, but `java`, needs to be rendered using the `clike` mode.
10
- //
11
- export const modes = {
12
- asp: 'clike',
13
- aspx: 'clike',
14
- bash: 'shell',
15
- c: 'clike',
16
- 'c#': ['clike', 'text/x-csharp'],
17
- 'c++': ['clike', 'text/x-c++src'],
18
- clj: 'clojure',
19
- cljc: 'clojure',
20
- cljx: 'clojure',
21
- coffeescript: 'javascript',
22
- cplusplus: ['clike', 'text/x-c++src'],
23
- cpp: ['clike', 'text/x-c++src'],
24
- cql: ['sql', 'text/x-cassandra'],
25
- cs: ['clike', 'text/x-csharp'],
26
- csharp: ['clike', 'text/x-csharp'],
27
- curl: 'shell',
28
- d: 'd',
29
- diff: 'diff',
30
- ecmascript: 'javascript',
31
- erl: 'erlang',
32
- go: ['go', 'text/x-go'],
33
- gradle: 'groovy',
34
- gql: 'graphql',
35
- handlebars: 'htmlmixed',
36
- hbs: 'htmlmixed',
37
- html: 'htmlmixed',
38
- java: ['clike', 'text/x-java'],
39
- jl: 'julia',
40
- js: 'javascript',
41
- jsx: 'jsx',
42
- json: ['javascript', 'application/ld+json'],
43
- jruby: 'ruby',
44
- kotlin: ['clike', 'text/x-kotlin'],
45
- kt: ['clike', 'text/x-kotlin'],
46
- less: 'css',
47
- liquid: 'htmlmixed',
48
- lua: 'lua',
49
- node: 'javascript',
50
- macruby: 'ruby',
51
- markdown: 'gfm',
52
- md: 'gfm',
53
- ml: ['mllike', 'text/x-ocaml'],
54
- mssql: ['sql', 'text/x-mssql'],
55
- mysql: ['sql', 'text/x-mysql'],
56
- objc: ['clike', 'text/x-objectivec'],
57
- 'objc++': ['clike', 'text/x-objectivec++'],
58
- objcpp: ['clike', 'text/x-objectivec++'],
59
- objectivec: ['clike', 'text/x-objectivec'],
60
- objectivecpp: ['clike', 'text/x-objectivec++'],
61
- objectivecplusplus: ['clike', 'text/x-objectivec++'],
62
- ocaml: ['mllike', 'text/x-ocaml'],
63
- php: ['php', 'text/x-php'],
64
- pgsql: ['sql', 'text/x-pgsql'],
65
- pl: 'perl',
66
- plsql: ['sql', 'text/x-plsql'],
67
- postgres: ['sql', 'text/x-pgsql'],
68
- postgresql: ['sql', 'text/x-pgsql'],
69
- ps1: 'powershell',
70
- py: 'python',
71
- r: 'r',
72
- rake: 'ruby',
73
- rb: 'ruby',
74
- rbx: 'ruby',
75
- rs: 'rust',
76
- sass: 'css',
77
- scala: ['clike', 'text/x-scala'],
78
- scss: 'css',
79
- sh: 'shell',
80
- sol: 'solidity',
81
- solidity: 'solidity',
82
- sql: ['sql', 'text/x-sql'],
83
- sqlite: ['sql', 'text/x-sqlite'],
84
- styl: 'css',
85
- stylus: 'css',
86
- text: ['null', 'text/plain'],
87
- ts: ['javascript', 'text/typescript'],
88
- typescript: ['javascript', 'text/typescript'],
89
- xhtml: 'htmlmixed',
90
- yml: 'yaml',
91
- zsh: 'shell',
92
- } as const;
93
-
94
- export function getMode(lang: string): string {
95
- let mode: string | readonly [string, string] = lang;
96
- if (mode in modes) {
97
- mode = modes[mode as keyof typeof modes];
98
- if (Array.isArray(mode)) {
99
- [, mode] = mode;
100
- }
101
- }
102
-
103
- return mode as string;
104
- }