Research
Recent Trends in Malicious Packages Targeting Discord
The Socket research team breaks down a sampling of malicious packages that download and execute files, among other suspicious behaviors, targeting the popular Discord platform.
braces
Advanced tools
Package description
The braces npm package is a library for expanding braces in a string, similar to how shells like bash perform brace expansion. It is used to generate permutations of strings based on patterns with braces, which is useful for file globbing, configuration, and other tasks where such patterns are needed.
Brace Expansion
Expands a pattern with comma-separated values inside braces into an array of strings.
"{a,b,c}d" -> ['ad', 'bd', 'cd']
Sequence Expansion
Expands a pattern with numerical sequences inside braces into an array of strings.
"{1..3}d" -> ['1d', '2d', '3d']
Nested Expansion
Expands a pattern with nested braces into an array of strings.
"{a,{b,c}d}e" -> ['ae', 'bde', 'cde']
Minimatch is a minimal matching utility that works by converting glob expressions into JavaScript RegExp objects. It is similar to braces in that it supports pattern matching, but it is more focused on matching file paths and does not support brace expansion.
Micromatch is a fast and accurate glob matching library, optimized for speed and accuracy. It extends the capabilities of minimatch and braces, providing more powerful matching features and better performance for complex patterns.
Globby is a user-friendly glob matching library that uses micromatch under the hood. It provides a higher-level API for file matching and supports multiple patterns, making it a convenient alternative to braces for file system operations.
Changelog
[2.1.1] - 2017-04-27
Readme
Fast, comprehensive, bash-like brace expansion implemented in JavaScript. Complete support for the Bash 4.3 braces specification, without sacrificing speed.
Install with npm:
$ npm install --save braces
Install with yarn:
$ yarn add braces
The main export is a function that takes a brace pattern
to expand and an options
object if necessary.
var braces = require('braces');
braces(pattern[, options]);
Optimized
Patterns are optimized for regex and matching by default:
console.log(braces('a/{x,y,z}/b'));
//=> ['a/(x|y|z)/b']
Expanded
To expand patterns the same way as Bash or minimatch, use the .expand method:
console.log(braces.expand('a/{x,y,z}/b'));
//=> ['a/x/b', 'a/y/b', 'a/z/b']
Or use options.expand:
console.log(braces('a/{x,y,z}/b', {expand: true}));
//=> ['a/x/b', 'a/y/b', 'a/z/b']
a/{b,c}/d
=> ['a/b/d', 'a/c/d']
{1..3}
=> ['1', '2', '3']
{2..10..2}
=> ['2', '4', '6', '8', '10']
Uses fill-range for expanding alphabetical or numeric lists:
console.log(braces('a/{foo,bar,baz}/*.js'));
//=> ['a/(foo|bar|baz)/*.js']
console.log(braces.expand('a/{foo,bar,baz}/*.js'));
//=> ['a/foo/*.js', 'a/bar/*.js', 'a/baz/*.js']
Uses fill-range for expanding alphabetical or numeric ranges (bash "sequences"):
console.log(braces.expand('{1..3}')); // ['1', '2', '3']
console.log(braces.expand('a{01..03}b')); // ['a01b', 'a02b', 'a03b']
console.log(braces.expand('a{1..3}b')); // ['a1b', 'a2b', 'a3b']
console.log(braces.expand('{a..c}')); // ['a', 'b', 'c']
console.log(braces.expand('foo/{a..c}')); // ['foo/a', 'foo/b', 'foo/c']
// supports padded ranges
console.log(braces('a{01..03}b')); //=> [ 'a(0[1-3])b' ]
console.log(braces('a{001..300}b')); //=> [ 'a(0{2}[1-9]|0[1-9][0-9]|[12][0-9]{2}|300)b' ]
Steps, or increments, may be used with ranges:
console.log(braces.expand('{2..10..2}'));
//=> ['2', '4', '6', '8', '10']
console.log(braces('{2..10..2}'));
//=> ['(2|4|6|8|10)']
When the .optimize method is used, or options.optimize is set to true, sequences are passed to to-regex-range for expansion.
Brace patterns may be nested. The results of each expanded string are not sorted, and left to right order is preserved.
"Expanded" braces
console.log(braces.expand('a{b,c,/{x,y}}/e'));
//=> ['ab/e', 'ac/e', 'a/x/e', 'a/y/e']
console.log(braces.expand('a/{x,{1..5},y}/c'));
//=> ['a/x/c', 'a/1/c', 'a/2/c', 'a/3/c', 'a/4/c', 'a/5/c', 'a/y/c']
"Optimized" braces
console.log(braces('a{b,c,/{x,y}}/e'));
//=> ['a(b|c|/(x|y))/e']
console.log(braces('a/{x,{1..5},y}/c'));
//=> ['a/(x|([1-5])|y)/c']
Escaping braces
A brace pattern will not be expanded or evaluted if either the opening or closing brace is escaped:
console.log(braces.expand('a\\{d,c,b}e'));
//=> ['a{d,c,b}e']
console.log(braces.expand('a{d,c,b\\}e'));
//=> ['a{d,c,b}e']
Escaping commas
Commas inside braces may also be escaped:
console.log(braces.expand('a{b\\,c}d'));
//=> ['a{b,c}d']
console.log(braces.expand('a{d\\,c,b}e'));
//=> ['ad,ce', 'abe']
Single items
Following bash conventions, a brace pattern is also not expanded when it contains a single character:
console.log(braces.expand('a{b}c'));
//=> ['a{b}c']
Type: Boolean
Default: undefined
Description: Generate an "expanded" brace pattern (this option is unncessary with the .expand
method, which does the same thing).
console.log(braces('a/{b,c}/d', {expand: true}));
//=> [ 'a/b/d', 'a/c/d' ]
Type: Boolean
Default: true
Description: Enabled by default.
console.log(braces('a/{b,c}/d'));
//=> [ 'a/(b|c)/d' ]
Type: Boolean
Default: true
Description: Duplicates are removed by default. To keep duplicates, pass {nodupes: false}
on the options
Type: Number
Default: 250
Description: When braces.expand()
is used, or options.expand
is true, brace patterns will automatically be optimized when the difference between the range minimum and range maximum exceeds the rangeLimit
. This is to prevent huge ranges from freezing your application.
You can set this to any number, or change options.rangeLimit
to Inifinity
to disable this altogether.
Examples
// pattern exceeds the "rangeLimit", so it's optimized automatically
console.log(braces.expand('{1..1000}'));
//=> ['([1-9]|[1-9][0-9]{1,2}|1000)']
// pattern does not exceed "rangeLimit", so it's NOT optimized
console.log(braces.expand('{1..100}'));
//=> ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '100']
Type: Function
Default: undefined
Description: Customize range expansion.
var range = braces.expand('x{a..e}y', {
transform: function(str) {
return 'foo' + str;
}
});
console.log(range);
//=> [ 'xfooay', 'xfooby', 'xfoocy', 'xfoody', 'xfooey' ]
Type: Boolean
Default: undefined
Description: In regular expressions, quanitifiers can be used to specify how many times a token can be repeated. For example, a{1,3}
will match the letter a
one to three times.
Unfortunately, regex quantifiers happen to share the same syntax as Bash lists
The quantifiers
option tells braces to detect when regex quantifiers are defined in the given pattern, and not to try to expand them as lists.
Examples
var braces = require('braces');
console.log(braces('a/b{1,3}/{x,y,z}'));
//=> [ 'a/b(1|3)/(x|y|z)' ]
console.log(braces('a/b{1,3}/{x,y,z}', {quantifiers: true}));
//=> [ 'a/b{1,3}/(x|y|z)' ]
console.log(braces('a/b{1,3}/{x,y,z}', {quantifiers: true, expand: true}));
//=> [ 'a/b{1,3}/x', 'a/b{1,3}/y', 'a/b{1,3}/z' ]
Type: Boolean
Default: undefined
Description: Strip backslashes that were used for escaping from the result.
Install dev dependencies:
npm i -d && npm benchmark
Benchmarking: (8 of 8)
· combination-nested
· combination
· escaped
· list-basic
· list-multiple
· no-braces
· sequence-basic
· sequence-multiple
# benchmark/fixtures/combination-nested.js (52 bytes)
brace-expansion x 4,756 ops/sec ±1.09% (86 runs sampled)
braces x 11,202,303 ops/sec ±1.06% (88 runs sampled)
minimatch x 4,816 ops/sec ±0.99% (87 runs sampled)
fastest is braces
# benchmark/fixtures/combination.js (51 bytes)
brace-expansion x 625 ops/sec ±0.87% (87 runs sampled)
braces x 11,031,884 ops/sec ±0.72% (90 runs sampled)
minimatch x 637 ops/sec ±0.84% (88 runs sampled)
fastest is braces
# benchmark/fixtures/escaped.js (44 bytes)
brace-expansion x 163,325 ops/sec ±1.05% (87 runs sampled)
braces x 10,655,071 ops/sec ±1.22% (88 runs sampled)
minimatch x 147,495 ops/sec ±0.96% (88 runs sampled)
fastest is braces
# benchmark/fixtures/list-basic.js (40 bytes)
brace-expansion x 99,726 ops/sec ±1.07% (83 runs sampled)
braces x 10,596,584 ops/sec ±0.98% (88 runs sampled)
minimatch x 100,069 ops/sec ±1.17% (86 runs sampled)
fastest is braces
# benchmark/fixtures/list-multiple.js (52 bytes)
brace-expansion x 34,348 ops/sec ±1.08% (88 runs sampled)
braces x 9,264,131 ops/sec ±1.12% (88 runs sampled)
minimatch x 34,893 ops/sec ±0.87% (87 runs sampled)
fastest is braces
# benchmark/fixtures/no-braces.js (48 bytes)
brace-expansion x 275,368 ops/sec ±1.18% (89 runs sampled)
braces x 9,134,677 ops/sec ±0.95% (88 runs sampled)
minimatch x 3,755,954 ops/sec ±1.13% (89 runs sampled)
fastest is braces
# benchmark/fixtures/sequence-basic.js (41 bytes)
brace-expansion x 5,492 ops/sec ±1.35% (87 runs sampled)
braces x 8,485,034 ops/sec ±1.28% (89 runs sampled)
minimatch x 5,341 ops/sec ±1.17% (87 runs sampled)
fastest is braces
# benchmark/fixtures/sequence-multiple.js (51 bytes)
brace-expansion x 116 ops/sec ±0.77% (77 runs sampled)
braces x 9,445,118 ops/sec ±1.32% (84 runs sampled)
minimatch x 109 ops/sec ±1.16% (76 runs sampled)
fastest is braces
If you use globbing a lot, whether in your build tool chain or in your application, the speed of the glob matcher not only impacts your experience, but a slow glob matcher can slow everything else down, limitimg what you thought was possible in your application.
minimatch gets exponentially slower as patterns increase in complexity, braces does not
Brace patterns are meant to be expanded - at least, if you're using Bash, that is. It's not at all unusual for users to want to use brace patterns for dates or similar ranges. It's also very easy to define a brace pattern that appears to be very simple but in fact is fairly complex.
For example, here is how generated regex size and processing time compare as patterns increase in complexity:
(the following results were generated using braces()
and minimatch.braceExpand()
)
Pattern | minimatch | braces |
---|---|---|
{1..9007199254740991} [^1] | N/A (freezes) | 300 B (12ms 878μs) |
{1..10000000} | 98.9 MB (20s 193ms 13μs) | 34 B (11ms 204μs) |
{1..1000000} | 8.89 MB (1s 838ms 718μs) | 33 B (1ms 761μs) |
{1..100000} | 789 kB (181ms 518μs) | 32 B (1ms 76μs) |
{1..10000} | 68.9 kB (17ms 436μs) | 31 B (1ms 382μs) |
{1..1000} | 5.89 kB (1ms 773μs) | 30 B (1ms 509μs) |
{1..100} | 491 B (321μs) | 24 B (309μs) |
{1..10} | 40 B (56μs) | 12 B (333μs) |
{1..3} | 11 B (80μs) | 9 B (370μs) |
These numbers are actually pretty small as far as numeric ranges are concerned. Regardless, we shouldn't have to consider such things when creating a glob pattern. The tool should get out of your way and let you be as creative as you want.
Even when brace patterns are fully expanded, braces
is still much faster.
(the following results were generated using braces.expand()
and minimatch.braceExpand()
)
Pattern | minimatch | braces |
---|---|---|
a/{1..10000000} | 98.9 MB (19s 754ms 376μs) | 98.9 MB (5s 734ms 419μs) |
a/{1..1000000} | 8.89 MB (1s 866ms 968μs) | 8.89 MB (561ms 594μs) |
a/{1..100000} | 789 kB (178ms 311μs) | 789 kB (29ms 823μs) |
a/{1..10000} | 68.9 kB (17ms 692μs) | 68.9 kB (2ms 351μs) |
a/{1..1000} | 5.89 kB (1ms 823μs) | 5.89 kB (706μs) |
a/{1..100} | 491 B (609μs) | 491 B (267μs) |
a/{1..10} | 40 B (61μs) | 40 B (636μs) |
a/{1..3} | 11 B (206μs) | 11 B (207μs) |
Braces was built from the ground up to be as performant as possible when matching, using a combination of the following:
Last, but perhaps most important of all, unlike brace-expansion and minimatch, braces will not freeze your application when a user passes a complex brace pattern.
The trouble with tribbles brace patterns
There are unlimited scenarios where brace patterns cause the resulting array to grow geometrically. If you define two brace patterns for example, the result is multiplicative if not exponential. For example, given the pattern {1..1000}
, we would end up with 1 thousand strings. But if two patterns are given, such as {1...1000}{1...1000}
, we would end up with 1 million strings.
It's easy to think, "I wouldn't do that", but that's not the point. Even though those example patterns are contrived:
1-2016
, for example, and how easy it might be for someone to also add an alphabetical range if searching records of some kind)Potential for DoS attacks
Most brace expansion libraries, including Bash, minimatch, multimatch and brace-expansion are vulnerable to DoS attacks (similar to the ReDoS bug minimatch had recently).
Braces mitigates this risk in three ways:
(you might also want to consider using micromatch for glob matching, as a safer alternative to minimatch and multimatch)
step
to… more | homepagePull requests and stars are always welcome. For bugs and feature requests, please create an issue.
Commits | Contributor |
---|---|
155 | jonschlinkert |
4 | doowb |
1 | es128 |
1 | eush77 |
1 | hemanth |
(This project's readme.md is generated by verb, please don't edit the readme directly. Any changes to the readme must be made in the .verb.md readme template.)
To generate the readme, run the following command:
$ npm install -g verbose/verb#dev verb-generate-readme && verb
Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
$ npm install && npm test
Jon Schlinkert
Copyright © 2017, Jon Schlinkert. Released under the MIT License.
This file was generated by verb-generate-readme, v0.6.0, on April 26, 2017.
FAQs
Bash-like brace expansion, implemented in JavaScript. Safer than other brace expansion libs, with complete support for the Bash 4.3 braces specification, without sacrificing speed.
We found that braces demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
The Socket research team breaks down a sampling of malicious packages that download and execute files, among other suspicious behaviors, targeting the popular Discord platform.
Security News
Socket CEO Feross Aboukhadijeh joins a16z partners to discuss how modern, sophisticated supply chain attacks require AI-driven defenses and explore the challenges and solutions in leveraging AI for threat detection early in the development life cycle.
Security News
NIST's new AI Risk Management Framework aims to enhance the security and reliability of generative AI systems and address the unique challenges of malicious AI exploits.