-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathgrep.ts
125 lines (113 loc) · 3.02 KB
/
grep.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import fs from 'fs';
import path from 'path';
/**
* This function runs the GREP functionality on a given file.
* Returns null if no match found in the file.
*
* @param {string} expression
* @param {string} filePath
* @param {boolean} [prependFilePath=false] - Used when we are recursively searching in a dir.
* @param {boolean} [exclude=false] - Represents the -v option
* @param {boolean} [caseInsensitive=false] - Represents the -i option
* @returns {(string | null)}
*/
function grepFile(
expression: string,
filePath: string,
prependFilePath: boolean = false,
exclude: boolean = false,
caseInsensitive: boolean = false
): string | null {
const input = fs.readFileSync(filePath).toString();
if (expression === '') {
return input;
}
// Split the lines into input
const lines = input.split(/\r|\r\n|\n/);
const output: string[] = [];
// Generate the RegExp based on the inputs
let regExp: RegExp;
if (caseInsensitive) {
regExp = new RegExp(expression, 'i');
} else {
regExp = new RegExp(expression);
}
// For each line test the RegExp and include/exclude based on the inputs.
lines.forEach((line) => {
const matches = regExp.exec(line);
if (exclude && matches === null) {
output.push(line);
} else if (!exclude && matches !== null) {
if (prependFilePath) {
output.push(filePath + ':' + line);
} else {
output.push(line);
}
}
});
if (output.length > 0) {
return output.join('\n').replace(/\\/g, '/');
}
return null;
}
/**
* Helper function to recursively traverse a DIR.
*
* @param {string} dirname
* @param {string[]} [arr=[]]
* @returns {string[]}
*/
function getFiles(dirname: string, arr: string[] = []): string[] {
const files = fs.readdirSync(dirname);
files.forEach((file) => {
const filepath = path.join(dirname, file).replace(/\\/g, '/');
if (fs.statSync(filepath).isDirectory()) {
arr = getFiles(filepath, arr);
} else {
arr.push(filepath);
}
});
return arr;
}
/**
* Main grep function that performs the GREP operation.
* Returns null if no match found
*
* @param {string} expression
* @param {string} pathStr
* @param {boolean} [exclude=false] - Represents the -v option
* @param {boolean} [caseInsensitive=false] - Represents the -i option
* @returns {(string | null)}
*/
function grep(
expression: string,
pathStr: string,
exclude: boolean = false,
caseInsensitive: boolean = false
): string | null {
const stats = fs.statSync(pathStr);
if (stats.isFile()) {
return grepFile(expression, pathStr, false, exclude, caseInsensitive);
}
const output: string[] = [];
if (stats.isDirectory()) {
const files = getFiles(pathStr);
files.forEach((file) => {
const fileOutput = grepFile(
expression,
file,
true,
exclude,
caseInsensitive
);
if (fileOutput != null) {
output.push(fileOutput);
}
});
}
if (output.length > 0) {
return output.join('\n');
}
return null;
}
export { grep };