Skip to content

Commit

Permalink
Merge pull request #13 from Agentic-Insights/linterfixes
Browse files Browse the repository at this point in the history
fix: add the contextignore fix and linter usage
  • Loading branch information
killerapp authored Sep 22, 2024
2 parents 97c8b49 + 3a88501 commit a2fb8c2
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 19 deletions.
61 changes: 47 additions & 14 deletions linters/typescript/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,63 @@ function parseLogLevel(logLevelArg: string): LogLevel {
}
}

function printUsage() {
console.log(`
Usage: codebase-context-lint <directory_to_lint> [options]
Codebase Context Linter
This tool validates context files (.context.md, .context.yaml, .context.json),
.contextdocs.md, and .contextignore according to the Codebase Context Specification.
Arguments:
<directory_to_lint> The directory containing the files to lint
Options:
--log-level <level> Set the logging level (error, warn, info, debug)
Default: info
--help, -h Show this help message
Examples:
codebase-context-lint .
codebase-context-lint /path/to/project --log-level debug
For more information, visit: https://github.com/Agentic-Insights/codebase-context-spec
`);
}

async function main() {
const args = process.argv.slice(2);
let directoryToLint: string | undefined;
let logLevel = LogLevel.INFO;

for (let i = 0; i < args.length; i++) {
if (args[i] === '--log-level' && i + 1 < args.length) {
logLevel = parseLogLevel(args[i + 1]);
i++; // Skip the next argument as it's the log level value
} else if (!directoryToLint) {
directoryToLint = args[i];
switch (args[i]) {
case '--log-level':
if (i + 1 < args.length) {
logLevel = parseLogLevel(args[++i]);
} else {
console.error('Error: --log-level requires a value');
process.exit(1);
}
break;
case '--help':
case '-h':
printUsage();
process.exit(0);
default:
if (!directoryToLint) {
directoryToLint = args[i];
} else {
console.error(`Error: Unexpected argument '${args[i]}'`);
printUsage();
process.exit(1);
}
}
}

if (!directoryToLint) {
console.error(`
Usage: codebase-context-lint <directory_to_lint> [--log-level <level>]
Codebase Context Linter
This tool validates context files, including .contextdocs.md and .contextignore, according to the Codebase Context Specification.
Options:
--log-level <level> Set the logging level (error, warn, info, debug). Default: info
`);
console.error('Error: Directory to lint is required');
printUsage();
process.exit(1);
}

Expand Down
27 changes: 22 additions & 5 deletions linters/typescript/src/context_linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ export class ContextLinter {
isValid = await this.handleContextdocs(directoryPath) && isValid;
isValid = await this.handleContextFilesRecursively(directoryPath) && isValid;

// Log ignored files
this.logIgnoredFiles(directoryPath);
// Report on .contextignore usage
this.reportContextignoreUsage(directoryPath);

// Clear all caches after processing the directory
this.clearAllCaches();
Expand Down Expand Up @@ -109,6 +109,9 @@ export class ContextLinter {
if (await fileExists(contextignorePath)) {
const content = await fs.promises.readFile(contextignorePath, 'utf-8');
await this.contextignoreLinter.lintContextignoreFile(content, contextignorePath);
this.log(LogLevel.INFO, `Found .contextignore file at ${this.normalizePath(contextignorePath)}`);
} else {
this.log(LogLevel.INFO, 'No .contextignore file found. All files will be processed.');
}
}

Expand Down Expand Up @@ -174,19 +177,33 @@ export class ContextLinter {
}

/**
* Log ignored files in the directory
* Report on .contextignore usage
* @param directoryPath The path of the directory to check for ignored files
*/
private logIgnoredFiles(directoryPath: string): void {
private reportContextignoreUsage(directoryPath: string): void {
const ignoredFiles = this.contextignoreLinter.getIgnoredFiles(directoryPath);
const ignoredDirectories = this.contextignoreLinter.getIgnoredDirectories(directoryPath);

this.log(LogLevel.INFO, '\n.contextignore Usage Report:');
this.log(LogLevel.INFO, `Total ignored files: ${ignoredFiles.length}`);
this.log(LogLevel.INFO, `Total ignored directories: ${ignoredDirectories.length}`);

if (this.logLevel === LogLevel.DEBUG) {
const ignoredFiles = this.contextignoreLinter.getIgnoredFiles(directoryPath);
if (ignoredFiles.length > 0) {
this.log(LogLevel.DEBUG, '\nIgnored files:');
for (const file of ignoredFiles) {
this.log(LogLevel.DEBUG, ` ${this.normalizePath(file)}`);
}
}
if (ignoredDirectories.length > 0) {
this.log(LogLevel.DEBUG, '\nIgnored directories:');
for (const dir of ignoredDirectories) {
this.log(LogLevel.DEBUG, ` ${this.normalizePath(dir)}`);
}
}
}

this.log(LogLevel.INFO, ''); // Add a blank line for better readability
}

/**
Expand Down
36 changes: 36 additions & 0 deletions linters/typescript/src/contextignore_linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,40 @@ export class ContextignoreLinter {
return [];
}
}

/**
* Get a list of ignored directories in a directory
* @param directoryPath The path of the directory to check
* @returns An array of ignored directory paths
*/
public getIgnoredDirectories(directoryPath: string): string[] {
try {
const ig = this.ignoreCache.get(directoryPath);
if (!ig) {
return [];
}

const ignoredDirectories: string[] = [];
const walk = (dir: string) => {
const dirents = fs.readdirSync(dir, { withFileTypes: true });
for (const dirent of dirents) {
if (dirent.isDirectory()) {
const res = path.join(dir, dirent.name);
const relativePath = path.relative(directoryPath, res);
if (ig.ignores(relativePath)) {
ignoredDirectories.push(res);
} else {
walk(res);
}
}
}
};

walk(directoryPath);
return ignoredDirectories;
} catch (error) {
this.log(LogLevel.ERROR, `Error getting ignored directories for directory ${directoryPath}: ${error instanceof Error ? error.message : String(error)}`);
return [];
}
}
}

0 comments on commit a2fb8c2

Please sign in to comment.