@franciscosolis/braces

中文文档
3.1.1发布于 2026/10/09MITTypeScriptESM + CJS构建来源已验证近 30 天下载 2.4万

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.

原始使用文档
文档目录19 节
  1. 📖 Overview
  2. ✨ Features
  3. 📦 Installation
  4. Replacing braces in your dependency tree
  5. 🚀 Usage
  6. Compile vs. expand
  7. Lists
  8. Sequences and steps
  9. Nesting
  10. Escaping
  11. 📚 API
  12. ⚙️ Options
  13. Handling untrusted patterns
  14. 🛠 Development
  15. Keeping up with upstream
  16. 🤝 Contributing
  17. 🔒 Security
  18. 🙏 Credits
  19. 📄 License

{braces}

Bash-like brace expansion for JavaScript, with a fix for the deep-nesting crash (GHSA-vfj7-8cjw-p6xm).

npm CI License


📖 Overview

@franciscosolis/braces is a maintained fork of micromatch/braces, the brace expansion library used by micromatch, chokidar, fast-glob and much of the npm ecosystem. It turns patterns like a/{b,c}/d or {01..10} into either a list of strings (as Bash does) or a compact, regex-ready string for matching.

The fork exists to fix GHSA-vfj7-8cjw-p6xm (CVE-2026-93687). Deeply nested patterns under the maxLength limit exhausted the call stack and crashed the process with an uncaught RangeError. Every published version of braces up to 3.0.3 is affected, and upstream declined to fix it. This fork caps the nesting depth in the parser and in the compile, expand and stringify walkers, including ASTs passed in directly, and throws a SyntaxError instead.

The API is the same as braces 3.x, so it works as a drop-in replacement.


✨ Features

  • Bash 4.3 brace expansion: lists ({a,b}), sequences ({1..5}, {a..e}), steps ({1..10..2}), zero padding ({01..10}), nesting and escaping.
  • Compile or expand: by default patterns compile to regex-ready strings (a/(b|c)/d), which stay small even for huge ranges. Use expand: true to get every string.
  • Safe on untrusted input: limits on input length (maxLength), nesting depth (maxDepth) and expanded range size (rangeLimit) throw catchable errors instead of hanging or crashing.
  • TypeScript declarations included (since 3.1.0).
  • CommonJS and ESM: require() and import, including named imports (since 3.1.0).
  • Wide runtime support: Node.js >= 8.3. One runtime dependency (fill-range).

📦 Installation

npm install @franciscosolis/braces

Replacing braces in your dependency tree

Most projects get braces indirectly (through micromatch, chokidar, etc.). To swap it for this fork, add an override to your package.json. Versions stay in the 3.x major, so they satisfy the usual ^3.0.2 and ^3.0.3 ranges:

{
  "overrides": {
    "braces": "npm:@franciscosolis/braces@^3.0.5"
  }
}

With Yarn use resolutions, and with pnpm use pnpm.overrides, with the same value. Then reinstall and check with npm ls braces.


🚀 Usage

const braces = require('@franciscosolis/braces');
// ESM (3.1.0+)
import braces, { expand, compile } from '@franciscosolis/braces';

The main export takes one pattern or an array of patterns, plus options, and always returns an array.

braces('a/{x,y,z}/b'); //=> ['a/(x|y|z)/b']
braces(['{01..05}', '{a..e}']); //=> ['(0[1-5])', '([a-e])']
braces('a/{x,y,z}/b', { expand: true }); //=> ['a/x/b', 'a/y/b', 'a/z/b']

Compile vs. expand

By default patterns are compiled into strings meant for building regular expressions. A range like {1..1000000} stays a short string instead of a million items. Set expand: true, or call braces.expand(), to get the strings Bash would print.

braces('a/{001..300}/b'); //=> ['a/(00[1-9]|0[1-9][0-9]|[12][0-9]{2}|300)/b']
braces.expand('{01..05}'); //=> ['01', '02', '03', '04', '05']

Lists

braces.expand('a/{foo,bar,baz}/*.js'); //=> ['a/foo/*.js', 'a/bar/*.js', 'a/baz/*.js']
braces.expand('{a,b}{1,2}'); //=> ['a1', 'a2', 'b1', 'b2']

Sequences and steps

braces.expand('{1..3}'); //=> ['1', '2', '3']
braces.expand('{4..-4}'); //=> ['4', '3', '2', '1', '0', '-1', '-2', '-3', '-4']
braces.expand('{a..z..3}'); //=> ['a', 'd', 'g', 'j', 'm', 'p', 's', 'v', 'y']
braces('{2..10..2}'); //=> ['(2|4|6|8|10)']

Nesting

Results keep left-to-right order and are not sorted.

braces.expand('a{b,c,/{x,y}}/e'); //=> ['ab/e', 'ac/e', 'a/x/e', 'a/y/e']
braces('a/{x,{1..5},y}/c'); //=> ['a/(x|([1-5])|y)/c']

Escaping

A pattern is left as-is when either brace is escaped, and escaped commas are not separators. As in Bash, a single item in braces is not expanded.

braces.expand('a\\{d,c,b}e'); //=> ['a{d,c,b}e']
braces.expand('a{d\\,c,b}e'); //=> ['ad,ce', 'abe']
braces.expand('a{b}c'); //=> ['a{b}c']

📚 API

MethodReturnsDescription
braces(patterns, options?)string[]Compiles (or expands, with expand: true) one or more patterns.
braces.compile(pattern | ast, options?)stringCompiles to a regex-ready string.
braces.expand(pattern | ast, options?)string[]Expands to every matching string.
braces.create(pattern, options?)string | string[]Calls compile, or expand when options.expand is true.
braces.parse(pattern, options?)ASTParses a pattern into an AST.
braces.stringify(pattern | ast, options?)stringTurns an AST back into a pattern.
const ast = braces.parse('a/{b,c}');
braces.stringify(ast); //=> 'a/{b,c}'
braces.compile(ast); //=> 'a/(b|c)'

⚙️ Options

OptionTypeDefaultDescription
expandbooleanfalseReturn every expanded string instead of a regex-ready string.
maxLengthnumber10000Maximum input length. Longer input throws a SyntaxError. Values above 10000 are capped.
maxDepthnumber100Maximum nesting depth of braces and parentheses, for strings and for ASTs passed to compile, expand and stringify. Deeper input throws a SyntaxError. Values above 100 are capped; values that are not integers >= 1 throw a TypeError.
rangeLimitnumber1000When expanding, a range with this many items or more throws a RangeError. Use Infinity to disable.
nodupesbooleanfalseRemove duplicates from the result.
noemptybooleanfalseRemove empty strings from the result of expand.
transform(value, index) => stringCustomize each item of a range. value is a number for numeric ranges and a character code for letter ranges.
keepEscapingbooleanfalseKeep the backslashes used for escaping in the result.
keepQuotesbooleanfalseKeep the quotes around quoted strings in the result.
braces.expand('x/{a..e}/y', {
  transform: (value, index) => String.fromCharCode(value) + index,
}); //=> ['x/a0/y', 'x/b1/y', 'x/c2/y', 'x/d3/y', 'x/e4/y']

Handling untrusted patterns

Brace expansion grows multiplicatively: {1..100}{1..100}{1..100} expands to a million strings. If users can supply patterns:

  • Prefer compiling (the default) over expanding.
  • Keep rangeLimit (and lower maxLength or maxDepth if you can).
  • Catch the errors: SyntaxError for maxLength/maxDepth, RangeError for rangeLimit.
try {
  braces('{a,{b,c}}', { maxDepth: 1 });
} catch (err) {
  // SyntaxError: Input nesting depth exceeds max depth (1)
}

🛠 Development

Requires Node.js >= 8.3 and npm.

git clone https://github.com/Im-Fran/braces.git
cd braces
npm install
npm test

Benchmarks against minimatch live in bench/ and have their own dependencies:

cd bench
npm install
node index.js

CI runs the tests on Node.js 8.3 through 22. Releases are published to npm from GitHub Actions with provenance when a v* tag is pushed. See the CHANGELOG for what changed in each version.

Keeping up with upstream

The fork follows upstream. To review and bring in upstream changes:

git remote add upstream https://github.com/micromatch/braces.git
git fetch upstream
git log dev..upstream/master
git checkout -b im-fran/chore/sync-upstream origin/dev
git merge upstream/master

Then open a pull request into dev. Always merge; never rebase the published history onto upstream.


🤝 Contributing

Issues and pull requests are welcome. Branch from dev, add tests for any behavior change, make sure npm test passes, and open a pull request into dev. Commits follow Conventional Commits.

Changes that are not specific to this fork are often worth proposing upstream too.


🔒 Security

Please report vulnerabilities privately through GitHub security advisories, not in public issues.


🙏 Credits

braces was created by Jon Schlinkert, who wrote nearly all of it, and is maintained upstream at micromatch/braces. This fork would not exist without that work. If it is useful to you, consider starring the original project.

Upstream contributors include Brian Woodward, Elan Shanker, Eugene Sharygin, hemanth.hm, Paul Miller, Denis Malinochkin and many others.

The fork is maintained by Francisco Solis.


📄 License

Released under the MIT License.

Copyright © 2014-present, Jon Schlinkert. Copyright © 2026-present, Francisco Solis (fork).


Made with ☕ by Fran, on top of the work of Jon Schlinkert and the braces contributors.

版本与发布记录

@franciscosolis/braces 共发布 5 个版本,首次发布于 2026/10/09;过去 12 个月发布了 5 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
3.1.1latest2026/10/091 个月前
3.1.02026/10/091 个月前
3.0.62026/10/091 个月前
3.0.52026/10/091 个月前
0.0.0-stage2026/10/091 个月前

关于 @franciscosolis/braces 的常见问题

@franciscosolis/braces 是什么?

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.

如何安装 @franciscosolis/braces?

在项目目录运行 npm install @franciscosolis/braces,或使用 pnpm add / yarn add / bun add。

@franciscosolis/braces 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@franciscosolis/braces 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@franciscosolis/braces 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=8.3。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@franciscosolis/braces 可以商用吗?

@franciscosolis/braces 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@franciscosolis/braces 的下载量有多少?

根据 npm 官方下载统计,@franciscosolis/braces 在 2026/10/16 – 2026/11/14 这 30 天内被下载 23,556 次,日均约 785 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@franciscosolis/braces 还在维护吗?

最新版本 3.1.1 发布于 2026/10/09(1 个月前);至今共发布 5 个版本,其中过去 12 个月发布了 5 个;首次发布于 2026/10/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。