From 3ec76d0282b6adcdf2cd8cef978bdcbecc2ae507 Mon Sep 17 00:00:00 2001 From: Maciej Mensfeld Date: Tue, 27 Jan 2026 09:58:31 +0100 Subject: [PATCH] Add support for 5 new ignore file parsers Implements feature request from #5 New ignore file parsers: - remarkignore (.remarkignore) - remark markdown processor - lycheeignore (.lycheeignore) - lychee link checker - secretlintignore (.secretlintignore) - secretlint - vscodeignore (.vscodeignore) - VS Code extensions - ignoresecrets (.ignoresecrets) - git-leaks alternative Changes: - Add 5 new ignore file parsers using the existing parseIgnoreFile function - Export new parsers from gitignore.ts and index.ts - Add new parsers to getBuiltinParsers() array - Update --skip-ignore-files to handle 'ignoresecrets' (doesn't end with 'ignore') - Update README.md to document new ignore files (67+ configs now supported) - Add comprehensive tests for all new parsers - Update CHANGELOG.md with both the fix and feature from #5 - Update integration tests to verify new ignore files are skipped with --skip-ignore-files All 303 tests pass. --- CHANGELOG.md | 14 +++++++++ README.md | 7 ++++- src/cli.ts | 5 +++- src/parsers/gitignore.ts | 35 ++++++++++++++++++++++ src/parsers/index.ts | 26 ++++++++++++++-- tests/integration/cli.test.ts | 5 ++++ tests/parsers/gitignore.test.ts | 53 ++++++++++++++++++++++++++++++++- 7 files changed, 140 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd17acc..9bac75f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- Support for 5 new ignore file parsers (Issue #5): + - **remark** (`.remarkignore`) - Markdown processor ignore file + - **lychee** (`.lycheeignore`) - Link checker ignore file + - **secretlint** (`.secretlintignore`) - Secret detection ignore file + - **VS Code** (`.vscodeignore`) - VS Code extension ignore file + - **git-leaks** (`.ignoresecrets`) - Gitleaks alternative ignore file +- Total supported configuration files increased from 62+ to 67+ + +### Fixed +- `--skip-ignore-files` now properly skips `.stylelintignore` files (Issue #5) +- `--skip-ignore-files` now dynamically skips all ignore file parsers (names ending with 'ignore') +- Future-proof: new ignore file parsers are automatically skipped when using `--skip-ignore-files` + ## [0.3.0] - 2026-01-26 ### Added diff --git a/README.md b/README.md index e22a460..347ae53 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ npx lostconf --exclude "**/test/**" --exclude "**/tests/**" ## Supported Config Files -lostconf supports **62+ configuration files** from popular tools across **15+ languages**: +lostconf supports **67+ configuration files** from popular tools across **15+ languages**: | Language/Category | Tool | Config File(s) | What We Check | |-------------------|------|----------------|---------------| @@ -171,6 +171,11 @@ lostconf supports **62+ configuration files** from popular tools across **15+ la | **General** | Git | `.gitignore` | All file paths and patterns | | | Docker | `.dockerignore` | All file paths and patterns | | | markdownlint | `.markdownlintignore` | All file paths and patterns | +| | remark | `.remarkignore` | All file paths and patterns | +| | lychee | `.lycheeignore` | All file paths and patterns | +| | secretlint | `.secretlintignore` | All file paths and patterns | +| | VS Code | `.vscodeignore` | All file paths and patterns | +| | git-leaks | `.ignoresecrets` | All file paths and patterns | | **Documentation** | alex | `.alexignore`, `.alexrc`, `.alexrc.json` | Ignore patterns and allowed terms | ## What Does lostconf Validate? diff --git a/src/cli.ts b/src/cli.ts index ad1099e..4126d82 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -113,8 +113,11 @@ async function run(paths: string[], options: CliOptions): Promise { // If skipIgnoreFiles is enabled, find all parsers whose names end with 'ignore' // Note: This filters parser names (e.g., 'gitignore', 'stylelintignore'), not file paths. // Parser names are defined in code, so a directory named 'superignore' won't be affected. + // Special case: 'ignoresecrets' doesn't end with 'ignore' but is an ignore file const ignoreParserNames = skipIgnoreFiles - ? parsers.filter((p) => p.name.endsWith('ignore')).map((p) => p.name) + ? parsers + .filter((p) => p.name.endsWith('ignore') || p.name === 'ignoresecrets') + .map((p) => p.name) : []; const excludeParserSet = new Set([...ignoreParserNames, ...excludeParsers]); diff --git a/src/parsers/gitignore.ts b/src/parsers/gitignore.ts index c53de94..c8d34d4 100644 --- a/src/parsers/gitignore.ts +++ b/src/parsers/gitignore.ts @@ -78,6 +78,41 @@ export const dockerignoreParser: Parser = { parse: parseIgnoreFile }; +/** Remarkignore parser (remark markdown processor) */ +export const remarkignoreParser: Parser = { + name: 'remarkignore', + filePatterns: ['.remarkignore', '**/.remarkignore'], + parse: parseIgnoreFile +}; + +/** Lycheeignore parser (lychee link checker) */ +export const lycheeignoreParser: Parser = { + name: 'lycheeignore', + filePatterns: ['.lycheeignore', '**/.lycheeignore'], + parse: parseIgnoreFile +}; + +/** Secretlintignore parser (secretlint) */ +export const secretlintignoreParser: Parser = { + name: 'secretlintignore', + filePatterns: ['.secretlintignore', '**/.secretlintignore'], + parse: parseIgnoreFile +}; + +/** Vscodeignore parser (VS Code extensions) */ +export const vscodeignoreParser: Parser = { + name: 'vscodeignore', + filePatterns: ['.vscodeignore', '**/.vscodeignore'], + parse: parseIgnoreFile +}; + +/** Ignoresecrets parser (git-leaks) */ +export const ignoresecretsParser: Parser = { + name: 'ignoresecrets', + filePatterns: ['.ignoresecrets', '**/.ignoresecrets'], + parse: parseIgnoreFile +}; + /** Generic ignore file parser factory */ export function createIgnoreParser(name: string, filePatterns: string[]): Parser { return { diff --git a/src/parsers/index.ts b/src/parsers/index.ts index d18f2f6..4c9b6bc 100644 --- a/src/parsers/index.ts +++ b/src/parsers/index.ts @@ -3,7 +3,16 @@ */ // General -export { gitignoreParser, dockerignoreParser, createIgnoreParser } from './gitignore.js'; +export { + gitignoreParser, + dockerignoreParser, + remarkignoreParser, + lycheeignoreParser, + secretlintignoreParser, + vscodeignoreParser, + ignoresecretsParser, + createIgnoreParser +} from './gitignore.js'; // JavaScript/TypeScript export { eslintIgnoreParser } from './eslint.js'; @@ -100,7 +109,15 @@ export { alexIgnoreParser, alexRcParser } from './alex.js'; import type { Parser } from '../plugin/types.js'; // Import all parsers for getBuiltinParsers -import { gitignoreParser, dockerignoreParser } from './gitignore.js'; +import { + gitignoreParser, + dockerignoreParser, + remarkignoreParser, + lycheeignoreParser, + secretlintignoreParser, + vscodeignoreParser, + ignoresecretsParser +} from './gitignore.js'; import { eslintIgnoreParser } from './eslint.js'; import { eslintFlatParser } from './eslint-flat.js'; import { prettierIgnoreParser } from './prettier.js'; @@ -152,6 +169,11 @@ export function getBuiltinParsers(): Parser[] { // General gitignoreParser, dockerignoreParser, + remarkignoreParser, + lycheeignoreParser, + secretlintignoreParser, + vscodeignoreParser, + ignoresecretsParser, // JavaScript/TypeScript eslintIgnoreParser, diff --git a/tests/integration/cli.test.ts b/tests/integration/cli.test.ts index 37a3d6a..010ed08 100644 --- a/tests/integration/cli.test.ts +++ b/tests/integration/cli.test.ts @@ -185,6 +185,11 @@ describe('CLI Integration Tests', () => { await fs.writeFile(path.join(testDir, '.eslintignore'), 'stale-eslint'); await fs.writeFile(path.join(testDir, '.stylelintignore'), 'stale-stylelint'); await fs.writeFile(path.join(testDir, '.dockerignore'), 'stale-docker'); + await fs.writeFile(path.join(testDir, '.remarkignore'), 'stale-remark'); + await fs.writeFile(path.join(testDir, '.lycheeignore'), 'stale-lychee'); + await fs.writeFile(path.join(testDir, '.secretlintignore'), 'stale-secretlint'); + await fs.writeFile(path.join(testDir, '.vscodeignore'), 'stale-vscode'); + await fs.writeFile(path.join(testDir, '.ignoresecrets'), 'stale-ignoresecrets'); await fs.writeFile(path.join(testDir, 'tsconfig.json'), '{"exclude": ["stale-ts"]}'); const { stdout } = await execAsync( diff --git a/tests/parsers/gitignore.test.ts b/tests/parsers/gitignore.test.ts index f11273e..3dbce92 100644 --- a/tests/parsers/gitignore.test.ts +++ b/tests/parsers/gitignore.test.ts @@ -1,5 +1,12 @@ import { describe, it, expect } from 'vitest'; -import { gitignoreParser } from '../../src/parsers/gitignore.js'; +import { + gitignoreParser, + remarkignoreParser, + lycheeignoreParser, + secretlintignoreParser, + vscodeignoreParser, + ignoresecretsParser +} from '../../src/parsers/gitignore.js'; import { PatternType } from '../../src/core/types.js'; describe('gitignoreParser', () => { @@ -80,3 +87,47 @@ dist expect(patterns[2].line).toBe(4); }); }); + +describe('New ignore file parsers', () => { + const testContent = ` +# Test comment +*.log +node_modules +`; + + it('remarkignoreParser should parse correctly', () => { + expect(remarkignoreParser.name).toBe('remarkignore'); + expect(remarkignoreParser.filePatterns).toContain('.remarkignore'); + const patterns = remarkignoreParser.parse('.remarkignore', testContent); + expect(patterns).toHaveLength(2); + expect(patterns[0].value).toBe('*.log'); + }); + + it('lycheeignoreParser should parse correctly', () => { + expect(lycheeignoreParser.name).toBe('lycheeignore'); + expect(lycheeignoreParser.filePatterns).toContain('.lycheeignore'); + const patterns = lycheeignoreParser.parse('.lycheeignore', testContent); + expect(patterns).toHaveLength(2); + }); + + it('secretlintignoreParser should parse correctly', () => { + expect(secretlintignoreParser.name).toBe('secretlintignore'); + expect(secretlintignoreParser.filePatterns).toContain('.secretlintignore'); + const patterns = secretlintignoreParser.parse('.secretlintignore', testContent); + expect(patterns).toHaveLength(2); + }); + + it('vscodeignoreParser should parse correctly', () => { + expect(vscodeignoreParser.name).toBe('vscodeignore'); + expect(vscodeignoreParser.filePatterns).toContain('.vscodeignore'); + const patterns = vscodeignoreParser.parse('.vscodeignore', testContent); + expect(patterns).toHaveLength(2); + }); + + it('ignoresecretsParser should parse correctly', () => { + expect(ignoresecretsParser.name).toBe('ignoresecrets'); + expect(ignoresecretsParser.filePatterns).toContain('.ignoresecrets'); + const patterns = ignoresecretsParser.parse('.ignoresecrets', testContent); + expect(patterns).toHaveLength(2); + }); +});