Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
|-------------------|------|----------------|---------------|
Expand Down Expand Up @@ -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?
Expand Down
5 changes: 4 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,11 @@ async function run(paths: string[], options: CliOptions): Promise<void> {
// 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]);

Expand Down
35 changes: 35 additions & 0 deletions src/parsers/gitignore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
26 changes: 24 additions & 2 deletions src/parsers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -152,6 +169,11 @@ export function getBuiltinParsers(): Parser[] {
// General
gitignoreParser,
dockerignoreParser,
remarkignoreParser,
lycheeignoreParser,
secretlintignoreParser,
vscodeignoreParser,
ignoresecretsParser,

// JavaScript/TypeScript
eslintIgnoreParser,
Expand Down
5 changes: 5 additions & 0 deletions tests/integration/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
53 changes: 52 additions & 1 deletion tests/parsers/gitignore.test.ts
Original file line number Diff line number Diff line change
@@ -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', () => {
Expand Down Expand Up @@ -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);
});
});