brace-expansion 4.0.1 → 5.0.3
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/LICENSE +3 -1
- package/README.md +19 -58
- package/dist/commonjs/index.d.ts +6 -0
- package/dist/commonjs/index.d.ts.map +1 -0
- package/dist/commonjs/index.js +199 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/esm/index.d.ts +6 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +195 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/package.json +50 -36
- package/.github/FUNDING.yml +0 -2
- package/.github/workflows/ci.yml +0 -15
- package/bench/bench.js +0 -13
- package/index.js +0 -235
- package/tea.yaml +0 -6
package/LICENSE
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright
|
|
3
|
+
Copyright Julian Gruber <julian@juliangruber.com>
|
|
4
|
+
|
|
5
|
+
TypeScript port Copyright Isaac Z. Schlueter <i@izs.me>
|
|
4
6
|
|
|
5
7
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
8
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ as known from sh/bash, in JavaScript.
|
|
|
9
9
|
## Example
|
|
10
10
|
|
|
11
11
|
```js
|
|
12
|
-
import expand from 'brace-expansion'
|
|
12
|
+
import { expand } from 'brace-expansion'
|
|
13
13
|
|
|
14
14
|
expand('file-{a,b,c}.jpg')
|
|
15
15
|
// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
|
|
@@ -45,25 +45,36 @@ expand('ppp{,config,oe{,conf}}')
|
|
|
45
45
|
## API
|
|
46
46
|
|
|
47
47
|
```js
|
|
48
|
-
import expand from 'brace-expansion'
|
|
48
|
+
import { expand } from '@isaacs/brace-expansion'
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
### const expanded = expand(str)
|
|
51
|
+
### const expanded = expand(str, [options])
|
|
52
52
|
|
|
53
|
-
Return an array of all possible and valid expansions of `str`. If
|
|
54
|
-
found, `[str]` is returned.
|
|
53
|
+
Return an array of all possible and valid expansions of `str`. If
|
|
54
|
+
none are found, `[str]` is returned.
|
|
55
|
+
|
|
56
|
+
The `options` object can provide a `max` value to cap the number
|
|
57
|
+
of expansions allowed. This is limited to `100_000` by default,
|
|
58
|
+
to prevent DoS attacks.
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
const expansions = expand('{1..100}'.repeat(5), {
|
|
62
|
+
max: 100,
|
|
63
|
+
})
|
|
64
|
+
// expansions.length will be 100, not 100^5
|
|
65
|
+
```
|
|
55
66
|
|
|
56
67
|
Valid expansions are:
|
|
57
68
|
|
|
58
69
|
```js
|
|
59
|
-
|
|
70
|
+
;/^(.*,)+(.+)?$/
|
|
60
71
|
// {a,b,...}
|
|
61
72
|
```
|
|
62
73
|
|
|
63
74
|
A comma separated list of options, like `{a,b}` or `{a,{b,c}}` or `{,a,}`.
|
|
64
75
|
|
|
65
76
|
```js
|
|
66
|
-
|
|
77
|
+
;/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
|
|
67
78
|
// {x..y[..incr]}
|
|
68
79
|
```
|
|
69
80
|
|
|
@@ -72,7 +83,7 @@ If `x` or `y` start with a leading `0`, all the numbers will be padded
|
|
|
72
83
|
to have equal length. Negative numbers and backwards iteration work too.
|
|
73
84
|
|
|
74
85
|
```js
|
|
75
|
-
|
|
86
|
+
;/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
|
|
76
87
|
// {x..y[..incr]}
|
|
77
88
|
```
|
|
78
89
|
|
|
@@ -81,53 +92,3 @@ An alphabetic sequence from `x` to `y` inclusive, with optional increment.
|
|
|
81
92
|
number.
|
|
82
93
|
|
|
83
94
|
For compatibility reasons, the string `${` is not eligible for brace expansion.
|
|
84
|
-
|
|
85
|
-
## Installation
|
|
86
|
-
|
|
87
|
-
With [npm](https://npmjs.org) do:
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
npm install brace-expansion
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Contributors
|
|
94
|
-
|
|
95
|
-
- [Julian Gruber](https://github.com/juliangruber)
|
|
96
|
-
- [Isaac Z. Schlueter](https://github.com/isaacs)
|
|
97
|
-
- [Haelwenn Monnier](https://github.com/lanodan)
|
|
98
|
-
|
|
99
|
-
## Sponsors
|
|
100
|
-
|
|
101
|
-
This module is proudly supported by my [Sponsors](https://github.com/juliangruber/sponsors)!
|
|
102
|
-
|
|
103
|
-
Do you want to support modules like this to improve their quality, stability and weigh in on new features? Then please consider donating to my [Patreon](https://www.patreon.com/juliangruber). Not sure how much of my modules you're using? Try [feross/thanks](https://github.com/feross/thanks)!
|
|
104
|
-
|
|
105
|
-
## Security contact information
|
|
106
|
-
|
|
107
|
-
To report a security vulnerability, please use the
|
|
108
|
-
[Tidelift security contact](https://tidelift.com/security).
|
|
109
|
-
Tidelift will coordinate the fix and disclosure.
|
|
110
|
-
|
|
111
|
-
## License
|
|
112
|
-
|
|
113
|
-
(MIT)
|
|
114
|
-
|
|
115
|
-
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
|
116
|
-
|
|
117
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
118
|
-
this software and associated documentation files (the "Software"), to deal in
|
|
119
|
-
the Software without restriction, including without limitation the rights to
|
|
120
|
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
121
|
-
of the Software, and to permit persons to whom the Software is furnished to do
|
|
122
|
-
so, subject to the following conditions:
|
|
123
|
-
|
|
124
|
-
The above copyright notice and this permission notice shall be included in all
|
|
125
|
-
copies or substantial portions of the Software.
|
|
126
|
-
|
|
127
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
128
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
129
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
130
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
131
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
132
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
133
|
-
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,aAAa,SAAU,CAAA;AAwDpC,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,CAAA;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,YAkBtE"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EXPANSION_MAX = void 0;
|
|
4
|
+
exports.expand = expand;
|
|
5
|
+
const balanced_match_1 = require("balanced-match");
|
|
6
|
+
const escSlash = '\0SLASH' + Math.random() + '\0';
|
|
7
|
+
const escOpen = '\0OPEN' + Math.random() + '\0';
|
|
8
|
+
const escClose = '\0CLOSE' + Math.random() + '\0';
|
|
9
|
+
const escComma = '\0COMMA' + Math.random() + '\0';
|
|
10
|
+
const escPeriod = '\0PERIOD' + Math.random() + '\0';
|
|
11
|
+
const escSlashPattern = new RegExp(escSlash, 'g');
|
|
12
|
+
const escOpenPattern = new RegExp(escOpen, 'g');
|
|
13
|
+
const escClosePattern = new RegExp(escClose, 'g');
|
|
14
|
+
const escCommaPattern = new RegExp(escComma, 'g');
|
|
15
|
+
const escPeriodPattern = new RegExp(escPeriod, 'g');
|
|
16
|
+
const slashPattern = /\\\\/g;
|
|
17
|
+
const openPattern = /\\{/g;
|
|
18
|
+
const closePattern = /\\}/g;
|
|
19
|
+
const commaPattern = /\\,/g;
|
|
20
|
+
const periodPattern = /\\./g;
|
|
21
|
+
exports.EXPANSION_MAX = 100_000;
|
|
22
|
+
function numeric(str) {
|
|
23
|
+
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
|
|
24
|
+
}
|
|
25
|
+
function escapeBraces(str) {
|
|
26
|
+
return str
|
|
27
|
+
.replace(slashPattern, escSlash)
|
|
28
|
+
.replace(openPattern, escOpen)
|
|
29
|
+
.replace(closePattern, escClose)
|
|
30
|
+
.replace(commaPattern, escComma)
|
|
31
|
+
.replace(periodPattern, escPeriod);
|
|
32
|
+
}
|
|
33
|
+
function unescapeBraces(str) {
|
|
34
|
+
return str
|
|
35
|
+
.replace(escSlashPattern, '\\')
|
|
36
|
+
.replace(escOpenPattern, '{')
|
|
37
|
+
.replace(escClosePattern, '}')
|
|
38
|
+
.replace(escCommaPattern, ',')
|
|
39
|
+
.replace(escPeriodPattern, '.');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Basically just str.split(","), but handling cases
|
|
43
|
+
* where we have nested braced sections, which should be
|
|
44
|
+
* treated as individual members, like {a,{b,c},d}
|
|
45
|
+
*/
|
|
46
|
+
function parseCommaParts(str) {
|
|
47
|
+
if (!str) {
|
|
48
|
+
return [''];
|
|
49
|
+
}
|
|
50
|
+
const parts = [];
|
|
51
|
+
const m = (0, balanced_match_1.balanced)('{', '}', str);
|
|
52
|
+
if (!m) {
|
|
53
|
+
return str.split(',');
|
|
54
|
+
}
|
|
55
|
+
const { pre, body, post } = m;
|
|
56
|
+
const p = pre.split(',');
|
|
57
|
+
p[p.length - 1] += '{' + body + '}';
|
|
58
|
+
const postParts = parseCommaParts(post);
|
|
59
|
+
if (post.length) {
|
|
60
|
+
;
|
|
61
|
+
p[p.length - 1] += postParts.shift();
|
|
62
|
+
p.push.apply(p, postParts);
|
|
63
|
+
}
|
|
64
|
+
parts.push.apply(parts, p);
|
|
65
|
+
return parts;
|
|
66
|
+
}
|
|
67
|
+
function expand(str, options = {}) {
|
|
68
|
+
if (!str) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
const { max = exports.EXPANSION_MAX } = options;
|
|
72
|
+
// I don't know why Bash 4.3 does this, but it does.
|
|
73
|
+
// Anything starting with {} will have the first two bytes preserved
|
|
74
|
+
// but *only* at the top level, so {},a}b will not expand to anything,
|
|
75
|
+
// but a{},b}c will be expanded to [a}c,abc].
|
|
76
|
+
// One could argue that this is a bug in Bash, but since the goal of
|
|
77
|
+
// this module is to match Bash's rules, we escape a leading {}
|
|
78
|
+
if (str.slice(0, 2) === '{}') {
|
|
79
|
+
str = '\\{\\}' + str.slice(2);
|
|
80
|
+
}
|
|
81
|
+
return expand_(escapeBraces(str), max, true).map(unescapeBraces);
|
|
82
|
+
}
|
|
83
|
+
function embrace(str) {
|
|
84
|
+
return '{' + str + '}';
|
|
85
|
+
}
|
|
86
|
+
function isPadded(el) {
|
|
87
|
+
return /^-?0\d/.test(el);
|
|
88
|
+
}
|
|
89
|
+
function lte(i, y) {
|
|
90
|
+
return i <= y;
|
|
91
|
+
}
|
|
92
|
+
function gte(i, y) {
|
|
93
|
+
return i >= y;
|
|
94
|
+
}
|
|
95
|
+
function expand_(str, max, isTop) {
|
|
96
|
+
/** @type {string[]} */
|
|
97
|
+
const expansions = [];
|
|
98
|
+
const m = (0, balanced_match_1.balanced)('{', '}', str);
|
|
99
|
+
if (!m)
|
|
100
|
+
return [str];
|
|
101
|
+
// no need to expand pre, since it is guaranteed to be free of brace-sets
|
|
102
|
+
const pre = m.pre;
|
|
103
|
+
const post = m.post.length ? expand_(m.post, max, false) : [''];
|
|
104
|
+
if (/\$$/.test(m.pre)) {
|
|
105
|
+
for (let k = 0; k < post.length && k < max; k++) {
|
|
106
|
+
const expansion = pre + '{' + m.body + '}' + post[k];
|
|
107
|
+
expansions.push(expansion);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
|
112
|
+
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
|
113
|
+
const isSequence = isNumericSequence || isAlphaSequence;
|
|
114
|
+
const isOptions = m.body.indexOf(',') >= 0;
|
|
115
|
+
if (!isSequence && !isOptions) {
|
|
116
|
+
// {a},b}
|
|
117
|
+
if (m.post.match(/,(?!,).*\}/)) {
|
|
118
|
+
str = m.pre + '{' + m.body + escClose + m.post;
|
|
119
|
+
return expand_(str, max, true);
|
|
120
|
+
}
|
|
121
|
+
return [str];
|
|
122
|
+
}
|
|
123
|
+
let n;
|
|
124
|
+
if (isSequence) {
|
|
125
|
+
n = m.body.split(/\.\./);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
n = parseCommaParts(m.body);
|
|
129
|
+
if (n.length === 1 && n[0] !== undefined) {
|
|
130
|
+
// x{{a,b}}y ==> x{a}y x{b}y
|
|
131
|
+
n = expand_(n[0], max, false).map(embrace);
|
|
132
|
+
//XXX is this necessary? Can't seem to hit it in tests.
|
|
133
|
+
/* c8 ignore start */
|
|
134
|
+
if (n.length === 1) {
|
|
135
|
+
return post.map(p => m.pre + n[0] + p);
|
|
136
|
+
}
|
|
137
|
+
/* c8 ignore stop */
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// at this point, n is the parts, and we know it's not a comma set
|
|
141
|
+
// with a single entry.
|
|
142
|
+
let N;
|
|
143
|
+
if (isSequence && n[0] !== undefined && n[1] !== undefined) {
|
|
144
|
+
const x = numeric(n[0]);
|
|
145
|
+
const y = numeric(n[1]);
|
|
146
|
+
const width = Math.max(n[0].length, n[1].length);
|
|
147
|
+
let incr = n.length === 3 && n[2] !== undefined ? Math.abs(numeric(n[2])) : 1;
|
|
148
|
+
let test = lte;
|
|
149
|
+
const reverse = y < x;
|
|
150
|
+
if (reverse) {
|
|
151
|
+
incr *= -1;
|
|
152
|
+
test = gte;
|
|
153
|
+
}
|
|
154
|
+
const pad = n.some(isPadded);
|
|
155
|
+
N = [];
|
|
156
|
+
for (let i = x; test(i, y); i += incr) {
|
|
157
|
+
let c;
|
|
158
|
+
if (isAlphaSequence) {
|
|
159
|
+
c = String.fromCharCode(i);
|
|
160
|
+
if (c === '\\') {
|
|
161
|
+
c = '';
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
c = String(i);
|
|
166
|
+
if (pad) {
|
|
167
|
+
const need = width - c.length;
|
|
168
|
+
if (need > 0) {
|
|
169
|
+
const z = new Array(need + 1).join('0');
|
|
170
|
+
if (i < 0) {
|
|
171
|
+
c = '-' + z + c.slice(1);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
c = z + c;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
N.push(c);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
N = [];
|
|
184
|
+
for (let j = 0; j < n.length; j++) {
|
|
185
|
+
N.push.apply(N, expand_(n[j], max, false));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
for (let j = 0; j < N.length; j++) {
|
|
189
|
+
for (let k = 0; k < post.length && expansions.length < max; k++) {
|
|
190
|
+
const expansion = pre + N[j] + post[k];
|
|
191
|
+
if (!isTop || isSequence || expansion) {
|
|
192
|
+
expansions.push(expansion);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return expansions;
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { balanced } from 'balanced-match'\n\nconst escSlash = '\\0SLASH' + Math.random() + '\\0'\nconst escOpen = '\\0OPEN' + Math.random() + '\\0'\nconst escClose = '\\0CLOSE' + Math.random() + '\\0'\nconst escComma = '\\0COMMA' + Math.random() + '\\0'\nconst escPeriod = '\\0PERIOD' + Math.random() + '\\0'\nconst escSlashPattern = new RegExp(escSlash, 'g')\nconst escOpenPattern = new RegExp(escOpen, 'g')\nconst escClosePattern = new RegExp(escClose, 'g')\nconst escCommaPattern = new RegExp(escComma, 'g')\nconst escPeriodPattern = new RegExp(escPeriod, 'g')\nconst slashPattern = /\\\\\\\\/g\nconst openPattern = /\\\\{/g\nconst closePattern = /\\\\}/g\nconst commaPattern = /\\\\,/g\nconst periodPattern = /\\\\./g\n\nexport const EXPANSION_MAX = 100_000\n\nfunction numeric(str: string) {\n return !isNaN(str as any) ? parseInt(str, 10) : str.charCodeAt(0)\n}\n\nfunction escapeBraces(str: string) {\n return str\n .replace(slashPattern, escSlash)\n .replace(openPattern, escOpen)\n .replace(closePattern, escClose)\n .replace(commaPattern, escComma)\n .replace(periodPattern, escPeriod)\n}\n\nfunction unescapeBraces(str: string) {\n return str\n .replace(escSlashPattern, '\\\\')\n .replace(escOpenPattern, '{')\n .replace(escClosePattern, '}')\n .replace(escCommaPattern, ',')\n .replace(escPeriodPattern, '.')\n}\n\n/**\n * Basically just str.split(\",\"), but handling cases\n * where we have nested braced sections, which should be\n * treated as individual members, like {a,{b,c},d}\n */\nfunction parseCommaParts(str: string) {\n if (!str) {\n return ['']\n }\n\n const parts: string[] = []\n const m = balanced('{', '}', str)\n\n if (!m) {\n return str.split(',')\n }\n\n const { pre, body, post } = m\n const p = pre.split(',')\n\n p[p.length - 1] += '{' + body + '}'\n const postParts = parseCommaParts(post)\n if (post.length) {\n ;(p[p.length - 1] as string) += postParts.shift()\n p.push.apply(p, postParts)\n }\n\n parts.push.apply(parts, p)\n\n return parts\n}\n\nexport type BraceExpansionOptions = {\n max?: number\n}\n\nexport function expand(str: string, options: BraceExpansionOptions = {}) {\n if (!str) {\n return []\n }\n\n const { max = EXPANSION_MAX } = options\n\n // I don't know why Bash 4.3 does this, but it does.\n // Anything starting with {} will have the first two bytes preserved\n // but *only* at the top level, so {},a}b will not expand to anything,\n // but a{},b}c will be expanded to [a}c,abc].\n // One could argue that this is a bug in Bash, but since the goal of\n // this module is to match Bash's rules, we escape a leading {}\n if (str.slice(0, 2) === '{}') {\n str = '\\\\{\\\\}' + str.slice(2)\n }\n\n return expand_(escapeBraces(str), max, true).map(unescapeBraces)\n}\n\nfunction embrace(str: string) {\n return '{' + str + '}'\n}\n\nfunction isPadded(el: string) {\n return /^-?0\\d/.test(el)\n}\n\nfunction lte(i: number, y: number) {\n return i <= y\n}\n\nfunction gte(i: number, y: number) {\n return i >= y\n}\n\nfunction expand_(str: string, max: number, isTop: boolean): string[] {\n /** @type {string[]} */\n const expansions: string[] = []\n\n const m = balanced('{', '}', str)\n if (!m) return [str]\n\n // no need to expand pre, since it is guaranteed to be free of brace-sets\n const pre = m.pre\n const post: string[] = m.post.length ? expand_(m.post, max, false) : ['']\n\n if (/\\$$/.test(m.pre)) {\n for (let k = 0; k < post.length && k < max; k++) {\n const expansion = pre + '{' + m.body + '}' + post[k]\n expansions.push(expansion)\n }\n } else {\n const isNumericSequence = /^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(m.body)\n const isAlphaSequence = /^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(\n m.body,\n )\n const isSequence = isNumericSequence || isAlphaSequence\n const isOptions = m.body.indexOf(',') >= 0\n if (!isSequence && !isOptions) {\n // {a},b}\n if (m.post.match(/,(?!,).*\\}/)) {\n str = m.pre + '{' + m.body + escClose + m.post\n return expand_(str, max, true)\n }\n return [str]\n }\n\n let n: string[]\n if (isSequence) {\n n = m.body.split(/\\.\\./)\n } else {\n n = parseCommaParts(m.body)\n if (n.length === 1 && n[0] !== undefined) {\n // x{{a,b}}y ==> x{a}y x{b}y\n n = expand_(n[0], max, false).map(embrace)\n //XXX is this necessary? Can't seem to hit it in tests.\n /* c8 ignore start */\n if (n.length === 1) {\n return post.map(p => m.pre + n[0] + p)\n }\n /* c8 ignore stop */\n }\n }\n\n // at this point, n is the parts, and we know it's not a comma set\n // with a single entry.\n let N: string[]\n\n if (isSequence && n[0] !== undefined && n[1] !== undefined) {\n const x = numeric(n[0])\n const y = numeric(n[1])\n const width = Math.max(n[0].length, n[1].length)\n let incr =\n n.length === 3 && n[2] !== undefined ? Math.abs(numeric(n[2])) : 1\n let test = lte\n const reverse = y < x\n if (reverse) {\n incr *= -1\n test = gte\n }\n const pad = n.some(isPadded)\n\n N = []\n\n for (let i = x; test(i, y); i += incr) {\n let c\n if (isAlphaSequence) {\n c = String.fromCharCode(i)\n if (c === '\\\\') {\n c = ''\n }\n } else {\n c = String(i)\n if (pad) {\n const need = width - c.length\n if (need > 0) {\n const z = new Array(need + 1).join('0')\n if (i < 0) {\n c = '-' + z + c.slice(1)\n } else {\n c = z + c\n }\n }\n }\n }\n N.push(c)\n }\n } else {\n N = []\n\n for (let j = 0; j < n.length; j++) {\n N.push.apply(N, expand_(n[j] as string, max, false))\n }\n }\n\n for (let j = 0; j < N.length; j++) {\n for (let k = 0; k < post.length && expansions.length < max; k++) {\n const expansion = pre + N[j] + post[k]\n if (!isTop || isSequence || expansion) {\n expansions.push(expansion)\n }\n }\n }\n }\n\n return expansions\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,aAAa,SAAU,CAAA;AAwDpC,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,CAAA;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,YAkBtE"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { balanced } from 'balanced-match';
|
|
2
|
+
const escSlash = '\0SLASH' + Math.random() + '\0';
|
|
3
|
+
const escOpen = '\0OPEN' + Math.random() + '\0';
|
|
4
|
+
const escClose = '\0CLOSE' + Math.random() + '\0';
|
|
5
|
+
const escComma = '\0COMMA' + Math.random() + '\0';
|
|
6
|
+
const escPeriod = '\0PERIOD' + Math.random() + '\0';
|
|
7
|
+
const escSlashPattern = new RegExp(escSlash, 'g');
|
|
8
|
+
const escOpenPattern = new RegExp(escOpen, 'g');
|
|
9
|
+
const escClosePattern = new RegExp(escClose, 'g');
|
|
10
|
+
const escCommaPattern = new RegExp(escComma, 'g');
|
|
11
|
+
const escPeriodPattern = new RegExp(escPeriod, 'g');
|
|
12
|
+
const slashPattern = /\\\\/g;
|
|
13
|
+
const openPattern = /\\{/g;
|
|
14
|
+
const closePattern = /\\}/g;
|
|
15
|
+
const commaPattern = /\\,/g;
|
|
16
|
+
const periodPattern = /\\./g;
|
|
17
|
+
export const EXPANSION_MAX = 100_000;
|
|
18
|
+
function numeric(str) {
|
|
19
|
+
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
|
|
20
|
+
}
|
|
21
|
+
function escapeBraces(str) {
|
|
22
|
+
return str
|
|
23
|
+
.replace(slashPattern, escSlash)
|
|
24
|
+
.replace(openPattern, escOpen)
|
|
25
|
+
.replace(closePattern, escClose)
|
|
26
|
+
.replace(commaPattern, escComma)
|
|
27
|
+
.replace(periodPattern, escPeriod);
|
|
28
|
+
}
|
|
29
|
+
function unescapeBraces(str) {
|
|
30
|
+
return str
|
|
31
|
+
.replace(escSlashPattern, '\\')
|
|
32
|
+
.replace(escOpenPattern, '{')
|
|
33
|
+
.replace(escClosePattern, '}')
|
|
34
|
+
.replace(escCommaPattern, ',')
|
|
35
|
+
.replace(escPeriodPattern, '.');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Basically just str.split(","), but handling cases
|
|
39
|
+
* where we have nested braced sections, which should be
|
|
40
|
+
* treated as individual members, like {a,{b,c},d}
|
|
41
|
+
*/
|
|
42
|
+
function parseCommaParts(str) {
|
|
43
|
+
if (!str) {
|
|
44
|
+
return [''];
|
|
45
|
+
}
|
|
46
|
+
const parts = [];
|
|
47
|
+
const m = balanced('{', '}', str);
|
|
48
|
+
if (!m) {
|
|
49
|
+
return str.split(',');
|
|
50
|
+
}
|
|
51
|
+
const { pre, body, post } = m;
|
|
52
|
+
const p = pre.split(',');
|
|
53
|
+
p[p.length - 1] += '{' + body + '}';
|
|
54
|
+
const postParts = parseCommaParts(post);
|
|
55
|
+
if (post.length) {
|
|
56
|
+
;
|
|
57
|
+
p[p.length - 1] += postParts.shift();
|
|
58
|
+
p.push.apply(p, postParts);
|
|
59
|
+
}
|
|
60
|
+
parts.push.apply(parts, p);
|
|
61
|
+
return parts;
|
|
62
|
+
}
|
|
63
|
+
export function expand(str, options = {}) {
|
|
64
|
+
if (!str) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
const { max = EXPANSION_MAX } = options;
|
|
68
|
+
// I don't know why Bash 4.3 does this, but it does.
|
|
69
|
+
// Anything starting with {} will have the first two bytes preserved
|
|
70
|
+
// but *only* at the top level, so {},a}b will not expand to anything,
|
|
71
|
+
// but a{},b}c will be expanded to [a}c,abc].
|
|
72
|
+
// One could argue that this is a bug in Bash, but since the goal of
|
|
73
|
+
// this module is to match Bash's rules, we escape a leading {}
|
|
74
|
+
if (str.slice(0, 2) === '{}') {
|
|
75
|
+
str = '\\{\\}' + str.slice(2);
|
|
76
|
+
}
|
|
77
|
+
return expand_(escapeBraces(str), max, true).map(unescapeBraces);
|
|
78
|
+
}
|
|
79
|
+
function embrace(str) {
|
|
80
|
+
return '{' + str + '}';
|
|
81
|
+
}
|
|
82
|
+
function isPadded(el) {
|
|
83
|
+
return /^-?0\d/.test(el);
|
|
84
|
+
}
|
|
85
|
+
function lte(i, y) {
|
|
86
|
+
return i <= y;
|
|
87
|
+
}
|
|
88
|
+
function gte(i, y) {
|
|
89
|
+
return i >= y;
|
|
90
|
+
}
|
|
91
|
+
function expand_(str, max, isTop) {
|
|
92
|
+
/** @type {string[]} */
|
|
93
|
+
const expansions = [];
|
|
94
|
+
const m = balanced('{', '}', str);
|
|
95
|
+
if (!m)
|
|
96
|
+
return [str];
|
|
97
|
+
// no need to expand pre, since it is guaranteed to be free of brace-sets
|
|
98
|
+
const pre = m.pre;
|
|
99
|
+
const post = m.post.length ? expand_(m.post, max, false) : [''];
|
|
100
|
+
if (/\$$/.test(m.pre)) {
|
|
101
|
+
for (let k = 0; k < post.length && k < max; k++) {
|
|
102
|
+
const expansion = pre + '{' + m.body + '}' + post[k];
|
|
103
|
+
expansions.push(expansion);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
|
108
|
+
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
|
109
|
+
const isSequence = isNumericSequence || isAlphaSequence;
|
|
110
|
+
const isOptions = m.body.indexOf(',') >= 0;
|
|
111
|
+
if (!isSequence && !isOptions) {
|
|
112
|
+
// {a},b}
|
|
113
|
+
if (m.post.match(/,(?!,).*\}/)) {
|
|
114
|
+
str = m.pre + '{' + m.body + escClose + m.post;
|
|
115
|
+
return expand_(str, max, true);
|
|
116
|
+
}
|
|
117
|
+
return [str];
|
|
118
|
+
}
|
|
119
|
+
let n;
|
|
120
|
+
if (isSequence) {
|
|
121
|
+
n = m.body.split(/\.\./);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
n = parseCommaParts(m.body);
|
|
125
|
+
if (n.length === 1 && n[0] !== undefined) {
|
|
126
|
+
// x{{a,b}}y ==> x{a}y x{b}y
|
|
127
|
+
n = expand_(n[0], max, false).map(embrace);
|
|
128
|
+
//XXX is this necessary? Can't seem to hit it in tests.
|
|
129
|
+
/* c8 ignore start */
|
|
130
|
+
if (n.length === 1) {
|
|
131
|
+
return post.map(p => m.pre + n[0] + p);
|
|
132
|
+
}
|
|
133
|
+
/* c8 ignore stop */
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// at this point, n is the parts, and we know it's not a comma set
|
|
137
|
+
// with a single entry.
|
|
138
|
+
let N;
|
|
139
|
+
if (isSequence && n[0] !== undefined && n[1] !== undefined) {
|
|
140
|
+
const x = numeric(n[0]);
|
|
141
|
+
const y = numeric(n[1]);
|
|
142
|
+
const width = Math.max(n[0].length, n[1].length);
|
|
143
|
+
let incr = n.length === 3 && n[2] !== undefined ? Math.abs(numeric(n[2])) : 1;
|
|
144
|
+
let test = lte;
|
|
145
|
+
const reverse = y < x;
|
|
146
|
+
if (reverse) {
|
|
147
|
+
incr *= -1;
|
|
148
|
+
test = gte;
|
|
149
|
+
}
|
|
150
|
+
const pad = n.some(isPadded);
|
|
151
|
+
N = [];
|
|
152
|
+
for (let i = x; test(i, y); i += incr) {
|
|
153
|
+
let c;
|
|
154
|
+
if (isAlphaSequence) {
|
|
155
|
+
c = String.fromCharCode(i);
|
|
156
|
+
if (c === '\\') {
|
|
157
|
+
c = '';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
c = String(i);
|
|
162
|
+
if (pad) {
|
|
163
|
+
const need = width - c.length;
|
|
164
|
+
if (need > 0) {
|
|
165
|
+
const z = new Array(need + 1).join('0');
|
|
166
|
+
if (i < 0) {
|
|
167
|
+
c = '-' + z + c.slice(1);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
c = z + c;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
N.push(c);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
N = [];
|
|
180
|
+
for (let j = 0; j < n.length; j++) {
|
|
181
|
+
N.push.apply(N, expand_(n[j], max, false));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
for (let j = 0; j < N.length; j++) {
|
|
185
|
+
for (let k = 0; k < post.length && expansions.length < max; k++) {
|
|
186
|
+
const expansion = pre + N[j] + post[k];
|
|
187
|
+
if (!isTop || isSequence || expansion) {
|
|
188
|
+
expansions.push(expansion);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return expansions;
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { balanced } from 'balanced-match'\n\nconst escSlash = '\\0SLASH' + Math.random() + '\\0'\nconst escOpen = '\\0OPEN' + Math.random() + '\\0'\nconst escClose = '\\0CLOSE' + Math.random() + '\\0'\nconst escComma = '\\0COMMA' + Math.random() + '\\0'\nconst escPeriod = '\\0PERIOD' + Math.random() + '\\0'\nconst escSlashPattern = new RegExp(escSlash, 'g')\nconst escOpenPattern = new RegExp(escOpen, 'g')\nconst escClosePattern = new RegExp(escClose, 'g')\nconst escCommaPattern = new RegExp(escComma, 'g')\nconst escPeriodPattern = new RegExp(escPeriod, 'g')\nconst slashPattern = /\\\\\\\\/g\nconst openPattern = /\\\\{/g\nconst closePattern = /\\\\}/g\nconst commaPattern = /\\\\,/g\nconst periodPattern = /\\\\./g\n\nexport const EXPANSION_MAX = 100_000\n\nfunction numeric(str: string) {\n return !isNaN(str as any) ? parseInt(str, 10) : str.charCodeAt(0)\n}\n\nfunction escapeBraces(str: string) {\n return str\n .replace(slashPattern, escSlash)\n .replace(openPattern, escOpen)\n .replace(closePattern, escClose)\n .replace(commaPattern, escComma)\n .replace(periodPattern, escPeriod)\n}\n\nfunction unescapeBraces(str: string) {\n return str\n .replace(escSlashPattern, '\\\\')\n .replace(escOpenPattern, '{')\n .replace(escClosePattern, '}')\n .replace(escCommaPattern, ',')\n .replace(escPeriodPattern, '.')\n}\n\n/**\n * Basically just str.split(\",\"), but handling cases\n * where we have nested braced sections, which should be\n * treated as individual members, like {a,{b,c},d}\n */\nfunction parseCommaParts(str: string) {\n if (!str) {\n return ['']\n }\n\n const parts: string[] = []\n const m = balanced('{', '}', str)\n\n if (!m) {\n return str.split(',')\n }\n\n const { pre, body, post } = m\n const p = pre.split(',')\n\n p[p.length - 1] += '{' + body + '}'\n const postParts = parseCommaParts(post)\n if (post.length) {\n ;(p[p.length - 1] as string) += postParts.shift()\n p.push.apply(p, postParts)\n }\n\n parts.push.apply(parts, p)\n\n return parts\n}\n\nexport type BraceExpansionOptions = {\n max?: number\n}\n\nexport function expand(str: string, options: BraceExpansionOptions = {}) {\n if (!str) {\n return []\n }\n\n const { max = EXPANSION_MAX } = options\n\n // I don't know why Bash 4.3 does this, but it does.\n // Anything starting with {} will have the first two bytes preserved\n // but *only* at the top level, so {},a}b will not expand to anything,\n // but a{},b}c will be expanded to [a}c,abc].\n // One could argue that this is a bug in Bash, but since the goal of\n // this module is to match Bash's rules, we escape a leading {}\n if (str.slice(0, 2) === '{}') {\n str = '\\\\{\\\\}' + str.slice(2)\n }\n\n return expand_(escapeBraces(str), max, true).map(unescapeBraces)\n}\n\nfunction embrace(str: string) {\n return '{' + str + '}'\n}\n\nfunction isPadded(el: string) {\n return /^-?0\\d/.test(el)\n}\n\nfunction lte(i: number, y: number) {\n return i <= y\n}\n\nfunction gte(i: number, y: number) {\n return i >= y\n}\n\nfunction expand_(str: string, max: number, isTop: boolean): string[] {\n /** @type {string[]} */\n const expansions: string[] = []\n\n const m = balanced('{', '}', str)\n if (!m) return [str]\n\n // no need to expand pre, since it is guaranteed to be free of brace-sets\n const pre = m.pre\n const post: string[] = m.post.length ? expand_(m.post, max, false) : ['']\n\n if (/\\$$/.test(m.pre)) {\n for (let k = 0; k < post.length && k < max; k++) {\n const expansion = pre + '{' + m.body + '}' + post[k]\n expansions.push(expansion)\n }\n } else {\n const isNumericSequence = /^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(m.body)\n const isAlphaSequence = /^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(\n m.body,\n )\n const isSequence = isNumericSequence || isAlphaSequence\n const isOptions = m.body.indexOf(',') >= 0\n if (!isSequence && !isOptions) {\n // {a},b}\n if (m.post.match(/,(?!,).*\\}/)) {\n str = m.pre + '{' + m.body + escClose + m.post\n return expand_(str, max, true)\n }\n return [str]\n }\n\n let n: string[]\n if (isSequence) {\n n = m.body.split(/\\.\\./)\n } else {\n n = parseCommaParts(m.body)\n if (n.length === 1 && n[0] !== undefined) {\n // x{{a,b}}y ==> x{a}y x{b}y\n n = expand_(n[0], max, false).map(embrace)\n //XXX is this necessary? Can't seem to hit it in tests.\n /* c8 ignore start */\n if (n.length === 1) {\n return post.map(p => m.pre + n[0] + p)\n }\n /* c8 ignore stop */\n }\n }\n\n // at this point, n is the parts, and we know it's not a comma set\n // with a single entry.\n let N: string[]\n\n if (isSequence && n[0] !== undefined && n[1] !== undefined) {\n const x = numeric(n[0])\n const y = numeric(n[1])\n const width = Math.max(n[0].length, n[1].length)\n let incr =\n n.length === 3 && n[2] !== undefined ? Math.abs(numeric(n[2])) : 1\n let test = lte\n const reverse = y < x\n if (reverse) {\n incr *= -1\n test = gte\n }\n const pad = n.some(isPadded)\n\n N = []\n\n for (let i = x; test(i, y); i += incr) {\n let c\n if (isAlphaSequence) {\n c = String.fromCharCode(i)\n if (c === '\\\\') {\n c = ''\n }\n } else {\n c = String(i)\n if (pad) {\n const need = width - c.length\n if (need > 0) {\n const z = new Array(need + 1).join('0')\n if (i < 0) {\n c = '-' + z + c.slice(1)\n } else {\n c = z + c\n }\n }\n }\n }\n N.push(c)\n }\n } else {\n N = []\n\n for (let j = 0; j < n.length; j++) {\n N.push.apply(N, expand_(n[j] as string, max, false))\n }\n }\n\n for (let j = 0; j < N.length; j++) {\n for (let k = 0; k < post.length && expansions.length < max; k++) {\n const expansion = pre + N[j] + post[k]\n if (!isTop || isSequence || expansion) {\n expansions.push(expansion)\n }\n }\n }\n }\n\n return expansions\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,50 +1,64 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brace-expansion",
|
|
3
3
|
"description": "Brace expansion as known from sh/bash",
|
|
4
|
-
"version": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
4
|
+
"version": "5.0.3",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"exports": {
|
|
9
|
+
"./package.json": "./package.json",
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/esm/index.d.ts",
|
|
13
|
+
"default": "./dist/esm/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/commonjs/index.d.ts",
|
|
17
|
+
"default": "./dist/commonjs/index.js"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
8
20
|
},
|
|
9
|
-
"homepage": "https://github.com/juliangruber/brace-expansion",
|
|
10
|
-
"exports": "./index.js",
|
|
11
21
|
"type": "module",
|
|
12
22
|
"scripts": {
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
23
|
+
"preversion": "npm test",
|
|
24
|
+
"postversion": "npm publish",
|
|
25
|
+
"prepublishOnly": "git push origin --follow-tags",
|
|
26
|
+
"prepare": "tshy",
|
|
27
|
+
"pretest": "npm run prepare",
|
|
28
|
+
"presnap": "npm run prepare",
|
|
29
|
+
"test": "tap",
|
|
30
|
+
"snap": "tap",
|
|
31
|
+
"format": "prettier --write .",
|
|
32
|
+
"benchmark": "node benchmark/index.js",
|
|
33
|
+
"typedoc": "typedoc --tsconfig .tshy/esm.json ./src/*.ts"
|
|
19
34
|
},
|
|
20
35
|
"devDependencies": {
|
|
21
|
-
"@
|
|
22
|
-
"
|
|
36
|
+
"@types/brace-expansion": "^1.1.2",
|
|
37
|
+
"@types/node": "^25.2.1",
|
|
38
|
+
"mkdirp": "^3.0.1",
|
|
39
|
+
"prettier": "^3.3.2",
|
|
40
|
+
"tap": "^21.6.2",
|
|
41
|
+
"tshy": "^3.0.2",
|
|
42
|
+
"typedoc": "^0.28.5"
|
|
23
43
|
},
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
"name": "Julian Gruber",
|
|
27
|
-
"email": "mail@juliangruber.com",
|
|
28
|
-
"url": "http://juliangruber.com"
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"balanced-match": "^4.0.2"
|
|
29
46
|
},
|
|
30
47
|
"license": "MIT",
|
|
31
|
-
"testling": {
|
|
32
|
-
"files": "test/*.js",
|
|
33
|
-
"browsers": [
|
|
34
|
-
"ie/8..latest",
|
|
35
|
-
"firefox/20..latest",
|
|
36
|
-
"firefox/nightly",
|
|
37
|
-
"chrome/25..latest",
|
|
38
|
-
"chrome/canary",
|
|
39
|
-
"opera/12..latest",
|
|
40
|
-
"opera/next",
|
|
41
|
-
"safari/5.1..latest",
|
|
42
|
-
"ipad/6.0..latest",
|
|
43
|
-
"iphone/6.0..latest",
|
|
44
|
-
"android-browser/4.2..latest"
|
|
45
|
-
]
|
|
46
|
-
},
|
|
47
48
|
"engines": {
|
|
48
|
-
"node": ">=
|
|
49
|
+
"node": "18 || 20 || >=22"
|
|
50
|
+
},
|
|
51
|
+
"tshy": {
|
|
52
|
+
"exports": {
|
|
53
|
+
"./package.json": "./package.json",
|
|
54
|
+
".": "./src/index.ts"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"main": "./dist/commonjs/index.js",
|
|
58
|
+
"types": "./dist/commonjs/index.d.ts",
|
|
59
|
+
"module": "./dist/esm/index.js",
|
|
60
|
+
"repository": {
|
|
61
|
+
"type": "git",
|
|
62
|
+
"url": "git+ssh://git@github.com/juliangruber/brace-expansion.git"
|
|
49
63
|
}
|
|
50
64
|
}
|
package/.github/FUNDING.yml
DELETED
package/.github/workflows/ci.yml
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
on: [push]
|
|
3
|
-
jobs:
|
|
4
|
-
build:
|
|
5
|
-
runs-on: ubuntu-latest
|
|
6
|
-
strategy:
|
|
7
|
-
matrix:
|
|
8
|
-
node: ['18', '20']
|
|
9
|
-
steps:
|
|
10
|
-
- uses: actions/checkout@v2
|
|
11
|
-
- uses: actions/setup-node@v2
|
|
12
|
-
with:
|
|
13
|
-
node-version: ${{ matrix.node }}
|
|
14
|
-
- run: npm ci
|
|
15
|
-
- run: npm test
|
package/bench/bench.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/* global bench */
|
|
2
|
-
|
|
3
|
-
import expand from '..'
|
|
4
|
-
import fs from 'fs'
|
|
5
|
-
|
|
6
|
-
const resfile = new URL('../test/cases.txt', import.meta.url)
|
|
7
|
-
const cases = fs.readFileSync(resfile, 'utf8').split('\n')
|
|
8
|
-
|
|
9
|
-
bench('Average', function () {
|
|
10
|
-
cases.forEach(function (testcase) {
|
|
11
|
-
expand(testcase)
|
|
12
|
-
})
|
|
13
|
-
})
|
package/index.js
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import balanced from 'balanced-match'
|
|
2
|
-
|
|
3
|
-
const escSlash = '\0SLASH' + Math.random() + '\0'
|
|
4
|
-
const escOpen = '\0OPEN' + Math.random() + '\0'
|
|
5
|
-
const escClose = '\0CLOSE' + Math.random() + '\0'
|
|
6
|
-
const escComma = '\0COMMA' + Math.random() + '\0'
|
|
7
|
-
const escPeriod = '\0PERIOD' + Math.random() + '\0'
|
|
8
|
-
const escSlashPattern = new RegExp(escSlash, 'g')
|
|
9
|
-
const escOpenPattern = new RegExp(escOpen, 'g')
|
|
10
|
-
const escClosePattern = new RegExp(escClose, 'g')
|
|
11
|
-
const escCommaPattern = new RegExp(escComma, 'g')
|
|
12
|
-
const escPeriodPattern = new RegExp(escPeriod, 'g')
|
|
13
|
-
const slashPattern = /\\\\/g
|
|
14
|
-
const openPattern = /\\{/g
|
|
15
|
-
const closePattern = /\\}/g
|
|
16
|
-
const commaPattern = /\\,/g
|
|
17
|
-
const periodPattern = /\\./g
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @return {number}
|
|
21
|
-
*/
|
|
22
|
-
function numeric (str) {
|
|
23
|
-
return !isNaN(str)
|
|
24
|
-
? parseInt(str, 10)
|
|
25
|
-
: str.charCodeAt(0)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @param {string} str
|
|
30
|
-
*/
|
|
31
|
-
function escapeBraces (str) {
|
|
32
|
-
return str.replace(slashPattern, escSlash)
|
|
33
|
-
.replace(openPattern, escOpen)
|
|
34
|
-
.replace(closePattern, escClose)
|
|
35
|
-
.replace(commaPattern, escComma)
|
|
36
|
-
.replace(periodPattern, escPeriod)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @param {string} str
|
|
41
|
-
*/
|
|
42
|
-
function unescapeBraces (str) {
|
|
43
|
-
return str.replace(escSlashPattern, '\\')
|
|
44
|
-
.replace(escOpenPattern, '{')
|
|
45
|
-
.replace(escClosePattern, '}')
|
|
46
|
-
.replace(escCommaPattern, ',')
|
|
47
|
-
.replace(escPeriodPattern, '.')
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Basically just str.split(","), but handling cases
|
|
52
|
-
* where we have nested braced sections, which should be
|
|
53
|
-
* treated as individual members, like {a,{b,c},d}
|
|
54
|
-
* @param {string} str
|
|
55
|
-
*/
|
|
56
|
-
function parseCommaParts (str) {
|
|
57
|
-
if (!str) { return [''] }
|
|
58
|
-
|
|
59
|
-
const parts = []
|
|
60
|
-
const m = balanced('{', '}', str)
|
|
61
|
-
|
|
62
|
-
if (!m) { return str.split(',') }
|
|
63
|
-
|
|
64
|
-
const { pre, body, post } = m
|
|
65
|
-
const p = pre.split(',')
|
|
66
|
-
|
|
67
|
-
p[p.length - 1] += '{' + body + '}'
|
|
68
|
-
const postParts = parseCommaParts(post)
|
|
69
|
-
if (post.length) {
|
|
70
|
-
p[p.length - 1] += postParts.shift()
|
|
71
|
-
p.push.apply(p, postParts)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
parts.push.apply(parts, p)
|
|
75
|
-
|
|
76
|
-
return parts
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* @param {string} str
|
|
81
|
-
*/
|
|
82
|
-
export default function expandTop (str) {
|
|
83
|
-
if (!str) { return [] }
|
|
84
|
-
|
|
85
|
-
// I don't know why Bash 4.3 does this, but it does.
|
|
86
|
-
// Anything starting with {} will have the first two bytes preserved
|
|
87
|
-
// but *only* at the top level, so {},a}b will not expand to anything,
|
|
88
|
-
// but a{},b}c will be expanded to [a}c,abc].
|
|
89
|
-
// One could argue that this is a bug in Bash, but since the goal of
|
|
90
|
-
// this module is to match Bash's rules, we escape a leading {}
|
|
91
|
-
if (str.slice(0, 2) === '{}') {
|
|
92
|
-
str = '\\{\\}' + str.slice(2)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return expand(escapeBraces(str), true).map(unescapeBraces)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* @param {string} str
|
|
100
|
-
*/
|
|
101
|
-
function embrace (str) {
|
|
102
|
-
return '{' + str + '}'
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* @param {string} el
|
|
107
|
-
*/
|
|
108
|
-
function isPadded (el) {
|
|
109
|
-
return /^-?0\d/.test(el)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* @param {number} i
|
|
114
|
-
* @param {number} y
|
|
115
|
-
*/
|
|
116
|
-
function lte (i, y) {
|
|
117
|
-
return i <= y
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* @param {number} i
|
|
122
|
-
* @param {number} y
|
|
123
|
-
*/
|
|
124
|
-
function gte (i, y) {
|
|
125
|
-
return i >= y
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* @param {string} str
|
|
130
|
-
* @param {boolean} [isTop]
|
|
131
|
-
*/
|
|
132
|
-
function expand (str, isTop) {
|
|
133
|
-
/** @type {string[]} */
|
|
134
|
-
const expansions = []
|
|
135
|
-
|
|
136
|
-
const m = balanced('{', '}', str)
|
|
137
|
-
if (!m) return [str]
|
|
138
|
-
|
|
139
|
-
// no need to expand pre, since it is guaranteed to be free of brace-sets
|
|
140
|
-
const pre = m.pre
|
|
141
|
-
const post = m.post.length
|
|
142
|
-
? expand(m.post, false)
|
|
143
|
-
: ['']
|
|
144
|
-
|
|
145
|
-
if (/\$$/.test(m.pre)) {
|
|
146
|
-
for (let k = 0; k < post.length; k++) {
|
|
147
|
-
const expansion = pre + '{' + m.body + '}' + post[k]
|
|
148
|
-
expansions.push(expansion)
|
|
149
|
-
}
|
|
150
|
-
} else {
|
|
151
|
-
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body)
|
|
152
|
-
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body)
|
|
153
|
-
const isSequence = isNumericSequence || isAlphaSequence
|
|
154
|
-
const isOptions = m.body.indexOf(',') >= 0
|
|
155
|
-
if (!isSequence && !isOptions) {
|
|
156
|
-
// {a},b}
|
|
157
|
-
if (m.post.match(/,(?!,).*\}/)) {
|
|
158
|
-
str = m.pre + '{' + m.body + escClose + m.post
|
|
159
|
-
return expand(str)
|
|
160
|
-
}
|
|
161
|
-
return [str]
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
let n
|
|
165
|
-
if (isSequence) {
|
|
166
|
-
n = m.body.split(/\.\./)
|
|
167
|
-
} else {
|
|
168
|
-
n = parseCommaParts(m.body)
|
|
169
|
-
if (n.length === 1) {
|
|
170
|
-
// x{{a,b}}y ==> x{a}y x{b}y
|
|
171
|
-
n = expand(n[0], false).map(embrace)
|
|
172
|
-
if (n.length === 1) {
|
|
173
|
-
return post.map(function (p) {
|
|
174
|
-
return m.pre + n[0] + p
|
|
175
|
-
})
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// at this point, n is the parts, and we know it's not a comma set
|
|
181
|
-
// with a single entry.
|
|
182
|
-
let N
|
|
183
|
-
|
|
184
|
-
if (isSequence) {
|
|
185
|
-
const x = numeric(n[0])
|
|
186
|
-
const y = numeric(n[1])
|
|
187
|
-
const width = Math.max(n[0].length, n[1].length)
|
|
188
|
-
let incr = n.length === 3
|
|
189
|
-
? Math.abs(numeric(n[2]))
|
|
190
|
-
: 1
|
|
191
|
-
let test = lte
|
|
192
|
-
const reverse = y < x
|
|
193
|
-
if (reverse) {
|
|
194
|
-
incr *= -1
|
|
195
|
-
test = gte
|
|
196
|
-
}
|
|
197
|
-
const pad = n.some(isPadded)
|
|
198
|
-
|
|
199
|
-
N = []
|
|
200
|
-
|
|
201
|
-
for (let i = x; test(i, y); i += incr) {
|
|
202
|
-
let c
|
|
203
|
-
if (isAlphaSequence) {
|
|
204
|
-
c = String.fromCharCode(i)
|
|
205
|
-
if (c === '\\') { c = '' }
|
|
206
|
-
} else {
|
|
207
|
-
c = String(i)
|
|
208
|
-
if (pad) {
|
|
209
|
-
const need = width - c.length
|
|
210
|
-
if (need > 0) {
|
|
211
|
-
const z = new Array(need + 1).join('0')
|
|
212
|
-
if (i < 0) { c = '-' + z + c.slice(1) } else { c = z + c }
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
N.push(c)
|
|
217
|
-
}
|
|
218
|
-
} else {
|
|
219
|
-
N = []
|
|
220
|
-
|
|
221
|
-
for (let j = 0; j < n.length; j++) {
|
|
222
|
-
N.push.apply(N, expand(n[j], false))
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
for (let j = 0; j < N.length; j++) {
|
|
227
|
-
for (let k = 0; k < post.length; k++) {
|
|
228
|
-
const expansion = pre + N[j] + post[k]
|
|
229
|
-
if (!isTop || isSequence || expansion) { expansions.push(expansion) }
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return expansions
|
|
235
|
-
}
|