-
-
Notifications
You must be signed in to change notification settings - Fork 45
feat: Add new includeIgnoreFile() to config-helpers
#430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
DMartens
merged 37 commits into
eslint:main
from
kirkwaiblinger:include-gitignore-in-path
May 4, 2026
Merged
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
d1118c6
copy functionality from compat
kirkwaiblinger d973693
deprecate old APIs
kirkwaiblinger eb8cada
more deprecation documentation
kirkwaiblinger 24e10cb
changes
kirkwaiblinger 66b5597
lol why is that even allowed
kirkwaiblinger 8caf15a
feedback
kirkwaiblinger 45dd1b1
extract to function
kirkwaiblinger 819308f
Update packages/compat/README.md
kirkwaiblinger 7f1ab85
fileoverview
kirkwaiblinger 122711f
use standard markdown
kirkwaiblinger d00b460
update migrate-config
kirkwaiblinger 15f1c93
remove docs for undocumented API
kirkwaiblinger b691d0f
Update packages/config-helpers/README.md
kirkwaiblinger 0fae05c
Update packages/config-helpers/README.md
kirkwaiblinger 1fb1fd8
Update packages/config-helpers/README.md
kirkwaiblinger 2ceb6aa
fix remark about being cwd-relative in the docs
kirkwaiblinger 5627708
gitignoreResolution: boolean
kirkwaiblinger c8e16b6
tweak doc
kirkwaiblinger 5f6dc2e
overload correctly
kirkwaiblinger 729f667
cleanup
kirkwaiblinger 21aff8a
remove unused dev dep
kirkwaiblinger 0095f6d
Merge branch 'main' into include-gitignore-in-path
kirkwaiblinger 8dabd37
update stale comment
kirkwaiblinger ed0e79b
update typing and jsdoc
kirkwaiblinger 4a63985
Update packages/config-helpers/src/ignore-file.js
kirkwaiblinger 98141bd
Update packages/config-helpers/src/ignore-file.js
kirkwaiblinger a3af3c2
deprecated
kirkwaiblinger 5ec1eb1
Update packages/config-helpers/tests/types/types.test.ts
kirkwaiblinger ab0c58e
convertIgnorePatternToMinimatch type tests
kirkwaiblinger c3a24c2
add redundant test that exports are exported
kirkwaiblinger a49ef42
true placeholder strings in type tests
kirkwaiblinger e2fd6b4
tweak input validation
kirkwaiblinger 0f85748
Merge branch 'main' into include-gitignore-in-path
kirkwaiblinger b9ddf41
DRY tests and TypeErrors
kirkwaiblinger fa43e29
defineConfig[
kirkwaiblinger 9d4461c
Update packages/config-helpers/README.md
kirkwaiblinger 8f99a34
remove copilot prompt
kirkwaiblinger File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
|
lumirlumir marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,211 @@ | ||
| /** | ||
| * @fileoverview Ignore file utilities for the config-helpers package. | ||
| * This file was forked from the source code for the compat package. | ||
| * | ||
| * @author Nicholas C. Zakas | ||
| * @author Kirk Waiblinger | ||
| */ | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Imports | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| import fs from "node:fs"; | ||
| import path from "node:path"; | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Types | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| /** @typedef {import("@eslint/core").ConfigObject} Config */ | ||
|
|
||
| /** | ||
| * @typedef {object} IncludeIgnoreFileOptionsObject | ||
| * @property {boolean} [gitignoreResolution] Whether to interpret the contents of an ignore file relative to the config file or the ignore file. | ||
| * - gitignoreResolution: false (default): Interprets ignore patterns relative to the config file | ||
| * - gitignoreResolution: true: Interprets the ignore patterns in a file relative to the ignore file | ||
| * @property {string} [name] The name to give the output config object(s). | ||
| */ | ||
|
|
||
| /** | ||
| * Options for `includeIgnoreFile()`. May be provided as an object or, for | ||
| * legacy compatibility with `@eslint/compat`, as a string which is treated as | ||
| * the `name` option. | ||
| * @typedef {IncludeIgnoreFileOptionsObject | string} IncludeIgnoreFileOptions | ||
| */ | ||
|
mdjermanovic marked this conversation as resolved.
|
||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Exports | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| /** | ||
| * Converts an ESLint ignore pattern to a minimatch pattern. | ||
| * @param {string} pattern The .eslintignore or .gitignore pattern to convert. | ||
| * @returns {string} The converted pattern. | ||
| */ | ||
| export function convertIgnorePatternToMinimatch(pattern) { | ||
| const isNegated = pattern.startsWith("!"); | ||
| const negatedPrefix = isNegated ? "!" : ""; | ||
| const patternToTest = (isNegated ? pattern.slice(1) : pattern).trimEnd(); | ||
|
|
||
| // special cases | ||
| if (["", "**", "/**", "**/"].includes(patternToTest)) { | ||
| return `${negatedPrefix}${patternToTest}`; | ||
| } | ||
|
|
||
| const firstIndexOfSlash = patternToTest.indexOf("/"); | ||
|
|
||
| const matchEverywherePrefix = | ||
| firstIndexOfSlash < 0 || firstIndexOfSlash === patternToTest.length - 1 | ||
| ? "**/" | ||
| : ""; | ||
|
|
||
| const patternWithoutLeadingSlash = | ||
| firstIndexOfSlash === 0 ? patternToTest.slice(1) : patternToTest; | ||
|
|
||
| /* | ||
| * Escape `{` and `(` because in gitignore patterns they are just | ||
| * literal characters without any specific syntactic meaning, | ||
| * while in minimatch patterns they can form brace expansion or extglob syntax. | ||
| * | ||
| * For example, gitignore pattern `src/{a,b}.js` ignores file `src/{a,b}.js`. | ||
| * But, the same minimatch pattern `src/{a,b}.js` ignores files `src/a.js` and `src/b.js`. | ||
| * Minimatch pattern `src/\{a,b}.js` is equivalent to gitignore pattern `src/{a,b}.js`. | ||
| */ | ||
| const escapedPatternWithoutLeadingSlash = | ||
| patternWithoutLeadingSlash.replaceAll( | ||
| // eslint-disable-next-line regexp/no-empty-lookarounds-assertion -- False positive | ||
| /(?=((?:\\.|[^{(])*))\1([{(])/guy, | ||
| "$1\\$2", | ||
| ); | ||
|
|
||
| const matchInsideSuffix = patternToTest.endsWith("/**") ? "/*" : ""; | ||
|
|
||
| return `${negatedPrefix}${matchEverywherePrefix}${escapedPatternWithoutLeadingSlash}${matchInsideSuffix}`; | ||
| } | ||
|
|
||
| /** | ||
| * @param {string} ignoreFilePath | ||
| * @returns {string[]} | ||
| */ | ||
| function ignoreFilePathToPatterns(ignoreFilePath) { | ||
| const ignoreFile = fs.readFileSync(ignoreFilePath, "utf8"); | ||
| const lines = ignoreFile.split(/\r?\n/u); | ||
|
|
||
| return lines | ||
| .map(line => line.trim()) | ||
| .filter(line => line && !line.startsWith("#")) | ||
| .map(convertIgnorePatternToMinimatch); | ||
| } | ||
|
|
||
| /** | ||
| * Helper to parse and validate the options to `includeIgnoreFile()` | ||
| * | ||
| * @param {string | { gitignoreResolution?: unknown, name?: unknown } | undefined} options | ||
| * @returns {{ gitignoreResolution: boolean, name: string }} | ||
| */ | ||
| function parseOptions(options) { | ||
| // legacy compatibility with @eslint/compat's `includeIgnoreFile` | ||
| if (typeof options === "string") { | ||
| return { gitignoreResolution: false, name: options }; | ||
| } | ||
|
|
||
| const optionsObject = options ?? {}; | ||
| if (typeof optionsObject !== "object" || Array.isArray(optionsObject)) { | ||
| throw new TypeError( | ||
| "The options argument to `includeIgnoreFile()` should be an object or a string.", | ||
| ); | ||
| } | ||
|
|
||
| const gitignoreResolution = optionsObject.gitignoreResolution ?? false; | ||
| if (typeof gitignoreResolution !== "boolean") { | ||
| throw new TypeError( | ||
| "The `gitignoreResolution` option must be specified a boolean or omitted", | ||
| ); | ||
| } | ||
|
mdjermanovic marked this conversation as resolved.
|
||
|
|
||
| const name = optionsObject.name ?? `Imported .gitignore patterns`; | ||
| if (typeof name !== "string") { | ||
| throw new TypeError( | ||
| "The `name` option must be specified as a string or omitted.", | ||
| ); | ||
| } | ||
|
|
||
| return { gitignoreResolution, name }; | ||
| } | ||
|
|
||
| /** | ||
| * @overload | ||
| * | ||
| * Reads ignore files and returns objects with the ignore patterns. | ||
| * | ||
| * @param {string[]} ignoreFilePathArg The paths of ignore files to include. | ||
| * @param {IncludeIgnoreFileOptions} [options] | ||
| * @returns {Config[]} | ||
| */ | ||
|
|
||
| /** | ||
| * @overload | ||
| * | ||
| * Reads an ignore file and returns an object with the ignore patterns. | ||
| * | ||
| * @param {string} ignoreFilePathArg The path of the ignore file to include. | ||
| * @param {IncludeIgnoreFileOptions} [options] | ||
| * @returns {Config} | ||
| */ | ||
|
|
||
| /** | ||
| * @overload | ||
| * | ||
| * Reads an ignore file(s) and returns an object(s) with the ignore patterns. | ||
| * | ||
| * @param {string[] | string} ignoreFilePathArg The path(s) of the ignore file(s) to include. | ||
| * @param {IncludeIgnoreFileOptions} [options] | ||
| * @returns {Config[] | Config} | ||
| */ | ||
|
|
||
| /** | ||
| * Reads an ignore file(s) and returns an object(s) with the ignore patterns. | ||
| * | ||
| * @param {string[] | string} ignoreFilePathArg The path(s) of the ignore file(s) to include. | ||
| * @param {IncludeIgnoreFileOptions} [options] | ||
| * @returns {Config[] | Config} | ||
| */ | ||
| export function includeIgnoreFile(ignoreFilePathArg, options) { | ||
| const returnSingleObject = !Array.isArray(ignoreFilePathArg); | ||
| const ignoreFilePaths = Array.isArray(ignoreFilePathArg) | ||
| ? ignoreFilePathArg | ||
| : [ignoreFilePathArg]; | ||
| for (const ignorePath of ignoreFilePaths) { | ||
| if (typeof ignorePath !== "string") { | ||
| throw new TypeError( | ||
| "The first argument to `includeIgnoreFile()` should be a string or array of strings", | ||
| ); | ||
| } | ||
| if (!path.isAbsolute(ignorePath)) { | ||
| throw new Error( | ||
| `The ignore file location must be an absolute path. Received ${ignorePath}`, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| const { gitignoreResolution, name } = parseOptions(options); | ||
|
|
||
| if (returnSingleObject) { | ||
| return { | ||
| name, | ||
| ignores: ignoreFilePathToPatterns(ignoreFilePathArg), | ||
| ...(gitignoreResolution | ||
| ? { basePath: path.dirname(ignoreFilePathArg) } | ||
| : {}), | ||
| }; | ||
| } | ||
|
|
||
| return ignoreFilePaths.map((ignoreFilePath, i) => ({ | ||
| name: `${name} (${i})`, | ||
| ignores: ignoreFilePathToPatterns(ignoreFilePath), | ||
| ...(gitignoreResolution | ||
| ? { basePath: path.dirname(ignoreFilePath) } | ||
| : {}), | ||
| })); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
packages/config-helpers/tests/fixtures/ignore-files/gitignore1.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # Node.js | ||
| node_modules | ||
| !/fixtures/node_modules | ||
| /dist | ||
|
|
||
| # Logs | ||
| *.log | ||
|
|
||
| # Gatsby files | ||
| .cache/ | ||
|
|
||
| # vuepress build output | ||
| .vuepress/dist | ||
|
|
||
| # other | ||
| */foo.js | ||
| dir/** |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.