-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathfindfilewithpattern
More file actions
executable file
·71 lines (59 loc) · 2.73 KB
/
findfilewithpattern
File metadata and controls
executable file
·71 lines (59 loc) · 2.73 KB
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
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const programname = path.basename(process.argv[1]);
const helpMessage = `
${programname} - searches for files with IntelliJ style pattern.
Usage: ${programname} [pattern]
Options:
-h, --help Show this help message and exit
Examples:
${programname} src/main/**/MyFile*java
Details:
- * are wildcards within a file / directory name
- ** are wildcards that can span directories (that is, matches foo/bar/baz)
- the matching is case insensitive
- on boundaries between uppercase and lowercase there are implicit * wildcards - e.g. fooBaz will match FoOBARbaz
`;
if (process.argv.length < 3 || process.argv.includes('--help') || process.argv.includes('-h')) {
console.log(helpMessage);
process.exit(0);
}
for (let i = 2; i < process.argv.length; i++) {
const arg = process.argv[i];
locateFile(arg).forEach(f => console.log(f));
}
/** If the file doesn't exist, we treat it as a glob pattern and search for it in the current directory and its subdirectories.
* If something like that doesn't exist, we log an error and abort. Also, if there are several files matching that pattern. */
function locateFile(filepattern) {
const fileregex = makeIntellijStylePattern(filepattern);
const files = searchFile(fileregex);
return files;
}
function searchFile(fileregex, dir = '.', files = []) {
const entries = fs.readdirSync(dir, {withFileTypes: true});
entries.forEach((entry) => {
if (entry.isDirectory()) {
searchFile(fileregex, path.join(dir, entry.name), files);
} else if (entry.isFile() && entry.name.match(fileregex)) {
files.push(path.join(dir, entry.name));
}
});
return files;
}
/**
* Creates a case-insensitive regular expression based on the given file pattern.
* The function splits the input string at the boundary before uppercase letters,
* the boundary before and after a block of digits,
* alphanumeric-to-non-alphanumeric boundaries, and non-alphanumeric-to-alphanumeric
* boundaries. It then concatenates the segments with '.*' in between.
* Example: for 'ab-cFX23qwerX' it returns /ab.*-.*c.*F.*X.*23.*qwer.*X/i
*
* @param {string} filepattern - The file pattern to convert into a regular expression.
* @returns {RegExp} - A case-insensitive regular expression based on the input file pattern.
*/
function makeIntellijStylePattern(filepattern) {
const segments = filepattern.split(/(?=[A-Z])|(?<=[^0-9])(?=[0-9])|(?<=[0-9])(?=[^0-9])|(?<=[0-9a-zA-Z])(?=[^0-9a-zA-Z])|(?<=[^0-9a-zA-Z])(?=[0-9a-zA-Z])/);
const regexPattern = segments.map(segment => segment.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')).join('.*');
return new RegExp(regexPattern, 'i');
}