ssh-config 4.1.5 → 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/Readme.md +3 -1
- package/index.js +23 -473
- 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/Readme.md
CHANGED
|
@@ -108,12 +108,14 @@ config.find({ Host: 'example1' })
|
|
|
108
108
|
config.find(line => line.param == 'Host' && line.value == 'example1')
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
### `.remove` sections by Host or
|
|
111
|
+
### `.remove` sections by Host / Match or function
|
|
112
112
|
|
|
113
113
|
To remove sections, we can pass the section to `.remove(opts)`.
|
|
114
114
|
|
|
115
115
|
```js
|
|
116
116
|
config.remove({ Host: 'example1' })
|
|
117
|
+
// or the ES2015 Array.prototype.find
|
|
118
|
+
config.remove(line => line.param == 'Host' && line.value == 'example1')
|
|
117
119
|
```
|
|
118
120
|
|
|
119
121
|
### `.append` sections
|
package/index.js
CHANGED
|
@@ -1,473 +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 or Match
|
|
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
|
|
96
|
-
*/
|
|
97
|
-
remove(opts = {}) {
|
|
98
|
-
if (!(opts && ('Host' in opts || 'Match' in opts))) {
|
|
99
|
-
throw new Error('Can only remove by Host or Match')
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const index = typeof opts === 'function'
|
|
103
|
-
? super.findIndex(opts)
|
|
104
|
-
: super.findIndex(line => compare(line, opts))
|
|
105
|
-
|
|
106
|
-
if (index >= 0) return this.splice(index, 1)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* toString()
|
|
111
|
-
* @returns {string}
|
|
112
|
-
*/
|
|
113
|
-
toString() {
|
|
114
|
-
return this.constructor.stringify(this)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Append new section to existing ssh config.
|
|
120
|
-
* @param {Object} opts
|
|
121
|
-
*/
|
|
122
|
-
append(opts) {
|
|
123
|
-
const indent = getIndent(this)
|
|
124
|
-
const lastEntry = this.length > 0 ? this[this.length - 1] : null
|
|
125
|
-
let config = lastEntry && lastEntry.config || this
|
|
126
|
-
let configWas = this
|
|
127
|
-
|
|
128
|
-
let lastLine = config.length > 0 ? config[config.length - 1] : lastEntry
|
|
129
|
-
if (lastLine && !lastLine.after) lastLine.after = '\n'
|
|
130
|
-
|
|
131
|
-
for (const param in opts) {
|
|
132
|
-
const line = {
|
|
133
|
-
type: DIRECTIVE,
|
|
134
|
-
param,
|
|
135
|
-
separator: ' ',
|
|
136
|
-
value: opts[param],
|
|
137
|
-
before: '',
|
|
138
|
-
after: '\n'
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (RE_SECTION_DIRECTIVE.test(param)) {
|
|
142
|
-
config = configWas
|
|
143
|
-
// separate sections with an extra newline
|
|
144
|
-
// https://github.com/cyjake/ssh-config/issues/23#issuecomment-564768248
|
|
145
|
-
if (lastLine && lastLine.after === '\n') lastLine.after += '\n'
|
|
146
|
-
config.push(line)
|
|
147
|
-
config = line.config = new SSHConfig()
|
|
148
|
-
} else {
|
|
149
|
-
line.before = config === configWas ? '' : indent
|
|
150
|
-
config.push(line)
|
|
151
|
-
}
|
|
152
|
-
lastLine = line
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return configWas
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Prepend new section to existing ssh config.
|
|
160
|
-
* @param {Object} opts
|
|
161
|
-
*/
|
|
162
|
-
prepend(opts, beforeFirstSection = false) {
|
|
163
|
-
const indent = getIndent(this)
|
|
164
|
-
let config = this
|
|
165
|
-
let i = 0
|
|
166
|
-
|
|
167
|
-
// insert above known sections
|
|
168
|
-
if (beforeFirstSection) {
|
|
169
|
-
while (i < this.length && !RE_SECTION_DIRECTIVE.test(this[i].param)) {
|
|
170
|
-
i += 1
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (i >= this.length) { // No sections in original config
|
|
174
|
-
return this.append(opts)
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Prepend new section above the first section
|
|
179
|
-
let sectionLineFound = false
|
|
180
|
-
let processedLines = 0
|
|
181
|
-
|
|
182
|
-
for (const param in opts) {
|
|
183
|
-
processedLines += 1
|
|
184
|
-
const line = {
|
|
185
|
-
type: DIRECTIVE,
|
|
186
|
-
param,
|
|
187
|
-
separator: ' ',
|
|
188
|
-
value: opts[param],
|
|
189
|
-
before: '',
|
|
190
|
-
after: '\n'
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (RE_SECTION_DIRECTIVE.test(param)) {
|
|
194
|
-
config.splice(i, 0, line)
|
|
195
|
-
config = line.config = new SSHConfig()
|
|
196
|
-
sectionLineFound = true
|
|
197
|
-
continue
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// separate from previous sections with an extra newline
|
|
201
|
-
if (processedLines === Object.keys(opts).length) {
|
|
202
|
-
line.after += '\n'
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (!sectionLineFound) {
|
|
206
|
-
config.splice(i, 0, line)
|
|
207
|
-
i += 1
|
|
208
|
-
|
|
209
|
-
// Add an extra newline if a single line directive like Include
|
|
210
|
-
if (RE_SINGLE_LINE_DIRECTIVE.test(param)) {
|
|
211
|
-
line.after += '\n'
|
|
212
|
-
}
|
|
213
|
-
continue
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
line.before = indent
|
|
217
|
-
config.push(line)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return config
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Stringify structured object into ssh config text
|
|
225
|
-
* @param {SSHConfig} config
|
|
226
|
-
* @returns {string}
|
|
227
|
-
*/
|
|
228
|
-
static stringify(config) {
|
|
229
|
-
let str = ''
|
|
230
|
-
|
|
231
|
-
function formatValue(value, quoted) {
|
|
232
|
-
if (Array.isArray(value)) {
|
|
233
|
-
return value.map(chunk => formatValue(chunk, RE_SPACE.test(chunk))).join(' ')
|
|
234
|
-
}
|
|
235
|
-
return quoted ? `"${value}"` : value
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function formatDirective(line) {
|
|
239
|
-
const quoted = line.quoted
|
|
240
|
-
|| (RE_QUOTE_DIRECTIVE.test(line.param) && RE_SPACE.test(line.value))
|
|
241
|
-
const value = formatValue(line.value, quoted)
|
|
242
|
-
return `${line.param}${line.separator}${value}`
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const format = line => {
|
|
246
|
-
str += line.before
|
|
247
|
-
|
|
248
|
-
if (line.type === COMMENT) {
|
|
249
|
-
str += line.content
|
|
250
|
-
}
|
|
251
|
-
else if (line.type === DIRECTIVE && MULTIPLE_VALUE_PROPS.includes(line.param)) {
|
|
252
|
-
[].concat(line.value).forEach(function (value, i, values) {
|
|
253
|
-
str += formatDirective({ ...line, value })
|
|
254
|
-
if (i < values.length - 1) str += `\n${line.before}`
|
|
255
|
-
})
|
|
256
|
-
}
|
|
257
|
-
else if (line.type === DIRECTIVE) {
|
|
258
|
-
str += formatDirective(line)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
str += line.after
|
|
262
|
-
|
|
263
|
-
if (line.config) {
|
|
264
|
-
line.config.forEach(format)
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
config.forEach(format)
|
|
269
|
-
|
|
270
|
-
return str
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
static get DIRECTIVE() {
|
|
274
|
-
return DIRECTIVE
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
static get COMMENT() {
|
|
278
|
-
return COMMENT
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Parse ssh config text into structured object.
|
|
283
|
-
*/
|
|
284
|
-
static parse(str) {
|
|
285
|
-
let i = 0
|
|
286
|
-
let chr = next()
|
|
287
|
-
let config = new SSHConfig()
|
|
288
|
-
let configWas = config
|
|
289
|
-
|
|
290
|
-
function next() {
|
|
291
|
-
return str[i++]
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
function space() {
|
|
295
|
-
let spaces = ''
|
|
296
|
-
|
|
297
|
-
while (RE_SPACE.test(chr)) {
|
|
298
|
-
spaces += chr
|
|
299
|
-
chr = next()
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return spaces
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
function linebreak() {
|
|
306
|
-
let breaks = ''
|
|
307
|
-
|
|
308
|
-
while (RE_LINE_BREAK.test(chr)) {
|
|
309
|
-
breaks += chr
|
|
310
|
-
chr = next()
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return breaks
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function parameter() {
|
|
317
|
-
let param = ''
|
|
318
|
-
|
|
319
|
-
while (chr && /[^ \t=]/.test(chr)) {
|
|
320
|
-
param += chr
|
|
321
|
-
chr = next()
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
return param
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function separator() {
|
|
328
|
-
let sep = space()
|
|
329
|
-
|
|
330
|
-
if (chr === '=') {
|
|
331
|
-
sep += chr
|
|
332
|
-
chr = next()
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
return sep + space()
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function value() {
|
|
339
|
-
let val = ''
|
|
340
|
-
let quoted = false
|
|
341
|
-
let escaped = false
|
|
342
|
-
|
|
343
|
-
while (chr && !RE_LINE_BREAK.test(chr)) {
|
|
344
|
-
// backslash escapes only double quotes
|
|
345
|
-
if (escaped) {
|
|
346
|
-
val += chr === '"' ? chr : `\\${chr}`
|
|
347
|
-
escaped = false
|
|
348
|
-
}
|
|
349
|
-
// ProxyCommand ssh -W "%h:%p" firewall.example.org
|
|
350
|
-
else if (chr === '"' && (!val || quoted)) {
|
|
351
|
-
quoted = !quoted
|
|
352
|
-
}
|
|
353
|
-
else if (chr === '\\') {
|
|
354
|
-
escaped = true
|
|
355
|
-
}
|
|
356
|
-
else {
|
|
357
|
-
val += chr
|
|
358
|
-
}
|
|
359
|
-
chr = next()
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (quoted || escaped) {
|
|
363
|
-
throw new Error(`Unexpected line break at ${val}`)
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return val.trim()
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
function comment() {
|
|
370
|
-
const type = COMMENT
|
|
371
|
-
let content = ''
|
|
372
|
-
|
|
373
|
-
while (chr && !RE_LINE_BREAK.test(chr)) {
|
|
374
|
-
content += chr
|
|
375
|
-
chr = next()
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
return { type, content }
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// Host *.co.uk
|
|
382
|
-
// Host * !local.dev
|
|
383
|
-
// Host "foo bar"
|
|
384
|
-
function values() {
|
|
385
|
-
const results = []
|
|
386
|
-
let val = ''
|
|
387
|
-
let quoted = false
|
|
388
|
-
let escaped = false
|
|
389
|
-
|
|
390
|
-
while (chr && !RE_LINE_BREAK.test(chr)) {
|
|
391
|
-
if (escaped) {
|
|
392
|
-
val += chr === '"' ? chr : `\\${chr}`
|
|
393
|
-
escaped = false
|
|
394
|
-
}
|
|
395
|
-
else if (chr === '"') {
|
|
396
|
-
quoted = !quoted
|
|
397
|
-
}
|
|
398
|
-
else if (chr === '\\') {
|
|
399
|
-
escaped = true
|
|
400
|
-
}
|
|
401
|
-
else if (quoted) {
|
|
402
|
-
val += chr
|
|
403
|
-
}
|
|
404
|
-
else if (/[ \t]/.test(chr)) {
|
|
405
|
-
if (val) {
|
|
406
|
-
results.push(val)
|
|
407
|
-
val = ''
|
|
408
|
-
}
|
|
409
|
-
// otherwise ignore the space
|
|
410
|
-
}
|
|
411
|
-
else {
|
|
412
|
-
val += chr
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
chr = next()
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (quoted || escaped) {
|
|
419
|
-
throw new Error(`Unexpected line break at ${results.concat(val).join(' ')}`)
|
|
420
|
-
}
|
|
421
|
-
if (val) results.push(val)
|
|
422
|
-
return results.length > 1 ? results : results[0]
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
function directive() {
|
|
426
|
-
const type = DIRECTIVE
|
|
427
|
-
const param = parameter()
|
|
428
|
-
// Host "foo bar" baz
|
|
429
|
-
const multiple = RE_MULTI_VALUE_DIRECTIVE.test(param)
|
|
430
|
-
const result = {
|
|
431
|
-
type,
|
|
432
|
-
param,
|
|
433
|
-
separator: separator(),
|
|
434
|
-
quoted: !multiple && chr === '"',
|
|
435
|
-
value: multiple ? values() : value()
|
|
436
|
-
}
|
|
437
|
-
if (!result.quoted) delete result.quoted
|
|
438
|
-
return result
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
function line() {
|
|
442
|
-
const before = space()
|
|
443
|
-
const node = chr === '#' ? comment() : directive()
|
|
444
|
-
const after = linebreak()
|
|
445
|
-
|
|
446
|
-
node.before = before
|
|
447
|
-
node.after = after
|
|
448
|
-
|
|
449
|
-
return node
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
while (chr) {
|
|
453
|
-
let node = line()
|
|
454
|
-
|
|
455
|
-
if (node.type === DIRECTIVE && RE_SECTION_DIRECTIVE.test(node.param)) {
|
|
456
|
-
config = configWas
|
|
457
|
-
config.push(node)
|
|
458
|
-
config = node.config = new SSHConfig()
|
|
459
|
-
}
|
|
460
|
-
else if (node.type === DIRECTIVE && !node.param) {
|
|
461
|
-
// blank lines at file end
|
|
462
|
-
config[config.length - 1].after += node.before
|
|
463
|
-
}
|
|
464
|
-
else {
|
|
465
|
-
config.push(node)
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
return configWas
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
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
|