@anirudw/repolens 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,125 @@
1
+ import { readdirSync, statSync } from "node:fs";
2
+ import { join, relative, isAbsolute, resolve } from "node:path";
3
+ import { createIgnoreRules, shouldIgnore } from "./ignore.js";
4
+ import {
5
+ isTargetLanguage,
6
+ SupportedLanguage,
7
+ getLanguageFromPath,
8
+ } from "./file-types.js";
9
+
10
+ export interface ScannedFile {
11
+ path: string;
12
+ absolutePath: string;
13
+ relativePath: string;
14
+ language: SupportedLanguage;
15
+ }
16
+
17
+ export interface ScanResult {
18
+ files: ScannedFile[];
19
+ totalFiles: number;
20
+ filesByLanguage: Record<SupportedLanguage, number>;
21
+ ignoredCount: number;
22
+ }
23
+
24
+ export interface ScanOptions {
25
+ rootDir: string;
26
+ verbose?: boolean;
27
+ }
28
+
29
+ export function scanDirectory(options: ScanOptions): ScanResult {
30
+ const { rootDir, verbose = false } = options;
31
+ const absoluteRoot = isAbsolute(rootDir) ? rootDir : resolve(rootDir);
32
+
33
+ if (verbose) {
34
+ console.log(`Scanning directory: ${absoluteRoot}`);
35
+ }
36
+
37
+ const ig = createIgnoreRules(absoluteRoot);
38
+ const files: ScannedFile[] = [];
39
+ let ignoredCount = 0;
40
+
41
+ function walk(dir: string, baseDir: string = dir): void {
42
+ let entries: string[];
43
+ try {
44
+ entries = readdirSync(dir);
45
+ } catch (err) {
46
+ if (verbose) {
47
+ console.warn(`Warning: Cannot read directory ${dir}: ${err}`);
48
+ }
49
+ return;
50
+ }
51
+
52
+ for (const entry of entries) {
53
+ const fullPath = join(dir, entry);
54
+ const relativePath = relative(baseDir, fullPath);
55
+
56
+ let isDir: boolean;
57
+ try {
58
+ isDir = statSync(fullPath).isDirectory();
59
+ } catch (err) {
60
+ if (verbose) {
61
+ console.warn(`Warning: Cannot stat ${fullPath}: ${err}`);
62
+ }
63
+ continue;
64
+ }
65
+
66
+ if (shouldIgnore(ig, relativePath, isDir)) {
67
+ if (!isDir) {
68
+ ignoredCount++;
69
+ }
70
+ continue;
71
+ }
72
+
73
+ if (isDir) {
74
+ walk(fullPath, baseDir);
75
+ } else {
76
+ if (isTargetLanguage(entry)) {
77
+ files.push({
78
+ path: entry,
79
+ absolutePath: fullPath,
80
+ relativePath: normalizePath(relativePath),
81
+ language: getLanguageFromFile(entry),
82
+ });
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ walk(absoluteRoot);
89
+
90
+ const filesByLanguage = countByLanguage(files);
91
+
92
+ if (verbose) {
93
+ console.log(`Found ${files.length} target files`);
94
+ for (const [lang, count] of Object.entries(filesByLanguage)) {
95
+ if (count > 0) {
96
+ console.log(` ${lang}: ${count}`);
97
+ }
98
+ }
99
+ }
100
+
101
+ return {
102
+ files,
103
+ totalFiles: files.length,
104
+ filesByLanguage,
105
+ ignoredCount,
106
+ };
107
+ }
108
+
109
+ function normalizePath(p: string): string {
110
+ return p.replace(/\\/g, "/");
111
+ }
112
+
113
+ function getLanguageFromFile(filePath: string): SupportedLanguage {
114
+ return getLanguageFromPath(filePath);
115
+ }
116
+
117
+ function countByLanguage(
118
+ files: ScannedFile[]
119
+ ): Record<SupportedLanguage, number> {
120
+ const counts: Partial<Record<SupportedLanguage, number>> = {};
121
+ for (const file of files) {
122
+ counts[file.language] = (counts[file.language] ?? 0) + 1;
123
+ }
124
+ return counts as Record<SupportedLanguage, number>;
125
+ }
@@ -0,0 +1,13 @@
1
+ import picocolors from "picocolors";
2
+
3
+ export const pc = {
4
+ bold: picocolors.bold,
5
+ dim: picocolors.dim,
6
+ cyan: picocolors.cyan,
7
+ yellow: picocolors.yellow,
8
+ green: picocolors.green,
9
+ red: picocolors.red,
10
+ blue: picocolors.blue,
11
+ magenta: picocolors.magenta,
12
+ white: picocolors.white,
13
+ };
@@ -0,0 +1,5 @@
1
+ # Dummy Repo
2
+ Welcome to the project.
3
+
4
+ Please read the [Setup Guide](./docs/setup.md) before starting.
5
+ Also check out our [[Architecture Notes]] for system design.
File without changes
@@ -0,0 +1,11 @@
1
+ package com.repolens.dummy;
2
+
3
+ import java.util.List;
4
+ import java.util.ArrayList;
5
+ import com.repolens.dummy.utils.Logger;
6
+
7
+ public class App {
8
+ public static void main(String[] args) {
9
+ System.out.println("Repolens Java Test");
10
+ }
11
+ }
@@ -0,0 +1,9 @@
1
+ import os
2
+ from sys import argv
3
+ from middleware import auth
4
+
5
+ def start_server():
6
+ print("Server starting...")
7
+
8
+ if __name__ == "__main__":
9
+ start_server()
@@ -0,0 +1,7 @@
1
+ import { App } from './components/App';
2
+ import React, { useState } from 'react';
3
+ const fs = require('fs');
4
+
5
+ function mount() {
6
+ console.log("App mounted");
7
+ }
@@ -0,0 +1,36 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { readFileSync } from 'fs';
3
+ import { createParser } from '../src/parser/index';
4
+
5
+ describe('AST Language Parsers', () => {
6
+ it('should parse JavaScript imports and React heuristics', async () => {
7
+ const parser = createParser('.js');
8
+ expect(parser).not.toBeNull();
9
+
10
+ const content = readFileSync('tests/fixtures/dummy-repo/src/index.js', 'utf-8');
11
+ const result = await parser!.parse('tests/fixtures/dummy-repo/src/index.js', content);
12
+
13
+ expect(result.dependencies.length).toBe(3);
14
+ expect(result.dependencies.map(d => d.rawSpecifier)).toContain('react');
15
+ expect(result.metadata.heuristics.isReact).toBe(true);
16
+ });
17
+
18
+ it('should parse Python imports and Entry Point heuristics', async () => {
19
+ const parser = createParser('.py');
20
+ const content = readFileSync('tests/fixtures/dummy-repo/src/api.py', 'utf-8');
21
+ const result = await parser!.parse('tests/fixtures/dummy-repo/src/api.py', content);
22
+
23
+ expect(result.dependencies.length).toBe(3);
24
+ expect(result.dependencies.map(d => d.rawSpecifier)).toContain('os');
25
+ expect(result.metadata.heuristics.hasEntrypoint).toBe(true);
26
+ });
27
+
28
+ it('should parse Markdown links and wikilinks', async () => {
29
+ const parser = createParser('.md');
30
+ const content = readFileSync('tests/fixtures/dummy-repo/README.md', 'utf-8');
31
+ const result = await parser!.parse('tests/fixtures/dummy-repo/README.md', content);
32
+
33
+ expect(result.dependencies.length).toBe(2);
34
+ expect(result.dependencies.map(d => d.type)).toContain('wikilink');
35
+ });
36
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022"],
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "declaration": true,
15
+ "declarationMap": true,
16
+ "sourceMap": true
17
+ },
18
+ "include": ["src/**/*"],
19
+ "exclude": ["node_modules", "dist", "tests"]
20
+ }