From 42b4ac576ff709b4f74e7468f3ca7cbf69142f48 Mon Sep 17 00:00:00 2001 From: neverland Date: Tue, 20 Oct 2026 16:20:24 +0800 Subject: [PATCH 1/2] feat(fmt): ignore Yarn releases by default --- packages/rstack/src/fmt/ignore.ts | 3 ++- packages/rstack/tests/fmt/discovery.test.ts | 22 +++++++++++++++++++++ website/docs/en/guide/formatting.mdx | 4 +++- website/docs/zh/guide/formatting.mdx | 4 +++- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/rstack/src/fmt/ignore.ts b/packages/rstack/src/fmt/ignore.ts index f1f40c0d..545050ff 100644 --- a/packages/rstack/src/fmt/ignore.ts +++ b/packages/rstack/src/fmt/ignore.ts @@ -8,7 +8,7 @@ import { loadNativeBinding } from '../native/index.ts'; import type { ResolvedFmtConfig } from './types.ts'; /** - * Common lock files that Prettier can format but `rs fmt` leaves to their generating tools. + * Generated files and tool distributions that `rs fmt` leaves to their owning tools. * * Prettier already skips other generated lock files when it cannot infer a parser, so this list * contains only the additional defaults owned by `rs fmt`. @@ -17,6 +17,7 @@ const defaultIgnorePatterns = [ 'package-lock.json', 'pnpm-lock.yaml', 'skills-lock.json', + '**/.yarn/releases/', ]; type IgnorePredicate = (filePath: string, isDirectory?: boolean) => boolean; diff --git a/packages/rstack/tests/fmt/discovery.test.ts b/packages/rstack/tests/fmt/discovery.test.ts index eeb9b44d..9e570c5b 100644 --- a/packages/rstack/tests/fmt/discovery.test.ts +++ b/packages/rstack/tests/fmt/discovery.test.ts @@ -124,6 +124,28 @@ test('excludes .rstack from discovery', async () => { }); }); +test('ignores Yarn releases by default and allows re-including their directories', async () => { + await withTempProject(async (rootPath) => { + const releases = [ + writeProjectFile(rootPath, '.yarn/releases/yarn.cjs'), + writeProjectFile(rootPath, 'packages/app/.yarn/releases/yarn.cjs'), + ]; + const keepPath = writeProjectFile(rootPath, '.yarn/versions/version.yml'); + + for (const patterns of [undefined, ['**/*'], [...releases, keepPath]]) { + const files = await discover(rootPath, patterns); + expect(files.map((file) => file.path)).toEqual([keepPath]); + } + + const files = await discover(rootPath, undefined, { + ignorePatterns: ['!**/.yarn/releases/'], + }); + expect(files.map((file) => file.path).sort()).toEqual( + [...releases, keepPath].sort(), + ); + }); +}); + const customCacheCases: { config?: FmtConfig; name: string }[] = [ { name: 'without configured ignore patterns' }, { diff --git a/website/docs/en/guide/formatting.mdx b/website/docs/en/guide/formatting.mdx index 10c7da05..a6f0701a 100644 --- a/website/docs/en/guide/formatting.mdx +++ b/website/docs/en/guide/formatting.mdx @@ -103,6 +103,8 @@ define.fmt({ Patterns follow Gitignore syntax and are resolved relative to the directory containing the Rstack configuration file. Because they are applied after the files are selected, they also exclude files passed explicitly on the command line. +By default, `rs fmt` ignores `.yarn/releases/` directories at any depth, which contain Yarn CLI distributions. To format these files, add `'!**/.yarn/releases/'` to `ignorePatterns` to re-include their directories. + ### Lock files By default, `rs fmt` ignores common lock files, including `package-lock.json`, `pnpm-lock.yaml`, and `skills-lock.json`. @@ -122,7 +124,7 @@ define.fmt({ `rs fmt` uses the following three steps to decide which paths to format: 1. **Process command-line arguments and `.gitignore`**: It first processes the files, directories, and glob patterns passed on the command line. A glob that starts with `!` excludes matching paths. Directory and glob scans follow `.gitignore`, while files passed directly do not. Paths excluded in this step cannot be re-included later. -2. **Apply default ignore rules and `ignorePatterns`**: By default, the command ignores [lock files](#lock-files), then applies `ignorePatterns`. These rules are evaluated in order, with later rules taking precedence. For example, `!pnpm-lock.yaml` re-includes the otherwise ignored file. +2. **Apply default ignore rules and `ignorePatterns`**: By default, the command ignores [lock files](#lock-files) and `.yarn/releases/` directories, then applies `ignorePatterns`. These rules are evaluated in order, with later rules taking precedence. For example, `!pnpm-lock.yaml` re-includes the otherwise ignored file. 3. **Apply files specified with [`--ignore-path`](./cli/fmt#--ignore-path-path)**: Each ignore file is evaluated separately, and later rules take precedence within that file. Exclusions from different files and `ignorePatterns` are combined: if any source ignores a path, that path remains excluded, even if another source re-includes it. > Even when a file is passed directly on the command line, the default ignore rules, `ignorePatterns`, and rules from `--ignore-path` still apply. The same is true for paths specified with [`--stdin-filepath`](./cli/fmt#--stdin-filepath-path) and for documents formatted through [`--lsp`](./cli/fmt#--lsp). diff --git a/website/docs/zh/guide/formatting.mdx b/website/docs/zh/guide/formatting.mdx index abe23c07..6b762f23 100644 --- a/website/docs/zh/guide/formatting.mdx +++ b/website/docs/zh/guide/formatting.mdx @@ -103,6 +103,8 @@ define.fmt({ 这些模式遵循 Gitignore 语法,并且基于 Rstack 配置文件所在的目录解析。由于规则会在确定格式化范围后生效,因此也会排除命令行中显式传入的文件。 +`rs fmt` 默认忽略任意层级的 `.yarn/releases/` 目录,其中存放的是 Yarn CLI 发布产物。如果需要格式化这些文件,可以在 `ignorePatterns` 中添加 `'!**/.yarn/releases/'`,重新包含这些目录。 + ### Lock 文件 \{#lock-files} `rs fmt` 默认忽略常见的 lock 文件,包括 `package-lock.json`、`pnpm-lock.yaml` 和 `skills-lock.json`。 @@ -122,7 +124,7 @@ define.fmt({ `rs fmt` 会通过以下三个步骤,决定需要格式化哪些路径: 1. **处理命令行参数和 `.gitignore`**:首先处理命令行中指定的文件、目录和 glob 模式。以 `!` 开头的 glob 模式用于排除路径。扫描目录或 glob 模式时会遵循 `.gitignore`,直接指定的文件则不会。在这一步被排除的路径无法被后续规则重新包含。 -2. **应用默认忽略规则和 `ignorePatterns`**:默认忽略 [lock 文件](#lock-files),随后应用 `ignorePatterns`。这些规则按顺序匹配,后面的规则优先。例如,`!pnpm-lock.yaml` 可以重新包含默认忽略的文件。 +2. **应用默认忽略规则和 `ignorePatterns`**:默认忽略 [lock 文件](#lock-files) 和 `.yarn/releases/` 目录,随后应用 `ignorePatterns`。这些规则按顺序匹配,后面的规则优先。例如,`!pnpm-lock.yaml` 可以重新包含默认忽略的文件。 3. **应用 [`--ignore-path`](./cli/fmt#--ignore-path-path) 指定的文件**:每个 ignore 文件单独匹配,同一文件中后面的规则优先。不同 ignore 文件与 `ignorePatterns` 的排除结果会叠加:只要任一来源忽略某个路径,该路径就会保持排除,即使其他来源尝试重新包含它。 > 即使命令行直接指定了某个文件,默认忽略规则、`ignorePatterns` 和 `--ignore-path` 中的规则仍然有效。通过 [`--stdin-filepath`](./cli/fmt#--stdin-filepath-path) 指定的路径,以及通过 [`--lsp`](./cli/fmt#--lsp) 格式化的文档也是如此。 From 21c158679625f271f54f18ab9ae3651d01d7a848 Mon Sep 17 00:00:00 2001 From: neverland Date: Tue, 20 Oct 2026 17:14:23 +0800 Subject: [PATCH 2/2] chore(fmt): minimize Yarn ignore changes --- packages/rstack/tests/fmt/discovery.test.ts | 22 --------------------- website/docs/en/guide/formatting.mdx | 2 -- website/docs/zh/guide/formatting.mdx | 2 -- 3 files changed, 26 deletions(-) diff --git a/packages/rstack/tests/fmt/discovery.test.ts b/packages/rstack/tests/fmt/discovery.test.ts index 9e570c5b..eeb9b44d 100644 --- a/packages/rstack/tests/fmt/discovery.test.ts +++ b/packages/rstack/tests/fmt/discovery.test.ts @@ -124,28 +124,6 @@ test('excludes .rstack from discovery', async () => { }); }); -test('ignores Yarn releases by default and allows re-including their directories', async () => { - await withTempProject(async (rootPath) => { - const releases = [ - writeProjectFile(rootPath, '.yarn/releases/yarn.cjs'), - writeProjectFile(rootPath, 'packages/app/.yarn/releases/yarn.cjs'), - ]; - const keepPath = writeProjectFile(rootPath, '.yarn/versions/version.yml'); - - for (const patterns of [undefined, ['**/*'], [...releases, keepPath]]) { - const files = await discover(rootPath, patterns); - expect(files.map((file) => file.path)).toEqual([keepPath]); - } - - const files = await discover(rootPath, undefined, { - ignorePatterns: ['!**/.yarn/releases/'], - }); - expect(files.map((file) => file.path).sort()).toEqual( - [...releases, keepPath].sort(), - ); - }); -}); - const customCacheCases: { config?: FmtConfig; name: string }[] = [ { name: 'without configured ignore patterns' }, { diff --git a/website/docs/en/guide/formatting.mdx b/website/docs/en/guide/formatting.mdx index a6f0701a..ae47fa0f 100644 --- a/website/docs/en/guide/formatting.mdx +++ b/website/docs/en/guide/formatting.mdx @@ -103,8 +103,6 @@ define.fmt({ Patterns follow Gitignore syntax and are resolved relative to the directory containing the Rstack configuration file. Because they are applied after the files are selected, they also exclude files passed explicitly on the command line. -By default, `rs fmt` ignores `.yarn/releases/` directories at any depth, which contain Yarn CLI distributions. To format these files, add `'!**/.yarn/releases/'` to `ignorePatterns` to re-include their directories. - ### Lock files By default, `rs fmt` ignores common lock files, including `package-lock.json`, `pnpm-lock.yaml`, and `skills-lock.json`. diff --git a/website/docs/zh/guide/formatting.mdx b/website/docs/zh/guide/formatting.mdx index 6b762f23..7615fbfb 100644 --- a/website/docs/zh/guide/formatting.mdx +++ b/website/docs/zh/guide/formatting.mdx @@ -103,8 +103,6 @@ define.fmt({ 这些模式遵循 Gitignore 语法,并且基于 Rstack 配置文件所在的目录解析。由于规则会在确定格式化范围后生效,因此也会排除命令行中显式传入的文件。 -`rs fmt` 默认忽略任意层级的 `.yarn/releases/` 目录,其中存放的是 Yarn CLI 发布产物。如果需要格式化这些文件,可以在 `ignorePatterns` 中添加 `'!**/.yarn/releases/'`,重新包含这些目录。 - ### Lock 文件 \{#lock-files} `rs fmt` 默认忽略常见的 lock 文件,包括 `package-lock.json`、`pnpm-lock.yaml` 和 `skills-lock.json`。