ssh-config 4.1.6 → 4.2.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.
- package/index.js +23 -478
- package/package.json +9 -7
- package/src/glob.js +29 -35
- package/src/glob.js.map +1 -0
- package/src/glob.ts +45 -0
- package/src/ssh-config.js +459 -0
- package/src/ssh-config.js.map +1 -0
- package/src/ssh-config.ts +544 -0
- package/types/index.d.ts +0 -46
package/index.js
CHANGED
|
@@ -1,478 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return opts.hasOwnProperty(line.param) && opts[line.param] === line.value
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function getIndent(config) {
|
|
28
|
-
for (const line of config) {
|
|
29
|
-
if (RE_SECTION_DIRECTIVE.test(line.param)) {
|
|
30
|
-
for (const subline of line.config) {
|
|
31
|
-
if (subline.before) {
|
|
32
|
-
return subline.before
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return ' '
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
class SSHConfig extends Array {
|
|
42
|
-
/**
|
|
43
|
-
* Query ssh config by host.
|
|
44
|
-
*
|
|
45
|
-
* @return {Object} The applied options of current Host
|
|
46
|
-
*/
|
|
47
|
-
compute(host) {
|
|
48
|
-
const obj = {}
|
|
49
|
-
const setProperty = (name, value) => {
|
|
50
|
-
if (MULTIPLE_VALUE_PROPS.includes(name)) {
|
|
51
|
-
const list = obj[name] || (obj[name] = [])
|
|
52
|
-
list.push(value)
|
|
53
|
-
}
|
|
54
|
-
else if (obj[name] == null) {
|
|
55
|
-
obj[name] = value
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
for (const line of this) {
|
|
60
|
-
if (line.type !== DIRECTIVE) continue
|
|
61
|
-
if (line.param === 'Host') {
|
|
62
|
-
if (glob(line.value, host)) {
|
|
63
|
-
setProperty(line.param, line.value)
|
|
64
|
-
|
|
65
|
-
line.config
|
|
66
|
-
.filter(line => line.type === DIRECTIVE)
|
|
67
|
-
.forEach(line => setProperty(line.param, line.value))
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
else if (line.param === 'Match') {
|
|
71
|
-
// TODO
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
setProperty(line.param, line.value)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return obj
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* find section by Host / Match or function
|
|
83
|
-
*/
|
|
84
|
-
find(opts = {}) {
|
|
85
|
-
if (typeof opts === 'function') return super.find(opts)
|
|
86
|
-
|
|
87
|
-
if (!(opts && ('Host' in opts || 'Match' in opts))) {
|
|
88
|
-
throw new Error('Can only find by Host or Match')
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return super.find(line => compare(line, opts))
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Remove section by Host / Match or function
|
|
96
|
-
*/
|
|
97
|
-
remove(opts = {}) {
|
|
98
|
-
let index;
|
|
99
|
-
|
|
100
|
-
if (typeof opts === 'function') {
|
|
101
|
-
index = super.findIndex(opts);
|
|
102
|
-
|
|
103
|
-
} else if (!(opts && ('Host' in opts || 'Match' in opts))) {
|
|
104
|
-
throw new Error('Can only remove by Host or Match');
|
|
105
|
-
|
|
106
|
-
} else {
|
|
107
|
-
index = super.findIndex(line => compare(line, opts));
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (index >= 0) return this.splice(index, 1)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* toString()
|
|
116
|
-
* @returns {string}
|
|
117
|
-
*/
|
|
118
|
-
toString() {
|
|
119
|
-
return this.constructor.stringify(this)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Append new section to existing ssh config.
|
|
125
|
-
* @param {Object} opts
|
|
126
|
-
*/
|
|
127
|
-
append(opts) {
|
|
128
|
-
const indent = getIndent(this)
|
|
129
|
-
const lastEntry = this.length > 0 ? this[this.length - 1] : null
|
|
130
|
-
let config = lastEntry && lastEntry.config || this
|
|
131
|
-
let configWas = this
|
|
132
|
-
|
|
133
|
-
let lastLine = config.length > 0 ? config[config.length - 1] : lastEntry
|
|
134
|
-
if (lastLine && !lastLine.after) lastLine.after = '\n'
|
|
135
|
-
|
|
136
|
-
for (const param in opts) {
|
|
137
|
-
const line = {
|
|
138
|
-
type: DIRECTIVE,
|
|
139
|
-
param,
|
|
140
|
-
separator: ' ',
|
|
141
|
-
value: opts[param],
|
|
142
|
-
before: '',
|
|
143
|
-
after: '\n'
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (RE_SECTION_DIRECTIVE.test(param)) {
|
|
147
|
-
config = configWas
|
|
148
|
-
// separate sections with an extra newline
|
|
149
|
-
// https://github.com/cyjake/ssh-config/issues/23#issuecomment-564768248
|
|
150
|
-
if (lastLine && lastLine.after === '\n') lastLine.after += '\n'
|
|
151
|
-
config.push(line)
|
|
152
|
-
config = line.config = new SSHConfig()
|
|
153
|
-
} else {
|
|
154
|
-
line.before = config === configWas ? '' : indent
|
|
155
|
-
config.push(line)
|
|
156
|
-
}
|
|
157
|
-
lastLine = line
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return configWas
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Prepend new section to existing ssh config.
|
|
165
|
-
* @param {Object} opts
|
|
166
|
-
*/
|
|
167
|
-
prepend(opts, beforeFirstSection = false) {
|
|
168
|
-
const indent = getIndent(this)
|
|
169
|
-
let config = this
|
|
170
|
-
let i = 0
|
|
171
|
-
|
|
172
|
-
// insert above known sections
|
|
173
|
-
if (beforeFirstSection) {
|
|
174
|
-
while (i < this.length && !RE_SECTION_DIRECTIVE.test(this[i].param)) {
|
|
175
|
-
i += 1
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (i >= this.length) { // No sections in original config
|
|
179
|
-
return this.append(opts)
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Prepend new section above the first section
|
|
184
|
-
let sectionLineFound = false
|
|
185
|
-
let processedLines = 0
|
|
186
|
-
|
|
187
|
-
for (const param in opts) {
|
|
188
|
-
processedLines += 1
|
|
189
|
-
const line = {
|
|
190
|
-
type: DIRECTIVE,
|
|
191
|
-
param,
|
|
192
|
-
separator: ' ',
|
|
193
|
-
value: opts[param],
|
|
194
|
-
before: '',
|
|
195
|
-
after: '\n'
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (RE_SECTION_DIRECTIVE.test(param)) {
|
|
199
|
-
config.splice(i, 0, line)
|
|
200
|
-
config = line.config = new SSHConfig()
|
|
201
|
-
sectionLineFound = true
|
|
202
|
-
continue
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// separate from previous sections with an extra newline
|
|
206
|
-
if (processedLines === Object.keys(opts).length) {
|
|
207
|
-
line.after += '\n'
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (!sectionLineFound) {
|
|
211
|
-
config.splice(i, 0, line)
|
|
212
|
-
i += 1
|
|
213
|
-
|
|
214
|
-
// Add an extra newline if a single line directive like Include
|
|
215
|
-
if (RE_SINGLE_LINE_DIRECTIVE.test(param)) {
|
|
216
|
-
line.after += '\n'
|
|
217
|
-
}
|
|
218
|
-
continue
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
line.before = indent
|
|
222
|
-
config.push(line)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return config
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Stringify structured object into ssh config text
|
|
230
|
-
* @param {SSHConfig} config
|
|
231
|
-
* @returns {string}
|
|
232
|
-
*/
|
|
233
|
-
static stringify(config) {
|
|
234
|
-
let str = ''
|
|
235
|
-
|
|
236
|
-
function formatValue(value, quoted) {
|
|
237
|
-
if (Array.isArray(value)) {
|
|
238
|
-
return value.map(chunk => formatValue(chunk, RE_SPACE.test(chunk))).join(' ')
|
|
239
|
-
}
|
|
240
|
-
return quoted ? `"${value}"` : value
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function formatDirective(line) {
|
|
244
|
-
const quoted = line.quoted
|
|
245
|
-
|| (RE_QUOTE_DIRECTIVE.test(line.param) && RE_SPACE.test(line.value))
|
|
246
|
-
const value = formatValue(line.value, quoted)
|
|
247
|
-
return `${line.param}${line.separator}${value}`
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const format = line => {
|
|
251
|
-
str += line.before
|
|
252
|
-
|
|
253
|
-
if (line.type === COMMENT) {
|
|
254
|
-
str += line.content
|
|
255
|
-
}
|
|
256
|
-
else if (line.type === DIRECTIVE && MULTIPLE_VALUE_PROPS.includes(line.param)) {
|
|
257
|
-
[].concat(line.value).forEach(function (value, i, values) {
|
|
258
|
-
str += formatDirective({ ...line, value })
|
|
259
|
-
if (i < values.length - 1) str += `\n${line.before}`
|
|
260
|
-
})
|
|
261
|
-
}
|
|
262
|
-
else if (line.type === DIRECTIVE) {
|
|
263
|
-
str += formatDirective(line)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
str += line.after
|
|
267
|
-
|
|
268
|
-
if (line.config) {
|
|
269
|
-
line.config.forEach(format)
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
config.forEach(format)
|
|
274
|
-
|
|
275
|
-
return str
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
static get DIRECTIVE() {
|
|
279
|
-
return DIRECTIVE
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
static get COMMENT() {
|
|
283
|
-
return COMMENT
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Parse ssh config text into structured object.
|
|
288
|
-
*/
|
|
289
|
-
static parse(str) {
|
|
290
|
-
let i = 0
|
|
291
|
-
let chr = next()
|
|
292
|
-
let config = new SSHConfig()
|
|
293
|
-
let configWas = config
|
|
294
|
-
|
|
295
|
-
function next() {
|
|
296
|
-
return str[i++]
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
function space() {
|
|
300
|
-
let spaces = ''
|
|
301
|
-
|
|
302
|
-
while (RE_SPACE.test(chr)) {
|
|
303
|
-
spaces += chr
|
|
304
|
-
chr = next()
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return spaces
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
function linebreak() {
|
|
311
|
-
let breaks = ''
|
|
312
|
-
|
|
313
|
-
while (RE_LINE_BREAK.test(chr)) {
|
|
314
|
-
breaks += chr
|
|
315
|
-
chr = next()
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
return breaks
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
function parameter() {
|
|
322
|
-
let param = ''
|
|
323
|
-
|
|
324
|
-
while (chr && /[^ \t=]/.test(chr)) {
|
|
325
|
-
param += chr
|
|
326
|
-
chr = next()
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return param
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function separator() {
|
|
333
|
-
let sep = space()
|
|
334
|
-
|
|
335
|
-
if (chr === '=') {
|
|
336
|
-
sep += chr
|
|
337
|
-
chr = next()
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return sep + space()
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function value() {
|
|
344
|
-
let val = ''
|
|
345
|
-
let quoted = false
|
|
346
|
-
let escaped = false
|
|
347
|
-
|
|
348
|
-
while (chr && !RE_LINE_BREAK.test(chr)) {
|
|
349
|
-
// backslash escapes only double quotes
|
|
350
|
-
if (escaped) {
|
|
351
|
-
val += chr === '"' ? chr : `\\${chr}`
|
|
352
|
-
escaped = false
|
|
353
|
-
}
|
|
354
|
-
// ProxyCommand ssh -W "%h:%p" firewall.example.org
|
|
355
|
-
else if (chr === '"' && (!val || quoted)) {
|
|
356
|
-
quoted = !quoted
|
|
357
|
-
}
|
|
358
|
-
else if (chr === '\\') {
|
|
359
|
-
escaped = true
|
|
360
|
-
}
|
|
361
|
-
else {
|
|
362
|
-
val += chr
|
|
363
|
-
}
|
|
364
|
-
chr = next()
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
if (quoted || escaped) {
|
|
368
|
-
throw new Error(`Unexpected line break at ${val}`)
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
return val.trim()
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
function comment() {
|
|
375
|
-
const type = COMMENT
|
|
376
|
-
let content = ''
|
|
377
|
-
|
|
378
|
-
while (chr && !RE_LINE_BREAK.test(chr)) {
|
|
379
|
-
content += chr
|
|
380
|
-
chr = next()
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return { type, content }
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Host *.co.uk
|
|
387
|
-
// Host * !local.dev
|
|
388
|
-
// Host "foo bar"
|
|
389
|
-
function values() {
|
|
390
|
-
const results = []
|
|
391
|
-
let val = ''
|
|
392
|
-
let quoted = false
|
|
393
|
-
let escaped = false
|
|
394
|
-
|
|
395
|
-
while (chr && !RE_LINE_BREAK.test(chr)) {
|
|
396
|
-
if (escaped) {
|
|
397
|
-
val += chr === '"' ? chr : `\\${chr}`
|
|
398
|
-
escaped = false
|
|
399
|
-
}
|
|
400
|
-
else if (chr === '"') {
|
|
401
|
-
quoted = !quoted
|
|
402
|
-
}
|
|
403
|
-
else if (chr === '\\') {
|
|
404
|
-
escaped = true
|
|
405
|
-
}
|
|
406
|
-
else if (quoted) {
|
|
407
|
-
val += chr
|
|
408
|
-
}
|
|
409
|
-
else if (/[ \t]/.test(chr)) {
|
|
410
|
-
if (val) {
|
|
411
|
-
results.push(val)
|
|
412
|
-
val = ''
|
|
413
|
-
}
|
|
414
|
-
// otherwise ignore the space
|
|
415
|
-
}
|
|
416
|
-
else {
|
|
417
|
-
val += chr
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
chr = next()
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
if (quoted || escaped) {
|
|
424
|
-
throw new Error(`Unexpected line break at ${results.concat(val).join(' ')}`)
|
|
425
|
-
}
|
|
426
|
-
if (val) results.push(val)
|
|
427
|
-
return results.length > 1 ? results : results[0]
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
function directive() {
|
|
431
|
-
const type = DIRECTIVE
|
|
432
|
-
const param = parameter()
|
|
433
|
-
// Host "foo bar" baz
|
|
434
|
-
const multiple = RE_MULTI_VALUE_DIRECTIVE.test(param)
|
|
435
|
-
const result = {
|
|
436
|
-
type,
|
|
437
|
-
param,
|
|
438
|
-
separator: separator(),
|
|
439
|
-
quoted: !multiple && chr === '"',
|
|
440
|
-
value: multiple ? values() : value()
|
|
441
|
-
}
|
|
442
|
-
if (!result.quoted) delete result.quoted
|
|
443
|
-
return result
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
function line() {
|
|
447
|
-
const before = space()
|
|
448
|
-
const node = chr === '#' ? comment() : directive()
|
|
449
|
-
const after = linebreak()
|
|
450
|
-
|
|
451
|
-
node.before = before
|
|
452
|
-
node.after = after
|
|
453
|
-
|
|
454
|
-
return node
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
while (chr) {
|
|
458
|
-
let node = line()
|
|
459
|
-
|
|
460
|
-
if (node.type === DIRECTIVE && RE_SECTION_DIRECTIVE.test(node.param)) {
|
|
461
|
-
config = configWas
|
|
462
|
-
config.push(node)
|
|
463
|
-
config = node.config = new SSHConfig()
|
|
464
|
-
}
|
|
465
|
-
else if (node.type === DIRECTIVE && !node.param) {
|
|
466
|
-
// blank lines at file end
|
|
467
|
-
config[config.length - 1].after += node.before
|
|
468
|
-
}
|
|
469
|
-
else {
|
|
470
|
-
config.push(node)
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
return configWas
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
module.exports = SSHConfig
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
const ssh_config_1 = __importDefault(require("./src/ssh-config"));
|
|
21
|
+
__exportStar(require("./src/ssh-config"), exports);
|
|
22
|
+
exports.default = ssh_config_1.default;
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
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
|
+
"version": "4.2.0",
|
|
5
5
|
"author": "Chen Yangjian (https://www.cyj.me)",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -9,20 +9,23 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"index.js",
|
|
12
|
-
"src"
|
|
13
|
-
"types"
|
|
12
|
+
"src"
|
|
14
13
|
],
|
|
15
14
|
"devDependencies": {
|
|
16
15
|
"@types/mocha": "^9.1.0",
|
|
17
|
-
"@types/node": "^17.0.
|
|
18
|
-
"eslint": "^
|
|
16
|
+
"@types/node": "^17.0.45",
|
|
17
|
+
"@typescript-eslint/eslint-plugin": "^5.48.0",
|
|
18
|
+
"@typescript-eslint/parser": "^5.48.0",
|
|
19
|
+
"eslint": "^8.31.0",
|
|
19
20
|
"heredoc": "^1.3.1",
|
|
20
21
|
"mocha": "^8.2.1",
|
|
21
22
|
"nyc": "^15.1.0",
|
|
22
23
|
"typescript": "^4.6.3"
|
|
23
24
|
},
|
|
24
25
|
"scripts": {
|
|
25
|
-
"lint": "eslint .",
|
|
26
|
+
"lint": "eslint --ext ts .",
|
|
27
|
+
"lint:fix": "eslint --ext ts --fix .",
|
|
28
|
+
"prepack": "tsc",
|
|
26
29
|
"pretest": "tsc",
|
|
27
30
|
"test": "NODE_OPTIONS=--enable-source-maps mocha --exit --recursive",
|
|
28
31
|
"test:coverage": "nyc mocha --exit --recursive && nyc report --reporter=lcov"
|
|
@@ -30,6 +33,5 @@
|
|
|
30
33
|
"engine": {
|
|
31
34
|
"node": ">= 10.0.0"
|
|
32
35
|
},
|
|
33
|
-
"types": "types/index.d.ts",
|
|
34
36
|
"license": "MIT"
|
|
35
37
|
}
|
package/src/glob.js
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function escapeChars(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return str
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
function escapeChars(text, chars) {
|
|
4
|
+
for (let char of chars) {
|
|
5
|
+
text = text.replace(new RegExp('\\' + char, 'g'), '\\' + char);
|
|
6
|
+
}
|
|
7
|
+
return text;
|
|
9
8
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return new RegExp('^(?:' + pattern + ')$').test(str)
|
|
9
|
+
function match(pattern, text) {
|
|
10
|
+
pattern = escapeChars(pattern, '\\()[]{}.+^$|');
|
|
11
|
+
pattern = pattern
|
|
12
|
+
.replace(/\*/g, '.*')
|
|
13
|
+
.replace(/\?/g, '.?');
|
|
14
|
+
return new RegExp('^(?:' + pattern + ')$').test(text);
|
|
18
15
|
}
|
|
19
|
-
|
|
20
16
|
/**
|
|
21
17
|
* A helper function to match input against [pattern-list](https://www.freebsd.org/cgi/man.cgi?query=ssh_config&sektion=5#PATTERNS).
|
|
22
18
|
* According to `man ssh_config`, negated patterns shall be matched first.
|
|
@@ -24,23 +20,21 @@ function match(pattern, str) {
|
|
|
24
20
|
* @param {string|string[]} patternList
|
|
25
21
|
* @param {string} str
|
|
26
22
|
*/
|
|
27
|
-
function glob(patternList,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
23
|
+
function glob(patternList, text) {
|
|
24
|
+
const patterns = Array.isArray(patternList) ? patternList : patternList.split(/,/);
|
|
25
|
+
// > If a negated entry is matched, then the Host entry is ignored, regardless of whether any other patterns on the line match.
|
|
26
|
+
let result = false;
|
|
27
|
+
for (const pattern of patterns) {
|
|
28
|
+
const negate = pattern[0] == '!';
|
|
29
|
+
if (negate && match(pattern.slice(1), text)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
else if (match(pattern, text)) {
|
|
33
|
+
// wait until all of the pattern match results because there might be a negated pattern
|
|
34
|
+
result = true;
|
|
35
|
+
}
|
|
40
36
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return result
|
|
37
|
+
return result;
|
|
44
38
|
}
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
exports.default = glob;
|
|
40
|
+
//# sourceMappingURL=glob.js.map
|
package/src/glob.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["glob.ts"],"names":[],"mappings":";;AACA,SAAS,WAAW,CAAC,IAAY,EAAE,KAAa;IAC9C,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE;QACtB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,CAAA;KAC/D;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,KAAK,CAAC,OAAe,EAAE,IAAY;IAC1C,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;IAC/C,OAAO,GAAG,OAAO;SACd,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IAEvB,OAAO,IAAI,MAAM,CAAC,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACvD,CAAC;AAED;;;;;;GAMG;AACH,SAAS,IAAI,CAAC,WAA8B,EAAE,IAAY;IACxD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAElF,+HAA+H;IAC/H,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;QAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;QAEhC,IAAI,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE;YAC3C,OAAO,KAAK,CAAA;SACb;aAAM,IAAI,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;YAC/B,uFAAuF;YACvF,MAAM,GAAG,IAAI,CAAA;SACd;KACF;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,kBAAe,IAAI,CAAA"}
|
package/src/glob.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
|
|
2
|
+
function escapeChars(text: string, chars: string) {
|
|
3
|
+
for (let char of chars) {
|
|
4
|
+
text = text.replace(new RegExp('\\' + char, 'g'), '\\' + char)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
return text
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function match(pattern: string, text: string) {
|
|
11
|
+
pattern = escapeChars(pattern, '\\()[]{}.+^$|')
|
|
12
|
+
pattern = pattern
|
|
13
|
+
.replace(/\*/g, '.*')
|
|
14
|
+
.replace(/\?/g, '.?')
|
|
15
|
+
|
|
16
|
+
return new RegExp('^(?:' + pattern + ')$').test(text)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A helper function to match input against [pattern-list](https://www.freebsd.org/cgi/man.cgi?query=ssh_config&sektion=5#PATTERNS).
|
|
21
|
+
* According to `man ssh_config`, negated patterns shall be matched first.
|
|
22
|
+
*
|
|
23
|
+
* @param {string|string[]} patternList
|
|
24
|
+
* @param {string} str
|
|
25
|
+
*/
|
|
26
|
+
function glob(patternList: string | string[], text: string) {
|
|
27
|
+
const patterns = Array.isArray(patternList) ? patternList : patternList.split(/,/)
|
|
28
|
+
|
|
29
|
+
// > If a negated entry is matched, then the Host entry is ignored, regardless of whether any other patterns on the line match.
|
|
30
|
+
let result = false
|
|
31
|
+
for (const pattern of patterns) {
|
|
32
|
+
const negate = pattern[0] == '!'
|
|
33
|
+
|
|
34
|
+
if (negate && match(pattern.slice(1), text)) {
|
|
35
|
+
return false
|
|
36
|
+
} else if (match(pattern, text)) {
|
|
37
|
+
// wait until all of the pattern match results because there might be a negated pattern
|
|
38
|
+
result = true
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return result
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default glob
|