ssh-config 4.4.4 → 5.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ssh-config",
3
3
  "description": "SSH config parser and stringifier",
4
- "version": "4.4.4",
4
+ "version": "5.0.1",
5
5
  "author": "Chen Yangjian (https://www.cyj.me)",
6
6
  "repository": {
7
7
  "type": "git",
@@ -9,14 +9,22 @@ export interface Directive {
9
9
  after: string;
10
10
  param: string;
11
11
  separator: Separator;
12
- value: string | string[];
12
+ value: string | {
13
+ val: string;
14
+ separator: string;
15
+ quoted?: boolean;
16
+ }[];
13
17
  quoted?: boolean;
14
18
  }
15
19
  export interface Section extends Directive {
16
20
  config: SSHConfig;
17
21
  }
18
22
  export interface Match extends Section {
19
- criteria: Record<string, string | string[]>;
23
+ criteria: Record<string, string | {
24
+ val: string;
25
+ separator: string;
26
+ quoted?: boolean;
27
+ }[]>;
20
28
  }
21
29
  export interface Comment {
22
30
  type: LineType.COMMENT;
package/src/ssh-config.js CHANGED
@@ -3,7 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.stringify = exports.parse = exports.LineType = void 0;
6
+ exports.LineType = void 0;
7
+ exports.parse = parse;
8
+ exports.stringify = stringify;
7
9
  const glob_1 = __importDefault(require("./glob"));
8
10
  const child_process_1 = require("child_process");
9
11
  const os_1 = __importDefault(require("os"));
@@ -69,7 +71,8 @@ function match(criteria, context) {
69
71
  };
70
72
  for (const key in criteria) {
71
73
  const criterion = criteria[key];
72
- if (!testCriterion(key, criterion)) {
74
+ const values = Array.isArray(criterion) ? criterion.map(({ val }) => val) : criterion;
75
+ if (!testCriterion(key, values)) {
73
76
  return false;
74
77
  }
75
78
  }
@@ -112,18 +115,20 @@ class SSHConfig extends Array {
112
115
  };
113
116
  const obj = {};
114
117
  const setProperty = (name, value) => {
118
+ const val = Array.isArray(value) ? value.map(({ val }) => val) : value;
119
+ const val0 = Array.isArray(val) ? val[0] : val;
115
120
  if (MULTIPLE_VALUE_PROPS.includes(name)) {
116
- const list = obj[name] || (obj[name] = []);
117
- list.push(value);
121
+ const list = (obj[name] || (obj[name] = []));
122
+ list.push(...[].concat(val));
118
123
  }
119
124
  else if (obj[name] == null) {
120
125
  if (name === 'HostName') {
121
- context.params.HostName = value;
126
+ context.params.HostName = val0;
122
127
  }
123
128
  else if (name === 'User') {
124
- context.params.User = value;
129
+ context.params.User = val0;
125
130
  }
126
- obj[name] = value;
131
+ obj[name] = val;
127
132
  }
128
133
  };
129
134
  if (opts.User !== undefined) {
@@ -133,7 +138,7 @@ class SSHConfig extends Array {
133
138
  for (const line of this) {
134
139
  if (line.type !== LineType.DIRECTIVE)
135
140
  continue;
136
- if (line.param === 'Host' && (0, glob_1.default)(line.value, context.params.Host)) {
141
+ if (line.param === 'Host' && (0, glob_1.default)(Array.isArray(line.value) ? line.value.map(({ val }) => val) : line.value, context.params.Host)) {
137
142
  let canonicalizeHostName = false;
138
143
  let canonicalDomains = [];
139
144
  setProperty(line.param, line.value);
@@ -144,7 +149,7 @@ class SSHConfig extends Array {
144
149
  canonicalizeHostName = true;
145
150
  }
146
151
  if (/^CanonicalDomains$/i.test(subline.param) && Array.isArray(subline.value)) {
147
- canonicalDomains = subline.value;
152
+ canonicalDomains = subline.value.map(({ val }) => val);
148
153
  }
149
154
  }
150
155
  }
@@ -224,7 +229,7 @@ class SSHConfig extends Array {
224
229
  type: LineType.DIRECTIVE,
225
230
  param,
226
231
  separator: ' ',
227
- value,
232
+ value: Array.isArray(value) ? value.map((val, i) => ({ val, separator: i === 0 ? '' : ' ' })) : value,
228
233
  before: sectionLineFound ? indent : indent.replace(/ |\t/, ''),
229
234
  after: '\n',
230
235
  };
@@ -272,7 +277,7 @@ class SSHConfig extends Array {
272
277
  type: LineType.DIRECTIVE,
273
278
  param,
274
279
  separator: ' ',
275
- value,
280
+ value: Array.isArray(value) ? value.map((val, i) => ({ val, separator: i === 0 ? '' : ' ' })) : value,
276
281
  before: '',
277
282
  after: '\n',
278
283
  };
@@ -393,6 +398,11 @@ function parse(text) {
393
398
  function values() {
394
399
  const results = [];
395
400
  let val = '';
401
+ // whether current value is quoted or not
402
+ let valQuoted = false;
403
+ // the separator preceding current value
404
+ let valSeparator = ' ';
405
+ // whether current context is within quotations or not
396
406
  let quoted = false;
397
407
  let escaped = false;
398
408
  while (chr && !RE_LINE_BREAK.test(chr)) {
@@ -408,11 +418,14 @@ function parse(text) {
408
418
  }
409
419
  else if (quoted) {
410
420
  val += chr;
421
+ valQuoted = true;
411
422
  }
412
423
  else if (/[ \t=]/.test(chr)) {
413
424
  if (val) {
414
- results.push(val);
425
+ results.push({ val, separator: valSeparator, quoted: valQuoted });
415
426
  val = '';
427
+ valQuoted = false;
428
+ valSeparator = chr;
416
429
  }
417
430
  // otherwise ignore the space
418
431
  }
@@ -425,11 +438,11 @@ function parse(text) {
425
438
  chr = next();
426
439
  }
427
440
  if (quoted || escaped) {
428
- throw new Error(`Unexpected line break at ${results.concat(val).join(' ')}`);
441
+ throw new Error(`Unexpected line break at ${results.map(({ val }) => val).concat(val).join(' ')}`);
429
442
  }
430
443
  if (val)
431
- results.push(val);
432
- return results.length > 1 ? results : results[0];
444
+ results.push({ val, separator: valSeparator, quoted: valQuoted });
445
+ return results.length > 1 ? results : results[0].val;
433
446
  }
434
447
  function directive() {
435
448
  const type = LineType.DIRECTIVE;
@@ -450,11 +463,11 @@ function parse(text) {
450
463
  if (/^Match$/i.test(param)) {
451
464
  const criteria = {};
452
465
  if (typeof result.value === 'string') {
453
- result.value = [result.value];
466
+ result.value = [{ val: result.value, separator: '', quoted: result.quoted }];
454
467
  }
455
468
  let i = 0;
456
469
  while (i < result.value.length) {
457
- const keyword = result.value[i];
470
+ const { val: keyword } = result.value[i];
458
471
  switch (keyword.toLowerCase()) {
459
472
  case 'all':
460
473
  case 'canonical':
@@ -466,7 +479,7 @@ function parse(text) {
466
479
  if (i + 1 >= result.value.length) {
467
480
  throw new Error(`Missing value for match criteria ${keyword}`);
468
481
  }
469
- criteria[keyword] = result.value[i + 1];
482
+ criteria[keyword] = result.value[i + 1].val;
470
483
  i += 2;
471
484
  break;
472
485
  }
@@ -505,7 +518,6 @@ function parse(text) {
505
518
  }
506
519
  return configWas;
507
520
  }
508
- exports.parse = parse;
509
521
  /**
510
522
  * Stringify structured object into SSH config text.
511
523
  */
@@ -513,7 +525,11 @@ function stringify(config) {
513
525
  let str = '';
514
526
  function formatValue(value, quoted) {
515
527
  if (Array.isArray(value)) {
516
- return value.map(chunk => formatValue(chunk, RE_SPACE.test(chunk))).join(' ');
528
+ let result = '';
529
+ for (const { val, separator, quoted } of value) {
530
+ result += (result ? separator : '') + formatValue(val, quoted || RE_SPACE.test(val));
531
+ }
532
+ return result;
517
533
  }
518
534
  return quoted ? `"${value}"` : value;
519
535
  }
@@ -523,14 +539,14 @@ function stringify(config) {
523
539
  const value = formatValue(line.value, quoted);
524
540
  return `${line.param}${line.separator}${value}`;
525
541
  }
526
- const format = line => {
542
+ const format = (line) => {
527
543
  str += line.before;
528
544
  if (line.type === LineType.COMMENT) {
529
545
  str += line.content;
530
546
  }
531
547
  else if (line.type === LineType.DIRECTIVE && MULTIPLE_VALUE_PROPS.includes(line.param)) {
532
- [].concat(line.value).forEach(function (value, i, values) {
533
- str += formatDirective({ ...line, value });
548
+ (Array.isArray(line.value) ? line.value : [line.value]).forEach((value, i, values) => {
549
+ str += formatDirective({ ...line, value: typeof value !== 'string' ? value.val : value });
534
550
  if (i < values.length - 1)
535
551
  str += `\n${line.before}`;
536
552
  });
@@ -539,12 +555,11 @@ function stringify(config) {
539
555
  str += formatDirective(line);
540
556
  }
541
557
  str += line.after;
542
- if (line.config) {
558
+ if ('config' in line) {
543
559
  line.config.forEach(format);
544
560
  }
545
561
  };
546
562
  config.forEach(format);
547
563
  return str;
548
564
  }
549
- exports.stringify = stringify;
550
565
  //# sourceMappingURL=ssh-config.js.map